2 Translated by Leonardo Fantascienza, downloaded from http://codepad.org/xGDCS3KO
3 Modified by Leandro Lucarella to be really quiet when -v is not used.
5 A D implementation of the Voronoi Olden benchmark. Voronoi
6 generates a random set of points and computes a Voronoi diagram for
9 L. Guibas and J. Stolfi. "General Subdivisions and Voronoi Diagrams"
10 ACM Trans. on Graphics 4(2):74-123, 1985.
12 The Java version of voronoi (slightly) differs from the C version
13 in several ways. The C version allocates an array of 4 edges and
14 uses pointer addition to implement quick rotate operations. The
15 Java version does not use pointer addition to implement these
19 time voronoi1_d -n 100000 -v
23 import tango.stdc.stdio: printf, fprintf, sprintf, stderr;
24 import tango.stdc.stdlib: exit;
25 import tango.math.Math: sqrt, exp, log;
26 import tango.stdc.time: CLOCKS_PER_SEC, clock;
27 import Integer = tango.text.convert.Integer;
28 alias Integer.parse toInt;
30 import std.c.stdio: printf, fprintf, sprintf, stderr;
31 import std.c.stdlib: exit;
32 import std.math: sqrt, exp, log;
33 import std.c.time: CLOCKS_PER_SEC, clock;
34 import std.conv: toInt;
39 return clock() / cast(double)CLOCKS_PER_SEC;
45 int length() { return data.length; }
46 bool empty() { return data.length == 0; }
47 void push(T item) { data ~= item; }
51 data.length = data.length - 1;
58 * A class that represents a wrapper around a double value so
59 * that we can use it as an 'out' parameter. The java.lang.Double
62 final class MyDouble {
69 public char* toCString() {
70 auto repr = new char[64];
71 sprintf(repr.ptr, "%f", value);
78 * Vector Routines from CMU vision library.
79 * They are used only for the Voronoi Diagram, not the Delaunay Triagulation.
80 * They are slow because of large call-by-value parameters.
88 this(double xx, double yy) {
94 final public double X() {
98 final public double Y() {
102 final public double Norm() {
106 final public void setNorm(double d) {
110 final public char* toCString() {
111 auto repr = new char[256];
112 sprintf(repr.ptr, "%f %f", x, y);
116 final Vec2 circle_center(Vec2 b, Vec2 c) {
118 double d1 = vv1.magn();
120 Vec2 vv2 = vv1.times(0.5);
122 // there is no intersection point, the bisectors coincide.
125 Vec2 vv3 = b.sub(this);
126 Vec2 vv4 = c.sub(this);
127 double d3 = vv3.cprod(vv4) ;
128 double d2 = -2.0 * d3 ;
130 double d4 = vv5.dot(vv4);
131 Vec2 vv6 = vv3.cross();
132 Vec2 vv7 = vv6.times(d4 / d2);
138 * cprod: forms triple scalar product of [u,v,k], where k = u cross v
139 * (returns the magnitude of u cross v in space)
141 final double cprod(Vec2 v) {
142 return x * v.y - y * v.x;
145 /* V2_dot: vector dot product */
146 final double dot(Vec2 v) {
147 return x * v.x + y * v.y;
150 /* V2_times: multiply a vector by a scalar */
151 final Vec2 times(double c) {
152 return new Vec2(c * x, c * y);
155 /* V2_sum, V2_sub: Vector addition and subtraction */
156 final Vec2 sum(Vec2 v) {
157 return new Vec2(x + v.x, y + v.y);
160 final Vec2 sub(Vec2 v) {
161 return new Vec2(x - v.x,y - v.y);
164 /* V2_magn: magnitude of vector */
165 final double magn() {
166 return sqrt(x * x + y * y);
169 /* returns k X v (cross product). this is a vector perpendicular to v */
171 return new Vec2(y, -x);
177 * A class that represents a voronoi diagram. The diagram is represnted
178 * as a binary tree of points.
180 final class Vertex : Vec2 {
182 * The left and right child of the tree that represents the voronoi diagram.
187 * Seed value used during tree creation.
193 this(double x, double y) {
199 public void setLeft(Vertex l) {
203 public void setRight(Vertex r) {
207 public Vertex getLeft() {
211 public Vertex getRight() {
216 * Generate a voronoi diagram
218 static Vertex createPoints(int n, MyDouble curmax, int i) {
222 Vertex cur = new Vertex();
223 Vertex right = Vertex.createPoints(n / 2, curmax, i);
225 cur.x = curmax.value * exp(log(Vertex.drand()) / i);
226 cur.y = Vertex.drand();
227 cur.norm = cur.x * cur.x + cur.y * cur.y;
229 curmax.value = cur.X();
230 Vertex left = Vertex.createPoints(n / 2, curmax, i - 1);
236 * Builds delaunay triangulation.
238 Edge buildDelaunayTriangulation(Vertex extra) {
239 EdgePair retVal = buildDelaunay(extra);
240 return retVal.getLeft();
244 * Recursive delaunay triangulation procedure
245 * Contains modifications for axis-switching division.
247 EdgePair buildDelaunay(Vertex extra) {
248 EdgePair retval = null;
249 if (getRight() !is null && getLeft() !is null) {
250 // more than three elements; do recursion
251 Vertex minx = getLow();
254 EdgePair delright = getRight().buildDelaunay(extra);
255 EdgePair delleft = getLeft().buildDelaunay(this);
257 retval = Edge.doMerge(delleft.getLeft(), delleft.getRight(),
258 delright.getLeft(), delright.getRight());
260 Edge ldo = retval.getLeft();
261 while (ldo.orig() != minx) {
264 Edge rdo = retval.getRight();
265 while (rdo.orig() != maxx) {
269 retval = new EdgePair(ldo, rdo);
271 } else if (getLeft() is null) {
273 Edge a = Edge.makeEdge(this, extra);
274 retval = new EdgePair(a, a.symmetric());
276 // left, !right three points
277 // 3 cases: triangles of 2 orientations, and 3 points on a line. */
278 Vertex s1 = getLeft();
281 Edge a = Edge.makeEdge(s1, s2);
282 Edge b = Edge.makeEdge(s2, s3);
283 a.symmetric().splice(b);
284 Edge c = b.connectLeft(a);
285 if (s1.ccw(s3, s2)) {
286 retval = new EdgePair(c.symmetric(), c);
288 retval = new EdgePair(a, b.symmetric());
301 Vertex tleft, tright;
303 printf("X=%f Y=%f\n", X(), Y());
315 * Traverse down the left child to the end
321 while ((temp=tree.getLeft()) !is null)
326 /****************************************************************/
327 /* Geometric primitives
328 ****************************************************************/
329 bool incircle(Vertex b, Vertex c, Vertex d) {
330 // incircle, as in the Guibas-Stolfi paper
331 double adx, ady, bdx, bdy, cdx, cdy, dx, dy, anorm, bnorm, cnorm, dnorm;
333 Vertex loc_a,loc_b,loc_c,loc_d;
335 int donedx,donedy,donednorm;
337 dx = loc_d.X(); dy = loc_d.Y(); dnorm = loc_d.Norm();
339 adx = loc_a.X() - dx; ady = loc_a.Y() - dy; anorm = loc_a.Norm();
341 bdx = loc_b.X() - dx; bdy = loc_b.Y() - dy; bnorm = loc_b.Norm();
343 cdx = loc_c.X() - dx; cdy = loc_c.Y() - dy; cnorm = loc_c.Norm();
344 dret = (anorm - dnorm) * (bdx * cdy - bdy * cdx);
345 dret += (bnorm - dnorm) * (cdx * ady - cdy * adx);
346 dret += (cnorm - dnorm) * (adx * bdy - ady * bdx);
347 return (0.0 < dret) ? true : false;
350 bool ccw(Vertex b, Vertex c) {
351 // TRUE iff this, B, C form a counterclockwise oriented triangle
353 double xa,ya, xb, yb, xc, yc;
354 Vertex loc_a, loc_b, loc_c;
355 int donexa, doneya, donexb, doneyb, donexc, doneyc;
366 dret = (xa-xc) * (yb-yc) - (xb-xc) * (ya-yc);
367 return (dret > 0.0)? true : false;
371 * A routine used by the random number generator
373 static int mult(int p,int q) {
375 int CONST_m1 = 10000;
377 p1 = p / CONST_m1; p0 = p % CONST_m1;
378 q1 = q / CONST_m1; q0 = q % CONST_m1;
379 return ((p0 * q1 + p1 * q0) % CONST_m1) * CONST_m1 + p0 * q0;
383 * Generate the nth random number
385 static int skiprand(int seed, int n) {
391 static int random(int seed) {
392 int CONST_b = 31415821;
394 seed = mult(seed, CONST_b) + 1;
398 static double drand() {
399 double retval = (cast(double)(Vertex.seed = Vertex.random(Vertex.seed))) /
400 cast(double)2147483647;
407 * A class that represents the quad edge data structure which implements
408 * the edge algebra as described in the algorithm.
410 * Each edge contains 4 parts, or other edges. Any edge in the group may
411 * be accessed using a series of rotate and flip operations. The 0th
412 * edge is the canonical representative of the group.
414 * The quad edge class does not contain separate information for vertice
415 * or faces; a vertex is implicitly defined as a ring of edges (the ring
416 * is created using the next field).
420 * Group of edges that describe the quad edge
425 * The position of this edge within the quad list
430 * The vertex that this edge represents
435 * Contains a reference to a connected quad edge
440 * Create a new edge which.
442 this(Vertex v, Edge[] ql, int pos) {
449 * Create a new edge which.
451 this(Edge[] ql, int pos) {
456 * Create a string representation of the edge
458 public char* toCString() {
460 return vertex.toCString();
465 public static Edge makeEdge(Vertex o, Vertex d) {
466 Edge ql[] = new Edge[4];
467 ql[0] = new Edge(ql, 0);
468 ql[1] = new Edge(ql, 1);
469 ql[2] = new Edge(ql, 2);
470 ql[3] = new Edge(ql, 3);
483 public void setNext(Edge n) {
488 * Initialize the data (vertex) for the edge's origin
490 public void setOrig(Vertex o) {
495 * Initialize the data (vertex) for the edge's destination
497 public void setDest(Vertex d) {
498 symmetric().setOrig(d);
506 return this.rotate().oNext().rotate();
510 return this.rotateInv().oNext().rotate();
514 return this.oNext().symmetric();
518 return this.rotate().oNext().rotateInv();
522 return this.symmetric().oNext();
526 return this.symmetric().oNext().symmetric();
530 return this.rotateInv().oNext().rotateInv();
538 return symmetric().orig();
542 * Return the symmetric of the edge. The symmetric is the same edge
543 * with the opposite direction.
544 * @return the symmetric of the edge
547 return quadList[(listPos + 2) % 4];
551 * Return the rotated version of the edge. The rotated version is a
552 * 90 degree counterclockwise turn.
553 * @return the rotated version of the edge
556 return quadList[(listPos + 1) % 4];
560 * Return the inverse rotated version of the edge. The inverse
561 * is a 90 degree clockwise turn.
562 * @return the inverse rotated edge.
565 return quadList[(listPos + 3) % 4];
568 Edge nextQuadEdge() {
569 return quadList[(listPos + 1) % 4];
572 Edge connectLeft(Edge b) {
579 ans = Edge.makeEdge(t1, t2);
581 ans.symmetric().splice(b);
585 Edge connectRight(Edge b) {
587 Edge ans, oprevb, q1;
593 ans = Edge.makeEdge(t1, t2);
594 ans.splice(symmetric());
595 ans.symmetric().splice(oprevb);
599 /****************************************************************/
600 /* Quad-edge manipulation primitives
601 ****************************************************************/
604 Edge syme = symmetric();
605 Edge b = syme.oPrev();
608 Edge lnexttmp = a.lNext();
610 lnexttmp = b.lNext();
611 syme.splice(lnexttmp);
612 Vertex a1 = a.dest();
613 Vertex b1 = b.dest();
618 void splice(Edge b) {
619 Edge alpha = oNext().rotate();
620 Edge beta = b.oNext().rotate();
621 Edge t1 = beta.oNext();
622 Edge temp = alpha.oNext();
631 bool valid(Edge basel) {
632 Vertex t1 = basel.orig();
633 Vertex t3 = basel.dest();
635 return t1.ccw(t2, t3);
641 f = symmetric().oPrev();
642 symmetric().splice(f);
645 static EdgePair doMerge(Edge ldo, Edge ldi, Edge rdi, Edge rdo) {
647 Vertex t3 = rdi.orig();
648 Vertex t1 = ldi.orig();
649 Vertex t2 = ldi.dest();
651 while (t1.ccw(t2, t3)) {
666 Edge basel = rdi.symmetric().connectLeft(ldi);
668 Edge lcand = basel.rPrev();
669 Edge rcand = basel.oPrev();
670 Vertex t1 = basel.orig();
671 Vertex t2 = basel.dest();
673 if (t1 == rdo.orig())
675 if (t2 == ldo.orig())
676 ldo = basel.symmetric();
679 Edge t = lcand.oNext();
680 if (t.valid(basel)) {
681 Vertex v4 = basel.orig();
683 Vertex v1 = lcand.dest();
684 Vertex v3 = lcand.orig();
685 Vertex v2 = t.dest();
686 while (v1.incircle(v2,v3,v4)){
698 if (t.valid(basel)) {
699 Vertex v4 = basel.dest();
700 Vertex v1 = t.dest();
701 Vertex v2 = rcand.dest();
702 Vertex v3 = rcand.orig();
703 while (v1.incircle(v2, v3, v4)) {
713 bool lvalid = lcand.valid(basel);
715 bool rvalid = rcand.valid(basel);
716 if ((!lvalid) && (!rvalid))
717 return new EdgePair(ldo, rdo);
719 Vertex v1 = lcand.dest();
720 Vertex v2 = lcand.orig();
721 Vertex v3 = rcand.orig();
722 Vertex v4 = rcand.dest();
723 if (!lvalid || (rvalid && v1.incircle(v2, v3, v4))) {
724 basel = rcand.connectLeft(basel.symmetric());
725 rcand = basel.symmetric().lNext();
727 basel = lcand.connectRight(basel).symmetric();
728 lcand = basel.rPrev();
737 * Print the voronoi diagram and its dual, the delaunay triangle for the
740 void outputVoronoiDiagram() {
742 // Plot voronoi diagram edges with one endpoint at infinity.
744 Vec2 v21 = nex.dest();
745 Vec2 v22 = nex.orig();
746 Edge tmp = nex.oNext();
747 Vec2 v23 = tmp.dest();
748 Vec2 cvxvec = v21.sub(v22);
749 Vec2 center = v22.circle_center(v21, v23);
752 Vec2 vv1 = v22.sum(v22);
753 Vec2 vv2 = vv1.times(0.5);
754 Vec2 vv3 = center.sub(vv2);
755 double ln = 1.0 + vv3.magn();
756 double d1 = ln / cvxvec.magn();
757 vv1 = cvxvec.cross();
758 vv2 = vv1.times(d1) ;
759 vv3 = center.sum(vv2);
760 printf("Vedge %s %s\n", center.toCString(), vv3.toCString());
762 } while (nex != this);
764 // plot delaunay triangle edges and finite VD edges.
765 Stack!(Edge) edges = new Stack!(Edge);
767 pushRing(edges, seen);
768 printf("no. of edges = %d\n", edges.length);
769 while (!edges.empty()) {
770 Edge edge = edges.pop();
771 if (edge in seen && seen[edge]) {
775 Vertex v1 = prev.orig();
777 Vertex v2 = prev.dest();
780 printf("Dedge %s %s\n", v1.toCString(), v2.toCString());
781 Edge sprev = prev.symmetric();
782 Edge snex = sprev.oNext();
785 Vertex v3 = nex.dest();
786 Vertex v4 = snex.dest();
787 if (v1.ccw(v2, v3) != v1.ccw(v2, v4)) {
788 Vec2 v21 = prev.orig();
789 Vec2 v22 = prev.dest();
790 Vec2 v23 = nex.dest();
791 Vec2 vv1 = v21.circle_center(v22, v23);
795 Vec2 vv2 = v21.circle_center(v22, v23);
796 printf("Vedge %s %s\n", vv1.toCString(), vv2.toCString());
802 } while (prev != edge);
804 edge.symmetric().pushRing(edges, seen);
808 void pushRing(Stack!(Edge) stack, ref bool[Edge] seen) {
810 while (nex != this) {
811 if (!(nex in seen)) {
819 void pushNonezeroRing(Stack!(Edge) stack, ref bool[Edge] seen) {
821 while (nex != this) {
833 * A class that represents an edge pair
835 final class EdgePair {
839 this(Edge l, Edge r) {
844 public Edge getLeft() {
848 public Edge getRight() {
856 * The number of points in the diagram
858 private static int points = 0;
861 * Set to true to print informative messages
863 private static bool printMsgs = false;
866 * Set to true to print the voronoi diagram and its dual,
867 * the delaunay diagram
869 private static bool printResults = false;
872 * The main routine which creates the points and then performs
873 * the delaunay triagulation.
874 * @param args the command line parameters
876 public static void main(char[][] args) {
880 printf("Getting %d points\n", points);
882 auto start0 = myclock();
884 Vertex extra = Vertex.createPoints(1, new MyDouble(1.0), points);
885 Vertex point = Vertex.createPoints(points-1, new MyDouble(extra.X()),
887 auto end0 = myclock();
890 printf("Doing voronoi on %d nodes\n", points);
892 auto start1 = myclock();
893 Edge edge = point.buildDelaunayTriangulation(extra);
894 auto end1 = myclock();
897 edge.outputVoronoiDiagram();
900 printf("Build time %f\n", end0 - start0);
901 printf("Compute time %f\n", end1 - start1);
902 printf("Total time %f\n", end1 - start0);
908 * Parse the command line options.
909 * @param args the command line options.
911 private static final void parseCmdLine(char[][] args) {
914 while (i < args.length && args[i][0] == '-') {
915 char[] arg = args[i++];
919 points = toInt(args[i++]);
921 throw new Exception("-n requires the number of points");
922 } else if (arg == "-p") {
924 } else if (arg == "-v") {
926 } else if (arg == "-h") {
936 * The usage routine which describes the program options.
938 private static final void usage() {
939 fprintf(stderr, "usage: voronoi_d -n <points> [-p] [-m] [-h]\n");
940 fprintf(stderr, " -n the number of points in the diagram\n");
941 fprintf(stderr, " -p (print detailed results/messages - the voronoi diagram>)\n");
942 fprintf(stderr, " -v (print informative message)\n");
943 fprintf(stderr, " -h (this message)\n");
949 void main(char[][] args) {