123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378(**************************************************************************)(* *)(* Ocamlgraph: a generic graph library for OCaml *)(* Copyright (C) 2004-2010 *)(* Sylvain Conchon, Jean-Christophe Filliatre and Julien Signoles *)(* *)(* This software is free software; you can redistribute it and/or *)(* modify it under the terms of the GNU Library General Public *)(* License version 2.1, with the special exception on linking *)(* described in file LICENSE. *)(* *)(* This software is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *)(* *)(**************************************************************************)(* $Id: delaunay.ml,v 1.12 2005-11-02 13:43:35 filliatr Exp $ *)(** Code follows Don Knuth's algorithm
from ``Axioms and hulls'' (LNCS 606, Springer-Verlag, 1992), pp. 73-77.
Some code and comments are taken from the Stanford Graph Base,
file [gb_plane].
*)moduletypeCCC=sigtypepointvalccw:point->point->point->boolvalin_circle:point->point->point->point->boolendmoduletypeTriangulation=sigmoduleS:CCCtypetriangulationvaltriangulate:S.pointarray->triangulationvaliter:(S.point->S.point->unit)->triangulation->unitvalfold:(S.point->S.point->'a->'a)->triangulation->'a->'avaliter_triangles:(S.point->S.point->S.point->unit)->triangulation->unitendmoduleMake(S:CCC)=structmoduleS=Stypepoint=Pointofint|Infinity(* Each edge of the current triangulation is represented by two arcs
pointing in opposite directions; the two arcs are called mates. Each
arc conceptually has a triangle on its left and a mate on its right. *)typearc={mutablevert:point;(* v, if this arc goes from u to v *)mutablenext:arc;(* the arc from v that shares a triangle with this one *)mutableinst:noderef;(* instruction to change when the triangle is modified *)mate:int}andnode=|Branchofint*int*noderef*noderef|Terminalofarctypetriangulation={points:S.pointarray;arcs:arcarray;last_used_arc:int}letrecdummy_arc={vert=Infinity;next=dummy_arc;inst=ref(Terminaldummy_arc);mate=-1}letmake_arcni={vert=Infinity;next=dummy_arc;inst=ref(Terminaldummy_arc);mate=6*n-7-i}letfinite=functionPointp->p|Infinity->assertfalse(* [flip] will be used in both steps T4 and T5 *)letflipcdet''pnn'=lete'=e.nextinletc'=c.nextinletc''=c'.nextine.next<-c;c.next<-c'';c''.next<-e;c''.inst<-n;c.inst<-n;e.inst<-n;c.vert<-Pointp;d.next<-e';e'.next<-c';c'.next<-d;c'.inst<-n';e'.inst<-n';d.inst<-n';d.vert<-Pointt''lettriangulatepoints=letccwpqr=S.ccwpoints.(p)points.(q)points.(r)inletin_circlepqrs=S.in_circlepoints.(p)points.(q)points.(r)points.(s)inletn=Array.lengthpointsinifn<2theninvalid_arg"triangulate";letarcs=Array.init(6*n-6)(make_arcn)inletmatei=6*n-7-iin(*i DEBUG
let rec dump d l =
eprintf "%s" (String.make (2*d) ' ');
match !l with
| Terminal a ->
eprintf "T %d\n" (mate a.mate)
| Branch (u, v, l, r) ->
eprintf "N %d %d\n" u v;
dump (d+1) l;
dump (d+1) r
in
i*)(* initialization:
create a trivial triangulation for the first 2 vertices *)letu=0inletv=1inleta1=arcs.(0)inleta2=arcs.(1)inleta3=arcs.(2)inletb1=arcs.(mate0)inletb2=arcs.(mate1)inletb3=arcs.(mate2)inletl1=ref(Terminala2)inletl2=ref(Terminalb3)ina1.vert<-Pointv;a1.next<-a2;a1.inst<-l1;a2.vert<-Infinity;a2.next<-a3;a2.inst<-l1;a3.vert<-Pointu;a3.next<-a1;a3.inst<-l1;b1.vert<-Pointu;b1.next<-b3;b1.inst<-l2;b2.vert<-Pointv;b2.next<-b1;b2.inst<-l2;b3.vert<-Infinity;b3.next<-b2;b3.inst<-l2;letl0=ref(Branch(u,v,l1,l2))inletj=ref2in(* last used arc *)(* then for each new vertex [p] *)forp=2ton-1do(* Step T1 *)letrecstep_T1lp=match!lwith|Terminalal->l,al|Branch(pl,ql,al,bl)->step_T1(ifccwplqlpthenalelsebl)pinletl,al=step_T1l0pin(* Step T2 *)leta=alinletb=a.nextinletc=b.nextinletq=a.vertinletr=b.vertinlets=c.vertinj:=!j+3;letaj=arcs.(!j)inletaj_1=arcs.(!j-1)inletaj_2=arcs.(!j-2)inletbj=arcs.(aj.mate)inletbj_1=arcs.(aj_1.mate)inletbj_2=arcs.(aj_2.mate)inletl'=ref(Terminala)inletl''=ref(Terminalaj)inletl'''=ref(Terminalc)inaj.vert<-q;aj.next<-b;aj.inst<-l'';aj_1.vert<-r;aj_1.next<-c;aj_1.inst<-l''';aj_2.vert<-s;aj_2.next<-a;aj_2.inst<-l';bj.vert<-Pointp;bj.next<-aj_2;bj.inst<-l';bj_1.vert<-Pointp;bj_1.next<-aj;bj_1.inst<-l'';bj_2.vert<-Pointp;bj_2.next<-aj_1;bj_2.inst<-l''';a.next<-bj;a.inst<-l';b.next<-bj_1;b.inst<-l'';c.next<-bj_2;c.inst<-l''';letr=finiterinlets=finitesin(* steps T3 or T4 depending on [q] *)letr=matchqwith|Pointq->(* Step T3 *)letn=ref(Branch(q,p,l',l''))inletn'=ref(Branch(s,p,l''',l'))inl:=Branch(r,p,n,n');r|Infinity->(* Step T4 *)letn=ref(Branch(s,p,l''',l'))inl:=Branch(r,p,l'',n);letrecloopmadst=ift<>r&&ccwpstthenbeginletn=ref(Terminald)inmatch!mwith|Branch(mu,mv,ml,is_l')->assert(is_l'==l');m:=Branch(mu,mv,ml,d.inst);d.inst:=Branch(t,p,n,l');letm=d.instinflipaarcs.(a.mate)dtpnl';leta=arcs.(a.mate).nextinletd=arcs.(a.mate).nextinlets=tinlett=finited.vertinl':=Terminala;loopmadst|Terminal_->assertfalseendelsebegin(* at exit of while loop *)letn=ref(Terminald.next)ind.inst:=Branch(s,p,n,l');d.inst<-n;d.next.inst<-n;d.next.next.inst<-n;sendinletd=arcs.(a.mate).nextinloopnads(finited.vert)in(* Step T5 *)letrecloopc=letd=arcs.(c.mate)inlete=d.nextinlett=finited.vertinlett'=finitec.vertinlett''=e.vertinift''<>Infinity&&in_circle(finitet'')t'tpthenbeginlett''=finitet''inletn=ref(Terminale)inletn'=ref(Terminald)inc.inst:=Branch(t'',p,n,n');d.inst:=Branch(t'',p,n,n');flipcdet''pnn';loopeendelseift'<>rthenlooparcs.(c.next.mate).nextelse()(* break *)inloopcdone;{points=points;arcs=arcs;last_used_arc=!j}letiterft=letpoints=t.pointsinletn=Array.lengtht.arcsinfori=0tot.last_used_arcdomatcht.arcs.(i).vert,t.arcs.(n-1-i).vertwith|Pointu,Pointv->fpoints.(u)points.(v)|_->()doneletiter_trianglesft=letn=Array.lengtht.arcsinletseen_arc=Array.makenfalseinletmatei=n-1-iinletindexa=matea.mateinfori=0ton-1doifnotseen_arc.(i)thenbeginleta1=t.arcs.(i)inleta2=a1.nextinleta3=a2.nextinseen_arc.(i)<-true;seen_arc.(indexa2)<-true;seen_arc.(indexa3)<-true;matcha1.vert,a2.vert,a3.vertwith|Pointi1,Pointi2,Pointi3->ft.points.(i1)t.points.(i2)t.points.(i3)|_->()enddoneletfoldfta=letpoints=t.pointsinletn=Array.lengtht.arcsinletrecloopia=ifi<=t.last_used_arcthenmatcht.arcs.(i).vert,t.arcs.(n-1-i).vertwith|Pointu,Pointv->loop(succi)(fpoints.(u)points.(v)a)|_->loop(succi)aelseainloop0aend(** Points with floating point coordinates *)moduleFloatPoints=structtypepoint=float*floatlet(+)=(+.)let(-)=(-.)let(*)=(*.)letdet=function|[|[|a00;a01|];[|a10;a11|]|]->a00*a11-a01*a10|[|[|a00;a01;a02|];[|a10;a11;a12|];[|a20;a21;a22|]|]->a00*a11*a22-a00*a12*a21-a10*a01*a22+a10*a02*a21+a20*a01*a12-a20*a02*a11|[|[|a00;a01;a02;a03|];[|a10;a11;a12;a13|];[|a20;a21;a22;a23|];[|a30;a31;a32;a33|]|]->a00*a11*a22*a33-a00*a11*a23*a32-a00*a21*a12*a33+a00*a21*a13*a32+a00*a31*a12*a23-a00*a31*a13*a22-a10*a01*a22*a33+a10*a01*a23*a32+a10*a21*a02*a33-a10*a21*a03*a32-a10*a31*a02*a23+a10*a31*a03*a22+a20*a01*a12*a33-a20*a01*a13*a32-a20*a11*a02*a33+a20*a11*a03*a32+a20*a31*a02*a13-a20*a31*a03*a12-a30*a01*a12*a23+a30*a01*a13*a22+a30*a11*a02*a23-a30*a11*a03*a22-a30*a21*a02*a13+a30*a21*a03*a12|_->assertfalseletccw(xu,yu)(xv,yv)(xw,yw)=det[|[|xu;yu;1.0|];[|xv;yv;1.0|];[|xw;yw;1.0|]|]>0.0(*i DEBUG
let ccw (xu,yu) (xv,yv) (xw,yw) =
eprintf "ccw((%.0f,%.0f),(%.0f,%.0f),(%.0f,%.0f)) -> "
xu yu xv yv xw yw;
let r = ccw (xu,yu) (xv,yv) (xw,yw) in
eprintf "%b\n" r; flush stderr;
r
i*)letin_circle(xt,yt)(xu,yu)(xv,yv)(xw,yw)=det[|[|xt;yt;(xt*xt+yt*yt);1.0|];[|xu;yu;(xu*xu+yu*yu);1.0|];[|xv;yv;(xv*xv+yv*yv);1.0|];[|xw;yw;(xw*xw+yw*yw);1.0|];|]>0.0(*i DEBUG
let in_circle (xt,yt) (xu,yu) (xv,yv) (xw,yw) =
eprintf "in_circle((%.0f,%.0f),(%.0f,%.0f),(%.0f,%.0f),(%.0f,%.0f)) -> "
xt yt xu yu xv yv xw yw;
let r = in_circle (xt,yt) (xu,yu) (xv,yv) (xw,yw) in
eprintf "%b\n" r; flush stderr;
r
i*)endmoduleFloat=Make(FloatPoints)(** Points with integer coordinates.
We approximate using module [FloatPoints] but this could be made exact
following Knuth's code in Axioms and Hulls *)moduleIntPoints=structtypepoint=int*intletccw(xu,yu)(xv,yv)(xw,yw)=FloatPoints.ccw(floatxu,floatyu)(floatxv,floatyv)(floatxw,floatyw)letin_circle(xt,yt)(xu,yu)(xv,yv)(xw,yw)=FloatPoints.in_circle(floatxt,floatyt)(floatxu,floatyu)(floatxv,floatyv)(floatxw,floatyw)endmoduleInt=Make(IntPoints)