comparison pkg/octree/vertex.go @ 788:9f3a4a60dc04

Cleaned up interpolation mess in vertical triangle intersection.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 27 Sep 2018 08:15:28 +0200
parents 3d927e06b92c
children d43e61044ad8
comparison
equal deleted inserted replaced
787:3d927e06b92c 788:9f3a4a60dc04
426 426
427 func dist(x1, y1, x2, y2 float64) float64 { 427 func dist(x1, y1, x2, y2 float64) float64 {
428 return math.Sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) 428 return math.Sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))
429 } 429 }
430 430
431 func interpolate(v1, v2 Vertex) func(x, y float64) float64 { 431 func relative(v1, v2 Vertex) func(x, y float64) float64 {
432 432
433 length := dist(v1.X, v1.Y, v2.X, v2.Y) 433 length := dist(v1.X, v1.Y, v2.X, v2.Y)
434 434
435 // f(0) = v1.Z 435 // f(0) = v1.Z
436 // f(length) = v2.Z 436 // f(length) = v2.Z
441 m := (v2.Z - v1.Z) / length 441 m := (v2.Z - v1.Z) / length
442 442
443 return func(x, y float64) float64 { 443 return func(x, y float64) float64 {
444 l := dist(v1.X, v1.Y, x, y) 444 l := dist(v1.X, v1.Y, x, y)
445 return m*l + b 445 return m*l + b
446 }
447 }
448
449 func interpolate(a, b float64) func(float64) float64 {
450 return func(x float64) float64 {
451 return (b-a)*x + a
446 } 452 }
447 } 453 }
448 454
449 func linear(v1, v2 Vertex) func(t float64) Vertex { 455 func linear(v1, v2 Vertex) func(t float64) Vertex {
450 return func(t float64) Vertex { 456 return func(t float64) Vertex {
454 (v2.Z-v1.Z)*t + v1.Z, 460 (v2.Z-v1.Z)*t + v1.Z,
455 } 461 }
456 } 462 }
457 } 463 }
458 464
459 func inRange(a, b, c float64) bool { 465 func inRange(a float64) bool { return 0 <= a && a <= 1 }
460 if a > b {
461 a, b = b, a
462 }
463 return c >= a && c <= b
464 }
465 466
466 func (vl *VerticalLine) Intersection(t *Triangle) LineStringZ { 467 func (vl *VerticalLine) Intersection(t *Triangle) LineStringZ {
467 468
468 var out LineStringZ 469 var out LineStringZ
469
470 length := dist(vl.x1, vl.y1, vl.x2, vl.y2)
471 470
472 edges: 471 edges:
473 for i := 0; i < 3 && len(out) < 2; i++ { 472 for i := 0; i < 3 && len(out) < 2; i++ {
474 j := (i + 1) % 3 473 j := (i + 1) % 3
475 edge := NewPlane2D(t[i].X, t[i].Y, t[j].X, t[j].Y) 474 edge := NewPlane2D(t[i].X, t[i].Y, t[j].X, t[j].Y)
480 o1 := onPlane(s1) 479 o1 := onPlane(s1)
481 o2 := onPlane(s2) 480 o2 := onPlane(s2)
482 481
483 switch { 482 switch {
484 case o1 && o2: 483 case o1 && o2:
485 // XXX: Broken! 484 pos := relative(t[i], t[j])
486 pos := interpolate(t[i], t[j])
487 t1 := pos(vl.x1, vl.y1) 485 t1 := pos(vl.x1, vl.y1)
488 t2 := pos(vl.x2, vl.y2) 486 t2 := pos(vl.x2, vl.y2)
489 487
490 r1 := inRange(0, length, t1) 488 r1 := inRange(t1)
491 r2 := inRange(0, length, t2) 489 r2 := inRange(t2)
492 490
493 switch { 491 switch {
494 case r1 && r2: 492 case r1 && r2:
495 l := linear(t[i], t[j]) 493 lin := linear(t[i], t[j])
496 // XXX: Broken! 494 out = append(out, lin(t1), lin(t2))
497 out = append(out, l(t1/length), l(t2/length))
498 return out 495 return out
499 496
500 case !r1 && !r2: // the hole edge 497 case !r1 && !r2: // the hole edge
501 out = append(out, t[i], t[j]) 498 out = append(out, t[i], t[j])
502 return out 499 return out
505 case !r2: 502 case !r2:
506 // TODO 503 // TODO
507 } 504 }
508 505
509 case o1: 506 case o1:
510 t1 := interpolate(t[i], t[j])(vl.x1, vl.y1) 507 t1 := relative(t[i], t[j])(vl.x1, vl.y1)
511 if !inRange(0, length, t1) { 508 if !inRange(t1) {
512 continue edges 509 continue edges
513 } 510 }
514 out = append(out, linear(t[i], t[j])(t1)) 511 out = append(out, linear(t[i], t[j])(t1))
515 512
516 case o2: 513 case o2:
517 t2 := interpolate(t[i], t[j])(vl.x2, vl.y2) 514 t2 := relative(t[i], t[j])(vl.x2, vl.y2)
518 if !inRange(0, length, t2) { 515 if !inRange(t2) {
519 continue edges 516 continue edges
520 } 517 }
521 out = append(out, linear(t[i], t[j])(t2)) 518 out = append(out, linear(t[i], t[j])(t2))
522 519
523 default: 520 default:
524 x, y, intersects := vl.line.Intersection(edge) 521 x, y, intersects := vl.line.Intersection(edge)
525 if !intersects { 522 if !intersects {
526 continue edges 523 continue edges
527 } 524 }
528 t1 := interpolate(t[i], t[j])(x, y) 525 t1 := relative(t[i], t[j])(x, y)
529 if !inRange(0, length, t1) { 526 if !inRange(t1) {
530 continue edges 527 continue edges
531 } 528 }
532 529
533 // XXX: Ugly! 530 z := interpolate(t[j].Z, t[i].Z)(t1)
534 z := (t[j].Z-t[i].Z)*(t1/length) + t[1].Z
535 n := Vertex{x, y, z} 531 n := Vertex{x, y, z}
536 532
537 if math.Signbit(s1) != math.Signbit(s2) { 533 if math.Signbit(s1) != math.Signbit(s2) {
538 // different sides -> vertex on edge. 534 // different sides -> vertex on edge.
539 out = append(out) 535 out = append(out, n)
540 } else { // same side -> inside. Find peer 536 } else { // same side -> inside. Find peer
541 if len(out) > 0 { // we already have our peer 537 if len(out) > 0 { // we already have our peer
542 out = append(out, n) 538 out = append(out, n)
543 return out 539 return out
544 } 540 }
551 other := NewPlane2D(t[k].X, t[k].Y, t[l].X, t[l].Y) 547 other := NewPlane2D(t[k].X, t[k].Y, t[l].X, t[l].Y)
552 xo, yo, intersects := vl.line.Intersection(edge) 548 xo, yo, intersects := vl.line.Intersection(edge)
553 if !intersects { 549 if !intersects {
554 continue 550 continue
555 } 551 }
556 // XXX: Broken!!! 552 t2 := relative(t[k], t[j])(xo, yo)
557 zo := interpolate(t[k], t[j])(xo, yo) 553 if !inRange(t2) {
558 if !inRange(t[k].Z, t[k].Z, zo) {
559 continue 554 continue
560 } 555 }
556 zo := interpolate(t[k].Z, t[j].Z)(t2)
557
561 m := Vertex{xo, yo, zo} 558 m := Vertex{xo, yo, zo}
562 559
563 var xn, yn, xf, yf float64 560 var xn, yn, xf, yf float64
564 561
565 // Which is nearer to current edge? 562 // Which is nearer to current edge?
572 } 569 }
573 570
574 if onPlane(other.Eval(xn, yn)) { 571 if onPlane(other.Eval(xn, yn)) {
575 // triangle intersect in only point 572 // triangle intersect in only point
576 // treat as no intersection 573 // treat as no intersection
577 return out 574 break edges
578 } 575 }
579 576
580 // XXX: Broken!!! 577 pos := relative(n, m)
581 zint := interpolate(n, m) 578
582 579 tzn := pos(xn, yn)
583 zn := zint(xn, yn) 580 tzf := pos(xf, yf)
584 zf := zint(xf, yf) 581
585 582 if !inRange(tzn) {
586 if !inRange(n.Z, m.Z, zn) {
587 // if near is out of range far is, too. 583 // if near is out of range far is, too.
588 return out 584 return out
589 } 585 }
590 586
591 if inRange(n.Z, m.Z, zf) { 587 lin := interpolate(n.Z, m.Z)
588
589 if inRange(tzf) {
592 m.X = xf 590 m.X = xf
593 m.Y = yf 591 m.Y = yf
594 m.Z = zf 592 m.Z = lin(tzf)
595 } // else m is clipping 593 } // else m is clipping
596 594
597 n.X = xn 595 n.X = xn
598 n.Y = yn 596 n.Y = yn
599 n.Z = zn 597 n.Z = lin(tzn)
600 598
601 out = append(out, n, m) 599 out = append(out, n, m)
602 return out 600 return out
603 } 601 }
604 } 602 }