Giter VIP home page Giter VIP logo

adaptagrams's Introduction

Adaptagrams

Adaptagrams is a library of tools and reusable code for adaptive diagramming applications, for example: drawing tools, automated document and diagram layout, smart presentation software, graph drawing, chart layout, etc.

Currently, the Adaptagrams repository includes five cross-platform C++ libraries:

  • libvpsc
    - a solver for the Variable Placement with Separation Constraints problem. This is a quadratic programming problem in which the squared differences between a placement vector and some ideal placement are minimised subject to a set of separation constraints. This is very useful in a number of layout problems.
  • libcola
    - a library for constraint graph layout. Specifically, force-directed layout using the stress-majorization method subject to separation constraints. Applications include layout with non-overlapping nodes and clusters, directed graph layout and layout preserving the crossing properties of a given starting layout.
    - libcola depends on libvpsc.
  • libavoid
    - a library providing high-quality object-avoiding polyline and orthogonal connector routing for use in interactive diagram editors.
  • libtopology
    - a library containing extensions to libcola to support topology preserving constraint-based layout.
    - libtopology depends on libavoid, libcola and libvpsc.
  • libdialect
    - a library for computing human-like orthogonal network (DiAlEcT) layouts via the following steps: D = Decompose/Distribute; A = Arrange; E = Expand/Emend; and T = Transform.
    - libdialect depends on libavoid, libcola and libvpsc.

These libraries are collectively known as cola (for Constraint Layout). The newest version of the C++ source code for cola can be found in the Adaptagrams GitHub repository maintained by Michael Wybrow:

The algorithms were developed by members of the Immersive Analytics Lab at Monash University in Melbourne, Australia. The Adaptagrams libraries were written by Tim Dwyer, Michael Wybrow and Steve Kieffer.

All code in the Adaptagrams repository is released as open source software under the terms of the LGPL 2.1 or later, see the LICENSE file.

We also dual-license the Adaptagrams libraries and for a fee we can provide them under a less-restrictive commercial license as well as extend them to fit your needs (contact us). For this reason, if you contribute code to the project and would like it to appear in the main Adaptagrams repository, we require that you assign the copyright on your changes to Monash University with the following statement: "I hereby assign copyright in this code to Monash University, to be licensed under the same terms as the rest of the code."

Software using one or more of the Adaptagrams libraries include:

  • Dunnart, constraint-based diagram editor,
  • Inkscape, the popular open source vector graphics editor,
  • Graphviz, open source graph visualisation software,
  • Arcadia, a visualisation tool for metabolic pathways,
  • Gaphas, an open source Python-based diagramming widget for GTK+, and
  • BRL-CAD, a powerful cross-platform open source solid modeling system that includes interactive geometry editing, high-performance ray-tracing for rendering and geometric analysis, image and signal-processing tools, a system performance analysis benchmark suite, libraries for robust geometric representation, with more than 20 years of active development.

Building

The library code is all contained in the cola directory of the repository.

We use GNU automake to build. We've tried to make the contents of the repository as platform agnostic as possible, so you'll need to call aclocal, autoconf, and automake before configure.

The only dependency is Cairo if debugging SVG output is to be included in several example test cases. The libraries themselves have no dependencies.

Run ./autogen.sh to compile from scratch.

Use from other languages

Bindings for use of the Adaptagrams libraries can be generated using SWIG. The repository contains a SWIG interface file cola/adaptagrams.i. We have successfully tested and used Adaptagrams from Java and Python in this way.

Cola in the browser

cola.js (a.k.a. WebCola) is a JavaScript based rewrite of libcola which works well with D3.js

adaptagrams's People

Contributors

11235813 avatar aidandelaney avatar amolenaar avatar andres-erbsen avatar cmears avatar ede123 avatar milianw avatar mjwybrow avatar p-n-l avatar skieffer avatar speleo3 avatar tbrowder avatar tczauderna avatar thomasb81 avatar timmmm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adaptagrams's Issues

HOLA not trying all expansion options

In #60, we improved the tree placement step in HOLA so that, instead of selecting a best placement and giving up if it proved infeasible, HOLA now backtracks and tries the next best placement. However, HOLA is still too eager to call a given placement infeasible in the first place.

In order to make a given tree placement, the target face needs to be expanded to make room for the tree box. This involves a call to Face::buildBestProjSeq(), but this method currently represents another step where HOLA is selecting a best option, trying it, and giving up without first trying the next best option.

To be precise, Face::buildBestProjSeq() must select one dimension, x or y, in which to expand first. It then attempts expansion in this order. If this fails, it currently gives up, but it should attempt expansion again, now handling the dimensions in the opposite order. This is because cases can arise in which expansion is impossible in one order, but possible in the other order.

Example

Garr_Screen_Shot

This example arises during HOLA layout of the graph Garr201001.tglf that I will include in a linked PR.
(Note that tree box 723 is rooted at node 195, with SW placement.)

We are now attempting to place a new tree box B rooted at node 192, with placement and growth directions both equal to NORTH. The width and height of B are roughly 3, resp. 2, times those of node 192.

Face::buildBestProjSeq() heuristically selects the x-dimension as the best one in which to expand first. When we attempt this, however, we generate a separation constraint that wants to put tree box 723 EAST of node 192, which is impossible, due to non-overlap constraints. We then give up, and call the tree placement impossible. In fact, as things stand, all 10 conceivable placements for this tree fail, and the entire layout fails.

Instead, Face::buildBestProjSeq() should now try expanding again, only now working in the y-dimension first.
When it tries this, it will generate a separation constraint that wants to put tree box 723 NORTH of node 192, which works.
This time the expansion succeeds, as does the tree placement, and the entire layout.

[libavoid] Minimizing edge crossing by choosing appropriate connectionPin

Hello

On following example :
test6

The testcase is represented by 4 shapes. The 2 left shape, are each connected to shape on the right.
Each shape on the right have 2 connectorPin.
Each connectorPin of each shape are registered with the same channel id and has the attribute exclusive set to true.
In other words, the 2 connectorPin of each of the right shape are free to commute.

Since the router is configured with non null crossingPenalty, why the router does not look for the solution that consist to switch the 2 connectorPin on right bottom shape from current solution to remove 1 edge crossing ?
By increasing the crossingPenalty the router end-up to choose a route that pass on the left of the left shape : that's not a solution I expect ...

It look like the astar algo is picking up the first available connectorPin as target without considering other option ...

If the router is able to identify the right connectorPin, it could minimize edge crossing. Consequently a drawing of the routing become simpler to understand.

For clarity, here is the result of the modified testcase for which connectionPin channel is chosen to force router to find the solution with only one edge crossing.
test6

Is there a way to configure the router to make it chose the appropriate connectorPin to minimize edge crossing ?
Is this behavior a bug or a limitation ?

Thanks

Here the code produce by outputInstanceToSVG:

#include "libavoid/libavoid.h"
using namespace Avoid;
int main(void) {
    Router *router = new Router(OrthogonalRouting);
    router->setRoutingParameter((RoutingParameter)0, 10);
    router->setRoutingParameter((RoutingParameter)1, 0);
    router->setRoutingParameter((RoutingParameter)2, 10);
    router->setRoutingParameter((RoutingParameter)3, 4000);
    router->setRoutingParameter((RoutingParameter)4, 10);
    router->setRoutingParameter((RoutingParameter)5, 100);
    router->setRoutingParameter((RoutingParameter)6, 10);
    router->setRoutingParameter((RoutingParameter)7, 20);
    router->setRoutingParameter((RoutingParameter)8, 1);
    router->setRoutingOption((RoutingOption)0, false);
    router->setRoutingOption((RoutingOption)1, true);
    router->setRoutingOption((RoutingOption)2, false);
    router->setRoutingOption((RoutingOption)3, false);
    router->setRoutingOption((RoutingOption)4, true);
    router->setRoutingOption((RoutingOption)5, true);
    router->setRoutingOption((RoutingOption)6, true);
    Polygon polygon;
    ConnRef *connRef = nullptr;
    ConnEnd srcPt;
    ConnEnd dstPt;
    ConnEnd heConnPt;
    PolyLine newRoute;
    ShapeConnectionPin *connPin = nullptr;

    // shapeRef1
    polygon = Polygon(4);
    polygon.ps[0] = Point(100, 0);
    polygon.ps[1] = Point(100, 50);
    polygon.ps[2] = Point(0, 50);
    polygon.ps[3] = Point(0, 0);
    ShapeRef *shapeRef1 = new ShapeRef(router, polygon, 1);
    connPin = new ShapeConnectionPin(shapeRef1, 1, 100, 25, false, 0, (ConnDirFlags) 8);
    connPin->setExclusive(false);

    // shapeRef2
    polygon = Polygon(4);
    polygon.ps[0] = Point(100, 100);
    polygon.ps[1] = Point(100, 150);
    polygon.ps[2] = Point(0, 150);
    polygon.ps[3] = Point(0, 100);
    ShapeRef *shapeRef2 = new ShapeRef(router, polygon, 2);
    connPin = new ShapeConnectionPin(shapeRef2, 1, 100, 25, false, 0, (ConnDirFlags) 8);
    connPin->setExclusive(false);

    // shapeRef3
    polygon = Polygon(4);
    polygon.ps[0] = Point(300, 0);
    polygon.ps[1] = Point(300, 50);
    polygon.ps[2] = Point(200, 50);
    polygon.ps[3] = Point(200, 0);
    ShapeRef *shapeRef3 = new ShapeRef(router, polygon, 3);
    connPin = new ShapeConnectionPin(shapeRef3, 1, 0, 15, false, 0, (ConnDirFlags) 4);
    connPin = new ShapeConnectionPin(shapeRef3, 1, 0, 35, false, 0, (ConnDirFlags) 4);

    // shapeRef6
    polygon = Polygon(4);
    polygon.ps[0] = Point(300, 100);
    polygon.ps[1] = Point(300, 150);
    polygon.ps[2] = Point(200, 150);
    polygon.ps[3] = Point(200, 100);
    ShapeRef *shapeRef6 = new ShapeRef(router, polygon, 6);
    connPin = new ShapeConnectionPin(shapeRef6, 2, 0, 15, false, 0, (ConnDirFlags) 4);
    connPin = new ShapeConnectionPin(shapeRef6, 2, 0, 35, false, 0, (ConnDirFlags) 4);

    // connRef4
    connRef = new ConnRef(router, 4);
    srcPt = ConnEnd(shapeRef1, 1);
    connRef->setSourceEndpoint(srcPt);
    dstPt = ConnEnd(shapeRef3, 1);
    connRef->setDestEndpoint(dstPt);
    connRef->setRoutingType((ConnType)2);

    // connRef5
    connRef = new ConnRef(router, 5);
    srcPt = ConnEnd(shapeRef2, 1);
    connRef->setSourceEndpoint(srcPt);
    dstPt = ConnEnd(shapeRef3, 1);
    connRef->setDestEndpoint(dstPt);
    connRef->setRoutingType((ConnType)2);

    // connRef7
    connRef = new ConnRef(router, 7);
    srcPt = ConnEnd(shapeRef1, 1);
    connRef->setSourceEndpoint(srcPt);
    dstPt = ConnEnd(shapeRef6, 2);
    connRef->setDestEndpoint(dstPt);
    connRef->setRoutingType((ConnType)2);

    // connRef8
    connRef = new ConnRef(router, 8);
    srcPt = ConnEnd(shapeRef2, 1);
    connRef->setSourceEndpoint(srcPt);
    dstPt = ConnEnd(shapeRef6, 2);
    connRef->setDestEndpoint(dstPt);
    connRef->setRoutingType((ConnType)2);

    router->processTransaction();
    router->outputInstanceToSVG();
    delete router;
    return 0;
};

Split libraries into separate subprojects

Hi,
I think it could be useful to split the repository into one repository for each library. This would ease integration using git if one would only want to use one of the libraries. It would also add to the logical separation of the libraries with each one having its own commit history and commits always belonging to exactly one of them. A repository like this one would still be possible by creating a "meta-repository" including the library repos as git submodules.

Thanks for the good work, anyway
Sebastian

Downcast issue with ColaTopologyAddon when using the C# bindings

Hello,

I am using the four adaptagrams libraries on windows, via the C# bindings generated with SWIG. Basic layouting and edge routing works, however I am trying to use the topology preserving addon using the Dunnart code as an example (is there any other documentation available?). It goes like this:

layout = new ConstrainedFDLayout(rectangles, edges, idealEdgeLength, true);
// passing libcola an empty instance of this class will cause it to populate it 
// with the current topology information for nodes and edges when layout.makeFeasible() is run
var topology = new ColaTopologyAddon();
layout.setTopology(topology);
layout.makeFeasible();
layout.run();

var nodes = topology.topologyNodes; //  nodes count is zero
var routes = topology.topologyRoutes; // routes count is zero

var newTopology = (ColaTopologyAddon)layout.getTopology(); // cast exception

The issue is that the getTopology() method returns an instance of the base class TopologyAddonInterface which cannot be downcasted in C#. This sounds like a problem with the SWIG-generated bindings (after I've read some related issues here http://johnnado.com/swig-csharp-java-downcast/).

Any ideas? Thanks.

Release of libavoid and possibly others?

Hi,

I couldn't find a mailing list so I'm opening this issue to ask: What is holding back a first release of the COLA libraries? (specifically libavoid). Is it a code maturity/API stability issue (code is not ready to be released) or simply a manpower issue (everyone too busy to prepare a release)?

It would be great to have releases of these libraries in major distro repos, and possibly also pre-built Windows DLLs and a Mac bundle.

Thanks!

Syntax error when building on MacOS

After running brew install libtool autoconf automake and running ./autogen.sh, I ran into the following error:

./configure: line 16763: syntax error near unexpected token `CAIROMM,cairomm-1.0,cairomm=yes,cairomm=no'
./configure: line 16763: `PKG_CHECK_MODULES(CAIROMM,cairomm-1.0,cairomm=yes,cairomm=no)'

I still got a build working by removing the following lines from cola/configure.ac

#AC_CHECK_LIB(cairomm-1.0,cairo_create)
PKG_CHECK_MODULES(CAIROMM,cairomm-1.0,cairomm=yes,cairomm=no)
if test "x$cairomm" = "xyes"; then
	AC_DEFINE(HAVE_CAIROMM, 1, [Enable CairoMM code])
fi

This is on macOS 11.6.1.
autoconf 2.71
automaker 1.16.5
libtool 2.4.7

Buffer link origins

@mjwybrow Is there an option that allows you to space the originating/terminating position for a link?

E.g.

screenshot 2018-11-26 at 10 55 31

For node 10, I'd like those links to be automatically spaced further apart across more of the box's real estate. I've tried idealNudgingDistance with no improvement.

Additionally, when a node has many links that bleed over the boundaries of the box, does Adaptagrams have an option for automatically resizing the box?

Building Java Bindings with SWIG on Mac

I stumbled over some obstacles in the above endeavor. First it is necessary to stick with 3.x version of SWIG. Mine was 3.0.12.
As you use C11 I had to add -std=c++11 to FATFLAGS in buildSWIGVersionForMac. Then during the java-compilation part the java compiler complained about doubled getters and setters of the class BoundingBox. I had to resolve that manually. But looking at graph.h there is the struct BoundingBox which contains 4 doubles x,X,y,Y. It seems this reuse of of x and y as capitalized letters caused the doubled getter/setter problem. Not sure if this is an issue or a bug. I simply wanted to point out this obstacles such that others are a bit more fortunate than I was.

Cheers && thanks for your work.

Webcola supports gridification. Why not libcola?

Hi all,

I've noticed that webcola - a javascript library based on some rewrite on libcola - has already supported snap-to-grid feature. Yet there is no trace within the range of libcola. Can we implement some anyway? Or can you generously point out some way towards that?

John Chen

Possible to move ShapeConnectionPin after creation

Hi,
Is it possible to move a ShapeConnectionPin after it has been created? The position is passed to the constructor as a x and y portionOffset of the ShapeRef. But after it has been created it seems the pin can't be moved.

Thanks!

Test fail: beautify

Trying to compile adaptagrams, I hit the following issue:

~/adaptagrams/cola$ ./libtopology/tests/beautify
random seed=1207906420
DAG depth=6
maxbranch=4
extraedgeprob0.002000
V=201
E=243
stress=3070.47 iteration=0
stress=2361.57 iteration=1
stress=2050.17 iteration=2
stress=1895.06 iteration=3
stress=1794.66 iteration=4
stress=1732.67 iteration=5
stress=1696.61 iteration=6
stress=1666.28 iteration=7
stress=1643.41 iteration=8
stress=1622.09 iteration=9
stress=1602.09 iteration=10
stress=1575.2 iteration=11
stress=1588.93 iteration=12
unconstrained layout ran in 0.33662 seconds
Removing overlaps...
done.
Running libavoid to compute routes...
writing svg file: beautify0.svg
Wrote file "beautify0.svg"
done. Libavoid ran in 1.09424 seconds
makefeasible ran in 1.09703 seconds
writing svg file: beautify1.svg
Wrote file "beautify1.svg"
beautify: ../libtopology/topology_graph.h:325: double topology::Segment::intersection(vpsc::Dim, double, const topology::EdgePoint*, const topology::EdgePoint*, double&) const: Assertion `denom!=0' failed.
Aborted

update to use brew installed cairomm for macos?

Hi,

Had a straightforward compilation on macOS except for cairomm since it was looking for caromm 1.0 while I had the latest version cairomm 1.16 install . I tried to add pkg-config cairomm-1.16 --libs and pkg-config cairomm-1.16 --cflags to ./configure in the autopen.sh file but couldn't get it compile.

I then search for cairomm-1.0 at https://www.cairographics.org/releases/ to compile manually but it's even available anymore.

Would it be possible to update the cairomm dependency considering the above?

Thanks!

building swig python interface fails

Hi,
I'm trying to build the python library with swig but it fails.

What I've done: build cola with autogen.sh. It passes all the tests. then sudo make install.

to build the python library I did:

swig -c++ -python adaptagrams.i

and

python swig-python-setup.py install

I have python3.6. It then fails with:

running install
running build
running build_py
copying adaptagrams.py -> build/lib.linux-x86_64-3.6
running build_ext
building '_adaptagrams' extension
gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fno-plt -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fno-plt -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fno-plt -fPIC -I. -I/usr/include/python3.6m -c adaptagrams_wrap.cxx -o build/temp.linux-x86_64-3.6/adaptagrams_wrap.o -DUSE_ASSERT_EXCEPTIONS -DSWIG_PYTHON_SILENT_MEMLEAK
cc1plus: warning: command line option โ€˜-Wstrict-prototypesโ€™ is valid for C/ObjC but not for C++
In file included from adaptagrams_wrap.cxx:3734:
./libtopology/topology_graph.h:242:22: warning: โ€˜template<class _Operation> class std::binder1stโ€™ is deprecated [-Wdeprecated-declarations]
         typedef std::binder1st<
                      ^~~~~~~~~
In file included from /usr/include/c++/8.1.1/bits/stl_function.h:1368,
                 from /usr/include/c++/8.1.1/string:48,
                 from adaptagrams_wrap.cxx:3032:
/usr/include/c++/8.1.1/backward/binders.h:108:11: note: declared here
     class binder1st
           ^~~~~~~~~
adaptagrams_wrap.cxx: In function โ€˜PyObject* _wrap_new_CriticalFailure__SWIG_0(PyObject*, PyObject*)โ€™:
adaptagrams_wrap.cxx:44354:9: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   vpsc::CriticalFailure *result = 0 ;
         ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44354:26: error: โ€˜resultโ€™ was not declared in this scope
   vpsc::CriticalFailure *result = 0 ;
                          ^~~~~~
adaptagrams_wrap.cxx:44354:26: note: suggested alternative: โ€˜res4โ€™
   vpsc::CriticalFailure *result = 0 ;
                          ^~~~~~
                          res4
adaptagrams_wrap.cxx:44377:19: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   result = (vpsc::CriticalFailure *)new vpsc::CriticalFailure((char const *)arg1,(char const *)arg2,arg3,(char const *)arg4);
                   ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44377:36: error: expected primary-expression before โ€˜)โ€™ token
   result = (vpsc::CriticalFailure *)new vpsc::CriticalFailure((char const *)arg1,(char const *)arg2,arg3,(char const *)arg4);
                                    ^
adaptagrams_wrap.cxx: In function โ€˜PyObject* _wrap_new_CriticalFailure__SWIG_1(PyObject*, PyObject*)โ€™:
adaptagrams_wrap.cxx:44407:9: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   vpsc::CriticalFailure *result = 0 ;
         ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44407:26: error: โ€˜resultโ€™ was not declared in this scope
   vpsc::CriticalFailure *result = 0 ;
                          ^~~~~~
adaptagrams_wrap.cxx:44407:26: note: suggested alternative: โ€˜res2โ€™
   vpsc::CriticalFailure *result = 0 ;
                          ^~~~~~
                          res2
adaptagrams_wrap.cxx:44425:19: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   result = (vpsc::CriticalFailure *)new vpsc::CriticalFailure((char const *)arg1,(char const *)arg2,arg3);
                   ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44425:36: error: expected primary-expression before โ€˜)โ€™ token
   result = (vpsc::CriticalFailure *)new vpsc::CriticalFailure((char const *)arg1,(char const *)arg2,arg3);
                                    ^
adaptagrams_wrap.cxx: In function โ€˜PyObject* _wrap_CriticalFailure_what(PyObject*, PyObject*)โ€™:
adaptagrams_wrap.cxx:44501:9: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
         ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44501:26: error: โ€˜arg1โ€™ was not declared in this scope
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                          ^~~~
adaptagrams_wrap.cxx:44501:26: note: suggested alternative: โ€˜argsโ€™
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                          ^~~~
                          args
adaptagrams_wrap.cxx:44501:40: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                                        ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44501:57: error: expected primary-expression before โ€˜)โ€™ token
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                                                         ^
adaptagrams_wrap.cxx:44512:34: error: โ€˜CriticalFailureโ€™ in namespace โ€˜vpscโ€™ does not name a type
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                  ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44512:50: error: expected โ€˜>โ€™ before โ€˜*โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                  ^
adaptagrams_wrap.cxx:44512:50: error: expected โ€˜(โ€™ before โ€˜*โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                  ^
                                                  (
adaptagrams_wrap.cxx:44512:52: error: expected primary-expression before โ€˜>โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                    ^
adaptagrams_wrap.cxx:44512:60: error: expected โ€˜)โ€™ before โ€˜;โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                            ^
                                                            )
adaptagrams_wrap.cxx:44513:20: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   result = ((vpsc::CriticalFailure const *)arg1)->what();
                    ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44513:35: error: expected โ€˜)โ€™ before โ€˜constโ€™
   result = ((vpsc::CriticalFailure const *)arg1)->what();
             ~                     ^~~~~~
                                   )
adaptagrams_wrap.cxx:44513:57: error: expected โ€˜)โ€™ before โ€˜;โ€™ token
   result = ((vpsc::CriticalFailure const *)arg1)->what();
            ~                                            ^
                                                         )
adaptagrams_wrap.cxx: In function โ€˜PyObject* _wrap_delete_CriticalFailure(PyObject*, PyObject*)โ€™:
adaptagrams_wrap.cxx:44523:9: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
         ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44523:26: error: โ€˜arg1โ€™ was not declared in this scope
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                          ^~~~
adaptagrams_wrap.cxx:44523:26: note: suggested alternative: โ€˜argsโ€™
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                          ^~~~
                          args
adaptagrams_wrap.cxx:44523:40: error: โ€˜CriticalFailureโ€™ is not a member of โ€˜vpscโ€™
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                                        ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44523:57: error: expected primary-expression before โ€˜)โ€™ token
   vpsc::CriticalFailure *arg1 = (vpsc::CriticalFailure *) 0 ;
                                                         ^
adaptagrams_wrap.cxx:44533:34: error: โ€˜CriticalFailureโ€™ in namespace โ€˜vpscโ€™ does not name a type
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                  ^~~~~~~~~~~~~~~
adaptagrams_wrap.cxx:44533:50: error: expected โ€˜>โ€™ before โ€˜*โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                  ^
adaptagrams_wrap.cxx:44533:50: error: expected โ€˜(โ€™ before โ€˜*โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                  ^
                                                  (
adaptagrams_wrap.cxx:44533:52: error: expected primary-expression before โ€˜>โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                    ^
adaptagrams_wrap.cxx:44533:60: error: expected โ€˜)โ€™ before โ€˜;โ€™ token
   arg1 = reinterpret_cast< vpsc::CriticalFailure * >(argp1);
                                                            ^
                                                            )
adaptagrams_wrap.cxx:44534:10: error: type โ€˜<type error>โ€™ argument given to โ€˜deleteโ€™, expected pointer
   delete arg1;
          ^~~~
adaptagrams_wrap.cxx: In instantiation of โ€˜static Type swig::traits_as<Type, swig::pointer_category>::as(PyObject*, bool) [with Type = std::pair<unsigned int, unsigned int>; PyObject = _object]โ€™:
adaptagrams_wrap.cxx:4506:64:   required from โ€˜Type swig::as(PyObject*, bool) [with Type = std::pair<unsigned int, unsigned int>; PyObject = _object]โ€™
adaptagrams_wrap.cxx:5073:20:   required from โ€˜swig::SwigPySequence_Ref<T>::operator T() const [with T = std::pair<unsigned int, unsigned int>]โ€™
adaptagrams_wrap.cxx:5527:30:   required from โ€˜void swig::assign(const SwigPySeq&, Seq*) [with SwigPySeq = swig::SwigPySequence_Cont<std::pair<unsigned int, unsigned int> >; Seq = std::vector<std::pair<unsigned int, unsigned int> >]โ€™
adaptagrams_wrap.cxx:5549:12:   required from โ€˜static int swig::traits_asptr_stdseq<Seq, T>::asptr(PyObject*, swig::traits_asptr_stdseq<Seq, T>::sequence**) [with Seq = std::vector<std::pair<unsigned int, unsigned int> >; T = std::pair<unsigned int, unsigned int>; PyObject = _object; swig::traits_asptr_stdseq<Seq, T>::sequence = std::vector<std::pair<unsigned int, unsigned int> >]โ€™
adaptagrams_wrap.cxx:5610:52:   required from โ€˜static int swig::traits_asptr<std::vector<T> >::asptr(PyObject*, std::vector<T>**) [with T = std::pair<unsigned int, unsigned int>; PyObject = _object]โ€™
adaptagrams_wrap.cxx:4398:37:   required from โ€˜int swig::asptr(PyObject*, Type**) [with Type = std::vector<std::pair<unsigned int, unsigned int> >; PyObject = _object]โ€™
adaptagrams_wrap.cxx:16926:34:   required from here
adaptagrams_wrap.cxx:4481:8: warning: โ€˜void* memset(void*, int, size_t)โ€™ clearing an object of type โ€˜struct std::pair<unsigned int, unsigned int>โ€™ with no trivial copy-assignment; use assignment instead [-Wclass-memaccess]
  memset(v_def,0,sizeof(Type));
  ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/8.1.1/bits/stl_algobase.h:64,
                 from /usr/include/c++/8.1.1/bits/char_traits.h:39,
                 from /usr/include/c++/8.1.1/string:40,
                 from adaptagrams_wrap.cxx:3032:
/usr/include/c++/8.1.1/bits/stl_pair.h:198:12: note: โ€˜struct std::pair<unsigned int, unsigned int>โ€™ declared here
     struct pair
            ^~~~
adaptagrams_wrap.cxx: In instantiation of โ€˜static Type swig::traits_as<Type, swig::pointer_category>::as(PyObject*, bool) [with Type = cola::Lock; PyObject = _object]โ€™:
adaptagrams_wrap.cxx:4506:64:   required from โ€˜Type swig::as(PyObject*, bool) [with Type = cola::Lock; PyObject = _object]โ€™
adaptagrams_wrap.cxx:5073:20:   required from โ€˜swig::SwigPySequence_Ref<T>::operator T() const [with T = cola::Lock]โ€™
adaptagrams_wrap.cxx:5527:30:   required from โ€˜void swig::assign(const SwigPySeq&, Seq*) [with SwigPySeq = swig::SwigPySequence_Cont<cola::Lock>; Seq = std::vector<cola::Lock>]โ€™
adaptagrams_wrap.cxx:5549:12:   required from โ€˜static int swig::traits_asptr_stdseq<Seq, T>::asptr(PyObject*, swig::traits_asptr_stdseq<Seq, T>::sequence**) [with Seq = std::vector<cola::Lock>; T = cola::Lock; PyObject = _object; swig::traits_asptr_stdseq<Seq, T>::sequence = std::vector<cola::Lock>]โ€™
adaptagrams_wrap.cxx:5610:52:   required from โ€˜static int swig::traits_asptr<std::vector<T> >::asptr(PyObject*, std::vector<T>**) [with T = cola::Lock; PyObject = _object]โ€™
adaptagrams_wrap.cxx:4398:37:   required from โ€˜int swig::asptr(PyObject*, Type**) [with Type = std::vector<cola::Lock>; PyObject = _object]โ€™
adaptagrams_wrap.cxx:22668:34:   required from here
adaptagrams_wrap.cxx:4481:8: warning: โ€˜void* memset(void*, int, size_t)โ€™ clearing an object of non-trivial type โ€˜class cola::Lockโ€™; use assignment or value-initialization instead [-Wclass-memaccess]
  memset(v_def,0,sizeof(Type));
  ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
In file included from adaptagrams_wrap.cxx:3729:
./libcola/cola.h:75:7: note: โ€˜class cola::Lockโ€™ declared here
 class Lock {
       ^~~~
adaptagrams_wrap.cxx: In instantiation of โ€˜static Type swig::traits_as<Type, swig::pointer_category>::as(PyObject*, bool) [with Type = cola::Resize; PyObject = _object]โ€™:
adaptagrams_wrap.cxx:4506:64:   required from โ€˜Type swig::as(PyObject*, bool) [with Type = cola::Resize; PyObject = _object]โ€™
adaptagrams_wrap.cxx:5073:20:   required from โ€˜swig::SwigPySequence_Ref<T>::operator T() const [with T = cola::Resize]โ€™
adaptagrams_wrap.cxx:5527:30:   required from โ€˜void swig::assign(const SwigPySeq&, Seq*) [with SwigPySeq = swig::SwigPySequence_Cont<cola::Resize>; Seq = std::vector<cola::Resize>]โ€™
adaptagrams_wrap.cxx:5549:12:   required from โ€˜static int swig::traits_asptr_stdseq<Seq, T>::asptr(PyObject*, swig::traits_asptr_stdseq<Seq, T>::sequence**) [with Seq = std::vector<cola::Resize>; T = cola::Resize; PyObject = _object; swig::traits_asptr_stdseq<Seq, T>::sequence = std::vector<cola::Resize>]โ€™
adaptagrams_wrap.cxx:5610:52:   required from โ€˜static int swig::traits_asptr<std::vector<T> >::asptr(PyObject*, std::vector<T>**) [with T = cola::Resize; PyObject = _object]โ€™
adaptagrams_wrap.cxx:4398:37:   required from โ€˜int swig::asptr(PyObject*, Type**) [with Type = std::vector<cola::Resize>; PyObject = _object]โ€™
adaptagrams_wrap.cxx:24584:34:   required from here
adaptagrams_wrap.cxx:4481:8: warning: โ€˜void* memset(void*, int, size_t)โ€™ clearing an object of non-trivial type โ€˜class cola::Resizeโ€™; use assignment or value-initialization instead [-Wclass-memaccess]
  memset(v_def,0,sizeof(Type));
  ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
In file included from adaptagrams_wrap.cxx:3729:
./libcola/cola.h:104:7: note: โ€˜class cola::Resizeโ€™ declared here
 class Resize {
       ^~~~~~
adaptagrams_wrap.cxx: In instantiation of โ€˜static Type swig::traits_as<Type, swig::pointer_category>::as(PyObject*, bool) [with Type = Avoid::Point; PyObject = _object]โ€™:
adaptagrams_wrap.cxx:4506:64:   required from โ€˜Type swig::as(PyObject*, bool) [with Type = Avoid::Point; PyObject = _object]โ€™
adaptagrams_wrap.cxx:5073:20:   required from โ€˜swig::SwigPySequence_Ref<T>::operator T() const [with T = Avoid::Point]โ€™
adaptagrams_wrap.cxx:5527:30:   required from โ€˜void swig::assign(const SwigPySeq&, Seq*) [with SwigPySeq = swig::SwigPySequence_Cont<Avoid::Point>; Seq = std::vector<Avoid::Point>]โ€™
adaptagrams_wrap.cxx:5549:12:   required from โ€˜static int swig::traits_asptr_stdseq<Seq, T>::asptr(PyObject*, swig::traits_asptr_stdseq<Seq, T>::sequence**) [with Seq = std::vector<Avoid::Point>; T = Avoid::Point; PyObject = _object; swig::traits_asptr_stdseq<Seq, T>::sequence = std::vector<Avoid::Point>]โ€™
adaptagrams_wrap.cxx:5610:52:   required from โ€˜static int swig::traits_asptr<std::vector<T> >::asptr(PyObject*, std::vector<T>**) [with T = Avoid::Point; PyObject = _object]โ€™
adaptagrams_wrap.cxx:4398:37:   required from โ€˜int swig::asptr(PyObject*, Type**) [with Type = std::vector<Avoid::Point>; PyObject = _object]โ€™
adaptagrams_wrap.cxx:37901:34:   required from here
adaptagrams_wrap.cxx:4481:8: warning: โ€˜void* memset(void*, int, size_t)โ€™ clearing an object of non-trivial type โ€˜class Avoid::Pointโ€™; use assignment or value-initialization instead [-Wclass-memaccess]
  memset(v_def,0,sizeof(Type));
  ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
In file included from ./libavoid/libavoid.h:39,
                 from adaptagrams_wrap.cxx:3736:
./libavoid/geomtypes.h:52:20: note: โ€˜class Avoid::Pointโ€™ declared here
 class AVOID_EXPORT Point
                    ^~~~~
adaptagrams_wrap.cxx: In instantiation of โ€˜static Type swig::traits_as<Type, swig::pointer_category>::as(PyObject*, bool) [with Type = Avoid::Checkpoint; PyObject = _object]โ€™:
adaptagrams_wrap.cxx:4506:64:   required from โ€˜Type swig::as(PyObject*, bool) [with Type = Avoid::Checkpoint; PyObject = _object]โ€™
adaptagrams_wrap.cxx:5073:20:   required from โ€˜swig::SwigPySequence_Ref<T>::operator T() const [with T = Avoid::Checkpoint]โ€™
adaptagrams_wrap.cxx:5527:30:   required from โ€˜void swig::assign(const SwigPySeq&, Seq*) [with SwigPySeq = swig::SwigPySequence_Cont<Avoid::Checkpoint>; Seq = std::vector<Avoid::Checkpoint>]โ€™
adaptagrams_wrap.cxx:5549:12:   required from โ€˜static int swig::traits_asptr_stdseq<Seq, T>::asptr(PyObject*, swig::traits_asptr_stdseq<Seq, T>::sequence**) [with Seq = std::vector<Avoid::Checkpoint>; T = Avoid::Checkpoint; PyObject = _object; swig::traits_asptr_stdseq<Seq, T>::sequence = std::vector<Avoid::Checkpoint>]โ€™
adaptagrams_wrap.cxx:5610:52:   required from โ€˜static int swig::traits_asptr<std::vector<T> >::asptr(PyObject*, std::vector<T>**) [with T = Avoid::Checkpoint; PyObject = _object]โ€™
adaptagrams_wrap.cxx:4398:37:   required from โ€˜int swig::asptr(PyObject*, Type**) [with Type = std::vector<Avoid::Checkpoint>; PyObject = _object]โ€™
adaptagrams_wrap.cxx:39817:34:   required from here
adaptagrams_wrap.cxx:4481:8: warning: โ€˜void* memset(void*, int, size_t)โ€™ clearing an object of non-trivial type โ€˜class Avoid::Checkpointโ€™; use assignment or value-initialization instead [-Wclass-memaccess]
  memset(v_def,0,sizeof(Type));
  ~~~~~~^~~~~~~~~~~~~~~~~~~~~~
In file included from ./libavoid/libavoid.h:41,
                 from adaptagrams_wrap.cxx:3736:
./libavoid/connector.h:68:20: note: โ€˜class Avoid::Checkpointโ€™ declared here
 class AVOID_EXPORT Checkpoint
                    ^~~~~~~~~~
adaptagrams_wrap.cxx: In function โ€˜void SWIG_Python_FixMethods(PyMethodDef*, swig_const_info*, swig_type_info**, swig_type_info**)โ€™:
adaptagrams_wrap.cxx:76503:22: warning: โ€˜char* strncpy(char*, const char*, size_t)โ€™ output truncated before terminating nul copying 10 bytes from a string of the same length [-Wstringop-truncation]
               strncpy(buff, "swig_ptr: ", 10);

Do you know why it fails?

I tried to run configure with ./configure CXXFLAGS="-O3 -DNDEBUG -arch x86_64 -arch i386" LDFLAGS="-arch x86_64 -arch i386" (this is commented in the autogen.sh file) but configure fails as -arch is not recognized by gcc... I am using gcc (GCC) 8.1.1 20180531 on arch linux.

Thanks!

Hola/Dialect tree directions and grouped nodes

I'm trying to make a very large org chart diagram which is just a simple tree. I thought I'd try HOLA/Dialect because the examples look great, but sadly it just gives me the same results as Graphviz - a really really wide tree that's impossible to read:

image

It's a very wide flat tree so it's not exactly wrong, but I have some ideas for improvement.

  1. It could change the tree direction at each node. Especially at the root node, the CEO's immediate reports could be placed in trees going west, north and east. That would help make the whole thing squarer.
  2. Each person's reports could be grouped in a box, and then placed in a grid.

Sort of like this:

image

Is any of that possible with Dialect?

automake issues with gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)

So it seems like the automake configuration is not working correctly with my current gcc version. When I try to run the automake it dies with this this long in the configure step:

checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for g++... g++
checking whether the C++ compiler works... no
configure: error: in `/home/krishna/CIDAR/adaptagrams/cola':
configure: error: C++ compiler cannot create executables
See `config.log' for more details

So from this I deduced that it failed to verify if GCC would work.

Next, I check the log to see why thats a problem

Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 
configure:3093: $? = 0
configure:3082: g++ -V >&5
g++: error: unrecognized command line option '-V'
g++: fatal error: no input files
compilation terminated.
configure:3093: $? = 1
configure:3082: g++ -qversion >&5
g++: error: unrecognized command line option '-qversion'; did you mean '--version'?
g++: fatal error: no input files
compilation terminated.

So from what I gather:

g++: error: unrecognized command line option '-V'
g++: fatal error: no input files`

or

g++: error: unrecognized command line option '-qversion'; did you mean '--version'?
g++: fatal error: no input files

seems to be the problem.

This is the first time I'm using automake, so I'm kind of a noob with this. It'll be really helpful if you can help me configure this. I considered switching the compiler options but, I have a ton of other libraries for which I had to build Makefiles manually for this project and I don't want to spend time re-configuring everything again.

Thanks

Non-orthogonal Line

Hi,

I have a scenario where I was trying to route an orthogonal path between 2 connection ends and there is no route-able space for the path. The requirement is for me to place a constraint on the idealNudgingDistance in such a way that there is no space for the path to be made.
And, the result of the orthogonal routing algorithm is that the path made is non-orthogonal (See attached picture).
non-orthogonal2x

Is there a way to force an orthogonal path? Note, cutting through other obstacles in this corner case would be permissible.

Some questions about libavoid

libavoid is a very good router library, but I have some questions about it.

  1. I tried to run the performance01 example, and output SVG, but I found there are some oblique edges in the SVG diagram, my diagram also contains oblique. How to avoid the oblique edge?

  2. I use libavoid in my diagram, my diagram contains 14 node and 1000+ edge, the node size was 400* 10000, and the point coordinates are from 0 to 50000.
    When I router 100 edges, it costs 3s, router 200 edges costs 42s, router 300 edges costs 3m20s, and router 400 edges causes a core dumped error.
    I don't know why the performane becauses very bad when the edge increases and cause core dumped. Could you could you give me some advise for make the performane better?

  3. My requirements are the edges were orthogonal, not overlap with other edge, not cross node and not bad performane. Could you give me some recommend option and parametter can reach my requirements?

`libavoid`: false assertion in `nudgeOrthogonalRoutes()` when `nudgeSharedPathsWithCommonEndPoint` is `false`

Problem

Sometimes, when the routing option nudgeSharedPathsWithCommonEndPoint is set to false, the nudgeOrthogonalRoutes() method of the ImproveOrthogonalRoutes class in libavoid makes the assertion

COLA_ASSERT(vs[i - 1]->id == channelLeftID);

which turns out to be false, and the process crashes.

Review

As a non-author of libavoid, I want to start with a review of how orthogonal connector
nudging works, for the sake of my own understanding as much as anyone else's.

The nudgeOrthogonalRoutes() function works one dimension at a time, and I will
assume throughout that we are working in the y-dimension. This means we are looking at
all of the horizontal connector segments, and we are interested in adjusting their y-coords,
in order to nudge them apart.

Before nudging can begin, each segment is assigned a channel.
The channel for a given horizontal segment is a rectangle whose x-interval equals that of the segment,
and whose y-interval is defined by the min and max allowed y-coords for this segment. These
bounds are defined by the set of all obstacles. The channel thus represents the space
in which the segment is allowed to move up or down in the nudging process. Importantly, either of the
upper or lower bounds may be infinite, in cases where there are no obstacles in the way.

The basic process of nudgeOrthogonalRoutes() is to partition the set of all horizontal segments into
groups whose channels overlap, and then to work one group at a time.
For each group, nudgeOrthogonalRoutes() sets up a vpsc problem, to try to nudge
the segments apart by the desired nudging distance. If the vpsc problem is not satisifed,
it decreases the nudging distance and tries again. It tries at most 10 times, then gives up on that group,
leaving all segments in their original position.

justUnifying

The nudgeOrthogonalRoutes() is actually called twice in the overall routing process, the first time with
a flag, justUnifying = true, which makes it conduct a very different process, explained by the comment here:

// Do Unifying first, by itself. This greedily tries to position free
// segments in overlapping channels at the same position. This way they
// have correct nudging orders determined for them since they will form
// shared paths, rather than segments just positioned as an results of
// the routing process. Of course, don't do this when rerouting with

The vpsc problem

A vpsc problem is defined by a set of variables and a set of constraints. For each group of segments,
we set up the following problem.

Variables

What are the variables in a nudging problem?
They are of four kinds:

  • Free: represents a connector segment that is allowed to wind up anywhere within its channel
  • Fixed: represents a connector segment that is required to stay in its starting position
  • Left Channel: represents the "left" side of a channel (the upper side, when working in the y-dimension)
  • Right Channel: represents the "right" side of a channel (the lower side, when working in the y-dimension)

Constraints

What are the constraints?

  • Free vars must stay between their corrsp. left and right channel vars
  • Separation constraints to achieve the desired nudging
  • Certain equality constraints for special cases defined here

The special case equality constraints -- the third item above -- play a critical role in the issue discussed here.

Weights

The vpsc problem defined in nudgeOrthogonalRoutes() takes a "soft" approach to the variables that are not supposed
to move, which includes all three of the fixed, left, and right variables. Instead of strictly forbidding movement,
with the possibility that vpsc could actually fail, it uses weights. It puts a weight of 100000 on the variables that
should not move, and a weight of 0.001 on the free variables. This means the vpsc problem is always solvable. After it
is solved, nudgeOrthogonalRoutes() assesses whether it was satisfied or not, by checking whether any of the heavy-weight
variables was moved from its desired position by more than a small threshold value (0.0001).

Responding to an unsatisfied vpsc problem

The issue arises in the way nudgeOrthogonalRoutes() responds to an unsatisfied vpsc problem, i.e. one in which one or more
fixed vars was forced to move.

The goal is to determine the set of separation constraints whose gaps should be diminished before trying again.
For this, nudgeOrthogonalRoutes() uses a notion of an "unsat range," a closed interval of indices into the vector of vpsc variables, being those fixed variables that were forced to move.

It is in the process of determining these ranges that the false assertion is made. The expectation expressed here,

// There are no existing unsatisfied ranges,
// so start a new unsatisfied range.
// We are looking at a unsatisfied right side
// where the left side was satisfied, so the
// range begins at the previous variable
// which should be a left channel side.
COLA_ASSERT(i > 0);
COLA_ASSERT(vs[i - 1]->id == channelLeftID);

implies that, if a right channel side had to move, this channel must also have a left side. But this is not always true, as the following example will show. When the corresponding left channel var is absent, the second assertion above fails.

Example

The example routing problem we'll look at succeeds if the routing option nudgeSharedPathsWithCommonEndPoint is true;
it fails with the false assertion when this option is false. In order to be able to visualize and understand the routing problem,
we begin by looking at the successful routing we get when nudgeSharedPathsWithCommonEndPoint is true:

yes_NSPWCE_labeled

By commenting out the problematic assertions, and setting nudgeSharedPathsWithCommonEndPoint back to false, we can see how the routing looks before the nudging attempt:

no_NSPWCE_labeled

In the "no-nudging" image, I have labeled the four different desired y-coords that come up in the vpsc problem (see below), which concerns the segments in the group at the top of the diagram.

In the "with-nudging" image, it is easy to see all the different connectors that were bundled together at these y-coords, before nudging.

Problematic vars and constraints

The vpsc problem constructed for the segments participating in this group has 13 variables, and 23 constraints.

Variables

index, id, desiredPosition, finalPosition, weight,   notes

0,      0,  -516.954,       -503.733,       0.001    ConnRef 49
1,      3,  -516.954,       -503.733,       100000     UNSAT

2,      0,  -516.954,       -507.733,       0.001    ConnRef 27
3,      3,  -516.954,       -507.733,       100000     UNSAT


4,      1,  -485.291,       -507.733,       100000     UNSAT   ConnRef 35


5,      0,  -458.302,       -503.733,       0.001
6,      3,  -458.302,       -458.302,       100000

7,      0,  -458.302,       -507.733,       0.001    ConnRef 48
8,      3,  -458.302,       -458.302,       100000

9,      0,  -458.302,       -507.733,       0.001    ConnRef 41
10,     3,  -458.302,       -458.302,       100000


11,     0,  -431.639,       -507.733,       0.001
12,     3,  -431.639,       -431.639,       100000

Note: the id column indicates which of the four types each variable is:

free=0, fixed=1, left=2, right=3

Notice that there are no left variables in this problem. This simply reflects the fact that, for all of these segments, there is no lower channel boundary, because we are at the top of the diagram. There are no obstacles above, and these segments are allowed to move up as far as they want.

The three unsatisfied vars (1, 3, and 4) are noted in the notes column.

Constraints

I will not spell out all 23 constraints. I believe that most of them are fine, while the problematic ones are the following equality constraints:

v7 == v2
v7 == v4

v9 == v2
v9 == v4
v9 == v7

v11 == v2
v11 == v4
v11 == v7
v11 == v9

Each of these is one of the special case equality constraints noted earlier, and is generated here:

else if (!nudgeSharedPathsWithCommonEnd &&
(m_shared_path_connectors_with_common_endpoints.count(
UnsignedPair(currSegment->connRef->id(), prevSeg->connRef->id())) > 0))
{
// We don't want to nudge apart these two segments
// since they are from a shared path with a common
// endpoint. There might be multiple chains of
// segments that don't all have the same endpoints
// so we need to make this an equality to prevent
// some of them possibly getting nudged apart.
thisSepDist = 0;
equality = true;
}

Simplifying all these constraints, they amount to:

v2 == v4 == v7 == v9 == v11

Since v4 is supposed to be fixed, while v2 <= v3 and v3 is fixed at a position less than v4, the problem is unsatisfiable.

Because the problem is unsatifiable, and in particular because the right channel vars v1 and v3 are forced to move, the
nudgeOrthogonalRoutes() function asserts that these right channel vars have corresponding left channel vars. But they do not.

The assertion seems reasonable. It is reasonable to expect that, when a channel boundary is forced to move, it is because the channel is too narrow, there is not enough space for the free vars inside. And that requires that both sides of the channel are finite. But the present example shows a case where channel boundaries are forced to move for a very different reason, namely the special equality constraints generated in the if (!nudgeSharedPathsWithCommonEnd... clause.

Possible solution

In the example, it seems to me that the equality constraints are inappropriate unless the segments' desired positions are equal. So, v9 == v7 may make sense, but each of v2, v4, v11 should be allowed to differ, since they all have different desired positions.

In terms of the comments written in the code where these equality constraints are generated, it seems like we shouldn't be trying to "prevent" these segments from being "nudged apart." They already are apart, and we want them that way.

I wonder if these equality constraints were only really meant to keep together those segments that were put together during the justUnifying pass.

Should this be added as another condition? If so, the clause:

else if (!nudgeSharedPathsWithCommonEnd &&
        (m_shared_path_connectors_with_common_endpoints.count(
             UnsignedPair(currSegment->connRef->id(), prevSeg->connRef->id())) > 0))

would become:

else if (!nudgeSharedPathsWithCommonEnd &&
        (m_shared_path_connectors_with_common_endpoints.count(
             UnsignedPair(currSegment->connRef->id(), prevSeg->connRef->id())) > 0) &&
             currSegment->variable->desiredPosition == prevSeg->variable->desiredPosition)

To really judge whether this is the right solution would require a full grasp of all the cases these
equality constraints were designed to handle, and I don't have that grasp. I will open a PR to encode
this solution, as well as to provide the test case that generated the figures above, but I will mark
it as a draft, since I'm not sure if it's really the right solution or not.

unsatisfiableRangeAssertion fails make check

[ unsatisfiableRangeAssertion.o ] Error 1

This error also makes cc1plus.exe stop working as well. If unsatisfiableRangeAssertion is removed from the Makefile.am, make check passes.

I am building this using MinGW on Windows 7. I assume unsatisfiableRangeAssertion is missing something simple.

packaging adaptagrams

Hi @mjwybrow ,

Would it be possible to package adaptagrams for debian/arch/fedora ?
It would allow easier maintenance in projects that depend on it (Inkscape, in my case)

Thanks!

'check-recursive' Test Failed

Will this be an issue while using the library ?

Tail of the automake console output

PASS: orthogonalOpt
============================================================================
Testsuite summary for libcola 0.1
============================================================================
# TOTAL: 5
# PASS:  4
# SKIP:  0
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0
============================================================================
See libtopology/tests/test-suite.log
============================================================================
Makefile:733: recipe for target 'test-suite.log' failed
make[4]: *** [test-suite.log] Error 1
make[4]: Leaving directory '/home/krishna/adaptagrams/cola/libtopology/tests'
Makefile:839: recipe for target 'check-TESTS' failed
make[3]: *** [check-TESTS] Error 2
make[3]: Leaving directory '/home/krishna/adaptagrams/cola/libtopology/tests'
Makefile:940: recipe for target 'check-am' failed
make[2]: *** [check-am] Error 2
make[2]: Leaving directory '/home/krishna/adaptagrams/cola/libtopology/tests'
Makefile:647: recipe for target 'check-recursive' failed
make[1]: *** [check-recursive] Error 1
make[1]: Leaving directory '/home/krishna/adaptagrams/cola/libtopology'
Makefile:390: recipe for target 'check-recursive' failed
make: *** [check-recursive] Error 1

Here is the test-suite.log file:

===================================================
   libcola 0.1: libtopology/tests/test-suite.log
===================================================

# TOTAL: 5
# PASS:  4
# SKIP:  0
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0

.. contents:: :depth: 2

FAIL: beautify
==============

random seed=1207906420
DAG depth=6
maxbranch=4
extraedgeprob0.002000
V=201
E=243
stress=3070.47 iteration=0
stress=2361.57 iteration=1
stress=2050.17 iteration=2
stress=1895.06 iteration=3
stress=1794.66 iteration=4
stress=1732.67 iteration=5
stress=1696.61 iteration=6
stress=1666.28 iteration=7
stress=1643.41 iteration=8
stress=1622.09 iteration=9
stress=1602.09 iteration=10
stress=1575.2 iteration=11
stress=1588.93 iteration=12
unconstrained layout ran in 0.315067 seconds
Removing overlaps...
done.
Running libavoid to compute routes...
WARNING: cola::OutputFile::generate(): No SVG file produced.
         You must have cairomm (and cairo with SVG support) this to work.
done. Libavoid ran in 0.932603 seconds
makefeasible ran in 0.935755 seconds
WARNING: cola::OutputFile::generate(): No SVG file produced.
         You must have cairomm (and cairo with SVG support) this to work.
beautify: ../libtopology/topology_graph.h:325: double topology::Segment::intersection(vpsc::Dim, double, const topology::EdgePoint*, const topology::EdgePoint*, double&) const: Assertion `denom!=0' failed.
FAIL beautify (exit status: 134)

Tests use a non-existent Router#setOrthogonalNudgeDistance method

Some tests such as corneroverlap01 refer to a non-existent method:
Error C2039 'setOrthogonalNudgeDistance': is not a member of 'Avoid::Router' corneroverlap01 D:\work\adaptagrams-master[2019-01-24]\cola\libavoid\tests\corneroverlap01.cpp 12
The method was deleted in 2012 apparently: c64d677.

Hola in Python: ImportError

Hi!

I'm trying to resolve an ImportError when trying to import hola into python

ImportError: dlopen(./_adaptagrams.so, 2): Symbol not found: __ZN4cola17generateVariablesERSt6vectorIPNS_18CompoundConstraintESaIS2_EEN4vpsc3DimERS0_IPNS6_8VariableESaIS9_EE
  Referenced from: ./_adaptagrams.so
  Expected in: flat namespace
 in ./_adaptagrams.so

more details

  • I cloned Hola and Adaptagrams
  • added $HOLADIR and $ADAPDIR to my path.
  • added the hola directory to my python path.
 # HOLA path                                                                     
 export PYTHONPATH=$HOME/Code/HOLADIR/hola                                       
 # ADAPACA path                                                                  
 export ADAPDIR=$HOME/Code/ADAPDIR/adaptagrams                                   
 #export PYTHONPATH=$ADAPDIR                                                     
 # HOLADIR path                                                                  
 export HOLADIR=$HOME/CODE/HOLADIR/hola/ 
  • I compiled Adaptagrams using ./autogen.sh

  • I then ran make -f Makefile-swig-python

  • Followed by python swig-python-setup.py build_ext --inplace

  • I receive an ImportError when I attempt to use Hola in python

In [1]: from hola.hola import hola
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-e3809a4a9595> in <module>()
----> 1 from hola.hola import hola

/Users/petar/Code/HOLADIR/hola/hola/hola.py in <module>()
     28 import sys
     29 
---> 30 import adaptagrams.adaptagrams as adg
     31 from gmlparse import buildGraph
     32 from treePruner3 import prune

/Users/petar/Code/ADAPDIR/adaptagrams/cola/adaptagrams.py in <module>()
     15         except ImportError:
     16             return importlib.import_module('_adaptagrams')
---> 17     _adaptagrams = swig_import_helper()
     18     del swig_import_helper
     19 elif _swig_python_version_info >= (2, 6, 0):

/Users/petar/Code/ADAPDIR/adaptagrams/cola/adaptagrams.py in swig_import_helper()
     14             return importlib.import_module(mname)
     15         except ImportError:
---> 16             return importlib.import_module('_adaptagrams')
     17     _adaptagrams = swig_import_helper()
     18     del swig_import_helper

/Users/petar/anaconda/lib/python2.7/importlib/__init__.pyc in import_module(name, package)
     35             level += 1
     36         name = _resolve_name(name[level:], package, level)
---> 37     __import__(name)
     38     return sys.modules[name]

ImportError: dlopen(./_adaptagrams.so, 2): Symbol not found: __ZN4cola17generateVariablesERSt6vectorIPNS_18CompoundConstraintESaIS2_EEN4vpsc3DimERS0_IPNS6_8VariableESaIS9_EE
  Referenced from: ./_adaptagrams.so
  Expected in: flat namespace
 in ./_adaptagrams.so

My system information

Python 2.7.12 |Anaconda custom (x86_64)| (default, Jul  2 2016, 17:43:17) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)] on darwin
macOS Sierra
System Version:	macOS 10.12.4 (16E195)
Kernel Version:	Darwin 16.5.0

Assertion failure in beautify test case

I've compiled adaptagrams with CXXFLAGS="-O0 -g" and with the default CXXFLAGS. In both cases I get the following failure in the beautify test case. This backtrace has been generated -O0. Running on Linux on x86_64. This failure happens on every run of beautify.

random seed=1207906420
DAG depth=6
maxbranch=4
extraedgeprob0.002000
V=201
E=243
stress=3070.47 iteration=0
stress=2361.57 iteration=1
stress=2050.17 iteration=2
stress=1895.06 iteration=3
stress=1794.66 iteration=4
stress=1732.67 iteration=5
stress=1696.61 iteration=6
stress=1666.28 iteration=7
stress=1643.41 iteration=8
stress=1622.09 iteration=9
stress=1602.09 iteration=10
stress=1575.2 iteration=11
stress=1588.93 iteration=12
unconstrained layout ran in 1.45957 seconds
Removing overlaps...
done.
Running libavoid to compute routes...
WARNING: cola::OutputFile::generate(): No SVG file produced.
You must have cairomm (and cairo with SVG support) this to work.
done. Libavoid ran in 4.78719 seconds
makefeasible ran in 4.79767 seconds
WARNING: cola::OutputFile::generate(): No SVG file produced.
You must have cairomm (and cairo with SVG support) this to work.
lt-beautify: ../libtopology/topology_graph.h:325: double topology::Segment::intersection(vpsc::Dim, double, const topology::EdgePoint_, const topology::EdgePoint_, double&) const: Assertion `denom!=0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff6621c39 in raise () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.18-12.fc20.x86_64 libgcc-4.8.3-1.fc20.x86_64 libstdc++-4.8.3-1.fc20.x86_64
(gdb) backtrace
#0 0x00007ffff6621c39 in raise () from /lib64/libc.so.6
#1 0x00007ffff6623348 in abort () from /lib64/libc.so.6
#2 0x00007ffff661ab96 in __assert_fail_base () from /lib64/libc.so.6
#3 0x00007ffff661ac42 in __assert_fail () from /lib64/libc.so.6
#4 0x00007ffff7b95cd6 in topology::Segment::intersection (this=0x6ff030, scanDim=vpsc::HORIZONTAL, pos=336.04288043322771, s=0x6ff420, e=0x6ff690, p=@0x7fffffffbda8: 1)

at ../libtopology/topology_graph.h:325

#5 0x00007ffff7b95b8b in topology::Segment::reverseIntersection (this=0x6ff030, scanDim=vpsc::HORIZONTAL, pos=336.04288043322771, p=@0x7fffffffbda8: 1)

at ../libtopology/topology_graph.h:311

#6 0x00007ffff7b9419b in topology::BendConstraint::BendConstraint (this=0xa6a340, v=0x6ff690, dim=vpsc::HORIZONTAL) at topology_constraints_constructor.cpp:485
#7 0x00007ffff7b83220 in topology::EdgePoint::createBendConstraint (this=0x6ff690, scanDim=vpsc::HORIZONTAL) at topology_graph.cpp:129
#8 0x00007ffff7b8309e in topology::EdgePoint::prune (this=0x6ffb30, scanDim=vpsc::HORIZONTAL) at topology_graph.cpp:109
#9 0x00007ffff7b94d70 in topology::TopologyConstraints::TopologyConstraints (this=0x7fffffffcd20, axisDim=vpsc::HORIZONTAL,

nodes=std::vector of length 201, capacity 201 = {...}, edges=std::vector of length 243, capacity 243 = {...}, clusterHierarchy=0x0, 
vs=std::vector of length 201, capacity 201 = {...}, cs=std::vector of length 0, capacity 0) at topology_constraints_constructor.cpp:698

#10 0x00007ffff7ba4f62 in topology::ColaTopologyAddon::moveTo (this=0x6e6770, dim=vpsc::HORIZONTAL, vs=std::vector of length 201, capacity 201 = {...},

cs=std::vector of length 0, capacity 0, coords=..., clusterHierarchy=0x0) at cola_topology_addon.cpp:376

#11 0x00007ffff74ccc03 in cola::ConstrainedFDLayout::moveTo (this=0x7fffffffdc00, dim=vpsc::HORIZONTAL, target=...) at colafd.cpp:957
#12 0x00007ffff74c88a1 in cola::ConstrainedFDLayout::setPosition (this=0x7fffffffdc00, pos=...) at colafd.cpp:210
#13 0x00007ffff74c88f3 in cola::ConstrainedFDLayout::computeDescentVectorOnBothAxes (this=0x7fffffffdc00, xAxis=true, yAxis=true, stress=1.7976931348623157e+308, x0=...,

x1=...) at colafd.cpp:221

#14 0x00007ffff74c8d50 in cola::ConstrainedFDLayout::run (this=0x7fffffffdc00, xAxis=true, yAxis=true) at colafd.cpp:270
#15 0x0000000000415bd6 in main () at beautify.cpp:354

libavoid library build Compilation/Linking fails.

I had to change use of MFC: Use Standard Windows Libraries to Use MFC in a Shared DLL ion both debug and release mode. to get it started

Compilation fails due to std::min and std::max wherever used not mentioned #inculde
Linking fails due to HyperedgeImprover.h/.cpp files are not added into Project.
{This are thing which worked for me after fresh pull of whole repository}
Or it must be something I must have missed but i didn't find any document "How to build"

Please update accordingly, Thanks for your great work.

Interop project problem

Hello, I am trying to get access to the libcola library using the cola.interop project. However, it throws a TypeInitializationException in runtime.
"An unhandled exception of type 'System.TypeInitializationException' occurred in ColaClassLibrary.dll

Additional information: The type initializer for 'org.adaptagrams.cola.colaPINVOKE' threw an exception."
Is this interop project still valid? How could I use the libcola in .Net environment?

Is libavoid routing result deterministic?

Hi,

May I know if given the same inputs, is the routing result deterministic?

Please find attached sample program for illustration of the issue. The test program basically configure the router with same parameters/options and same set of obstacles (Rectangle) and ask the router to route a wire (ConnRef) 10 times, the routing result are logged in "LibavoidTest.log". For this instance of test, observe that 4th and 8th routing results are different from other results.

Generally the algorithm is producing very good routing results. When the issue happens, usually the difference is one of the segment is off by few pixels. On very rare cases, it may took a different path.

I raise this question is because our tests are automated and it rely on consistent routing result for verification.

Please advise if I have use libavoid correctly. If so, is this behavior by design or is indeed an issue and will it get fixed?

Thanks.

LibavoidTest.zip

Modernizing libavoid

Is it possible to have the following:

Thank you.

Invalid points passed to the rotationalAngle method leading to crash (failed assertion)

I do not have full debugging information since I am using the libraries via the C# bindings. The issue occurs when using a Router with PolylineRouting and with the shapeBufferDistance penalty:

var router = new Router((uint)RouterFlag.PolyLineRouting);
router.setRoutingPenalty(RoutingParameter.shapeBufferDistance, 10);

In this conditions the rotationalAngle method from libavoid/geometry.cpp sometimes gets passed a point with invalid coordinates, leading to an assertion fail. Some debugging revealed that the coordinates are nan:

Ang: nan, X: nan, Y: nan

I am not sure why this happens or if it's related to some specific configuration that i didn't set for the router. If it helps, the adaptagrams libraries are compiled using MingW with optimizations enabled. I will try replicating the issue on a linux machine.

dialect::dimensions object's contents not accessible from python swig wrapper

Hi,

The python swig wrapper works great except that I am unable to access the contents of the dimensions objects which is a std::pair<double, double> instance return from DialectNode.getDimensions.

dialect::dimensions is a typedef std::pair<double,double> dimensions

But I am not able to retrieve its contents in python.

In [1]: from adaptagrams import *

In [2]: n = DialectNode.allocate(10.0, 20.0, 30.0, 30.0)

In [3]: d = n.getDimensions()

In [4]: d.first
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-6ed88d6b1bba> in <module>
----> 1 d.first

AttributeError: 'SwigPyObject' object has no attribute 'first'

I have tried to add some additional wrapping code to adaptagrams.i. The following gives the same error as above:

%typedef std::pair<double,double> dimensions;
%template() std::pair<double,double>;
%rename(dimensions) dialect::dimensions;

and when I add a %template(dimensions) std::pair<double,double>; it generates the wrapping code but then cannot find it in the resultant extension module.

My knowledge of SWIG is quite limited so would appreciate some advice on how to fix this.

Suggestion: WebAssembly build of libavoid?

I'd be very interested in using the libavoid library in a browser-based technology stack. Thus, I was thinking whether it would make sense to have a WebAssembly build of libavoid. Is that something that would be of interest for the adaptagrams community?

Or are there JavaScript-based alternatives to libavoid's object-avoiding routing library?

Thanks in advance!

Specialisation of dialect::Edge::makeLibavoidConnEnds

Hello

My C++ inheritance and smart pointer knowledge are a little bit rusty.

The way dialect::Edge::makeLibavoidConnEnds create Avoid::ConnEnd on the center of the shape is not fine for me. I would like depending of context create them all around the shape of the node.

https://github.com/mjwybrow/adaptagrams/blame/344d513826100c36ce04b5589924e9fd9d6944cd/cola/libdialect/edges.cpp#L113

How can I specialized dialect::Edge::makeLibavoidConnEnds ?

So far my trial did not work...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.