Search in sources :

Example 1 with SVGImage

use of org.eclipse.elk.alg.common.utils.SVGImage in project elk by eclipse.

the class BowyerWatsonTriangulation method triangulate.

/**
 * Triangulates a list of points.
 *
 * @param vertices the input points
 * @param debugOutputFile file name for debug SVG. Debug output will be deactivated if this is null.
 * @return the edges of the triangulation
 */
public static Set<TEdge> triangulate(final List<KVector> vertices, final String debugOutputFile) {
    /*d*/
    SVGImage svg = new SVGImage(debugOutputFile);
    /*d*/
    svg.addGroups("invalid", "tri", "bndry", "done", "new");
    /* preliminaries */
    // determine the bounding box of the given points
    KVector topleft = new KVector(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
    KVector bottomright = new KVector(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
    for (KVector v : vertices) {
        topleft.x = Math.min(topleft.x, v.x);
        topleft.y = Math.min(topleft.y, v.y);
        bottomright.x = Math.max(bottomright.x, v.x);
        bottomright.y = Math.max(bottomright.y, v.y);
        // CHECKSTYLEOFF MagicNumber
        /*d*/
        svg.g("bb").addCircle(v.x, v.y, 18, "stroke=\"black\" stroke-width=\"1\" fill=\"lightgray\"");
    }
    KVector size = new KVector(bottomright.x - topleft.x, bottomright.y - topleft.y);
    /*d*/
    svg.g("bb").addRect(topleft.x, topleft.y, size.x, size.y, "stroke=\"blue\" stroke-width=\"4\" fill=\"none\"");
    // find a super-triangle spanning over all vertices
    final double wiggleroom = 50;
    // This ensures that no vertices are too close to the edges of the super-triangle
    // because that would result in circumcircles that are so large that a double would not
    // be precise enough to compute the circumcircle criterion.
    KVector sa = new KVector(topleft.x - wiggleroom, topleft.y - size.x - wiggleroom);
    KVector sb = new KVector(topleft.x - wiggleroom, bottomright.y + size.x + wiggleroom);
    KVector sc = new KVector(bottomright.x + size.y / 2 + wiggleroom, topleft.y + size.y / 2);
    /*d*/
    svg.g("bb").addPoly("stroke=\"gray\" stroke-width=\"4\" fill=\"none\" stroke-dasharray=\"20,20\"", sa, sb, sc, sa);
    TTriangle superTriangle = new TTriangle(sa, sb, sc);
    /*d*/
    // circumcircles will make it gigantic
    svg.setViewBox(sa.x, sa.y, sc.x - sa.x, sb.y - sa.y);
    /*d*/
    svg.isave();
    /*d*/
    svg.removeGroup("bb");
    /* Bowyer Watson algorithm*/
    Set<TTriangle> triangulation = Sets.newHashSet();
    List<TTriangle> invalidTriangles = Lists.newArrayList();
    List<TEdge> boundary = Lists.newArrayList();
    triangulation.add(superTriangle);
    // incrementally adding vertices
    for (KVector vertex : vertices) {
        /*d*/
        svg.g("done").addCircle(vertex.x, vertex.y, 18, "stroke=\"black\" stroke-width=\"1\" fill=\"lightgray\"");
        /*d*/
        svg.g("new").addCircle(vertex.x, vertex.y, 18, "stroke=\"black\" stroke-width=\"1\" fill=\"black\"");
        // gather invalid triangles where the new vertex lies inside the circumcircle
        invalidTriangles.clear();
        for (TTriangle triangle : triangulation) {
            /*d*/
            svg.g("tri").addPoly("stroke=\"black\" fill=\"none\" stroke-width=\"4\"", triangle.a, triangle.b, triangle.c, triangle.a);
            /*d*/
            KVector c = triangle.getCircumcenter();
            /*d*/
            svg.g("invalid").addCircle(c.x, c.y, c.distance(triangle.a), "stroke=\"orange\" stroke-width=\"4\" fill=\"none\"");
            if (triangle.inCircumcircle(vertex)) {
                invalidTriangles.add(triangle);
                /*d*/
                svg.g("invalid").addPoly("stroke=\"none\" fill=\"red\" opacity=\"0.18\"", triangle.a, triangle.b, triangle.c, triangle.a);
            }
        }
        /*d*/
        svg.isave();
        /*d*/
        svg.clearGroup("invalid");
        // calculate boundary of invalid triangles
        boundary.clear();
        for (TTriangle triangle : invalidTriangles) {
            for (TEdge tEdge : triangle.tEdges) {
                boolean onBoundary = true;
                // edges that are not shared with other invalid triangles are on the boundary
                for (TTriangle other : invalidTriangles) {
                    if (other != triangle && other.contains(tEdge)) {
                        onBoundary = false;
                    }
                }
                if (onBoundary) {
                    boundary.add(tEdge);
                    /*d*/
                    svg.g("bndry").addLine(tEdge.u.x, tEdge.u.y, tEdge.v.x, tEdge.v.y, "stroke=\"purple\" stroke-width=\"18\" stroke-dasharray=\"20,20\"");
                }
            }
        }
        /*d*/
        svg.isave();
        // remove invalid triangles
        triangulation.removeAll(invalidTriangles);
        /*d*/
        svg.clearGroup("tri");
        /*d*/
        triangulation.forEach(triangle -> svg.g("tri").addPoly("stroke=\"black\" fill=\"none\" stroke-width=\"4\"", triangle.a, triangle.b, triangle.c, triangle.a));
        /*d*/
        svg.isave();
        // triangulate boundary
        for (TEdge tEdge : boundary) {
            triangulation.add(new TTriangle(vertex, tEdge.u, tEdge.v));
            /*d*/
            svg.g("tri").addPoly("stroke=\"black\" fill=\"none\" stroke-width=\"4\"", vertex, tEdge.u, tEdge.v, vertex);
        }
        /*d*/
        svg.isave();
        /*d*/
        svg.clearGroup("new");
        /*d*/
        svg.clearGroup("bndry");
        /*d*/
        svg.clearGroup("tri");
    }
    // convert triangulation to set of edges
    // Because it's a set, edges that were redundant in the triangulation exist only once in the set.
    Set<TEdge> tEdges = Sets.newHashSet();
    triangulation.forEach(triangle -> tEdges.addAll(triangle.tEdges));
    // remove edges connected to super triangle
    Iterator<TEdge> i = tEdges.iterator();
    while (i.hasNext()) {
        TEdge tEdge = i.next();
        if (superTriangle.contains(tEdge.u) || superTriangle.contains(tEdge.v)) {
            i.remove();
        }
    }
    /*d*/
    tEdges.forEach(tEdge -> svg.addLine(tEdge.u.x, tEdge.u.y, tEdge.v.x, tEdge.v.y, "stroke=\"black\" stroke-width=\"4\""));
    /*d*/
    svg.isave();
    return tEdges;
}
Also used : KVector(org.eclipse.elk.core.math.KVector) SVGImage(org.eclipse.elk.alg.common.utils.SVGImage)

Example 2 with SVGImage

use of org.eclipse.elk.alg.common.utils.SVGImage in project elk by eclipse.

the class NaiveMinST method createSpanningTree.

/**
 * Creates a minimum spanning tree for a graph using the cost function specified in the constructor.
 * @param tEdges the edges of the graph
 * @param root the root node to start the spanning tree
 * @param costFunction a function returning a cost value for a {@link TEdge}
 * @param debugOutputFile file name for debug SVG. Debug output will be deactivated if this is null.
 * @return the spanning tree
 */
public static Tree<KVector> createSpanningTree(final Set<TEdge> tEdges, final KVector root, final ICostFunction costFunction, final String debugOutputFile) {
    // determine edge weights
    Map<TEdge, Double> weight = Maps.newHashMap();
    for (TEdge edge : tEdges) {
        weight.put(edge, costFunction.cost(edge));
    }
    // sort edges by weight
    List<TEdge> edgeList = Lists.newArrayList(tEdges);
    edgeList.sort((TEdge e1, TEdge e2) -> weight.get(e1).compareTo(weight.get(e2)));
    // preserves order
    Set<TEdge> edges = Sets.newLinkedHashSet(edgeList);
    // iteratively add cheapest edge where one node is contained in current tree and one is new
    Tree<KVector> minST = new Tree<KVector>(root);
    Map<KVector, Tree<KVector>> treeNodes = Maps.newHashMap();
    treeNodes.put(root, minST);
    // debug output ----------------------------------------------------------------------------------------------
    SVGImage svg = new SVGImage(debugOutputFile);
    // elkjs-exclude-start
    svg.addGroups("e", "t");
    for (TEdge e : edges) {
        svg.g("e").addLine(e.u.x, e.u.y, e.v.x, e.v.y, "stroke=\"black\" stroke-width=\"1\"");
        svg.g("t").addElementStr("<text x=\"" + (e.u.x + e.v.x) / 2 + "\" y=\"" + (e.u.y + e.v.y) / 2 + "\" fill=\"blue\"" + " font-size=\"20px\">" + String.format("%.2f", weight.get(e)) + "</text>");
    }
    svg.isave();
    while (!edges.isEmpty()) {
        TEdge nextEdge = null;
        KVector nextNode = null;
        KVector nodeInTree = null;
        double minWeight = Double.POSITIVE_INFINITY;
        for (TEdge edge : edges) {
            if (weight.get(edge) <= minWeight) {
                if (treeNodes.containsKey(edge.u) && !treeNodes.containsKey(edge.v)) {
                    nextNode = edge.v;
                    nodeInTree = edge.u;
                    nextEdge = edge;
                    // because edges is sorted we don't have to look any further
                    break;
                }
                if (treeNodes.containsKey(edge.v)) {
                    if (!treeNodes.containsKey(edge.u)) {
                        nextNode = edge.u;
                        nodeInTree = edge.v;
                        nextEdge = edge;
                        // because edges is sorted we don't have to look any further
                        break;
                    }
                }
            }
        }
        // connects a new node to the tree.
        if (nextEdge == null) {
            break;
        }
        // add the new node to the spanning tree
        Tree<KVector> subTree = new Tree<KVector>(nextNode);
        treeNodes.get(nodeInTree).children.add(subTree);
        treeNodes.put(nextNode, subTree);
        edges.remove(nextEdge);
        // debug output -------------------------------------------------------------------------------------------
        svg.g("e").addLine(nextEdge.u.x, nextEdge.u.y, nextEdge.v.x, nextEdge.v.y, "stroke=\"red\" stroke-width=\"3\"");
        svg.isave();
    // --------------------------------------------------------------------------------------------------------
    }
    return minST;
}
Also used : KVector(org.eclipse.elk.core.math.KVector) SVGImage(org.eclipse.elk.alg.common.utils.SVGImage)

Example 3 with SVGImage

use of org.eclipse.elk.alg.common.utils.SVGImage in project elk by eclipse.

the class DepthFirstCompaction method compact.

/**
 * Executes the compaction of the graph represented by the spanning tree.
 * @param tree the spanning tree of a graph
 * @param orthogonal whether to restrict the movement to orthogonal translations
 * @param debugOutputFile file name for debug SVG. Debug output will be deactivated if this is null.
 */
public static void compact(final Tree<Node> tree, final boolean orthogonal, final String debugOutputFile) {
    svg = new SVGImage(debugOutputFile);
    orthogonalCompaction = orthogonal;
    root = tree;
    debugOut(tree, null);
    compactTree(root);
}
Also used : SVGImage(org.eclipse.elk.alg.common.utils.SVGImage)

Example 4 with SVGImage

use of org.eclipse.elk.alg.common.utils.SVGImage in project elk by eclipse.

the class GrowTreePhase method process.

@Override
public void process(final Graph graph, final IElkProgressMonitor progressMonitor) {
    progressMonitor.begin("Grow Tree", 1);
    root = graph.tree;
    if (graph.getProperty(InternalProperties.DEBUG_SVG)) {
        svg = new SVGImage(ElkUtil.debugFolderPath("spore") + "40or");
        svg.addGroups("n", "e", "o");
        debugOut();
    } else {
        svg = new SVGImage(null);
    }
    overlapsExisted = false;
    growAt(graph.tree);
    graph.setProperty(InternalProperties.OVERLAPS_EXISTED, overlapsExisted);
    progressMonitor.done();
}
Also used : SVGImage(org.eclipse.elk.alg.common.utils.SVGImage)

Example 5 with SVGImage

use of org.eclipse.elk.alg.common.utils.SVGImage in project elk by eclipse.

the class ShrinkTreeCompactionPhase method debugOut.

// --- debug utils --------------------------------------
private void debugOut(final Tree<Node> tree) {
    SVGImage svg = new SVGImage(ElkUtil.debugFolderPath("spore") + "30Tree");
    svg.clear();
    // CHECKSTYLEOFF MagicNumber
    svg.addCircle(tree.node.vertex.x, tree.node.vertex.y, 10, "fill=\"lime\"");
    draw(tree, svg);
    svg.save();
    svg.debug = false;
}
Also used : SVGImage(org.eclipse.elk.alg.common.utils.SVGImage)

Aggregations

SVGImage (org.eclipse.elk.alg.common.utils.SVGImage)6 KVector (org.eclipse.elk.core.math.KVector)2 Sets (com.google.common.collect.Sets)1 List (java.util.List)1 Set (java.util.Set)1 TEdge (org.eclipse.elk.alg.common.TEdge)1 IOverlapHandler (org.eclipse.elk.alg.common.spore.IOverlapHandler)1 InternalProperties (org.eclipse.elk.alg.common.spore.InternalProperties)1 ScanlineOverlapCheck (org.eclipse.elk.alg.common.spore.ScanlineOverlapCheck)1 Graph (org.eclipse.elk.alg.spore.graph.Graph)1 OverlapRemovalStrategy (org.eclipse.elk.alg.spore.options.OverlapRemovalStrategy)1 RootSelection (org.eclipse.elk.alg.spore.options.RootSelection)1 SpanningTreeCostFunction (org.eclipse.elk.alg.spore.options.SpanningTreeCostFunction)1 SporeCompactionOptions (org.eclipse.elk.alg.spore.options.SporeCompactionOptions)1 SporeOverlapRemovalOptions (org.eclipse.elk.alg.spore.options.SporeOverlapRemovalOptions)1 StructureExtractionStrategy (org.eclipse.elk.alg.spore.options.StructureExtractionStrategy)1 TreeConstructionStrategy (org.eclipse.elk.alg.spore.options.TreeConstructionStrategy)1 AbstractLayoutProvider (org.eclipse.elk.core.AbstractLayoutProvider)1 AlgorithmAssembler (org.eclipse.elk.core.alg.AlgorithmAssembler)1 ILayoutProcessor (org.eclipse.elk.core.alg.ILayoutProcessor)1