Mercurial > gemma
comparison pkg/octree/polygon.go @ 4764:5c80a33edd44
Fixed handling of none-closed polygons in containment test.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sat, 19 Oct 2019 19:40:51 +0200 |
parents | 1137c5a18242 |
children | db6c2955ee31 |
comparison
equal
deleted
inserted
replaced
4763:d786c37b02c0 | 4764:5c80a33edd44 |
---|---|
339 return IntersectionInside | 339 return IntersectionInside |
340 } | 340 } |
341 return IntersectionOutSide | 341 return IntersectionOutSide |
342 } | 342 } |
343 | 343 |
344 func (rng ring) closed() bool { | |
345 return (len(rng) / 2) >= 3 | |
346 } | |
347 | |
348 func (rng ring) length() int { | 344 func (rng ring) length() int { |
349 return len(rng) / 2 | 345 return len(rng) / 2 |
350 } | 346 } |
351 | 347 |
352 func (rng ring) point(i int) (float64, float64) { | 348 func (rng ring) point(i int) (float64, float64) { |
353 i *= 2 | 349 i *= 2 |
354 return rng[i], rng[i+1] | 350 return rng[i], rng[i+1] |
355 } | 351 } |
356 | 352 |
357 type segments interface { | 353 type segments interface { |
358 closed() bool | |
359 length() int | 354 length() int |
360 point(int) (float64, float64) | 355 point(int) (float64, float64) |
361 } | 356 } |
362 | 357 |
363 func contains(s segments, pX, pY float64) bool { | 358 func contains(s segments, pX, pY float64) bool { |
364 if !s.closed() { | |
365 return false | |
366 } | |
367 | 359 |
368 n := s.length() | 360 n := s.length() |
361 if n < 3 { | |
362 return false | |
363 } | |
369 | 364 |
370 sX, sY := s.point(0) | 365 sX, sY := s.point(0) |
371 eX, eY := s.point(n - 1) | 366 eX, eY := s.point(n - 1) |
372 | 367 |
373 contains := intersectsWithRaycast(pX, pY, sX, sY, eX, eY) | 368 const eps = 0.0000001 |
369 | |
370 if math.Abs(sX-eX) > eps && math.Abs(sY-eY) > eps { | |
371 // It's not closed! | |
372 return false | |
373 } | |
374 | |
375 var inside bool | |
374 | 376 |
375 for i := 1; i < n; i++ { | 377 for i := 1; i < n; i++ { |
376 sX, sY := s.point(i - 1) | |
377 eX, eY := s.point(i) | 378 eX, eY := s.point(i) |
378 if intersectsWithRaycast(pX, pY, sX, sY, eX, eY) { | 379 if intersectsWithRaycast(pX, pY, sX, sY, eX, eY) { |
379 contains = !contains | 380 inside = !inside |
380 } | 381 } |
381 } | 382 sX, sY = eX, eY |
382 | 383 } |
383 return contains | 384 |
385 return inside | |
384 } | 386 } |
385 | 387 |
386 // Using the raycast algorithm, this returns whether or not the passed in point | 388 // Using the raycast algorithm, this returns whether or not the passed in point |
387 // Intersects with the edge drawn by the passed in start and end points. | 389 // Intersects with the edge drawn by the passed in start and end points. |
388 // Original implementation: http://rosettacode.org/wiki/Ray-casting_algorithm#Go | 390 // Original implementation: http://rosettacode.org/wiki/Ray-casting_algorithm#Go |