gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

polygon.go (38825B)


      1 // Copyright 2015 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package s2
     16 
     17 import (
     18 	"fmt"
     19 	"io"
     20 	"math"
     21 )
     22 
     23 // Polygon represents a sequence of zero or more loops; recall that the
     24 // interior of a loop is defined to be its left-hand side (see Loop).
     25 //
     26 // When the polygon is initialized, the given loops are automatically converted
     27 // into a canonical form consisting of "shells" and "holes". Shells and holes
     28 // are both oriented CCW, and are nested hierarchically. The loops are
     29 // reordered to correspond to a pre-order traversal of the nesting hierarchy.
     30 //
     31 // Polygons may represent any region of the sphere with a polygonal boundary,
     32 // including the entire sphere (known as the "full" polygon). The full polygon
     33 // consists of a single full loop (see Loop), whereas the empty polygon has no
     34 // loops at all.
     35 //
     36 // Use FullPolygon() to construct a full polygon. The zero value of Polygon is
     37 // treated as the empty polygon.
     38 //
     39 // Polygons have the following restrictions:
     40 //
     41 //  - Loops may not cross, i.e. the boundary of a loop may not intersect
     42 //    both the interior and exterior of any other loop.
     43 //
     44 //  - Loops may not share edges, i.e. if a loop contains an edge AB, then
     45 //    no other loop may contain AB or BA.
     46 //
     47 //  - Loops may share vertices, however no vertex may appear twice in a
     48 //    single loop (see Loop).
     49 //
     50 //  - No loop may be empty. The full loop may appear only in the full polygon.
     51 type Polygon struct {
     52 	loops []*Loop
     53 
     54 	// index is a spatial index of all the polygon loops.
     55 	index *ShapeIndex
     56 
     57 	// hasHoles tracks if this polygon has at least one hole.
     58 	hasHoles bool
     59 
     60 	// numVertices keeps the running total of all of the vertices of the contained loops.
     61 	numVertices int
     62 
     63 	// numEdges tracks the total number of edges in all the loops in this polygon.
     64 	numEdges int
     65 
     66 	// bound is a conservative bound on all points contained by this loop.
     67 	// If l.ContainsPoint(P), then l.bound.ContainsPoint(P).
     68 	bound Rect
     69 
     70 	// Since bound is not exact, it is possible that a loop A contains
     71 	// another loop B whose bounds are slightly larger. subregionBound
     72 	// has been expanded sufficiently to account for this error, i.e.
     73 	// if A.Contains(B), then A.subregionBound.Contains(B.bound).
     74 	subregionBound Rect
     75 
     76 	// A slice where element i is the cumulative number of edges in the
     77 	// preceding loops in the polygon. This field is used for polygons that
     78 	// have a large number of loops, and may be empty for polygons with few loops.
     79 	cumulativeEdges []int
     80 }
     81 
     82 // PolygonFromLoops constructs a polygon from the given set of loops. The polygon
     83 // interior consists of the points contained by an odd number of loops. (Recall
     84 // that a loop contains the set of points on its left-hand side.)
     85 //
     86 // This method determines the loop nesting hierarchy and assigns every loop a
     87 // depth. Shells have even depths, and holes have odd depths.
     88 //
     89 // Note: The given set of loops are reordered by this method so that the hierarchy
     90 // can be traversed using Parent, LastDescendant and the loops depths.
     91 func PolygonFromLoops(loops []*Loop) *Polygon {
     92 	p := &Polygon{}
     93 	// Empty polygons do not contain any loops, even the Empty loop.
     94 	if len(loops) == 1 && loops[0].IsEmpty() {
     95 		p.initLoopProperties()
     96 		return p
     97 	}
     98 	p.loops = loops
     99 	p.initNested()
    100 	return p
    101 }
    102 
    103 // PolygonFromOrientedLoops returns a Polygon from the given set of loops,
    104 // like PolygonFromLoops. It expects loops to be oriented such that the polygon
    105 // interior is on the left-hand side of all loops. This implies that shells
    106 // and holes should have opposite orientations in the input to this method.
    107 // (During initialization, loops representing holes will automatically be
    108 // inverted.)
    109 func PolygonFromOrientedLoops(loops []*Loop) *Polygon {
    110 	// Here is the algorithm:
    111 	//
    112 	// 1. Remember which of the given loops contain OriginPoint.
    113 	//
    114 	// 2. Invert loops as necessary to ensure that they are nestable (i.e., no
    115 	//    loop contains the complement of any other loop). This may result in a
    116 	//    set of loops corresponding to the complement of the given polygon, but
    117 	//    we will fix that problem later.
    118 	//
    119 	//    We make the loops nestable by first normalizing all the loops (i.e.,
    120 	//    inverting any loops whose turning angle is negative). This handles
    121 	//    all loops except those whose turning angle is very close to zero
    122 	//    (within the maximum error tolerance). Any such loops are inverted if
    123 	//    and only if they contain OriginPoint(). (In theory this step is only
    124 	//    necessary if there are at least two such loops.) The resulting set of
    125 	//    loops is guaranteed to be nestable.
    126 	//
    127 	// 3. Build the polygon. This yields either the desired polygon or its
    128 	//    complement.
    129 	//
    130 	// 4. If there is at least one loop, we find a loop L that is adjacent to
    131 	//    OriginPoint() (where "adjacent" means that there exists a path
    132 	//    connecting OriginPoint() to some vertex of L such that the path does
    133 	//    not cross any loop). There may be a single such adjacent loop, or
    134 	//    there may be several (in which case they should all have the same
    135 	//    contains_origin() value). We choose L to be the loop containing the
    136 	//    origin whose depth is greatest, or loop(0) (a top-level shell) if no
    137 	//    such loop exists.
    138 	//
    139 	// 5. If (L originally contained origin) != (polygon contains origin), we
    140 	//    invert the polygon. This is done by inverting a top-level shell whose
    141 	//    turning angle is minimal and then fixing the nesting hierarchy. Note
    142 	//    that because we normalized all the loops initially, this step is only
    143 	//    necessary if the polygon requires at least one non-normalized loop to
    144 	//    represent it.
    145 
    146 	containedOrigin := make(map[*Loop]bool)
    147 	for _, l := range loops {
    148 		containedOrigin[l] = l.ContainsOrigin()
    149 	}
    150 
    151 	for _, l := range loops {
    152 		angle := l.TurningAngle()
    153 		if math.Abs(angle) > l.turningAngleMaxError() {
    154 			// Normalize the loop.
    155 			if angle < 0 {
    156 				l.Invert()
    157 			}
    158 		} else {
    159 			// Ensure that the loop does not contain the origin.
    160 			if l.ContainsOrigin() {
    161 				l.Invert()
    162 			}
    163 		}
    164 	}
    165 
    166 	p := PolygonFromLoops(loops)
    167 
    168 	if p.NumLoops() > 0 {
    169 		originLoop := p.Loop(0)
    170 		polygonContainsOrigin := false
    171 		for _, l := range p.Loops() {
    172 			if l.ContainsOrigin() {
    173 				polygonContainsOrigin = !polygonContainsOrigin
    174 
    175 				originLoop = l
    176 			}
    177 		}
    178 		if containedOrigin[originLoop] != polygonContainsOrigin {
    179 			p.Invert()
    180 		}
    181 	}
    182 
    183 	return p
    184 }
    185 
    186 // Invert inverts the polygon (replaces it by its complement).
    187 func (p *Polygon) Invert() {
    188 	// Inverting any one loop will invert the polygon.  The best loop to invert
    189 	// is the one whose area is largest, since this yields the smallest area
    190 	// after inversion. The loop with the largest area is always at depth 0.
    191 	// The descendents of this loop all have their depth reduced by 1, while the
    192 	// former siblings of this loop all have their depth increased by 1.
    193 
    194 	// The empty and full polygons are handled specially.
    195 	if p.IsEmpty() {
    196 		*p = *FullPolygon()
    197 		p.initLoopProperties()
    198 		return
    199 	}
    200 	if p.IsFull() {
    201 		*p = Polygon{}
    202 		p.initLoopProperties()
    203 		return
    204 	}
    205 
    206 	// Find the loop whose area is largest (i.e., whose turning angle is
    207 	// smallest), minimizing calls to TurningAngle(). In particular, for
    208 	// polygons with a single shell at level 0 there is no need to call
    209 	// TurningAngle() at all. (This method is relatively expensive.)
    210 	best := 0
    211 	const none = 10.0 // Flag that means "not computed yet"
    212 	bestAngle := none
    213 	for i := 1; i < p.NumLoops(); i++ {
    214 		if p.Loop(i).depth != 0 {
    215 			continue
    216 		}
    217 		// We defer computing the turning angle of loop 0 until we discover
    218 		// that the polygon has another top-level shell.
    219 		if bestAngle == none {
    220 			bestAngle = p.Loop(best).TurningAngle()
    221 		}
    222 		angle := p.Loop(i).TurningAngle()
    223 		// We break ties deterministically in order to avoid having the output
    224 		// depend on the input order of the loops.
    225 		if angle < bestAngle || (angle == bestAngle && compareLoops(p.Loop(i), p.Loop(best)) < 0) {
    226 			best = i
    227 			bestAngle = angle
    228 		}
    229 	}
    230 	// Build the new loops vector, starting with the inverted loop.
    231 	p.Loop(best).Invert()
    232 	newLoops := make([]*Loop, 0, p.NumLoops())
    233 	// Add the former siblings of this loop as descendants.
    234 	lastBest := p.LastDescendant(best)
    235 	newLoops = append(newLoops, p.Loop(best))
    236 	for i, l := range p.Loops() {
    237 		if i < best || i > lastBest {
    238 			l.depth++
    239 			newLoops = append(newLoops, l)
    240 		}
    241 	}
    242 	// Add the former children of this loop as siblings.
    243 	for i, l := range p.Loops() {
    244 		if i > best && i <= lastBest {
    245 			l.depth--
    246 			newLoops = append(newLoops, l)
    247 		}
    248 	}
    249 
    250 	p.loops = newLoops
    251 	p.initLoopProperties()
    252 }
    253 
    254 // Defines a total ordering on Loops that does not depend on the cyclic
    255 // order of loop vertices. This function is used to choose which loop to
    256 // invert in the case where several loops have exactly the same area.
    257 func compareLoops(a, b *Loop) int {
    258 	if na, nb := a.NumVertices(), b.NumVertices(); na != nb {
    259 		return na - nb
    260 	}
    261 	ai, aDir := a.CanonicalFirstVertex()
    262 	bi, bDir := b.CanonicalFirstVertex()
    263 	if aDir != bDir {
    264 		return aDir - bDir
    265 	}
    266 	for n := a.NumVertices() - 1; n >= 0; n, ai, bi = n-1, ai+aDir, bi+bDir {
    267 		if cmp := a.Vertex(ai).Cmp(b.Vertex(bi).Vector); cmp != 0 {
    268 			return cmp
    269 		}
    270 	}
    271 	return 0
    272 }
    273 
    274 // PolygonFromCell returns a Polygon from a single loop created from the given Cell.
    275 func PolygonFromCell(cell Cell) *Polygon {
    276 	return PolygonFromLoops([]*Loop{LoopFromCell(cell)})
    277 }
    278 
    279 // initNested takes the set of loops in this polygon and performs the nesting
    280 // computations to set the proper nesting and parent/child relationships.
    281 func (p *Polygon) initNested() {
    282 	if len(p.loops) == 1 {
    283 		p.initOneLoop()
    284 		return
    285 	}
    286 
    287 	lm := make(loopMap)
    288 
    289 	for _, l := range p.loops {
    290 		lm.insertLoop(l, nil)
    291 	}
    292 	// The loops have all been added to the loopMap for ordering. Clear the
    293 	// loops slice because we add all the loops in-order in initLoops.
    294 	p.loops = nil
    295 
    296 	// Reorder the loops in depth-first traversal order.
    297 	p.initLoops(lm)
    298 	p.initLoopProperties()
    299 }
    300 
    301 // loopMap is a map of a loop to its immediate children with respect to nesting.
    302 // It is used to determine which loops are shells and which are holes.
    303 type loopMap map[*Loop][]*Loop
    304 
    305 // insertLoop adds the given loop to the loop map under the specified parent.
    306 // All children of the new entry are checked to see if the need to move up to
    307 // a different level.
    308 func (lm loopMap) insertLoop(newLoop, parent *Loop) {
    309 	var children []*Loop
    310 	for done := false; !done; {
    311 		children = lm[parent]
    312 		done = true
    313 		for _, child := range children {
    314 			if child.ContainsNested(newLoop) {
    315 				parent = child
    316 				done = false
    317 				break
    318 			}
    319 		}
    320 	}
    321 
    322 	// Now, we have found a parent for this loop, it may be that some of the
    323 	// children of the parent of this loop may now be children of the new loop.
    324 	newChildren := lm[newLoop]
    325 	for i := 0; i < len(children); {
    326 		child := children[i]
    327 		if newLoop.ContainsNested(child) {
    328 			newChildren = append(newChildren, child)
    329 			children = append(children[0:i], children[i+1:]...)
    330 		} else {
    331 			i++
    332 		}
    333 	}
    334 
    335 	lm[newLoop] = newChildren
    336 	lm[parent] = append(children, newLoop)
    337 }
    338 
    339 // loopStack simplifies access to the loops while being initialized.
    340 type loopStack []*Loop
    341 
    342 func (s *loopStack) push(v *Loop) {
    343 	*s = append(*s, v)
    344 }
    345 func (s *loopStack) pop() *Loop {
    346 	l := len(*s)
    347 	r := (*s)[l-1]
    348 	*s = (*s)[:l-1]
    349 	return r
    350 }
    351 
    352 // initLoops walks the mapping of loops to all of their children, and adds them in
    353 // order into to the polygons set of loops.
    354 func (p *Polygon) initLoops(lm loopMap) {
    355 	var stack loopStack
    356 	stack.push(nil)
    357 	depth := -1
    358 
    359 	for len(stack) > 0 {
    360 		loop := stack.pop()
    361 		if loop != nil {
    362 			depth = loop.depth
    363 			p.loops = append(p.loops, loop)
    364 		}
    365 		children := lm[loop]
    366 		for i := len(children) - 1; i >= 0; i-- {
    367 			child := children[i]
    368 			child.depth = depth + 1
    369 			stack.push(child)
    370 		}
    371 	}
    372 }
    373 
    374 // initOneLoop set the properties for a polygon made of a single loop.
    375 // TODO(roberts): Can this be merged with initLoopProperties
    376 func (p *Polygon) initOneLoop() {
    377 	p.hasHoles = false
    378 	p.numVertices = len(p.loops[0].vertices)
    379 	p.bound = p.loops[0].RectBound()
    380 	p.subregionBound = ExpandForSubregions(p.bound)
    381 	// Ensure the loops depth is set correctly.
    382 	p.loops[0].depth = 0
    383 
    384 	p.initEdgesAndIndex()
    385 }
    386 
    387 // initLoopProperties sets the properties for polygons with multiple loops.
    388 func (p *Polygon) initLoopProperties() {
    389 	p.numVertices = 0
    390 	// the loops depths are set by initNested/initOriented prior to this.
    391 	p.bound = EmptyRect()
    392 	p.hasHoles = false
    393 	for _, l := range p.loops {
    394 		if l.IsHole() {
    395 			p.hasHoles = true
    396 		} else {
    397 			p.bound = p.bound.Union(l.RectBound())
    398 		}
    399 		p.numVertices += l.NumVertices()
    400 	}
    401 	p.subregionBound = ExpandForSubregions(p.bound)
    402 
    403 	p.initEdgesAndIndex()
    404 }
    405 
    406 // initEdgesAndIndex performs the shape related initializations and adds the final
    407 // polygon to the index.
    408 func (p *Polygon) initEdgesAndIndex() {
    409 	p.numEdges = 0
    410 	p.cumulativeEdges = nil
    411 	if p.IsFull() {
    412 		return
    413 	}
    414 	const maxLinearSearchLoops = 12 // Based on benchmarks.
    415 	if len(p.loops) > maxLinearSearchLoops {
    416 		p.cumulativeEdges = make([]int, 0, len(p.loops))
    417 	}
    418 
    419 	for _, l := range p.loops {
    420 		if p.cumulativeEdges != nil {
    421 			p.cumulativeEdges = append(p.cumulativeEdges, p.numEdges)
    422 		}
    423 		p.numEdges += len(l.vertices)
    424 	}
    425 
    426 	p.index = NewShapeIndex()
    427 	p.index.Add(p)
    428 }
    429 
    430 // FullPolygon returns a special "full" polygon.
    431 func FullPolygon() *Polygon {
    432 	ret := &Polygon{
    433 		loops: []*Loop{
    434 			FullLoop(),
    435 		},
    436 		numVertices:    len(FullLoop().Vertices()),
    437 		bound:          FullRect(),
    438 		subregionBound: FullRect(),
    439 	}
    440 	ret.initEdgesAndIndex()
    441 	return ret
    442 }
    443 
    444 // Validate checks whether this is a valid polygon,
    445 // including checking whether all the loops are themselves valid.
    446 func (p *Polygon) Validate() error {
    447 	for i, l := range p.loops {
    448 		// Check for loop errors that don't require building a ShapeIndex.
    449 		if err := l.findValidationErrorNoIndex(); err != nil {
    450 			return fmt.Errorf("loop %d: %v", i, err)
    451 		}
    452 		// Check that no loop is empty, and that the full loop only appears in the
    453 		// full polygon.
    454 		if l.IsEmpty() {
    455 			return fmt.Errorf("loop %d: empty loops are not allowed", i)
    456 		}
    457 		if l.IsFull() && len(p.loops) > 1 {
    458 			return fmt.Errorf("loop %d: full loop appears in non-full polygon", i)
    459 		}
    460 	}
    461 
    462 	// TODO(roberts): Uncomment the remaining checks when they are completed.
    463 
    464 	// Check for loop self-intersections and loop pairs that cross
    465 	// (including duplicate edges and vertices).
    466 	// if findSelfIntersection(p.index) {
    467 	//	return fmt.Errorf("polygon has loop pairs that cross")
    468 	// }
    469 
    470 	// Check whether initOriented detected inconsistent loop orientations.
    471 	// if p.hasInconsistentLoopOrientations {
    472 	// 	return fmt.Errorf("inconsistent loop orientations detected")
    473 	// }
    474 
    475 	// Finally, verify the loop nesting hierarchy.
    476 	return p.findLoopNestingError()
    477 }
    478 
    479 // findLoopNestingError reports if there is an error in the loop nesting hierarchy.
    480 func (p *Polygon) findLoopNestingError() error {
    481 	// First check that the loop depths make sense.
    482 	lastDepth := -1
    483 	for i, l := range p.loops {
    484 		depth := l.depth
    485 		if depth < 0 || depth > lastDepth+1 {
    486 			return fmt.Errorf("loop %d: invalid loop depth (%d)", i, depth)
    487 		}
    488 		lastDepth = depth
    489 	}
    490 	// Then check that they correspond to the actual loop nesting.  This test
    491 	// is quadratic in the number of loops but the cost per iteration is small.
    492 	for i, l := range p.loops {
    493 		last := p.LastDescendant(i)
    494 		for j, l2 := range p.loops {
    495 			if i == j {
    496 				continue
    497 			}
    498 			nested := (j >= i+1) && (j <= last)
    499 			const reverseB = false
    500 
    501 			if l.containsNonCrossingBoundary(l2, reverseB) != nested {
    502 				nestedStr := ""
    503 				if !nested {
    504 					nestedStr = "not "
    505 				}
    506 				return fmt.Errorf("invalid nesting: loop %d should %scontain loop %d", i, nestedStr, j)
    507 			}
    508 		}
    509 	}
    510 	return nil
    511 }
    512 
    513 // IsEmpty reports whether this is the special "empty" polygon (consisting of no loops).
    514 func (p *Polygon) IsEmpty() bool {
    515 	return len(p.loops) == 0
    516 }
    517 
    518 // IsFull reports whether this is the special "full" polygon (consisting of a
    519 // single loop that encompasses the entire sphere).
    520 func (p *Polygon) IsFull() bool {
    521 	return len(p.loops) == 1 && p.loops[0].IsFull()
    522 }
    523 
    524 // NumLoops returns the number of loops in this polygon.
    525 func (p *Polygon) NumLoops() int {
    526 	return len(p.loops)
    527 }
    528 
    529 // Loops returns the loops in this polygon.
    530 func (p *Polygon) Loops() []*Loop {
    531 	return p.loops
    532 }
    533 
    534 // Loop returns the loop at the given index. Note that during initialization,
    535 // the given loops are reordered according to a pre-order traversal of the loop
    536 // nesting hierarchy. This implies that every loop is immediately followed by
    537 // its descendants. This hierarchy can be traversed using the methods Parent,
    538 // LastDescendant, and Loop.depth.
    539 func (p *Polygon) Loop(k int) *Loop {
    540 	return p.loops[k]
    541 }
    542 
    543 // Parent returns the index of the parent of loop k.
    544 // If the loop does not have a parent, ok=false is returned.
    545 func (p *Polygon) Parent(k int) (index int, ok bool) {
    546 	// See where we are on the depth hierarchy.
    547 	depth := p.loops[k].depth
    548 	if depth == 0 {
    549 		return -1, false
    550 	}
    551 
    552 	// There may be several loops at the same nesting level as us that share a
    553 	// parent loop with us. (Imagine a slice of swiss cheese, of which we are one loop.
    554 	// we don't know how many may be next to us before we get back to our parent loop.)
    555 	// Move up one position from us, and then begin traversing back through the set of loops
    556 	// until we find the one that is our parent or we get to the top of the polygon.
    557 	for k--; k >= 0 && p.loops[k].depth <= depth; k-- {
    558 	}
    559 	return k, true
    560 }
    561 
    562 // LastDescendant returns the index of the last loop that is contained within loop k.
    563 // If k is negative, it returns the last loop in the polygon.
    564 // Note that loops are indexed according to a pre-order traversal of the nesting
    565 // hierarchy, so the immediate children of loop k can be found by iterating over
    566 // the loops (k+1)..LastDescendant(k) and selecting those whose depth is equal
    567 // to Loop(k).depth+1.
    568 func (p *Polygon) LastDescendant(k int) int {
    569 	if k < 0 {
    570 		return len(p.loops) - 1
    571 	}
    572 
    573 	depth := p.loops[k].depth
    574 
    575 	// Find the next loop immediately past us in the set of loops, and then start
    576 	// moving down the list until we either get to the end or find the next loop
    577 	// that is higher up the hierarchy than we are.
    578 	for k++; k < len(p.loops) && p.loops[k].depth > depth; k++ {
    579 	}
    580 	return k - 1
    581 }
    582 
    583 // CapBound returns a bounding spherical cap.
    584 func (p *Polygon) CapBound() Cap { return p.bound.CapBound() }
    585 
    586 // RectBound returns a bounding latitude-longitude rectangle.
    587 func (p *Polygon) RectBound() Rect { return p.bound }
    588 
    589 // ContainsPoint reports whether the polygon contains the point.
    590 func (p *Polygon) ContainsPoint(point Point) bool {
    591 	// NOTE: A bounds check slows down this function by about 50%. It is
    592 	// worthwhile only when it might allow us to delay building the index.
    593 	if !p.index.IsFresh() && !p.bound.ContainsPoint(point) {
    594 		return false
    595 	}
    596 
    597 	// For small polygons, and during initial construction, it is faster to just
    598 	// check all the crossing.
    599 	const maxBruteForceVertices = 32
    600 	if p.numVertices < maxBruteForceVertices || p.index == nil {
    601 		inside := false
    602 		for _, l := range p.loops {
    603 			// use loops bruteforce to avoid building the index on each loop.
    604 			inside = inside != l.bruteForceContainsPoint(point)
    605 		}
    606 		return inside
    607 	}
    608 
    609 	// Otherwise we look up the ShapeIndex cell containing this point.
    610 	return NewContainsPointQuery(p.index, VertexModelSemiOpen).Contains(point)
    611 }
    612 
    613 // ContainsCell reports whether the polygon contains the given cell.
    614 func (p *Polygon) ContainsCell(cell Cell) bool {
    615 	it := p.index.Iterator()
    616 	relation := it.LocateCellID(cell.ID())
    617 
    618 	// If "cell" is disjoint from all index cells, it is not contained.
    619 	// Similarly, if "cell" is subdivided into one or more index cells then it
    620 	// is not contained, since index cells are subdivided only if they (nearly)
    621 	// intersect a sufficient number of edges.  (But note that if "cell" itself
    622 	// is an index cell then it may be contained, since it could be a cell with
    623 	// no edges in the loop interior.)
    624 	if relation != Indexed {
    625 		return false
    626 	}
    627 
    628 	// Otherwise check if any edges intersect "cell".
    629 	if p.boundaryApproxIntersects(it, cell) {
    630 		return false
    631 	}
    632 
    633 	// Otherwise check if the loop contains the center of "cell".
    634 	return p.iteratorContainsPoint(it, cell.Center())
    635 }
    636 
    637 // IntersectsCell reports whether the polygon intersects the given cell.
    638 func (p *Polygon) IntersectsCell(cell Cell) bool {
    639 	it := p.index.Iterator()
    640 	relation := it.LocateCellID(cell.ID())
    641 
    642 	// If cell does not overlap any index cell, there is no intersection.
    643 	if relation == Disjoint {
    644 		return false
    645 	}
    646 	// If cell is subdivided into one or more index cells, there is an
    647 	// intersection to within the S2ShapeIndex error bound (see Contains).
    648 	if relation == Subdivided {
    649 		return true
    650 	}
    651 	// If cell is an index cell, there is an intersection because index cells
    652 	// are created only if they have at least one edge or they are entirely
    653 	// contained by the loop.
    654 	if it.CellID() == cell.id {
    655 		return true
    656 	}
    657 	// Otherwise check if any edges intersect cell.
    658 	if p.boundaryApproxIntersects(it, cell) {
    659 		return true
    660 	}
    661 	// Otherwise check if the loop contains the center of cell.
    662 	return p.iteratorContainsPoint(it, cell.Center())
    663 }
    664 
    665 // CellUnionBound computes a covering of the Polygon.
    666 func (p *Polygon) CellUnionBound() []CellID {
    667 	// TODO(roberts): Use ShapeIndexRegion when it's available.
    668 	return p.CapBound().CellUnionBound()
    669 }
    670 
    671 // boundaryApproxIntersects reports whether the loop's boundary intersects cell.
    672 // It may also return true when the loop boundary does not intersect cell but
    673 // some edge comes within the worst-case error tolerance.
    674 //
    675 // This requires that it.Locate(cell) returned Indexed.
    676 func (p *Polygon) boundaryApproxIntersects(it *ShapeIndexIterator, cell Cell) bool {
    677 	aClipped := it.IndexCell().findByShapeID(0)
    678 
    679 	// If there are no edges, there is no intersection.
    680 	if len(aClipped.edges) == 0 {
    681 		return false
    682 	}
    683 
    684 	// We can save some work if cell is the index cell itself.
    685 	if it.CellID() == cell.ID() {
    686 		return true
    687 	}
    688 
    689 	// Otherwise check whether any of the edges intersect cell.
    690 	maxError := (faceClipErrorUVCoord + intersectsRectErrorUVDist)
    691 	bound := cell.BoundUV().ExpandedByMargin(maxError)
    692 	for _, e := range aClipped.edges {
    693 		edge := p.index.Shape(0).Edge(e)
    694 		v0, v1, ok := ClipToPaddedFace(edge.V0, edge.V1, cell.Face(), maxError)
    695 		if ok && edgeIntersectsRect(v0, v1, bound) {
    696 			return true
    697 		}
    698 	}
    699 
    700 	return false
    701 }
    702 
    703 // iteratorContainsPoint reports whether the iterator that is positioned at the
    704 // ShapeIndexCell that may contain p, contains the point p.
    705 func (p *Polygon) iteratorContainsPoint(it *ShapeIndexIterator, point Point) bool {
    706 	// Test containment by drawing a line segment from the cell center to the
    707 	// given point and counting edge crossings.
    708 	aClipped := it.IndexCell().findByShapeID(0)
    709 	inside := aClipped.containsCenter
    710 
    711 	if len(aClipped.edges) == 0 {
    712 		return inside
    713 	}
    714 
    715 	// This block requires ShapeIndex.
    716 	crosser := NewEdgeCrosser(it.Center(), point)
    717 	shape := p.index.Shape(0)
    718 	for _, e := range aClipped.edges {
    719 		edge := shape.Edge(e)
    720 		inside = inside != crosser.EdgeOrVertexCrossing(edge.V0, edge.V1)
    721 	}
    722 
    723 	return inside
    724 }
    725 
    726 // Shape Interface
    727 
    728 // NumEdges returns the number of edges in this shape.
    729 func (p *Polygon) NumEdges() int {
    730 	return p.numEdges
    731 }
    732 
    733 // Edge returns endpoints for the given edge index.
    734 func (p *Polygon) Edge(e int) Edge {
    735 	var i int
    736 
    737 	if len(p.cumulativeEdges) > 0 {
    738 		for i = range p.cumulativeEdges {
    739 			if i+1 >= len(p.cumulativeEdges) || e < p.cumulativeEdges[i+1] {
    740 				e -= p.cumulativeEdges[i]
    741 				break
    742 			}
    743 		}
    744 	} else {
    745 		// When the number of loops is small, use linear search. Most often
    746 		// there is exactly one loop and the code below executes zero times.
    747 		for i = 0; e >= len(p.Loop(i).vertices); i++ {
    748 			e -= len(p.Loop(i).vertices)
    749 		}
    750 	}
    751 
    752 	return Edge{p.Loop(i).OrientedVertex(e), p.Loop(i).OrientedVertex(e + 1)}
    753 }
    754 
    755 // ReferencePoint returns the reference point for this polygon.
    756 func (p *Polygon) ReferencePoint() ReferencePoint {
    757 	containsOrigin := false
    758 	for _, l := range p.loops {
    759 		containsOrigin = containsOrigin != l.ContainsOrigin()
    760 	}
    761 	return OriginReferencePoint(containsOrigin)
    762 }
    763 
    764 // NumChains reports the number of contiguous edge chains in the Polygon.
    765 func (p *Polygon) NumChains() int {
    766 	return p.NumLoops()
    767 }
    768 
    769 // Chain returns the i-th edge Chain (loop) in the Shape.
    770 func (p *Polygon) Chain(chainID int) Chain {
    771 	if p.cumulativeEdges != nil {
    772 		return Chain{p.cumulativeEdges[chainID], len(p.Loop(chainID).vertices)}
    773 	}
    774 	e := 0
    775 	for j := 0; j < chainID; j++ {
    776 		e += len(p.Loop(j).vertices)
    777 	}
    778 
    779 	// Polygon represents a full loop as a loop with one vertex, while
    780 	// Shape represents a full loop as a chain with no vertices.
    781 	if numVertices := p.Loop(chainID).NumVertices(); numVertices != 1 {
    782 		return Chain{e, numVertices}
    783 	}
    784 	return Chain{e, 0}
    785 }
    786 
    787 // ChainEdge returns the j-th edge of the i-th edge Chain (loop).
    788 func (p *Polygon) ChainEdge(i, j int) Edge {
    789 	return Edge{p.Loop(i).OrientedVertex(j), p.Loop(i).OrientedVertex(j + 1)}
    790 }
    791 
    792 // ChainPosition returns a pair (i, j) such that edgeID is the j-th edge
    793 // of the i-th edge Chain.
    794 func (p *Polygon) ChainPosition(edgeID int) ChainPosition {
    795 	var i int
    796 
    797 	if len(p.cumulativeEdges) > 0 {
    798 		for i = range p.cumulativeEdges {
    799 			if i+1 >= len(p.cumulativeEdges) || edgeID < p.cumulativeEdges[i+1] {
    800 				edgeID -= p.cumulativeEdges[i]
    801 				break
    802 			}
    803 		}
    804 	} else {
    805 		// When the number of loops is small, use linear search. Most often
    806 		// there is exactly one loop and the code below executes zero times.
    807 		for i = 0; edgeID >= len(p.Loop(i).vertices); i++ {
    808 			edgeID -= len(p.Loop(i).vertices)
    809 		}
    810 	}
    811 	// TODO(roberts): unify this and Edge since they are mostly identical.
    812 	return ChainPosition{i, edgeID}
    813 }
    814 
    815 // Dimension returns the dimension of the geometry represented by this Polygon.
    816 func (p *Polygon) Dimension() int { return 2 }
    817 
    818 func (p *Polygon) typeTag() typeTag { return typeTagPolygon }
    819 
    820 func (p *Polygon) privateInterface() {}
    821 
    822 // Contains reports whether this polygon contains the other polygon.
    823 // Specifically, it reports whether all the points in the other polygon
    824 // are also in this polygon.
    825 func (p *Polygon) Contains(o *Polygon) bool {
    826 	// If both polygons have one loop, use the more efficient Loop method.
    827 	// Note that Loop's Contains does its own bounding rectangle check.
    828 	if len(p.loops) == 1 && len(o.loops) == 1 {
    829 		return p.loops[0].Contains(o.loops[0])
    830 	}
    831 
    832 	// Otherwise if neither polygon has holes, we can still use the more
    833 	// efficient Loop's Contains method (rather than compareBoundary),
    834 	// but it's worthwhile to do our own bounds check first.
    835 	if !p.subregionBound.Contains(o.bound) {
    836 		// Even though Bound(A) does not contain Bound(B), it is still possible
    837 		// that A contains B. This can only happen when union of the two bounds
    838 		// spans all longitudes. For example, suppose that B consists of two
    839 		// shells with a longitude gap between them, while A consists of one shell
    840 		// that surrounds both shells of B but goes the other way around the
    841 		// sphere (so that it does not intersect the longitude gap).
    842 		if !p.bound.Lng.Union(o.bound.Lng).IsFull() {
    843 			return false
    844 		}
    845 	}
    846 
    847 	if !p.hasHoles && !o.hasHoles {
    848 		for _, l := range o.loops {
    849 			if !p.anyLoopContains(l) {
    850 				return false
    851 			}
    852 		}
    853 		return true
    854 	}
    855 
    856 	// Polygon A contains B iff B does not intersect the complement of A. From
    857 	// the intersection algorithm below, this means that the complement of A
    858 	// must exclude the entire boundary of B, and B must exclude all shell
    859 	// boundaries of the complement of A. (It can be shown that B must then
    860 	// exclude the entire boundary of the complement of A.) The first call
    861 	// below returns false if the boundaries cross, therefore the second call
    862 	// does not need to check for any crossing edges (which makes it cheaper).
    863 	return p.containsBoundary(o) && o.excludesNonCrossingComplementShells(p)
    864 }
    865 
    866 // Intersects reports whether this polygon intersects the other polygon, i.e.
    867 // if there is a point that is contained by both polygons.
    868 func (p *Polygon) Intersects(o *Polygon) bool {
    869 	// If both polygons have one loop, use the more efficient Loop method.
    870 	// Note that Loop Intersects does its own bounding rectangle check.
    871 	if len(p.loops) == 1 && len(o.loops) == 1 {
    872 		return p.loops[0].Intersects(o.loops[0])
    873 	}
    874 
    875 	// Otherwise if neither polygon has holes, we can still use the more
    876 	// efficient Loop.Intersects method. The polygons intersect if and
    877 	// only if some pair of loop regions intersect.
    878 	if !p.bound.Intersects(o.bound) {
    879 		return false
    880 	}
    881 
    882 	if !p.hasHoles && !o.hasHoles {
    883 		for _, l := range o.loops {
    884 			if p.anyLoopIntersects(l) {
    885 				return true
    886 			}
    887 		}
    888 		return false
    889 	}
    890 
    891 	// Polygon A is disjoint from B if A excludes the entire boundary of B and B
    892 	// excludes all shell boundaries of A. (It can be shown that B must then
    893 	// exclude the entire boundary of A.) The first call below returns false if
    894 	// the boundaries cross, therefore the second call does not need to check
    895 	// for crossing edges.
    896 	return !p.excludesBoundary(o) || !o.excludesNonCrossingShells(p)
    897 }
    898 
    899 // compareBoundary returns +1 if this polygon contains the boundary of B, -1 if A
    900 // excludes the boundary of B, and 0 if the boundaries of A and B cross.
    901 func (p *Polygon) compareBoundary(o *Loop) int {
    902 	result := -1
    903 	for i := 0; i < len(p.loops) && result != 0; i++ {
    904 		// If B crosses any loop of A, the result is 0. Otherwise the result
    905 		// changes sign each time B is contained by a loop of A.
    906 		result *= -p.loops[i].compareBoundary(o)
    907 	}
    908 	return result
    909 }
    910 
    911 // containsBoundary reports whether this polygon contains the entire boundary of B.
    912 func (p *Polygon) containsBoundary(o *Polygon) bool {
    913 	for _, l := range o.loops {
    914 		if p.compareBoundary(l) <= 0 {
    915 			return false
    916 		}
    917 	}
    918 	return true
    919 }
    920 
    921 // excludesBoundary reports whether this polygon excludes the entire boundary of B.
    922 func (p *Polygon) excludesBoundary(o *Polygon) bool {
    923 	for _, l := range o.loops {
    924 		if p.compareBoundary(l) >= 0 {
    925 			return false
    926 		}
    927 	}
    928 	return true
    929 }
    930 
    931 // containsNonCrossingBoundary reports whether polygon A contains the boundary of
    932 // loop B. Shared edges are handled according to the rule described in loops
    933 // containsNonCrossingBoundary.
    934 func (p *Polygon) containsNonCrossingBoundary(o *Loop, reverse bool) bool {
    935 	var inside bool
    936 	for _, l := range p.loops {
    937 		x := l.containsNonCrossingBoundary(o, reverse)
    938 		inside = (inside != x)
    939 	}
    940 	return inside
    941 }
    942 
    943 // excludesNonCrossingShells reports wheterh given two polygons A and B such that the
    944 // boundary of A does not cross any loop of B, if A excludes all shell boundaries of B.
    945 func (p *Polygon) excludesNonCrossingShells(o *Polygon) bool {
    946 	for _, l := range o.loops {
    947 		if l.IsHole() {
    948 			continue
    949 		}
    950 		if p.containsNonCrossingBoundary(l, false) {
    951 			return false
    952 		}
    953 	}
    954 	return true
    955 }
    956 
    957 // excludesNonCrossingComplementShells reports whether given two polygons A and B
    958 // such that the boundary of A does not cross any loop of B, if A excludes all
    959 // shell boundaries of the complement of B.
    960 func (p *Polygon) excludesNonCrossingComplementShells(o *Polygon) bool {
    961 	// Special case to handle the complement of the empty or full polygons.
    962 	if o.IsEmpty() {
    963 		return !p.IsFull()
    964 	}
    965 	if o.IsFull() {
    966 		return true
    967 	}
    968 
    969 	// Otherwise the complement of B may be obtained by inverting loop(0) and
    970 	// then swapping the shell/hole status of all other loops. This implies
    971 	// that the shells of the complement consist of loop 0 plus all the holes of
    972 	// the original polygon.
    973 	for j, l := range o.loops {
    974 		if j > 0 && !l.IsHole() {
    975 			continue
    976 		}
    977 
    978 		// The interior of the complement is to the right of loop 0, and to the
    979 		// left of the loops that were originally holes.
    980 		if p.containsNonCrossingBoundary(l, j == 0) {
    981 			return false
    982 		}
    983 	}
    984 	return true
    985 }
    986 
    987 // anyLoopContains reports whether any loop in this polygon contains the given loop.
    988 func (p *Polygon) anyLoopContains(o *Loop) bool {
    989 	for _, l := range p.loops {
    990 		if l.Contains(o) {
    991 			return true
    992 		}
    993 	}
    994 	return false
    995 }
    996 
    997 // anyLoopIntersects reports whether any loop in this polygon intersects the given loop.
    998 func (p *Polygon) anyLoopIntersects(o *Loop) bool {
    999 	for _, l := range p.loops {
   1000 		if l.Intersects(o) {
   1001 			return true
   1002 		}
   1003 	}
   1004 	return false
   1005 }
   1006 
   1007 // Area returns the area of the polygon interior, i.e. the region on the left side
   1008 // of an odd number of loops. The return value is between 0 and 4*Pi.
   1009 func (p *Polygon) Area() float64 {
   1010 	var area float64
   1011 	for _, loop := range p.loops {
   1012 		area += float64(loop.Sign()) * loop.Area()
   1013 	}
   1014 	return area
   1015 }
   1016 
   1017 // Encode encodes the Polygon
   1018 func (p *Polygon) Encode(w io.Writer) error {
   1019 	e := &encoder{w: w}
   1020 	p.encode(e)
   1021 	return e.err
   1022 }
   1023 
   1024 // encode only supports lossless encoding and not compressed format.
   1025 func (p *Polygon) encode(e *encoder) {
   1026 	if p.numVertices == 0 {
   1027 		p.encodeCompressed(e, maxLevel, nil)
   1028 		return
   1029 	}
   1030 
   1031 	// Convert all the polygon vertices to XYZFaceSiTi format.
   1032 	vs := make([]xyzFaceSiTi, 0, p.numVertices)
   1033 	for _, l := range p.loops {
   1034 		vs = append(vs, l.xyzFaceSiTiVertices()...)
   1035 	}
   1036 
   1037 	// Computes a histogram of the cell levels at which the vertices are snapped.
   1038 	// (histogram[0] is the number of unsnapped vertices, histogram[i] the number
   1039 	// of vertices snapped at level i-1).
   1040 	histogram := make([]int, maxLevel+2)
   1041 	for _, v := range vs {
   1042 		histogram[v.level+1]++
   1043 	}
   1044 
   1045 	// Compute the level at which most of the vertices are snapped.
   1046 	// If multiple levels have the same maximum number of vertices
   1047 	// snapped to it, the first one (lowest level number / largest
   1048 	// area / smallest encoding length) will be chosen, so this
   1049 	// is desired.
   1050 	var snapLevel, numSnapped int
   1051 	for level, h := range histogram[1:] {
   1052 		if h > numSnapped {
   1053 			snapLevel, numSnapped = level, h
   1054 		}
   1055 	}
   1056 
   1057 	// Choose an encoding format based on the number of unsnapped vertices and a
   1058 	// rough estimate of the encoded sizes.
   1059 	numUnsnapped := p.numVertices - numSnapped // Number of vertices that won't be snapped at snapLevel.
   1060 	const pointSize = 3 * 8                    // s2.Point is an r3.Vector, which is 3 float64s. That's 3*8 = 24 bytes.
   1061 	compressedSize := 4*p.numVertices + (pointSize+2)*numUnsnapped
   1062 	losslessSize := pointSize * p.numVertices
   1063 	if compressedSize < losslessSize {
   1064 		p.encodeCompressed(e, snapLevel, vs)
   1065 	} else {
   1066 		p.encodeLossless(e)
   1067 	}
   1068 }
   1069 
   1070 // encodeLossless encodes the polygon's Points as float64s.
   1071 func (p *Polygon) encodeLossless(e *encoder) {
   1072 	e.writeInt8(encodingVersion)
   1073 	e.writeBool(true) // a legacy c++ value. must be true.
   1074 	e.writeBool(p.hasHoles)
   1075 	e.writeUint32(uint32(len(p.loops)))
   1076 
   1077 	if e.err != nil {
   1078 		return
   1079 	}
   1080 	if len(p.loops) > maxEncodedLoops {
   1081 		e.err = fmt.Errorf("too many loops (%d; max is %d)", len(p.loops), maxEncodedLoops)
   1082 		return
   1083 	}
   1084 	for _, l := range p.loops {
   1085 		l.encode(e)
   1086 	}
   1087 
   1088 	// Encode the bound.
   1089 	p.bound.encode(e)
   1090 }
   1091 
   1092 func (p *Polygon) encodeCompressed(e *encoder, snapLevel int, vertices []xyzFaceSiTi) {
   1093 	e.writeUint8(uint8(encodingCompressedVersion))
   1094 	e.writeUint8(uint8(snapLevel))
   1095 	e.writeUvarint(uint64(len(p.loops)))
   1096 
   1097 	if e.err != nil {
   1098 		return
   1099 	}
   1100 	if l := len(p.loops); l > maxEncodedLoops {
   1101 		e.err = fmt.Errorf("too many loops to encode: %d; max is %d", l, maxEncodedLoops)
   1102 		return
   1103 	}
   1104 
   1105 	for _, l := range p.loops {
   1106 		l.encodeCompressed(e, snapLevel, vertices[:len(l.vertices)])
   1107 		vertices = vertices[len(l.vertices):]
   1108 	}
   1109 	// Do not write the bound, num_vertices, or has_holes_ as they can be
   1110 	// cheaply recomputed by decodeCompressed.  Microbenchmarks show the
   1111 	// speed difference is inconsequential.
   1112 }
   1113 
   1114 // Decode decodes the Polygon.
   1115 func (p *Polygon) Decode(r io.Reader) error {
   1116 	d := &decoder{r: asByteReader(r)}
   1117 	version := int8(d.readUint8())
   1118 	var dec func(*decoder)
   1119 	switch version {
   1120 	case encodingVersion:
   1121 		dec = p.decode
   1122 	case encodingCompressedVersion:
   1123 		dec = p.decodeCompressed
   1124 	default:
   1125 		return fmt.Errorf("unsupported version %d", version)
   1126 	}
   1127 	dec(d)
   1128 	return d.err
   1129 }
   1130 
   1131 // maxEncodedLoops is the biggest supported number of loops in a polygon during encoding.
   1132 // Setting a maximum guards an allocation: it prevents an attacker from easily pushing us OOM.
   1133 const maxEncodedLoops = 10000000
   1134 
   1135 func (p *Polygon) decode(d *decoder) {
   1136 	*p = Polygon{}
   1137 	d.readUint8() // Ignore irrelevant serialized owns_loops_ value.
   1138 
   1139 	p.hasHoles = d.readBool()
   1140 
   1141 	// Polygons with no loops are explicitly allowed here: a newly created
   1142 	// polygon has zero loops and such polygons encode and decode properly.
   1143 	nloops := d.readUint32()
   1144 	if d.err != nil {
   1145 		return
   1146 	}
   1147 	if nloops > maxEncodedLoops {
   1148 		d.err = fmt.Errorf("too many loops (%d; max is %d)", nloops, maxEncodedLoops)
   1149 		return
   1150 	}
   1151 	p.loops = make([]*Loop, nloops)
   1152 	for i := range p.loops {
   1153 		p.loops[i] = new(Loop)
   1154 		p.loops[i].decode(d)
   1155 		p.numVertices += len(p.loops[i].vertices)
   1156 	}
   1157 
   1158 	p.bound.decode(d)
   1159 	if d.err != nil {
   1160 		return
   1161 	}
   1162 	p.subregionBound = ExpandForSubregions(p.bound)
   1163 	p.initEdgesAndIndex()
   1164 }
   1165 
   1166 func (p *Polygon) decodeCompressed(d *decoder) {
   1167 	snapLevel := int(d.readUint8())
   1168 
   1169 	if snapLevel > maxLevel {
   1170 		d.err = fmt.Errorf("snaplevel too big: %d", snapLevel)
   1171 		return
   1172 	}
   1173 	// Polygons with no loops are explicitly allowed here: a newly created
   1174 	// polygon has zero loops and such polygons encode and decode properly.
   1175 	nloops := int(d.readUvarint())
   1176 	if nloops > maxEncodedLoops {
   1177 		d.err = fmt.Errorf("too many loops (%d; max is %d)", nloops, maxEncodedLoops)
   1178 	}
   1179 	p.loops = make([]*Loop, nloops)
   1180 	for i := range p.loops {
   1181 		p.loops[i] = new(Loop)
   1182 		p.loops[i].decodeCompressed(d, snapLevel)
   1183 	}
   1184 	p.initLoopProperties()
   1185 }
   1186 
   1187 // TODO(roberts): Differences from C++
   1188 // Centroid
   1189 // SnapLevel
   1190 // DistanceToPoint
   1191 // DistanceToBoundary
   1192 // Project
   1193 // ProjectToBoundary
   1194 // ApproxContains/ApproxDisjoint for Polygons
   1195 // InitTo{Intersection/ApproxIntersection/Union/ApproxUnion/Diff/ApproxDiff}
   1196 // InitToSimplified
   1197 // InitToSnapped
   1198 // IntersectWithPolyline
   1199 // ApproxIntersectWithPolyline
   1200 // SubtractFromPolyline
   1201 // ApproxSubtractFromPolyline
   1202 // DestructiveUnion
   1203 // DestructiveApproxUnion
   1204 // InitToCellUnionBorder
   1205 // IsNormalized
   1206 // Equal/BoundaryEqual/BoundaryApproxEqual/BoundaryNear Polygons
   1207 // BreakEdgesAndAddToBuilder
   1208 //
   1209 // clearLoops
   1210 // findLoopNestingError
   1211 // initToSimplifiedInternal
   1212 // internalClipPolyline
   1213 // clipBoundary