calculate_INTERNAL method
Implementation
SegmentList calculate_INTERNAL(
bool primaryPolyInverted, bool secondaryPolyInverted) {
//
// main event loop
//
var segments = new SegmentList();
status_root = new StatusLinkedList();
while (!event_root.isEmpty) {
var ev = event_root.head;
//if (buildLog != null) buildLog.vert(ev.pt.x);
if (ev.isStart) {
// if (buildLog != null) {
// buildLog.segmentNew(ev.seg, ev.primary);
// }
var surrounding = statusFindSurrounding(ev);
var above = surrounding.before != null ? surrounding.before : null;
var below = surrounding.after != null ? surrounding.after : null;
// if( buildLog != null )
// {
// buildLog.tempStatus(
// ev.seg,
// above != null ? above.seg : (object)false,
// below != null ? below.seg : (object)false
// );
// }
var eve = checkBothIntersections(ev, above, below);
if (eve != null) {
// ev and eve are equal
// we'll keep eve and throw away ev
// merge ev.seg's fill information into eve.seg
if (selfIntersection) {
var toggle = false; // are we a toggling edge?
if (ev.seg.myFill.below == null)
toggle = true;
else
toggle = ev.seg.myFill.above != ev.seg.myFill.below;
// merge two segments that belong to the same polygon
// think of this as sandwiching two segments together, where `eve.seg` is
// the bottom -- this will cause the above fill flag to toggle
if (toggle) {
eve.seg.myFill.above = !eve.seg.myFill.above;
}
} else {
// merge two segments that belong to different polygons
// each segment has distinct knowledge, so no special logic is needed
// note that this can only happen once per segment in this phase, because we
// are guaranteed that all self-intersections are gone
eve.seg.otherFill = ev.seg.myFill;
}
// if (buildLog != null) {
// buildLog.segmentUpdate(eve.seg);
// }
ev.other.remove();
ev.remove();
}
if (event_root.head != ev) {
// something was inserted before us in the event queue, so loop back around and
// process it before continuing
// if (buildLog != null) {
// buildLog.rewind(ev.seg);
// }
continue;
}
//
// calculate fill flags
//
if (selfIntersection) {
bool toggle = false; // are we a toggling edge?
// if we are a new segment...
if (ev.seg.myFill.below == null)
// then we toggle
toggle = true;
else
// we are a segment that has previous knowledge from a division
toggle =
ev.seg.myFill.above != ev.seg.myFill.below; // calculate toggle
// next, calculate whether we are filled below us
if (below == null) {
// if nothing is below us...
// we are filled below us if the polygon is inverted
ev.seg.myFill.below = primaryPolyInverted;
} else {
// otherwise, we know the answer -- it's the same if whatever is below
// us is filled above it
ev.seg.myFill.below = below.seg.myFill.above;
}
// since now we know if we're filled below us, we can calculate whether
// we're filled above us by applying toggle to whatever is below us
if (toggle)
ev.seg.myFill.above = ev.seg.myFill.below != null
? !ev.seg.myFill.below
: ev.seg.myFill.above;
else
ev.seg.myFill.above = ev.seg.myFill.below != null
? ev.seg.myFill.below
: ev.seg.myFill.above;
} else {
// now we fill in any missing transition information, since we are all-knowing
// at this point
if (ev.seg.otherFill == null) {
// if we don't have other information, then we need to figure out if we're
// inside the other polygon
var inside = false;
if (below == null) {
// if nothing is below us, then we're inside if the other polygon is
// inverted
inside = ev.primary ? secondaryPolyInverted : primaryPolyInverted;
} else {
// otherwise, something is below us
// so copy the below segment's other polygon's above
if (ev.primary == below.primary)
inside = below.seg.otherFill.above;
else
inside = below.seg.myFill.above;
}
ev.seg.otherFill = new SegmentFill(above: inside, below: inside);
}
}
// if( buildLog != null )
// {
// buildLog.status(
// ev.seg,
// above != null ? above.seg : (object)false,
// below != null ? below.seg : (object)false
// );
// }
// insert the status and remember it for later removal
ev.other.status = status_root.insert(surrounding, ev);
} else {
var st = ev.status;
if (st == null) {
throw new Exception(
"PolyBool: Zero-length segment detected; your epsilon is probably too small or too large");
}
// removing the status will create two new adjacent edges, so we'll need to check
// for those
if (status_root.exists(st.prev) && status_root.exists(st.next))
checkIntersection(st.prev.ev, st.next.ev);
// if (buildLog != null) buildLog.statusRemove(st.ev.seg);
// remove the status
st.remove();
// if we've reached this point, we've calculated everything there is to know, so
// save the segment for reporting
if (!ev.primary) {
// make sure `seg.myFill` actually points to the primary polygon though
var s = ev.seg.myFill;
ev.seg.myFill = ev.seg.otherFill;
ev.seg.otherFill = s;
}
segments.add(ev.seg);
}
// remove the event and continue
event_root.head.remove();
}
// if (buildLog != null) {
// buildLog.done();
// }
return segments;
}