/** @param args */ public static void main(String[] args) { VoronoiCore core = new VoronoiCore(); OpenList sites = new OpenList(); Random rand = new Random(100); int amount = 200; PolygonSimple rootPolygon = new PolygonSimple(); int width = 500; int height = 500; rootPolygon.add(0, 0); rootPolygon.add(width, 0); rootPolygon.add(width, height); rootPolygon.add(0, height); for (int i = 0; i < amount; i++) { Site site = new Site(rand.nextInt(width), rand.nextInt(width)); site.setPercentage(1); sites.add(site); } sites.get(0).setPercentage(3); core.setDebugMode(); // core.setOutputMode(); core.normalizeSites(sites); // ArrayList<Site> sites = TestConvergence.getSites(100, rectangle, // true); // core.setErrorAreaThreshold(0.00); // core.setUseExtrapolation(false); // normalizeSites(sites); core.setSites(sites); core.setClipPolygon(rootPolygon); long start = System.currentTimeMillis(); core.setUseNegativeWeights(true); core.setCancelOnAreaErrorThreshold(true); core.doIterate(5000); long end = System.currentTimeMillis(); double diff = (end - start) / 1000.0D; System.out.println("NeededTime: " + diff); // } }
public void iterate() { currentMaxNegativeWeight = 0; currentEuclidChange = 0; currentAreaError = 0; currentMaxError = 0; // long start=System.currentTimeMillis(); // move the sites to their center completeArea = clipPolygon.getArea(); drawCurrentState(false); double errorArea = 0; /** Extrapolation */ int amount = 0; if (isUseExtrapolation() && !preflowFinished) { Site[] array = sites.array; int size = sites.size; for (int z = 0; z < size; z++) { Site site = array[z]; PolygonSimple poly = site.getPolygon(); double percentage = site.getPercentage(); double wantedArea = completeArea * percentage; double currentArea = poly.getArea(); double increase = wantedArea / currentArea; /** Extrapolation */ if (percentage >= getPreflowPercentage() && increase >= getPreflowIncrease()) { // System.out.println("Percentage:" + percentage // + "\t Increase:" + preflowIncrease); amount++; double radiusIncrease = Math.sqrt(increase); double radiusCurrent = Math.sqrt(site.getWeight()); double deltaRadius = radiusCurrent * (radiusIncrease) - radiusCurrent; for (int y = 0; y < size; y++) { Site other = array[y]; if (other != site && other.getPercentage() < getPreflowPercentage()) { Point2D vector = new Point2D(); // Vector2d vector=new Vec vector.x = other.getX() - site.getX(); vector.y = other.getY() - site.getY(); double length = vector.length(); double linearDistanceScaledDeltaRadius = deltaRadius * (1 - ((length - radiusCurrent) / maxDelta)); double scale = linearDistanceScaledDeltaRadius / length; // double scale = deltaRadius // / length; vector.scale(scale); other.preflowVector.x += vector.x; other.preflowVector.y += vector.y; } } } } } if (amount == 0) { preflowFinished = true; } /** move to centers */ Site[] array = sites.array; int size = sites.size; for (int z = 0; z < size; z++) { Site point = array[z]; // point.preflowVector.scale(1.0/(double)amount); double error = 0; double percentage = point.getPercentage(); PolygonSimple poly = point.getPolygon(); if (poly != null) { Point2D centroid = poly.getCentroid(); double centroidX = centroid.getX(); double centroidY = centroid.getY(); double dx = centroidX - point.getX(); double dy = centroidY - point.getY(); currentEuclidChange += dx * dx + dy * dy; double currentArea = poly.getArea(); double wantedArea = completeArea * point.getPercentage(); double increase = (wantedArea / currentArea); error = Math.abs(wantedArea - currentArea); double minDistanceClipped = poly.getMinDistanceToBorder(centroidX, centroidY); minDistanceClipped = minDistanceClipped * nearlyOne; // scale preflow vector to have minDistanceClipped length double rootBorder = clipPolygon.getMinDistanceToBorder(point.getX(), point.getY()); // if (isUseExtrapolation() && !preflowFinished && // rootBorder>maxDelta/Math.sqrt(sites.size()))) { if (isUseExtrapolation() && !preflowFinished) { if (point.preflowVector.length() != 0) { point.preflowVector.scale(minDistanceClipped / point.preflowVector.length()); if (point.preflowVector.length() > 5) { centroidX += point.preflowVector.x; centroidY += point.preflowVector.y; } point.preflowVector.x = 0; point.preflowVector.y = 0; } /** This could also be used as further speedup, but is not 100% stable */ // if (point.preflowVector.length()!=0){ // Point2D centroidNew = poly.getRelativePosition(new // Point2D.Double(point.preflowVector.x, // point.preflowVector.y)); // centroidX=centroidNew.getX(); // centroidY=centroidNew.getY(); // } } double minDistance = point.nonClippedPolyon.getMinDistanceToBorder(centroidX, centroidY); /** radius has to be at most the minimal distance to the border segments of the polygon */ double weight = Math.min(point.getWeight(), minDistance * minDistance); if (weight < 0.00000001) { weight = 0.00000001; } // set new position to the centroid point.setXYW(centroidX, centroidY, weight); } error = error / (completeArea * 2); errorArea += error; // System.out.println("ErrorArea:"+error); } // if (site 0) { // errorArea = 1; // } else { // errorArea = errorArea / (completeArea * 2); currentAreaError += errorArea; // } // drawCurrentState(false); // System.out.println("Area Error: "+errorArea); voroDiagram(); // drawCurrentState(false); // try to improve the radius of the circle so that the wanted area gets // improved // int a = 0; // if (a == 0) // ; /** adapt weights */ /** if activated also allow negative weights */ /** compute the ordinary Voronoi diagram */ OpenList sitesCopy = null; if (guaranteeInvariant) { sitesCopy = sites.cloneWithZeroWeights(); diagram.setSites(sitesCopy); diagram.setClipPoly(clipPolygon); diagram.computeDiagram(); } for (int z = 0; z < size; z++) { Site point = array[z]; PolygonSimple poly = point.getPolygon(); double completeArea = clipPolygon.getArea(); double currentArea = poly.getArea(); double wantedArea = completeArea * point.getPercentage(); double currentRadius = Math.sqrt(currentArea / Math.PI); double wantedRadius = Math.sqrt(wantedArea / Math.PI); double deltaCircle = currentRadius - wantedRadius; double increase = wantedArea / currentArea; if (getAggressiveMode() == false) { increase = Math.sqrt(increase); } // get the minimal distance to the neighbours. otherwise the // neighbours could be dominated double minDistance = 0; if (guaranteeInvariant) { Site pointOrdinary = sitesCopy.array[z]; minDistance = getMinNeighbourDistance(pointOrdinary); } else { minDistance = getMinNeighbourDistance(point); } minDistance = minDistance * nearlyOne; // minDistance = Math.max(1, minDistance); // change the radius of the circles /** we have to take care that the radius doesn't get to big to dominate other sites. */ double radiusOld = Math.sqrt(point.getWeight()); double radiusNew = radiusOld * increase; double deltaRadius = radiusNew - radiusOld; if (radiusNew > minDistance) { radiusNew = minDistance; } double finalWeight = radiusNew * radiusNew; if (useNegativeWeights) { Point2D center = poly.getCentroid(); double distanceBorder = poly.getMinDistanceToBorder(center.x, center.y); double maxDelta = Math.min(distanceBorder, deltaCircle); if (finalWeight < 0.0001) { double radiusNew2 = radiusNew - maxDelta; if (radiusNew2 < 0) { finalWeight = -(radiusNew2 * radiusNew2); if (finalWeight < currentMaxNegativeWeight) { currentMaxNegativeWeight = finalWeight; } } } } point.setWeight(finalWeight); } /** make weights non negative again by adding the smallest negative value */ if (useNegativeWeights) { if (currentMaxNegativeWeight < 0) { currentMaxNegativeWeight += (1 - nearlyOne); currentMaxNegativeWeight = -currentMaxNegativeWeight; for (int z = 0; z < size; z++) { Site s = array[z]; double w = s.getWeight(); w += currentMaxNegativeWeight; s.setWeight(w); } } } // drawCurrentState(false); voroDiagram(); drawCurrentState(false); // drawCurrentState(false); /** compute the maximal error of the area. */ currentMaxError = 0; array = sites.array; size = sites.size; for (int z = 0; z < size; z++) { Site site = array[z]; PolygonSimple poly = site.getPolygon(); double percentage = site.getPercentage(); double wantedArea = completeArea * percentage; double currentArea = poly.getArea(); double singleError = Math.abs(1 - (currentArea / wantedArea)); if (singleError > currentMaxError) { currentMaxError = singleError; } } lastEuclidChange = currentEuclidChange / size; lastSumErrorChange = Math.abs(lastAreaError - currentAreaError); lastAreaError = currentAreaError; lastMaxError = currentMaxError; lastAVGError = currentAreaError / size; // long ende=System.currentTimeMillis(); // System.out.println((ende-start)); }
public void doIterate(final int iterationAmount) { // solveDuplicates(this.sites); // if there is just one side we don't have to do anything if (sites.size == 1) { PolygonSimple p = (PolygonSimple) clipPolygon.clone(); Site site = sites.get(0); site.setPolygon(p); return; } if (firstIteration) { voroDiagram(); drawCurrentState(false); } // long start = System.nanoTime(); int k = 0; for (int i = 0; i < iterationAmount; i++) { iterate(); // long end = System.nanoTime(); // System.out.println("Time in MilliSeconds,Iter "+i+":" + ((double)(end - start))/10E6); // start=end; // for (Site site : polygons.keySet()) { // NPoly poly=polygons.get(site); // /** // * the the resulting polygon // */ // if (site.cellObject != null) { // site.cellObject.setVoroPolygon(poly.clone()); // } // } drawCurrentState(false); if (isCancelOnAreaErrorThreshold() && lastMaxError < errorAreaThreshold) { // System.out.println("AreaError:" + lastAreaError); // System.out.println("Iterations:" + i); break; } } // System.out.println("AreaError:"+errorArea); // now its finish so give the cells a hint drawCurrentState(true); /** TODO remove cellObject notification */ Site[] array = sites.array; int size = sites.size; for (int z = 0; z < size; z++) { Site site = array[z]; PolygonSimple poly = site.getPolygon(); if (site.cellObject != null) { site.cellObject.setVoroPolygon(poly); site.cellObject.doFinalWork(); } } // long end = System.currentTimeMillis(); // System.out.println("Time in MilliSeconds:" + (end - start)); // System.out.println("LastErrorArea:" + lastAreaError); // System.out.println("LastErrorArea:" + lastAreaError/sites.size()); }
/** * Adds a site, which is a voronoi cell to the list * * @param site */ public void addSite(Site site) { sites.add(site); }