123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310# 1 "triangle/mesh_triangleFC.ml"(* Binding to Triangle for layout c_layout. *)openPrintfopenBigarrayopenMesh_triangle_commontypelayout=Bigarray.c_layouttypemesh=layoutttypemat=layoutMesh.mattypevec=layoutMesh.vectypeint_mat=layoutMesh.int_mattypeint_vec=layoutMesh.int_vecletlayout=Bigarray.c_layoutletdefault_switches="z"letempty_vec=Array1.createintlayout0letempty_mat0=Array2.create(float64)c_layout(0)(0)letempty_mat2=Array2.create(float64)c_layout(0)(2)letempty_mat4=Array2.create(float64)c_layout(0)(4)letpslg~hole~region~point_attribute~point_marker~point~segment_marker~segment=letpoint_marker=matchpoint_markerwith|None->empty_vec|Somem->letn=Array1.dimminif0<n&&n<Array2.dim1(point)theninvalid_arg"Mesh_triangle.pslg: point_marker too small";minletpoint_attribute=matchpoint_attributewith|None->empty_mat0|Somea->ifArray2.dim2(a)>0&&Array2.dim1(a)<>Array2.dim1(point)theninvalid_arg"Mesh_triangle.pslg: dim1 point_attribute <> dim1 point";ainletsegment_marker=matchsegment_markerwith|None->empty_vec|Somem->letn=Array1.dimminif0<n&&n<Array2.dim1(segment)theninvalid_arg"Mesh_triangle.pslg: segment_marker too small";minlethole=matchholewith|None->empty_mat2|Someh->ifArray2.dim1(h)>0&&Array2.dim2(h)<>2theninvalid_arg"Mesh_triangle.pslg: dim2 hole must be 2";hinletregion=matchregionwith|None->empty_mat4|Somer->ifArray2.dim1(r)>0&&Array2.dim2(r)<>4theninvalid_arg"Mesh_triangle.pslg: dim2 region must be 4";rin(objectmethodpoint=pointmethodpoint_marker=point_markermethodpoint_attribute=point_attributemethodsegment=segmentmethodsegment_marker=segment_markermethodhole=holemethodregion=regionend:c_layoutpslg)externaltriangle:string->(* options *)layoutt->vec(* trianglearea *)->mat*mat*int_vec*int_mat*mat*int_mat*int_mat*int_vec*(* edge *)int_mat*int_vec*(* voronoi *)mat*mat*int_mat*mat="triangulate_c_layout"letempty_vec=Array1.createfloat64layout0(* not used => global *)(* check that all C "triexit" have been avoided. *)lettriangulate?(delaunay=true)?min_angle?max_area?(region_area=false)?max_steiner?(voronoi=false)?(edge=true)?(neighbor=false)?(subparam=false)?triangle_area?triunsuitable?(check_finite=true)?(debug=true)?verbose~pslg~refine(mesh:layoutt)=(* Check points *)letpoint=mesh#pointinifArray2.dim2(point)<>2theninvalid_arg("dim2 mesh#point <> 2");ifArray2.dim1(mesh#point_attribute)>0&&Array2.dim1(mesh#point_attribute)<Array2.dim1(point)theninvalid_arg("dim1 mesh#point_attribute < dim1 mesh#point");ifArray1.dimmesh#point_marker>0&&Array1.dimmesh#point_marker<Array2.dim1(point)theninvalid_arg("dim mesh#point_marker < dim1 mesh#point");ifcheck_finitethen((* Check that no point contains NaN (or infinities). Triangle
seems to go into an infinite loop with these which can easily
be confused with other difficulties. *)fori=0toArray2.dim1(point)doifnot(is_finite(point.{i,0}))theninvalid_arg(sprintf"mesh#point.{%i, %i} is not finite"(i)(0));ifnot(is_finite(point.{i,1}))theninvalid_arg(sprintf"mesh#point.{%i, %i} is not finite"(i)(1));done;);letswitches=Buffer.create20inBuffer.add_stringswitchesdefault_switches;(* Check for PSLG *)ifpslgthen(ifArray2.dim1(mesh#segment)>0thenbeginifArray2.dim2(mesh#segment)<>2theninvalid_arg("dim2 segment <> 2");ifArray1.dimmesh#segment_marker>0&&Array1.dimmesh#segment_marker<Array2.dim1(mesh#segment)theninvalid_arg("dim mesh#segment_marker < dim1 mesh#segment");end;ifnotrefinethen(lethole=mesh#holeinifArray2.dim1(hole)>0&&Array2.dim2(hole)<>2theninvalid_arg("dim2 hole <> 2");letregion=mesh#regioninifArray2.dim1(region)>0then(ifArray2.dim2(region)<>4theninvalid_arg("dim2 region <> 4");Buffer.add_charswitches'A';(* regional attributes *)ifregion_areathenBuffer.add_charswitches'a';(* area constraint *));ifcheck_finitethen(fori=0toArray2.dim1(hole)doifnot(is_finite(hole.{i,0}))theninvalid_arg(sprintf"mesh#hole.{%i, %i} is not finite"(i)(0));ifnot(is_finite(hole.{i,1}))theninvalid_arg(sprintf"mesh#hole.{%i, %i} is not finite"(i)(1));done;fori=0toArray2.dim1(region)doforj=0toArray2.dim2(region)doifnot(is_finite(region.{i,j}))theninvalid_arg(sprintf"mesh#region.{%i, %i} is not finite"(i)(j));donedone));Buffer.add_charswitches'p';ifArray2.dim2(mesh#segment)=0||Array2.dim1(mesh#segment)=0thenBuffer.add_charswitches'c';);(* Check for refinement -- triangles *)ifrefinethen(ifArray2.dim1(mesh#triangle)>0thenbeginifArray2.dim2(mesh#triangle)<3theninvalid_arg("dim2 mesh#triangle < 3");ifArray2.dim2(mesh#triangle_attribute)>0&&Array2.dim1(mesh#triangle_attribute)<Array2.dim1(mesh#triangle)theninvalid_arg("dim1 mesh#triangle_attribute < dim1 mesh#triangle");end;Buffer.add_charswitches'r';(* Check triangle_area *)(matchtriangle_areawith|Somea->ifArray1.dima<Array2.dim1(mesh#triangle)theninvalid_arg("dim triangle_area < dim1 mesh#triangle");Buffer.add_charswitches'a';|None->()););(* Area constraints *)(matchmax_areawith|None->()|Somea->bprintfswitches"a%f"a);lettriangle_area=matchtriangle_areawith|None->empty_vec|Somea->a(* for refinement only *)in(* Check for a triunsuitable function *)(matchtriunsuitablewith|None->()|Somef->register_triunsuitablef;Buffer.add_charswitches'u');(* Other switches *)ifdelaunaythenBuffer.add_charswitches'D';(matchmin_anglewith|None->()|Somea->ifa<0.||a>60.then(* required: 3 min_algle <= 180 *)Buffer.add_charswitches'q'else(* Angle may include a decimal point, but not exponential notation. *)bprintfswitches"d%f"a);(matchmax_steinerwith|None->()|Somea->bprintfswitches"S%i"a);ifvoronoithenBuffer.add_charswitches'v';ifedgethenBuffer.add_charswitches'e';ifneighborthenBuffer.add_charswitches'n';ifsubparamthenBuffer.add_stringswitches"o2";ifnotdebugthenBuffer.add_charswitches'Q';(matchverbosewith|Some`V->Buffer.add_stringswitches"V";|Some`VV->Buffer.add_stringswitches"V";|Some`VVV->Buffer.add_stringswitches"VVV";|None->());(* Call triangle and build the resulting objects *)letpoint,point_attribute,point_marker,triangle,triangle_attribute,neighbor,segment,segment_marker,edge,edge_marker,vor_point,vor_point_attribute,vor_edge,vor_normal=triangle(Buffer.contentsswitches)meshtriangle_areainletmesh_out:layoutt=(make_mesh~point:point~point_attribute:point_attribute~point_marker:point_marker~triangle:triangle~triangle_attribute:triangle_attribute~neighbor:neighbor~segment:segment~segment_marker:segment_marker~edge:edge~edge_marker:edge_marker~hole:mesh#hole~region:mesh#region)andvor:layoutvoronoi=(objectmethodpoint=vor_pointmethodpoint_attribute=vor_point_attributemethodedge=vor_edgemethodnormal=vor_normalend)in(mesh_out,vor)(* Sub
***********************************************************************)letsub(mesh:mesh)?(pos=0)len=letm,n_tr,cols_tr=Mesh__MeshC.internal_sub(mesh:>Mesh__MeshC.mesh)~posleninletpoint_attribute=ifArray2.dim2(mesh#point_attribute)=0||Array2.dim1(mesh#point_attribute)=0thenmesh#point_attributeelseArray2.sub_leftmesh#point_attributeposleninlettriangle_attribute=letold_att=mesh#triangle_attributeinifArray2.dim2(old_att)=0||Array2.dim1(old_att)=0thenold_attelse(letatt=Array2.create(float64)c_layout(n_tr)(Array2.dim2(old_att))inMesh__MeshC.iteri(funipi->forj=0toArray2.dim2(att)-1doatt.{i,j}<-old_att.{pi,j};done)cols_tr;att)inextend_meshm~point_attribute:point_attribute~triangle_attribute:triangle_attribute(* Permutations
***********************************************************************)letpermute_points_name="Mesh_triangle.permute_points"letdo_permute_points(old_mesh:mesh)(perm:int_vec)inv_perm:mesh=letmesh=Mesh__MeshC.do_permute_pointspermute_points_name(old_mesh:>Mesh__MeshC.mesh)perminv_permin(* Permute the attributes *)letold_attr:mat=old_mesh#point_attributeinletattr=Array2.create(float64)c_layout(Array2.dim1(old_attr))(Array2.dim2(old_attr))infori=0toArray2.dim1(old_attr)-1doletold_i=perm.{i}infora=0toArray2.dim2(old_attr)-1doattr.{i,a}<-old_attr.{old_i,a}donedone;extend_meshmesh~point_attribute:attr~triangle_attribute:old_mesh#triangle_attributeletpermute_points(mesh:mesh)~inv(perm:int_vec)=letinv_perm=Mesh__MeshC.inverse_permpermute_points_nameperminifinvthendo_permute_pointsmeshinv_permpermelsedo_permute_pointsmeshperminv_permletpermute_triangles_name="Mesh_triangle.permute_triangles"letdo_permute_triangles(old_mesh:mesh)(perm:int_vec):mesh=letmesh=Mesh__MeshC.do_permute_trianglespermute_triangles_name(old_mesh:>Mesh__MeshC.mesh)permin(* Permute attributes *)letold_attr:mat=old_mesh#triangle_attributeinletattr=Array2.create(float64)c_layout(Array2.dim1(old_attr))(Array2.dim2(old_attr))infori=0toArray2.dim1(old_attr)-1doletold_i=perm.{i}infora=0toArray2.dim2(old_attr)-1doattr.{i,a}<-old_attr.{old_i,a}donedone;extend_meshmesh~point_attribute:(old_mesh#point_attribute)~triangle_attribute:attrletpermute_triangles(mesh:mesh)~inv(perm:int_vec)=letinv_perm=Mesh__MeshC.inverse_permpermute_triangles_nameperminifinvthendo_permute_trianglesmeshinv_permelsedo_permute_trianglesmeshperm