diff --git a/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/AttenuatedPaths.java b/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/AttenuatedPaths.java index 0266acc15..48e3953cd 100644 --- a/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/AttenuatedPaths.java +++ b/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/AttenuatedPaths.java @@ -9,7 +9,7 @@ package org.noise_planet.noisemodelling.jdbc; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.propagation.Attenuation; import java.util.concurrent.ConcurrentLinkedDeque; diff --git a/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapInStack.java b/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapInStack.java index 0d79282a9..d49449912 100644 --- a/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapInStack.java +++ b/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapInStack.java @@ -10,7 +10,7 @@ package org.noise_planet.noisemodelling.jdbc; import org.noise_planet.noisemodelling.pathfinder.IComputePathsOut; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.utils.AcousticIndicatorsFunctions; import org.noise_planet.noisemodelling.propagation.Attenuation; import org.noise_planet.noisemodelling.propagation.AttenuationVisitor; diff --git a/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapWriter.java b/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapWriter.java index d7512e830..fae625c7b 100644 --- a/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapWriter.java +++ b/noisemodelling-jdbc/src/main/java/org/noise_planet/noisemodelling/jdbc/NoiseMapWriter.java @@ -11,7 +11,7 @@ import org.locationtech.jts.geom.LineString; import org.noise_planet.noisemodelling.jdbc.utils.StringPreparedStatements; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.propagation.Attenuation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/AttenuationCnossosTest.java b/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/AttenuationCnossosTest.java index 8b1984651..b56697a53 100644 --- a/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/AttenuationCnossosTest.java +++ b/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/AttenuationCnossosTest.java @@ -19,9 +19,9 @@ import org.locationtech.jts.math.Vector3D; import org.noise_planet.noisemodelling.pathfinder.path.Scene; import org.noise_planet.noisemodelling.pathfinder.PathFinder; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.delaunay.LayerDelaunayError; -import org.noise_planet.noisemodelling.pathfinder.path.SegmentPath; +import org.noise_planet.noisemodelling.propagation.cnossos.SegmentPath; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilderDecorator; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.WallAbsorption; diff --git a/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/NoiseMapByReceiverMakerTest.java b/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/NoiseMapByReceiverMakerTest.java index f8e82fc46..5bbdc5c3b 100644 --- a/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/NoiseMapByReceiverMakerTest.java +++ b/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/NoiseMapByReceiverMakerTest.java @@ -23,7 +23,7 @@ import org.noise_planet.noisemodelling.jdbc.Utils.JDBCComputeRaysOut; import org.noise_planet.noisemodelling.jdbc.Utils.JDBCPropagationData; import org.noise_planet.noisemodelling.pathfinder.*; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.GroundAbsorption; import org.noise_planet.noisemodelling.pathfinder.utils.geometry.Orientation; import org.noise_planet.noisemodelling.pathfinder.utils.profiler.RootProgressVisitor; diff --git a/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/Utils.java b/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/Utils.java index 2a43e97d7..0d52d87e1 100644 --- a/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/Utils.java +++ b/noisemodelling-jdbc/src/test/java/org/noise_planet/noisemodelling/jdbc/Utils.java @@ -12,7 +12,7 @@ import org.h2gis.utilities.SpatialResultSet; import org.locationtech.jts.geom.Geometry; import org.noise_planet.noisemodelling.pathfinder.*; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.path.Scene; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder; import org.noise_planet.noisemodelling.propagation.cnossos.AttenuationCnossosParameters; diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/IComputePathsOut.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/IComputePathsOut.java index b102e92ef..4d762a476 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/IComputePathsOut.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/IComputePathsOut.java @@ -9,25 +9,45 @@ package org.noise_planet.noisemodelling.pathfinder; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.CutProfile; import java.util.List; +/** + * Instead of feeding a list and returning all vertical cut planes. + * A visitor instance that implement this interface can skip planes and intervene in the search of cut planes. + */ public interface IComputePathsOut { /** - * Get propagation path result - * @param sourceId Source identifier - * @param sourceLi Source power per meter coefficient - * @param pathParameters Propagation path result + * A new vertical profile between a receiver and a source has been found + * + * @param cutProfile vertical profile + * @return Will skip or not the next processing depending on this value. */ - double[] addPropagationPaths(long sourceId, double sourceLi, long receiverId, List pathParameters); + PathSearchStrategy onNewCutPlane(CutProfile cutProfile); + + enum PathSearchStrategy { + /** + * Continue looking for vertical cut planes + */ + CONTINUE, + /** + * Skip remaining potential vertical planes for this source point + */ + SKIP_SOURCE, + /** + * Ignore other sources and process to the next receiver + */ + SKIP_RECEIVER + } /** * No more propagation paths will be pushed for this receiver identifier - * @param receiverId + * @param receiverId Primary key of the receiver (not the id of the receiver in the subdomain) */ void finalizeReceiver(long receiverId); + /** * If the implementation does not support thread concurrency, this method is called to return an instance * @return 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 b8a7e2963..0c19ab572 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 @@ -14,15 +14,11 @@ import org.h2gis.api.ProgressVisitor; import org.locationtech.jts.algorithm.*; import org.locationtech.jts.geom.*; -import org.locationtech.jts.math.Vector2D; import org.locationtech.jts.math.Vector3D; import org.locationtech.jts.triangulate.quadedge.Vertex; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder; import org.noise_planet.noisemodelling.pathfinder.path.*; -import org.noise_planet.noisemodelling.pathfinder.path.SegmentPath; import org.noise_planet.noisemodelling.pathfinder.path.MirrorReceiversCompute; -import org.noise_planet.noisemodelling.pathfinder.path.PointPath; import org.noise_planet.noisemodelling.pathfinder.path.MirrorReceiver; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.*; import org.noise_planet.noisemodelling.pathfinder.utils.geometry.Orientation; @@ -43,10 +39,8 @@ import static java.lang.Math.*; import static org.noise_planet.noisemodelling.pathfinder.PathFinder.ComputationSide.LEFT; import static org.noise_planet.noisemodelling.pathfinder.PathFinder.ComputationSide.RIGHT; -import static org.noise_planet.noisemodelling.pathfinder.path.PointPath.POINT_TYPE.*; import static org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder.IntersectionType.*; import static org.noise_planet.noisemodelling.pathfinder.utils.geometry.GeometricAttenuation.getADiv; -import static org.noise_planet.noisemodelling.pathfinder.utils.geometry.GeometryUtils.projectPointOnLine; import static org.noise_planet.noisemodelling.pathfinder.utils.AcousticIndicatorsFunctions.*; /** @@ -55,7 +49,6 @@ * @author Sylvain Palominos */ public class PathFinder { - private static final double ALPHA0 = 2e-4; // distance from wall for reflection points and diffraction points private static final double NAVIGATION_POINT_DISTANCE_FROM_WALLS = ProfileBuilder.MILLIMETER; private static final double epsilon = 1e-7; @@ -165,11 +158,11 @@ public void run(IComputePathsOut computeRaysOut) { * @param dataOut Computation output. * @param visitor Progress visitor used for cancellation and progression managing. */ - public void computeRaysAtPosition(PointPath.ReceiverPointInfo rcv, IComputePathsOut dataOut, ProgressVisitor visitor) { + public void computeRaysAtPosition(ReceiverPointInfo rcv, IComputePathsOut dataOut, ProgressVisitor visitor) { MirrorReceiversCompute receiverMirrorIndex = null; if(data.reflexionOrder > 0) { - Envelope receiverPropagationEnvelope = new Envelope(rcv.getCoord()); + Envelope receiverPropagationEnvelope = new Envelope(rcv.getCoordinates()); receiverPropagationEnvelope.expandBy(data.maxSrcDist); List buildWalls = data.profileBuilder.getWallsIn(receiverPropagationEnvelope); receiverMirrorIndex = new MirrorReceiversCompute(buildWalls, rcv.position, data.reflexionOrder, @@ -179,13 +172,13 @@ public void computeRaysAtPosition(PointPath.ReceiverPointInfo rcv, IComputePaths //Compute the source search area double searchSourceDistance = data.maxSrcDist; Envelope receiverSourceRegion = new Envelope( - rcv.getCoord().x - searchSourceDistance, - rcv.getCoord().x + searchSourceDistance, - rcv.getCoord().y - searchSourceDistance, - rcv.getCoord().y + searchSourceDistance + rcv.getCoordinates().x - searchSourceDistance, + rcv.getCoordinates().x + searchSourceDistance, + rcv.getCoordinates().y - searchSourceDistance, + rcv.getCoordinates().y + searchSourceDistance ); Iterator regionSourcesLst = data.sourcesIndex.query(receiverSourceRegion); - List sourceList = new ArrayList<>(); + List sourceList = new ArrayList<>(); //Already processed Raw source (line and/or points) HashSet processedLineSources = new HashSet<>(); // Sum of all sources power using only geometric dispersion with direct field @@ -198,7 +191,7 @@ public void computeRaysAtPosition(PointPath.ReceiverPointInfo rcv, IComputePaths double[] wj = data.getMaximalSourcePower(srcIndex); if (source instanceof Point) { Coordinate ptpos = source.getCoordinate(); - if (ptpos.distance(rcv.getCoord()) < data.maxSrcDist) { + if (ptpos.distance(rcv.getCoordinates()) < data.maxSrcDist) { Orientation orientation = null; if(data.sourcesPk.size() > srcIndex) { orientation = data.sourceOrientation.get(data.sourcesPk.get(srcIndex)); @@ -206,15 +199,15 @@ public void computeRaysAtPosition(PointPath.ReceiverPointInfo rcv, IComputePaths if(orientation == null) { orientation = new Orientation(0,0, 0); } - totalPowerRemaining += insertPtSource((Point) source, rcv.getCoord(), srcIndex, sourceList, wj, 1., orientation); + totalPowerRemaining += insertPtSource((Point) source, rcv.getCoordinates(), srcIndex, sourceList, wj, 1., orientation); } } else if (source instanceof LineString) { - totalPowerRemaining += addLineSource((LineString) source, rcv.getCoord(), srcIndex, sourceList, wj); + totalPowerRemaining += addLineSource((LineString) source, rcv.getCoordinates(), srcIndex, sourceList, wj); } else if (source instanceof MultiLineString) { for (int id = 0; id < source.getNumGeometries(); id++) { Geometry subGeom = source.getGeometryN(id); if (subGeom instanceof LineString) { - totalPowerRemaining += addLineSource((LineString) subGeom, rcv.getCoord(), srcIndex, sourceList, wj); + totalPowerRemaining += addLineSource((LineString) subGeom, rcv.getCoordinates(), srcIndex, sourceList, wj); } } } else { @@ -225,22 +218,14 @@ public void computeRaysAtPosition(PointPath.ReceiverPointInfo rcv, IComputePaths } // Sort sources by power contribution descending Collections.sort(sourceList); - double powerAtSource = 0; + // For each Pt Source - Pt Receiver AtomicInteger raysCount = new AtomicInteger(0); - for (PointPath.SourcePointInfo src : sourceList) { - double[] power = rcvSrcPropagation(src, src.li, rcv, dataOut, raysCount, receiverMirrorIndex); - double global = sumArray(power.length, dbaToW(power)); - totalPowerRemaining -= src.globalWj; - if (power.length > 0) { - powerAtSource += global; - } else { - powerAtSource += src.globalWj; - } + for (SourcePointInfo src : sourceList) { + IComputePathsOut.PathSearchStrategy strategy = rcvSrcPropagation(src, rcv, dataOut, raysCount, receiverMirrorIndex); totalPowerRemaining = max(0, totalPowerRemaining); // If the delta between already received power and maximal potential power received is inferior than than data.maximumError - if ((visitor != null && visitor.isCanceled()) || (data.maximumError > 0 && - wToDba(powerAtSource + totalPowerRemaining) - wToDba(powerAtSource) < data.maximumError)) { + if ((visitor != null && visitor.isCanceled()) || !strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { break; //Stop looking for more rays } } @@ -258,45 +243,32 @@ public void computeRaysAtPosition(PointPath.ReceiverPointInfo rcv, IComputePaths * Calculation of the propagation between the given source and receiver. The result is registered in the given * output. * @param src Source point. - * @param srcLi Source power per meter coefficient. * @param rcv Receiver point. * @param dataOut Output. - * @return + * @return Continue or not looking for propagation paths */ - private double[] rcvSrcPropagation(PointPath.SourcePointInfo src, double srcLi, PointPath.ReceiverPointInfo rcv, - IComputePathsOut dataOut, AtomicInteger raysCount, - MirrorReceiversCompute receiverMirrorIndex) { - - double propaDistance = src.getCoord().distance(rcv.getCoord()); + private IComputePathsOut.PathSearchStrategy rcvSrcPropagation(SourcePointInfo src, + ReceiverPointInfo rcv, + IComputePathsOut dataOut, AtomicInteger raysCount, + MirrorReceiversCompute receiverMirrorIndex) { + IComputePathsOut.PathSearchStrategy strategy = IComputePathsOut.PathSearchStrategy.CONTINUE; + double propaDistance = src.getCoord().distance(rcv.getCoordinates()); if (propaDistance < data.maxSrcDist) { // Process direct : horizontal and vertical diff - List pathParameters = new ArrayList<>(directPath(src, rcv, - data.computeVerticalDiffraction, data.computeHorizontalDiffraction, data.isBodyBarrier())); + strategy = directPath(src, rcv, data.computeVerticalDiffraction, + data.computeHorizontalDiffraction, dataOut); + if(!strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { + return strategy; + } // Process reflection if (data.reflexionOrder > 0) { - pathParameters.addAll(computeReflexion(rcv.getCoord(), src.getCoord(), - src.getOrientation(), receiverMirrorIndex)); - } - if (!pathParameters.isEmpty()) { - if(raysCount != null) { - raysCount.addAndGet(pathParameters.size()); + strategy = computeReflexion(rcv, src, receiverMirrorIndex, dataOut); + if(!strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { + return strategy; } - return dataOut.addPropagationPaths(src.getId(), srcLi, rcv.getId(), pathParameters); } } - return new double[0]; - } - - /** - * Direct Path computation. - * @param src Source point. - * @param rcv Receiver point. - * @return Calculated propagation paths. - */ - public List directPath(PointPath.SourcePointInfo src, - PointPath.ReceiverPointInfo rcv, boolean verticalDiffraction, boolean horizontalDiffraction, boolean bodyBarrier) { - return directPath(src.getCoord(), src.getId(), src.getOrientation(), rcv.getCoord(), rcv.getId(), - verticalDiffraction, horizontalDiffraction, bodyBarrier); + return strategy; } /** @@ -307,23 +279,31 @@ public List directPath(PointPath.SourcePointInfo src, * @param rcvId Receiver point identifier. * @return Calculated propagation paths. */ - public List directPath(Coordinate srcCoord, int srcId, Orientation orientation, Coordinate rcvCoord, - int rcvId, boolean verticalDiffraction, boolean horizontalDiffraction, - boolean bodyBarrier) { - List pathsParameters = new ArrayList<>(); - CutProfile cutProfile = data.profileBuilder.getProfile(srcCoord, rcvCoord, data.gS, !verticalDiffraction); + public IComputePathsOut.PathSearchStrategy directPath(SourcePointInfo src, ReceiverPointInfo rcv, + boolean verticalDiffraction, boolean horizontalDiffraction, + IComputePathsOut dataOut) { + + IComputePathsOut.PathSearchStrategy strategy = IComputePathsOut.PathSearchStrategy.CONTINUE; + + CutProfile cutProfile = data.profileBuilder.getProfile(src.position, rcv.position, data.gS, !verticalDiffraction); if(cutProfile.getSource() != null) { - cutProfile.getSource().setId(srcId); + cutProfile.getSource().setId(src.getId()); + cutProfile.getSource().li = src.li; + cutProfile.getSource().orientation = src.getOrientation(); } if(cutProfile.getReceiver() != null) { - cutProfile.getReceiver().setId(rcvId); + cutProfile.getReceiver().setId(rcv.getId()); } - cutProfile.setSrcOrientation(orientation); + if(verticalDiffraction || cutProfile.isFreeField()) { - CnossosPath hEdgePath = computeHEdgeDiffraction(cutProfile, bodyBarrier); - if (hEdgePath != null) { - pathsParameters.add(hEdgePath); + assert cutProfile.getSource().getType() == SOURCE; + assert cutProfile.getReceiver().getType() == RECEIVER; + cutProfile.getReceiver().primaryKey = data.receiversPk.get(rcv.receiverIndex); + cutProfile.getSource().primaryKey = data.sourcesPk.get(src.sourceIndex); + strategy = dataOut.onNewCutPlane(cutProfile); + if(!strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { + return strategy; } } @@ -333,87 +313,23 @@ public List directPath(Coordinate srcCoord, int srcId, Orientation // between source and receiver is blocked and does not penetrate the terrain profile. // In addition, the source must not be a mirror source due to reflection" if (horizontalDiffraction && !cutProfile.isFreeField()) { - CnossosPath vEdgePath = computeVEdgeDiffraction(rcvCoord, srcCoord, data, RIGHT, orientation); - if (vEdgePath != null && vEdgePath.getPointList() != null) { - pathsParameters.add(vEdgePath); + CutProfile cutProfileRight = computeVEdgeDiffraction(rcv, src, data, RIGHT); + if (cutProfileRight != null) { + strategy = dataOut.onNewCutPlane(cutProfileRight); + if(!strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { + return strategy; + } } - vEdgePath = computeVEdgeDiffraction(rcvCoord, srcCoord, data, LEFT, orientation); - if (vEdgePath != null && vEdgePath.getPointList() != null) { - pathsParameters.add(vEdgePath); + CutProfile cutProfileLeft = computeVEdgeDiffraction(rcv, src, data, LEFT); + if (cutProfileLeft != null) { + strategy = dataOut.onNewCutPlane(cutProfileLeft); + if(!strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { + return strategy; + } } } - for(CnossosPath pathParameters : pathsParameters) { - pathParameters.idSource = srcId; - pathParameters.idReceiver = rcvId; - pathParameters.setSourceOrientation(orientation); - } - - return pathsParameters; - } - - - /** - * Eq.2.5.24 and Eq. 2.5.25 - * @param mn - * @param d - * @return - */ - - private static double toCurve(double mn, double d){ - return 2*max(1000, 8*d)* asin(mn/(2*max(1000, 8*d))); - } - - /** - * Compute the segment path - * @param src - * @param rcv - * @param meanPlane - * @return the calculated segment - */ - private static SegmentPath computeSegment(Coordinate src, Coordinate rcv, double[] meanPlane) { - return computeSegment(src, rcv, meanPlane, 0, 0); - } - - /** - * Compute the segment path with more attribute - * @param src - * @param rcv - * @param meanPlane - * @param gPath - * @param gS - * @return the computed segment path - */ - - private static SegmentPath computeSegment(Coordinate src, Coordinate rcv, double[] meanPlane, double gPath, double gS) { - SegmentPath seg = new SegmentPath(); - Coordinate sourcePointOnMeanPlane = projectPointOnLine(src, meanPlane[0], meanPlane[1]); - Coordinate receiverPointOnMeanPlane = projectPointOnLine(rcv, meanPlane[0], meanPlane[1]); - Vector2D sourceToProjectedPoint = Vector2D.create(src, sourcePointOnMeanPlane); - Vector2D receiverToProjectedPoint = Vector2D.create(rcv, receiverPointOnMeanPlane); - seg.s = src; - seg.r = rcv; - seg.sMeanPlane = sourcePointOnMeanPlane; - seg.rMeanPlane = receiverPointOnMeanPlane; - seg.sPrime = Vector2D.create(sourcePointOnMeanPlane).add(sourceToProjectedPoint).toCoordinate(); - seg.rPrime = Vector2D.create(receiverPointOnMeanPlane).add(receiverToProjectedPoint).toCoordinate(); - - seg.d = src.distance(rcv); - seg.dp =sourcePointOnMeanPlane.distance(receiverPointOnMeanPlane); - seg.zsH = src.distance(sourcePointOnMeanPlane); - seg.zrH = rcv.distance(receiverPointOnMeanPlane); - seg.a = meanPlane[0]; - seg.b = meanPlane[1]; - seg.testFormH = seg.dp/(30*(seg.zsH +seg.zrH)); - seg.gPath = gPath; - seg.gPathPrime = seg.testFormH <= 1 ? seg.gPath*(seg.testFormH) + gS*(1-seg.testFormH) : seg.gPath; // 2.5.14 - double deltaZT = 6e-3 * seg.dp / (seg.zsH + seg.zrH); - double deltaZS = ALPHA0 * pow((seg.zsH / (seg.zsH + seg.zrH)), 2) * (seg.dp*seg.dp / 2); //2.5.19 - seg.zsF = seg.zsH + deltaZS + deltaZT; - double deltaZR = ALPHA0 * pow((seg.zrH / (seg.zsH + seg.zrH)), 2) * (seg.dp*seg.dp / 2); - seg.zrF = seg.zrH + deltaZR + deltaZT; - seg.testFormF = seg.dp/(30*(seg.zsF +seg.zrF)); - return seg; + return strategy; } @@ -455,10 +371,11 @@ private static Orientation computeOrientation(Orientation sourceOrientation, Coo * @param side Side to compute. From Source to receiver coordinates * @return The propagation path of the horizontal diffraction. */ - public CnossosPath computeVEdgeDiffraction(Coordinate receiverCoordinates, Coordinate sourceCoordinates, - Scene data, ComputationSide side, Orientation orientation) { + public CutProfile computeVEdgeDiffraction(ReceiverPointInfo rcv, SourcePointInfo src, + Scene data, ComputationSide side) { - List coordinates = computeSideHull(side == LEFT, new Coordinate(sourceCoordinates), new Coordinate(receiverCoordinates), data.profileBuilder); + List coordinates = computeSideHull(side == LEFT, new Coordinate(src.position), + new Coordinate(rcv.position), data.profileBuilder); List cutPoints = new ArrayList<>(); @@ -483,472 +400,21 @@ public CnossosPath computeVEdgeDiffraction(Coordinate receiverCoordinates, Coord CutProfile mainProfile = new CutProfile(); mainProfile.addCutPoints(cutPoints); mainProfile.setSource(cutPoints.get(0)); - mainProfile.setSrcOrientation(orientation); mainProfile.setReceiver(cutPoints.get(cutPoints.size() - 1)); - // Compute Ray path from vertical cuts (like a folding screen) - CnossosPath cnossosPath = computeHEdgeDiffraction(mainProfile, data.isBodyBarrier()); - - if(cnossosPath == null) { - // path not valid (ex: intersection with ground) - return null; - } - - return cnossosPath; - } - return null; - } - private void computeRayleighDiff(SegmentPath srSeg, CutProfile cutProfile, CnossosPath pathParameters, - LineSegment dSR, List segments, List points, - List pts2D, Coordinate[] pts2DGround, List cut2DGroundIndex) { - final List cuts = cutProfile.getCutPoints(); - - Coordinate src = pts2D.get(0); - Coordinate rcv = pts2D.get(pts2D.size() - 1); - CutPoint srcCut = cutProfile.getSource(); - CutPoint rcvCut = cutProfile.getReceiver(); - for (int iO = 1; iO < pts2DGround.length - 1; iO++) { - int i0Cut = cut2DGroundIndex.indexOf(iO); - Coordinate o = pts2DGround[iO]; - - double dSO = src.distance(o); - double dOR = o.distance(rcv); - double deltaH = dSR.orientationIndex(o) * (dSO + dOR - srSeg.d); - List freqs = data.freq_lvl; - boolean rcrit = false; - for(int f : freqs) { - if(deltaH > -(340./f) / 20) { - rcrit = true; - break; - } - } - if (rcrit) { - rcrit = false; - //Add point path - - //Plane S->O - Coordinate[] soCoords = Arrays.copyOfRange(pts2DGround, 0, iO + 1); - double[] abs = JTSUtility.getMeanPlaneCoefficients(soCoords); - SegmentPath seg1 = computeSegment(src, o, abs); - - //Plane O->R - Coordinate[] orCoords = Arrays.copyOfRange(pts2DGround, iO, pts2DGround.length); - double[] abr = JTSUtility.getMeanPlaneCoefficients(orCoords); - SegmentPath seg2 = computeSegment(o, rcv, abr); - - Coordinate srcPrime = new Coordinate(src.x + (seg1.sMeanPlane.x - src.x) * 2, src.y + (seg1.sMeanPlane.y - src.y) * 2); - Coordinate rcvPrime = new Coordinate(rcv.x + (seg2.rMeanPlane.x - rcv.x) * 2, rcv.y + (seg2.rMeanPlane.y - rcv.y) * 2); - - LineSegment dSPrimeRPrime = new LineSegment(srcPrime, rcvPrime); - srSeg.dPrime = srcPrime.distance(rcvPrime); - seg1.dPrime = srcPrime.distance(o); - seg2.dPrime = o.distance(rcvPrime); - - double deltaPrimeH = dSPrimeRPrime.orientationIndex(o) * (seg1.dPrime + seg2.dPrime - srSeg.dPrime); - for(int f : freqs) { - if(deltaH > (340./f) / 4 - deltaPrimeH) { - rcrit = true; - break; - } - } - if (rcrit) { - pathParameters.deltaH = deltaH; - pathParameters.deltaPrimeH = deltaPrimeH; - seg1.setGpath(cutProfile.getGPath(srcCut, cuts.get(i0Cut)), srcCut.getGroundCoef()); - seg2.setGpath(cutProfile.getGPath(cuts.get(i0Cut), rcvCut), srcCut.getGroundCoef()); - - if(dSR.orientationIndex(o) == 1) { - pathParameters.deltaF = toCurve(dSO, srSeg.d) + toCurve(dOR, srSeg.d) - toCurve(srSeg.d, srSeg.d); - } - else { - Coordinate pA = dSR.pointAlong((o.x-src.x)/(rcv.x-src.x)); - pathParameters.deltaF =2*toCurve(src.distance(pA), srSeg.d) + 2*toCurve(pA.distance(rcv), srSeg.d) - toCurve(dSO, srSeg.d) - toCurve(dOR, srSeg.d) - toCurve(srSeg.d, srSeg.d); - } - - LineSegment sPrimeR = new LineSegment(seg1.sPrime, rcv); - double dSPrimeO = seg1.sPrime.distance(o); - double dSPrimeR = seg1.sPrime.distance(rcv); - pathParameters.deltaSPrimeRH = sPrimeR.orientationIndex(o)*(dSPrimeO + dOR - dSPrimeR); - - LineSegment sRPrime = new LineSegment(src, seg2.rPrime); - double dORPrime = o.distance(seg2.rPrime); - double dSRPrime = src.distance(seg2.rPrime); - pathParameters.deltaSRPrimeH = sRPrime.orientationIndex(o)*(dSO + dORPrime - dSRPrime); - - if(dSPrimeRPrime.orientationIndex(o) == 1) { - pathParameters.deltaPrimeF = toCurve(seg1.dPrime, srSeg.dPrime) + toCurve(seg2.dPrime, srSeg.dPrime) - toCurve(srSeg.dPrime, srSeg.dPrime); - } - else { - Coordinate pA = dSPrimeRPrime.pointAlong((o.x-srcPrime.x)/(rcvPrime.x-srcPrime.x)); - pathParameters.deltaPrimeF =2*toCurve(srcPrime.distance(pA), srSeg.dPrime) + 2*toCurve(pA.distance(srcPrime), srSeg.dPrime) - toCurve(seg1.dPrime, srSeg.dPrime) - toCurve(seg2.dPrime, srSeg.d) - toCurve(srSeg.dPrime, srSeg.dPrime); - } + assert mainProfile.getSource().getType() == SOURCE; + assert mainProfile.getReceiver().getType() == RECEIVER; - segments.add(seg1); - segments.add(seg2); + mainProfile.getReceiver().primaryKey = data.receiversPk.get(rcv.receiverIndex); + mainProfile.getSource().primaryKey = data.sourcesPk.get(src.sourceIndex); + mainProfile.getSource().orientation = src.orientation; + mainProfile.getSource().li = src.li; - points.add(new PointPath(o, o.z, new ArrayList<>(), DIFH_RCRIT)); - } - } + return mainProfile; } + return null; } - /** - * Given the vertical cut profile (can be a single plane or multiple like a folding panel) return the ray path - * following Cnossos specification, or null if there is no valid path. - * @param cutProfile Vertical cut of a domain - * @param bodyBarrier - * @return The cnossos path or null - */ - public CnossosPath computeHEdgeDiffraction(CutProfile cutProfile , boolean bodyBarrier) { - List segments = new ArrayList<>(); - List points = new ArrayList<>(); - final List cutProfilePoints = cutProfile.getCutPoints(); - - List pts2D = computePts2D(cutProfilePoints); - if(pts2D.size() != cutProfilePoints.size()) { - throw new IllegalArgumentException("The two arrays size should be the same"); - } - - List cut2DGroundIndex = new ArrayList<>(cutProfile.getCutPoints().size()); - Coordinate[] pts2DGround = cutProfile.computePts2DGround(cut2DGroundIndex).toArray(new Coordinate[0]); - double[] meanPlane = JTSUtility.getMeanPlaneCoefficients(pts2DGround); - Coordinate firstPts2D = pts2D.get(0); - Coordinate lastPts2D = pts2D.get(pts2D.size()-1); - SegmentPath srPath = computeSegment(firstPts2D, lastPts2D, meanPlane, cutProfile.getGPath(), cutProfile.getSource().getGroundCoef()); - srPath.setPoints2DGround(pts2DGround); - srPath.dc = CGAlgorithms3D.distance(cutProfile.getReceiver().getCoordinate(), - cutProfile.getSource().getCoordinate()); - CnossosPath pathParameters = new CnossosPath(); - pathParameters.setCutProfile(cutProfile); - pathParameters.setFavorable(true); - pathParameters.setPointList(points); - pathParameters.setSegmentList(segments); - pathParameters.setSRSegment(srPath); - pathParameters.init(data.freq_lvl.size()); - pathParameters.angle=Angle.angle(cutProfile.getReceiver().getCoordinate(), cutProfile.getSource().getCoordinate()); - // Extract the first and last points to define the line segment - Coordinate firstPt = pts2D.get(0); - Coordinate lastPt = pts2D.get(pts2D.size() - 1); - - // Filter out points that are below the line segment - List convexHullInput = new ArrayList<>(); - // Add source position - convexHullInput.add(pts2D.get(0)); - // Add valid diffraction point, building/walls/dem - for (int idPoint=1; idPoint < cutProfilePoints.size() - 1; idPoint++) { - boolean validIntersection = false; - CutPoint currentPoint = cutProfilePoints.get(idPoint); - switch (currentPoint.getType()) { - case BUILDING: - case WALL: - // We only add the point at the top of the wall, not the point at the bottom of the wall - validIntersection = Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0; - break; - case TOPOGRAPHY: - validIntersection = true; - break; - default: - } - if(validIntersection) { - convexHullInput.add(pts2D.get(idPoint)); - } - } - // Add receiver position - convexHullInput.add(pts2D.get(pts2D.size() - 1)); - - // Compute the convex hull using JTS - List convexHullPoints = new ArrayList<>(); - if(convexHullInput.size() > 2) { - GeometryFactory geomFactory = new GeometryFactory(); - Coordinate[] coordsArray = convexHullInput.toArray(new Coordinate[0]); - ConvexHull convexHull = new ConvexHull(coordsArray, geomFactory); - Coordinate[] convexHullCoords = convexHull.getConvexHull().getCoordinates(); - int indexFirst = Arrays.asList(convexHull.getConvexHull().getCoordinates()).indexOf(firstPt); - int indexLast = Arrays.asList(convexHull.getConvexHull().getCoordinates()).lastIndexOf(lastPt); - if(indexFirst == -1 || indexLast == -1 || indexFirst > indexLast) { - throw new IllegalArgumentException("Wrong input data " + cutProfile.toString()); - } - convexHullCoords = Arrays.copyOfRange(convexHullCoords, indexFirst, indexLast + 1); - CoordinateSequence coordSequence = geomFactory.getCoordinateSequenceFactory().create(convexHullCoords); - Geometry geom = geomFactory.createLineString(coordSequence); - Geometry uniqueGeom = geom.union(); // Removes duplicate coordinates - convexHullCoords = uniqueGeom.getCoordinates(); - // Convert the result back to your format (List pts) - if (convexHullCoords.length == 3) { - convexHullPoints = Arrays.asList(convexHullCoords); - } else { - for (int j = 0; j < convexHullCoords.length; j++) { - // Check if the y-coordinate is valid (not equal to Double.MAX_VALUE and not infinite) - if (convexHullCoords[j].y == Double.MAX_VALUE || Double.isInfinite(convexHullCoords[j].y)) { - continue; // Skip this point as it's not part of the hull - } - convexHullPoints.add(convexHullCoords[j]); - } - } - } else { - convexHullPoints = convexHullInput; - } - List pts = convexHullPoints; - - Coordinate src = cutProfile.getSource().getCoordinate(); - - // Move then check reflection height if there is diffraction on the path - if(pts.size() > 2) { - for (int i = 1; i < pts.size(); i++) { - int i0 = pts2D.indexOf(pts.get(i - 1)); - int i1 = pts2D.indexOf(pts.get(i)); - LineSegment segmentHull = new LineSegment(pts.get(i - 1), pts.get(i)); - for (int pointIndex = i0 + 1; pointIndex < i1; pointIndex++) { - final CutPoint currentPoint = cutProfilePoints.get(pointIndex); - // If the current point is the reflection point (not on the ground level) - if (currentPoint.getType().equals(REFLECTION) && - Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0) { - MirrorReceiver mirrorReceiver = currentPoint.getMirrorReceiver(); - Coordinate interpolatedReflectionPoint = segmentHull.closestPoint(pts2D.get(pointIndex)); - // Check if the new elevation of the reflection point is not higher than the wall - double wallAltitudeAtReflexionPoint = Vertex.interpolateZ(mirrorReceiver.getReflectionPosition(), - mirrorReceiver.getWall().p0, mirrorReceiver.getWall().p1); - if(wallAltitudeAtReflexionPoint + epsilon >= interpolatedReflectionPoint.y) { - // update the reflection position - currentPoint.getCoordinate().setZ(interpolatedReflectionPoint.y); - pts2D.get(pointIndex).setY(interpolatedReflectionPoint.y); - } else { - // Reflection is not valid, so the whole path is not valid - return null; - } - } - } - } - } - - // Create segments from each diffraction point to the receiver - for (int i = 1; i < pts.size(); i++) { - int i0 = pts2D.indexOf(pts.get(i - 1)); - int i1 = pts2D.indexOf(pts.get(i)); - int i0Ground = cut2DGroundIndex.get(i0); - int i1Ground = cut2DGroundIndex.get(i1); - final CutPoint cutPt0 = cutProfilePoints.get(i0); - final CutPoint cutPt1 = cutProfilePoints.get(i1); - // ground index may be near the diffraction point - // mean ground plane is computed using from the bottom of the walls - if (i0Ground < i1Ground - 1) { - CutPoint nextPoint = cutProfilePoints.get(i0 + 1); - if (cutPt0.getCoordinate().distance(nextPoint.getCoordinate()) <= ProfileBuilder.MILLIMETER + epsilon - && Double.compare(nextPoint.getCoordinate().z, nextPoint.getzGround()) == 0 - && (nextPoint.getType().equals(WALL) || nextPoint.getType().equals(BUILDING))) { - i0Ground += 1; - } - } - if (i1Ground - 1 > i0Ground) { - CutPoint previousPoint = cutProfilePoints.get(i1 - 1); - if (cutPt1.getCoordinate().distance(previousPoint.getCoordinate()) <= ProfileBuilder.MILLIMETER + - epsilon && Double.compare(previousPoint.getCoordinate().z, previousPoint.getzGround()) == 0 - && (previousPoint.getType().equals(WALL) || previousPoint.getType().equals(BUILDING))) { - i1Ground -= 1; - } - } - // Create a profile for the segment i0->i1 - CutProfile profileSeg = new CutProfile(); - profileSeg.addCutPoints(cutProfilePoints.subList(i0, i1 + 1)); - profileSeg.setSource(cutPt0); - profileSeg.setReceiver(cutPt1); - - - if (points.isEmpty()) { - // First segment, add the source point in the array - points.add(new PointPath(pts2D.get(i0), cutPt0.getzGround(), cutPt0.getWallAlpha(), cutPt1.getBuildingId(), SRCE)); - // look for the first reflection before the first diffraction, the source orientation is to the first reflection point - Coordinate targetPosition = cutProfilePoints.get(i1).getCoordinate(); - for (int pointIndex = i0 + 1; pointIndex < i1; pointIndex++) { - final CutPoint currentPoint = cutProfilePoints.get(pointIndex); - if ((currentPoint.getType().equals(REFLECTION) || currentPoint.getType().equals(V_EDGE_DIFFRACTION)) && - Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0) { - // The first reflection (the one not at ground level) - // from the source coordinate is the direction of the propagation - targetPosition = currentPoint.getCoordinate(); - break; - } - } - points.get(0).orientation = computeOrientation(cutProfile.getSrcOrientation(), - cutProfilePoints.get(0).getCoordinate(), targetPosition); - pathParameters.raySourceReceiverDirectivity = points.get(0).orientation; - src = pts2D.get(i0); - } - // Add reflection/vertical edge diffraction points/segments between i0 i1 - int previousPivotPoint = i0; - for (int pointIndex = i0 + 1; pointIndex < i1; pointIndex++) { - final CutPoint currentPoint = cutProfilePoints.get(pointIndex); - if (currentPoint.getType().equals(REFLECTION) && - Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0) { - // If the current point is a reflection and not before/after the reflection - MirrorReceiver mirrorReceiver = currentPoint.getMirrorReceiver(); - double wallAltitudeAtReflexionPoint = Vertex.interpolateZ(mirrorReceiver.getReflectionPosition(), - mirrorReceiver.getWall().p0, mirrorReceiver.getWall().p1); - PointPath reflectionPoint = new PointPath(pts2D.get(pointIndex),currentPoint.getzGround(), currentPoint.getWallAlpha(), REFL); - reflectionPoint.obstacleZ = wallAltitudeAtReflexionPoint; - reflectionPoint.setWallId(currentPoint.getWallId()); - points.add(reflectionPoint); - } else if (currentPoint.getType().equals(V_EDGE_DIFFRACTION)) { - // current point is a vertical edge diffraction (there is no additional points unlike reflection) - PointPath diffractionPoint = new PointPath(pts2D.get(pointIndex),currentPoint.getzGround(), new ArrayList<>(), DIFV); - diffractionPoint.setWallId(currentPoint.getWallId()); - points.add(diffractionPoint); - // Compute additional segment - Coordinate[] segmentGroundPoints = Arrays.copyOfRange(pts2DGround, i0Ground,cut2DGroundIndex.get(pointIndex) + 1); - meanPlane = JTSUtility.getMeanPlaneCoefficients(segmentGroundPoints); - SegmentPath seg = computeSegment(pts2D.get(previousPivotPoint), pts2D.get(pointIndex), - meanPlane, profileSeg.getGPath(cutPt0, cutProfilePoints.get(pointIndex)), data.gS); - seg.setPoints2DGround(segmentGroundPoints); - previousPivotPoint = pointIndex; - segments.add(seg); - } - } - points.add(new PointPath(pts2D.get(i1), cutPt1.getzGround(), cutPt1.getWallAlpha(), cutPt1.getBuildingId(), RECV)); - if(previousPivotPoint != i0 && i == pts.size() - 1) { - // we added segments before i1 vertical plane diffraction point, but it is the last vertical plane - // diffraction point and we must add the remaining segment between the last horizontal diffraction point - // and the last point - Coordinate[] segmentGroundPoints = Arrays.copyOfRange(pts2DGround, i1Ground, pts2DGround.length); - meanPlane = JTSUtility.getMeanPlaneCoefficients(segmentGroundPoints); - SegmentPath seg = computeSegment(pts2D.get(previousPivotPoint), pts2D.get(pts2D.size() - 1), - meanPlane, profileSeg.getGPath(cutPt1, cutProfilePoints.get(cutProfilePoints.size() - 1)), - data.gS); - seg.setPoints2DGround(segmentGroundPoints); - segments.add(seg); - } - if(pts.size() == 2) { - // no diffraction over buildings/dem, we already computed SR segment - break; - } - Coordinate[] segmentGroundPoints = Arrays.copyOfRange(pts2DGround, i0Ground,i1Ground + 1); - meanPlane = JTSUtility.getMeanPlaneCoefficients(segmentGroundPoints); - SegmentPath path = computeSegment(pts2D.get(i0), pts2D.get(i1), meanPlane, profileSeg.getGPath(), - profileSeg.getSource().getGroundCoef()); - path.dc = cutPt0.getCoordinate().distance3D(cutPt1.getCoordinate()); - path.setPoints2DGround(segmentGroundPoints); - segments.add(path); - if (i != pts.size() - 1) { - PointPath pt = points.get(points.size() - 1); - pt.type = DIFH; - pt.bodyBarrier = bodyBarrier; - if (pt.buildingId != -1) { - pt.alphaWall = data.profileBuilder.getBuilding(pt.buildingId).getAlphas(); - pt.setObstacleZ(data.profileBuilder.getBuilding(pt.buildingId).getZ()); - } else if (pt.wallId != -1) { - pt.alphaWall = data.profileBuilder.getWall(pt.wallId).getAlphas(); - Wall wall = data.profileBuilder.getWall(pt.wallId); - pt.setObstacleZ(Vertex.interpolateZ(pt.coordinate, wall.p0, wall.p1)); - } - } - } - - if(points.isEmpty()) { - return null; - } - - Coordinate rcv = points.get(points.size()-1).coordinate; - PointPath p0 = points.stream().filter(p -> p.type.equals(DIFH)).findFirst().orElse(null); - if(p0==null){ - // Direct propagation (no diffraction over obstructing objects) - boolean horizontalPlaneDiffraction = cutProfile.getCutPoints().stream() - .anyMatch( - cutPoint -> cutPoint.getType().equals(V_EDGE_DIFFRACTION)); - List rayleighSegments = new ArrayList<>(); - List rayleighPoints = new ArrayList<>(); - // do not check for rayleigh if the path is not direct between R and S - if(!horizontalPlaneDiffraction) { - // Check for Rayleigh criterion for segments computation - LineSegment dSR = new LineSegment(firstPts2D, lastPts2D); - // Look for diffraction over edge on free field (frequency dependent) - computeRayleighDiff(srPath, cutProfile, pathParameters, dSR, rayleighSegments, rayleighPoints, pts2D, - pts2DGround, cut2DGroundIndex); - } - if(rayleighSegments.isEmpty()) { - // We don't have a Rayleigh diffraction over DEM. Only direct SR path - if(segments.isEmpty()) { - segments.add(pathParameters.getSRSegment()); - } - // Compute cumulated distance between the first diffraction and the last diffraction point - pathParameters.e = 0; - List diffPoints = points.stream().filter(pointPath -> pointPath.type != REFL).collect(Collectors.toList()); - for(int idPoint = 1; idPoint < diffPoints.size() - 2; idPoint++) { - pathParameters.e += diffPoints.get(idPoint).coordinate.distance(diffPoints.get(idPoint+1).coordinate); - } - long difVPointCount = pathParameters.getPointList().stream(). - filter(pointPath -> pointPath.type.equals(DIFV)).count(); - double distance = difVPointCount == 0 ? pathParameters.getSRSegment().d : pathParameters.getSRSegment().dc; - pathParameters.deltaH = segments.get(0).d + pathParameters.e + segments.get(segments.size()-1).d - distance; - pathParameters.deltaF = pathParameters.deltaH; - } else { - segments.addAll(rayleighSegments); - points.addAll(1, rayleighPoints); - } - return pathParameters; - } - Coordinate c0 = p0.coordinate; - PointPath pn = points.stream().filter(p -> p.type.equals(DIFH)).reduce((first, second) -> second).orElse(null); - if(pn==null){ - return null; - } - Coordinate cn = pn.coordinate; - - SegmentPath seg1 = segments.get(0); - SegmentPath seg2 = segments.get(segments.size()-1); - - double dSO0 = seg1.d; - double dOnR = seg2.d; - LineSegment sr = new LineSegment(src, rcv); - - LineSegment sPrimeR = new LineSegment(seg1.sPrime, rcv); - double dSPrimeR = seg1.sPrime.distance(rcv); - double dSPrimeO = seg1.sPrime.distance(c0); - // Compute cumulated distance between the first diffraction and the last diffraction point - pathParameters.e = 0; - List diffPoints = points.stream().filter(pointPath -> pointPath.type != REFL).collect(Collectors.toList()); - for(int idPoint = 1; idPoint < diffPoints.size() - 2; idPoint++) { - pathParameters.e += diffPoints.get(idPoint).coordinate.distance(diffPoints.get(idPoint+1).coordinate); - } - pathParameters.deltaSPrimeRH = sPrimeR.orientationIndex(c0)*(dSPrimeO + pathParameters.e + dOnR - dSPrimeR); - pathParameters.deltaSPrimeRF = toCurve(dSPrimeO, dSPrimeR) + toCurve(pathParameters.e, dSPrimeR) + toCurve(dOnR, dSPrimeR) - toCurve(dSPrimeR, dSPrimeR); - - LineSegment sRPrime = new LineSegment(src, seg2.rPrime); - double dSRPrime = src.distance(seg2.rPrime); - double dORPrime = cn.distance(seg2.rPrime); - pathParameters.deltaSRPrimeH = (src.x>seg2.rPrime.x?-1:1)*sRPrime.orientationIndex(cn)*(dSO0 + pathParameters.e + dORPrime - dSRPrime); - pathParameters.deltaSRPrimeF = toCurve(dSO0, dSRPrime) + toCurve(pathParameters.e, dSRPrime) + toCurve(dORPrime, dSRPrime) - toCurve(dSRPrime, dSRPrime); - - Coordinate srcPrime = new Coordinate(src.x + (seg1.sMeanPlane.x - src.x) * 2, src.y + (seg1.sMeanPlane.y - src.y) * 2); - Coordinate rcvPrime = new Coordinate(rcv.x + (seg2.rMeanPlane.x - rcv.x) * 2, rcv.y + (seg2.rMeanPlane.y - rcv.y) * 2); - - LineSegment dSPrimeRPrime = new LineSegment(srcPrime, rcvPrime); - srPath.dPrime = srcPrime.distance(rcvPrime); - seg1.dPrime = srcPrime.distance(c0); - seg2.dPrime = cn.distance(rcvPrime); - - - long difVPointCount = pathParameters.getPointList().stream(). - filter(pointPath -> pointPath.type.equals(DIFV)).count(); - double distance = difVPointCount == 0 ? pathParameters.getSRSegment().d : pathParameters.getSRSegment().dc; - pathParameters.deltaH = sr.orientationIndex(c0) * (dSO0 + pathParameters.e + dOnR - distance); - if (sr.orientationIndex(c0) == 1) { - pathParameters.deltaF = toCurve(seg1.d, srPath.d) + toCurve(pathParameters.e, srPath.d) + toCurve(seg2.d, srPath.d) - toCurve(srPath.d, srPath.d); - } else { - Coordinate pA = sr.pointAlong((c0.x - srcPrime.x) / (rcvPrime.x - srcPrime.x)); - pathParameters.deltaF = 2 * toCurve(srcPrime.distance(pA), srPath.dPrime) + 2 * toCurve(pA.distance(rcvPrime), srPath.dPrime) - toCurve(seg1.dPrime, srPath.dPrime) - toCurve(seg2.dPrime, srPath.dPrime) - toCurve(srPath.dPrime, srPath.dPrime); - } - - pathParameters.deltaPrimeH = dSPrimeRPrime.orientationIndex(c0) * (seg1.dPrime + pathParameters.e + seg2.dPrime - srPath.dPrime); - - pathParameters.deltaPrimeH = dSPrimeRPrime.orientationIndex(c0) * (seg1.dPrime + seg2.dPrime - srPath.dPrime); - if(dSPrimeRPrime.orientationIndex(c0) == 1) { - pathParameters.deltaPrimeF = toCurve(seg1.dPrime, srPath.dPrime) + toCurve(seg2.dPrime, srPath.dPrime) - toCurve(srPath.dPrime, srPath.dPrime); - } else { - Coordinate pA = dSPrimeRPrime.pointAlong((c0.x-srcPrime.x)/(rcvPrime.x-srcPrime.x)); - pathParameters.deltaPrimeF =2*toCurve(srcPrime.distance(pA), srPath.dPrime) + 2*toCurve(pA.distance(srcPrime), srPath.dPrime) - toCurve(seg1.dPrime, srPath.dPrime) - toCurve(seg2.dPrime, srPath.d) - toCurve(srPath.dPrime, srPath.dPrime); - } - - return pathParameters; - } /** * Compute Side Hull @@ -1177,17 +643,17 @@ private void updateReflectionPointAttributes(CutPoint reflectionPoint, CutProfil * @param srcCoord * @param orientation * @param receiverMirrorIndex - * @return propagation path list + * @return Skip or continue looking for vertical cut */ - public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoord, - Orientation orientation, MirrorReceiversCompute receiverMirrorIndex) { + public IComputePathsOut.PathSearchStrategy computeReflexion(ReceiverPointInfo rcv, + SourcePointInfo src, + MirrorReceiversCompute receiverMirrorIndex, + IComputePathsOut dataOut) { // Compute receiver mirror LineIntersector linters = new RobustLineIntersector(); //Keep only building walls which are not too far. - List mirrorResults = receiverMirrorIndex.findCloseMirrorReceivers(srcCoord); - - List reflexionPathParameters = new ArrayList<>(); + List mirrorResults = receiverMirrorIndex.findCloseMirrorReceivers(src.position); for (MirrorReceiver receiverReflection : mirrorResults) { Wall seg = receiverReflection.getWall(); @@ -1195,7 +661,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo MirrorReceiver receiverReflectionCursor = receiverReflection; // Test whether intersection point is on the wall // segment or not - Coordinate destinationPt = new Coordinate(srcCoord); + Coordinate destinationPt = new Coordinate(src.position); linters.computeIntersection(seg.p0, seg.p1, receiverReflection.getReceiverPos(), @@ -1249,7 +715,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo // A valid propagation path as been found (without looking at occlusion) CutProfile mainProfile = new CutProfile(); // Compute direct path between source and first reflection point, add profile to the data - CutProfile cutProfile = data.profileBuilder.getProfile(srcCoord, rayPath.get(0).getReflectionPosition(), + CutProfile cutProfile = data.profileBuilder.getProfile(src.position, rayPath.get(0).getReflectionPosition(), data.gS, !data.computeVerticalDiffraction); if(!cutProfile.isFreeField() && !data.computeVerticalDiffraction) { // (maybe there is a blocking building/dem, and we disabled diffraction) @@ -1283,7 +749,7 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo } // Compute direct path between receiver and last reflection point, add profile to the data cutProfile = data.profileBuilder.getProfile(rayPath.get(rayPath.size() - 1).getReflectionPosition(), - rcvCoord, data.gS, !data.computeVerticalDiffraction); + rcv.position, data.gS, !data.computeVerticalDiffraction); if(!cutProfile.isFreeField() && !data.computeVerticalDiffraction) { // (maybe there is a blocking building/dem, and we disabled diffraction) continue; @@ -1292,23 +758,22 @@ public List computeReflexion(Coordinate rcvCoord, Coordinate srcCoo // Add points to the main profile, remove the last point, or it will be duplicated later mainProfile.addCutPoints(cutProfile.getCutPoints()); mainProfile.setSource(mainProfile.getCutPoints().get(0)); - mainProfile.setSrcOrientation(orientation); mainProfile.setReceiver(mainProfile.getCutPoints().get(mainProfile.getCutPoints().size() - 1)); assert mainProfile.getSource().getType() == SOURCE; assert mainProfile.getReceiver().getType() == RECEIVER; - // Compute Ray path from vertical cuts (like a folding screen) - CnossosPath cnossosPath = computeHEdgeDiffraction(mainProfile, data.isBodyBarrier()); + mainProfile.getReceiver().primaryKey = data.receiversPk.get(rcv.receiverIndex); + mainProfile.getSource().primaryKey = data.sourcesPk.get(src.sourceIndex); + mainProfile.getSource().orientation = src.orientation; + mainProfile.getSource().li = src.li; - if(cnossosPath == null) { - // path not valid (ex: reflexion over the wall) - continue; + IComputePathsOut.PathSearchStrategy strategy = dataOut.onNewCutPlane(mainProfile); + if(!strategy.equals(IComputePathsOut.PathSearchStrategy.CONTINUE)) { + return strategy; } - - reflexionPathParameters.add(cnossosPath); } - return reflexionPathParameters; + return IComputePathsOut.PathSearchStrategy.CONTINUE; } /** @@ -1489,13 +954,13 @@ public void makeReceiverRelativeZToAbsolute() { * @return */ private static double insertPtSource(Coordinate source, Coordinate receiverPos, Integer sourceId, - List sourceList, double[] wj, double li, Orientation orientation) { + List sourceList, double[] wj, double li, Orientation orientation) { double aDiv = -getADiv(CGAlgorithms3D.distance(receiverPos, source)); double[] srcWJ = new double[wj.length]; for (int idFreq = 0; idFreq < srcWJ.length; idFreq++) { srcWJ[idFreq] = wj[idFreq] * li * dbaToW(aDiv) * dbaToW(3); } - sourceList.add(new PointPath.SourcePointInfo(srcWJ, sourceId, source, li, orientation)); + sourceList.add(new SourcePointInfo(srcWJ, sourceId, source, li, orientation)); return sumArray(srcWJ.length, srcWJ); } @@ -1512,14 +977,14 @@ private static double insertPtSource(Coordinate source, Coordinate receiverPos, * @return */ private static double insertPtSource(Point source, Coordinate receiverPos, Integer sourceId, - List sourceList, double[] wj, double li, Orientation orientation) { + List sourceList, double[] wj, double li, Orientation orientation) { // Compute maximal power at freefield at the receiver position with reflective ground double aDiv = -getADiv(CGAlgorithms3D.distance(receiverPos, source.getCoordinate())); double[] srcWJ = new double[wj.length]; for (int idFreq = 0; idFreq < srcWJ.length; idFreq++) { srcWJ[idFreq] = wj[idFreq] * li * dbaToW(aDiv) * dbaToW(3); } - sourceList.add(new PointPath.SourcePointInfo(srcWJ, sourceId, source.getCoordinate(), li, orientation)); + sourceList.add(new SourcePointInfo(srcWJ, sourceId, source.getCoordinate(), li, orientation)); return sumArray(srcWJ.length, srcWJ); } @@ -1532,7 +997,7 @@ private static double insertPtSource(Point source, Coordinate receiverPos, Integ * @param wj * @return */ - private double addLineSource(LineString source, Coordinate receiverCoord, int srcIndex, List sourceList, double[] wj) { + private double addLineSource(LineString source, Coordinate receiverCoord, int srcIndex, List sourceList, double[] wj) { double totalPowerRemaining = 0; ArrayList pts = new ArrayList<>(); Coordinate nearestPoint = JTSUtility.getNearestPoint(receiverCoord, source); @@ -1570,4 +1035,78 @@ private double addLineSource(LineString source, Coordinate receiverCoord, int sr public enum ComputationSide {LEFT, RIGHT} + /** + * Attribute of the receiver point + */ + public static final class ReceiverPointInfo { + public int receiverIndex; + public Coordinate position; + + public ReceiverPointInfo(int sourcePrimaryKey, Coordinate position) { + this.receiverIndex = sourcePrimaryKey; + this.position = position; + } + + public Coordinate getCoordinates() { + return position; + } + + public int getId() { + return receiverIndex; + } + } + + /** + * Attributes of the source point + */ + public static final class SourcePointInfo implements Comparable { + public final double li; + public int sourceIndex; + Coordinate position; + public final double globalWj; + Orientation orientation; + + /** + * @param wj Maximum received power from this source + * @param sourcePrimaryKey + * @param position + */ + public SourcePointInfo(double[] wj, int sourcePrimaryKey, Coordinate position, double li, Orientation orientation) { + this.sourceIndex = sourcePrimaryKey; + this.position = position; + if (isNaN(position.z)) { + this.position = new Coordinate(position.x, position.y, 0); + } + this.globalWj = sumArray(wj.length, wj); + this.li = li; + this.orientation = orientation; + } + + public Orientation getOrientation() { + return orientation; + } + + public Coordinate getCoord() { + return position; + } + + public int getId() { + return sourceIndex; + } + + /** + * + * @param sourcePointInfo the object to be compared. + * @return 1, 0 or -1 + */ + @Override + public int compareTo(SourcePointInfo sourcePointInfo) { + int cmp = -Double.compare(globalWj, sourcePointInfo.globalWj); + if (cmp == 0) { + return Integer.compare(sourceIndex, sourcePointInfo.sourceIndex); + } else { + return cmp; + } + } + } } diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinderVisitor.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinderVisitor.java index 5c7e720f1..e83178def 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinderVisitor.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/PathFinderVisitor.java @@ -8,44 +8,38 @@ */ package org.noise_planet.noisemodelling.pathfinder; - -import org.h2gis.api.EmptyProgressVisitor; -import org.h2gis.api.ProgressVisitor; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.path.Scene; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.CutProfile; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.Collection; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicLong; /** * Way to store data computed by threads. * Multiple threads use one instance. * This class must be thread safe - * Store only propagation rays + * Store only vertical cut planes * @author Nicolas Fortin * @author Pierre Aumond */ public class PathFinderVisitor implements IComputePathsOut { - public List pathParameters = Collections.synchronizedList(new ArrayList<>()); + /** This list is thread safe so can be used in a multi-thread environment */ + public ConcurrentLinkedDeque cutProfiles = new ConcurrentLinkedDeque<>(); public Scene inputData; - public PathFinderVisitor(boolean keepRays, Scene inputData) { - this.keepRays = keepRays; + public boolean keepCutPlanes = true; + public AtomicLong pathCount = new AtomicLong(); + + public PathFinderVisitor(boolean keepCutPlanes, Scene inputData) { + this.keepCutPlanes = keepCutPlanes; this.inputData = inputData; } - public PathFinderVisitor(boolean keepRays) { - this.keepRays = keepRays; + public PathFinderVisitor(boolean keepCutPlanes) { + this.keepCutPlanes = keepCutPlanes; } - public boolean keepRays = true; - public AtomicLong rayCount = new AtomicLong(); - /** * No more propagation paths will be pushed for this receiver identifier * @param receiverId @@ -60,19 +54,13 @@ public Scene getInputData() { } - /** - * Get propagation path result - * @param sourceId Source identifier - * @param sourceLi Source power per meter coefficient - * @param path Propagation path result - */ @Override - public double[] addPropagationPaths(long sourceId, double sourceLi, long receiverId, List path) { - rayCount.addAndGet(path.size()); - if (keepRays) { - pathParameters.addAll(path); + public PathSearchStrategy onNewCutPlane(CutProfile cutProfile) { + pathCount.addAndGet(1); + if (keepCutPlanes) { + cutProfiles.add(cutProfile); } - return new double[0]; + return PathSearchStrategy.CONTINUE; } /** @@ -81,74 +69,10 @@ public double[] addPropagationPaths(long sourceId, double sourceLi, long receive */ @Override public IComputePathsOut subProcess() { - return new ThreadPathsOut(this); + return this; } - public List getPropagationPaths() { - return pathParameters; + public Collection getCutProfiles() { + return cutProfiles; } - - public static class ThreadPathsOut implements IComputePathsOut { - protected PathFinderVisitor multiThreadParent; - public List pathParameters = new ArrayList<>(); - - public ThreadPathsOut(PathFinderVisitor multiThreadParent) { - this.multiThreadParent = multiThreadParent; - } - - /** - * Get propagation path result - * @param sourceId Source identifier - * @param sourceLi Source power per meter coefficient - * @param path path result - */ - @Override - public double[] addPropagationPaths(long sourceId, double sourceLi, long receiverId, List path) { - multiThreadParent.rayCount.addAndGet(path.size()); - if (multiThreadParent.keepRays) { - if (multiThreadParent.inputData != null && sourceId < multiThreadParent.inputData.sourcesPk.size() && - receiverId < multiThreadParent.inputData.receiversPk.size()) { - for (CnossosPath pathParameter : path) { - pathParameter.setIdReceiver(multiThreadParent.inputData.receiversPk.get((int) receiverId).intValue()); - pathParameter.setIdSource(multiThreadParent.inputData.sourcesPk.get((int) sourceId).intValue()); - pathParameters.add(pathParameter); - } - } else { - pathParameters.addAll(path); - } - } - return new double[0]; - } - - /** - * No more propagation paths will be pushed for this receiver identifier - * @param receiverId - */ - @Override - public void finalizeReceiver(final long receiverId) { - if (multiThreadParent.keepRays && !pathParameters.isEmpty()) { - multiThreadParent.pathParameters.addAll(pathParameters); - pathParameters.clear(); - } - long receiverPK = receiverId; - if (multiThreadParent.inputData != null) { - if (receiverId < multiThreadParent.inputData.receiversPk.size()) { - receiverPK = multiThreadParent.inputData.receiversPk.get((int) receiverId); - } - } - multiThreadParent.finalizeReceiver(receiverId); - - } - - /** - * - * @return an instance of the interface IComputePathsOut - */ - - @Override - public IComputePathsOut subProcess() { - return multiThreadParent.subProcess(); - } -} - } diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ThreadPathFinder.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ThreadPathFinder.java index c837532d5..02b682077 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ThreadPathFinder.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/ThreadPathFinder.java @@ -10,7 +10,6 @@ package org.noise_planet.noisemodelling.pathfinder; import org.h2gis.api.ProgressVisitor; -import org.noise_planet.noisemodelling.pathfinder.path.PointPath; import org.noise_planet.noisemodelling.pathfinder.path.Scene; import org.noise_planet.noisemodelling.pathfinder.utils.profiler.ReceiverStatsMetric; @@ -63,7 +62,7 @@ public Boolean call() throws Exception { break; } } - PointPath.ReceiverPointInfo rcv = new PointPath.ReceiverPointInfo(idReceiver, data.receivers.get(idReceiver)); + PathFinder.ReceiverPointInfo rcv = new PathFinder.ReceiverPointInfo(idReceiver, data.receivers.get(idReceiver)); long start = 0; if(propagationProcess.getProfilerThread() != null) { diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/MirrorReceiver.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/MirrorReceiver.java index 7859059c1..62f657f8b 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/MirrorReceiver.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/MirrorReceiver.java @@ -23,10 +23,10 @@ public class MirrorReceiver { - private Coordinate receiverPos; - private Coordinate reflectionPosition = new Coordinate(Coordinate.NULL_ORDINATE, Coordinate.NULL_ORDINATE, Coordinate.NULL_ORDINATE); - private final MirrorReceiver parentMirror; - private final Wall wall; + public Coordinate receiverPos; + public Coordinate reflectionPosition = new Coordinate(Coordinate.NULL_ORDINATE, Coordinate.NULL_ORDINATE, Coordinate.NULL_ORDINATE); + public final MirrorReceiver parentMirror; + public final Wall wall; /** * This data is not stored in the RTREE as it is not used after the creation of the index */ diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutPoint.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutPoint.java index ea3feebb1..bd82e86e5 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutPoint.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/CutPoint.java @@ -11,6 +11,7 @@ import org.locationtech.jts.geom.Coordinate; import org.noise_planet.noisemodelling.pathfinder.path.MirrorReceiver; +import org.noise_planet.noisemodelling.pathfinder.utils.geometry.Orientation; import java.util.ArrayList; import java.util.Collections; @@ -19,24 +20,35 @@ public class CutPoint implements Comparable { /** {@link Coordinate} of the cut point. */ - Coordinate coordinate = new Coordinate(); + public Coordinate coordinate = new Coordinate(); /** Intersection type. */ - ProfileBuilder.IntersectionType type; + public ProfileBuilder.IntersectionType type; /** Identifier of the cut element. */ - int id = -1; + public int id = -1; /** Identifier of the building containing the point. -1 if no building. */ - int buildingId = -1; + public int buildingId = -1; /** Identifier of the wall containing the point. -1 if no wall. */ - int wallId = -1; + public int wallId = -1; /** Topographic height of the point. */ - double zGround = Double.NaN; + public double zGround = Double.NaN; /** Ground effect coefficient. 0 if there is no coefficient. */ - double groundCoef = Double.NaN; + public double groundCoef = Double.NaN; /** Wall alpha. NaN if there is no coefficient. */ - List wallAlpha = Collections.emptyList(); + public List wallAlpha = Collections.emptyList(); + /** Source line subdivision length (1.0 means a point is representing 1 meter of line sound source) */ + public double li = 1.0; + /** + * Index of the object that reference the external data (not a temporary index in a subdomain) + */ + public long primaryKey; + /** + * Orientation of the point (should be about the source or receiver point) + * The orientation is related to the directivity associated to the object + */ + public Orientation orientation = new Orientation(); /** On reflection intersection type this object contain the associated reflection data */ - private MirrorReceiver mirrorReceiver; + public MirrorReceiver mirrorReceiver = null; /** * Constructor using a {@link Coordinate}. @@ -48,6 +60,7 @@ public CutPoint(Coordinate coord, ProfileBuilder.IntersectionType type, int id) this.coordinate = new Coordinate(coord); this.type = type; this.id = id; + this.primaryKey = id; } public CutPoint() { @@ -208,6 +221,9 @@ public String toString() { ", zGround=" + zGround + ", groundCoef=" + groundCoef + ", wallAlpha=" + wallAlpha + + ", li=" + li + + ", primaryKey=" + primaryKey + + ", orientation=" + orientation + (mirrorReceiver == null ? "" : ", mirrorReceiver=" + mirrorReceiver) + '}'; } 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 04cd544be..b721d4964 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 @@ -18,10 +18,8 @@ import java.util.Collections; import java.util.List; -//import static org.noise_planet.noisemodelling.pathfinder.utils.geometry.JTSUtility.dist2D; import static org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder.IntersectionType.*; - public class CutProfile { /** List of cut points. */ ArrayList pts = new ArrayList<>(); @@ -33,7 +31,6 @@ public class CutProfile { Boolean hasBuildingIntersection = false; /** True if Source-Receiver linestring is below topography cutting point. */ Boolean hasTopographyIntersection = false; - Orientation srcOrientation; /** * Add the source point. @@ -189,14 +186,6 @@ public void reverse() { Collections.reverse(pts); } - public void setSrcOrientation(Orientation srcOrientation){ - this.srcOrientation = srcOrientation; - } - - public Orientation getSrcOrientation(){ - return srcOrientation; - } - public boolean intersectBuilding(){ return hasBuildingIntersection; } @@ -252,7 +241,6 @@ public String toString() { ", receiver=" + receiver + ", hasBuildingIntersection=" + hasBuildingIntersection + ", hasTopographyIntersection=" + hasTopographyIntersection + - ", srcOrientation=" + srcOrientation + '}'; } 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 736dcd3a1..bb01228e0 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 @@ -20,7 +20,6 @@ import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; -import org.locationtech.jts.index.ItemVisitor; import org.locationtech.jts.index.strtree.STRtree; import org.locationtech.jts.math.Vector2D; import org.locationtech.jts.math.Vector3D; @@ -30,7 +29,6 @@ import org.noise_planet.noisemodelling.pathfinder.delaunay.LayerDelaunayError; import org.noise_planet.noisemodelling.pathfinder.delaunay.LayerTinfour; import org.noise_planet.noisemodelling.pathfinder.delaunay.Triangle; -import org.noise_planet.noisemodelling.pathfinder.path.PointPath; import org.noise_planet.noisemodelling.pathfinder.path.Scene; import org.noise_planet.noisemodelling.pathfinder.utils.IntegerTuple; import org.noise_planet.noisemodelling.pathfinder.utils.geometry.JTSUtility; @@ -1455,20 +1453,7 @@ public double getZGround(Coordinate coordinate, AtomicInteger triangleHint) { /** * Different type of intersection. */ - public enum IntersectionType {BUILDING, WALL, TOPOGRAPHY, GROUND_EFFECT, SOURCE, RECEIVER, REFLECTION, V_EDGE_DIFFRACTION; - - public PointPath.POINT_TYPE toPointType(PointPath.POINT_TYPE dflt) { - if(this.equals(SOURCE)){ - return PointPath.POINT_TYPE.SRCE; - } - else if(this.equals(RECEIVER)){ - return PointPath.POINT_TYPE.RECV; - } - else { - return dflt; - } - } - } + public enum IntersectionType {BUILDING, WALL, TOPOGRAPHY, GROUND_EFFECT, SOURCE, RECEIVER, REFLECTION, V_EDGE_DIFFRACTION} /** * Cutting profile containing all th cut points with there x,y,z position. diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/Wall.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/Wall.java index 91a46ca2d..a3c10cda1 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/Wall.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/profilebuilder/Wall.java @@ -14,17 +14,17 @@ public class Wall { /** Type of the wall */ - final ProfileBuilder.IntersectionType type; + public final ProfileBuilder.IntersectionType type; /** Id or index of the source building or topographic triangle. */ - final int originId; + public final int originId; /** Wall alpha value. */ - List alphas; + public List alphas; /** Wall height, if -1, use z coordinate. */ - double height; + public double height; public Coordinate p0; public Coordinate p1; - LineSegment ls; - int processedWallIndex; + public LineSegment ls; + public int processedWallIndex; /** * Constructor using segment and id. diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/utils/documents/KMLDocument.java b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/utils/documents/KMLDocument.java index e14bbff1f..643871a62 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/utils/documents/KMLDocument.java +++ b/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/utils/documents/KMLDocument.java @@ -27,10 +27,8 @@ import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.Polygon; import org.locationtech.jts.io.kml.KMLWriter; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.delaunay.Triangle; import org.noise_planet.noisemodelling.pathfinder.profilebuilder.*; -import org.noise_planet.noisemodelling.pathfinder.utils.AcousticIndicatorsFunctions; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; @@ -40,7 +38,6 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -380,85 +377,6 @@ private String formatColorEntry(double key) { return String.format(Locale.ROOT, "scale%g", key); } - - /** - * - * @param rays - * @return - * @throws XMLStreamException - */ - public KMLDocument writeRays(Collection rays) throws XMLStreamException { - double minDb = Double.MAX_VALUE; - double maxDb = -Double.MAX_VALUE; - for(CnossosPath line : rays) { - if(line.aGlobal != null && line.aGlobal.length > 0) { - double attenuationLevel = AcousticIndicatorsFunctions.sumDbArray(line.aGlobal); - minDb = Math.min(minDb, attenuationLevel); - maxDb = Math.max(maxDb, attenuationLevel); - } - } - for (Map.Entry colorEntry : colorScale.entrySet()) { - xmlOut.writeStartElement("Style"); - xmlOut.writeAttribute("id", formatColorEntry(colorEntry.getKey())); - xmlOut.writeStartElement("LineStyle"); - xmlOut.writeStartElement("color"); - Color color = colorEntry.getValue(); - xmlOut.writeCharacters(String.format("#FF%02x%02x%02x", color.getBlue(), color.getGreen(), color.getRed())); - xmlOut.writeEndElement(); // /color - xmlOut.writeEndElement(); // /LineStyle - xmlOut.writeEndElement(); // / Style - } - - xmlOut.writeStartElement("Schema"); - xmlOut.writeAttribute("name", "rays"); - xmlOut.writeAttribute("id", "rays"); - xmlOut.writeEndElement();//Write schema - xmlOut.writeStartElement("Folder"); - xmlOut.writeStartElement("name"); - xmlOut.writeCharacters("rays"); - xmlOut.writeEndElement();//Name - for(CnossosPath line : rays) { - double attenuationLevel = 0; - xmlOut.writeStartElement("Placemark"); - xmlOut.writeStartElement("name"); - boolean hasGroundElevation = false; - for(CutPoint cutPoint : line.getCutPoints()) { - if(!Double.isNaN(cutPoint.getzGround())) { - hasGroundElevation = true; - break; - } - } - if(line.aGlobal != null && line.aGlobal.length > 0) { - attenuationLevel = AcousticIndicatorsFunctions.sumDbArray(line.aGlobal); - xmlOut.writeCharacters(String.format("%.1f dB R:%d S:%d", - attenuationLevel,line.getIdReceiver(), line.getIdSource())); - } else { - xmlOut.writeCharacters(String.format("R:%d S:%d", line.getIdReceiver(), line.getIdSource())); - } - xmlOut.writeEndElement();//Name - if(line.aGlobal != null && line.aGlobal.length > 0) { - Map.Entry colorEntry = - colorScale.floorEntry((attenuationLevel - minDb) / (maxDb - minDb)); - if(colorEntry == null) { - colorEntry = colorScale.firstEntry(); - } - xmlOut.writeStartElement("styleUrl"); - xmlOut.writeCharacters("#" + formatColorEntry(colorEntry.getKey())); - xmlOut.writeEndElement(); //styleurl - } - LineString lineString = (LineString) line.asGeom().copy(); - // Apply CRS transform - doTransform(lineString); - //Write geometry - writeRawXml(KMLWriter.writeGeometry(lineString, Double.NaN, - wgs84Precision, false, - hasGroundElevation ? KMLWriter.ALTITUDE_MODE_ABSOLUTE : KMLWriter.ALTITUDE_MODE_RELATIVETOGROUND)); - xmlOut.writeEndElement();//Write Placemark - } - xmlOut.writeEndElement();//Folder - return this; - } - /** * * @param geometry 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 50860a10a..eff36609c 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 @@ -14,11 +14,7 @@ import org.junit.jupiter.api.Test; import org.locationtech.jts.algorithm.CGAlgorithms3D; import org.locationtech.jts.geom.*; -import org.locationtech.jts.math.Plane3D; -import org.locationtech.jts.math.Vector2D; import org.locationtech.jts.math.Vector3D; -import org.locationtech.jts.operation.distance.DistanceOp; -import org.locationtech.jts.operation.distance3d.PlanarPolygon3D; import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.path.Scene; import org.noise_planet.noisemodelling.pathfinder.path.PointPath; @@ -32,7 +28,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.*; -import java.util.stream.Collectors; import static java.lang.Double.NaN; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -86,7 +81,7 @@ public void TC01() { }; //Assertion - assertPaths(pts, gPaths, propDataOut.getPropagationPaths()); + assertPaths(pts, gPaths, propDataOut.getCutPlanes()); } /** @@ -121,7 +116,7 @@ public void TC02() { }; //Assertion - assertPaths(pts, gPaths, propDataOut.getPropagationPaths()); + assertPaths(pts, gPaths, propDataOut.getCutPlanes()); } /** @@ -156,7 +151,7 @@ public void TC03() { }; //Assertion - assertPaths(pts, gPaths, propDataOut.getPropagationPaths()); + assertPaths(pts, gPaths, propDataOut.getCutPlanes()); } /** @@ -198,7 +193,7 @@ public void TC04() { }; //Assertion - assertPaths(pts, gPaths, propDataOut.getPropagationPaths()); + assertPaths(pts, gPaths, propDataOut.getCutPlanes()); } @@ -317,9 +312,9 @@ public void TC05() { }; //Assertion - assertPaths(pts, gPaths, propDataOut.getPropagationPaths()); // table17 - assertPlanes(meanPlanes, propDataOut.getPropagationPaths().get(0).getSRSegment()); // table 18 - assertPlanes(meanPlanes, propDataOut.getPropagationPaths().get(0).getSegmentList()); // table 18 + assertPaths(pts, gPaths, propDataOut.getCutPlanes()); // table17 + assertPlanes(meanPlanes, propDataOut.getCutPlanes().get(0).getSRSegment()); // table 18 + assertPlanes(meanPlanes, propDataOut.getCutPlanes().get(0).getSegmentList()); // table 18 } /** @@ -348,15 +343,15 @@ public void TC06() { //Run computation computeRays.run(propDataOut); - assertEquals(1, propDataOut.getPropagationPaths().size()); - assertEquals(2, propDataOut.getPropagationPaths().get(0).getSegmentList().size()); + assertEquals(1, propDataOut.getCutPlanes().size()); + assertEquals(2, propDataOut.getCutPlanes().get(0).getSegmentList().size()); // Test R-CRIT table 27 - Coordinate D = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).r; - Coordinate Sp = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime; - Coordinate Rp = propDataOut.getPropagationPaths().get(0).getSegmentList().get(1).rPrime ; + Coordinate D = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).r; + Coordinate Sp = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime; + Coordinate Rp = propDataOut.getCutPlanes().get(0).getSegmentList().get(1).rPrime ; - double deltaD = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).d + propDataOut.getPropagationPaths().get(0).getSegmentList().get(1).d - propDataOut.getPropagationPaths().get(0).getSRSegment().d; + double deltaD = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).d + propDataOut.getCutPlanes().get(0).getSegmentList().get(1).d - propDataOut.getCutPlanes().get(0).getSRSegment().d; double deltaDE = Sp.distance(D) + D.distance(Rp) - Sp.distance(Rp); List res1 = new ArrayList<>(3) ; List res2 = new ArrayList<>(3); @@ -387,7 +382,7 @@ public void TC06() { Coordinate expectedRPrime =new Coordinate(194.16,8.5); if(!profileBuilder.getWalls().isEmpty()){ - assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getPropagationPaths().get(0).getSRSegment().sPrime,propDataOut.getPropagationPaths().get(0).getSRSegment().rPrime); + assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getCutPlanes().get(0).getSRSegment().sPrime,propDataOut.getCutPlanes().get(0).getSRSegment().rPrime); } @@ -403,9 +398,9 @@ public void TC06() { }; //Assertion - assertZProfil(expectedZProfile, propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround()); - assertPlanes(srMeanPlanes, propDataOut.getPropagationPaths().get(0).getSRSegment()); - assertPlanes(segmentsMeanPlanes, propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertZProfil(expectedZProfile, propDataOut.getCutPlanes().get(0).getCutProfile().computePts2DGround()); + assertPlanes(srMeanPlanes, propDataOut.getCutPlanes().get(0).getSRSegment()); + assertPlanes(segmentsMeanPlanes, propDataOut.getCutPlanes().get(0).getSegmentList()); } /** @@ -466,7 +461,7 @@ public void TC07() { Coordinate expectedSPrime =new Coordinate(0.00,-1.00); Coordinate expectedRPrime =new Coordinate(194.16,-4.00); if(!profileBuilder.getWalls().isEmpty()){ - assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(propDataOut.getPropagationPaths().get(0).getSegmentList().size()-1).rPrime); + assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(propDataOut.getCutPlanes().get(0).getSegmentList().size()-1).rPrime); } @@ -484,7 +479,7 @@ public void TC07() { //Assertion assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes, propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes, propDataOut.getCutPlanes().get(0).getSegmentList()); try { exportScene("target/T07.kml", profileBuilder, propDataOut); } catch (IOException e) { @@ -547,11 +542,11 @@ public void TC08() { Coordinate expectedSPrime =new Coordinate(0.00,-1.00); Coordinate expectedRPrime =new Coordinate(194.16,-4.00); - assertEquals(3, propDataOut.getPropagationPaths().size()); + assertEquals(3, propDataOut.getCutPlanes().size()); if(!profileBuilder.getWalls().isEmpty()){ - assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(propDataOut.getPropagationPaths().get(0).getSegmentList().size()-1).rPrime); + assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(propDataOut.getCutPlanes().get(0).getSegmentList().size()-1).rPrime); } /* Table 43 */ @@ -571,10 +566,10 @@ public void TC08() { //Assertion - assertZProfil(expectedZProfile, propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround()); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertZProfil(expectedZProfile, propDataOut.getCutPlanes().get(0).getCutProfile().computePts2DGround()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); try { exportScene("target/T08.kml", profileBuilder, propDataOut); } catch (IOException e) { @@ -636,7 +631,7 @@ public void TC09() { Coordinate expectedSPrime =new Coordinate(0.24,-4.92); Coordinate expectedRPrime =new Coordinate(194.48,6.59); if(!profileBuilder.getWalls().isEmpty()){ - assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(propDataOut.getPropagationPaths().get(0).getSegmentList().size()-1).rPrime); + assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(propDataOut.getCutPlanes().get(0).getSegmentList().size()-1).rPrime); } /* Table 60 */ @@ -656,9 +651,9 @@ public void TC09() { //Assertion assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); try { exportScene("target/T09.kml", profileBuilder, propDataOut); } catch (IOException e) { @@ -737,9 +732,9 @@ public void TC10() { //Assertion assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); try { exportScene("target/T10.kml", profileBuilder, propDataOut); } catch (IOException e) { @@ -832,14 +827,14 @@ public void TC11() { }; //Assertion - assertZProfil(expectedZProfile, propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround()); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertZProfil(expectedZProfile, propDataOut.getCutPlanes().get(0).getCutProfile().computePts2DGround()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); - assertZProfil(expectedZProfileRight, propDataOut.getPropagationPaths().get(1).getCutProfile().computePts2DGround()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); + assertZProfil(expectedZProfileRight, propDataOut.getCutPlanes().get(1).getCutProfile().computePts2DGround()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); - assertZProfil(expectedZProfileLeft, propDataOut.getPropagationPaths().get(2).getCutProfile().computePts2DGround()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertZProfil(expectedZProfileLeft, propDataOut.getCutPlanes().get(2).getCutProfile().computePts2DGround()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); } /** @@ -918,22 +913,22 @@ public void TC12() { }; //Assertion - assertEquals(3, propDataOut.getPropagationPaths().size()); + assertEquals(3, propDataOut.getCutPlanes().size()); - CnossosPath directPath = propDataOut.getPropagationPaths().get(0); + CnossosPath directPath = propDataOut.getCutPlanes().get(0); assertZProfil(expectedZProfile, Arrays.asList(directPath.getSRSegment().getPoints2DGround())); assertZProfil(expectedZProfileSO, Arrays.asList(directPath.getSegmentList().get(0).getPoints2DGround())); assertZProfil(expectedZProfileOnR, Arrays.asList(directPath.getSegmentList(). get(directPath.getSegmentList().size() - 1).getPoints2DGround())); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); - assertEquals(3, propDataOut.getPropagationPaths().get(0).getSegmentList().size()); - Coordinate sPrime = propDataOut.pathParameters.get(0).getSegmentList().get(0).sPrime; - Coordinate rPrime = propDataOut.pathParameters.get(0).getSegmentList().get(2).rPrime; + assertEquals(3, propDataOut.getCutPlanes().get(0).getSegmentList().size()); + Coordinate sPrime = propDataOut.cutProfiles.get(0).getSegmentList().get(0).sPrime; + Coordinate rPrime = propDataOut.cutProfiles.get(0).getSegmentList().get(2).rPrime; assertCoordinateEquals("TC12 Table 102 S' S->O", new Coordinate(0, -1), sPrime, DELTA_COORDS); assertCoordinateEquals("TC12 Table 102 R' O->R", new Coordinate(31.62, -6), rPrime, DELTA_COORDS); @@ -1012,9 +1007,9 @@ public void TC13() { //Assertion assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); } /** @@ -1090,9 +1085,9 @@ public void TC14() { //Assertion // Wrong value of z1 in Cnossos document for the 3 paths assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); } /** @@ -1183,8 +1178,8 @@ public void TC15() { //Assertion assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes2, propDataOut.getPropagationPaths().get(2).getSRSegment()); // left + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes2, propDataOut.getCutPlanes().get(2).getSRSegment()); // left //assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); // right : error in value of b cnossos //exportRays("target/T06.geojson", propDataOut); @@ -1250,7 +1245,7 @@ public void TC16() { Coordinate expectedSPrime =new Coordinate(0.42,-6.64); Coordinate expectedRPrime =new Coordinate(194.84,1.70); if(!profileBuilder.getWalls().isEmpty()){ - assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getPropagationPaths().get(0).getSRSegment().sPrime,propDataOut.getPropagationPaths().get(0).getSRSegment().rPrime); + assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getCutPlanes().get(0).getSRSegment().sPrime,propDataOut.getCutPlanes().get(0).getSRSegment().rPrime); } /* Table 165 */ @@ -1268,15 +1263,15 @@ public void TC16() { //Assertion // Check SR direct line - List result = propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround(); + List result = propDataOut.getCutPlanes().get(0).getCutProfile().computePts2DGround(); assertZProfil(expectedZProfile,result); - assertEquals(2, propDataOut.getPropagationPaths().size()); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSRSegment()); + assertEquals(2, propDataOut.getCutPlanes().size()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSRSegment()); // Check reflection path - result = propDataOut.getPropagationPaths().get(1).getCutProfile().computePts2DGround(); + result = propDataOut.getCutPlanes().get(1).getCutProfile().computePts2DGround(); assertZProfil(expectedZProfileReflection, result); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); try { exportScene("target/T16.kml", profileBuilder, propDataOut); @@ -1339,11 +1334,11 @@ public void TC17() { assertZProfil(expectedZProfile,result); // Test R-CRIT table 179 - Coordinate D = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).r; - Coordinate Sp = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime; - Coordinate Rp = propDataOut.getPropagationPaths().get(0).getSegmentList().get(1).rPrime ; + Coordinate D = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).r; + Coordinate Sp = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime; + Coordinate Rp = propDataOut.getCutPlanes().get(0).getSegmentList().get(1).rPrime ; - double deltaD = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).d + propDataOut.getPropagationPaths().get(0).getSegmentList().get(1).d - propDataOut.getPropagationPaths().get(0).getSRSegment().d; + double deltaD = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).d + propDataOut.getCutPlanes().get(0).getSegmentList().get(1).d - propDataOut.getCutPlanes().get(0).getSRSegment().d; double deltaDE = Sp.distance(D) + D.distance(Rp) - Sp.distance(Rp); List res1 = new ArrayList<>(3) ; List res2 = new ArrayList<>(3); @@ -1419,7 +1414,7 @@ public void TC18() { //Run computation computeRays.run(propDataOut); - assertEquals(2, propDataOut.getPropagationPaths().size()); + assertEquals(2, propDataOut.getCutPlanes().size()); // Expected Values @@ -1430,7 +1425,7 @@ public void TC18() { expectedZProfile.add(new Coordinate(178.84, 10)); expectedZProfile.add(new Coordinate(194.16, 10)); - CutProfile cutProfile = propDataOut.getPropagationPaths().get(0).getCutProfile(); + CutProfile cutProfile = propDataOut.getCutPlanes().get(0).getCutProfile(); List result = cutProfile.computePts2DGround(); assertZProfil(expectedZProfile, result); @@ -1452,9 +1447,9 @@ public void TC18() { // S-R (not the rayleigh segments SO OR) - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSRSegment()); - CnossosPath reflectionPath = propDataOut.getPropagationPaths().get(1); + CnossosPath reflectionPath = propDataOut.getCutPlanes().get(1); // Check reflexion mean planes assertPlanes(segmentsMeanPlanes1, reflectionPath.getSegmentList()); @@ -1508,7 +1503,7 @@ public void TC18Altered() { //Run computation computeRays.run(propDataOut); - assertEquals(1, propDataOut.getPropagationPaths().size()); + assertEquals(1, propDataOut.getCutPlanes().size()); // Expected Values @@ -1519,7 +1514,7 @@ public void TC18Altered() { expectedZProfile.add(new Coordinate(178.84, 10)); expectedZProfile.add(new Coordinate(194.16, 10)); - CutProfile cutProfile = propDataOut.getPropagationPaths().get(0).getCutProfile(); + CutProfile cutProfile = propDataOut.getCutPlanes().get(0).getCutProfile(); List result = cutProfile.computePts2DGround(); assertZProfil(expectedZProfile, result); @@ -1534,7 +1529,7 @@ public void TC18Altered() { // S-R (not the rayleigh segments SO OR) - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSRSegment()); } /** @@ -1667,18 +1662,18 @@ public void TC19() { {0.06, -2.01, 3.00, 5.00, 192.81, 0.46, 0.55} }; - assertEquals(3, propDataOut.getPropagationPaths().size()); + assertEquals(3, propDataOut.getCutPlanes().size()); //Assertion - assertZProfil(expectedZProfile, propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround()); - assertZProfil(expectedZProfileRight, propDataOut.getPropagationPaths().get(1).getCutProfile().computePts2DGround()); + assertZProfil(expectedZProfile, propDataOut.getCutPlanes().get(0).getCutProfile().computePts2DGround()); + assertZProfil(expectedZProfileRight, propDataOut.getCutPlanes().get(1).getCutProfile().computePts2DGround()); // Error in ISO // The iso is making the ray do a diffraction on the horizontal edge of the building then a diffraction on // the last wall. The hull is ignoring the 12 meters building on the left side. // assertZProfil(expectedZProfileLeft, propDataOut.getPropagationPaths().get(2).getCutProfile().computePts2DGround()); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); - assertPlanes(segmentsMeanPlanes1, propDataOut.getPropagationPaths().get(1).getSRSegment()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes1, propDataOut.getCutPlanes().get(1).getSRSegment()); // Error in ISO // The iso is making the ray do a diffraction on the horizontal edge of the building then a diffraction on @@ -1737,7 +1732,7 @@ public void TC20() { //Assertion assertZProfil(expectedZProfile,result); - assertPlanes(segmentsMeanPlanes0, propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes0, propDataOut.getCutPlanes().get(0).getSegmentList()); } /** @@ -1795,14 +1790,14 @@ public void TC21() { //Run computation computeRays.run(propDataOut); - assertEquals(3, propDataOut.getPropagationPaths().size()); + assertEquals(3, propDataOut.getCutPlanes().size()); // Test R-CRIT table 235 - Coordinate D = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).r; - Coordinate Sp = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime; - Coordinate Rp = propDataOut.getPropagationPaths().get(0).getSegmentList().get(1).rPrime ; + Coordinate D = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).r; + Coordinate Sp = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime; + Coordinate Rp = propDataOut.getCutPlanes().get(0).getSegmentList().get(1).rPrime ; - double deltaD = propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).d + D.distance(propDataOut.getPropagationPaths().get(0).getPointList().get(2).coordinate) - propDataOut.getPropagationPaths().get(0).getSRSegment().d; + double deltaD = propDataOut.getCutPlanes().get(0).getSegmentList().get(0).d + D.distance(propDataOut.getCutPlanes().get(0).getPointList().get(2).coordinate) - propDataOut.getCutPlanes().get(0).getSRSegment().d; double deltaDE = Sp.distance(D) + D.distance(Rp) - Sp.distance(Rp); List res1 = new ArrayList<>(3) ; List res2 = new ArrayList<>(3); @@ -1876,7 +1871,7 @@ public void TC21() { //Assertion Direct - CnossosPath directPath = propDataOut.getPropagationPaths().get(0); + CnossosPath directPath = propDataOut.getCutPlanes().get(0); assertZProfil(expectedZProfileSR, Arrays.asList(directPath.getSRSegment().getPoints2DGround()), 0.01); assertZProfil(expectedZProfileSO, Arrays.asList(directPath.getSegmentList().get(0).getPoints2DGround()), 0.01); @@ -1887,11 +1882,11 @@ public void TC21() { assertPlanes(segmentsMeanPlanes0,directPath.getSegmentList()); //Assertion Right - CnossosPath rightPath = propDataOut.getPropagationPaths().get(1); + CnossosPath rightPath = propDataOut.getCutPlanes().get(1); assertZProfil(expectedZProfileRight, Arrays.asList(rightPath.getSRSegment().getPoints2DGround()), 0.01); //Assertion Left - CnossosPath leftPath = propDataOut.getPropagationPaths().get(2); + CnossosPath leftPath = propDataOut.getCutPlanes().get(2); assertZProfil(expectedZProfileLeft, Arrays.asList(leftPath.getSRSegment().getPoints2DGround()), 0.01); } @@ -2002,9 +1997,9 @@ public void TC22(){ }; // Must have direct path + diffraction left + diffraction right - assertEquals(3, propDataOut.getPropagationPaths().size()); + assertEquals(3, propDataOut.getCutPlanes().size()); - CnossosPath directPropagationPath = propDataOut.getPropagationPaths().get(0); + CnossosPath directPropagationPath = propDataOut.getCutPlanes().get(0); SegmentPath SRSegment = directPropagationPath.getSRSegment(); // Asserts @@ -2023,12 +2018,12 @@ public void TC22(){ assertPlanes(segmentsMeanPlanes0, directPropagationPath.getSegmentList()); // Check diffraction on horizontal plane - CnossosPath rightPropagationPath = propDataOut.getPropagationPaths().get(1); + CnossosPath rightPropagationPath = propDataOut.getCutPlanes().get(1); assertZProfil(expectedZProfileRight, Arrays.asList(rightPropagationPath.getSRSegment().getPoints2DGround())); assertPlanes(SRRightMeanPlanes0, rightPropagationPath.getSRSegment()); - CnossosPath leftPropagationPath = propDataOut.getPropagationPaths().get(2); + CnossosPath leftPropagationPath = propDataOut.getCutPlanes().get(2); assertZProfil(expectedZProfileLeft, Arrays.asList(leftPropagationPath.getSRSegment().getPoints2DGround())); assertPlanes(SRLeftMeanPlanes0, leftPropagationPath.getSRSegment()); @@ -2093,7 +2088,7 @@ public void TC23() { //Run computation computeRays.run(propDataOut); - assertEquals(1, propDataOut.getPropagationPaths().size()); + assertEquals(1, propDataOut.getCutPlanes().size()); CutProfile cutProfile = computeRays.getData().profileBuilder.getProfile(rayData.sourceGeometries.get(0).getCoordinate(), rayData.receivers.get(0), computeRays.getData().gS, false); List result = cutProfile.computePts2DGround(); @@ -2121,7 +2116,7 @@ public void TC23() { } catch (IOException e) { throw new RuntimeException(e); } - assertPlanes(segmentsMeanPlanes0,propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes0,propDataOut.getCutPlanes().get(0).getSegmentList()); assertZProfil(expectedZProfile,result); @@ -2188,7 +2183,7 @@ public void TC24() { //Run computation computeRays.run(propDataOut); - assertEquals(2, propDataOut.getPropagationPaths().size()); + assertEquals(2, propDataOut.getCutPlanes().size()); // Expected Values @@ -2219,7 +2214,7 @@ public void TC24() { expectedZProfileOR.add(new Coordinate(43.53, 0.0)); expectedZProfileOR.add(new Coordinate(70.74, 0.0)); - List result = propDataOut.getPropagationPaths().get(0).getCutProfile().computePts2DGround(); + List result = propDataOut.getCutPlanes().get(0).getCutProfile().computePts2DGround(); assertZProfil(expectedZProfile,result); /* Table 280 */ @@ -2228,7 +2223,7 @@ public void TC24() { {0.18, -1.17, 2.13, 1.94, 23.37, 0.37, 0.07}, {0.0, 0.0, 6.0, 4.0, 7.57, 0.00, NaN} }; - assertPlanes(segmentsMeanPlanes0,propDataOut.getPropagationPaths().get(0).getSegmentList()); + assertPlanes(segmentsMeanPlanes0,propDataOut.getCutPlanes().get(0).getSegmentList()); @@ -2280,7 +2275,7 @@ public void TC25(){ computeRays.run(propDataOut); // Should find Direct,Left/Right diffraction and one reflection - assertEquals(4, propDataOut.getPropagationPaths().size()); + assertEquals(4, propDataOut.getCutPlanes().size()); // Expected Values @@ -2322,7 +2317,7 @@ public void TC25(){ Coordinate expectedRPrime =new Coordinate(68.15,-4.0); if(!builder.getWalls().isEmpty()){ - assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(0).sPrime,propDataOut.getPropagationPaths().get(0).getSegmentList().get(propDataOut.getPropagationPaths().get(0).getSegmentList().size()-1).rPrime); + assertMirrorPoint(expectedSPrime,expectedRPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(0).sPrime,propDataOut.getCutPlanes().get(0).getSegmentList().get(propDataOut.getCutPlanes().get(0).getSegmentList().size()-1).rPrime); } /* Table 303 */ @@ -2339,22 +2334,22 @@ public void TC25(){ {0.0, 0.0, 5.0, 4.0, 47.49, 0.0, NaN} }; - CnossosPath directPath = propDataOut.getPropagationPaths().get(0); + CnossosPath directPath = propDataOut.getCutPlanes().get(0); assertZProfil(expectedZProfile, Arrays.asList(directPath.getSRSegment().getPoints2DGround())); assertZProfil(expectedZProfileSO, Arrays.asList(directPath.getSegmentList().get(0).getPoints2DGround())); assertZProfil(expectedZProfileONR, Arrays.asList(directPath.getSegmentList().get( directPath.getSegmentList().size() - 1).getPoints2DGround())); assertPlanes(segmentsMeanPlanes0, directPath.getSegmentList()); - CnossosPath rightPath = propDataOut.getPropagationPaths().get(1); + CnossosPath rightPath = propDataOut.getCutPlanes().get(1); assertZProfil(expectedZProfileRight, Arrays.asList(rightPath.getSRSegment().getPoints2DGround())); - CnossosPath leftPath = propDataOut.getPropagationPaths().get(2); + CnossosPath leftPath = propDataOut.getCutPlanes().get(2); assertZProfil(expectedZProfileLeft, Arrays.asList(leftPath.getSRSegment().getPoints2DGround())); - CnossosPath reflectionPath = propDataOut.getPropagationPaths().get(3); + CnossosPath reflectionPath = propDataOut.getCutPlanes().get(3); assertPlanes(segmentsMeanPlanesReflection, reflectionPath.getSegmentList()); } @@ -2444,14 +2439,14 @@ public void TC27(){ computeRays.run(propDataOut); - assertEquals(2, propDataOut.getPropagationPaths().size()); + assertEquals(2, propDataOut.getCutPlanes().size()); // Test R-CRIT table 338 reflexion: Error: no data for "Rayleigh-Criterion" (favourable) we just have (homogeneous) data - Coordinate D = propDataOut.getPropagationPaths().get(1).getSegmentList().get(1).r; - Coordinate Sp = propDataOut.getPropagationPaths().get(1).getSegmentList().get(0).sPrime; - Coordinate Rp = propDataOut.getPropagationPaths().get(1).getSRSegment().rPrime ; + Coordinate D = propDataOut.getCutPlanes().get(1).getSegmentList().get(1).r; + Coordinate Sp = propDataOut.getCutPlanes().get(1).getSegmentList().get(0).sPrime; + Coordinate Rp = propDataOut.getCutPlanes().get(1).getSRSegment().rPrime ; - double deltaD = propDataOut.getPropagationPaths().get(1).getSegmentList().get(0).s.distance(D) + D.distance(propDataOut.getPropagationPaths().get(1).getPointList().get(3).coordinate) - propDataOut.getPropagationPaths().get(1).getSRSegment().d; + double deltaD = propDataOut.getCutPlanes().get(1).getSegmentList().get(0).s.distance(D) + D.distance(propDataOut.getCutPlanes().get(1).getPointList().get(3).coordinate) - propDataOut.getCutPlanes().get(1).getSRSegment().d; double deltaDE = Sp.distance(D) + D.distance(Rp) - Sp.distance(Rp); List res1 = new ArrayList<>(3) ; List res2 = new ArrayList<>(3); @@ -2476,7 +2471,7 @@ public void TC27(){ {0.0, 0.0, 0.0, 4.0, 90.10, 1.0, 1.0} }; - CnossosPath directPath = propDataOut.getPropagationPaths().get(0); + CnossosPath directPath = propDataOut.getCutPlanes().get(0); assertPlanes(segmentsMeanPlanesH, directPath.getSegmentList()); assertMirrorPoint(expectedSPrime,expectedRPrime,directPath.getSegmentList().get(0).sPrime, @@ -2492,7 +2487,7 @@ public void TC27(){ Coordinate expectedSPrimeSO =new Coordinate(0.01,-0.69); Coordinate expectedRPrimeOR =new Coordinate(100.65,-4.0); - CnossosPath reflectionPath = propDataOut.getPropagationPaths().get(1); + CnossosPath reflectionPath = propDataOut.getCutPlanes().get(1); assertPlanes(segmentsMeanPlanesH, reflectionPath.getSegmentList()); @@ -2593,7 +2588,7 @@ public void TC28(){ // Expected Values - assertEquals(3, propDataOut.getPropagationPaths().size()); + assertEquals(3, propDataOut.getCutPlanes().size()); /* Table 346 */ List expectedZProfile = Arrays.asList( @@ -2681,7 +2676,7 @@ public void TC28(){ {0.0, 0.68, 3.32, 1.12, 1022.31, 0.49, 0.49} }; - CnossosPath SR = propDataOut.getPropagationPaths().get(0); + CnossosPath SR = propDataOut.getCutPlanes().get(0); assertZProfil(expectedZProfile, Arrays.asList(SR.getSRSegment().getPoints2DGround())); assertZProfil(expectedZProfileSO, Arrays.asList(SR.getSegmentList().get(0).getPoints2DGround())); @@ -2692,12 +2687,12 @@ public void TC28(){ assertPlanes(segmentsMeanPlanes0,SR.getSegmentList()); - CnossosPath pathRight = propDataOut.getPropagationPaths().get(1); + CnossosPath pathRight = propDataOut.getCutPlanes().get(1); assertZProfil(expectedZProfileRight, Arrays.asList(pathRight.getSRSegment().getPoints2DGround())); assertPlanes(segmentsMeanPlanes1, pathRight.getSRSegment()); - CnossosPath pathLeft = propDataOut.getPropagationPaths().get(2); + CnossosPath pathLeft = propDataOut.getCutPlanes().get(2); // Error in CNOSSOS unit test, left diffraction is going over a building but not in their 3D view ! // Why the weird left path in homogeneous ? it is not explained. // assertZProfil(expectedZProfileLeft, Arrays.asList(pathLeft.getSRSegment().getPoints2DGround())); @@ -2826,7 +2821,7 @@ private void exportScene(String name, ProfileBuilder builder, PathFinderVisitor //kmlDocument.writeProfile("S:0 R:0", builder.getProfile(result.getInputData().sourceGeometries.get(0).getCoordinate(),result.getInputData().receivers.get(0))); } if(result != null) { - kmlDocument.writeRays(result.getPropagationPaths()); + kmlDocument.writeRays(result.getCutPlanes()); } kmlDocument.writeFooter(); } catch (XMLStreamException | CoordinateOperationException | CRSException ex) { diff --git a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/Attenuation.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/Attenuation.java index efd9c7220..856ef07af 100644 --- a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/Attenuation.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/Attenuation.java @@ -13,9 +13,9 @@ import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.math.Vector3D; import org.noise_planet.noisemodelling.pathfinder.*; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.pathfinder.path.Scene; -import org.noise_planet.noisemodelling.pathfinder.path.PointPath; +import org.noise_planet.noisemodelling.propagation.cnossos.PointPath; import org.noise_planet.noisemodelling.pathfinder.utils.geometry.Orientation; import org.noise_planet.noisemodelling.propagation.cnossos.AttenuationCnossos; import org.noise_planet.noisemodelling.propagation.cnossos.AttenuationCnossosParameters; diff --git a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/AttenuationVisitor.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/AttenuationVisitor.java index d475440c8..bcda0a392 100644 --- a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/AttenuationVisitor.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/AttenuationVisitor.java @@ -10,7 +10,7 @@ package org.noise_planet.noisemodelling.propagation; import org.noise_planet.noisemodelling.pathfinder.IComputePathsOut; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.propagation.cnossos.AttenuationCnossosParameters; import java.util.ArrayList; diff --git a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/AttenuationCnossos.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/AttenuationCnossos.java index c27248c92..d860aaa6d 100644 --- a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/AttenuationCnossos.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/AttenuationCnossos.java @@ -10,9 +10,6 @@ package org.noise_planet.noisemodelling.propagation.cnossos; import org.locationtech.jts.geom.Coordinate; -import org.noise_planet.noisemodelling.pathfinder.path.PointPath; -import org.noise_planet.noisemodelling.pathfinder.path.SegmentPath; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +19,7 @@ import java.util.stream.Collectors; import static java.lang.Math.*; -import static org.noise_planet.noisemodelling.pathfinder.path.PointPath.POINT_TYPE.*; +import static org.noise_planet.noisemodelling.propagation.cnossos.PointPath.POINT_TYPE.*; /** diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/cnossos/CnossosPath.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/CnossosPath.java similarity index 97% rename from noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/cnossos/CnossosPath.java rename to noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/CnossosPath.java index b943229f5..d002f95f5 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/cnossos/CnossosPath.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/CnossosPath.java @@ -7,11 +7,9 @@ * Contact: contact@noise-planet.org */ -package org.noise_planet.noisemodelling.pathfinder.cnossos; +package org.noise_planet.noisemodelling.propagation.cnossos; -import org.noise_planet.noisemodelling.pathfinder.path.Path; - /** * All the datas Path of Cnossos */ diff --git a/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/CnossosPathBuilder.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/CnossosPathBuilder.java new file mode 100644 index 000000000..66139a422 --- /dev/null +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/CnossosPathBuilder.java @@ -0,0 +1,548 @@ +package org.noise_planet.noisemodelling.propagation.cnossos; + +import org.locationtech.jts.algorithm.Angle; +import org.locationtech.jts.algorithm.CGAlgorithms3D; +import org.locationtech.jts.algorithm.ConvexHull; +import org.locationtech.jts.geom.*; +import org.locationtech.jts.math.Vector2D; +import org.locationtech.jts.triangulate.quadedge.Vertex; +import org.noise_planet.noisemodelling.pathfinder.path.MirrorReceiver; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.CutPoint; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.CutProfile; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.Wall; +import org.noise_planet.noisemodelling.pathfinder.utils.geometry.JTSUtility; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.Math.*; +import static java.lang.Math.max; +import static org.noise_planet.noisemodelling.propagation.cnossos.PointPath.POINT_TYPE.*; +import static org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder.IntersectionType.*; +import static org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder.IntersectionType.V_EDGE_DIFFRACTION; +import static org.noise_planet.noisemodelling.pathfinder.utils.geometry.GeometryUtils.projectPointOnLine; + +/** + * Generate a CnossosPath from a vertical cut plane data + */ +public class CnossosPathBuilder { + public static final double ALPHA0 = 2e-4; + + public static void computeRayleighDiff(SegmentPath srSeg, CutProfile cutProfile, CnossosPath pathParameters, + LineSegment dSR, List segments, List points, + List pts2D, Coordinate[] pts2DGround, List cut2DGroundIndex, + List frequencyTable) { + final List cuts = cutProfile.getCutPoints(); + + Coordinate src = pts2D.get(0); + Coordinate rcv = pts2D.get(pts2D.size() - 1); + CutPoint srcCut = cutProfile.getSource(); + CutPoint rcvCut = cutProfile.getReceiver(); + for (int iO = 1; iO < pts2DGround.length - 1; iO++) { + int i0Cut = cut2DGroundIndex.indexOf(iO); + Coordinate o = pts2DGround[iO]; + + double dSO = src.distance(o); + double dOR = o.distance(rcv); + double deltaH = dSR.orientationIndex(o) * (dSO + dOR - srSeg.d); + boolean rcrit = false; + for(int f : frequencyTable) { + if(deltaH > -(340./f) / 20) { + rcrit = true; + break; + } + } + if (rcrit) { + rcrit = false; + //Add point path + + //Plane S->O + Coordinate[] soCoords = Arrays.copyOfRange(pts2DGround, 0, iO + 1); + double[] abs = JTSUtility.getMeanPlaneCoefficients(soCoords); + SegmentPath seg1 = computeSegment(src, o, abs); + + //Plane O->R + Coordinate[] orCoords = Arrays.copyOfRange(pts2DGround, iO, pts2DGround.length); + double[] abr = JTSUtility.getMeanPlaneCoefficients(orCoords); + SegmentPath seg2 = computeSegment(o, rcv, abr); + + Coordinate srcPrime = new Coordinate(src.x + (seg1.sMeanPlane.x - src.x) * 2, src.y + (seg1.sMeanPlane.y - src.y) * 2); + Coordinate rcvPrime = new Coordinate(rcv.x + (seg2.rMeanPlane.x - rcv.x) * 2, rcv.y + (seg2.rMeanPlane.y - rcv.y) * 2); + + LineSegment dSPrimeRPrime = new LineSegment(srcPrime, rcvPrime); + srSeg.dPrime = srcPrime.distance(rcvPrime); + seg1.dPrime = srcPrime.distance(o); + seg2.dPrime = o.distance(rcvPrime); + + double deltaPrimeH = dSPrimeRPrime.orientationIndex(o) * (seg1.dPrime + seg2.dPrime - srSeg.dPrime); + for(int f : frequencyTable) { + if(deltaH > (340./f) / 4 - deltaPrimeH) { + rcrit = true; + break; + } + } + if (rcrit) { + pathParameters.deltaH = deltaH; + pathParameters.deltaPrimeH = deltaPrimeH; + seg1.setGpath(cutProfile.getGPath(srcCut, cuts.get(i0Cut)), srcCut.getGroundCoef()); + seg2.setGpath(cutProfile.getGPath(cuts.get(i0Cut), rcvCut), srcCut.getGroundCoef()); + + if(dSR.orientationIndex(o) == 1) { + pathParameters.deltaF = toCurve(dSO, srSeg.d) + toCurve(dOR, srSeg.d) - toCurve(srSeg.d, srSeg.d); + } + else { + Coordinate pA = dSR.pointAlong((o.x-src.x)/(rcv.x-src.x)); + pathParameters.deltaF =2*toCurve(src.distance(pA), srSeg.d) + 2*toCurve(pA.distance(rcv), srSeg.d) - toCurve(dSO, srSeg.d) - toCurve(dOR, srSeg.d) - toCurve(srSeg.d, srSeg.d); + } + + LineSegment sPrimeR = new LineSegment(seg1.sPrime, rcv); + double dSPrimeO = seg1.sPrime.distance(o); + double dSPrimeR = seg1.sPrime.distance(rcv); + pathParameters.deltaSPrimeRH = sPrimeR.orientationIndex(o)*(dSPrimeO + dOR - dSPrimeR); + + LineSegment sRPrime = new LineSegment(src, seg2.rPrime); + double dORPrime = o.distance(seg2.rPrime); + double dSRPrime = src.distance(seg2.rPrime); + pathParameters.deltaSRPrimeH = sRPrime.orientationIndex(o)*(dSO + dORPrime - dSRPrime); + + if(dSPrimeRPrime.orientationIndex(o) == 1) { + pathParameters.deltaPrimeF = toCurve(seg1.dPrime, srSeg.dPrime) + toCurve(seg2.dPrime, srSeg.dPrime) - toCurve(srSeg.dPrime, srSeg.dPrime); + } + else { + Coordinate pA = dSPrimeRPrime.pointAlong((o.x-srcPrime.x)/(rcvPrime.x-srcPrime.x)); + pathParameters.deltaPrimeF =2*toCurve(srcPrime.distance(pA), srSeg.dPrime) + 2*toCurve(pA.distance(srcPrime), srSeg.dPrime) - toCurve(seg1.dPrime, srSeg.dPrime) - toCurve(seg2.dPrime, srSeg.d) - toCurve(srSeg.dPrime, srSeg.dPrime); + } + + segments.add(seg1); + segments.add(seg2); + + points.add(new PointPath(o, o.z, new ArrayList<>(), DIFH_RCRIT)); + } + } + } + } + + + /** + * Compute the segment path + * @param src + * @param rcv + * @param meanPlane + * @return the calculated segment + */ + public static SegmentPath computeSegment(Coordinate src, Coordinate rcv, double[] meanPlane) { + return computeSegment(src, rcv, meanPlane, 0, 0); + } + + /** + * Compute the segment path with more attribute + * @param src + * @param rcv + * @param meanPlane + * @param gPath + * @param gS + * @return the computed segment path + */ + + public static SegmentPath computeSegment(Coordinate src, Coordinate rcv, double[] meanPlane, double gPath, double gS) { + SegmentPath seg = new SegmentPath(); + Coordinate sourcePointOnMeanPlane = projectPointOnLine(src, meanPlane[0], meanPlane[1]); + Coordinate receiverPointOnMeanPlane = projectPointOnLine(rcv, meanPlane[0], meanPlane[1]); + Vector2D sourceToProjectedPoint = Vector2D.create(src, sourcePointOnMeanPlane); + Vector2D receiverToProjectedPoint = Vector2D.create(rcv, receiverPointOnMeanPlane); + seg.s = src; + seg.r = rcv; + seg.sMeanPlane = sourcePointOnMeanPlane; + seg.rMeanPlane = receiverPointOnMeanPlane; + seg.sPrime = Vector2D.create(sourcePointOnMeanPlane).add(sourceToProjectedPoint).toCoordinate(); + seg.rPrime = Vector2D.create(receiverPointOnMeanPlane).add(receiverToProjectedPoint).toCoordinate(); + + seg.d = src.distance(rcv); + seg.dp =sourcePointOnMeanPlane.distance(receiverPointOnMeanPlane); + seg.zsH = src.distance(sourcePointOnMeanPlane); + seg.zrH = rcv.distance(receiverPointOnMeanPlane); + seg.a = meanPlane[0]; + seg.b = meanPlane[1]; + seg.testFormH = seg.dp/(30*(seg.zsH +seg.zrH)); + seg.gPath = gPath; + seg.gPathPrime = seg.testFormH <= 1 ? seg.gPath*(seg.testFormH) + gS*(1-seg.testFormH) : seg.gPath; // 2.5.14 + double deltaZT = 6e-3 * seg.dp / (seg.zsH + seg.zrH); + double deltaZS = ALPHA0 * pow((seg.zsH / (seg.zsH + seg.zrH)), 2) * (seg.dp*seg.dp / 2); //2.5.19 + seg.zsF = seg.zsH + deltaZS + deltaZT; + double deltaZR = ALPHA0 * pow((seg.zrH / (seg.zsH + seg.zrH)), 2) * (seg.dp*seg.dp / 2); + seg.zrF = seg.zrH + deltaZR + deltaZT; + seg.testFormF = seg.dp/(30*(seg.zsF +seg.zrF)); + return seg; + } + + /** + * Eq.2.5.24 and Eq. 2.5.25 + * @param mn + * @param d + * @return + */ + public static double toCurve(double mn, double d){ + return 2*max(1000, 8*d)* asin(mn/(2*max(1000, 8*d))); + } + + /** + * Given the vertical cut profile (can be a single plane or multiple like a folding panel) return the ray path + * following Cnossos specification, or null if there is no valid path. + * @param cutProfile Vertical cut of a domain + * @param bodyBarrier + * @return The cnossos path or null + */ + public static CnossosPath computeHEdgeDiffraction(CutProfile cutProfile , boolean bodyBarrier) { + List segments = new ArrayList<>(); + List points = new ArrayList<>(); + final List cutProfilePoints = cutProfile.getCutPoints(); + + List pts2D = computePts2D(cutProfilePoints); + if(pts2D.size() != cutProfilePoints.size()) { + throw new IllegalArgumentException("The two arrays size should be the same"); + } + + List cut2DGroundIndex = new ArrayList<>(cutProfile.getCutPoints().size()); + Coordinate[] pts2DGround = cutProfile.computePts2DGround(cut2DGroundIndex).toArray(new Coordinate[0]); + double[] meanPlane = JTSUtility.getMeanPlaneCoefficients(pts2DGround); + Coordinate firstPts2D = pts2D.get(0); + Coordinate lastPts2D = pts2D.get(pts2D.size()-1); + SegmentPath srPath = computeSegment(firstPts2D, lastPts2D, meanPlane, cutProfile.getGPath(), cutProfile.getSource().getGroundCoef()); + srPath.setPoints2DGround(pts2DGround); + srPath.dc = CGAlgorithms3D.distance(cutProfile.getReceiver().getCoordinate(), + cutProfile.getSource().getCoordinate()); + CnossosPath pathParameters = new CnossosPath(); + pathParameters.setCutProfile(cutProfile); + pathParameters.setFavorable(true); + pathParameters.setPointList(points); + pathParameters.setSegmentList(segments); + pathParameters.setSRSegment(srPath); + pathParameters.init(data.freq_lvl.size()); + pathParameters.angle= Angle.angle(cutProfile.getReceiver().getCoordinate(), cutProfile.getSource().getCoordinate()); + // Extract the first and last points to define the line segment + Coordinate firstPt = pts2D.get(0); + Coordinate lastPt = pts2D.get(pts2D.size() - 1); + + // Filter out points that are below the line segment + List convexHullInput = new ArrayList<>(); + // Add source position + convexHullInput.add(pts2D.get(0)); + // Add valid diffraction point, building/walls/dem + for (int idPoint=1; idPoint < cutProfilePoints.size() - 1; idPoint++) { + boolean validIntersection = false; + CutPoint currentPoint = cutProfilePoints.get(idPoint); + switch (currentPoint.getType()) { + case BUILDING: + case WALL: + // We only add the point at the top of the wall, not the point at the bottom of the wall + validIntersection = Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0; + break; + case TOPOGRAPHY: + validIntersection = true; + break; + default: + } + if(validIntersection) { + convexHullInput.add(pts2D.get(idPoint)); + } + } + // Add receiver position + convexHullInput.add(pts2D.get(pts2D.size() - 1)); + + // Compute the convex hull using JTS + List convexHullPoints = new ArrayList<>(); + if(convexHullInput.size() > 2) { + GeometryFactory geomFactory = new GeometryFactory(); + Coordinate[] coordsArray = convexHullInput.toArray(new Coordinate[0]); + ConvexHull convexHull = new ConvexHull(coordsArray, geomFactory); + Coordinate[] convexHullCoords = convexHull.getConvexHull().getCoordinates(); + int indexFirst = Arrays.asList(convexHull.getConvexHull().getCoordinates()).indexOf(firstPt); + int indexLast = Arrays.asList(convexHull.getConvexHull().getCoordinates()).lastIndexOf(lastPt); + if(indexFirst == -1 || indexLast == -1 || indexFirst > indexLast) { + throw new IllegalArgumentException("Wrong input data " + cutProfile.toString()); + } + convexHullCoords = Arrays.copyOfRange(convexHullCoords, indexFirst, indexLast + 1); + CoordinateSequence coordSequence = geomFactory.getCoordinateSequenceFactory().create(convexHullCoords); + Geometry geom = geomFactory.createLineString(coordSequence); + Geometry uniqueGeom = geom.union(); // Removes duplicate coordinates + convexHullCoords = uniqueGeom.getCoordinates(); + // Convert the result back to your format (List pts) + if (convexHullCoords.length == 3) { + convexHullPoints = Arrays.asList(convexHullCoords); + } else { + for (int j = 0; j < convexHullCoords.length; j++) { + // Check if the y-coordinate is valid (not equal to Double.MAX_VALUE and not infinite) + if (convexHullCoords[j].y == Double.MAX_VALUE || Double.isInfinite(convexHullCoords[j].y)) { + continue; // Skip this point as it's not part of the hull + } + convexHullPoints.add(convexHullCoords[j]); + } + } + } else { + convexHullPoints = convexHullInput; + } + List pts = convexHullPoints; + + Coordinate src = cutProfile.getSource().getCoordinate(); + + // Move then check reflection height if there is diffraction on the path + if(pts.size() > 2) { + for (int i = 1; i < pts.size(); i++) { + int i0 = pts2D.indexOf(pts.get(i - 1)); + int i1 = pts2D.indexOf(pts.get(i)); + LineSegment segmentHull = new LineSegment(pts.get(i - 1), pts.get(i)); + for (int pointIndex = i0 + 1; pointIndex < i1; pointIndex++) { + final CutPoint currentPoint = cutProfilePoints.get(pointIndex); + // If the current point is the reflection point (not on the ground level) + if (currentPoint.getType().equals(REFLECTION) && + Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0) { + MirrorReceiver mirrorReceiver = currentPoint.getMirrorReceiver(); + Coordinate interpolatedReflectionPoint = segmentHull.closestPoint(pts2D.get(pointIndex)); + // Check if the new elevation of the reflection point is not higher than the wall + double wallAltitudeAtReflexionPoint = Vertex.interpolateZ(mirrorReceiver.getReflectionPosition(), + mirrorReceiver.getWall().p0, mirrorReceiver.getWall().p1); + if(wallAltitudeAtReflexionPoint + epsilon >= interpolatedReflectionPoint.y) { + // update the reflection position + currentPoint.getCoordinate().setZ(interpolatedReflectionPoint.y); + pts2D.get(pointIndex).setY(interpolatedReflectionPoint.y); + } else { + // Reflection is not valid, so the whole path is not valid + return null; + } + } + } + } + } + + // Create segments from each diffraction point to the receiver + for (int i = 1; i < pts.size(); i++) { + int i0 = pts2D.indexOf(pts.get(i - 1)); + int i1 = pts2D.indexOf(pts.get(i)); + int i0Ground = cut2DGroundIndex.get(i0); + int i1Ground = cut2DGroundIndex.get(i1); + final CutPoint cutPt0 = cutProfilePoints.get(i0); + final CutPoint cutPt1 = cutProfilePoints.get(i1); + // ground index may be near the diffraction point + // mean ground plane is computed using from the bottom of the walls + if (i0Ground < i1Ground - 1) { + CutPoint nextPoint = cutProfilePoints.get(i0 + 1); + if (cutPt0.getCoordinate().distance(nextPoint.getCoordinate()) <= ProfileBuilder.MILLIMETER + epsilon + && Double.compare(nextPoint.getCoordinate().z, nextPoint.getzGround()) == 0 + && (nextPoint.getType().equals(WALL) || nextPoint.getType().equals(BUILDING))) { + i0Ground += 1; + } + } + if (i1Ground - 1 > i0Ground) { + CutPoint previousPoint = cutProfilePoints.get(i1 - 1); + if (cutPt1.getCoordinate().distance(previousPoint.getCoordinate()) <= ProfileBuilder.MILLIMETER + + epsilon && Double.compare(previousPoint.getCoordinate().z, previousPoint.getzGround()) == 0 + && (previousPoint.getType().equals(WALL) || previousPoint.getType().equals(BUILDING))) { + i1Ground -= 1; + } + } + // Create a profile for the segment i0->i1 + CutProfile profileSeg = new CutProfile(); + profileSeg.addCutPoints(cutProfilePoints.subList(i0, i1 + 1)); + profileSeg.setSource(cutPt0); + profileSeg.setReceiver(cutPt1); + + + if (points.isEmpty()) { + // First segment, add the source point in the array + points.add(new PointPath(pts2D.get(i0), cutPt0.getzGround(), cutPt0.getWallAlpha(), cutPt1.getBuildingId(), SRCE)); + // look for the first reflection before the first diffraction, the source orientation is to the first reflection point + Coordinate targetPosition = cutProfilePoints.get(i1).getCoordinate(); + for (int pointIndex = i0 + 1; pointIndex < i1; pointIndex++) { + final CutPoint currentPoint = cutProfilePoints.get(pointIndex); + if ((currentPoint.getType().equals(REFLECTION) || currentPoint.getType().equals(V_EDGE_DIFFRACTION)) && + Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0) { + // The first reflection (the one not at ground level) + // from the source coordinate is the direction of the propagation + targetPosition = currentPoint.getCoordinate(); + break; + } + } + points.get(0).orientation = computeOrientation(cutProfile.getSrcOrientation(), + cutProfilePoints.get(0).getCoordinate(), targetPosition); + pathParameters.raySourceReceiverDirectivity = points.get(0).orientation; + src = pts2D.get(i0); + } + // Add reflection/vertical edge diffraction points/segments between i0 i1 + int previousPivotPoint = i0; + for (int pointIndex = i0 + 1; pointIndex < i1; pointIndex++) { + final CutPoint currentPoint = cutProfilePoints.get(pointIndex); + if (currentPoint.getType().equals(REFLECTION) && + Double.compare(currentPoint.getCoordinate().z, currentPoint.getzGround()) != 0) { + // If the current point is a reflection and not before/after the reflection + MirrorReceiver mirrorReceiver = currentPoint.getMirrorReceiver(); + double wallAltitudeAtReflexionPoint = Vertex.interpolateZ(mirrorReceiver.getReflectionPosition(), + mirrorReceiver.getWall().p0, mirrorReceiver.getWall().p1); + PointPath reflectionPoint = new PointPath(pts2D.get(pointIndex),currentPoint.getzGround(), currentPoint.getWallAlpha(), REFL); + reflectionPoint.obstacleZ = wallAltitudeAtReflexionPoint; + reflectionPoint.setWallId(currentPoint.getWallId()); + points.add(reflectionPoint); + } else if (currentPoint.getType().equals(V_EDGE_DIFFRACTION)) { + // current point is a vertical edge diffraction (there is no additional points unlike reflection) + PointPath diffractionPoint = new PointPath(pts2D.get(pointIndex),currentPoint.getzGround(), new ArrayList<>(), DIFV); + diffractionPoint.setWallId(currentPoint.getWallId()); + points.add(diffractionPoint); + // Compute additional segment + Coordinate[] segmentGroundPoints = Arrays.copyOfRange(pts2DGround, i0Ground,cut2DGroundIndex.get(pointIndex) + 1); + meanPlane = JTSUtility.getMeanPlaneCoefficients(segmentGroundPoints); + SegmentPath seg = computeSegment(pts2D.get(previousPivotPoint), pts2D.get(pointIndex), + meanPlane, profileSeg.getGPath(cutPt0, cutProfilePoints.get(pointIndex)), data.gS); + seg.setPoints2DGround(segmentGroundPoints); + previousPivotPoint = pointIndex; + segments.add(seg); + } + } + points.add(new PointPath(pts2D.get(i1), cutPt1.getzGround(), cutPt1.getWallAlpha(), cutPt1.getBuildingId(), RECV)); + if(previousPivotPoint != i0 && i == pts.size() - 1) { + // we added segments before i1 vertical plane diffraction point, but it is the last vertical plane + // diffraction point and we must add the remaining segment between the last horizontal diffraction point + // and the last point + Coordinate[] segmentGroundPoints = Arrays.copyOfRange(pts2DGround, i1Ground, pts2DGround.length); + meanPlane = JTSUtility.getMeanPlaneCoefficients(segmentGroundPoints); + SegmentPath seg = computeSegment(pts2D.get(previousPivotPoint), pts2D.get(pts2D.size() - 1), + meanPlane, profileSeg.getGPath(cutPt1, cutProfilePoints.get(cutProfilePoints.size() - 1)), + data.gS); + seg.setPoints2DGround(segmentGroundPoints); + segments.add(seg); + } + if(pts.size() == 2) { + // no diffraction over buildings/dem, we already computed SR segment + break; + } + Coordinate[] segmentGroundPoints = Arrays.copyOfRange(pts2DGround, i0Ground,i1Ground + 1); + meanPlane = JTSUtility.getMeanPlaneCoefficients(segmentGroundPoints); + SegmentPath path = computeSegment(pts2D.get(i0), pts2D.get(i1), meanPlane, profileSeg.getGPath(), + profileSeg.getSource().getGroundCoef()); + path.dc = cutPt0.getCoordinate().distance3D(cutPt1.getCoordinate()); + path.setPoints2DGround(segmentGroundPoints); + segments.add(path); + if (i != pts.size() - 1) { + PointPath pt = points.get(points.size() - 1); + pt.type = DIFH; + pt.bodyBarrier = bodyBarrier; + if (pt.buildingId != -1) { + pt.alphaWall = data.profileBuilder.getBuilding(pt.buildingId).getAlphas(); + pt.setObstacleZ(data.profileBuilder.getBuilding(pt.buildingId).getZ()); + } else if (pt.wallId != -1) { + pt.alphaWall = data.profileBuilder.getWall(pt.wallId).getAlphas(); + Wall wall = data.profileBuilder.getWall(pt.wallId); + pt.setObstacleZ(Vertex.interpolateZ(pt.coordinate, wall.p0, wall.p1)); + } + } + } + + if(points.isEmpty()) { + return null; + } + + Coordinate rcv = points.get(points.size()-1).coordinate; + PointPath p0 = points.stream().filter(p -> p.type.equals(DIFH)).findFirst().orElse(null); + if(p0==null){ + // Direct propagation (no diffraction over obstructing objects) + boolean horizontalPlaneDiffraction = cutProfile.getCutPoints().stream() + .anyMatch( + cutPoint -> cutPoint.getType().equals(V_EDGE_DIFFRACTION)); + List rayleighSegments = new ArrayList<>(); + List rayleighPoints = new ArrayList<>(); + // do not check for rayleigh if the path is not direct between R and S + if(!horizontalPlaneDiffraction) { + // Check for Rayleigh criterion for segments computation + LineSegment dSR = new LineSegment(firstPts2D, lastPts2D); + // Look for diffraction over edge on free field (frequency dependent) + computeRayleighDiff(srPath, cutProfile, pathParameters, dSR, rayleighSegments, rayleighPoints, pts2D, + pts2DGround, cut2DGroundIndex); + } + if(rayleighSegments.isEmpty()) { + // We don't have a Rayleigh diffraction over DEM. Only direct SR path + if(segments.isEmpty()) { + segments.add(pathParameters.getSRSegment()); + } + // Compute cumulated distance between the first diffraction and the last diffraction point + pathParameters.e = 0; + List diffPoints = points.stream().filter(pointPath -> pointPath.type != REFL).collect(Collectors.toList()); + for(int idPoint = 1; idPoint < diffPoints.size() - 2; idPoint++) { + pathParameters.e += diffPoints.get(idPoint).coordinate.distance(diffPoints.get(idPoint+1).coordinate); + } + long difVPointCount = pathParameters.getPointList().stream(). + filter(pointPath -> pointPath.type.equals(DIFV)).count(); + double distance = difVPointCount == 0 ? pathParameters.getSRSegment().d : pathParameters.getSRSegment().dc; + pathParameters.deltaH = segments.get(0).d + pathParameters.e + segments.get(segments.size()-1).d - distance; + pathParameters.deltaF = pathParameters.deltaH; + } else { + segments.addAll(rayleighSegments); + points.addAll(1, rayleighPoints); + } + return pathParameters; + } + Coordinate c0 = p0.coordinate; + PointPath pn = points.stream().filter(p -> p.type.equals(DIFH)).reduce((first, second) -> second).orElse(null); + if(pn==null){ + return null; + } + Coordinate cn = pn.coordinate; + + SegmentPath seg1 = segments.get(0); + SegmentPath seg2 = segments.get(segments.size()-1); + + double dSO0 = seg1.d; + double dOnR = seg2.d; + LineSegment sr = new LineSegment(src, rcv); + + LineSegment sPrimeR = new LineSegment(seg1.sPrime, rcv); + double dSPrimeR = seg1.sPrime.distance(rcv); + double dSPrimeO = seg1.sPrime.distance(c0); + // Compute cumulated distance between the first diffraction and the last diffraction point + pathParameters.e = 0; + List diffPoints = points.stream().filter(pointPath -> pointPath.type != REFL).collect(Collectors.toList()); + for(int idPoint = 1; idPoint < diffPoints.size() - 2; idPoint++) { + pathParameters.e += diffPoints.get(idPoint).coordinate.distance(diffPoints.get(idPoint+1).coordinate); + } + pathParameters.deltaSPrimeRH = sPrimeR.orientationIndex(c0)*(dSPrimeO + pathParameters.e + dOnR - dSPrimeR); + pathParameters.deltaSPrimeRF = toCurve(dSPrimeO, dSPrimeR) + toCurve(pathParameters.e, dSPrimeR) + toCurve(dOnR, dSPrimeR) - toCurve(dSPrimeR, dSPrimeR); + + LineSegment sRPrime = new LineSegment(src, seg2.rPrime); + double dSRPrime = src.distance(seg2.rPrime); + double dORPrime = cn.distance(seg2.rPrime); + pathParameters.deltaSRPrimeH = (src.x>seg2.rPrime.x?-1:1)*sRPrime.orientationIndex(cn)*(dSO0 + pathParameters.e + dORPrime - dSRPrime); + pathParameters.deltaSRPrimeF = toCurve(dSO0, dSRPrime) + toCurve(pathParameters.e, dSRPrime) + toCurve(dORPrime, dSRPrime) - toCurve(dSRPrime, dSRPrime); + + Coordinate srcPrime = new Coordinate(src.x + (seg1.sMeanPlane.x - src.x) * 2, src.y + (seg1.sMeanPlane.y - src.y) * 2); + Coordinate rcvPrime = new Coordinate(rcv.x + (seg2.rMeanPlane.x - rcv.x) * 2, rcv.y + (seg2.rMeanPlane.y - rcv.y) * 2); + + LineSegment dSPrimeRPrime = new LineSegment(srcPrime, rcvPrime); + srPath.dPrime = srcPrime.distance(rcvPrime); + seg1.dPrime = srcPrime.distance(c0); + seg2.dPrime = cn.distance(rcvPrime); + + + long difVPointCount = pathParameters.getPointList().stream(). + filter(pointPath -> pointPath.type.equals(DIFV)).count(); + double distance = difVPointCount == 0 ? pathParameters.getSRSegment().d : pathParameters.getSRSegment().dc; + pathParameters.deltaH = sr.orientationIndex(c0) * (dSO0 + pathParameters.e + dOnR - distance); + if (sr.orientationIndex(c0) == 1) { + pathParameters.deltaF = toCurve(seg1.d, srPath.d) + toCurve(pathParameters.e, srPath.d) + toCurve(seg2.d, srPath.d) - toCurve(srPath.d, srPath.d); + } else { + Coordinate pA = sr.pointAlong((c0.x - srcPrime.x) / (rcvPrime.x - srcPrime.x)); + pathParameters.deltaF = 2 * toCurve(srcPrime.distance(pA), srPath.dPrime) + 2 * toCurve(pA.distance(rcvPrime), srPath.dPrime) - toCurve(seg1.dPrime, srPath.dPrime) - toCurve(seg2.dPrime, srPath.dPrime) - toCurve(srPath.dPrime, srPath.dPrime); + } + + pathParameters.deltaPrimeH = dSPrimeRPrime.orientationIndex(c0) * (seg1.dPrime + pathParameters.e + seg2.dPrime - srPath.dPrime); + + pathParameters.deltaPrimeH = dSPrimeRPrime.orientationIndex(c0) * (seg1.dPrime + seg2.dPrime - srPath.dPrime); + if(dSPrimeRPrime.orientationIndex(c0) == 1) { + pathParameters.deltaPrimeF = toCurve(seg1.dPrime, srPath.dPrime) + toCurve(seg2.dPrime, srPath.dPrime) - toCurve(srPath.dPrime, srPath.dPrime); + } else { + Coordinate pA = dSPrimeRPrime.pointAlong((c0.x-srcPrime.x)/(rcvPrime.x-srcPrime.x)); + pathParameters.deltaPrimeF =2*toCurve(srcPrime.distance(pA), srPath.dPrime) + 2*toCurve(pA.distance(srcPrime), srPath.dPrime) - toCurve(seg1.dPrime, srPath.dPrime) - toCurve(seg2.dPrime, srPath.d) - toCurve(srPath.dPrime, srPath.dPrime); + } + + return pathParameters; + } +} diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/Path.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/Path.java similarity index 99% rename from noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/Path.java rename to noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/Path.java index a01bb4d5d..bbbc23d36 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/Path.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/Path.java @@ -7,7 +7,7 @@ * Contact: contact@noise-planet.org */ -package org.noise_planet.noisemodelling.pathfinder.path; +package org.noise_planet.noisemodelling.propagation.cnossos; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.LineSegment; @@ -24,7 +24,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import static org.noise_planet.noisemodelling.pathfinder.utils.geometry.GeometryUtils.projectPointOnSegment; diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/PointPath.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/PointPath.java similarity index 73% rename from noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/PointPath.java rename to noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/PointPath.java index 216686e31..5697c1f03 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/PointPath.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/PointPath.java @@ -7,9 +7,10 @@ * Contact: contact@noise-planet.org */ -package org.noise_planet.noisemodelling.pathfinder.path; +package org.noise_planet.noisemodelling.propagation.cnossos; import org.locationtech.jts.geom.Coordinate; +import org.noise_planet.noisemodelling.pathfinder.profilebuilder.ProfileBuilder; import org.noise_planet.noisemodelling.pathfinder.utils.geometry.Orientation; import java.io.DataInputStream; @@ -193,72 +194,14 @@ public void setCoordinate(Coordinate coordinate) { this.coordinate = coordinate; } - public static final class ReceiverPointInfo { - int sourcePrimaryKey; - public Coordinate position; - - public ReceiverPointInfo(int sourcePrimaryKey, Coordinate position) { - this.sourcePrimaryKey = sourcePrimaryKey; - this.position = position; - } - - public Coordinate getCoord() { - return position; - } - - public int getId() { - return sourcePrimaryKey; - } - } - - public static final class SourcePointInfo implements Comparable { - public final double li; - final int sourcePrimaryKey; - Coordinate position; - public final double globalWj; - Orientation orientation; - - /** - * @param wj Maximum received power from this source - * @param sourcePrimaryKey - * @param position - */ - public SourcePointInfo(double[] wj, int sourcePrimaryKey, Coordinate position, double li, Orientation orientation) { - this.sourcePrimaryKey = sourcePrimaryKey; - this.position = position; - if (isNaN(position.z)) { - this.position = new Coordinate(position.x, position.y, 0); - } - this.globalWj = sumArray(wj.length, wj); - this.li = li; - this.orientation = orientation; - } - - public Orientation getOrientation() { - return orientation; - } - - public Coordinate getCoord() { - return position; + public PointPath.POINT_TYPE toPointType(ProfileBuilder.IntersectionType intersectionType, PointPath.POINT_TYPE defaultPointType) { + if(intersectionType.equals(ProfileBuilder.IntersectionType.SOURCE)){ + return PointPath.POINT_TYPE.SRCE; } - - public int getId() { - return sourcePrimaryKey; - } - - /** - * - * @param sourcePointInfo the object to be compared. - * @return 1, 0 or -1 - */ - @Override - public int compareTo(SourcePointInfo sourcePointInfo) { - int cmp = -Double.compare(globalWj, sourcePointInfo.globalWj); - if (cmp == 0) { - return Integer.compare(sourcePrimaryKey, sourcePointInfo.sourcePrimaryKey); - } else { - return cmp; - } + else if(intersectionType.equals(ProfileBuilder.IntersectionType.RECEIVER)){ + return PointPath.POINT_TYPE.RECV; + } else { + return defaultPointType; } } } diff --git a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/SegmentPath.java b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/SegmentPath.java similarity index 97% rename from noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/SegmentPath.java rename to noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/SegmentPath.java index 937840d30..a70cbd968 100644 --- a/noisemodelling-pathfinder/src/main/java/org/noise_planet/noisemodelling/pathfinder/path/SegmentPath.java +++ b/noisemodelling-propagation/src/main/java/org/noise_planet/noisemodelling/propagation/cnossos/SegmentPath.java @@ -7,7 +7,7 @@ * Contact: contact@noise-planet.org */ -package org.noise_planet.noisemodelling.pathfinder.path; +package org.noise_planet.noisemodelling.propagation.cnossos; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.math.Vector3D; @@ -15,8 +15,6 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; public class SegmentPath { // debug/unit test purpose data diff --git a/noisemodelling-propagation/src/test/java/org/noise_planet/noisemodelling/propagation/RayAttenuationTest.java b/noisemodelling-propagation/src/test/java/org/noise_planet/noisemodelling/propagation/RayAttenuationTest.java index eee119545..292157fc7 100644 --- a/noisemodelling-propagation/src/test/java/org/noise_planet/noisemodelling/propagation/RayAttenuationTest.java +++ b/noisemodelling-propagation/src/test/java/org/noise_planet/noisemodelling/propagation/RayAttenuationTest.java @@ -11,7 +11,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.databind.json.JsonMapper; import org.junit.jupiter.api.Test; -import org.noise_planet.noisemodelling.pathfinder.cnossos.CnossosPath; +import org.noise_planet.noisemodelling.propagation.cnossos.CnossosPath; import org.noise_planet.noisemodelling.propagation.cnossos.AttenuationCnossos; import org.noise_planet.noisemodelling.propagation.cnossos.AttenuationCnossosParameters;