gtsocial-umbx

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

polyline.go (19348B)


      1 // Copyright 2016 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 	"github.com/golang/geo/s1"
     23 )
     24 
     25 // Polyline represents a sequence of zero or more vertices connected by
     26 // straight edges (geodesics). Edges of length 0 and 180 degrees are not
     27 // allowed, i.e. adjacent vertices should not be identical or antipodal.
     28 type Polyline []Point
     29 
     30 // PolylineFromLatLngs creates a new Polyline from the given LatLngs.
     31 func PolylineFromLatLngs(points []LatLng) *Polyline {
     32 	p := make(Polyline, len(points))
     33 	for k, v := range points {
     34 		p[k] = PointFromLatLng(v)
     35 	}
     36 	return &p
     37 }
     38 
     39 // Reverse reverses the order of the Polyline vertices.
     40 func (p *Polyline) Reverse() {
     41 	for i := 0; i < len(*p)/2; i++ {
     42 		(*p)[i], (*p)[len(*p)-i-1] = (*p)[len(*p)-i-1], (*p)[i]
     43 	}
     44 }
     45 
     46 // Length returns the length of this Polyline.
     47 func (p *Polyline) Length() s1.Angle {
     48 	var length s1.Angle
     49 
     50 	for i := 1; i < len(*p); i++ {
     51 		length += (*p)[i-1].Distance((*p)[i])
     52 	}
     53 	return length
     54 }
     55 
     56 // Centroid returns the true centroid of the polyline multiplied by the length of the
     57 // polyline. The result is not unit length, so you may wish to normalize it.
     58 //
     59 // Scaling by the Polyline length makes it easy to compute the centroid
     60 // of several Polylines (by simply adding up their centroids).
     61 func (p *Polyline) Centroid() Point {
     62 	var centroid Point
     63 	for i := 1; i < len(*p); i++ {
     64 		// The centroid (multiplied by length) is a vector toward the midpoint
     65 		// of the edge, whose length is twice the sin of half the angle between
     66 		// the two vertices. Defining theta to be this angle, we have:
     67 		vSum := (*p)[i-1].Add((*p)[i].Vector)  // Length == 2*cos(theta)
     68 		vDiff := (*p)[i-1].Sub((*p)[i].Vector) // Length == 2*sin(theta)
     69 
     70 		// Length == 2*sin(theta)
     71 		centroid = Point{centroid.Add(vSum.Mul(math.Sqrt(vDiff.Norm2() / vSum.Norm2())))}
     72 	}
     73 	return centroid
     74 }
     75 
     76 // Equal reports whether the given Polyline is exactly the same as this one.
     77 func (p *Polyline) Equal(b *Polyline) bool {
     78 	if len(*p) != len(*b) {
     79 		return false
     80 	}
     81 	for i, v := range *p {
     82 		if v != (*b)[i] {
     83 			return false
     84 		}
     85 	}
     86 
     87 	return true
     88 }
     89 
     90 // ApproxEqual reports whether two polylines have the same number of vertices,
     91 // and corresponding vertex pairs are separated by no more the standard margin.
     92 func (p *Polyline) ApproxEqual(o *Polyline) bool {
     93 	return p.approxEqual(o, s1.Angle(epsilon))
     94 }
     95 
     96 // approxEqual reports whether two polylines are equal within the given margin.
     97 func (p *Polyline) approxEqual(o *Polyline, maxError s1.Angle) bool {
     98 	if len(*p) != len(*o) {
     99 		return false
    100 	}
    101 	for offset, val := range *p {
    102 		if !val.approxEqual((*o)[offset], maxError) {
    103 			return false
    104 		}
    105 	}
    106 	return true
    107 }
    108 
    109 // CapBound returns the bounding Cap for this Polyline.
    110 func (p *Polyline) CapBound() Cap {
    111 	return p.RectBound().CapBound()
    112 }
    113 
    114 // RectBound returns the bounding Rect for this Polyline.
    115 func (p *Polyline) RectBound() Rect {
    116 	rb := NewRectBounder()
    117 	for _, v := range *p {
    118 		rb.AddPoint(v)
    119 	}
    120 	return rb.RectBound()
    121 }
    122 
    123 // ContainsCell reports whether this Polyline contains the given Cell. Always returns false
    124 // because "containment" is not numerically well-defined except at the Polyline vertices.
    125 func (p *Polyline) ContainsCell(cell Cell) bool {
    126 	return false
    127 }
    128 
    129 // IntersectsCell reports whether this Polyline intersects the given Cell.
    130 func (p *Polyline) IntersectsCell(cell Cell) bool {
    131 	if len(*p) == 0 {
    132 		return false
    133 	}
    134 
    135 	// We only need to check whether the cell contains vertex 0 for correctness,
    136 	// but these tests are cheap compared to edge crossings so we might as well
    137 	// check all the vertices.
    138 	for _, v := range *p {
    139 		if cell.ContainsPoint(v) {
    140 			return true
    141 		}
    142 	}
    143 
    144 	cellVertices := []Point{
    145 		cell.Vertex(0),
    146 		cell.Vertex(1),
    147 		cell.Vertex(2),
    148 		cell.Vertex(3),
    149 	}
    150 
    151 	for j := 0; j < 4; j++ {
    152 		crosser := NewChainEdgeCrosser(cellVertices[j], cellVertices[(j+1)&3], (*p)[0])
    153 		for i := 1; i < len(*p); i++ {
    154 			if crosser.ChainCrossingSign((*p)[i]) != DoNotCross {
    155 				// There is a proper crossing, or two vertices were the same.
    156 				return true
    157 			}
    158 		}
    159 	}
    160 	return false
    161 }
    162 
    163 // ContainsPoint returns false since Polylines are not closed.
    164 func (p *Polyline) ContainsPoint(point Point) bool {
    165 	return false
    166 }
    167 
    168 // CellUnionBound computes a covering of the Polyline.
    169 func (p *Polyline) CellUnionBound() []CellID {
    170 	return p.CapBound().CellUnionBound()
    171 }
    172 
    173 // NumEdges returns the number of edges in this shape.
    174 func (p *Polyline) NumEdges() int {
    175 	if len(*p) == 0 {
    176 		return 0
    177 	}
    178 	return len(*p) - 1
    179 }
    180 
    181 // Edge returns endpoints for the given edge index.
    182 func (p *Polyline) Edge(i int) Edge {
    183 	return Edge{(*p)[i], (*p)[i+1]}
    184 }
    185 
    186 // ReferencePoint returns the default reference point with negative containment because Polylines are not closed.
    187 func (p *Polyline) ReferencePoint() ReferencePoint {
    188 	return OriginReferencePoint(false)
    189 }
    190 
    191 // NumChains reports the number of contiguous edge chains in this Polyline.
    192 func (p *Polyline) NumChains() int {
    193 	return minInt(1, p.NumEdges())
    194 }
    195 
    196 // Chain returns the i-th edge Chain in the Shape.
    197 func (p *Polyline) Chain(chainID int) Chain {
    198 	return Chain{0, p.NumEdges()}
    199 }
    200 
    201 // ChainEdge returns the j-th edge of the i-th edge Chain.
    202 func (p *Polyline) ChainEdge(chainID, offset int) Edge {
    203 	return Edge{(*p)[offset], (*p)[offset+1]}
    204 }
    205 
    206 // ChainPosition returns a pair (i, j) such that edgeID is the j-th edge
    207 func (p *Polyline) ChainPosition(edgeID int) ChainPosition {
    208 	return ChainPosition{0, edgeID}
    209 }
    210 
    211 // Dimension returns the dimension of the geometry represented by this Polyline.
    212 func (p *Polyline) Dimension() int { return 1 }
    213 
    214 // IsEmpty reports whether this shape contains no points.
    215 func (p *Polyline) IsEmpty() bool { return defaultShapeIsEmpty(p) }
    216 
    217 // IsFull reports whether this shape contains all points on the sphere.
    218 func (p *Polyline) IsFull() bool { return defaultShapeIsFull(p) }
    219 
    220 func (p *Polyline) typeTag() typeTag { return typeTagPolyline }
    221 
    222 func (p *Polyline) privateInterface() {}
    223 
    224 // findEndVertex reports the maximal end index such that the line segment between
    225 // the start index and this one such that the line segment between these two
    226 // vertices passes within the given tolerance of all interior vertices, in order.
    227 func findEndVertex(p Polyline, tolerance s1.Angle, index int) int {
    228 	// The basic idea is to keep track of the "pie wedge" of angles
    229 	// from the starting vertex such that a ray from the starting
    230 	// vertex at that angle will pass through the discs of radius
    231 	// tolerance centered around all vertices processed so far.
    232 	//
    233 	// First we define a coordinate frame for the tangent and normal
    234 	// spaces at the starting vertex. Essentially this means picking
    235 	// three orthonormal vectors X,Y,Z such that X and Y span the
    236 	// tangent plane at the starting vertex, and Z is up. We use
    237 	// the coordinate frame to define a mapping from 3D direction
    238 	// vectors to a one-dimensional ray angle in the range (-π,
    239 	// π]. The angle of a direction vector is computed by
    240 	// transforming it into the X,Y,Z basis, and then calculating
    241 	// atan2(y,x). This mapping allows us to represent a wedge of
    242 	// angles as a 1D interval. Since the interval wraps around, we
    243 	// represent it as an Interval, i.e. an interval on the unit
    244 	// circle.
    245 	origin := p[index]
    246 	frame := getFrame(origin)
    247 
    248 	// As we go along, we keep track of the current wedge of angles
    249 	// and the distance to the last vertex (which must be
    250 	// non-decreasing).
    251 	currentWedge := s1.FullInterval()
    252 	var lastDistance s1.Angle
    253 
    254 	for index++; index < len(p); index++ {
    255 		candidate := p[index]
    256 		distance := origin.Distance(candidate)
    257 
    258 		// We don't allow simplification to create edges longer than
    259 		// 90 degrees, to avoid numeric instability as lengths
    260 		// approach 180 degrees. We do need to allow for original
    261 		// edges longer than 90 degrees, though.
    262 		if distance > math.Pi/2 && lastDistance > 0 {
    263 			break
    264 		}
    265 
    266 		// Vertices must be in increasing order along the ray, except
    267 		// for the initial disc around the origin.
    268 		if distance < lastDistance && lastDistance > tolerance {
    269 			break
    270 		}
    271 
    272 		lastDistance = distance
    273 
    274 		// Points that are within the tolerance distance of the origin
    275 		// do not constrain the ray direction, so we can ignore them.
    276 		if distance <= tolerance {
    277 			continue
    278 		}
    279 
    280 		// If the current wedge of angles does not contain the angle
    281 		// to this vertex, then stop right now. Note that the wedge
    282 		// of possible ray angles is not necessarily empty yet, but we
    283 		// can't continue unless we are willing to backtrack to the
    284 		// last vertex that was contained within the wedge (since we
    285 		// don't create new vertices). This would be more complicated
    286 		// and also make the worst-case running time more than linear.
    287 		direction := toFrame(frame, candidate)
    288 		center := math.Atan2(direction.Y, direction.X)
    289 		if !currentWedge.Contains(center) {
    290 			break
    291 		}
    292 
    293 		// To determine how this vertex constrains the possible ray
    294 		// angles, consider the triangle ABC where A is the origin, B
    295 		// is the candidate vertex, and C is one of the two tangent
    296 		// points between A and the spherical cap of radius
    297 		// tolerance centered at B. Then from the spherical law of
    298 		// sines, sin(a)/sin(A) = sin(c)/sin(C), where a and c are
    299 		// the lengths of the edges opposite A and C. In our case C
    300 		// is a 90 degree angle, therefore A = asin(sin(a) / sin(c)).
    301 		// Angle A is the half-angle of the allowable wedge.
    302 		halfAngle := math.Asin(math.Sin(tolerance.Radians()) / math.Sin(distance.Radians()))
    303 		target := s1.IntervalFromPointPair(center, center).Expanded(halfAngle)
    304 		currentWedge = currentWedge.Intersection(target)
    305 	}
    306 
    307 	// We break out of the loop when we reach a vertex index that
    308 	// can't be included in the line segment, so back up by one
    309 	// vertex.
    310 	return index - 1
    311 }
    312 
    313 // SubsampleVertices returns a subsequence of vertex indices such that the
    314 // polyline connecting these vertices is never further than the given tolerance from
    315 // the original polyline. Provided the first and last vertices are distinct,
    316 // they are always preserved; if they are not, the subsequence may contain
    317 // only a single index.
    318 //
    319 // Some useful properties of the algorithm:
    320 //
    321 //  - It runs in linear time.
    322 //
    323 //  - The output always represents a valid polyline. In particular, adjacent
    324 //    output vertices are never identical or antipodal.
    325 //
    326 //  - The method is not optimal, but it tends to produce 2-3% fewer
    327 //    vertices than the Douglas-Peucker algorithm with the same tolerance.
    328 //
    329 //  - The output is parametrically equivalent to the original polyline to
    330 //    within the given tolerance. For example, if a polyline backtracks on
    331 //    itself and then proceeds onwards, the backtracking will be preserved
    332 //    (to within the given tolerance). This is different than the
    333 //    Douglas-Peucker algorithm which only guarantees geometric equivalence.
    334 func (p *Polyline) SubsampleVertices(tolerance s1.Angle) []int {
    335 	var result []int
    336 
    337 	if len(*p) < 1 {
    338 		return result
    339 	}
    340 
    341 	result = append(result, 0)
    342 	clampedTolerance := s1.Angle(math.Max(tolerance.Radians(), 0))
    343 
    344 	for index := 0; index+1 < len(*p); {
    345 		nextIndex := findEndVertex(*p, clampedTolerance, index)
    346 		// Don't create duplicate adjacent vertices.
    347 		if (*p)[nextIndex] != (*p)[index] {
    348 			result = append(result, nextIndex)
    349 		}
    350 		index = nextIndex
    351 	}
    352 
    353 	return result
    354 }
    355 
    356 // Encode encodes the Polyline.
    357 func (p Polyline) Encode(w io.Writer) error {
    358 	e := &encoder{w: w}
    359 	p.encode(e)
    360 	return e.err
    361 }
    362 
    363 func (p Polyline) encode(e *encoder) {
    364 	e.writeInt8(encodingVersion)
    365 	e.writeUint32(uint32(len(p)))
    366 	for _, v := range p {
    367 		e.writeFloat64(v.X)
    368 		e.writeFloat64(v.Y)
    369 		e.writeFloat64(v.Z)
    370 	}
    371 }
    372 
    373 // Decode decodes the polyline.
    374 func (p *Polyline) Decode(r io.Reader) error {
    375 	d := decoder{r: asByteReader(r)}
    376 	p.decode(d)
    377 	return d.err
    378 }
    379 
    380 func (p *Polyline) decode(d decoder) {
    381 	version := d.readInt8()
    382 	if d.err != nil {
    383 		return
    384 	}
    385 	if int(version) != int(encodingVersion) {
    386 		d.err = fmt.Errorf("can't decode version %d; my version: %d", version, encodingVersion)
    387 		return
    388 	}
    389 	nvertices := d.readUint32()
    390 	if d.err != nil {
    391 		return
    392 	}
    393 	if nvertices > maxEncodedVertices {
    394 		d.err = fmt.Errorf("too many vertices (%d; max is %d)", nvertices, maxEncodedVertices)
    395 		return
    396 	}
    397 	*p = make([]Point, nvertices)
    398 	for i := range *p {
    399 		(*p)[i].X = d.readFloat64()
    400 		(*p)[i].Y = d.readFloat64()
    401 		(*p)[i].Z = d.readFloat64()
    402 	}
    403 }
    404 
    405 // Project returns a point on the polyline that is closest to the given point,
    406 // and the index of the next vertex after the projected point. The
    407 // value of that index is always in the range [1, len(polyline)].
    408 // The polyline must not be empty.
    409 func (p *Polyline) Project(point Point) (Point, int) {
    410 	if len(*p) == 1 {
    411 		// If there is only one vertex, it is always closest to any given point.
    412 		return (*p)[0], 1
    413 	}
    414 
    415 	// Initial value larger than any possible distance on the unit sphere.
    416 	minDist := 10 * s1.Radian
    417 	minIndex := -1
    418 
    419 	// Find the line segment in the polyline that is closest to the point given.
    420 	for i := 1; i < len(*p); i++ {
    421 		if dist := DistanceFromSegment(point, (*p)[i-1], (*p)[i]); dist < minDist {
    422 			minDist = dist
    423 			minIndex = i
    424 		}
    425 	}
    426 
    427 	// Compute the point on the segment found that is closest to the point given.
    428 	closest := Project(point, (*p)[minIndex-1], (*p)[minIndex])
    429 	if closest == (*p)[minIndex] {
    430 		minIndex++
    431 	}
    432 
    433 	return closest, minIndex
    434 }
    435 
    436 // IsOnRight reports whether the point given is on the right hand side of the
    437 // polyline, using a naive definition of "right-hand-sideness" where the point
    438 // is on the RHS of the polyline iff the point is on the RHS of the line segment
    439 // in the polyline which it is closest to.
    440 // The polyline must have at least 2 vertices.
    441 func (p *Polyline) IsOnRight(point Point) bool {
    442 	// If the closest point C is an interior vertex of the polyline, let B and D
    443 	// be the previous and next vertices. The given point P is on the right of
    444 	// the polyline (locally) if B, P, D are ordered CCW around vertex C.
    445 	closest, next := p.Project(point)
    446 	if closest == (*p)[next-1] && next > 1 && next < len(*p) {
    447 		if point == (*p)[next-1] {
    448 			// Polyline vertices are not on the RHS.
    449 			return false
    450 		}
    451 		return OrderedCCW((*p)[next-2], point, (*p)[next], (*p)[next-1])
    452 	}
    453 	// Otherwise, the closest point C is incident to exactly one polyline edge.
    454 	// We test the point P against that edge.
    455 	if next == len(*p) {
    456 		next--
    457 	}
    458 	return Sign(point, (*p)[next], (*p)[next-1])
    459 }
    460 
    461 // Validate checks whether this is a valid polyline or not.
    462 func (p *Polyline) Validate() error {
    463 	// All vertices must be unit length.
    464 	for i, pt := range *p {
    465 		if !pt.IsUnit() {
    466 			return fmt.Errorf("vertex %d is not unit length", i)
    467 		}
    468 	}
    469 
    470 	// Adjacent vertices must not be identical or antipodal.
    471 	for i := 1; i < len(*p); i++ {
    472 		prev, cur := (*p)[i-1], (*p)[i]
    473 		if prev == cur {
    474 			return fmt.Errorf("vertices %d and %d are identical", i-1, i)
    475 		}
    476 		if prev == (Point{cur.Mul(-1)}) {
    477 			return fmt.Errorf("vertices %d and %d are antipodal", i-1, i)
    478 		}
    479 	}
    480 
    481 	return nil
    482 }
    483 
    484 // Intersects reports whether this polyline intersects the given polyline. If
    485 // the polylines share a vertex they are considered to be intersecting. When a
    486 // polyline endpoint is the only intersection with the other polyline, the
    487 // function may return true or false arbitrarily.
    488 //
    489 // The running time is quadratic in the number of vertices.
    490 func (p *Polyline) Intersects(o *Polyline) bool {
    491 	if len(*p) == 0 || len(*o) == 0 {
    492 		return false
    493 	}
    494 
    495 	if !p.RectBound().Intersects(o.RectBound()) {
    496 		return false
    497 	}
    498 
    499 	// TODO(roberts): Use ShapeIndex here.
    500 	for i := 1; i < len(*p); i++ {
    501 		crosser := NewChainEdgeCrosser((*p)[i-1], (*p)[i], (*o)[0])
    502 		for j := 1; j < len(*o); j++ {
    503 			if crosser.ChainCrossingSign((*o)[j]) != DoNotCross {
    504 				return true
    505 			}
    506 		}
    507 	}
    508 	return false
    509 }
    510 
    511 // Interpolate returns the point whose distance from vertex 0 along the polyline is
    512 // the given fraction of the polyline's total length, and the index of
    513 // the next vertex after the interpolated point P. Fractions less than zero
    514 // or greater than one are clamped. The return value is unit length. The cost of
    515 // this function is currently linear in the number of vertices.
    516 //
    517 // This method allows the caller to easily construct a given suffix of the
    518 // polyline by concatenating P with the polyline vertices starting at that next
    519 // vertex. Note that P is guaranteed to be different than the point at the next
    520 // vertex, so this will never result in a duplicate vertex.
    521 //
    522 // The polyline must not be empty. Note that if fraction >= 1.0, then the next
    523 // vertex will be set to len(p) (indicating that no vertices from the polyline
    524 // need to be appended). The value of the next vertex is always between 1 and
    525 // len(p).
    526 //
    527 // This method can also be used to construct a prefix of the polyline, by
    528 // taking the polyline vertices up to next vertex-1 and appending the
    529 // returned point P if it is different from the last vertex (since in this
    530 // case there is no guarantee of distinctness).
    531 func (p *Polyline) Interpolate(fraction float64) (Point, int) {
    532 	// We intentionally let the (fraction >= 1) case fall through, since
    533 	// we need to handle it in the loop below in any case because of
    534 	// possible roundoff errors.
    535 	if fraction <= 0 {
    536 		return (*p)[0], 1
    537 	}
    538 	target := s1.Angle(fraction) * p.Length()
    539 
    540 	for i := 1; i < len(*p); i++ {
    541 		length := (*p)[i-1].Distance((*p)[i])
    542 		if target < length {
    543 			// This interpolates with respect to arc length rather than
    544 			// straight-line distance, and produces a unit-length result.
    545 			result := InterpolateAtDistance(target, (*p)[i-1], (*p)[i])
    546 
    547 			// It is possible that (result == vertex(i)) due to rounding errors.
    548 			if result == (*p)[i] {
    549 				return result, i + 1
    550 			}
    551 			return result, i
    552 		}
    553 		target -= length
    554 	}
    555 
    556 	return (*p)[len(*p)-1], len(*p)
    557 }
    558 
    559 // Uninterpolate is the inverse operation of Interpolate. Given a point on the
    560 // polyline, it returns the ratio of the distance to the point from the
    561 // beginning of the polyline over the length of the polyline. The return
    562 // value is always betwen 0 and 1 inclusive.
    563 //
    564 // The polyline should not be empty.  If it has fewer than 2 vertices, the
    565 // return value is zero.
    566 func (p *Polyline) Uninterpolate(point Point, nextVertex int) float64 {
    567 	if len(*p) < 2 {
    568 		return 0
    569 	}
    570 
    571 	var sum s1.Angle
    572 	for i := 1; i < nextVertex; i++ {
    573 		sum += (*p)[i-1].Distance((*p)[i])
    574 	}
    575 	lengthToPoint := sum + (*p)[nextVertex-1].Distance(point)
    576 	for i := nextVertex; i < len(*p); i++ {
    577 		sum += (*p)[i-1].Distance((*p)[i])
    578 	}
    579 	// The ratio can be greater than 1.0 due to rounding errors or because the
    580 	// point is not exactly on the polyline.
    581 	return minFloat64(1.0, float64(lengthToPoint/sum))
    582 }
    583 
    584 // TODO(roberts): Differences from C++.
    585 // NearlyCoversPolyline
    586 // InitToSnapped
    587 // InitToSimplified
    588 // SnapLevel
    589 // encode/decode compressed