in s2/loop.go [268:320]
func (l *Loop) Contains(o *Loop) bool {
// For a loop A to contain the loop B, all of the following must
// be true:
//
// (1) There are no edge crossings between A and B except at vertices.
//
// (2) At every vertex that is shared between A and B, the local edge
// ordering implies that A contains B.
//
// (3) If there are no shared vertices, then A must contain a vertex of B
// and B must not contain a vertex of A. (An arbitrary vertex may be
// chosen in each case.)
//
// The second part of (3) is necessary to detect the case of two loops whose
// union is the entire sphere, i.e. two loops that contains each other's
// boundaries but not each other's interiors.
if !l.subregionBound.Contains(o.bound) {
return false
}
// Special cases to handle either loop being empty or full.
if l.isEmptyOrFull() || o.isEmptyOrFull() {
return l.IsFull() || o.IsEmpty()
}
// Check whether there are any edge crossings, and also check the loop
// relationship at any shared vertices.
relation := &containsRelation{}
if hasCrossingRelation(l, o, relation) {
return false
}
// There are no crossings, and if there are any shared vertices then A
// contains B locally at each shared vertex.
if relation.foundSharedVertex {
return true
}
// Since there are no edge intersections or shared vertices, we just need to
// test condition (3) above. We can skip this test if we discovered that A
// contains at least one point of B while checking for edge crossings.
if !l.ContainsPoint(o.Vertex(0)) {
return false
}
// We still need to check whether (A union B) is the entire sphere.
// Normally this check is very cheap due to the bounding box precondition.
if (o.subregionBound.Contains(l.bound) || o.bound.Union(l.bound).IsFull()) &&
o.ContainsPoint(l.Vertex(0)) {
return false
}
return true
}