shapeindex.go (55623B)
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 "math" 19 "sort" 20 "sync" 21 "sync/atomic" 22 23 "github.com/golang/geo/r1" 24 "github.com/golang/geo/r2" 25 ) 26 27 // CellRelation describes the possible relationships between a target cell 28 // and the cells of the ShapeIndex. If the target is an index cell or is 29 // contained by an index cell, it is Indexed. If the target is subdivided 30 // into one or more index cells, it is Subdivided. Otherwise it is Disjoint. 31 type CellRelation int 32 33 // The possible CellRelations for a ShapeIndex. 34 const ( 35 Indexed CellRelation = iota 36 Subdivided 37 Disjoint 38 ) 39 40 const ( 41 // cellPadding defines the total error when clipping an edge which comes 42 // from two sources: 43 // (1) Clipping the original spherical edge to a cube face (the face edge). 44 // The maximum error in this step is faceClipErrorUVCoord. 45 // (2) Clipping the face edge to the u- or v-coordinate of a cell boundary. 46 // The maximum error in this step is edgeClipErrorUVCoord. 47 // Finally, since we encounter the same errors when clipping query edges, we 48 // double the total error so that we only need to pad edges during indexing 49 // and not at query time. 50 cellPadding = 2.0 * (faceClipErrorUVCoord + edgeClipErrorUVCoord) 51 52 // cellSizeToLongEdgeRatio defines the cell size relative to the length of an 53 // edge at which it is first considered to be long. Long edges do not 54 // contribute toward the decision to subdivide a cell further. For example, 55 // a value of 2.0 means that the cell must be at least twice the size of the 56 // edge in order for that edge to be counted. There are two reasons for not 57 // counting long edges: (1) such edges typically need to be propagated to 58 // several children, which increases time and memory costs without much benefit, 59 // and (2) in pathological cases, many long edges close together could force 60 // subdivision to continue all the way to the leaf cell level. 61 cellSizeToLongEdgeRatio = 1.0 62 ) 63 64 // clippedShape represents the part of a shape that intersects a Cell. 65 // It consists of the set of edge IDs that intersect that cell and a boolean 66 // indicating whether the center of the cell is inside the shape (for shapes 67 // that have an interior). 68 // 69 // Note that the edges themselves are not clipped; we always use the original 70 // edges for intersection tests so that the results will be the same as the 71 // original shape. 72 type clippedShape struct { 73 // shapeID is the index of the shape this clipped shape is a part of. 74 shapeID int32 75 76 // containsCenter indicates if the center of the CellID this shape has been 77 // clipped to falls inside this shape. This is false for shapes that do not 78 // have an interior. 79 containsCenter bool 80 81 // edges is the ordered set of ShapeIndex original edge IDs. Edges 82 // are stored in increasing order of edge ID. 83 edges []int 84 } 85 86 // newClippedShape returns a new clipped shape for the given shapeID and number of expected edges. 87 func newClippedShape(id int32, numEdges int) *clippedShape { 88 return &clippedShape{ 89 shapeID: id, 90 edges: make([]int, numEdges), 91 } 92 } 93 94 // numEdges returns the number of edges that intersect the CellID of the Cell this was clipped to. 95 func (c *clippedShape) numEdges() int { 96 return len(c.edges) 97 } 98 99 // containsEdge reports if this clipped shape contains the given edge ID. 100 func (c *clippedShape) containsEdge(id int) bool { 101 // Linear search is fast because the number of edges per shape is typically 102 // very small (less than 10). 103 for _, e := range c.edges { 104 if e == id { 105 return true 106 } 107 } 108 return false 109 } 110 111 // ShapeIndexCell stores the index contents for a particular CellID. 112 type ShapeIndexCell struct { 113 shapes []*clippedShape 114 } 115 116 // NewShapeIndexCell creates a new cell that is sized to hold the given number of shapes. 117 func NewShapeIndexCell(numShapes int) *ShapeIndexCell { 118 return &ShapeIndexCell{ 119 shapes: make([]*clippedShape, numShapes), 120 } 121 } 122 123 // numEdges reports the total number of edges in all clipped shapes in this cell. 124 func (s *ShapeIndexCell) numEdges() int { 125 var e int 126 for _, cs := range s.shapes { 127 e += cs.numEdges() 128 } 129 return e 130 } 131 132 // add adds the given clipped shape to this index cell. 133 func (s *ShapeIndexCell) add(c *clippedShape) { 134 // C++ uses a set, so it's ordered and unique. We don't currently catch 135 // the case when a duplicate value is added. 136 s.shapes = append(s.shapes, c) 137 } 138 139 // findByShapeID returns the clipped shape that contains the given shapeID, 140 // or nil if none of the clipped shapes contain it. 141 func (s *ShapeIndexCell) findByShapeID(shapeID int32) *clippedShape { 142 // Linear search is fine because the number of shapes per cell is typically 143 // very small (most often 1), and is large only for pathological inputs 144 // (e.g. very deeply nested loops). 145 for _, clipped := range s.shapes { 146 if clipped.shapeID == shapeID { 147 return clipped 148 } 149 } 150 return nil 151 } 152 153 // faceEdge and clippedEdge store temporary edge data while the index is being 154 // updated. 155 // 156 // While it would be possible to combine all the edge information into one 157 // structure, there are two good reasons for separating it: 158 // 159 // - Memory usage. Separating the two means that we only need to 160 // store one copy of the per-face data no matter how many times an edge is 161 // subdivided, and it also lets us delay computing bounding boxes until 162 // they are needed for processing each face (when the dataset spans 163 // multiple faces). 164 // 165 // - Performance. UpdateEdges is significantly faster on large polygons when 166 // the data is separated, because it often only needs to access the data in 167 // clippedEdge and this data is cached more successfully. 168 169 // faceEdge represents an edge that has been projected onto a given face, 170 type faceEdge struct { 171 shapeID int32 // The ID of shape that this edge belongs to 172 edgeID int // Edge ID within that shape 173 maxLevel int // Not desirable to subdivide this edge beyond this level 174 hasInterior bool // Belongs to a shape that has a dimension of 2 175 a, b r2.Point // The edge endpoints, clipped to a given face 176 edge Edge // The original edge. 177 } 178 179 // clippedEdge represents the portion of that edge that has been clipped to a given Cell. 180 type clippedEdge struct { 181 faceEdge *faceEdge // The original unclipped edge 182 bound r2.Rect // Bounding box for the clipped portion 183 } 184 185 // ShapeIndexIteratorPos defines the set of possible iterator starting positions. By 186 // default iterators are unpositioned, since this avoids an extra seek in this 187 // situation where one of the seek methods (such as Locate) is immediately called. 188 type ShapeIndexIteratorPos int 189 190 const ( 191 // IteratorBegin specifies the iterator should be positioned at the beginning of the index. 192 IteratorBegin ShapeIndexIteratorPos = iota 193 // IteratorEnd specifies the iterator should be positioned at the end of the index. 194 IteratorEnd 195 ) 196 197 // ShapeIndexIterator is an iterator that provides low-level access to 198 // the cells of the index. Cells are returned in increasing order of CellID. 199 // 200 // for it := index.Iterator(); !it.Done(); it.Next() { 201 // fmt.Print(it.CellID()) 202 // } 203 // 204 type ShapeIndexIterator struct { 205 index *ShapeIndex 206 position int 207 id CellID 208 cell *ShapeIndexCell 209 } 210 211 // NewShapeIndexIterator creates a new iterator for the given index. If a starting 212 // position is specified, the iterator is positioned at the given spot. 213 func NewShapeIndexIterator(index *ShapeIndex, pos ...ShapeIndexIteratorPos) *ShapeIndexIterator { 214 s := &ShapeIndexIterator{ 215 index: index, 216 } 217 218 if len(pos) > 0 { 219 if len(pos) > 1 { 220 panic("too many ShapeIndexIteratorPos arguments") 221 } 222 switch pos[0] { 223 case IteratorBegin: 224 s.Begin() 225 case IteratorEnd: 226 s.End() 227 default: 228 panic("unknown ShapeIndexIteratorPos value") 229 } 230 } 231 232 return s 233 } 234 235 func (s *ShapeIndexIterator) clone() *ShapeIndexIterator { 236 return &ShapeIndexIterator{ 237 index: s.index, 238 position: s.position, 239 id: s.id, 240 cell: s.cell, 241 } 242 } 243 244 // CellID returns the CellID of the current index cell. 245 // If s.Done() is true, a value larger than any valid CellID is returned. 246 func (s *ShapeIndexIterator) CellID() CellID { 247 return s.id 248 } 249 250 // IndexCell returns the current index cell. 251 func (s *ShapeIndexIterator) IndexCell() *ShapeIndexCell { 252 // TODO(roberts): C++ has this call a virtual method to allow subclasses 253 // of ShapeIndexIterator to do other work before returning the cell. Do 254 // we need such a thing? 255 return s.cell 256 } 257 258 // Center returns the Point at the center of the current position of the iterator. 259 func (s *ShapeIndexIterator) Center() Point { 260 return s.CellID().Point() 261 } 262 263 // Begin positions the iterator at the beginning of the index. 264 func (s *ShapeIndexIterator) Begin() { 265 if !s.index.IsFresh() { 266 s.index.maybeApplyUpdates() 267 } 268 s.position = 0 269 s.refresh() 270 } 271 272 // Next positions the iterator at the next index cell. 273 func (s *ShapeIndexIterator) Next() { 274 s.position++ 275 s.refresh() 276 } 277 278 // Prev advances the iterator to the previous cell in the index and returns true to 279 // indicate it was not yet at the beginning of the index. If the iterator is at the 280 // first cell the call does nothing and returns false. 281 func (s *ShapeIndexIterator) Prev() bool { 282 if s.position <= 0 { 283 return false 284 } 285 286 s.position-- 287 s.refresh() 288 return true 289 } 290 291 // End positions the iterator at the end of the index. 292 func (s *ShapeIndexIterator) End() { 293 s.position = len(s.index.cells) 294 s.refresh() 295 } 296 297 // Done reports if the iterator is positioned at or after the last index cell. 298 func (s *ShapeIndexIterator) Done() bool { 299 return s.id == SentinelCellID 300 } 301 302 // refresh updates the stored internal iterator values. 303 func (s *ShapeIndexIterator) refresh() { 304 if s.position < len(s.index.cells) { 305 s.id = s.index.cells[s.position] 306 s.cell = s.index.cellMap[s.CellID()] 307 } else { 308 s.id = SentinelCellID 309 s.cell = nil 310 } 311 } 312 313 // seek positions the iterator at the first cell whose ID >= target, or at the 314 // end of the index if no such cell exists. 315 func (s *ShapeIndexIterator) seek(target CellID) { 316 s.position = sort.Search(len(s.index.cells), func(i int) bool { 317 return s.index.cells[i] >= target 318 }) 319 s.refresh() 320 } 321 322 // LocatePoint positions the iterator at the cell that contains the given Point. 323 // If no such cell exists, the iterator position is unspecified, and false is returned. 324 // The cell at the matched position is guaranteed to contain all edges that might 325 // intersect the line segment between target and the cell's center. 326 func (s *ShapeIndexIterator) LocatePoint(p Point) bool { 327 // Let I = cellMap.LowerBound(T), where T is the leaf cell containing 328 // point P. Then if T is contained by an index cell, then the 329 // containing cell is either I or I'. We test for containment by comparing 330 // the ranges of leaf cells spanned by T, I, and I'. 331 target := cellIDFromPoint(p) 332 s.seek(target) 333 if !s.Done() && s.CellID().RangeMin() <= target { 334 return true 335 } 336 337 if s.Prev() && s.CellID().RangeMax() >= target { 338 return true 339 } 340 return false 341 } 342 343 // LocateCellID attempts to position the iterator at the first matching index cell 344 // in the index that has some relation to the given CellID. Let T be the target CellID. 345 // If T is contained by (or equal to) some index cell I, then the iterator is positioned 346 // at I and returns Indexed. Otherwise if T contains one or more (smaller) index cells, 347 // then the iterator is positioned at the first such cell I and return Subdivided. 348 // Otherwise Disjoint is returned and the iterator position is undefined. 349 func (s *ShapeIndexIterator) LocateCellID(target CellID) CellRelation { 350 // Let T be the target, let I = cellMap.LowerBound(T.RangeMin()), and 351 // let I' be the predecessor of I. If T contains any index cells, then T 352 // contains I. Similarly, if T is contained by an index cell, then the 353 // containing cell is either I or I'. We test for containment by comparing 354 // the ranges of leaf cells spanned by T, I, and I'. 355 s.seek(target.RangeMin()) 356 if !s.Done() { 357 if s.CellID() >= target && s.CellID().RangeMin() <= target { 358 return Indexed 359 } 360 if s.CellID() <= target.RangeMax() { 361 return Subdivided 362 } 363 } 364 if s.Prev() && s.CellID().RangeMax() >= target { 365 return Indexed 366 } 367 return Disjoint 368 } 369 370 // tracker keeps track of which shapes in a given set contain a particular point 371 // (the focus). It provides an efficient way to move the focus from one point 372 // to another and incrementally update the set of shapes which contain it. We use 373 // this to compute which shapes contain the center of every CellID in the index, 374 // by advancing the focus from one cell center to the next. 375 // 376 // Initially the focus is at the start of the CellID space-filling curve. We then 377 // visit all the cells that are being added to the ShapeIndex in increasing order 378 // of CellID. For each cell, we draw two edges: one from the entry vertex to the 379 // center, and another from the center to the exit vertex (where entry and exit 380 // refer to the points where the space-filling curve enters and exits the cell). 381 // By counting edge crossings we can incrementally compute which shapes contain 382 // the cell center. Note that the same set of shapes will always contain the exit 383 // point of one cell and the entry point of the next cell in the index, because 384 // either (a) these two points are actually the same, or (b) the intervening 385 // cells in CellID order are all empty, and therefore there are no edge crossings 386 // if we follow this path from one cell to the other. 387 // 388 // In C++, this is S2ShapeIndex::InteriorTracker. 389 type tracker struct { 390 isActive bool 391 a Point 392 b Point 393 nextCellID CellID 394 crosser *EdgeCrosser 395 shapeIDs []int32 396 397 // Shape ids saved by saveAndClearStateBefore. The state is never saved 398 // recursively so we don't need to worry about maintaining a stack. 399 savedIDs []int32 400 } 401 402 // newTracker returns a new tracker with the appropriate defaults. 403 func newTracker() *tracker { 404 // As shapes are added, we compute which ones contain the start of the 405 // CellID space-filling curve by drawing an edge from OriginPoint to this 406 // point and counting how many shape edges cross this edge. 407 t := &tracker{ 408 isActive: false, 409 b: trackerOrigin(), 410 nextCellID: CellIDFromFace(0).ChildBeginAtLevel(maxLevel), 411 } 412 t.drawTo(Point{faceUVToXYZ(0, -1, -1).Normalize()}) // CellID curve start 413 414 return t 415 } 416 417 // trackerOrigin returns the initial focus point when the tracker is created 418 // (corresponding to the start of the CellID space-filling curve). 419 func trackerOrigin() Point { 420 // The start of the S2CellId space-filling curve. 421 return Point{faceUVToXYZ(0, -1, -1).Normalize()} 422 } 423 424 // focus returns the current focus point of the tracker. 425 func (t *tracker) focus() Point { return t.b } 426 427 // addShape adds a shape whose interior should be tracked. containsOrigin indicates 428 // whether the current focus point is inside the shape. Alternatively, if 429 // the focus point is in the process of being moved (via moveTo/drawTo), you 430 // can also specify containsOrigin at the old focus point and call testEdge 431 // for every edge of the shape that might cross the current drawTo line. 432 // This updates the state to correspond to the new focus point. 433 // 434 // This requires shape.HasInterior 435 func (t *tracker) addShape(shapeID int32, containsFocus bool) { 436 t.isActive = true 437 if containsFocus { 438 t.toggleShape(shapeID) 439 } 440 } 441 442 // moveTo moves the focus of the tracker to the given point. This method should 443 // only be used when it is known that there are no edge crossings between the old 444 // and new focus locations; otherwise use drawTo. 445 func (t *tracker) moveTo(b Point) { t.b = b } 446 447 // drawTo moves the focus of the tracker to the given point. After this method is 448 // called, testEdge should be called with all edges that may cross the line 449 // segment between the old and new focus locations. 450 func (t *tracker) drawTo(b Point) { 451 t.a = t.b 452 t.b = b 453 // TODO: the edge crosser may need an in-place Init method if this gets expensive 454 t.crosser = NewEdgeCrosser(t.a, t.b) 455 } 456 457 // testEdge checks if the given edge crosses the current edge, and if so, then 458 // toggle the state of the given shapeID. 459 // This requires shape to have an interior. 460 func (t *tracker) testEdge(shapeID int32, edge Edge) { 461 if t.crosser.EdgeOrVertexCrossing(edge.V0, edge.V1) { 462 t.toggleShape(shapeID) 463 } 464 } 465 466 // setNextCellID is used to indicate that the last argument to moveTo or drawTo 467 // was the entry vertex of the given CellID, i.e. the tracker is positioned at the 468 // start of this cell. By using this method together with atCellID, the caller 469 // can avoid calling moveTo in cases where the exit vertex of the previous cell 470 // is the same as the entry vertex of the current cell. 471 func (t *tracker) setNextCellID(nextCellID CellID) { 472 t.nextCellID = nextCellID.RangeMin() 473 } 474 475 // atCellID reports if the focus is already at the entry vertex of the given 476 // CellID (provided that the caller calls setNextCellID as each cell is processed). 477 func (t *tracker) atCellID(cellid CellID) bool { 478 return cellid.RangeMin() == t.nextCellID 479 } 480 481 // toggleShape adds or removes the given shapeID from the set of IDs it is tracking. 482 func (t *tracker) toggleShape(shapeID int32) { 483 // Most shapeIDs slices are small, so special case the common steps. 484 485 // If there is nothing here, add it. 486 if len(t.shapeIDs) == 0 { 487 t.shapeIDs = append(t.shapeIDs, shapeID) 488 return 489 } 490 491 // If it's the first element, drop it from the slice. 492 if t.shapeIDs[0] == shapeID { 493 t.shapeIDs = t.shapeIDs[1:] 494 return 495 } 496 497 for i, s := range t.shapeIDs { 498 if s < shapeID { 499 continue 500 } 501 502 // If it's in the set, cut it out. 503 if s == shapeID { 504 copy(t.shapeIDs[i:], t.shapeIDs[i+1:]) // overwrite the ith element 505 t.shapeIDs = t.shapeIDs[:len(t.shapeIDs)-1] 506 return 507 } 508 509 // We've got to a point in the slice where we should be inserted. 510 // (the given shapeID is now less than the current positions id.) 511 t.shapeIDs = append(t.shapeIDs[0:i], 512 append([]int32{shapeID}, t.shapeIDs[i:len(t.shapeIDs)]...)...) 513 return 514 } 515 516 // We got to the end and didn't find it, so add it to the list. 517 t.shapeIDs = append(t.shapeIDs, shapeID) 518 } 519 520 // saveAndClearStateBefore makes an internal copy of the state for shape ids below 521 // the given limit, and then clear the state for those shapes. This is used during 522 // incremental updates to track the state of added and removed shapes separately. 523 func (t *tracker) saveAndClearStateBefore(limitShapeID int32) { 524 limit := t.lowerBound(limitShapeID) 525 t.savedIDs = append([]int32(nil), t.shapeIDs[:limit]...) 526 t.shapeIDs = t.shapeIDs[limit:] 527 } 528 529 // restoreStateBefore restores the state previously saved by saveAndClearStateBefore. 530 // This only affects the state for shapeIDs below "limitShapeID". 531 func (t *tracker) restoreStateBefore(limitShapeID int32) { 532 limit := t.lowerBound(limitShapeID) 533 t.shapeIDs = append(append([]int32(nil), t.savedIDs...), t.shapeIDs[limit:]...) 534 t.savedIDs = nil 535 } 536 537 // lowerBound returns the shapeID of the first entry x where x >= shapeID. 538 func (t *tracker) lowerBound(shapeID int32) int32 { 539 panic("not implemented") 540 } 541 542 // removedShape represents a set of edges from the given shape that is queued for removal. 543 type removedShape struct { 544 shapeID int32 545 hasInterior bool 546 containsTrackerOrigin bool 547 edges []Edge 548 } 549 550 // There are three basic states the index can be in. 551 const ( 552 stale int32 = iota // There are pending updates. 553 updating // Updates are currently being applied. 554 fresh // There are no pending updates. 555 ) 556 557 // ShapeIndex indexes a set of Shapes, where a Shape is some collection of edges 558 // that optionally defines an interior. It can be used to represent a set of 559 // points, a set of polylines, or a set of polygons. For Shapes that have 560 // interiors, the index makes it very fast to determine which Shape(s) contain 561 // a given point or region. 562 // 563 // The index can be updated incrementally by adding or removing shapes. It is 564 // designed to handle up to hundreds of millions of edges. All data structures 565 // are designed to be small, so the index is compact; generally it is smaller 566 // than the underlying data being indexed. The index is also fast to construct. 567 // 568 // Polygon, Loop, and Polyline implement Shape which allows these objects to 569 // be indexed easily. You can find useful query methods in CrossingEdgeQuery 570 // and ClosestEdgeQuery (Not yet implemented in Go). 571 // 572 // Example showing how to build an index of Polylines: 573 // 574 // index := NewShapeIndex() 575 // for _, polyline := range polylines { 576 // index.Add(polyline); 577 // } 578 // // Now you can use a CrossingEdgeQuery or ClosestEdgeQuery here. 579 // 580 type ShapeIndex struct { 581 // shapes is a map of shape ID to shape. 582 shapes map[int32]Shape 583 584 // The maximum number of edges per cell. 585 // TODO(roberts): Update the comments when the usage of this is implemented. 586 maxEdgesPerCell int 587 588 // nextID tracks the next ID to hand out. IDs are not reused when shapes 589 // are removed from the index. 590 nextID int32 591 592 // cellMap is a map from CellID to the set of clipped shapes that intersect that 593 // cell. The cell IDs cover a set of non-overlapping regions on the sphere. 594 // In C++, this is a BTree, so the cells are ordered naturally by the data structure. 595 cellMap map[CellID]*ShapeIndexCell 596 // Track the ordered list of cell IDs. 597 cells []CellID 598 599 // The current status of the index; accessed atomically. 600 status int32 601 602 // Additions and removals are queued and processed on the first subsequent 603 // query. There are several reasons to do this: 604 // 605 // - It is significantly more efficient to process updates in batches if 606 // the amount of entities added grows. 607 // - Often the index will never be queried, in which case we can save both 608 // the time and memory required to build it. Examples: 609 // + Loops that are created simply to pass to an Polygon. (We don't 610 // need the Loop index, because Polygon builds its own index.) 611 // + Applications that load a database of geometry and then query only 612 // a small fraction of it. 613 // 614 // The main drawback is that we need to go to some extra work to ensure that 615 // some methods are still thread-safe. Note that the goal is *not* to 616 // make this thread-safe in general, but simply to hide the fact that 617 // we defer some of the indexing work until query time. 618 // 619 // This mutex protects all of following fields in the index. 620 mu sync.RWMutex 621 622 // pendingAdditionsPos is the index of the first entry that has not been processed 623 // via applyUpdatesInternal. 624 pendingAdditionsPos int32 625 626 // The set of shapes that have been queued for removal but not processed yet by 627 // applyUpdatesInternal. 628 pendingRemovals []*removedShape 629 } 630 631 // NewShapeIndex creates a new ShapeIndex. 632 func NewShapeIndex() *ShapeIndex { 633 return &ShapeIndex{ 634 maxEdgesPerCell: 10, 635 shapes: make(map[int32]Shape), 636 cellMap: make(map[CellID]*ShapeIndexCell), 637 cells: nil, 638 status: fresh, 639 } 640 } 641 642 // Iterator returns an iterator for this index. 643 func (s *ShapeIndex) Iterator() *ShapeIndexIterator { 644 s.maybeApplyUpdates() 645 return NewShapeIndexIterator(s, IteratorBegin) 646 } 647 648 // Begin positions the iterator at the first cell in the index. 649 func (s *ShapeIndex) Begin() *ShapeIndexIterator { 650 s.maybeApplyUpdates() 651 return NewShapeIndexIterator(s, IteratorBegin) 652 } 653 654 // End positions the iterator at the last cell in the index. 655 func (s *ShapeIndex) End() *ShapeIndexIterator { 656 // TODO(roberts): It's possible that updates could happen to the index between 657 // the time this is called and the time the iterators position is used and this 658 // will be invalid or not the end. For now, things will be undefined if this 659 // happens. See about referencing the IsFresh to guard for this in the future. 660 s.maybeApplyUpdates() 661 return NewShapeIndexIterator(s, IteratorEnd) 662 } 663 664 // Len reports the number of Shapes in this index. 665 func (s *ShapeIndex) Len() int { 666 return len(s.shapes) 667 } 668 669 // Reset resets the index to its original state. 670 func (s *ShapeIndex) Reset() { 671 s.shapes = make(map[int32]Shape) 672 s.nextID = 0 673 s.cellMap = make(map[CellID]*ShapeIndexCell) 674 s.cells = nil 675 atomic.StoreInt32(&s.status, fresh) 676 } 677 678 // NumEdges returns the number of edges in this index. 679 func (s *ShapeIndex) NumEdges() int { 680 numEdges := 0 681 for _, shape := range s.shapes { 682 numEdges += shape.NumEdges() 683 } 684 return numEdges 685 } 686 687 // NumEdgesUpTo returns the number of edges in the given index, up to the given 688 // limit. If the limit is encountered, the current running total is returned, 689 // which may be more than the limit. 690 func (s *ShapeIndex) NumEdgesUpTo(limit int) int { 691 var numEdges int 692 // We choose to iterate over the shapes in order to match the counting 693 // up behavior in C++ and for test compatibility instead of using a 694 // more idiomatic range over the shape map. 695 for i := int32(0); i <= s.nextID; i++ { 696 s := s.Shape(i) 697 if s == nil { 698 continue 699 } 700 numEdges += s.NumEdges() 701 if numEdges >= limit { 702 break 703 } 704 } 705 706 return numEdges 707 } 708 709 // Shape returns the shape with the given ID, or nil if the shape has been removed from the index. 710 func (s *ShapeIndex) Shape(id int32) Shape { return s.shapes[id] } 711 712 // idForShape returns the id of the given shape in this index, or -1 if it is 713 // not in the index. 714 // 715 // TODO(roberts): Need to figure out an appropriate way to expose this on a Shape. 716 // C++ allows a given S2 type (Loop, Polygon, etc) to be part of multiple indexes. 717 // By having each type extend S2Shape which has an id element, they all inherit their 718 // own id field rather than having to track it themselves. 719 func (s *ShapeIndex) idForShape(shape Shape) int32 { 720 for k, v := range s.shapes { 721 if v == shape { 722 return k 723 } 724 } 725 return -1 726 } 727 728 // Add adds the given shape to the index and returns the assigned ID.. 729 func (s *ShapeIndex) Add(shape Shape) int32 { 730 s.shapes[s.nextID] = shape 731 s.nextID++ 732 atomic.StoreInt32(&s.status, stale) 733 return s.nextID - 1 734 } 735 736 // Remove removes the given shape from the index. 737 func (s *ShapeIndex) Remove(shape Shape) { 738 // The index updates itself lazily because it is much more efficient to 739 // process additions and removals in batches. 740 id := s.idForShape(shape) 741 742 // If the shape wasn't found, it's already been removed or was not in the index. 743 if s.shapes[id] == nil { 744 return 745 } 746 747 // Remove the shape from the shapes map. 748 delete(s.shapes, id) 749 750 // We are removing a shape that has not yet been added to the index, 751 // so there is nothing else to do. 752 if id >= s.pendingAdditionsPos { 753 return 754 } 755 756 numEdges := shape.NumEdges() 757 removed := &removedShape{ 758 shapeID: id, 759 hasInterior: shape.Dimension() == 2, 760 containsTrackerOrigin: shape.ReferencePoint().Contained, 761 edges: make([]Edge, numEdges), 762 } 763 764 for e := 0; e < numEdges; e++ { 765 removed.edges[e] = shape.Edge(e) 766 } 767 768 s.pendingRemovals = append(s.pendingRemovals, removed) 769 atomic.StoreInt32(&s.status, stale) 770 } 771 772 // Build triggers the update of the index. Calls to Add and Release are normally 773 // queued and processed on the first subsequent query. This has many advantages, 774 // the most important of which is that sometimes there *is* no subsequent 775 // query, which lets us avoid building the index completely. 776 // 777 // This method forces any pending updates to be applied immediately. 778 func (s *ShapeIndex) Build() { 779 s.maybeApplyUpdates() 780 } 781 782 // IsFresh reports if there are no pending updates that need to be applied. 783 // This can be useful to avoid building the index unnecessarily, or for 784 // choosing between two different algorithms depending on whether the index 785 // is available. 786 // 787 // The returned index status may be slightly out of date if the index was 788 // built in a different thread. This is fine for the intended use (as an 789 // efficiency hint), but it should not be used by internal methods. 790 func (s *ShapeIndex) IsFresh() bool { 791 return atomic.LoadInt32(&s.status) == fresh 792 } 793 794 // isFirstUpdate reports if this is the first update to the index. 795 func (s *ShapeIndex) isFirstUpdate() bool { 796 // Note that it is not sufficient to check whether cellMap is empty, since 797 // entries are added to it during the update process. 798 return s.pendingAdditionsPos == 0 799 } 800 801 // isShapeBeingRemoved reports if the shape with the given ID is currently slated for removal. 802 func (s *ShapeIndex) isShapeBeingRemoved(shapeID int32) bool { 803 // All shape ids being removed fall below the index position of shapes being added. 804 return shapeID < s.pendingAdditionsPos 805 } 806 807 // maybeApplyUpdates checks if the index pieces have changed, and if so, applies pending updates. 808 func (s *ShapeIndex) maybeApplyUpdates() { 809 // TODO(roberts): To avoid acquiring and releasing the mutex on every 810 // query, we should use atomic operations when testing whether the status 811 // is fresh and when updating the status to be fresh. This guarantees 812 // that any thread that sees a status of fresh will also see the 813 // corresponding index updates. 814 if atomic.LoadInt32(&s.status) != fresh { 815 s.mu.Lock() 816 s.applyUpdatesInternal() 817 atomic.StoreInt32(&s.status, fresh) 818 s.mu.Unlock() 819 } 820 } 821 822 // applyUpdatesInternal does the actual work of updating the index by applying all 823 // pending additions and removals. It does *not* update the indexes status. 824 func (s *ShapeIndex) applyUpdatesInternal() { 825 // TODO(roberts): Building the index can use up to 20x as much memory per 826 // edge as the final index memory size. If this causes issues, add in 827 // batched updating to limit the amount of items per batch to a 828 // configurable memory footprint overhead. 829 t := newTracker() 830 831 // allEdges maps a Face to a collection of faceEdges. 832 allEdges := make([][]faceEdge, 6) 833 834 for _, p := range s.pendingRemovals { 835 s.removeShapeInternal(p, allEdges, t) 836 } 837 838 for id := s.pendingAdditionsPos; id < int32(len(s.shapes)); id++ { 839 s.addShapeInternal(id, allEdges, t) 840 } 841 842 for face := 0; face < 6; face++ { 843 s.updateFaceEdges(face, allEdges[face], t) 844 } 845 846 s.pendingRemovals = s.pendingRemovals[:0] 847 s.pendingAdditionsPos = int32(len(s.shapes)) 848 // It is the caller's responsibility to update the index status. 849 } 850 851 // addShapeInternal clips all edges of the given shape to the six cube faces, 852 // adds the clipped edges to the set of allEdges, and starts tracking its 853 // interior if necessary. 854 func (s *ShapeIndex) addShapeInternal(shapeID int32, allEdges [][]faceEdge, t *tracker) { 855 shape, ok := s.shapes[shapeID] 856 if !ok { 857 // This shape has already been removed. 858 return 859 } 860 861 faceEdge := faceEdge{ 862 shapeID: shapeID, 863 hasInterior: shape.Dimension() == 2, 864 } 865 866 if faceEdge.hasInterior { 867 t.addShape(shapeID, containsBruteForce(shape, t.focus())) 868 } 869 870 numEdges := shape.NumEdges() 871 for e := 0; e < numEdges; e++ { 872 edge := shape.Edge(e) 873 874 faceEdge.edgeID = e 875 faceEdge.edge = edge 876 faceEdge.maxLevel = maxLevelForEdge(edge) 877 s.addFaceEdge(faceEdge, allEdges) 878 } 879 } 880 881 // addFaceEdge adds the given faceEdge into the collection of all edges. 882 func (s *ShapeIndex) addFaceEdge(fe faceEdge, allEdges [][]faceEdge) { 883 aFace := face(fe.edge.V0.Vector) 884 // See if both endpoints are on the same face, and are far enough from 885 // the edge of the face that they don't intersect any (padded) adjacent face. 886 if aFace == face(fe.edge.V1.Vector) { 887 x, y := validFaceXYZToUV(aFace, fe.edge.V0.Vector) 888 fe.a = r2.Point{x, y} 889 x, y = validFaceXYZToUV(aFace, fe.edge.V1.Vector) 890 fe.b = r2.Point{x, y} 891 892 maxUV := 1 - cellPadding 893 if math.Abs(fe.a.X) <= maxUV && math.Abs(fe.a.Y) <= maxUV && 894 math.Abs(fe.b.X) <= maxUV && math.Abs(fe.b.Y) <= maxUV { 895 allEdges[aFace] = append(allEdges[aFace], fe) 896 return 897 } 898 } 899 900 // Otherwise, we simply clip the edge to all six faces. 901 for face := 0; face < 6; face++ { 902 if aClip, bClip, intersects := ClipToPaddedFace(fe.edge.V0, fe.edge.V1, face, cellPadding); intersects { 903 fe.a = aClip 904 fe.b = bClip 905 allEdges[face] = append(allEdges[face], fe) 906 } 907 } 908 } 909 910 // updateFaceEdges adds or removes the various edges from the index. 911 // An edge is added if shapes[id] is not nil, and removed otherwise. 912 func (s *ShapeIndex) updateFaceEdges(face int, faceEdges []faceEdge, t *tracker) { 913 numEdges := len(faceEdges) 914 if numEdges == 0 && len(t.shapeIDs) == 0 { 915 return 916 } 917 918 // Create the initial clippedEdge for each faceEdge. Additional clipped 919 // edges are created when edges are split between child cells. We create 920 // two arrays, one containing the edge data and another containing pointers 921 // to those edges, so that during the recursion we only need to copy 922 // pointers in order to propagate an edge to the correct child. 923 clippedEdges := make([]*clippedEdge, numEdges) 924 bound := r2.EmptyRect() 925 for e := 0; e < numEdges; e++ { 926 clipped := &clippedEdge{ 927 faceEdge: &faceEdges[e], 928 } 929 clipped.bound = r2.RectFromPoints(faceEdges[e].a, faceEdges[e].b) 930 clippedEdges[e] = clipped 931 bound = bound.AddRect(clipped.bound) 932 } 933 934 // Construct the initial face cell containing all the edges, and then update 935 // all the edges in the index recursively. 936 faceID := CellIDFromFace(face) 937 pcell := PaddedCellFromCellID(faceID, cellPadding) 938 939 disjointFromIndex := s.isFirstUpdate() 940 if numEdges > 0 { 941 shrunkID := s.shrinkToFit(pcell, bound) 942 if shrunkID != pcell.id { 943 // All the edges are contained by some descendant of the face cell. We 944 // can save a lot of work by starting directly with that cell, but if we 945 // are in the interior of at least one shape then we need to create 946 // index entries for the cells we are skipping over. 947 s.skipCellRange(faceID.RangeMin(), shrunkID.RangeMin(), t, disjointFromIndex) 948 pcell = PaddedCellFromCellID(shrunkID, cellPadding) 949 s.updateEdges(pcell, clippedEdges, t, disjointFromIndex) 950 s.skipCellRange(shrunkID.RangeMax().Next(), faceID.RangeMax().Next(), t, disjointFromIndex) 951 return 952 } 953 } 954 955 // Otherwise (no edges, or no shrinking is possible), subdivide normally. 956 s.updateEdges(pcell, clippedEdges, t, disjointFromIndex) 957 } 958 959 // shrinkToFit shrinks the PaddedCell to fit within the given bounds. 960 func (s *ShapeIndex) shrinkToFit(pcell *PaddedCell, bound r2.Rect) CellID { 961 shrunkID := pcell.ShrinkToFit(bound) 962 963 if !s.isFirstUpdate() && shrunkID != pcell.CellID() { 964 // Don't shrink any smaller than the existing index cells, since we need 965 // to combine the new edges with those cells. 966 iter := s.Iterator() 967 if iter.LocateCellID(shrunkID) == Indexed { 968 shrunkID = iter.CellID() 969 } 970 } 971 return shrunkID 972 } 973 974 // skipCellRange skips over the cells in the given range, creating index cells if we are 975 // currently in the interior of at least one shape. 976 func (s *ShapeIndex) skipCellRange(begin, end CellID, t *tracker, disjointFromIndex bool) { 977 // If we aren't in the interior of a shape, then skipping over cells is easy. 978 if len(t.shapeIDs) == 0 { 979 return 980 } 981 982 // Otherwise generate the list of cell ids that we need to visit, and create 983 // an index entry for each one. 984 skipped := CellUnionFromRange(begin, end) 985 for _, cell := range skipped { 986 var clippedEdges []*clippedEdge 987 s.updateEdges(PaddedCellFromCellID(cell, cellPadding), clippedEdges, t, disjointFromIndex) 988 } 989 } 990 991 // updateEdges adds or removes the given edges whose bounding boxes intersect a 992 // given cell. disjointFromIndex is an optimization hint indicating that cellMap 993 // does not contain any entries that overlap the given cell. 994 func (s *ShapeIndex) updateEdges(pcell *PaddedCell, edges []*clippedEdge, t *tracker, disjointFromIndex bool) { 995 // This function is recursive with a maximum recursion depth of 30 (maxLevel). 996 997 // Incremental updates are handled as follows. All edges being added or 998 // removed are combined together in edges, and all shapes with interiors 999 // are tracked using tracker. We subdivide recursively as usual until we 1000 // encounter an existing index cell. At this point we absorb the index 1001 // cell as follows: 1002 // 1003 // - Edges and shapes that are being removed are deleted from edges and 1004 // tracker. 1005 // - All remaining edges and shapes from the index cell are added to 1006 // edges and tracker. 1007 // - Continue subdividing recursively, creating new index cells as needed. 1008 // - When the recursion gets back to the cell that was absorbed, we 1009 // restore edges and tracker to their previous state. 1010 // 1011 // Note that the only reason that we include removed shapes in the recursive 1012 // subdivision process is so that we can find all of the index cells that 1013 // contain those shapes efficiently, without maintaining an explicit list of 1014 // index cells for each shape (which would be expensive in terms of memory). 1015 indexCellAbsorbed := false 1016 if !disjointFromIndex { 1017 // There may be existing index cells contained inside pcell. If we 1018 // encounter such a cell, we need to combine the edges being updated with 1019 // the existing cell contents by absorbing the cell. 1020 iter := s.Iterator() 1021 r := iter.LocateCellID(pcell.id) 1022 if r == Disjoint { 1023 disjointFromIndex = true 1024 } else if r == Indexed { 1025 // Absorb the index cell by transferring its contents to edges and 1026 // deleting it. We also start tracking the interior of any new shapes. 1027 s.absorbIndexCell(pcell, iter, edges, t) 1028 indexCellAbsorbed = true 1029 disjointFromIndex = true 1030 } else { 1031 // DCHECK_EQ(SUBDIVIDED, r) 1032 } 1033 } 1034 1035 // If there are existing index cells below us, then we need to keep 1036 // subdividing so that we can merge with those cells. Otherwise, 1037 // makeIndexCell checks if the number of edges is small enough, and creates 1038 // an index cell if possible (returning true when it does so). 1039 if !disjointFromIndex || !s.makeIndexCell(pcell, edges, t) { 1040 // TODO(roberts): If it turns out to have memory problems when there 1041 // are 10M+ edges in the index, look into pre-allocating space so we 1042 // are not always appending. 1043 childEdges := [2][2][]*clippedEdge{} // [i][j] 1044 1045 // Compute the middle of the padded cell, defined as the rectangle in 1046 // (u,v)-space that belongs to all four (padded) children. By comparing 1047 // against the four boundaries of middle we can determine which children 1048 // each edge needs to be propagated to. 1049 middle := pcell.Middle() 1050 1051 // Build up a vector edges to be passed to each child cell. The (i,j) 1052 // directions are left (i=0), right (i=1), lower (j=0), and upper (j=1). 1053 // Note that the vast majority of edges are propagated to a single child. 1054 for _, edge := range edges { 1055 if edge.bound.X.Hi <= middle.X.Lo { 1056 // Edge is entirely contained in the two left children. 1057 a, b := s.clipVAxis(edge, middle.Y) 1058 if a != nil { 1059 childEdges[0][0] = append(childEdges[0][0], a) 1060 } 1061 if b != nil { 1062 childEdges[0][1] = append(childEdges[0][1], b) 1063 } 1064 } else if edge.bound.X.Lo >= middle.X.Hi { 1065 // Edge is entirely contained in the two right children. 1066 a, b := s.clipVAxis(edge, middle.Y) 1067 if a != nil { 1068 childEdges[1][0] = append(childEdges[1][0], a) 1069 } 1070 if b != nil { 1071 childEdges[1][1] = append(childEdges[1][1], b) 1072 } 1073 } else if edge.bound.Y.Hi <= middle.Y.Lo { 1074 // Edge is entirely contained in the two lower children. 1075 if a := s.clipUBound(edge, 1, middle.X.Hi); a != nil { 1076 childEdges[0][0] = append(childEdges[0][0], a) 1077 } 1078 if b := s.clipUBound(edge, 0, middle.X.Lo); b != nil { 1079 childEdges[1][0] = append(childEdges[1][0], b) 1080 } 1081 } else if edge.bound.Y.Lo >= middle.Y.Hi { 1082 // Edge is entirely contained in the two upper children. 1083 if a := s.clipUBound(edge, 1, middle.X.Hi); a != nil { 1084 childEdges[0][1] = append(childEdges[0][1], a) 1085 } 1086 if b := s.clipUBound(edge, 0, middle.X.Lo); b != nil { 1087 childEdges[1][1] = append(childEdges[1][1], b) 1088 } 1089 } else { 1090 // The edge bound spans all four children. The edge 1091 // itself intersects either three or four padded children. 1092 left := s.clipUBound(edge, 1, middle.X.Hi) 1093 a, b := s.clipVAxis(left, middle.Y) 1094 if a != nil { 1095 childEdges[0][0] = append(childEdges[0][0], a) 1096 } 1097 if b != nil { 1098 childEdges[0][1] = append(childEdges[0][1], b) 1099 } 1100 right := s.clipUBound(edge, 0, middle.X.Lo) 1101 a, b = s.clipVAxis(right, middle.Y) 1102 if a != nil { 1103 childEdges[1][0] = append(childEdges[1][0], a) 1104 } 1105 if b != nil { 1106 childEdges[1][1] = append(childEdges[1][1], b) 1107 } 1108 } 1109 } 1110 1111 // Now recursively update the edges in each child. We call the children in 1112 // increasing order of CellID so that when the index is first constructed, 1113 // all insertions into cellMap are at the end (which is much faster). 1114 for pos := 0; pos < 4; pos++ { 1115 i, j := pcell.ChildIJ(pos) 1116 if len(childEdges[i][j]) > 0 || len(t.shapeIDs) > 0 { 1117 s.updateEdges(PaddedCellFromParentIJ(pcell, i, j), childEdges[i][j], 1118 t, disjointFromIndex) 1119 } 1120 } 1121 } 1122 1123 if indexCellAbsorbed { 1124 // Restore the state for any edges being removed that we are tracking. 1125 t.restoreStateBefore(s.pendingAdditionsPos) 1126 } 1127 } 1128 1129 // makeIndexCell builds an indexCell from the given padded cell and set of edges and adds 1130 // it to the index. If the cell or edges are empty, no cell is added. 1131 func (s *ShapeIndex) makeIndexCell(p *PaddedCell, edges []*clippedEdge, t *tracker) bool { 1132 // If the cell is empty, no index cell is needed. (In most cases this 1133 // situation is detected before we get to this point, but this can happen 1134 // when all shapes in a cell are removed.) 1135 if len(edges) == 0 && len(t.shapeIDs) == 0 { 1136 return true 1137 } 1138 1139 // Count the number of edges that have not reached their maximum level yet. 1140 // Return false if there are too many such edges. 1141 count := 0 1142 for _, ce := range edges { 1143 if p.Level() < ce.faceEdge.maxLevel { 1144 count++ 1145 } 1146 1147 if count > s.maxEdgesPerCell { 1148 return false 1149 } 1150 } 1151 1152 // Possible optimization: Continue subdividing as long as exactly one child 1153 // of the padded cell intersects the given edges. This can be done by finding 1154 // the bounding box of all the edges and calling ShrinkToFit: 1155 // 1156 // cellID = p.ShrinkToFit(RectBound(edges)); 1157 // 1158 // Currently this is not beneficial; it slows down construction by 4-25% 1159 // (mainly computing the union of the bounding rectangles) and also slows 1160 // down queries (since more recursive clipping is required to get down to 1161 // the level of a spatial index cell). But it may be worth trying again 1162 // once containsCenter is computed and all algorithms are modified to 1163 // take advantage of it. 1164 1165 // We update the InteriorTracker as follows. For every Cell in the index 1166 // we construct two edges: one edge from entry vertex of the cell to its 1167 // center, and one from the cell center to its exit vertex. Here entry 1168 // and exit refer the CellID ordering, i.e. the order in which points 1169 // are encountered along the 2 space-filling curve. The exit vertex then 1170 // becomes the entry vertex for the next cell in the index, unless there are 1171 // one or more empty intervening cells, in which case the InteriorTracker 1172 // state is unchanged because the intervening cells have no edges. 1173 1174 // Shift the InteriorTracker focus point to the center of the current cell. 1175 if t.isActive && len(edges) != 0 { 1176 if !t.atCellID(p.id) { 1177 t.moveTo(p.EntryVertex()) 1178 } 1179 t.drawTo(p.Center()) 1180 s.testAllEdges(edges, t) 1181 } 1182 1183 // Allocate and fill a new index cell. To get the total number of shapes we 1184 // need to merge the shapes associated with the intersecting edges together 1185 // with the shapes that happen to contain the cell center. 1186 cshapeIDs := t.shapeIDs 1187 numShapes := s.countShapes(edges, cshapeIDs) 1188 cell := NewShapeIndexCell(numShapes) 1189 1190 // To fill the index cell we merge the two sources of shapes: edge shapes 1191 // (those that have at least one edge that intersects this cell), and 1192 // containing shapes (those that contain the cell center). We keep track 1193 // of the index of the next intersecting edge and the next containing shape 1194 // as we go along. Both sets of shape ids are already sorted. 1195 eNext := 0 1196 cNextIdx := 0 1197 for i := 0; i < numShapes; i++ { 1198 var clipped *clippedShape 1199 // advance to next value base + i 1200 eshapeID := int32(s.Len()) 1201 cshapeID := eshapeID // Sentinels 1202 1203 if eNext != len(edges) { 1204 eshapeID = edges[eNext].faceEdge.shapeID 1205 } 1206 if cNextIdx < len(cshapeIDs) { 1207 cshapeID = cshapeIDs[cNextIdx] 1208 } 1209 eBegin := eNext 1210 if cshapeID < eshapeID { 1211 // The entire cell is in the shape interior. 1212 clipped = newClippedShape(cshapeID, 0) 1213 clipped.containsCenter = true 1214 cNextIdx++ 1215 } else { 1216 // Count the number of edges for this shape and allocate space for them. 1217 for eNext < len(edges) && edges[eNext].faceEdge.shapeID == eshapeID { 1218 eNext++ 1219 } 1220 clipped = newClippedShape(eshapeID, eNext-eBegin) 1221 for e := eBegin; e < eNext; e++ { 1222 clipped.edges[e-eBegin] = edges[e].faceEdge.edgeID 1223 } 1224 if cshapeID == eshapeID { 1225 clipped.containsCenter = true 1226 cNextIdx++ 1227 } 1228 } 1229 cell.shapes[i] = clipped 1230 } 1231 1232 // Add this cell to the map. 1233 s.cellMap[p.id] = cell 1234 s.cells = append(s.cells, p.id) 1235 1236 // Shift the tracker focus point to the exit vertex of this cell. 1237 if t.isActive && len(edges) != 0 { 1238 t.drawTo(p.ExitVertex()) 1239 s.testAllEdges(edges, t) 1240 t.setNextCellID(p.id.Next()) 1241 } 1242 return true 1243 } 1244 1245 // updateBound updates the specified endpoint of the given clipped edge and returns the 1246 // resulting clipped edge. 1247 func (s *ShapeIndex) updateBound(edge *clippedEdge, uEnd int, u float64, vEnd int, v float64) *clippedEdge { 1248 c := &clippedEdge{faceEdge: edge.faceEdge} 1249 if uEnd == 0 { 1250 c.bound.X.Lo = u 1251 c.bound.X.Hi = edge.bound.X.Hi 1252 } else { 1253 c.bound.X.Lo = edge.bound.X.Lo 1254 c.bound.X.Hi = u 1255 } 1256 1257 if vEnd == 0 { 1258 c.bound.Y.Lo = v 1259 c.bound.Y.Hi = edge.bound.Y.Hi 1260 } else { 1261 c.bound.Y.Lo = edge.bound.Y.Lo 1262 c.bound.Y.Hi = v 1263 } 1264 1265 return c 1266 } 1267 1268 // clipUBound clips the given endpoint (lo=0, hi=1) of the u-axis so that 1269 // it does not extend past the given value of the given edge. 1270 func (s *ShapeIndex) clipUBound(edge *clippedEdge, uEnd int, u float64) *clippedEdge { 1271 // First check whether the edge actually requires any clipping. (Sometimes 1272 // this method is called when clipping is not necessary, e.g. when one edge 1273 // endpoint is in the overlap area between two padded child cells.) 1274 if uEnd == 0 { 1275 if edge.bound.X.Lo >= u { 1276 return edge 1277 } 1278 } else { 1279 if edge.bound.X.Hi <= u { 1280 return edge 1281 } 1282 } 1283 // We interpolate the new v-value from the endpoints of the original edge. 1284 // This has two advantages: (1) we don't need to store the clipped endpoints 1285 // at all, just their bounding box; and (2) it avoids the accumulation of 1286 // roundoff errors due to repeated interpolations. The result needs to be 1287 // clamped to ensure that it is in the appropriate range. 1288 e := edge.faceEdge 1289 v := edge.bound.Y.ClampPoint(interpolateFloat64(u, e.a.X, e.b.X, e.a.Y, e.b.Y)) 1290 1291 // Determine which endpoint of the v-axis bound to update. If the edge 1292 // slope is positive we update the same endpoint, otherwise we update the 1293 // opposite endpoint. 1294 var vEnd int 1295 positiveSlope := (e.a.X > e.b.X) == (e.a.Y > e.b.Y) 1296 if (uEnd == 1) == positiveSlope { 1297 vEnd = 1 1298 } 1299 return s.updateBound(edge, uEnd, u, vEnd, v) 1300 } 1301 1302 // clipVBound clips the given endpoint (lo=0, hi=1) of the v-axis so that 1303 // it does not extend past the given value of the given edge. 1304 func (s *ShapeIndex) clipVBound(edge *clippedEdge, vEnd int, v float64) *clippedEdge { 1305 if vEnd == 0 { 1306 if edge.bound.Y.Lo >= v { 1307 return edge 1308 } 1309 } else { 1310 if edge.bound.Y.Hi <= v { 1311 return edge 1312 } 1313 } 1314 1315 // We interpolate the new v-value from the endpoints of the original edge. 1316 // This has two advantages: (1) we don't need to store the clipped endpoints 1317 // at all, just their bounding box; and (2) it avoids the accumulation of 1318 // roundoff errors due to repeated interpolations. The result needs to be 1319 // clamped to ensure that it is in the appropriate range. 1320 e := edge.faceEdge 1321 u := edge.bound.X.ClampPoint(interpolateFloat64(v, e.a.Y, e.b.Y, e.a.X, e.b.X)) 1322 1323 // Determine which endpoint of the v-axis bound to update. If the edge 1324 // slope is positive we update the same endpoint, otherwise we update the 1325 // opposite endpoint. 1326 var uEnd int 1327 positiveSlope := (e.a.X > e.b.X) == (e.a.Y > e.b.Y) 1328 if (vEnd == 1) == positiveSlope { 1329 uEnd = 1 1330 } 1331 return s.updateBound(edge, uEnd, u, vEnd, v) 1332 } 1333 1334 // cliupVAxis returns the given edge clipped to within the boundaries of the middle 1335 // interval along the v-axis, and adds the result to its children. 1336 func (s *ShapeIndex) clipVAxis(edge *clippedEdge, middle r1.Interval) (a, b *clippedEdge) { 1337 if edge.bound.Y.Hi <= middle.Lo { 1338 // Edge is entirely contained in the lower child. 1339 return edge, nil 1340 } else if edge.bound.Y.Lo >= middle.Hi { 1341 // Edge is entirely contained in the upper child. 1342 return nil, edge 1343 } 1344 // The edge bound spans both children. 1345 return s.clipVBound(edge, 1, middle.Hi), s.clipVBound(edge, 0, middle.Lo) 1346 } 1347 1348 // absorbIndexCell absorbs an index cell by transferring its contents to edges 1349 // and/or "tracker", and then delete this cell from the index. If edges includes 1350 // any edges that are being removed, this method also updates their 1351 // InteriorTracker state to correspond to the exit vertex of this cell. 1352 func (s *ShapeIndex) absorbIndexCell(p *PaddedCell, iter *ShapeIndexIterator, edges []*clippedEdge, t *tracker) { 1353 // When we absorb a cell, we erase all the edges that are being removed. 1354 // However when we are finished with this cell, we want to restore the state 1355 // of those edges (since that is how we find all the index cells that need 1356 // to be updated). The edges themselves are restored automatically when 1357 // UpdateEdges returns from its recursive call, but the InteriorTracker 1358 // state needs to be restored explicitly. 1359 // 1360 // Here we first update the InteriorTracker state for removed edges to 1361 // correspond to the exit vertex of this cell, and then save the 1362 // InteriorTracker state. This state will be restored by UpdateEdges when 1363 // it is finished processing the contents of this cell. 1364 if t.isActive && len(edges) != 0 && s.isShapeBeingRemoved(edges[0].faceEdge.shapeID) { 1365 // We probably need to update the tracker. ("Probably" because 1366 // it's possible that all shapes being removed do not have interiors.) 1367 if !t.atCellID(p.id) { 1368 t.moveTo(p.EntryVertex()) 1369 } 1370 t.drawTo(p.ExitVertex()) 1371 t.setNextCellID(p.id.Next()) 1372 for _, edge := range edges { 1373 fe := edge.faceEdge 1374 if !s.isShapeBeingRemoved(fe.shapeID) { 1375 break // All shapes being removed come first. 1376 } 1377 if fe.hasInterior { 1378 t.testEdge(fe.shapeID, fe.edge) 1379 } 1380 } 1381 } 1382 1383 // Save the state of the edges being removed, so that it can be restored 1384 // when we are finished processing this cell and its children. We don't 1385 // need to save the state of the edges being added because they aren't being 1386 // removed from "edges" and will therefore be updated normally as we visit 1387 // this cell and its children. 1388 t.saveAndClearStateBefore(s.pendingAdditionsPos) 1389 1390 // Create a faceEdge for each edge in this cell that isn't being removed. 1391 var faceEdges []*faceEdge 1392 trackerMoved := false 1393 1394 cell := iter.IndexCell() 1395 for _, clipped := range cell.shapes { 1396 shapeID := clipped.shapeID 1397 shape := s.Shape(shapeID) 1398 if shape == nil { 1399 continue // This shape is being removed. 1400 } 1401 1402 numClipped := clipped.numEdges() 1403 1404 // If this shape has an interior, start tracking whether we are inside the 1405 // shape. updateEdges wants to know whether the entry vertex of this 1406 // cell is inside the shape, but we only know whether the center of the 1407 // cell is inside the shape, so we need to test all the edges against the 1408 // line segment from the cell center to the entry vertex. 1409 edge := &faceEdge{ 1410 shapeID: shapeID, 1411 hasInterior: shape.Dimension() == 2, 1412 } 1413 1414 if edge.hasInterior { 1415 t.addShape(shapeID, clipped.containsCenter) 1416 // There might not be any edges in this entire cell (i.e., it might be 1417 // in the interior of all shapes), so we delay updating the tracker 1418 // until we see the first edge. 1419 if !trackerMoved && numClipped > 0 { 1420 t.moveTo(p.Center()) 1421 t.drawTo(p.EntryVertex()) 1422 t.setNextCellID(p.id) 1423 trackerMoved = true 1424 } 1425 } 1426 for i := 0; i < numClipped; i++ { 1427 edgeID := clipped.edges[i] 1428 edge.edgeID = edgeID 1429 edge.edge = shape.Edge(edgeID) 1430 edge.maxLevel = maxLevelForEdge(edge.edge) 1431 if edge.hasInterior { 1432 t.testEdge(shapeID, edge.edge) 1433 } 1434 var ok bool 1435 edge.a, edge.b, ok = ClipToPaddedFace(edge.edge.V0, edge.edge.V1, p.id.Face(), cellPadding) 1436 if !ok { 1437 panic("invariant failure in ShapeIndex") 1438 } 1439 faceEdges = append(faceEdges, edge) 1440 } 1441 } 1442 // Now create a clippedEdge for each faceEdge, and put them in "new_edges". 1443 var newEdges []*clippedEdge 1444 for _, faceEdge := range faceEdges { 1445 clipped := &clippedEdge{ 1446 faceEdge: faceEdge, 1447 bound: clippedEdgeBound(faceEdge.a, faceEdge.b, p.bound), 1448 } 1449 newEdges = append(newEdges, clipped) 1450 } 1451 1452 // Discard any edges from "edges" that are being removed, and append the 1453 // remainder to "newEdges" (This keeps the edges sorted by shape id.) 1454 for i, clipped := range edges { 1455 if !s.isShapeBeingRemoved(clipped.faceEdge.shapeID) { 1456 newEdges = append(newEdges, edges[i:]...) 1457 break 1458 } 1459 } 1460 1461 // Update the edge list and delete this cell from the index. 1462 edges, newEdges = newEdges, edges 1463 delete(s.cellMap, p.id) 1464 // TODO(roberts): delete from s.Cells 1465 } 1466 1467 // testAllEdges calls the trackers testEdge on all edges from shapes that have interiors. 1468 func (s *ShapeIndex) testAllEdges(edges []*clippedEdge, t *tracker) { 1469 for _, edge := range edges { 1470 if edge.faceEdge.hasInterior { 1471 t.testEdge(edge.faceEdge.shapeID, edge.faceEdge.edge) 1472 } 1473 } 1474 } 1475 1476 // countShapes reports the number of distinct shapes that are either associated with the 1477 // given edges, or that are currently stored in the InteriorTracker. 1478 func (s *ShapeIndex) countShapes(edges []*clippedEdge, shapeIDs []int32) int { 1479 count := 0 1480 lastShapeID := int32(-1) 1481 1482 // next clipped shape id in the shapeIDs list. 1483 clippedNext := int32(0) 1484 // index of the current element in the shapeIDs list. 1485 shapeIDidx := 0 1486 for _, edge := range edges { 1487 if edge.faceEdge.shapeID == lastShapeID { 1488 continue 1489 } 1490 1491 count++ 1492 lastShapeID = edge.faceEdge.shapeID 1493 1494 // Skip over any containing shapes up to and including this one, 1495 // updating count as appropriate. 1496 for ; shapeIDidx < len(shapeIDs); shapeIDidx++ { 1497 clippedNext = shapeIDs[shapeIDidx] 1498 if clippedNext > lastShapeID { 1499 break 1500 } 1501 if clippedNext < lastShapeID { 1502 count++ 1503 } 1504 } 1505 } 1506 1507 // Count any remaining containing shapes. 1508 count += len(shapeIDs) - shapeIDidx 1509 return count 1510 } 1511 1512 // maxLevelForEdge reports the maximum level for a given edge. 1513 func maxLevelForEdge(edge Edge) int { 1514 // Compute the maximum cell size for which this edge is considered long. 1515 // The calculation does not need to be perfectly accurate, so we use Norm 1516 // rather than Angle for speed. 1517 cellSize := edge.V0.Sub(edge.V1.Vector).Norm() * cellSizeToLongEdgeRatio 1518 // Now return the first level encountered during subdivision where the 1519 // average cell size is at most cellSize. 1520 return AvgEdgeMetric.MinLevel(cellSize) 1521 } 1522 1523 // removeShapeInternal does the actual work for removing a given shape from the index. 1524 func (s *ShapeIndex) removeShapeInternal(removed *removedShape, allEdges [][]faceEdge, t *tracker) { 1525 // TODO(roberts): finish the implementation of this. 1526 }