123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430openPoint_libopenPoint_lib.InfixmoduleP=Point_libtypepoint=Ctypes.pointtypeabscissa=floattype'at'={sa:'a;sb:'a;sc:'a;sd:'a}typet=pointt'letinter_depth=ref15letdebug=falseletpt_ffmtp=Format.fprintffmt"{@[ %.20g,@ %.20g @]}"p.xp.yletprintfmtpt=Format.fprintffmt"@[{ %a,@ %a,@ %a,@ %a }@]@."pt_fpt.sapt_fpt.sbpt_fpt.scpt_fpt.sdletcreateabcd={sa=a;sb=b;sc=c;sd=d}letcreate_with_offset_offsabcd=createabcdletexplodes=(s.sa,s.sb,s.sc,s.sd)letreverse_conv{sa;sb;sc;sd}={sa=sd;sb=sc;sc=sb;sd=sa}letright_control_pointt=t.scletright_pointt=t.sdletleft_pointt=t.saletleft_control_pointt=t.sbletcubicabcdt=t*.(t*.((t*.(d+.(3.*.(b-.c))-.a))+.(3.*.(c-.(2.*.b)+.a)))+.(3.*.(b-.a)))+.a(* ((t^3)*(d - (3*c) + (3*b) - a)) + (3*(t^2)*(c - (2*b) + a)) +
* (3*t*(b - a)) + a*)(* d *. (t**3.) +. 3. *. c *. (t**2.) *. (1. -. t) +. 3. *. b *. (t**1.)
* *.(1. -. t)**2. +. a *. (1. -. t)**3.*)letpoint_ofst={x=cubics.sa.xs.sb.xs.sc.xs.sd.xt;y=cubics.sa.ys.sb.ys.sc.ys.sd.yt;}letpoint_of_sst=assert(0.<=t&&t<=1.);point_ofstletdirectionst=(* An expression as polynomial:
short but lots of point operations
(d-3*c+3*b-a)*t^2+(2*c-4*b+2*a)*t+b-a *)(*
t */ (t */ (s.sd -/ 3. */ (s.sc +/ s.sb) -/ s.sa) +/
2. */ (s.sc +/ s.sa -/ 2. */ s.sb)) +/ s.sb -/ s.sa
*)(* This expression is longer, but has less operations on points: *)((t**2.)*/s.sd)+/(((2.*.t)-.(3.*.(t**2.)))*/s.sc)+/((1.-.(4.*.t)+.(3.*.(t**2.)))*/s.sb)+/(-.((1.-.t)**2.)*/s.sa)(*
sqrt((a - b) d + c + (- b - a) c + b ) + c - 2 b + a
t = - -----------------------------------------------------]
d - 3 c + 3 b - a
*)(*
let extremum a b c d =
(* denominator *)
let eqa = (d -. a) +. (3.*.(b -. c)) in
(* *)
let eqb = 2.*.(c +. a -. (2.*.b)) in
let eqc = (b -. a) in
(*Format.printf "eqa : %f; eqb : %f; eqc : %f@." eqa eqb eqc;*)
let test s l = if 0.<=s && s<=1. then s::l else l in
if eqa = 0. then if eqb = 0. then []
else test (-. eqc /. eqb) []
else
(*let sol delta = (delta -. (2.*.b) +. a +. c)/.
(a -. d +. (3.*.(c -. b))) in*)
(*let delta = ((b*.b) -. (c*.(b +. a -. c)) +. (d*.(a -. b))) in*)
let sol delta = (delta -. c +. 2. *. b -. a) /. eqa in
let delta = (a -. b) *. d +. c *. c -. ( b +. a) *. c +. b *. b in
let delta2 = (eqb*.eqb) -. (4.*.eqa*.eqc) in
Format.printf "delta : %f delta2 : %f@." delta delta2;
match compare delta 0. with
| x when x<0 -> []
| 0 -> test (sol 0.) []
| _ ->
let delta = delta**0.5 in
test (sol delta) (test (sol (-.delta)) [])
(* let extremum a b c d =
* (\* denominator *\)
* let eqa = (d -. a) +. (3.*.(b -. c)) in
* (\* *\)
* let eqb = 2.*.(c +. a -. (2.*.b)) in
* let eqc = (b -. a) in
* (\*Format.printf "eqa : %f; eqb : %f; eqc : %f@." eqa eqb eqc;*\)
* let test s l = if 0.<=s && s<=1. then s::l else l in
* if eqa = 0. then if eqb = 0. then []
* else test (-. eqc /. eqb) []
* else
* (\*let sol delta = (delta -. (2.*.b) +. a +. c)/.
* (a -. d +. (3.*.(c -. b))) in*\)
* (\*let delta = ((b*.b) -. (c*.(b +. a -. c)) +. (d*.(a -. b))) in*\)
* let sol delta = (delta +. eqb) /. (-.2.*.eqa) in
* let delta = (eqb*.eqb) -. (4.*.eqa*.eqc) in
* (\*Format.printf "delta2 : %f; delta : %f@." delta2 delta;*\)
* match compare delta 0. with
* | x when x<0 -> []
* | 0 -> test (sol 0.) []
* | _ ->
* let delta = delta**0.5 in
* test (sol delta) (test (sol (-.delta)) []) *)
let remarkable a b c d =
let res = 0.::1.::(extremum a b c d) in
Format.printf "remarquable : %a@."
(fun fmt -> List.iter (Format.fprintf fmt "%f;")) res;
res
let precise_bounding_box s =
(*Format.printf "precise : %a@." print_spline s;*)
let x_remarq = List.map (apply_x cubic s) (apply_x remarkable s) in
let y_remarq = List.map (apply_y cubic s) (apply_y remarkable s) in
let x_max = List.fold_left Stdlib.max neg_infinity x_remarq in
let y_max = List.fold_left Stdlib.max neg_infinity y_remarq in
let x_min = List.fold_left Stdlib.min infinity x_remarq in
let y_min = List.fold_left Stdlib.min infinity y_remarq in
List.iter
(fun f ->
let x = apply_x cubic s f in
let y = apply_y cubic s f in
if not (x_min <= x && x <= x_max && y_min <= y && y <= y_max)
then begin
Format.eprintf "Error at %f(%f,%f): %a@." f x y print s;
List.iter (Format.eprintf " x:%f@.") x_remarq;
List.iter (Format.eprintf " y:%f@.") y_remarq;
end
)
(0.1::0.2::0.3::0.4::0.5::0.6::0.7::0.8::0.9::[]);
x_min,y_min,x_max,y_max
*)letapply_xfs=fs.sa.xs.sb.xs.sc.xs.sd.xletapply_yfs=fs.sa.ys.sb.ys.sc.ys.sd.yletapply4fs=fs.sas.sbs.scs.sdletf4fabcd=f(fab)(fcd)letbounding_boxs=letx_max=apply_x(f4Stdlib.max)sinlety_max=apply_y(f4Stdlib.max)sinletx_min=apply_x(f4Stdlib.min)sinlety_min=apply_y(f4Stdlib.min)sin(x_min,y_min,x_max,y_max)letmiddleab={x=(a.x*.0.5)+.(b.x*.0.5);y=(a.y*.0.5)+.(b.y*.0.5)}letbisectmiddlea=letb=ain(*D\leftarrow (C+D)/2*)letb={bwithsd=middleb.sdb.sc}in(*C\leftarrow (B+C)/2, D\leftarrow (C+D)/2*)letb={bwithsc=middleb.scb.sb}inletb={bwithsd=middleb.sdb.sc}in(*B\leftarrow (A+B)/2, C\leftarrow (B+C)/2, D\leftarrow(C+D)/2*)letb={bwithsb=middleb.sbb.sa}inletb={bwithsc=middleb.scb.sb}inletb={bwithsd=middleb.sdb.sc}inletc=ainletc={cwithsa=middlec.sac.sb}inletc={cwithsb=middlec.sbc.sc}inletc={cwithsa=middlec.sac.sb}inletc={cwithsc=middlec.scc.sd}inletc={cwithsb=middlec.sbc.sc}inletc={cwithsa=middlec.sac.sb}in(b,c)letbisect_pa=bisect(funab->(a*.0.5)+.(b*.0.5))aletbisecta=bisectmiddlealetrecprecise_bounding_box_aux~min~max~cmpcmins=letcmin'=mins.sbs.scinifcmpcmincmin'<=0thencminelseletcmin'=min(mins.sas.sd)cmin'inletcmax'=apply4(f4max)sinifcmpcmin'cmax'=0thencminelseletsa,sb=bisect_psinletcmin=minsa.sdcmininprecise_bounding_box_aux~min~max~cmp(precise_bounding_box_aux~min~max~cmpcminsa)sbletprecise_bounding_boxs=letf~min~max~cmp~maps=lets={sa=maps.sa;sb=maps.sb;sc=maps.sc;sd=maps.sd}inletcmin=mins.sas.sdinprecise_bounding_box_aux~min~max~cmpcminsin(f~min~max~cmp:(funab->compareab)s~map:(funp->p.x),f~min~max~cmp:(funab->compareab)s~map:(funp->p.y),f~min:max~max:min~cmp:(funab->-compareab)s~map:(funp->p.x),f~min:max~max:min~cmp:(funab->-compareab)s~map:(funp->p.y))lettest_inaminamaxbminbmax=amin<=bmax&&bmin<=amaxletis_intersectab=letax_min,ay_min,ax_max,ay_max=bounding_boxainletbx_min,by_min,bx_max,by_max=bounding_boxbintest_inax_minax_maxbx_minbx_max&&test_inay_minay_maxby_minby_maxlet_is_intersect_preciseab=letax_min,ay_min,ax_max,ay_max=precise_bounding_boxainletbx_min,by_min,bx_max,by_max=precise_bounding_boxbintest_inax_minax_maxbx_minbx_max&&test_inay_minay_maxby_minby_maxletintersect_foldfaccab=letrecauxaccabt1t2dt=function|0->ifis_intersectabthenf(t1+(dt/2),t2+(dt/2))accelseacc|n->ifis_intersectabthenletn=n-1anddt=dt/2inleta1,a2=bisectaandb1,b2=bisectbinletacc=auxacca1b1t1t2dtninletacc=auxacca1b2t1(t2+dt)dtninletacc=auxacca2b1(t1+dt)t2dtninletacc=auxacca2b2(t1+dt)(t2+dt)dtninaccelseaccinletnmax=int_of_float(2.**float_of_int(!inter_depth+1))inauxaccab00nmax!inter_depthexceptionFoundofint*intletone_intersectionab=letnmax=2.**float_of_int(!inter_depth+1)inletf_from_ix=float_of_intx*.(1./.nmax)intryintersect_fold(fun(x,y)()->raise(Found(x,y)))()ab;raiseNot_foundwithFound(t1,t2)->(f_from_it1,f_from_it2)moduleUF=Unionfindletintersectionab=ifa=bthen[]elseletrem_noisedeltamdelta=function|[]->[]|noisy->letuf=UF.initnoisyinletlinkselmsel=letsorted=List.fast_sort(funxy->compare(selx)(sely))noisyinletrecpassbef=function|[]->()|e::l->ifselbef-sele<=deltathen(ifabs(msele-mselbef)<=mdeltathenUF.unionebefuf;passbefl)else()inignore(List.fold_left(funaccbef->passbefacc;bef::acc)[]sorted)inlinkfstsnd;linksndfst;UF.fold_classes(funxacc->x::acc)[]ufinletnmax=2.**float_of_int(!inter_depth+1)inletl=intersect_fold(funxacc->x::acc)[]abinifdebugthenFormat.printf"@[%a@]@."(funfmt->List.iter(fun(f1,f2)->Format.fprintffmt"%i,%i"f1f2))l;letl=rem_noise(2*!inter_depth)(16*!inter_depth)linletf_from_ix=x*.(1./.nmax)inletres=List.rev_map(fun(x,y)->(f_from_ix,f_from_iy))linifdebugthenFormat.printf"@[%a@]@."(funfmt->List.iter(pt_ffmt))(List.map(fun(t1,t2)->point_ofat1-/point_ofbt2)res);restypesplit=Min|Max|InBetweenoft*tletsplitst=assert(0.<=t&&t<=1.);ift=1.thenMaxelseift=0.thenMinelselett0=(*_01_of_s s*)tinlet_1t0=1.-.t0inletb1=(t0*/s.sb)+/(_1t0*/s.sa)inletc1=(t0*.t0*/s.sc)+/(2.*.t0*._1t0*/s.sb)+/(_1t0*._1t0*/s.sa)inletd1=point_ofst0inleta2=d1inletc2=(_1t0*/s.sc)+/(t0*/s.sd)inletb2=(_1t0*._1t0*/s.sb)+/(2.*._1t0*.t0*/s.sc)+/(t0*.t0*/s.sd)inInBetween({swithsb=b1;sd=d1;sc=c1},{swithsa=a2;sb=b2;sc=c2})letnorm2ab=(a*.a)+.(b*.b)letis_possible(axmin,aymin,axmax,aymax)(bxmin,bymin,bxmax,bymax)=match(axmin>bxmax,aymin>bymax,axmax<bxmin,aymax<bymin)with|true,true,_,_->norm2(axmin-.bxmax)(aymin-.bymax)|_,_,true,true->norm2(axmax-.bxmin)(aymax-.bymin)|true,_,_,true->norm2(axmin-.bxmax)(aymax-.bymin)|_,true,true,_->norm2(axmax-.bxmin)(aymin-.bymax)|false,true,false,_->norm20.(aymin-.bymax)|false,_,false,true->norm20.(aymax-.bymin)|true,false,_,false->norm2(axmin-.bxmax)0.|_,false,true,false->norm2(axmax-.bxmin)0.|false,false,false,false->0.letdist_min_point({x=px;y=py}asp)s=(* TODO simplify *)letis_possible_ata=is_possible(bounding_boxa)(px,py,px,py)inletnmax=2.**float_of_int(!inter_depth+1)inletrecauxa((min,_)aspmin)t1dt=function|0->lett1=float_of_int(t1+(dt/2))/.nmaxinletpt1=point_ofst1inletdist=P.dist2pt1pinifdist<minthen(dist,t1)elsepmin|n->letdt=dt/2inletaf,al=bisectainletdist_af=is_possible_atafinletdist_al=is_possible_atalinletdoit((min,_)aspmin)distamt=ifdist<minthenauxampmintdt(n-1)elsepmininifdist_af<dist_althenletpmin=doitpmindist_afaft1indoitpmindist_alal(t1+dt)elseletpmin=doitpmindist_alal(t1+dt)indoitpmindist_afaft1inletpmin=(P.dist2(left_points)p,0.)inauxspmin0(int_of_floatnmax)!inter_depthletdist_min_splines1s2=letis_possible_atab=is_possible(bounding_boxa)(bounding_boxb)inletnmax=2.**float_of_int(!inter_depth+1)inletrecauxab((min,_)aspmin)t1t2dt=function|0->lett1=float_of_int(t1+(dt/2))/.nmaxinlett2=float_of_int(t2+(dt/2))/.nmaxinletap=point_ofs1t1inletbp=point_ofs2t2inletdist=norm2(ap.x-.bp.x)(ap.y-.bp.y)inifdist<minthen(dist,(t1,t2))elsepmin|n->letn=n-1inletdt=dt/2inletaf,al=bisectainletbf,bl=bisectbinletdoitdistambmt1t2((min,_)aspmin)=ifdist<minthenauxambmpmint1t2dtnelsepmininletl=[(af,bf,t1,t2);(af,bl,t1,t2+dt);(al,bf,t1+dt,t2);(al,bl,t1+dt,t2+dt);]inletl=List.map(fun(am,bm,t1,t2)->letdist=is_possible_atambmin(dist,doitdistambmt1t2))linletl=List.fast_sort(fun(da,_)(db,_)->comparedadb)linList.fold_left(funpmin(_,doit)->doitpmin)pminlinletpmin=(P.dist2(left_points1)(left_points2),(0.,0.))inauxs1s2pmin00(int_of_floatnmax)!inter_depthlettranslateta={sa=a.sa+/t;sb=a.sb+/t;sc=a.sc+/t;sd=a.sd+/t}lettransformta={sa=P.transformta.sa;sb=P.transformta.sb;sc=P.transformta.sc;sd=P.transformta.sd;}