in s2/polygon.go [187:252]
func (p *Polygon) Invert() {
// Inverting any one loop will invert the polygon. The best loop to invert
// is the one whose area is largest, since this yields the smallest area
// after inversion. The loop with the largest area is always at depth 0.
// The descendents of this loop all have their depth reduced by 1, while the
// former siblings of this loop all have their depth increased by 1.
// The empty and full polygons are handled specially.
if p.IsEmpty() {
*p = *FullPolygon()
p.initLoopProperties()
return
}
if p.IsFull() {
*p = Polygon{}
p.initLoopProperties()
return
}
// Find the loop whose area is largest (i.e., whose turning angle is
// smallest), minimizing calls to TurningAngle(). In particular, for
// polygons with a single shell at level 0 there is no need to call
// TurningAngle() at all. (This method is relatively expensive.)
best := 0
const none = 10.0 // Flag that means "not computed yet"
bestAngle := none
for i := 1; i < p.NumLoops(); i++ {
if p.Loop(i).depth != 0 {
continue
}
// We defer computing the turning angle of loop 0 until we discover
// that the polygon has another top-level shell.
if bestAngle == none {
bestAngle = p.Loop(best).TurningAngle()
}
angle := p.Loop(i).TurningAngle()
// We break ties deterministically in order to avoid having the output
// depend on the input order of the loops.
if angle < bestAngle || (angle == bestAngle && compareLoops(p.Loop(i), p.Loop(best)) < 0) {
best = i
bestAngle = angle
}
}
// Build the new loops vector, starting with the inverted loop.
p.Loop(best).Invert()
newLoops := make([]*Loop, 0, p.NumLoops())
// Add the former siblings of this loop as descendants.
lastBest := p.LastDescendant(best)
newLoops = append(newLoops, p.Loop(best))
for i, l := range p.Loops() {
if i < best || i > lastBest {
l.depth++
newLoops = append(newLoops, l)
}
}
// Add the former children of this loop as siblings.
for i, l := range p.Loops() {
if i > best && i <= lastBest {
l.depth--
newLoops = append(newLoops, l)
}
}
p.loops = newLoops
p.initLoopProperties()
}