123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229# 1 "easymesh/mesh_easymeshFC.ml"(* FORTRAN/C functions *)openPrintfopenScanfopenBigarraytypepslg=fortran_layoutMesh_common.pslgtypemesh=fortran_layoutMesh_common.t(* Write the [pslg] to the channel [fh]. *)letoutput_pslgfh(pslg:pslg)area=letpt=pslg#pointandseg=pslg#segmentandpt_marker=pslg#point_markerandseg_marker=pslg#segment_markerinletpt_marker=ifArray1.dimpt_marker>0then(funi->pt_marker.{i})else(fun_i->1)inletseg_marker=ifArray1.dimseg_marker>0then(funi->seg_marker.{i})else(fun_i->1)in(* Save points coordinates *)fprintffh"%i\n"(Array2.dim2(pt));(* number of nodes *)fori=1toArray2.dim2(pt)do(* EasyMesh expects indexes in 0 .. nnodes-1 *)fprintffh"%i: %.13g %.13g %.13g %i\n"(i-1)(pt.{1,i})(pt.{2,i})area(pt_markeri)done;(* Save segments *)fprintffh"%i\n"(Array2.dim2(seg));(* number of segments *)fori=1toArray2.dim2(seg)dofprintffh"%i: %i %i %i\n"(i-1)(seg.{1,i}-1)(seg.{2,i}-1)(seg_markeri)done(* FIXME: comments are possible in the files *)(* FIXME: if a file does not exists, return empty array? *)(* [read_fortran fname] reads the collection of filenames [fname].n,
[fname].e and [fname].s and creates a mesh struture with fortran
layout. This function can throw a variety of exceptions depending
of what goes wrong. *)letread(pslg:pslg)fname:mesh=(* Read nodes *)letfh=open_in(fname^".n")inletnnodes=int_of_string(input_linefh)inletpt=Array2.create(float64)fortran_layout(2)(nnodes)inletpt_marker=Array1.create(int)fortran_layout(nnodes)inletsb=Scanning.from_channelfhinfor_i=1toArray2.dim2(pt)dobscanfsb" %i: %g %g %i"(funixym->leti=i+1inpt.{1,i}<-x;pt.{2,i}<-y;pt_marker.{i}<-m)done;close_infh;(* Read triangles *)letfh=open_in(fname^".e")inletn=int_of_string(input_linefh)inlettr=Array2.create(int)fortran_layout(3)(n)andtr_nbh=Array2.create(int)fortran_layout(3)(n)inletsb=Scanning.from_channelfhinfor_i=1toArray2.dim2(tr)dobscanfsb" %i: %i %i %i %i %i %i %_i %_i %_i %_f %_f %_i"(funeijkeiejek->lete=e+1intr.{1,e}<-i+1;tr.{2,e}<-j+1;tr.{3,e}<-k+1;tr_nbh.{1,e}<-ei+1;tr_nbh.{2,e}<-ej+1;tr_nbh.{3,e}<-ek+1;)done;close_infh;try(* Read edges, if file exists *)letfh=open_in(fname^".s")inletn=int_of_string(input_linefh)inletedge=Array2.create(int)fortran_layout(2)(n)andedge_marker=Array1.create(int)fortran_layout(n)inletsb=Scanning.from_channelfhinfor_i=1toArray2.dim2(edge)dobscanfsb" %i: %i %i %_i %_i %i"(funscdm->lets=s+1inedge.{1,s}<-c+1;edge.{2,s}<-d+1;edge_marker.{s}<-m;)done;close_infh;(Mesh_common.make_mesh~point:pt~point_marker:pt_marker~triangle:tr~neighbor:tr_nbh~edge:edge~edge_marker:edge_marker~segment:pslg#segment~segment_marker:pslg#segment_marker~hole:pslg#hole~region:pslg#region)withSys_error_->(Mesh_common.make_mesh~point:pt~point_marker:pt_marker~triangle:tr~neighbor:tr_nbh~edge:(Array2.create(int)fortran_layout(2)(0))~edge_marker:(Array1.create(int)fortran_layout(0))~segment:pslg#segment~segment_marker:pslg#segment_marker~hole:pslg#hole~region:pslg#region)letempty_pslg:pslg=letempty_mat=Array2.create(float64)fortran_layout(2)(0)andempty_int_mat=Array2.create(int)fortran_layout(2)(0)andempty_vec=Array1.create(int)fortran_layout(0)in(objectmethodpoint=empty_matmethodpoint_marker=empty_vecmethodsegment=empty_int_matmethodsegment_marker=empty_vecmethodhole=empty_matmethodregion=empty_matend)(* [sort3 a b c] sort [a], [b], [c] from the larger to the smaller *)letsort3(a:int)bc=ifa>bthenifa<=cthen(c,a,b)elseifb>cthen(a,b,c)else(a,c,b)else(* a <= b *)ifb<=cthen(c,b,a)elseifa>cthen(b,a,c)else(b,c,a)letwrite(mesh:mesh)file=(* Compute the information needed by easymesh *)letpt=mesh#pointinletn=Array2.dim2ptinlettr=mesh#triangleinleted=mesh#edgein(* For two nodes (i,j), i > j, return the (at most) two triangles
sharing that edge. *)letpt_tr=Hashtbl.create(Array2.dim2(ed))infort=1toArray2.dim2(tr)doleti1,i2,i3=(* i1 > i2 > i3 *)sort3(tr.{1,t})(tr.{2,t})(tr.{3,t})inifi1=i2||i1=i3||i2=i3theninvalid_arg"Easymesh.write: illegal mesh (triangle corner indices)";Hashtbl.addpt_tr(i1,i2)t;Hashtbl.addpt_tr(i1,i3)t;Hashtbl.addpt_tr(i2,i3)t;done;(* For two nodes (i,j), i > j, give the index of the edge, if exists. *)letpt_ed=Hashtbl.create(Array2.dim2(ed))infore=1toArray2.dim2(ed)doleti=ed.{1,e}andj=ed.{2,e}inifi=jtheninvalid_arg"Easymesh.write: illegal mesh (egde enpoints)"elseifi>jthenHashtbl.addpt_ed(i,j)eelseHashtbl.addpt_ed(j,i)edone;(* Write [file].n *)letpt_marker=mesh#point_markerinletmarker=ifArray1.dimpt_marker=0then(fun_->1)else(funi->pt_marker.{i})inletfh=open_out(file^".n")infprintffh"%i\n"n;fori=1toArray2.dim2(pt)dofprintffh"%i: %.17g %.17g %i\n"(i-1)(pt.{1,i})(pt.{2,i})(markeri)done;close_outfh;(* Write [file].e *)letfh=open_out(file^".e")infprintffh"%i\n"(Array2.dim2(tr));letother_trianglei12t=(* assume i12 = (i1, i2) with i1 > i2 *)matchHashtbl.find_allpt_tri12with|[_]->-1(* no other triangle *)|[t1;t2]->ift1=tthent2-1elset1-1|_->assertfalseinfort=1toArray2.dim2(tr)doleti1,i2,i3=(* i1 > i2 > i3 *)sort3(tr.{1,t})(tr.{2,t})(tr.{3,t})inletx1=pt.{1,i1}andy1=pt.{2,i1}andx2=pt.{1,i2}andy2=pt.{2,i2}andx3=pt.{1,i3}andy3=pt.{2,i3}in(* Compute the circumcenter.
See http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html *)letx21=x2-.x1andy21=y2-.y1andx31=x3-.x1andy31=y3-.y1in(* FIXME: compute the determinant more accurately. *)letdet=2.*.(x21*.y31-.x31*.y21)inletd21=x21*.x21+.y21*.y21andd31=x31*.x31+.y31*.y31inletmx=x1-.(y21*.d31-.y31*.d21)/.detandmy=y1+.(x21*.d31-.x31*.d21)/.detinleti1'=(i2,i3)andi2'=(i1,i3)andi3'=(i1,i2)infprintffh"%i: %i %i %i %i %i %i %i %i %i %g %g 0\n"(t-1)(i1-1)(i2-1)(i3-1)(other_trianglei1't)(* opposite i1 *)(other_trianglei2't)(other_trianglei3't)(Hashtbl.findpt_edi1'-1)(Hashtbl.findpt_edi2'-1)(Hashtbl.findpt_edi3'-1)mxmydone;close_outfh;(* Write [file].s *)letfh=open_out(file^".s")infprintffh"%i\n"(Array2.dim2(ed));leted_marker=mesh#edge_markerinletmarker=ifArray1.dimed_marker=0then(fun_->1)else(fune->ed_marker.{e})infore=1toArray2.dim2(ed)doleti1=ed.{1,e}andi2=ed.{2,e}inleti12=ifi1>i2then(i1,i2)else(i2,i1)inlett1,t2=matchHashtbl.find_allpt_tri12with|[t1]->t1-1,-1|[t1;t2]->t1-1,t2-1|_->assertfalseinfprintffh"%i: %i %i %i %i %i\n"(e-1)(i1-1)(i2-1)t1t2(markere)done;close_outfh