use of org.eclipse.elk.core.math.KVector 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;
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class DepthFirstCompaction method compactTree.
/**
* Recursive function to compact a tree depth-first.
* @param tree root of a tree
*/
private static void compactTree(final Tree<Node> tree) {
// first compact the children of the current node
tree.children.forEach(DepthFirstCompaction::compactTree);
// remove underlap between root and its children
for (Tree<Node> child : tree.children) {
// find the direction and distance the subtree has to be moved to close the gap to the root node
KVector compactionVector = tree.node.vertex.clone().sub(child.node.vertex);
if (orthogonalCompaction) {
ElkRectangle rt = tree.node.rect;
ElkRectangle rc = child.node.rect;
// restrict the compaction vector to its larger coordinate
if (Math.abs(compactionVector.x) >= Math.abs(compactionVector.y)) {
compactionVector.y = 0;
// scale compaction vector to orthogonal distance between tree and child
if (rc.y + rc.height > rt.y && rc.y < rt.y + rt.height) {
// overlap in vertical dimension
compactionVector.scaleToLength(Math.max(rt.x - (rc.x + rc.width), rc.x - (rt.x + rt.width)));
}
} else {
compactionVector.x = 0;
// scale compaction vector to orthogonal distance between tree and child
if (rc.x + rc.width > rt.x && rc.x < rt.x + rt.width) {
// overlap in horizontal dimension
compactionVector.scaleToLength(Math.max(rt.y - (rc.y + rc.height), rc.y - (rt.y + rt.height)));
}
}
} else {
compactionVector.scaleToLength(tree.node.underlap(child.node));
}
// determine the maximum distance the subtree can be moved without collision, i.e. the minimum underlap
double minUnderlap = compactionVector.length();
// find minimum underlap between any node in the child and any other node in the rest of the
// tree in compaction direction
minUnderlap = getMinUnderlap(root, child, minUnderlap, compactionVector);
// use the minimum underlap to move whole subtree
compactionVector.scaleToLength(minUnderlap);
translateSubtree(child, compactionVector);
debugOut(tree, child);
}
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class SVGImage method addRect.
public void addRect(final double x, final double y, final double w, final double h, final String attributes) {
if (debug) {
addElementStr("<rect x=\"" + x + "\" y=\"" + y + "\" width=\"" + w + "\" height=\"" + h + "\" " + attributes + " />");
updateViewBox(new KVector(x, y), new KVector(x + w, y + h));
}
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class TTriangle method calculateCircumcenter.
/**
* Determines the center of the circumscribed circle of the triangle.
*
* @return the center point of the circumcircle
*/
private KVector calculateCircumcenter() {
KVector ab = b.clone().sub(a);
KVector ac = c.clone().sub(a);
KVector bc = c.clone().sub(b);
double e = ab.x * (a.x + b.x) + ab.y * (a.y + b.y);
double f = ac.x * (a.x + c.x) + ac.y * (a.y + c.y);
double g = 2 * (ab.x * bc.y - ab.y * bc.x);
double px = (ac.y * e - ab.y * f) / g;
double py = (ab.x * f - ac.x * e) / g;
return new KVector(px, py);
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class DebugUtil method drawHitboxes.
/**
* For debugging. Writes hitboxes to svg.
*
* @param fileName
* filename.
*/
public static void drawHitboxes(final CGraph cGraph, final String fileName) {
// determine viewBox
KVector topLeft = new KVector(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
KVector bottomRight = new KVector(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
for (CNode cNode : cGraph.cNodes) {
topLeft.x = Math.min(topLeft.x, cNode.hitbox.x);
topLeft.y = Math.min(topLeft.y, cNode.hitbox.y);
bottomRight.x = Math.max(bottomRight.x, cNode.hitbox.x + cNode.hitbox.width);
bottomRight.y = Math.max(bottomRight.y, cNode.hitbox.y + cNode.hitbox.height);
}
KVector size = bottomRight.clone().sub(topLeft);
// drawing hitboxes to svg
PrintWriter out;
try {
out = new PrintWriter(new FileWriter(fileName));
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
out.println("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\"" + " viewBox=\"" + (topLeft.x) + " " + (topLeft.y) + " " + size.x + " " + size.y + "\">");
out.println("<defs><marker id=\"markerArrow\" markerWidth=\"10\" " + "markerHeight=\"10\" refX=\"0\" refY=\"3\" orient=\"auto\">" + " <path d=\"M0,0 L0,6 L9,3 z\" style=\"fill: #000000;\" />" + "</marker></defs>");
for (CNode cNode : cGraph.cNodes) {
// the node's representation
out.println(cNode.getDebugSVG());
// the constraints
for (CNode inc : cNode.constraints) {
out.println("<line x1=\"" + (inc.hitbox.x) + "\" y1=\"" + (inc.hitbox.y + inc.hitbox.height / 2) + "\" x2=\"" + (cNode.hitbox.x + cNode.hitbox.width) + "\" y2=\"" + (cNode.hitbox.y + cNode.hitbox.height / 2) + "\" stroke=\"black\" opacity=\"0.4\"" + " style=\"marker-end: url(#markerArrow);\" />");
}
}
out.println("</svg>");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Aggregations