diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ComputeCnossosRays.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ComputeCnossosRays.java index 0a692aae7..9879dfe36 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ComputeCnossosRays.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ComputeCnossosRays.java @@ -1323,7 +1323,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate sr proPath.refPoints = reflIdx; // Compute direct path between source and first reflection point, add profile to the data computeReflexionOverBuildings(srcCoord, rayPath.get(0).getReceiverPos(), points, segments, data, orientation, proPath.difHPoints, proPath.difVPoints); - if (points.isEmpty()) { + if (points.isEmpty()) { // no valid path between the two points continue; } PointPath reflPoint = points.get(points.size() - 1); @@ -1338,58 +1338,67 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate sr reflPoint.setWallId(rayPath.get(0).getWall().getProcessedWallIndex()); reflPoint.setAlphaWall(rayPath.get(0).getWall().getAlphas()); } - reflPoint.altitude = data.profileBuilder.getZGround(reflPoint.coordinate); + reflPoint.altitude = data.profileBuilder.getZGround(rayPath.get(0).getReceiverPos()); // Add intermediate reflections for (int idPt = 0; idPt < rayPath.size() - 1; idPt++) { - Coordinate firstPt = rayPath.get(idPt).getReceiverPos(); - MirrorReceiverResult refl = rayPath.get(idPt + 1); - reflPoint = new PointPath(refl.getReceiverPos(), 0, new ArrayList<>(), PointPath.POINT_TYPE.REFL); - + MirrorReceiverResult firstPoint = rayPath.get(idPt); + MirrorReceiverResult secondPoint = rayPath.get(idPt + 1); + int previousPointSize = points.size(); + computeReflexionOverBuildings(firstPoint.getReceiverPos(), secondPoint.getReceiverPos(), + points, segments, data, orientation, proPath.difHPoints, proPath.difVPoints); + if(points.size() == previousPointSize) { // no visibility between the two reflection coordinates + // (maybe there is a blocking building, and we disabled diffraction) + continue; + } + points.remove(previousPointSize); // remove duplicate point + 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())) { + p.coordinate.x += points.get(previousPointSize - 1).coordinate.x; + } + PointPath lastReflexionPoint = points.get(points.size() - 1); + lastReflexionPoint.setType(PointPath.POINT_TYPE.REFL); if(rayPath.get(0).getType().equals(BUILDING)) { - reflPoint.setBuildingId(rayPath.get(0).getBuildingId()); - reflPoint.buildingHeight = data.profileBuilder.getBuilding(reflPoint.getBuildingId()).getHeight(); - reflPoint.setAlphaWall(data.profileBuilder.getBuilding(reflPoint.getBuildingId()).getAlphas()); + lastReflexionPoint.setBuildingId(secondPoint.getBuildingId()); + lastReflexionPoint.buildingHeight = data.profileBuilder.getBuilding(reflPoint.getBuildingId()).getHeight(); + lastReflexionPoint.setAlphaWall(data.profileBuilder.getBuilding(reflPoint.getBuildingId()).getAlphas()); } else { - reflPoint.buildingHeight = rayPath.get(0).getWall().p0.getZ(); - reflPoint.setWallId(rayPath.get(0).getWall().getProcessedWallIndex()); - reflPoint.setAlphaWall(rayPath.get(0).getWall().getAlphas()); + lastReflexionPoint.buildingHeight = secondPoint.getWall().p0.getZ(); + lastReflexionPoint.setWallId(secondPoint.getWall().getProcessedWallIndex()); + lastReflexionPoint.setAlphaWall(secondPoint.getWall().getAlphas()); } - reflPoint.altitude = data.profileBuilder.getZGround(reflPoint.coordinate); - points.add(reflPoint); - segments.add(new SegmentPath(1, new Vector3D(firstPt), refl.getReceiverPos())); + lastReflexionPoint.altitude = data.profileBuilder.getZGround(secondPoint.getReceiverPos()); } // Compute direct path between receiver and last reflection point, add profile to the data - List lastPts = new ArrayList<>(); - computeReflexionOverBuildings(rayPath.get(rayPath.size() - 1).getReceiverPos(), rcvCoord, lastPts, segments, data, orientation, proPath.difHPoints, proPath.difVPoints); - if (lastPts.isEmpty()) { + int previousPointSize = points.size(); + computeReflexionOverBuildings(rayPath.get(rayPath.size() - 1).getReceiverPos(), rcvCoord, points, segments, data, orientation, proPath.difHPoints, proPath.difVPoints); + 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; } - points.addAll(lastPts.subList(1, lastPts.size())); - double baseX = 0; - for(int i=0; i geom.getCoordinate().z - || points.get(i).coordinate.z <= data.profileBuilder.getZGround(points.get(i).coordinate)) { + final Coordinate p0 = points.get(i - 1).coordinate; + 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); + //check if new reflection point altitude is higher than the wall + if (currentPoint.coordinate.y > currentPoint.altitude + currentPoint.buildingHeight) { + // can't reflect higher than the wall points.clear(); segments.clear(); + rayPath.clear(); break; } } else { @@ -1402,7 +1411,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate sr } - if (rayPath.size() > 0) { + if (!rayPath.isEmpty()) { List pts = new ArrayList<>(); pts.add(srcCoord); rayPath.forEach(mrr -> pts.add(mrr.getReceiverPos())); diff --git a/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/TestWallReflection.java b/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/TestWallReflection.java index 394fba009..c95af7ddb 100644 --- a/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/TestWallReflection.java +++ b/noisemodelling-pathfinder/src/test/java/org/noise_planet/noisemodelling/pathfinder/TestWallReflection.java @@ -88,7 +88,6 @@ public void testWideWall() { @Test public void testNReflexion() throws ParseException, IOException, SQLException { - GeometryFactory factory = new GeometryFactory(); //Create profile builder @@ -124,6 +123,21 @@ public void testNReflexion() throws ParseException, IOException, SQLException { MirrorReceiverResultIndex receiverMirrorIndex = new MirrorReceiverResultIndex(buildWalls, receiver, inputData.reflexionOrder, inputData.maxSrcDist, inputData.maxRefDist); + // Keep only mirror receivers potentially visible from the source(and its parents) + List mirrorResults = receiverMirrorIndex.findCloseMirrorReceivers(inputData. + sourceGeometries.get(0).getCoordinate()); + assertEquals(18, mirrorResults.size()); + + try { + try (FileWriter fileWriter = new FileWriter("target/testNReflexion_testVisibilityCone.csv")) { + StringBuilder sb = new StringBuilder(); + receiverMirrorIndex.exportVisibility(sb, inputData.maxSrcDist, inputData.maxRefDist, + 0, mirrorResults, true); + fileWriter.write(sb.toString()); + } + } catch (IOException ex) { + //ignore + } List propagationPaths = computeRays.computeReflexion(receiver, inputData.sourceGeometries.get(0).getCoordinate(), false, @@ -131,49 +145,35 @@ public void testNReflexion() throws ParseException, IOException, SQLException { // Only one second order reflexion propagation path must be found assertEquals(1, propagationPaths.size()); - - -// int idPath = 1; -// for(PropagationPath path : propagationPaths) { -// try { -// try (FileWriter fileWriter = new FileWriter(String.format(Locale.ROOT, "target/testVisibilityPath_%03d.geojson", idPath))) { -// fileWriter.write(path.asGeom())); -// } -// } catch (IOException ex) { -// //ignore -// } -// idPath++; -// } - - // Keep only mirror receivers potentially visible from the source - List mirrorResults = receiverMirrorIndex.findCloseMirrorReceivers(inputData. - sourceGeometries.get(0).getCoordinate()); - assertEquals(18, mirrorResults.size()); - - // // Or Take all reflections - // List mirrorResults = new ArrayList<>(); - // var lst = receiverMirrorIndex.mirrorReceiverTree.query(new Envelope(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, - // Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); - // for(var item : lst) { - // if(item instanceof MirrorReceiverResult) { - // mirrorResults.add((MirrorReceiverResult) item); - // } - // } - // try { - // try (FileWriter fileWriter = new FileWriter("target/testVisibilityCone.csv")) { - // StringBuilder sb = new StringBuilder(); - // receiverMirrorIndex.exportVisibility(sb, inputData.maxSrcDist, inputData.maxRefDist, - // 0, mirrorResults, true); - // fileWriter.write(sb.toString()); - // } - // } catch (IOException ex) { - // //ignore - // } - // - - + // Check expected values for the propagation path + PropagationPath firstPath = propagationPaths.get(0); + var it = firstPath.getPointList().iterator(); + assertTrue(it.hasNext()); + PointPath current = it.next(); + assertEquals(PointPath.POINT_TYPE.SRCE ,current.type); + assertEquals(0.0, current.coordinate.x, 1e-12); + current = it.next(); + assertEquals(PointPath.POINT_TYPE.REFL ,current.type); + assertEquals(38.68, current.coordinate.x, 0.01); + current = it.next(); + assertEquals(PointPath.POINT_TYPE.REFL ,current.type); + assertEquals(53.28, current.coordinate.x, 0.01); + current = it.next(); + assertEquals(PointPath.POINT_TYPE.RECV ,current.type); + assertEquals(61.14, current.coordinate.x, 0.01); + + int idPath = 1; + for(PropagationPath path : propagationPaths) { + try { + try (FileWriter fileWriter = new FileWriter(String.format(Locale.ROOT, "target/testNReflexion_testVisibilityPath_%03d.geojson", idPath))) { + fileWriter.write(path.profileAsJSON(Integer.MAX_VALUE)); + } + } catch (IOException ex) { + //ignore + } + idPath++; + } } - }