Skip to content

Commit 927aad0

Browse files
author
Léna Voinchet
committed
Update hexagonal projection
1 parent 179fadc commit 927aad0

File tree

1 file changed

+103
-21
lines changed

1 file changed

+103
-21
lines changed

js/scene/SceneManager.js

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -713,31 +713,39 @@ class SceneManager{
713713
);
714714

715715
// 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
723723

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;
731739
});
732740

733-
coveredPointsAbove = tempProjectedToFloor; // Ces points sont au niveau du sol de la tranche de détection
741+
coveredPointsAbove = clippedProjectedPoints;
742+
} else {
743+
coveredPointsAbove = [];
734744
}
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());
741749

742750
} else {
743751

@@ -850,6 +858,80 @@ class SceneManager{
850858
}
851859

852860
}
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+
853935

854936
/**
855937
* Get every intersection points of multiple rays

0 commit comments

Comments
 (0)