package org.geogebra.common.kernel.discrete; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; import org.geogebra.common.awt.GPoint2D; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.kernel.SegmentType; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.discrete.delaunay.Delaunay_Triangulation; import org.geogebra.common.kernel.discrete.delaunay.Point_dt; import org.geogebra.common.kernel.discrete.delaunay.Triangle_dt; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.kernelND.GeoPointND; public class AlgoVoronoi extends AlgoDiscrete { public AlgoVoronoi(Construction cons, String label, GeoList inputList) { super(cons, label, inputList, null); } @Override public Commands getClassName() { return Commands.Voronoi; } @Override public final void compute() { size = inputList.size(); if (!inputList.isDefined() || size == 0) { locus.setUndefined(); return; } double inhom[] = new double[2]; ArrayList<Double> xcoords = new ArrayList<Double>(); ArrayList<Double> ycoords = new ArrayList<Double>(); final double delta = 0.0000001; // add to TreeSet to remove duplicates (from touching triangles) TreeSet<GPoint2D> pointTree = new TreeSet<GPoint2D>( getPointComparator()); for (int i = 0; i < size; i++) { GeoElement geo = inputList.get(i); if (geo.isDefined() && geo.isGeoPoint()) { GeoPointND p = (GeoPointND) geo; p.getInhomCoords(inhom); pointTree.add(new GPoint2D.Double(inhom[0], inhom[1])); } } Point_dt[] points = new Point_dt[pointTree.size()]; int indx = 0; Iterator<GPoint2D> it3 = pointTree.iterator(); while (it3.hasNext()) { GPoint2D p = it3.next(); double x = p.getX(); double y = p.getY(); while (xcoords.contains(x)) { x += delta; } while (ycoords.contains(y)) { y += delta; } // work around a bug in the algorithm for Points with an equal x or // y coordinate xcoords.add(x); ycoords.add(y); points[indx++] = new Point_dt(x, y); } Delaunay_Triangulation dt = new Delaunay_Triangulation(points); if (dt.allCollinear) { locus.setUndefined(); return; } Iterator<Triangle_dt> it = dt.trianglesIterator(); if (al == null) { al = new ArrayList<MyPoint>(); } else { al.clear(); } // add to TreeSet to remove duplicates (from touching triangles) TreeSet<MyLine> tree = new TreeSet<MyLine>( AlgoDelauneyTriangulation.getComparator()); while (it.hasNext()) { Triangle_dt triangle = it.next(); for (int index = 0; index < 3; index++) { Point_dt corner = triangle.getCorner(index); if (corner != null) { Point_dt[] voronoiCell = dt.calcVoronoiCell(triangle, corner); if (voronoiCell != null) { for (int i = 0; i < voronoiCell.length - 1; i++) { tree.add(new MyLine( new GPoint2D.Double(voronoiCell[i].x(), voronoiCell[i].y()), new GPoint2D.Double( voronoiCell[(i + 1) % voronoiCell.length].x(), voronoiCell[(i + 1) % voronoiCell.length] .y()))); } } } } } Iterator<MyLine> it2 = tree.iterator(); while (it2.hasNext()) { MyLine line = it2.next(); al.add(new MyPoint(line.p1.getX(), line.p1.getY(), SegmentType.MOVE_TO)); al.add(new MyPoint(line.p2.getX(), line.p2.getY(), SegmentType.LINE_TO)); } locus.setPoints(al); locus.setDefined(true); } /* * comparator used to eliminate duplicate objects (TreeSet deletes * duplicates ie those that return 0) */ public static Comparator<GPoint2D> getPointComparator() { if (pointComparator == null) { pointComparator = new Comparator<GPoint2D>() { @Override public int compare(GPoint2D p1, GPoint2D p2) { // double p1A = itemA.getX(); // double p1B = itemA.getY(); // double p2A = itemB.getX(); // double p2B = itemB.getY(); // return 0 if endpoints the same // so no duplicates in the TreeMap if (Kernel.isEqual(p1.getX(), p2.getX()) && Kernel.isEqual(p1.getY(), p2.getY())) { // Application.debug("equal2"); return 0; } // need to return something sensible, otherwise tree doesn't // work return p1.getX() > p2.getX() ? -1 : 1; } }; } return pointComparator; } private static Comparator<GPoint2D> pointComparator; }