contains_point_query.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2018 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. package s2
  15. // VertexModel defines whether shapes are considered to contain their vertices.
  16. // Note that these definitions differ from the ones used by BooleanOperation.
  17. //
  18. // Note that points other than vertices are never contained by polylines.
  19. // If you want need this behavior, use ClosestEdgeQuery's IsDistanceLess
  20. // with a suitable distance threshold instead.
  21. type VertexModel int
  22. const (
  23. // VertexModelOpen means no shapes contain their vertices (not even
  24. // points). Therefore Contains(Point) returns true if and only if the
  25. // point is in the interior of some polygon.
  26. VertexModelOpen VertexModel = iota
  27. // VertexModelSemiOpen means that polygon point containment is defined
  28. // such that if several polygons tile the region around a vertex, then
  29. // exactly one of those polygons contains that vertex. Points and
  30. // polylines still do not contain any vertices.
  31. VertexModelSemiOpen
  32. // VertexModelClosed means all shapes contain their vertices (including
  33. // points and polylines).
  34. VertexModelClosed
  35. )
  36. // ContainsPointQuery determines whether one or more shapes in a ShapeIndex
  37. // contain a given Point. The ShapeIndex may contain any number of points,
  38. // polylines, and/or polygons (possibly overlapping). Shape boundaries may be
  39. // modeled as Open, SemiOpen, or Closed (this affects whether or not shapes are
  40. // considered to contain their vertices).
  41. //
  42. // Note that if you need to do a large number of point containment
  43. // tests, it is more efficient to re-use the query rather than creating a new
  44. // one each time.
  45. type ContainsPointQuery struct {
  46. model VertexModel
  47. index *ShapeIndex
  48. iter *ShapeIndexIterator
  49. }
  50. // NewContainsPointQuery creates a new instance of the ContainsPointQuery for the index
  51. // and given vertex model choice.
  52. func NewContainsPointQuery(index *ShapeIndex, model VertexModel) *ContainsPointQuery {
  53. return &ContainsPointQuery{
  54. index: index,
  55. model: model,
  56. iter: index.Iterator(),
  57. }
  58. }
  59. // Contains reports whether any shape in the queries index contains the point p
  60. // under the queries vertex model (Open, SemiOpen, or Closed).
  61. func (q *ContainsPointQuery) Contains(p Point) bool {
  62. if !q.iter.LocatePoint(p) {
  63. return false
  64. }
  65. cell := q.iter.IndexCell()
  66. for _, clipped := range cell.shapes {
  67. if q.shapeContains(clipped, q.iter.Center(), p) {
  68. return true
  69. }
  70. }
  71. return false
  72. }
  73. // shapeContains reports whether the clippedShape from the iterator's center position contains
  74. // the given point.
  75. func (q *ContainsPointQuery) shapeContains(clipped *clippedShape, center, p Point) bool {
  76. inside := clipped.containsCenter
  77. numEdges := clipped.numEdges()
  78. if numEdges <= 0 {
  79. return inside
  80. }
  81. shape := q.index.Shape(clipped.shapeID)
  82. if !shape.HasInterior() {
  83. // Points and polylines can be ignored unless the vertex model is Closed.
  84. if q.model != VertexModelClosed {
  85. return false
  86. }
  87. // Otherwise, the point is contained if and only if it matches a vertex.
  88. for _, edgeID := range clipped.edges {
  89. edge := shape.Edge(edgeID)
  90. if edge.V0 == p || edge.V1 == p {
  91. return true
  92. }
  93. }
  94. return false
  95. }
  96. // Test containment by drawing a line segment from the cell center to the
  97. // given point and counting edge crossings.
  98. crosser := NewEdgeCrosser(center, p)
  99. for _, edgeID := range clipped.edges {
  100. edge := shape.Edge(edgeID)
  101. sign := crosser.CrossingSign(edge.V0, edge.V1)
  102. if sign == DoNotCross {
  103. continue
  104. }
  105. if sign == MaybeCross {
  106. // For the Open and Closed models, check whether p is a vertex.
  107. if q.model != VertexModelSemiOpen && (edge.V0 == p || edge.V1 == p) {
  108. return (q.model == VertexModelClosed)
  109. }
  110. // C++ plays fast and loose with the int <-> bool conversions here.
  111. if VertexCrossing(crosser.a, crosser.b, edge.V0, edge.V1) {
  112. sign = Cross
  113. } else {
  114. sign = DoNotCross
  115. }
  116. }
  117. inside = inside != (sign == Cross)
  118. }
  119. return inside
  120. }
  121. // ShapeContains reports whether the given shape contains the point under this
  122. // queries vertex model (Open, SemiOpen, or Closed).
  123. //
  124. // This requires the shape belongs to this queries index.
  125. func (q *ContainsPointQuery) ShapeContains(shape Shape, p Point) bool {
  126. if !q.iter.LocatePoint(p) {
  127. return false
  128. }
  129. clipped := q.iter.IndexCell().findByShapeID(q.index.idForShape(shape))
  130. if clipped == nil {
  131. return false
  132. }
  133. return q.shapeContains(clipped, q.iter.Center(), p)
  134. }
  135. // TODO(roberts): Remaining methods from C++
  136. // func (q *ContainsPointQuery) ContainingShapes(p Point) []Shape
  137. // type shapeVisitorFunc func(shape Shape) bool
  138. // func (q *ContainsPointQuery) VisitContainingShapes(p Point, v shapeVisitorFunc) bool
  139. // type edgeVisitorFunc func(shape ShapeEdge) bool
  140. // func (q *ContainsPointQuery) VisitIncidentEdges(p Point, v edgeVisitorFunc) bool