package org.geogebra.common.kernel.discrete; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import org.apache.commons.collections15.Transformer; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.kernel.SegmentType; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.kernelND.GeoPointND; import edu.uci.ics.jung.algorithms.shortestpath.MinimumSpanningForest2; import edu.uci.ics.jung.graph.DelegateForest; import edu.uci.ics.jung.graph.DelegateTree; import edu.uci.ics.jung.graph.Forest; import edu.uci.ics.jung.graph.UndirectedSparseMultigraph; import edu.uci.ics.jung.graph.util.EdgeType; public class AlgoMinimumSpanningTree extends AlgoDiscrete { protected int edgeCount; private static Transformer<MyLink, Double> wtTransformer = new Transformer<MyLink, Double>() { @Override public Double transform(MyLink link) { return link.weight; } }; public AlgoMinimumSpanningTree(Construction cons, String label, GeoList inputList) { super(cons, label, inputList, null); } @Override public Commands getClassName() { return Commands.MinimumSpanningTree; } @Override public final void compute() { size = inputList.size(); if (!inputList.isDefined() || size == 0) { locus.setUndefined(); return; } edgeCount = 0; HashMap<GeoPointND, MyNode> nodes = new HashMap<GeoPointND, MyNode>(); MyNode node1, node2; UndirectedSparseMultigraph<MyNode, MyLink> g = new UndirectedSparseMultigraph<MyNode, MyLink>(); for (int i = 0; i < size - 1; i++) { GeoPointND p1 = (GeoPointND) inputList.get(i); for (int j = i + 1; j < size; j++) { GeoPointND p2 = (GeoPointND) inputList.get(j); node1 = nodes.get(p1); node2 = nodes.get(p2); if (node1 == null) { node1 = new MyNode(p1); nodes.put(p1, node1); } if (node2 == null) { node2 = new MyNode(p2); nodes.put(p2, node2); } g.addEdge(new MyLink(p1.distance(p2), node1, node2), node1, node2, EdgeType.UNDIRECTED); } MinimumSpanningForest2<MyNode, MyLink> prim = new MinimumSpanningForest2<MyNode, MyLink>( g, new DelegateForest<MyNode, MyLink>(), DelegateTree.<MyNode, MyLink> getFactory(), wtTransformer); Forest<MyNode, MyLink> tree = prim.getForest(); Iterator<MyLink> it = tree.getEdges().iterator(); if (al == null) { al = new ArrayList<MyPoint>(); } else { al.clear(); } while (it.hasNext()) { MyLink edge = it.next(); Coords coords = edge.n1.id.getInhomCoordsInD2(); al.add(new MyPoint(coords.get(1), coords.get(2), SegmentType.MOVE_TO)); coords = edge.n2.id.getInhomCoordsInD2(); al.add(new MyPoint(coords.get(1), coords.get(2), SegmentType.LINE_TO)); } locus.setPoints(al); locus.setDefined(true); } } class MyLink { protected MyNode n1, n2; double weight; int id; public MyLink(double weight, MyNode n1, MyNode n2) { this.id = edgeCount++; // This is defined in the outer class. this.weight = weight; this.n1 = n1; this.n2 = n2; } @Override public String toString() { // Always good for debugging return "Edge" + id; } } }