123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494# 1 "graphics/mesh_graphicsFC.ml"openPrintfopenBigarrayopenGraphicsopenMeshtypemesh=c_layoutttype'avector='avec(* global vec *)typevec=c_layoutvector(* local vec *)(* FIXME: naive, remove it when 4.00.0 will be spread enough *)lethypotxy=sqrt(x*.x+.y*.y)(** Return the smaller box (xmin, xmax, ymin, ymax) containing the [mesh]. *)letbounding_box(mesh:mesh)=letpt=mesh#pointinletxmin=refinfinityandxmax=refneg_infinityandymin=refinfinityandymax=refneg_infinityinfori=0toArray2.dim1(pt)-1doletx=pt.{i,0}andy=pt.{i,1}inifx>!xmaxthenxmax:=x;ifx<!xminthenxmin:=x;ify>!ymaxthenymax:=y;ify<!yminthenymin:=y;done;(!xmin,!xmax,!ymin,!ymax)(** Contains the information to transform "mesh coordinates" into the
graphics ones. *)typesurf={hx:float;hy:float;xbd:int;ybd:int;xmin:float;ymin:float};;letpixel_xsx=truncate((x-.s.xmin)*.s.hx)+s.xbdletpixel_ysy=truncate((y-.s.ymin)*.s.hy)+s.ybdletmake_surfmeshwidthheight=letxmin,xmax,ymin,ymax=bounding_boxmeshinlethx=floatwidth/.(xmax-.xmin)andhy=floatheight/.(ymax-.ymin)inlet(xbd,ybd)=current_point()in{hx=hx;hy=hy;xbd=xbd;ybd=ybd;xmin=xmin;ymin=ymin}letdraw?(width=600)?(height=600)?(color=foreground)?(points=true)?point_idx?triangle_idx?voronoi?point_marker_color(mesh:mesh)=letsurf=make_surfmeshwidthheightin(* Triangles and Points *)letpt=mesh#pointandtriangle=mesh#triangleinlettriangle_idx=matchtriangle_idxwith|None->(fun_______->())|Somef->(funtx0y0x1y1x2y2->(* Move to the incenter of the triangle. *)letd01=hypot(x0-.x1)(y0-.y1)andd02=hypot(x0-.x2)(y0-.y2)andd12=hypot(x1-.x2)(y1-.y2)inletd=d12+.d02+.d01inletx=(d12*.x0+.d02*.x1+.d01*.x2)/.dandy=(d12*.y0+.d02*.y1+.d01*.y2)/.dinmoveto(pixel_xsurfx)(pixel_ysurfy);ft;set_colorcolor)inset_colorcolor;fort=0toArray2.dim1(triangle)-1do(* Draw triangle [t]. *)leti0=triangle.{t,0}andi1=triangle.{t,1}andi2=triangle.{t,2}intryletx0=pt.{i0,0}andy0=pt.{i0,1}inletx1=pt.{i1,0}andy1=pt.{i1,1}inletx2=pt.{i2,0}andy2=pt.{i2,1}inletpx0=pixel_xsurfx0andpy0=pixel_ysurfy0inletpx1=pixel_xsurfx1andpy1=pixel_ysurfy1inletpx2=pixel_xsurfx2andpy2=pixel_ysurfy2indraw_segments[|(px0,py0,px1,py1);(px1,py1,px2,py2);(px2,py2,px0,py0)|];triangle_idxtx0y0x1y1x2y2;withe->eprintf"Mesh_display: triangle %i (%i,%i,%i): %s\n%!"ti0i1i2(Printexc.to_stringe)done;letmarker=matchpoint_marker_colorwith|None->(fun___->())|Somec->(funmpxpy->set_colorc;movetopxpy;draw_string(string_of_intm);set_colorcolor)inletpoint_idx=matchpoint_idxwith|None->(fun____->())|Somef->(fun_spxpyi->movetopxpy;fi;set_colorcolor)inifpointsthenbeginletpt_marker=mesh#point_markerinfori=0toArray2.dim1(pt)-1doletx=pt.{i,0}andy=pt.{i,1}inletpx=pixel_xsurfxandpy=pixel_ysurfyinfill_circlepxpy3;(* draw point *)point_idxsurfpxpyi;markerpt_marker.{i}pxpydone;end;(* Voronoi diagram *)beginmatchvoronoiwith|None->()|Some_vor->()(* FIXME: todo *)end;;typepoint={x:float;y:float}(* For level curves, we just draw a dot. *)letpoints_i{x=x;y=y}=draw_rect(pixel_xsx)(pixel_ysy)11letlinescolor{x=x0;y=y0}{x=x1;y=y1}=set_colorcolor;draw_segments[|(pixel_xsx0,pixel_ysy0,pixel_xsx1,pixel_ysy1)|]lettrianglescolor{x=x0;y=y0}{x=x1;y=y1}{x=x2;y=y2}=set_colorcolor;fill_poly[|(pixel_xsx0,pixel_ysy0);(pixel_xsx1,pixel_ysy1);(pixel_xsx2,pixel_ysy2)|]letrecarray_of_pointsspts=letl=List.lengthptsinletapts=Array.makel(0,0)infill_array_of_pointssapts0pts;aptsandfill_array_of_pointssaptsi=function|[]->()|pt::tl->apts.(i)<-(pixel_xspt.x,pixel_yspt.y);fill_array_of_pointssapts(i+1)tlletfill_triangle=triangleletfill_quadrilateralscolor{x=x0;y=y0}{x=x1;y=y1}{x=x2;y=y2}{x=x3;y=y3}=set_colorcolor;fill_poly[|(pixel_xsx0,pixel_ysy0);(pixel_xsx1,pixel_ysy1);(pixel_xsx2,pixel_ysy2);(pixel_xsx3,pixel_ysy3)|](************************************************************************)(* Include peformed by make_FC_code.ml *)(* Generic code to draw level cuves. To be included in a file that
defines the drawing primitives. *)moduleM=Map.Make(structtypet=intletcomparexy=compare(x:int)yend)(* Module to build a structure helping to determine when the segment
joining 2 points are on the boundary. *)moduleEdge=structletmake()=refM.emptyletadd_edgeti1i2=assert(i1<i2);tryletv=M.findi1!tinv:=i2::!vwithNot_found->t:=M.addi1(ref[i2])!t(* Declare the segment joining the points of indexes [i1] and [i2]
as being part of the boundary. It is auusmed that [i1 <> i2]. *)letaddti1i2=ifi1<i2thenadd_edgeti1i2elseadd_edgeti2i1leton_boundaryti1i2=assert(i1<i2);tryletv=M.findi1!tinList.memi2!vwithNot_found->false(* Tells whether the segment (if any) joining the points of indices
[i1] and [i2] is on the boundary (according to the information in
[t]). It is assumed that [i1 <> i2]. *)letonti1i2=ifi1<i2thenon_boundaryti1i2elseon_boundaryti2i1end;;letdefault_level_eql1l2=abs_float(l1-.l2)<=1E-8*.(abs_floatl1+.abs_floatl2)letmidpq={x=0.5*.(p.x+.q.x);y=0.5*.(p.y+.q.y)}(* Intersection of the curve et level [l] and the line passing through
(x1,y1) and (x2,y2). [z1 <> z2] assumed. *)letintercept{x=x1;y=y1}z1{x=x2;y=y2}z2l=letd=z1-.z2anda=l-.z2andb=z1-.lin{x=(a*.x1+.b*.x2)/.d;y=(a*.y1+.b*.y2)/.d}letdraw_levels~boundary(mesh:mesh)(z:vec)?(level_eq=default_level_eq)levelssurf=letedge=mesh#edgeinletmarker=mesh#edge_markerinletpt=mesh#pointinifArray2.dim1(edge)=0theninvalid_arg("Mesh_graphics.level_curves: mesh#edge must be nonempty");ifArray2.dim2(edge)<>2theninvalid_arg("Mesh_graphics.level_curves: mesh#edge must have 2 rows (fortran)");ifArray1.dimmarker<Array2.dim1(edge)theninvalid_arg("Mesh_graphics.level_curves: dim mesh#edge_marker < number edges");ifArray2.dim1(pt)=0theninvalid_arg("Mesh_graphics.level_curves: mesh#point must be nonempty");ifArray2.dim2(pt)<>2theninvalid_arg("Mesh_graphics.level_curves: mesh#point must have 2 rows (fortran)");letbd=Edge.make()in(* Draw the boundary edges *)fore=0toArray2.dim1(edge)-1doletm=marker.{e}inifm<>0(* not an interior point *)thenbeginleti1=edge.{e,0}andi2=edge.{e,1}inEdge.addbdi1i2;(* collect boundary points *)matchboundarymwith|None->()|Somecolor->letp1={x=pt.{i1,0};y=pt.{i1,1}}andp2={x=pt.{i2,0};y=pt.{i2,1}}inlinesurfcolorp1p2enddone;lettr=mesh#triangleinifArray2.dim1(tr)=0theninvalid_arg("Mesh_graphics.level_curves: mesh#triangle must be nonempty");ifArray2.dim2(tr)<3theninvalid_arg("Mesh_graphics.level_curves: mesh#triangle must have at least 3 \
rows (fortran) or 3 columns (C)");letmarker=mesh#point_markerinfort=0toArray2.dim1(tr)-1doleti1=tr.{t,0}andi2=tr.{t,1}andi3=tr.{t,2}inletp1={x=pt.{i1,0};y=pt.{i1,1}}andz1=z.{i1}inletp2={x=pt.{i2,0};y=pt.{i2,1}}andz2=z.{i2}inletp3={x=pt.{i3,0};y=pt.{i3,1}}andz3=z.{i3}inList.iter(fun(l,color)->(* Draw the level curve [l] on the triangle [t] except if
that curve is on the boundary. *)iflevel_eqlz1then(iflevel_eqlz2then(iflevel_eqlz3then(* The entire triangle is at the same level. Try to
remove boundary edges. *)ifEdge.onbdi1i2thenifEdge.onbdi1i3||Edge.onbdi2i3thentrianglesurfcolorp1p2p3(* Full triangle ! *)elselinesurfcolorp3(midp1p2)else(* i1-i2 not on boundary *)ifEdge.onbdi1i3thenifEdge.onbdi2i3thentrianglesurfcolorp1p2p3elselinesurfcolorp2(midp1p3)else(* i1-i3 not on boundary *)ifEdge.onbdi2i3thenlinesurfcolorp1(midp2p3)elsetrianglesurfcolorp1p2p3(* Full triangle ! *)else(* l = z1 = z2 <> z3 *)ifnot(Edge.onbdi1i2)thenlinesurfcolorp1p2)else(* l = z1 <> z2 *)iflevel_eqlz3then(* l = z1 = z3 <> z2 *)(ifnot(Edge.onbdi1i3)thenlinesurfcolorp1p3)elseif(z2<l&&l<z3)||(z3<l&&l<z2)thenlinesurfcolorp1(interceptp2z2p3z3l))elseifl<z1then(iflevel_eqlz2theniflevel_eqlz3then(ifnot(Edge.onbdi2i3)thenlinesurfcolorp2p3)elseifl>z3then(* z3 < l = z2 < z1 *)linesurfcolorp2(interceptp1z1p3z3l)else(* corner point, inside the domain. Ususally this
happens because the level line passes through a
triangle corner. *)(ifmarker.{i2}=0thenpointsurfi2p2)elseifl<z2then(iflevel_eqlz3then(ifmarker.{i3}=0thenpointsurfi3p3)elseifl>z3thenlinesurfcolor(interceptp1z1p3z3l)(interceptp2z2p3z3l))else(* z2 < l < z1 *)linesurfcolor(interceptp1z1p2z2l)(iflevel_eqlz3thenp3elseifl<z3theninterceptp2z2p3z3lelse(* l > z3 *)interceptp1z1p3z3l))else(* l > z1 *)((* Symmetric of [l < z1] with all inequalities reversed *)iflevel_eqlz2theniflevel_eqlz3then(ifnot(Edge.onbdi2i3)thenlinesurfcolorp2p3)elseifl<z3then(* z1 < l = z2 < z3 *)linesurfcolorp2(interceptp1z1p3z3l)else(* corner point, inside the domain *)(ifmarker.{i2}=0thenpointsurfi2p2)elseifl>z2then(iflevel_eqlz3then(ifmarker.{i3}=0thenpointsurfi3p3)elseifl<z3thenlinesurfcolor(interceptp1z1p3z3l)(interceptp2z2p3z3l))else(* z1 < l < z2 *)linesurfcolor(interceptp1z1p2z2l)(iflevel_eqlz3thenp3elseifl>z3theninterceptp2z2p3z3lelse(* l < z3 *)interceptp1z1p3z3l)))levelsdone;;typepolygon_fill=|Tri123(* triangle with edge 1 and cut in edges 2, 3 *)|Tri231|Tri312|Quad123(* Quadrilateral with edges 1-2 and 1-3 of the triangle cut *)|Quad231|Quad312|Whole|Empty;;(* base 3: c1 + 1 + 3(c2 + 1) + 9(c3 + 1). The [c1], [c2] and [c3]
are the comparisons of the 3 corners with the desired level. *)letindexc1c2c3=c1+3*c2+9*c3+13letsuper=letd=Array.make27Emptyind.(index(1)(1)(1))<-Whole;d.(index(1)(1)(0))<-Whole;d.(index(1)(1)(-1))<-Quad312;d.(index(1)(0)(1))<-Whole;d.(index(1)(0)(0))<-Whole;d.(index(1)(0)(-1))<-Tri123;d.(index(1)(-1)(1))<-Quad231;d.(index(1)(-1)(0))<-Tri123;d.(index(1)(-1)(-1))<-Tri123;d.(index(0)(1)(1))<-Whole;d.(index(0)(1)(0))<-Whole;d.(index(0)(1)(-1))<-Tri231;d.(index(0)(0)(1))<-Whole;d.(index(0)(0)(0))<-Empty;(* > 0 required *)d.(index(0)(0)(-1))<-Empty;d.(index(0)(-1)(1))<-Tri312;d.(index(0)(-1)(0))<-Empty;d.(index(0)(-1)(-1))<-Empty;d.(index(-1)(1)(1))<-Quad123;d.(index(-1)(1)(0))<-Tri231;d.(index(-1)(1)(-1))<-Tri231;d.(index(-1)(0)(1))<-Tri312;d.(index(-1)(0)(0))<-Empty;d.(index(-1)(0)(-1))<-Empty;d.(index(-1)(-1)(1))<-Tri312;d.(index(-1)(-1)(0))<-Empty;d.(index(-1)(-1)(-1))<-Empty;dletsub=letd=Array.make27Emptyind.(index(1)(1)(1))<-Empty;d.(index(1)(1)(0))<-Empty;d.(index(1)(1)(-1))<-Tri312;d.(index(1)(0)(1))<-Empty;d.(index(1)(0)(0))<-Empty;d.(index(1)(0)(-1))<-Tri312;d.(index(1)(-1)(1))<-Tri231;d.(index(1)(-1)(0))<-Tri231;d.(index(1)(-1)(-1))<-Quad123;d.(index(0)(1)(1))<-Empty;d.(index(0)(1)(0))<-Empty;d.(index(0)(1)(-1))<-Tri312;d.(index(0)(0)(1))<-Empty;d.(index(0)(0)(0))<-Empty;(* < 0 required *)d.(index(0)(0)(-1))<-Whole;d.(index(0)(-1)(1))<-Tri231;d.(index(0)(-1)(0))<-Whole;d.(index(0)(-1)(-1))<-Whole;d.(index(-1)(1)(1))<-Tri123;d.(index(-1)(1)(0))<-Tri123;d.(index(-1)(1)(-1))<-Quad231;d.(index(-1)(0)(1))<-Tri123;d.(index(-1)(0)(0))<-Whole;d.(index(-1)(0)(-1))<-Whole;d.(index(-1)(-1)(1))<-Quad312;d.(index(-1)(-1)(0))<-Whole;d.(index(-1)(-1)(-1))<-Whole;dletdraw_xxx_leveldecisionname?(boundary=(fun_->Someblack))(mesh:mesh)(z:vec)lcolorsurf=letedge=mesh#edgeinletedge_marker=mesh#edge_markerinletpt=mesh#pointinifArray2.dim1(edge)=0theninvalid_arg("Mesh_graphics"^name^": mesh#edge must be nonempty");ifArray2.dim2(edge)<>2theninvalid_arg("Mesh_graphics"^name^": mesh#edge must have 2 rows (fortran)");ifArray1.dimedge_marker<Array2.dim1(edge)theninvalid_arg("Mesh_graphics"^name^": dim mesh#edge_marker < number edges");ifArray2.dim1(pt)=0theninvalid_arg("Mesh_graphics"^name^": mesh#point must be nonempty");ifArray2.dim2(pt)<>2theninvalid_arg("Mesh_graphics"^name^": mesh#point must have 2 rows (fortran)");lettr=mesh#triangleinifArray2.dim1(tr)=0theninvalid_arg("Mesh_graphics"^name^": mesh#triangle must be nonempty");ifArray2.dim2(tr)<3theninvalid_arg("Mesh_graphics"^name^": mesh#triangle must have at least 3 \
rows (fortran) or 3 columns (C)");fort=0toArray2.dim1(tr)-1doleti1=tr.{t,0}andi2=tr.{t,1}andi3=tr.{t,2}inletp1={x=pt.{i1,0};y=pt.{i1,1}}andz1=z.{i1}inletp2={x=pt.{i2,0};y=pt.{i2,1}}andz2=z.{i2}inletp3={x=pt.{i3,0};y=pt.{i3,1}}andz3=z.{i3}inmatchdecision.(index(comparez1l)(comparez2l)(comparez3l))with|Tri123->fill_trianglesurfcolorp1(interceptp1z1p2z2l)(interceptp1z1p3z3l)|Tri231->fill_trianglesurfcolorp2(interceptp2z2p3z3l)(interceptp2z2p1z1l)|Tri312->fill_trianglesurfcolorp3(interceptp3z3p1z1l)(interceptp3z3p2z2l)|Quad123->fill_quadrilateralsurfcolor(interceptp1z1p2z2l)(interceptp1z1p3z3l)p3p2|Quad231->fill_quadrilateralsurfcolor(interceptp2z2p3z3l)(interceptp2z2p1z1l)p1p3|Quad312->fill_quadrilateralsurfcolor(interceptp3z3p1z1l)(interceptp3z3p2z2l)p2p1|Whole->fill_trianglesurfcolorp1p2p3|Empty->()done;(* Draw the boundary edges (over the filled area) *)fore=0toArray2.dim1(edge)-1doletm=edge_marker.{e}inifm<>0(* not an interior point *)thenbeginmatchboundarymwith|None->()|Somecolor->leti1=edge.{e,0}andi2=edge.{e,1}inletp1={x=pt.{i1,0};y=pt.{i1,1}}andp2={x=pt.{i2,0};y=pt.{i2,1}}inlinesurfcolorp1p2enddoneletdraw_super_level?boundarymeshzlevelcolorsurf=draw_xxx_levelsuper".super_level"?boundarymeshzlevelcolorsurfletdraw_sub_level?boundarymeshzlevelcolorsurf=draw_xxx_levelsub".sub_level"?boundarymeshzlevelcolorsurf;;(************************************************************************)letlevel_curves~width~height?(boundary=(fun_->Some0))(mesh:mesh)(z:vec)?level_eqlevels=letsurf=make_surfmeshwidthheightindraw_levels~boundarymeshz?level_eqlevelssurfletsuper_level~width~height?(boundary=(fun_->Some0))(mesh:mesh)(z:vec)levelcolor=letsurf=make_surfmeshwidthheightindraw_super_level~boundarymeshzlevelcolorsurfletsub_level~width~height?(boundary=(fun_->Some0))(mesh:mesh)(z:vec)levelcolor=letsurf=make_surfmeshwidthheightindraw_sub_level~boundarymeshzlevelcolorsurf