12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849(* 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 Csg.mli *)type'aboundary={t:float;leaf:'a;flipped:bool}type'ainterval='aboundary*'aboundarytypeop=Union|Inter|Diffletflip(b:'aboundary):'aboundary={bwithflipped=notb.flipped}letcombine(op:op)(a:'aintervallist)(b:'aintervallist):'aintervallist=letholdsin_ain_b=matchopwithUnion->in_a||in_b|Inter->in_a&&in_b|Diff->in_a&¬in_bin(* the boundaries as events, (boundary, from A?, an entry?), by t;
* at the same t the entries first, so that [1, 2] and [2, 3] touch
* rather than part *)leteventssidel=List.concat_map(fun(i,o)->[(i,side,true);(o,side,false)])linletsorted=List.stable_sort(fun((b1:'aboundary),_,e1)((b2:'aboundary),_,e2)->matchFloat.compareb1.tb2.twith0->comparee2e1|c->c)(eventstruea@eventsfalseb)inletin_a=reffalseandin_b=reffalseandstart=refNoneandout=ref[]inList.iter(fun(bnd,from_a,entry)->letbefore=holds!in_a!in_biniffrom_athenin_a:=entryelsein_b:=entry;letafter=holds!in_a!in_bin(* the rule: an operand's exit as the result's entry, or its entry
* as the result's exit, turns the normal round *)if(notbefore)&&afterthenstart:=Some(ifentrythenbndelseflipbnd)elseifbefore&¬afterthenmatch!startwith|Somes->out:=(s,ifentrythenflipbndelsebnd)::!out;start:=None|None->())sorted;List.rev!outletinside(l:'aintervallist)(t:float):bool=List.exists(fun((i:'aboundary),(o:'aboundary))->i.t<=t&&t<=o.t)l