@@ -713,31 +713,39 @@ class SceneManager{
713
713
) ;
714
714
715
715
// Purple area
716
- coveredPointsAbove = [ ] ;
717
- if ( intersectionPointsAbove . length > 2 ) {
718
- const tempProjectedToFloor = [ ] ;
719
- intersectionPointsAbove . forEach ( originalPointOnAbovePlane => {
720
- const pointOnAbovePlane = originalPointOnAbovePlane . clone ( ) ; // Point on the Above Plane
721
- const pointProjectedToFloor = originalPointOnAbovePlane . clone ( ) ;
722
- pointProjectedToFloor . y - = this . heightDetected ; // Point projected on the Floor Plane
716
+ const subjectPolygonProjected = [ ] ;
717
+
718
+ intersectionPointsAbove . forEach ( originalPoint => {
719
+ // We only keep the points which are in the frustum at their real height
720
+ if ( pointInFrustum ( originalPoint , frustumPlanesWorld ) ) {
721
+ const projectedPoint = originalPoint . clone ( ) ;
722
+ projectedPoint . y = this . sceneElevation ; // Projected on the floor
723
723
724
- if ( pointInFrustum ( pointOnAbovePlane , frustumPlanesWorld ) && // Real point is in Frustum
725
- pointInFrustum ( pointProjectedToFloor , frustumPlanesWorld ) && // Projection on the floor too
726
- pointProjectedToFloor . x >= this . wallX . position . x - 0.01 &&
727
- pointProjectedToFloor . y >= this . sceneElevation - 0.01 &&
728
- pointProjectedToFloor . z >= this . wallY . position . z - 0.01 ) {
729
- tempProjectedToFloor . push ( pointProjectedToFloor ) ;
730
- }
724
+ subjectPolygonProjected . push ( projectedPoint ) ;
725
+ }
726
+ } ) ;
727
+
728
+ sortByAngle ( coveredPointsFloor , floorNormal ) ;
729
+ sortByAngle ( subjectPolygonProjected , floorNormal ) ;
730
+
731
+ coveredPointsAbove = [ ] ;
732
+ if ( subjectPolygonProjected . length > 2 && coveredPointsFloor . length > 2 ) {
733
+
734
+ // We cut the subject polygon (purple) by the cutting polygon (grey)
735
+ const clippedProjectedPoints = sutherlandHodgmanClip ( subjectPolygonProjected , coveredPointsFloor ) ;
736
+
737
+ clippedProjectedPoints . forEach ( p => {
738
+ p . y = this . sceneElevation ;
731
739
} ) ;
732
740
733
- coveredPointsAbove = tempProjectedToFloor ; // Ces points sont au niveau du sol de la tranche de détection
741
+ coveredPointsAbove = clippedProjectedPoints ;
742
+ } else {
743
+ coveredPointsAbove = [ ] ;
734
744
}
735
-
736
-
737
- sortByAngle ( coveredPointsFloor , floorNormal ) ;
738
- sortByAngle ( coveredPointsAbove , floorNormal ) ; // Triés au niveau du sol de la tranche
739
- sortByAngle ( coveredPointsWallX , wallXNormal . clone ( ) . negate ( ) ) ; // Normale intérieure du mur X
740
- sortByAngle ( coveredPointsWallY , wallYNormal . clone ( ) . negate ( ) ) ; // Normale intérieure du mur Y
745
+
746
+ sortByAngle ( coveredPointsAbove , floorNormal ) ;
747
+ sortByAngle ( coveredPointsWallX , wallXNormal . clone ( ) . negate ( ) ) ;
748
+ sortByAngle ( coveredPointsWallY , wallYNormal . clone ( ) . negate ( ) ) ;
741
749
742
750
} else {
743
751
@@ -850,6 +858,80 @@ class SceneManager{
850
858
}
851
859
852
860
}
861
+
862
+ function getLineIntersection ( p1 , p2 , p3 , p4 ) {
863
+ const d = ( p2 . x - p1 . x ) * ( p4 . z - p3 . z ) - ( p2 . z - p1 . z ) * ( p4 . x - p3 . x ) ;
864
+
865
+ // If lines are almost parallel, we don't compute to avoid mistakes
866
+ if ( Math . abs ( d ) < 1e-10 ) {
867
+ return null ;
868
+ }
869
+
870
+ const t = ( ( p3 . x - p1 . x ) * ( p4 . z - p3 . z ) - ( p3 . z - p1 . z ) * ( p4 . x - p3 . x ) ) / d ;
871
+
872
+ // We check intersection is on one segment and an infinite line
873
+ if ( t >= 0 && t <= 1 ) {
874
+ return new Vector3 ( p1 . x + t * ( p2 . x - p1 . x ) , p1 . y , p1 . z + t * ( p2 . z - p1 . z ) ) ;
875
+ }
876
+
877
+ return null ;
878
+ }
879
+
880
+
881
+ /**
882
+ * Cut a polygon with another
883
+ */
884
+ function sutherlandHodgmanClip ( subjectPolygon , clipPolygon ) {
885
+ let outputList = subjectPolygon ;
886
+ const epsilon = 1e-6 ;
887
+
888
+ for ( let i = 0 ; i < clipPolygon . length ; i ++ ) {
889
+ const clipEdgeStart = clipPolygon [ i ] ;
890
+ const clipEdgeEnd = clipPolygon [ ( i + 1 ) % clipPolygon . length ] ;
891
+
892
+ const inputList = outputList ;
893
+ outputList = [ ] ;
894
+
895
+ if ( inputList . length === 0 ) break ;
896
+
897
+ let S = inputList [ inputList . length - 1 ] ;
898
+
899
+ for ( let j = 0 ; j < inputList . length ; j ++ ) {
900
+ const E = inputList [ j ] ;
901
+
902
+ // 2D normal rotated inward (assuming counterclockwise order)
903
+ const normal = new Vector3 ( clipEdgeEnd . z - clipEdgeStart . z , 0 , clipEdgeStart . x - clipEdgeEnd . x ) . negate ( ) ;
904
+ const isS_inside = new Vector3 ( ) . subVectors ( S , clipEdgeStart ) . dot ( normal ) >= - epsilon ;
905
+ const isE_inside = new Vector3 ( ) . subVectors ( E , clipEdgeStart ) . dot ( normal ) >= - epsilon ;
906
+
907
+ if ( isE_inside ) {
908
+ if ( ! isS_inside ) {
909
+ // S is out, E is in -> we add intersection
910
+ const intersection = getLineIntersection ( S , E , clipEdgeStart , clipEdgeEnd ) ;
911
+ if ( intersection ) { // !! CRUCIAL CHECK !!
912
+ if ( outputList . length === 0 || intersection . distanceTo ( outputList [ outputList . length - 1 ] ) > epsilon ) {
913
+ outputList . push ( intersection ) ;
914
+ }
915
+ }
916
+ }
917
+ // E is in -> we add it
918
+ outputList . push ( E ) ;
919
+ } else if ( isS_inside ) {
920
+ // S is in, E is out -> we add intersection
921
+ const intersection = getLineIntersection ( S , E , clipEdgeStart , clipEdgeEnd ) ;
922
+ if ( intersection ) { // !! CRUCIAL CHECK !!
923
+ if ( outputList . length === 0 || intersection . distanceTo ( outputList [ outputList . length - 1 ] ) > epsilon ) {
924
+ outputList . push ( intersection ) ;
925
+ }
926
+ }
927
+ }
928
+ // Both are out -> we don't add anything
929
+ S = E ;
930
+ }
931
+ }
932
+ return outputList ;
933
+ }
934
+
853
935
854
936
/**
855
937
* Get every intersection points of multiple rays
0 commit comments