int countIntersections(path[] p, pair start, pair end)
{
int intersects=0;
for(path q : p)
intersects += intersections(start,end,q).length;
return intersects;
}
path[][] containmentTree(path[] paths)
{
path[][] result;
for(path g : paths) {
// check if current curve contains or is contained in a group of curves
int j;
for(j=0; j < result.length; ++j) {
path[] resultj=result[j];
int test=inside(g,resultj[0],zerowinding);
if(test == 1) {
// current curve contains group's toplevel curve;
// replace toplevel curve with current curve
resultj.insert(0,g);
// check to see if any other groups are contained within this curve
for(int k=j+1; k < result.length;) {
if(inside(g,result[k][0],zerowinding) == 1) {
resultj.append(result[k]);
result.delete(k);
} else ++k;
}
break;
} else if(test == -1) {
// current curve contained within group's toplevel curve
resultj.push(g);
break;
}
}
// create a new group if this curve does not belong to another group
if(j == result.length)
result.push(new path[] {g});
}
return result;
}
bool isDuplicate(pair a, pair b, real relSize)
{
return abs(a-b) <= duplicateFuzz*relSize;
}
path uncycle(path p, real t)
{
return subpath(p,t,t+length(p));
}
// returns outer paths
void connect(path[] paths, path[] result, path[] patch)
{
path[][] tree=containmentTree(paths);
for(path[] group : tree) {
path outer = group[0];
group.delete(0);
path[][] innerTree = containmentTree(group);
path[] remainingCurves;
path[] inners;
for(path[] innerGroup:innerTree)
{
inners.push(innerGroup[0]);
if(innerGroup.length>1)
remainingCurves.append(innerGroup[1:]);
}
connect(remainingCurves,result,patch);
real d=2*abs(max(outer)-min(outer));
while(inners.length > 0) {
int curveIndex = 0;
//pair direction=I*dir(inners[curveIndex],0,1); // Use outgoing direction
//if(direction == 0) // Try a random direction
// direction=expi(2pi*unitrand());
//pair start=point(inners[curveIndex],0);
// find shortest distance between a node on the inner curve and a node
// on the outer curve
real mindist = d;
int inner_i = 0;
int outer_i = 0;
for(int ni = 0; ni < length(inners[curveIndex]); ++ni)
{
for(int no = 0; no < length(outer); ++no)
{
real dist = abs(point(inners[curveIndex],ni)-point(outer,no));
if(dist < mindist)
{
inner_i = ni;
outer_i = no;
mindist = dist;
}
}
}
pair start=point(inners[curveIndex],inner_i);
pair end = point(outer,outer_i);
// find first intersection of line segment with outer curve
//real[][] ints=intersections(start,start+d*direction,outer);
real[][] ints=intersections(start,end,outer);
assert(ints.length != 0);
real endtime=ints[0][1]; // endtime is time on outer
end = point(outer,endtime);
// find first intersection of end--start with any inner curve
real starttime=inner_i; // starttime is time on inners[curveIndex]
real earliestTime=1;
for(int j=0; j < inners.length; ++j) {
real[][] ints=intersections(end,start,inners[j]);
if(ints.length > 0 && ints[0][0] < earliestTime) {
earliestTime=ints[0][0]; // time on end--start
starttime=ints[0][1]; // time on inner curve
curveIndex=j;
}
}
start=point(inners[curveIndex],starttime);