diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinder.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinder.java index 63fb27638..5869bd9cf 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinder.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinder.java @@ -798,7 +798,7 @@ public CnossosPath computeHEdgeDiffraction(CutProfile cutProfile , boolean bodyB double e = 0; Coordinate src = cutProfile.getSource().getCoordinate(); - // If we have at least one diffraction point + // Create segments from each diffraction point to the receiver for (int i = 1; i < pts.size(); i++) { int k = 0; int i0 = pts2D.indexOf(pts.get(i - 1)); @@ -1154,22 +1154,15 @@ public static org.apache.commons.math3.geometry.euclidean.threed.Vector3D coordi */ private void pushReflectionCutPointSequence(CutProfile mainProfile, CutPoint reflectionCutPoint, MirrorReceiver receiverImage) { // The reflection point is added 3 times, first at the base of the wall, second at the reflection coordinates, third when changing direction - // Coordinates must not be exactly the same as points may be ordered from the distance of the first point reflectionCutPoint.setType(REFLECTION); // Compute the coordinate just before the reflection int indexReflectionPoint = mainProfile.getCutPoints().indexOf(reflectionCutPoint); if(indexReflectionPoint > 0) { - Vector3D displacementBeforeReflection = Vector3D.create(receiverImage.getReceiverPos()); - Vector3D reflectionVector = Vector3D.create(receiverImage.getReflectionPosition()); - displacementBeforeReflection = displacementBeforeReflection.subtract(reflectionVector); - displacementBeforeReflection = displacementBeforeReflection.normalize(); - displacementBeforeReflection = displacementBeforeReflection.divide(1/NAVIGATION_POINT_DISTANCE_FROM_WALLS); - CutPoint reflectionBeforeCutPoint = new CutPoint(reflectionCutPoint); - reflectionBeforeCutPoint.setCoordinate(new Coordinate(reflectionVector.getX()+displacementBeforeReflection.getX(), - reflectionVector.getY()+displacementBeforeReflection.getY(), - reflectionVector.getZ()+displacementBeforeReflection.getZ())); - mainProfile.getCutPoints().add(indexReflectionPoint, reflectionBeforeCutPoint); - + CutPoint reflectionPointGround = new CutPoint(reflectionCutPoint); + reflectionPointGround.setCoordinate(new Coordinate(reflectionPointGround.getCoordinate().x, + reflectionPointGround.getCoordinate().y, reflectionPointGround.getzGround())); + mainProfile.getCutPoints().add(indexReflectionPoint, reflectionPointGround); + mainProfile.getCutPoints().add(indexReflectionPoint+2, new CutPoint(reflectionPointGround)); } } @@ -1293,13 +1286,13 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo pathParameters.setFavorable(favorable); pathParameters.setPointList(points); pathParameters.setSegmentList(segments); - pathParameters.angle=Angle.angle(rcvCoord, srcCoord); + pathParameters.angle = Angle.angle(rcvCoord, srcCoord); pathParameters.refPoints = reflIdx; CutProfile mainProfile = new CutProfile(); // Compute direct path between source and first reflection point, add profile to the data computeReflexionOverBuildings(srcCoord, rayPath.get(0).getReflectionPosition(), points, segments, data, orientation, pathParameters.difHPoints, pathParameters.difVPoints, mainProfile); - if(points.isEmpty()) { + if (points.isEmpty()) { // (maybe there is a blocking building, and we disabled diffraction) continue; } @@ -1309,7 +1302,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo PointPath reflPoint = points.get(points.size() - 1); reflIdx.add(points.size() - 1); updateReflectionPathAttributes(reflPoint, rayPath.get(0), - mainProfile.getCutPoints().get(mainProfile.getCutPoints().size()-1)); + mainProfile.getCutPoints().get(mainProfile.getCutPoints().size() - 1)); // Add intermediate reflections for (int idPt = 0; idPt < rayPath.size() - 1; idPt++) { MirrorReceiver firstPoint = rayPath.get(idPt); @@ -1319,7 +1312,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo computeReflexionOverBuildings(firstPoint.getReflectionPosition(), secondPoint.getReflectionPosition(), points, segments, data, orientation, pathParameters.difHPoints, pathParameters.difVPoints, mainProfile); - if(points.size() == previousPointSize) { // no visibility between the two reflection coordinates + if (points.size() == previousPointSize) { // no visibility between the two reflection coordinates // (maybe there is a blocking building, and we disabled diffraction) continue; } @@ -1328,18 +1321,18 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo reflIdx.add(points.size() - 1); // computeReflexionOverBuildings is making X relative to the "receiver" coordinate // so we have to add the X value of the last path - for(PointPath p : points.subList(previousPointSize, points.size())) { + for (PointPath p : points.subList(previousPointSize, points.size())) { p.coordinate.x += points.get(previousPointSize - 1).coordinate.x; } PointPath lastReflexionPoint = points.get(points.size() - 1); - updateReflectionPathAttributes(lastReflexionPoint, secondPoint, mainProfile.getCutPoints().get(mainProfile.getCutPoints().size() - 1)); + updateReflectionPathAttributes(lastReflexionPoint, secondPoint, mainProfile.getCutPoints().get(mainProfile.getCutPoints().size() - 1)); } // Compute direct path between receiver and last reflection point, add profile to the data int previousPointSize = points.size(); int previousCutPointsSize = mainProfile.getCutPoints().size(); computeReflexionOverBuildings(rayPath.get(rayPath.size() - 1).getReflectionPosition(), rcvCoord, points, segments, data, orientation, pathParameters.difHPoints, pathParameters.difVPoints, mainProfile); - if(points.size() == previousPointSize) { // no visibility between the last reflection coordinate and the receiver + if (points.size() == previousPointSize) { // no visibility between the last reflection coordinate and the receiver // (maybe there is a blocking building, and we disabled diffraction) continue; } @@ -1349,7 +1342,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo points.remove(previousPointSize); // remove duplicate point (last reflexion coordinate) // computeReflexionOverBuildings is making X relative to the "receiver" coordinate // so we have to add the X value of the last path - for(PointPath p : points.subList(previousPointSize, points.size())) { + for (PointPath p : points.subList(previousPointSize, points.size())) { p.coordinate.x += points.get(previousPointSize - 1).coordinate.x; } for (int i = 1; i < points.size(); i++) { @@ -1361,7 +1354,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo final Coordinate p1 = currentPoint.coordinate; final Coordinate p2 = points.get(i + 1).coordinate; // compute Y value (altitude) by interpolating the Y values of the two neighboring points - currentPoint.coordinate = new CoordinateXY(p1.x, (p1.x-p0.x)/(p2.x-p0.x)*(p2.y-p0.y)+p0.y); + currentPoint.coordinate = new CoordinateXY(p1.x, (p1.x - p0.x) / (p2.x - p0.x) * (p2.y - p0.y) + p0.y); //check if new reflection point altitude is higher than the wall if (currentPoint.coordinate.y > currentPoint.obstacleZ - epsilon) { // can't reflect higher than the wall @@ -1378,7 +1371,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo } } } - // Extract + double gPath = mainProfile.getGPath(); pathParameters.setCutProfile(mainProfile); List groundPts = mainProfile.computePts2DGround(); @@ -1386,6 +1379,35 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo SegmentPath srSegment = computeSegment(groundPts.get(0), srcCoord.z, groundPts.get(groundPts.size() - 1), rcvCoord.z, meanPlan, gPath, data.gS); pathParameters.setSRSegment(srSegment); + if (!pathParameters.difHPoints.isEmpty()) { + // Use source to first diffraction as segment 1 (SO¹) + // then last diffraction to receiver (OⁿR) + List reflectionSegments = new ArrayList<>(); + CutProfile soProfile = new CutProfile(); + soProfile.setCutPoints(mainProfile.getCutPoints().subList(0, pathParameters.difHPoints.get(0)+1)); + soProfile.setSource(soProfile.getCutPoints().get(0)); + soProfile.setReceiver(soProfile.getCutPoints().get(soProfile.getCutPoints().size() - 1)); + groundPts = soProfile.computePts2DGround(); + meanPlan = JTSUtility.getMeanPlaneCoefficients(groundPts.toArray(new Coordinate[0])); + SegmentPath soSegment = computeSegment(groundPts.get(0), srcCoord.z, + groundPts.get(groundPts.size() - 1), soProfile.getReceiver().getCoordinate().z, + meanPlan, soProfile.getGPath(), data.gS); + reflectionSegments.add(soSegment); + // compute OR profile + CutProfile orProfile = new CutProfile(); + int indexLastDiffraction = pathParameters.difHPoints.get(pathParameters.difHPoints.size() - 1); + orProfile.setCutPoints(mainProfile.getCutPoints().subList(indexLastDiffraction, + mainProfile.getCutPoints().size())); + orProfile.setSource(orProfile.getCutPoints().get(0)); + orProfile.setReceiver(orProfile.getCutPoints().get(orProfile.getCutPoints().size() - 1)); + groundPts = orProfile.computePts2DGround(); + meanPlan = JTSUtility.getMeanPlaneCoefficients(groundPts.toArray(new Coordinate[0])); + SegmentPath orSegment = computeSegment(groundPts.get(0), orProfile.getSource().getCoordinate().z, + groundPts.get(groundPts.size() - 1), orProfile.getReceiver().getCoordinate().z, + meanPlan, orProfile.getGPath(), orProfile.getSource().getGroundCoef()); + reflectionSegments.add(orSegment); + pathParameters.setSegmentList(reflectionSegments); + } reflexionPathParameters.add(pathParameters); } } diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutProfile.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutProfile.java index f944a6ddf..67a50a586 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutProfile.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutProfile.java @@ -141,8 +141,8 @@ public CutPoint addGroundCutPt(Coordinate coordinate, int id, double groundCoeff public List getCutPoints() { return pts; } - public void setCutPoints ( ArrayList ge){ - pts = ge; + public void setCutPoints ( List ge){ + pts = new ArrayList<>(ge); } /** diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/ProfileBuilder.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/ProfileBuilder.java index 8359f76c6..5ec42265f 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/ProfileBuilder.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/ProfileBuilder.java @@ -1173,7 +1173,11 @@ private void addGroundBuildingCutPts(LineSegment fullLine, CutProfile profile, b // add another ground surface, could be duplicate points if // the two ground surfaces is touching GroundAbsorption nextGroundAbsorption = groundAbsorptions.get(groundSurfaceIndex); - profile.addGroundCutPt(intersection, facetLine.getOriginId(), nextGroundAbsorption.getCoefficient()); + // if the interior of the two ground surfaces overlaps we add the ground point + // (as we will not encounter the side of this other ground surface) + if(!nextGroundAbsorption.geom.touches(groundAbsorption.geom)) { + profile.addGroundCutPt(intersection, groundSurfaceIndex, nextGroundAbsorption.getCoefficient()); + } } } } diff --git a/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/PathFinderTest.java b/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/PathFinderTest.java index 688912ae0..5de796705 100644 --- a/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/PathFinderTest.java +++ b/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/PathFinderTest.java @@ -1191,9 +1191,6 @@ public void TC16() { //Run computation computeRays.run(propDataOut); - CutProfile cutProfile = computeRays.getData().profileBuilder.getProfile(rayData.sourceGeometries.get(0).getCoordinate(), rayData.receivers.get(0), computeRays.getData().gS, false); - List result = cutProfile.computePts2DGround(); - //Expected values @@ -1204,6 +1201,16 @@ public void TC16() { expectedZ_profile.add(new Coordinate(178.84, 10)); expectedZ_profile.add(new Coordinate(194.16, 10)); + /* Table 169 */ + List expectedZProfileReflection = new ArrayList<>(); + expectedZProfileReflection.add(new Coordinate(0.0, 0.0)); + expectedZProfileReflection.add(new Coordinate(117.12, 0.0)); + expectedZProfileReflection.add(new Coordinate(129.75, 1.82)); + expectedZProfileReflection.add(new Coordinate(129.75, 1.82)); + expectedZProfileReflection.add(new Coordinate(129.75, 1.82)); + expectedZProfileReflection.add(new Coordinate(183.01, 10)); + expectedZProfileReflection.add(new Coordinate(198.04, 10)); + /* Table 166 */ Coordinate expectedSPrime =new Coordinate(0.42,-6.64); Coordinate expectedRPrime =new Coordinate(194.84,1.70); @@ -1224,11 +1231,16 @@ public void TC16() { }; //Assertion - assertZProfil(expectedZ_profile,result); + // Check SR direct line + List result = propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround(); + assertZProfil(expectedZ_profile,result); assertEquals(2, propDataOut.getPropagationPaths().size()); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSRSegment()); + + // Check reflection path + result = propDataOut.getPropagationPaths().get(1).getCutProfile().computePts2DGround(); + assertZProfil(expectedZProfileReflection, result); assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); try {