@@ -72,6 +72,7 @@ type Loop struct {
72
72
func LoopFromPoints (pts []Point ) * Loop {
73
73
l := & Loop {
74
74
vertices : pts ,
75
+ index : NewShapeIndex (),
75
76
}
76
77
77
78
l .initOriginAndBound ()
@@ -96,6 +97,7 @@ func LoopFromCell(c Cell) *Loop {
96
97
c .Vertex (2 ),
97
98
c .Vertex (3 ),
98
99
},
100
+ index : NewShapeIndex (),
99
101
}
100
102
101
103
l .initOriginAndBound ()
@@ -587,16 +589,24 @@ func (l *Loop) bruteForceContainsPoint(p Point) bool {
587
589
588
590
// ContainsPoint returns true if the loop contains the point.
589
591
func (l * Loop ) ContainsPoint (p Point ) bool {
590
- // Empty and full loops don't need a special case, but invalid loops with
591
- // zero vertices do, so we might as well handle them all at once.
592
- if len (l .vertices ) < 3 {
593
- return l .originInside
592
+ if ! l .index .IsFresh () && ! l .bound .ContainsPoint (p ) {
593
+ return false
594
594
}
595
595
596
- // For small loops, and during initial construction, it is faster to just
597
- // check all the crossing.
596
+ // For small loops it is faster to just check all the crossings. We also
597
+ // use this method during loop initialization because InitOriginAndBound()
598
+ // calls Contains() before InitIndex(). Otherwise, we keep track of the
599
+ // number of calls to Contains() and only build the index when enough calls
600
+ // have been made so that we think it is worth the effort. Note that the
601
+ // code below is structured so that if many calls are made in parallel only
602
+ // one thread builds the index, while the rest continue using brute force
603
+ // until the index is actually available.
604
+
598
605
const maxBruteForceVertices = 32
599
- if len (l .vertices ) < maxBruteForceVertices || l .index == nil {
606
+ // TODO(roberts): add unindexed contains calls tracking
607
+
608
+ if len (l .index .shapes ) == 0 || // Index has not been initialized yet.
609
+ len (l .vertices ) <= maxBruteForceVertices {
600
610
return l .bruteForceContainsPoint (p )
601
611
}
602
612
@@ -802,20 +812,23 @@ func (l *Loop) TurningAngle() float64 {
802
812
compensation = (oldSum - sum ) + angle
803
813
n --
804
814
}
805
- return float64 (dir ) * float64 (sum + compensation )
815
+
816
+ const maxCurvature = 2 * math .Pi - 4 * dblEpsilon
817
+
818
+ return math .Max (- maxCurvature , math .Min (maxCurvature , float64 (dir )* float64 (sum + compensation )))
806
819
}
807
820
808
821
// turningAngleMaxError return the maximum error in TurningAngle. The value is not
809
822
// constant; it depends on the loop.
810
823
func (l * Loop ) turningAngleMaxError () float64 {
811
824
// The maximum error can be bounded as follows:
812
- // 2.24 * dblEpsilon for RobustCrossProd(b, a)
813
- // 2.24 * dblEpsilon for RobustCrossProd(c, b)
825
+ // 3.00 * dblEpsilon for RobustCrossProd(b, a)
826
+ // 3.00 * dblEpsilon for RobustCrossProd(c, b)
814
827
// 3.25 * dblEpsilon for Angle()
815
828
// 2.00 * dblEpsilon for each addition in the Kahan summation
816
829
// ------------------
817
- // 9.73 * dblEpsilon
818
- maxErrorPerVertex := 9.73 * dblEpsilon
830
+ // 11.25 * dblEpsilon
831
+ maxErrorPerVertex := 11.25 * dblEpsilon
819
832
return maxErrorPerVertex * float64 (len (l .vertices ))
820
833
}
821
834
@@ -1275,12 +1288,12 @@ func (l *Loop) decode(d *decoder) {
1275
1288
l .vertices [i ].Y = d .readFloat64 ()
1276
1289
l .vertices [i ].Z = d .readFloat64 ()
1277
1290
}
1291
+ l .index = NewShapeIndex ()
1278
1292
l .originInside = d .readBool ()
1279
1293
l .depth = int (d .readUint32 ())
1280
1294
l .bound .decode (d )
1281
1295
l .subregionBound = ExpandForSubregions (l .bound )
1282
1296
1283
- l .index = NewShapeIndex ()
1284
1297
l .index .Add (l )
1285
1298
}
1286
1299
@@ -1359,6 +1372,7 @@ func (l *Loop) decodeCompressed(d *decoder, snapLevel int) {
1359
1372
return
1360
1373
}
1361
1374
1375
+ l .index = NewShapeIndex ()
1362
1376
l .originInside = (properties & originInside ) != 0
1363
1377
1364
1378
l .depth = int (d .readUvarint ())
@@ -1373,7 +1387,6 @@ func (l *Loop) decodeCompressed(d *decoder, snapLevel int) {
1373
1387
l .initBound ()
1374
1388
}
1375
1389
1376
- l .index = NewShapeIndex ()
1377
1390
l .index .Add (l )
1378
1391
}
1379
1392
0 commit comments