Переглянути джерело

improved getCircle and added epsilon parameter to deal with scale differences

ncannasse 12 роки тому
батько
коміт
9058ab431b
1 змінених файлів з 41 додано та 29 видалено
  1. 41 29
      h2d/col/Voronoi.hx

+ 41 - 29
h2d/col/Voronoi.hx

@@ -331,12 +331,23 @@ class Cell {
     }
 	
 	public function getCircle() {
+		// still not the best enclosing circle
+		// would require implementing http://www.personal.kent.edu/~rmuhamma/Compgeometry/MyCG/CG-Applets/Center/centercli.htm for complete solution
+		var p = new Point(), ec = 0;
+		for( e in halfedges ) {
+			var ep = e.getStartpoint();
+			p.x += ep.x;
+			p.y += ep.y;
+			ec++;
+		}
+		p.x /= ec;
+		p.y /= ec;
 		var r = 0.;
 		for( e in halfedges ) {
-			var d = point.distanceSq(e.getStartpoint());
+			var d = p.distanceSq(e.getStartpoint());
 			if( d > r ) r = d;
 		}
-		return new Circle(point.x, point.y, h3d.FMath.sqrt(r));
+		return new Circle(p.x, p.y, h3d.FMath.sqrt(r));
 	}
 
 	public function prepare() {
@@ -536,6 +547,7 @@ private class CircleEvent extends RBNode<CircleEvent> {
 
 class Voronoi {
 	
+	var epsilon : Float;
 	var beachline : RBTree<Beachsection>;
 	var vertices : Array<Point>;
 	var edges : Array<Edge>;
@@ -546,7 +558,8 @@ class Voronoi {
 	var firstCircleEvent : CircleEvent;
 	var pointCell : Map<Point,Cell>;
 
-	public function new() {
+	public function new( epsilon = 1e-9 ) {
+		this.epsilon = epsilon;
 		this.vertices = null;
 		this.edges = null;
 		this.cells = null;
@@ -576,13 +589,12 @@ class Voronoi {
 		this.cells = [];
 	}
 
-	static inline var EPSILON = 1e-9;
 	static inline function abs(x:Float) return x < 0 ? -x : x;
-	inline function equalWithEpsilon(a:Float,b:Float) return abs(a-b)<EPSILON;
-	inline function greaterThanWithEpsilon(a:Float,b:Float) return a-b>EPSILON;
-	inline function greaterThanOrEqualWithEpsilon(a:Float,b:Float) return b-a<EPSILON;
-	inline function lessThanWithEpsilon(a:Float,b:Float) return b-a>EPSILON;
-	inline function lessThanOrEqualWithEpsilon(a:Float,b:Float) return a-b<EPSILON;
+	inline function equalWithepsilon(a:Float,b:Float) return abs(a-b)<epsilon;
+	inline function greaterThanWithepsilon(a:Float,b:Float) return a-b>epsilon;
+	inline function greaterThanOrEqualWithepsilon(a:Float,b:Float) return b-a<epsilon;
+	inline function lessThanWithepsilon(a:Float,b:Float) return b-a>epsilon;
+	inline function lessThanOrEqualWithepsilon(a:Float,b:Float) return a-b<epsilon;
 
 	function createVertex(x, y) {
 		var v = new Point(x, y);
@@ -759,7 +771,7 @@ class Voronoi {
 
 		// look left
 		var lArc = previous;
-		while (lArc.circleEvent != null && abs(x-lArc.circleEvent.x)<1e-9 && abs(y-lArc.circleEvent.ycenter)<1e-9) {
+		while (lArc.circleEvent != null && abs(x-lArc.circleEvent.x)<epsilon && abs(y-lArc.circleEvent.ycenter)<epsilon) {
 			previous = lArc.rbPrevious;
 			disappearingTransitions.unshift(lArc);
 			this.detachBeachsection(lArc); // mark for reuse
@@ -774,7 +786,7 @@ class Voronoi {
 
 		// look right
 		var rArc = next;
-		while (rArc.circleEvent != null && abs(x-rArc.circleEvent.x)<1e-9 && abs(y-rArc.circleEvent.ycenter)<1e-9) {
+		while (rArc.circleEvent != null && abs(x-rArc.circleEvent.x)<epsilon && abs(y-rArc.circleEvent.ycenter)<epsilon) {
 			next = rArc.rbNext;
 			disappearingTransitions.push(rArc);
 			this.detachBeachsection(rArc); // mark for reuse
@@ -825,8 +837,8 @@ class Voronoi {
 
 		while (node != null) {
 			dxl = this.leftBreakPoint(node,directrix)-x;
-			// x lessThanWithEpsilon xl => falls somewhere before the left edge of the beachsection
-			if (dxl > 1e-9) {
+			// x lessThanWithepsilon xl => falls somewhere before the left edge of the beachsection
+			if (dxl > epsilon) {
 				// this case should never happen
 				// if (!node.rbLeft) {
 				//    rArc = node.rbLeft;
@@ -836,8 +848,8 @@ class Voronoi {
 				}
 			else {
 				dxr = x-this.rightBreakPoint(node,directrix);
-				// x greaterThanWithEpsilon xr => falls somewhere after the right edge of the beachsection
-				if (dxr > 1e-9) {
+				// x greaterThanWithepsilon xr => falls somewhere after the right edge of the beachsection
+				if (dxr > epsilon) {
 					if (node.rbRight == null) {
 						lArc = node;
 						break;
@@ -845,13 +857,13 @@ class Voronoi {
 					node = node.rbRight;
 					}
 				else {
-					// x equalWithEpsilon xl => falls exactly on the left edge of the beachsection
-					if (dxl > -1e-9) {
+					// x equalWithepsilon xl => falls exactly on the left edge of the beachsection
+					if (dxl > -epsilon) {
 						lArc = node.rbPrevious;
 						rArc = node;
 						}
-					// x equalWithEpsilon xr => falls exactly on the right edge of the beachsection
-					else if (dxr > -1e-9) {
+					// x equalWithepsilon xr => falls exactly on the right edge of the beachsection
+					else if (dxr > -epsilon) {
 						lArc = node;
 						rArc = node.rbNext;
 						}
@@ -1308,7 +1320,7 @@ class Voronoi {
 			// edge is removed if:
 			//   it is wholly outside the bounding box
 			//   it is actually a point rather than a line
-			if (!this.connectEdge(edge, bbox) || !this.clipEdge(edge, bbox) || (abs(edge.va.x-edge.vb.x)<1e-9 && abs(edge.va.y-edge.vb.y)<1e-9)) {
+			if (!this.connectEdge(edge, bbox) || !this.clipEdge(edge, bbox) || (abs(edge.va.x-edge.vb.x)<epsilon && abs(edge.va.y-edge.vb.y)<epsilon)) {
 				edge.va = edge.vb = null;
 				edges.splice(iEdge,1);
 			}
@@ -1356,26 +1368,26 @@ class Voronoi {
 				startpoint = halfedges[iRight].getStartpoint();
 				// if end point is not equal to start point, we need to add the missing
 				// halfedge(s) to close the cell
-				if (abs(endpoint.x-startpoint.x)>=1e-9 || abs(endpoint.y-startpoint.y)>=1e-9) {
+				if (abs(endpoint.x-startpoint.x)>=epsilon || abs(endpoint.y-startpoint.y)>=epsilon) {
 					// if we reach this point, cell needs to be closed by walking
 					// counterclockwise along the bounding box until it connects
 					// to next halfedge in the list
 					va = endpoint;
 					// walk downward along left side
-					if (this.equalWithEpsilon(endpoint.x,xl) && this.lessThanWithEpsilon(endpoint.y,yb)) {
-						vb = this.createVertex(xl, this.equalWithEpsilon(startpoint.x,xl) ? startpoint.y : yb);
+					if (this.equalWithepsilon(endpoint.x,xl) && this.lessThanWithepsilon(endpoint.y,yb)) {
+						vb = this.createVertex(xl, this.equalWithepsilon(startpoint.x,xl) ? startpoint.y : yb);
 					}
 					// walk rightward along bottom side
-					else if (this.equalWithEpsilon(endpoint.y,yb) && this.lessThanWithEpsilon(endpoint.x,xr)) {
-						vb = this.createVertex(this.equalWithEpsilon(startpoint.y,yb) ? startpoint.x : xr, yb);
+					else if (this.equalWithepsilon(endpoint.y,yb) && this.lessThanWithepsilon(endpoint.x,xr)) {
+						vb = this.createVertex(this.equalWithepsilon(startpoint.y,yb) ? startpoint.x : xr, yb);
 					}
 					// walk upward along right side
-					else if (this.equalWithEpsilon(endpoint.x,xr) && this.greaterThanWithEpsilon(endpoint.y,yt)) {
-						vb = this.createVertex(xr, this.equalWithEpsilon(startpoint.x,xr) ? startpoint.y : yt);
+					else if (this.equalWithepsilon(endpoint.x,xr) && this.greaterThanWithepsilon(endpoint.y,yt)) {
+						vb = this.createVertex(xr, this.equalWithepsilon(startpoint.x,xr) ? startpoint.y : yt);
 					}
 					// walk leftward along top side
-					else if (this.equalWithEpsilon(endpoint.y,yt) && this.greaterThanWithEpsilon(endpoint.x,xl)) {
-						vb = this.createVertex(this.equalWithEpsilon(startpoint.y,yt) ? startpoint.x : xl, yt);
+					else if (this.equalWithepsilon(endpoint.y,yt) && this.greaterThanWithepsilon(endpoint.x,xl)) {
+						vb = this.createVertex(this.equalWithepsilon(startpoint.y,yt) ? startpoint.x : xl, yt);
 					}
 					edge = this.createBorderEdge(cell.point, va, vb);
 					halfedges.insert(iLeft+1, new Halfedge(edge, cell.point, null));