private void moveToCenter2(double completeArea, Site point) { 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 error = Math.abs(wantedArea - currentArea); 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) { weight = 0.01; } double euclidChange = dx * dx + dy * dy; // set new position to the centroid point.setXYW(centroidX, centroidY, weight); // return error; } // return Double.MAX_VALUE; }
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)); }