@@ -585,10 +585,11 @@ contains
585585
586586 !> This procedure determines if a point is inside a surface using
587587 !! the generalized winding number (Jacobson et al., SIGGRAPH 2013 ).
588- !! The winding number is the sum of signed solid angles subtended
589- !! by each triangle, normalized by 4 * pi. Returns ~1.0 inside,
588+ !! In 3D , sums the solid angle subtended by each triangle (Van
589+ !! Oosterom- Strackee formula). In 2D (p==0 ), sums the signed
590+ !! angle subtended by each boundary edge. Returns ~1.0 inside,
590591 !! ~0.0 outside. Unlike ray casting, this is robust to small
591- !! triangles and vertex winding order.
592+ !! triangles/ edges and vertex winding order.
592593 !! @param ntrs Number of triangles in the model.
593594 !! @param pid Patch ID of this model.
594595 !! @param point Point to test.
@@ -606,40 +607,60 @@ contains
606607 real (wp) :: r1(3 ), r2(3 ), r3(3 )
607608 real (wp) :: r1_mag, r2_mag, r3_mag
608609 real (wp) :: numerator, denominator
610+ real (wp) :: d1(2 ), d2(2 )
609611 integer :: q
610612
611613 fraction = 0.0_wp
612614
613- do q = 1 , ntrs
614- r1 = gpu_trs_v(1 , :, q, pid) - point
615- r2 = gpu_trs_v(2 , :, q, pid) - point
616- r3 = gpu_trs_v(3 , :, q, pid) - point
617-
618- r1_mag = sqrt (dot_product (r1, r1))
619- r2_mag = sqrt (dot_product (r2, r2))
620- r3_mag = sqrt (dot_product (r3, r3))
621-
622- ! Van Oosterom- Strackee formula:
623- ! tan (Omega/ 2 ) = numerator / denominator
624- ! numerator = scalar triple product r1 . (r2 x r3)
625- numerator = r1(1 )* (r2(2 )* r3(3 ) - r2(3 )* r3(2 )) &
626- + r1(2 )* (r2(3 )* r3(1 ) - r2(1 )* r3(3 )) &
627- + r1(3 )* (r2(1 )* r3(2 ) - r2(2 )* r3(1 ))
628-
629- denominator = r1_mag* r2_mag* r3_mag &
630- + dot_product (r1, r2)* r3_mag &
631- + dot_product (r2, r3)* r1_mag &
632- + dot_product (r3, r1)* r2_mag
633-
634- ! Solid angle = 2 * atan2 (num, den).
635- ! atan2 (0 ,0 ) = 0 per IEEE 754 , so degenerate triangles
636- ! contribute nothing without special casing.
637- fraction = fraction + atan2 (numerator, denominator)
638- end do
615+ if (p == 0 ) then
616+ ! 2D winding number: sum signed angles subtended by
617+ ! each boundary edge at the query point.
618+ do q = 1 , gpu_boundary_edge_count(pid)
619+ d1(1 ) = gpu_boundary_v(q, 1 , 1 , pid) - point(1 )
620+ d1(2 ) = gpu_boundary_v(q, 1 , 2 , pid) - point(2 )
621+ d2(1 ) = gpu_boundary_v(q, 2 , 1 , pid) - point(1 )
622+ d2(2 ) = gpu_boundary_v(q, 2 , 2 , pid) - point(2 )
623+
624+ ! Signed angle = atan2 (d1 x d2, d1 . d2)
625+ fraction = fraction + atan2 ( &
626+ d1(1 )* d2(2 ) - d1(2 )* d2(1 ), &
627+ d1(1 )* d2(1 ) + d1(2 )* d2(2 ))
628+ end do
629+
630+ ! 2D winding number = total angle / (2 * pi)
631+ fraction = fraction/ (2.0_wp * acos (- 1.0_wp ))
632+ else
633+ ! 3D winding number: sum solid angles via Van
634+ ! Oosterom- Strackee formula.
635+ do q = 1 , ntrs
636+ r1 = gpu_trs_v(1 , :, q, pid) - point
637+ r2 = gpu_trs_v(2 , :, q, pid) - point
638+ r3 = gpu_trs_v(3 , :, q, pid) - point
639+
640+ r1_mag = sqrt (dot_product (r1, r1))
641+ r2_mag = sqrt (dot_product (r2, r2))
642+ r3_mag = sqrt (dot_product (r3, r3))
643+
644+ ! tan (Omega/ 2 ) = numerator / denominator
645+ ! numerator = scalar triple product r1 . (r2 x r3)
646+ numerator = r1(1 )* (r2(2 )* r3(3 ) - r2(3 )* r3(2 )) &
647+ + r1(2 )* (r2(3 )* r3(1 ) - r2(1 )* r3(3 )) &
648+ + r1(3 )* (r2(1 )* r3(2 ) - r2(2 )* r3(1 ))
649+
650+ denominator = r1_mag* r2_mag* r3_mag &
651+ + dot_product (r1, r2)* r3_mag &
652+ + dot_product (r2, r3)* r1_mag &
653+ + dot_product (r3, r1)* r2_mag
654+
655+ ! atan2 (0 ,0 ) = 0 per IEEE 754 , so degenerate
656+ ! triangles contribute nothing.
657+ fraction = fraction + atan2 (numerator, denominator)
658+ end do
639659
640- ! Winding number = total solid angle / (4 * pi)
641- ! Each triangle contributes 2 * atan2, so sum / (2 * pi)
642- fraction = fraction/ (2.0_wp * acos (- 1.0_wp ))
660+ ! Winding number = total solid angle / (4 * pi)
661+ ! Each triangle contributes 2 * atan2, so sum / (2 * pi)
662+ fraction = fraction/ (2.0_wp * acos (- 1.0_wp ))
663+ end if
643664
644665 end function f_model_is_inside_flat
645666
0 commit comments