1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Cad_snap.mli *)moduleG=Cad_geommoduleD=Cad_drawingtypekind=Endpoint|Midpoint|Center|Quadrant|Intersection|Perpendicularletname=function|Endpoint->"Endpoint"|Midpoint->"Midpoint"|Center->"Center"|Quadrant->"Quadrant"|Intersection->"Intersection"|Perpendicular->"Perpendicular"(* a piece's own points, of each kind *)letpoints=function|G.Segment(a,b)->[(Endpoint,a);(Endpoint,b);(Midpoint,G.scale0.5(G.addab))]|G.Circle(c,r)->(Center,c)::List.map(funa->(Quadrant,G.polarcra))[0.;90.;180.;270.]|G.Arc(c,r,a0,a1)->lets,e=G.arc_endscra0a1inletmid=G.polarcr(a0+.(G.norm_angle(a1-.a0)/.2.))in[(Endpoint,s);(Endpoint,e);(Midpoint,mid);(Center,c)]@List.filter_map(funa->ifG.withina0a1athenSome(Quadrant,G.polarcra)elseNone)[0.;90.;180.;270.]letfind(t:D.t)~aperture?fromp=letpieces=List.concat_map(fun(_,(e:D.ent))->if(D.layerte.layer).onthenList.mapfst(D.pieceste)else[])t.entsin(* a center is caught from the rim too, as AutoCAD's was *)letnearc=G.distancecp<=aperture||matchcwithG.Circle(c,_)|G.Arc(c,_,_,_)->G.distcp<=aperture|_->falseinletclose=List.filternearpiecesinletown=List.concat_mappointscloseinletrecpairs=function[]->[]|c::cs->List.map(fund->(c,d))cs@pairscsinletcrossings=List.concat_map(fun(c,d)->List.map(funq->(Intersection,q))(G.intersectionscd))(pairsclose)inletbestcands=List.fold_left(funacc(k,q)->letd=G.distpqinifd>aperturethenaccelsematchaccwithSome(_,_,db)whendb<=d->acc|_->Some(k,q,d))Nonecands|>Option.map(fun(k,q,_)->(k,q))inletunder=List.filter(func->G.distancecp<=aperture)closeinmatchbest(own@crossings)with|Somes->Somes|None->((* the cursor on a circle's rim, far from any of its points: its
center, as AutoCAD's CENter caught it *)matchList.find_map(functionG.Circle(c,_)|G.Arc(c,_,_,_)->Somec|G.Segment_->None)underwith|Somec->Some(Center,c)|None->(match(from,under)with|Somef,c::_->letq=G.footcfinifG.on_piececqthenSome(Perpendicular,q)elseNone|_->None))