From 73d873b91c1bd0fd5f6511c15722cb2517b19e4b Mon Sep 17 00:00:00 2001 From: Vincent Paturet Date: Fri, 14 Jul 2023 11:33:44 +0200 Subject: [PATCH] Add builder for StreetEdge --- .../module/OsmBoardingLocationsModule.java | 19 +- .../graph_builder/module/osm/OsmModule.java | 48 +- .../module/osm/WalkableAreaBuilder.java | 57 +-- .../routing/graph/index/StreetIndex.java | 55 +- .../routing/linking/VertexLinker.java | 53 +- .../street/model/edge/AreaEdge.java | 63 +-- .../street/model/edge/AreaEdgeBuilder.java | 32 ++ .../street/model/edge/StreetEdge.java | 469 +++++++----------- .../street/model/edge/StreetEdgeBuilder.java | 232 +++++++++ .../edge/TemporaryPartialStreetEdge.java | 65 +-- .../TemporaryPartialStreetEdgeBuilder.java | 22 + .../linking/LinkStopToPlatformTest.java | 39 +- .../module/ElevationModuleTest.java | 19 +- .../module/linking/LinkingTest.java | 37 +- .../ned/MissingElevationHandlerTest.java | 20 +- .../routing/TestHalfEdges.java | 145 +++--- .../routing/algorithm/GraphRoutingTest.java | 69 ++- .../algorithm/StreetModeLinkingTest.java | 5 +- .../routing/algorithm/TurnCostTest.java | 14 +- .../routing/core/GraphTest.java | 11 +- .../core/TemporaryVerticesContainerTest.java | 12 +- .../routing/core/TurnsTest.java | 37 +- .../routing/graph/EdgeTest.java | 56 +-- .../VehicleParkingTestUtil.java | 23 +- .../street/model/TurnRestrictionTest.java | 11 +- .../model/_data/StreetModelForTest.java | 21 +- .../model/edge/AreaEdgeBuilderTest.java | 40 ++ .../model/edge/StreetEdgeBuilderTest.java | 108 ++++ .../street/model/edge/StreetEdgeCostTest.java | 132 ++--- .../street/model/edge/StreetEdgeTest.java | 32 +- .../edge/StreetEdgeWheelchairCostTest.java | 86 ++-- ...TemporaryPartialStreetEdgeBuilderTest.java | 43 ++ .../edge/TemporaryPartialStreetEdgeTest.java | 26 +- .../model/vertex/BarrierVertexTest.java | 11 +- .../model/vertex/IntersectionVertexTest.java | 11 +- ...leIntersectionTraversalCalculatorTest.java | 11 +- 36 files changed, 1264 insertions(+), 870 deletions(-) create mode 100644 src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java create mode 100644 src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java create mode 100644 src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilder.java create mode 100644 src/test/java/org/opentripplanner/street/model/edge/AreaEdgeBuilderTest.java create mode 100644 src/test/java/org/opentripplanner/street/model/edge/StreetEdgeBuilderTest.java create mode 100644 src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilderTest.java diff --git a/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java b/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java index 6b05571e623..b712757b3da 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java @@ -19,6 +19,7 @@ import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.NamedArea; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.edge.StreetTransitStopLink; import org.opentripplanner.street.model.vertex.OsmBoardingLocationVertex; import org.opentripplanner.street.model.vertex.StreetVertex; @@ -185,15 +186,15 @@ private boolean connectVertexToStop(TransitStopVertex ts, StreetIndex index) { private StreetEdge linkBoardingLocationToStreetNetwork(StreetVertex from, StreetVertex to) { var line = GeometryUtils.makeLineString(List.of(from.getCoordinate(), to.getCoordinate())); - return StreetEdge.createStreetEdge( - from, - to, - line, - new LocalizedString("name.platform"), - SphericalDistanceLibrary.length(line), - StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE, - false - ); + return new StreetEdgeBuilder<>() + .withFromVertex(from) + .withToVertex(to) + .withGeometry(line) + .withName(new LocalizedString("name.platform")) + .withMeterLength(SphericalDistanceLibrary.length(line)) + .withPermission(StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE) + .withBack(false) + .buildAndConnect(); } private void linkBoardingLocationToStop( diff --git a/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java b/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java index 0f881c563c6..bfab1097ad7 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java @@ -29,6 +29,7 @@ import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.slf4j.Logger; @@ -463,7 +464,8 @@ private StreetEdgePair getEdgesForStreet( } LineString backGeometry = geometry.reverse(); - StreetEdge street = null, backStreet = null; + StreetEdge street = null; + StreetEdge backStreet = null; double length = getGeometryLengthMeters(geometry); var permissionPair = OsmFilter.getPermissions(permissions, way); @@ -499,13 +501,6 @@ private StreetEdgePair getEdgesForStreet( if (street != null && backStreet != null) { backStreet.shareData(street); } - - /* mark edges that are on roundabouts */ - if (way.isRoundabout()) { - if (street != null) street.setRoundabout(true); - if (backStreet != null) backStreet.setRoundabout(true); - } - return new StreetEdgePair(street, backStreet); } @@ -524,37 +519,34 @@ private StreetEdge getEdgeForStreet( I18NString name = params.edgeNamer().getNameForWay(way, label); float carSpeed = way.getOsmProvider().getOsmTagMapper().getCarSpeedForWay(way, back); - StreetEdge street = StreetEdge.createStreetEdge( - startEndpoint, - endEndpoint, - geometry, - name, - length, - permissions, - back - ); - street.setCarSpeed(carSpeed); - street.setLink(OsmFilter.isLink(way)); + StreetEdgeBuilder seb = new StreetEdgeBuilder<>() + .withFromVertex(startEndpoint) + .withToVertex(endEndpoint) + .withGeometry(geometry) + .withName(name) + .withMeterLength(length) + .withPermission(permissions) + .withBack(back) + .withCarSpeed(carSpeed) + .withLink(OsmFilter.isLink(way)) + .withRoundabout(way.isRoundabout()) + .withSlopeOverride(way.getOsmProvider().getWayPropertySet().getSlopeOverride(way)) + .withStairs(way.isSteps()); if (!way.hasTag("name") && !way.hasTag("ref")) { - street.setHasBogusName(true); + seb.withBogusName(true); } - - boolean steps = way.isSteps(); - street.setStairs(steps); - /* TODO: This should probably generalized somehow? */ - if ((way.isTagFalse("wheelchair") || (steps && !way.isTagTrue("wheelchair")))) { - street.setWheelchairAccessible(false); + if ((way.isTagFalse("wheelchair") || (way.isSteps() && !way.isTagTrue("wheelchair")))) { + seb.withWheelchairAccessible(false); } - street.setSlopeOverride(way.getOsmProvider().getWayPropertySet().getSlopeOverride(way)); - // < 0.04: account for if (carSpeed < 0.04) { issueStore.add(new StreetCarSpeedZero(way)); } + StreetEdge street = seb.buildAndConnect(); params.edgeNamer().recordEdge(way, street); return street; diff --git a/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java b/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java index 6244775ad02..b77aef8844e 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java @@ -37,6 +37,7 @@ import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.AreaEdge; +import org.opentripplanner.street.model.edge.AreaEdgeBuilder; import org.opentripplanner.street.model.edge.AreaEdgeList; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.NamedArea; @@ -527,27 +528,26 @@ private Set createSegments( endEndpoint.getLabel(); I18NString name = namer.getNameForWay(areaEntity, label); - AreaEdge street = AreaEdge.createAreaEdge( - startEndpoint, - endEndpoint, - line, - name, - length, - areaPermissions, - false, - edgeList - ); - street.setCarSpeed(carSpeed); + AreaEdgeBuilder streetEdgeBuilder = new AreaEdgeBuilder() + .withFromVertex(startEndpoint) + .withToVertex(endEndpoint) + .withGeometry(line) + .withName(name) + .withMeterLength(length) + .withPermission(areaPermissions) + .withBack(false) + .withArea(edgeList) + .withCarSpeed(carSpeed); if (!areaEntity.hasTag("name") && !areaEntity.hasTag("ref")) { - street.setHasBogusName(true); + streetEdgeBuilder.withBogusName(true); } if (areaEntity.isTagFalse("wheelchair")) { - street.setWheelchairAccessible(false); + streetEdgeBuilder.withWheelchairAccessible(false); } - street.setLink(OsmFilter.isLink(areaEntity)); + streetEdgeBuilder.withLink(OsmFilter.isLink(areaEntity)); label = "way (area) " + @@ -558,27 +558,26 @@ private Set createSegments( startEndpoint.getLabel(); name = namer.getNameForWay(areaEntity, label); - AreaEdge backStreet = AreaEdge.createAreaEdge( - endEndpoint, - startEndpoint, - line.reverse(), - name, - length, - areaPermissions, - true, - edgeList - ); - backStreet.setCarSpeed(carSpeed); + AreaEdgeBuilder backStreetEdgeBuilder = new AreaEdgeBuilder() + .withFromVertex(endEndpoint) + .withToVertex(startEndpoint) + .withGeometry(line.reverse()) + .withName(name) + .withMeterLength(length) + .withPermission(areaPermissions) + .withBack(true) + .withArea(edgeList) + .withCarSpeed(carSpeed); if (!areaEntity.hasTag("name") && !areaEntity.hasTag("ref")) { - backStreet.setHasBogusName(true); + backStreetEdgeBuilder.withBogusName(true); } if (areaEntity.isTagFalse("wheelchair")) { - backStreet.setWheelchairAccessible(false); + backStreetEdgeBuilder.withWheelchairAccessible(false); } - backStreet.setLink(OsmFilter.isLink(areaEntity)); + backStreetEdgeBuilder.withLink(OsmFilter.isLink(areaEntity)); if (!wayPropertiesCache.containsKey(areaEntity)) { WayProperties wayData = areaEntity @@ -588,6 +587,8 @@ private Set createSegments( wayPropertiesCache.put(areaEntity, wayData); } + AreaEdge street = streetEdgeBuilder.buildAndConnect(); + AreaEdge backStreet = backStreetEdgeBuilder.buildAndConnect(); normalizer.applyWayProperties( street, backStreet, diff --git a/src/main/java/org/opentripplanner/routing/graph/index/StreetIndex.java b/src/main/java/org/opentripplanner/routing/graph/index/StreetIndex.java index d29ccf5b64c..b9ab84bf4aa 100644 --- a/src/main/java/org/opentripplanner/routing/graph/index/StreetIndex.java +++ b/src/main/java/org/opentripplanner/routing/graph/index/StreetIndex.java @@ -29,6 +29,7 @@ import org.opentripplanner.street.model.edge.StreetEdge; import org.opentripplanner.street.model.edge.TemporaryFreeEdge; import org.opentripplanner.street.model.edge.TemporaryPartialStreetEdge; +import org.opentripplanner.street.model.edge.TemporaryPartialStreetEdgeBuilder; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TemporaryStreetLocation; import org.opentripplanner.street.model.vertex.TransitStopVertex; @@ -276,35 +277,33 @@ private static void createHalfLocationForTest( double lengthOut = street.getDistanceMeters() * (1 - lengthRatioIn); if (endVertex) { - TemporaryPartialStreetEdge temporaryPartialStreetEdge = TemporaryPartialStreetEdge.createTemporaryPartialStreetEdge( - street, - fromv, - base, - geometries.beginning(), - name, - lengthIn - ); - - temporaryPartialStreetEdge.setMotorVehicleNoThruTraffic(street.isMotorVehicleNoThruTraffic()); - temporaryPartialStreetEdge.setBicycleNoThruTraffic(street.isBicycleNoThruTraffic()); - temporaryPartialStreetEdge.setWalkNoThruTraffic(street.isWalkNoThruTraffic()); - temporaryPartialStreetEdge.setLink(street.isLink()); - tempEdges.addEdge(temporaryPartialStreetEdge); + TemporaryPartialStreetEdge tpse = new TemporaryPartialStreetEdgeBuilder() + .withParentEdge(street) + .withFromVertex(fromv) + .withToVertex(base) + .withGeometry(geometries.beginning()) + .withName(name) + .withMeterLength(lengthIn) + .withMotorVehicleNoThruTraffic(street.isMotorVehicleNoThruTraffic()) + .withBicycleNoThruTraffic(street.isBicycleNoThruTraffic()) + .withWalkNoThruTraffic(street.isWalkNoThruTraffic()) + .withLink(street.isLink()) + .buildAndConnect(); + tempEdges.addEdge(tpse); } else { - TemporaryPartialStreetEdge temporaryPartialStreetEdge = TemporaryPartialStreetEdge.createTemporaryPartialStreetEdge( - street, - base, - tov, - geometries.ending(), - name, - lengthOut - ); - - temporaryPartialStreetEdge.setLink(street.isLink()); - temporaryPartialStreetEdge.setMotorVehicleNoThruTraffic(street.isMotorVehicleNoThruTraffic()); - temporaryPartialStreetEdge.setBicycleNoThruTraffic(street.isBicycleNoThruTraffic()); - temporaryPartialStreetEdge.setWalkNoThruTraffic(street.isWalkNoThruTraffic()); - tempEdges.addEdge(temporaryPartialStreetEdge); + TemporaryPartialStreetEdge tpse = new TemporaryPartialStreetEdgeBuilder() + .withParentEdge(street) + .withFromVertex(base) + .withToVertex(tov) + .withGeometry(geometries.ending()) + .withName(name) + .withMeterLength(lengthOut) + .withLink(street.isLink()) + .withMotorVehicleNoThruTraffic(street.isMotorVehicleNoThruTraffic()) + .withBicycleNoThruTraffic(street.isBicycleNoThruTraffic()) + .withWalkNoThruTraffic(street.isWalkNoThruTraffic()) + .buildAndConnect(); + tempEdges.addEdge(tpse); } } diff --git a/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java b/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java index 669c1994ce8..bc0f8bfc64d 100644 --- a/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java +++ b/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java @@ -21,6 +21,7 @@ import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graph.index.EdgeSpatialIndex; import org.opentripplanner.street.model.edge.AreaEdge; +import org.opentripplanner.street.model.edge.AreaEdgeBuilder; import org.opentripplanner.street.model.edge.AreaEdgeList; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.NamedArea; @@ -639,42 +640,38 @@ private void createSegments( // if all joining edges are nothru, then the new edge should be as well var incomingNoThruModes = getNoThruModes(to.getIncoming()); var outgoingNoThruModes = getNoThruModes(to.getIncoming()); - - AreaEdge ae = AreaEdge.createAreaEdge( - from, - to, - line, - hit.getName(), - length, - hit.getPermission(), - false, - ael - ); + AreaEdgeBuilder areaEdgeBuilder = new AreaEdgeBuilder() + .withFromVertex(from) + .withToVertex(to) + .withGeometry(line) + .withName(hit.getName()) + .withMeterLength(length) + .withPermission(hit.getPermission()) + .withBack(false) + .withArea(ael); for (TraverseMode tm : outgoingNoThruModes) { - ae.setNoThruTraffic(tm); + areaEdgeBuilder.withNoThruTrafficTraverseMode(tm); } - + AreaEdge areaEdge = areaEdgeBuilder.buildAndConnect(); if (scope != Scope.PERMANENT) { - tempEdges.addEdge(ae); + tempEdges.addEdge(areaEdge); } - ae = - AreaEdge.createAreaEdge( - to, - from, - line.reverse(), - hit.getName(), - length, - hit.getPermission(), - true, - ael - ); + AreaEdgeBuilder reverseAreaEdgeBuilder = new AreaEdgeBuilder() + .withFromVertex(to) + .withToVertex(from) + .withGeometry(line.reverse()) + .withName(hit.getName()) + .withMeterLength(length) + .withPermission(hit.getPermission()) + .withBack(true) + .withArea(ael); for (TraverseMode tm : incomingNoThruModes) { - ae.setNoThruTraffic(tm); + reverseAreaEdgeBuilder.withNoThruTrafficTraverseMode(tm); } - + AreaEdge reverseAreaEdge = reverseAreaEdgeBuilder.buildAndConnect(); if (scope != Scope.PERMANENT) { - tempEdges.addEdge(ae); + tempEdges.addEdge(reverseAreaEdge); } } } diff --git a/src/main/java/org/opentripplanner/street/model/edge/AreaEdge.java b/src/main/java/org/opentripplanner/street/model/edge/AreaEdge.java index 7bb3ace9f5e..9a16c9c85ff 100644 --- a/src/main/java/org/opentripplanner/street/model/edge/AreaEdge.java +++ b/src/main/java/org/opentripplanner/street/model/edge/AreaEdge.java @@ -1,69 +1,12 @@ package org.opentripplanner.street.model.edge; -import org.locationtech.jts.geom.LineString; -import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.street.model.StreetTraversalPermission; -import org.opentripplanner.street.model.vertex.IntersectionVertex; - public class AreaEdge extends StreetEdge { private final AreaEdgeList area; - private AreaEdge( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, - LineString geometry, - I18NString name, - double length, - StreetTraversalPermission permissions, - boolean back, - AreaEdgeList area - ) { - super(startEndpoint, endEndpoint, geometry, name, length, permissions, back); - this.area = area; - } - - // constructor without precomputed length - private AreaEdge( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, - LineString geometry, - I18NString name, - StreetTraversalPermission permissions, - boolean back, - AreaEdgeList area - ) { - super(startEndpoint, endEndpoint, geometry, name, permissions, back); - this.area = area; - } - - public static AreaEdge createAreaEdge( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, - LineString geometry, - I18NString name, - double length, - StreetTraversalPermission permissions, - boolean back, - AreaEdgeList area - ) { - return connectToGraph( - new AreaEdge(startEndpoint, endEndpoint, geometry, name, length, permissions, back, area) - ); - } - - public static AreaEdge createAreaEdge( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, - LineString geometry, - I18NString name, - StreetTraversalPermission permissions, - boolean back, - AreaEdgeList area - ) { - return connectToGraph( - new AreaEdge(startEndpoint, endEndpoint, geometry, name, permissions, back, area) - ); + protected AreaEdge(AreaEdgeBuilder builder) { + super(builder); + this.area = builder.area(); } public AreaEdgeList getArea() { diff --git a/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java b/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java new file mode 100644 index 00000000000..efabefa7cea --- /dev/null +++ b/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java @@ -0,0 +1,32 @@ +package org.opentripplanner.street.model.edge; + +import org.opentripplanner.street.model.vertex.IntersectionVertex; + +public class AreaEdgeBuilder extends StreetEdgeBuilder { + + private AreaEdgeList area; + + @Override + public AreaEdge buildAndConnect() { + return Edge.connectToGraph(new AreaEdge(this)); + } + + @Override + public IntersectionVertex fromVertex() { + return (IntersectionVertex) super.fromVertex(); + } + + @Override + public IntersectionVertex toVertex() { + return (IntersectionVertex) super.toVertex(); + } + + public AreaEdgeList area() { + return area; + } + + public AreaEdgeBuilder withArea(AreaEdgeList area) { + this.area = area; + return this; + } +} diff --git a/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java b/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java index b9c7205792c..907c4eccf78 100644 --- a/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java +++ b/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -17,7 +18,6 @@ import org.opentripplanner.framework.geometry.SphericalDistanceLibrary; import org.opentripplanner.framework.geometry.SplitLineString; import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.framework.lang.BitSetUtils; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; import org.opentripplanner.routing.linking.DisposableEdgeCollection; @@ -51,21 +51,21 @@ public class StreetEdge private static final Logger LOG = LoggerFactory.getLogger(StreetEdge.class); private static final double GREENWAY_SAFETY_FACTOR = 0.1; - // TODO(flamholz): do something smarter with the car speed here. - public static final float DEFAULT_CAR_SPEED = 11.2f; + /** If you have more than 16 flags, increase flags to short or int */ - private static final int BACK_FLAG_INDEX = 0; - private static final int ROUNDABOUT_FLAG_INDEX = 1; - private static final int HASBOGUSNAME_FLAG_INDEX = 2; - private static final int MOTOR_VEHICLE_NOTHRUTRAFFIC = 3; - private static final int STAIRS_FLAG_INDEX = 4; - private static final int SLOPEOVERRIDE_FLAG_INDEX = 5; - private static final int WHEELCHAIR_ACCESSIBLE_FLAG_INDEX = 6; - private static final int BICYCLE_NOTHRUTRAFFIC = 7; - private static final int WALK_NOTHRUTRAFFIC = 8; - private static final int CLASS_LINK = 9; + static final int BACK_FLAG_INDEX = 0; + static final int ROUNDABOUT_FLAG_INDEX = 1; + static final int HASBOGUSNAME_FLAG_INDEX = 2; + static final int MOTOR_VEHICLE_NOTHRUTRAFFIC = 3; + static final int STAIRS_FLAG_INDEX = 4; + static final int SLOPEOVERRIDE_FLAG_INDEX = 5; + static final int WHEELCHAIR_ACCESSIBLE_FLAG_INDEX = 6; + static final int BICYCLE_NOTHRUTRAFFIC = 7; + static final int WALK_NOTHRUTRAFFIC = 8; + static final int CLASS_LINK = 9; private StreetEdgeCostExtension costExtension; + /** back, roundabout, stairs, ... */ private short flags; @@ -75,21 +75,21 @@ public class StreetEdge * double-precision floating point meters. Someday we might want to convert everything to fixed * point representations. */ - private int length_mm; + private final int length_mm; /** * bicycleSafetyWeight = length * bicycleSafetyFactor. For example, a 100m street with a safety * factor of 2.0 will be considered in term of safety cost as the same as a 200m street with a * safety factor of 1.0. */ - protected float bicycleSafetyFactor; + private float bicycleSafetyFactor; /** * walkSafetyFactor = length * walkSafetyFactor. For example, a 100m street with a safety * factor of 2.0 will be considered in term of safety cost as the same as a 200m street with a * safety factor of 1.0. */ - protected float walkSafetyFactor; + private float walkSafetyFactor; private byte[] compactGeometry; @@ -131,95 +131,23 @@ public class StreetEdge */ private List turnRestrictions = Collections.emptyList(); - StreetEdge( - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - double length, - StreetTraversalPermission permission, - boolean back - ) { - super(v1, v2); - this.setBack(back); - this.setGeometry(geometry); - this.length_mm = (int) (length * 1000); // CONVERT FROM FLOAT METERS TO FIXED MILLIMETERS - if (this.length_mm == 0) { - LOG.warn( - "StreetEdge {} from {} to {} has length of 0. This is usually an error.", - name, - v1, - v2 - ); - } - this.bicycleSafetyFactor = 1.0f; - this.walkSafetyFactor = 1.0f; - this.name = name; - this.setPermission(permission); - this.setCarSpeed(DEFAULT_CAR_SPEED); - this.setWheelchairAccessible(true); // accessible by default - LineStringInOutAngles lineStringInOutAngles = LineStringInOutAngles.of(geometry); + protected StreetEdge(StreetEdgeBuilder builder) { + super(builder.fromVertex(), builder.toVertex()); + this.flags = builder.getFlags(); + this.setGeometry(builder.geometry()); + this.length_mm = computeLength(builder); + this.setBicycleSafetyFactor(builder.bicycleSafetyFactor()); + this.setWalkSafetyFactor(builder.walkSafetyFactor()); + this.name = builder.name(); + this.setPermission(builder.permission()); + this.setCarSpeed(builder.carSpeed()); + LineStringInOutAngles lineStringInOutAngles = LineStringInOutAngles.of(builder.geometry()); inAngle = lineStringInOutAngles.inAngle(); outAngle = lineStringInOutAngles.outAngle(); } - //For testing only - private StreetEdge( - StreetVertex v1, - StreetVertex v2, - LineString geometry, - String name, - double length, - StreetTraversalPermission permission, - boolean back - ) { - this(v1, v2, geometry, new NonLocalizedString(name), length, permission, back); - } - - StreetEdge( - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - StreetTraversalPermission permission, - boolean back - ) { - this(v1, v2, geometry, name, SphericalDistanceLibrary.length(geometry), permission, back); - } - - public static StreetEdge createStreetEdge( - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - double length, - StreetTraversalPermission permission, - boolean back - ) { - return connectToGraph(new StreetEdge(v1, v2, geometry, name, length, permission, back)); - } - - public static StreetEdge createStreetEdge( - StreetVertex v1, - StreetVertex v2, - LineString geometry, - String name, - double length, - StreetTraversalPermission permission, - boolean back - ) { - return connectToGraph(new StreetEdge(v1, v2, geometry, name, length, permission, back)); - } - - public static StreetEdge createStreetEdge( - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - StreetTraversalPermission permission, - boolean back - ) { - return connectToGraph(new StreetEdge(v1, v2, geometry, name, permission, back)); + public StreetEdgeBuilder toBuilder() { + return new StreetEdgeBuilder<>(this); } /** @@ -287,20 +215,6 @@ public boolean isNoThruTraffic(TraverseMode traverseMode) { }; } - public void setNoThruTraffic(TraverseMode traverseMode) { - switch (traverseMode) { - case WALK: - setWalkNoThruTraffic(true); - break; - case BICYCLE, SCOOTER: - setBicycleNoThruTraffic(true); - break; - case CAR, FLEX: - setMotorVehicleNoThruTraffic(true); - break; - } - } - /** * Calculate the speed appropriately given the RouteRequest and traverseMode. */ @@ -520,66 +434,6 @@ else if (s0.currentMode() == TraverseMode.BICYCLE) { return State.ofNullable(state); } - /** - * A very special case: an arriveBy rental search has started in a no-drop-off zone - * we don't know yet which rental network we will end up using. - *

- * So we speculatively assume that we can rent any by setting the network in the state data - * to null. - *

- * When we then leave the no drop off zone on foot we generate a state for each network that the - * zone applies to where we pick up a vehicle with a specific network. - */ - @Nonnull - private State[] splitStatesAfterHavingExitedNoDropOffZoneWhenReverseSearching(State s0) { - var networks = Stream.concat( - // null is a special rental network that speculatively assumes that you can take any vehicle - // you have to check in the rental edge if this has search has been started in a no-drop off zone - Stream.of((String) null), - tov.rentalRestrictions().noDropOffNetworks().stream() - ); - - var states = networks.map(network -> { - var edit = doTraverse(s0, TraverseMode.WALK, false); - if (edit != null) { - edit.dropFloatingVehicle(s0.vehicleRentalFormFactor(), network, s0.getRequest().arriveBy()); - if (network != null) { - edit.resetStartedInNoDropOffZone(); - } - return edit.makeState(); - } - return null; - }); - return State.ofStream(states); - } - - /** - * This is the state that starts a backwards search inside a restricted zone - * (no drop off, no traversal or outside business area) and is walking towards finding a rental - * vehicle. Once we are leaving a geofencing zone or are entering a business area we want to - * speculatively pick up a vehicle a ride towards an edge where there is one parked. - */ - private boolean leavesZoneWithRentalRestrictionsWhenHavingRented(State s0) { - return ( - s0.getVehicleRentalState() == VehicleRentalState.HAVE_RENTED && - !fromv.rentalRestrictions().hasRestrictions() && - tov.rentalRestrictions().hasRestrictions() - ); - } - - /** - * If the reverse search has started in a no-drop off rental zone and you are exiting - * it . - */ - private boolean hasStartedWalkingInNoDropOffZoneAndIsExitingIt(State s0) { - return ( - s0.currentMode() == TraverseMode.WALK && - !s0.stateData.noRentalDropOffZonesAtStartOfReverseSearch.isEmpty() && - fromv.rentalRestrictions().noDropOffNetworks().isEmpty() && - !tov.rentalRestrictions().noDropOffNetworks().isEmpty() - ); - } - /** * Gets non-localized I18NString (Used when splitting edges) * @@ -628,22 +482,6 @@ public void removeRentalExtension(RentalRestrictionExtension ext) { tov.removeRentalRestriction(ext); } - private void setGeometry(LineString geometry) { - this.compactGeometry = - CompactLineStringUtils.compactLineString( - fromv.getLon(), - fromv.getLat(), - tov.getLon(), - tov.getLat(), - isBack() ? geometry.reverse() : geometry, - isBack() - ); - } - - public void setRoundabout(boolean roundabout) { - flags = BitSetUtils.set(flags, ROUNDABOUT_FLAG_INDEX, roundabout); - } - @Override public StreetEdge clone() { try { @@ -694,16 +532,12 @@ public boolean isWheelchairAccessible() { return BitSetUtils.get(flags, WHEELCHAIR_ACCESSIBLE_FLAG_INDEX); } - public void setWheelchairAccessible(boolean wheelchairAccessible) { - flags = BitSetUtils.set(flags, WHEELCHAIR_ACCESSIBLE_FLAG_INDEX, wheelchairAccessible); - } - public StreetTraversalPermission getPermission() { return permission; } public void setPermission(StreetTraversalPermission permission) { - this.permission = permission; + this.permission = Objects.requireNonNull(permission); } /** @@ -714,14 +548,6 @@ public boolean isBack() { return BitSetUtils.get(flags, BACK_FLAG_INDEX); } - public void setBack(boolean back) { - flags = BitSetUtils.set(flags, BACK_FLAG_INDEX, back); - } - - public void setHasBogusName(boolean hasBogusName) { - flags = BitSetUtils.set(flags, HASBOGUSNAME_FLAG_INDEX, hasBogusName); - } - public boolean isWalkNoThruTraffic() { return BitSetUtils.get(flags, WALK_NOTHRUTRAFFIC); } @@ -753,10 +579,6 @@ public boolean isStairs() { return BitSetUtils.get(flags, STAIRS_FLAG_INDEX); } - public void setStairs(boolean stairs) { - flags = BitSetUtils.set(flags, STAIRS_FLAG_INDEX, stairs); - } - /** * The edge is part of an osm way, which is of type link */ @@ -764,7 +586,7 @@ public boolean isLink() { return BitSetUtils.get(flags, CLASS_LINK); } - public void setLink(boolean link) { + private void setLink(boolean link) { flags = BitSetUtils.set(flags, CLASS_LINK, link); } @@ -772,7 +594,7 @@ public float getCarSpeed() { return carSpeed; } - public void setCarSpeed(float carSpeed) { + private void setCarSpeed(float carSpeed) { this.carSpeed = carSpeed; } @@ -780,10 +602,6 @@ public boolean isSlopeOverride() { return BitSetUtils.get(flags, SLOPEOVERRIDE_FLAG_INDEX); } - public void setSlopeOverride(boolean slopeOverride) { - flags = BitSetUtils.set(flags, SLOPEOVERRIDE_FLAG_INDEX, slopeOverride); - } - /** * Return the azimuth of the first segment in this edge in integer degrees clockwise from South. * TODO change everything to clockwise from North @@ -815,73 +633,69 @@ public void addRentalRestriction(RentalRestrictionExtension ext) { public SplitStreetEdge splitDestructively(SplitterVertex v) { SplitLineString geoms = GeometryUtils.splitGeometryAtPoint(getGeometry(), v.getCoordinate()); - StreetEdge e1 = createStreetEdge( - (StreetVertex) fromv, - v, - geoms.beginning(), - name, - permission, - this.isBack() - ); - StreetEdge e2 = createStreetEdge( - v, - (StreetVertex) tov, - geoms.ending(), - name, - permission, - this.isBack() - ); + StreetEdgeBuilder seb1 = new StreetEdgeBuilder<>() + .withFromVertex((StreetVertex) fromv) + .withToVertex(v) + .withGeometry(geoms.beginning()) + .withName(name) + .withPermission(permission) + .withBack(isBack()); + + StreetEdgeBuilder seb2 = new StreetEdgeBuilder<>() + .withFromVertex(v) + .withToVertex((StreetVertex) tov) + .withGeometry(geoms.ending()) + .withName(name) + .withPermission(permission) + .withBack(isBack()); // we have this code implemented in both directions, because splits are fudged half a millimeter // when the length of this is odd. We want to make sure the lengths of the split streets end up // exactly the same as their backStreets so that if they are split again the error does not accumulate // and so that the order in which they are split does not matter. + int l1 = defaultMillimeterLength(geoms.beginning()); + int l2 = defaultMillimeterLength(geoms.ending()); if (!isBack()) { // cast before the divide so that the sum is promoted - double frac = (double) e1.length_mm / (e1.length_mm + e2.length_mm); - e1.length_mm = (int) (length_mm * frac); - e2.length_mm = length_mm - e1.length_mm; + double frac = (double) l1 / (l1 + l2); + l1 = (int) (length_mm * frac); + l2 = length_mm - l1; } else { // cast before the divide so that the sum is promoted - double frac = (double) e2.length_mm / (e1.length_mm + e2.length_mm); - e2.length_mm = (int) (length_mm * frac); - e1.length_mm = length_mm - e2.length_mm; + double frac = (double) l2 / (l1 + l2); + l2 = (int) (length_mm * frac); + l1 = length_mm - l2; } // TODO: better handle this temporary fix to handle bad edge distance calculation - if (e1.length_mm <= 0) { + if (l1 <= 0) { LOG.error( "Edge 1 ({}) split at vertex at {},{} has length {} mm. Setting to 1 mm.", - e1.getName(), + name, v.getLat(), v.getLon(), - e1.length_mm + l1 ); - e1.length_mm = 1; + l1 = 1; } - if (e2.length_mm <= 0) { + if (l2 <= 0) { LOG.error( "Edge 2 ({}) split at vertex at {},{} has length {} mm. Setting to 1 mm.", - e2.getName(), + name, v.getLat(), v.getLon(), - e2.length_mm + l2 ); - e2.length_mm = 1; + l2 = 1; } - if (e1.length_mm < 0 || e2.length_mm < 0) { - e1.tov.removeIncoming(e1); - e1.fromv.removeOutgoing(e1); - e2.tov.removeIncoming(e2); - e2.fromv.removeOutgoing(e2); - throw new IllegalStateException("Split street is longer than original street!"); - } + StreetEdge se1 = seb1.withMilliMeterLength(l1).buildAndConnect(); + StreetEdge se2 = seb2.withMilliMeterLength(l2).buildAndConnect(); - copyPropertiesToSplitEdge(e1, 0, e1.getDistanceMeters()); - copyPropertiesToSplitEdge(e2, e1.getDistanceMeters(), getDistanceMeters()); + copyPropertiesToSplitEdge(se1, 0, se1.getDistanceMeters()); + copyPropertiesToSplitEdge(se2, se1.getDistanceMeters(), getDistanceMeters()); - var splitEdges = new SplitStreetEdge(e1, e2); + var splitEdges = new SplitStreetEdge(se1, se2); copyRestrictionsToSplitEdges(this, splitEdges); return splitEdges; } @@ -899,27 +713,27 @@ public SplitStreetEdge splitNonDestructively( if (direction == LinkingDirection.OUTGOING || direction == LinkingDirection.BOTH_WAYS) { e1 = - TemporaryPartialStreetEdge.createTemporaryPartialStreetEdge( - this, - (StreetVertex) fromv, - v, - geoms.beginning(), - name, - this.isBack() - ); + new TemporaryPartialStreetEdgeBuilder() + .withParentEdge(this) + .withFromVertex((StreetVertex) fromv) + .withToVertex(v) + .withGeometry(geoms.beginning()) + .withName(name) + .withBack(isBack()) + .buildAndConnect(); copyPropertiesToSplitEdge(e1, 0, e1.getDistanceMeters()); tempEdges.addEdge(e1); } if (direction == LinkingDirection.INCOMING || direction == LinkingDirection.BOTH_WAYS) { e2 = - TemporaryPartialStreetEdge.createTemporaryPartialStreetEdge( - this, - v, - (StreetVertex) tov, - geoms.ending(), - name, - this.isBack() - ); + new TemporaryPartialStreetEdgeBuilder() + .withParentEdge(this) + .withFromVertex(v) + .withToVertex((StreetVertex) tov) + .withGeometry(geoms.ending()) + .withName(name) + .withBack(isBack()) + .buildAndConnect(); copyPropertiesToSplitEdge( e2, getDistanceMeters() - e2.getDistanceMeters(), @@ -958,14 +772,14 @@ public Optional createPartialEdge(StreetVertex from, StreetVertex to) { double lengthRatio = partial.getLength() / parent.getLength(); double length = getDistanceMeters() * lengthRatio; - var tempEdge = TemporaryPartialStreetEdge.createTemporaryPartialStreetEdge( - this, - from, - to, - partial, - getName(), - length - ); + var tempEdge = new TemporaryPartialStreetEdgeBuilder() + .withParentEdge(this) + .withFromVertex(from) + .withToVertex(to) + .withGeometry(partial) + .withName(getName()) + .withMeterLength(length) + .buildAndConnect(); copyPropertiesToSplitEdge(tempEdge, start, start + length); return Optional.of(tempEdge); } else { @@ -1080,6 +894,14 @@ protected void setElevationExtensionUsingParent( StreetElevationExtension.addToEdge(this, profile, true); } + short getFlags() { + return flags; + } + + int getMillimeterLength() { + return length_mm; + } + /** * Copy restrictions having former edge as from to appropriate split edge, as well as restrictions * on incoming edges. @@ -1130,6 +952,97 @@ private static void applyRestrictionsToNewEdge( fromEdge.addTurnRestriction(splitTurnRestriction); } + private int computeLength(StreetEdgeBuilder builder) { + int lengthInMillimeter = builder.hasDefaultLength() + ? defaultMillimeterLength(builder.geometry()) + : builder.millimeterLength(); + if (lengthInMillimeter == 0) { + LOG.warn( + "StreetEdge {} from {} to {} has length of 0. This is usually an error.", + name, + builder.fromVertex(), + builder.toVertex() + ); + } + return lengthInMillimeter; + } + + static int defaultMillimeterLength(LineString geometry) { + return (int) (SphericalDistanceLibrary.length(geometry) * 1000); + } + + /** + * A very special case: an arriveBy rental search has started in a no-drop-off zone + * we don't know yet which rental network we will end up using. + *

+ * So we speculatively assume that we can rent any by setting the network in the state data + * to null. + *

+ * When we then leave the no drop off zone on foot we generate a state for each network that the + * zone applies to where we pick up a vehicle with a specific network. + */ + @Nonnull + private State[] splitStatesAfterHavingExitedNoDropOffZoneWhenReverseSearching(State s0) { + var networks = Stream.concat( + // null is a special rental network that speculatively assumes that you can take any vehicle + // you have to check in the rental edge if this has search has been started in a no-drop off zone + Stream.of((String) null), + tov.rentalRestrictions().noDropOffNetworks().stream() + ); + + var states = networks.map(network -> { + var edit = doTraverse(s0, TraverseMode.WALK, false); + if (edit != null) { + edit.dropFloatingVehicle(s0.vehicleRentalFormFactor(), network, s0.getRequest().arriveBy()); + if (network != null) { + edit.resetStartedInNoDropOffZone(); + } + return edit.makeState(); + } + return null; + }); + return State.ofStream(states); + } + + /** + * This is the state that starts a backwards search inside a restricted zone + * (no drop off, no traversal or outside business area) and is walking towards finding a rental + * vehicle. Once we are leaving a geofencing zone or are entering a business area we want to + * speculatively pick up a vehicle a ride towards an edge where there is one parked. + */ + private boolean leavesZoneWithRentalRestrictionsWhenHavingRented(State s0) { + return ( + s0.getVehicleRentalState() == VehicleRentalState.HAVE_RENTED && + !fromv.rentalRestrictions().hasRestrictions() && + tov.rentalRestrictions().hasRestrictions() + ); + } + + /** + * If the reverse search has started in a no-drop off rental zone and you are exiting + * it . + */ + private boolean hasStartedWalkingInNoDropOffZoneAndIsExitingIt(State s0) { + return ( + s0.currentMode() == TraverseMode.WALK && + !s0.stateData.noRentalDropOffZonesAtStartOfReverseSearch.isEmpty() && + fromv.rentalRestrictions().noDropOffNetworks().isEmpty() && + !tov.rentalRestrictions().noDropOffNetworks().isEmpty() + ); + } + + private void setGeometry(LineString geometry) { + this.compactGeometry = + CompactLineStringUtils.compactLineString( + fromv.getLon(), + fromv.getLat(), + tov.getLon(), + tov.getLat(), + isBack() ? geometry.reverse() : geometry, + isBack() + ); + } + private double getDistanceWithElevation() { return hasElevationExtension() ? elevationExtension.getDistanceWithElevation() diff --git a/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java b/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java new file mode 100644 index 00000000000..61917d16d89 --- /dev/null +++ b/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java @@ -0,0 +1,232 @@ +package org.opentripplanner.street.model.edge; + +import static org.opentripplanner.street.model.edge.StreetEdge.BACK_FLAG_INDEX; +import static org.opentripplanner.street.model.edge.StreetEdge.BICYCLE_NOTHRUTRAFFIC; +import static org.opentripplanner.street.model.edge.StreetEdge.CLASS_LINK; +import static org.opentripplanner.street.model.edge.StreetEdge.HASBOGUSNAME_FLAG_INDEX; +import static org.opentripplanner.street.model.edge.StreetEdge.MOTOR_VEHICLE_NOTHRUTRAFFIC; +import static org.opentripplanner.street.model.edge.StreetEdge.ROUNDABOUT_FLAG_INDEX; +import static org.opentripplanner.street.model.edge.StreetEdge.SLOPEOVERRIDE_FLAG_INDEX; +import static org.opentripplanner.street.model.edge.StreetEdge.STAIRS_FLAG_INDEX; +import static org.opentripplanner.street.model.edge.StreetEdge.WALK_NOTHRUTRAFFIC; +import static org.opentripplanner.street.model.edge.StreetEdge.WHEELCHAIR_ACCESSIBLE_FLAG_INDEX; + +import org.locationtech.jts.geom.LineString; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.framework.lang.BitSetUtils; +import org.opentripplanner.street.model.StreetTraversalPermission; +import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.search.TraverseMode; + +public class StreetEdgeBuilder> { + + // TODO(flamholz): do something smarter with the car speed here. + public static final float DEFAULT_CAR_SPEED = 11.2f; + public static final float DEFAULT_WALK_SAFETY_FACTOR = 1.0f; + private static final float DEFAULT_BICYCLE_SAFETY_FACTOR = 1.0f; + + private StreetVertex from; + private StreetVertex to; + private LineString geometry; + private I18NString name; + private int millimeterLength; + private StreetTraversalPermission permission; + private boolean defaultLength; + private float carSpeed; + private float walkSafetyFactor; + private float bicycleSafetyFactor; + private short flags; + + public StreetEdgeBuilder() { + this.defaultLength = true; + this.walkSafetyFactor = DEFAULT_WALK_SAFETY_FACTOR; + this.bicycleSafetyFactor = DEFAULT_BICYCLE_SAFETY_FACTOR; + this.carSpeed = DEFAULT_CAR_SPEED; + withWheelchairAccessible(true); + } + + public StreetEdgeBuilder(StreetEdge original) { + this.from = (StreetVertex) original.getFromVertex(); + this.to = (StreetVertex) original.getToVertex(); + this.geometry = original.getGeometry(); + this.name = original.getName(); + this.millimeterLength = original.getMillimeterLength(); + this.permission = original.getPermission(); + this.defaultLength = false; + this.carSpeed = original.getCarSpeed(); + this.walkSafetyFactor = original.getWalkSafetyFactor(); + this.bicycleSafetyFactor = original.getBicycleSafetyFactor(); + this.flags = original.getFlags(); + } + + public StreetEdge buildAndConnect() { + return Edge.connectToGraph(new StreetEdge(this)); + } + + public StreetVertex fromVertex() { + return from; + } + + public B withFromVertex(StreetVertex from) { + this.from = from; + return instance(); + } + + public StreetVertex toVertex() { + return to; + } + + public B withToVertex(StreetVertex to) { + this.to = to; + return instance(); + } + + public LineString geometry() { + return geometry; + } + + public B withGeometry(LineString geometry) { + this.geometry = geometry; + return instance(); + } + + public I18NString name() { + return name; + } + + public B withName(I18NString name) { + this.name = name; + return instance(); + } + + public B withName(String name) { + this.name = new NonLocalizedString(name); + return instance(); + } + + public int millimeterLength() { + return millimeterLength; + } + + public B withMeterLength(double length) { + return withMilliMeterLength((int) (length * 1000)); + } + + public B withMilliMeterLength(int length) { + this.millimeterLength = length; + this.defaultLength = false; + return instance(); + } + + public boolean hasDefaultLength() { + return defaultLength; + } + + public StreetTraversalPermission permission() { + return permission; + } + + public B withPermission(StreetTraversalPermission permission) { + this.permission = permission; + return instance(); + } + + public float carSpeed() { + return carSpeed; + } + + public B withCarSpeed(float carSpeed) { + this.carSpeed = carSpeed; + return instance(); + } + + public float walkSafetyFactor() { + return walkSafetyFactor; + } + + public B withWalkSafetyFactor(float walkSafetyFactor) { + this.walkSafetyFactor = walkSafetyFactor; + return instance(); + } + + public float bicycleSafetyFactor() { + return bicycleSafetyFactor; + } + + public B withBicycleSafetyFactor(float bicycleSafetyFactor) { + this.bicycleSafetyFactor = bicycleSafetyFactor; + return instance(); + } + + public short getFlags() { + return flags; + } + + public B withBack(boolean back) { + flags = BitSetUtils.set(flags, BACK_FLAG_INDEX, back); + return instance(); + } + + public B withLink(boolean link) { + flags = BitSetUtils.set(flags, CLASS_LINK, link); + return instance(); + } + + public B withBogusName(boolean hasBogusName) { + flags = BitSetUtils.set(flags, HASBOGUSNAME_FLAG_INDEX, hasBogusName); + return instance(); + } + + public B withStairs(boolean stairs) { + flags = BitSetUtils.set(flags, STAIRS_FLAG_INDEX, stairs); + return instance(); + } + + public B withWheelchairAccessible(boolean wheelchairAccessible) { + flags = BitSetUtils.set(flags, WHEELCHAIR_ACCESSIBLE_FLAG_INDEX, wheelchairAccessible); + return instance(); + } + + public B withSlopeOverride(boolean slopeOverride) { + flags = BitSetUtils.set(flags, SLOPEOVERRIDE_FLAG_INDEX, slopeOverride); + return instance(); + } + + public B withRoundabout(boolean roundabout) { + flags = BitSetUtils.set(flags, ROUNDABOUT_FLAG_INDEX, roundabout); + return instance(); + } + + public B withMotorVehicleNoThruTraffic(boolean motorVehicleNoThruTraffic) { + flags = BitSetUtils.set(flags, MOTOR_VEHICLE_NOTHRUTRAFFIC, motorVehicleNoThruTraffic); + return instance(); + } + + public B withBicycleNoThruTraffic(boolean bicycleNoThruTraffic) { + flags = BitSetUtils.set(flags, BICYCLE_NOTHRUTRAFFIC, bicycleNoThruTraffic); + return instance(); + } + + public B withWalkNoThruTraffic(boolean walkNoThruTraffic) { + flags = BitSetUtils.set(flags, WALK_NOTHRUTRAFFIC, walkNoThruTraffic); + return instance(); + } + + public B withNoThruTrafficTraverseMode(TraverseMode noThruTrafficTraverseMode) { + if (noThruTrafficTraverseMode == null) { + return instance(); + } + switch (noThruTrafficTraverseMode) { + case WALK -> withWalkNoThruTraffic(true); + case BICYCLE, SCOOTER -> withBicycleNoThruTraffic(true); + case CAR, FLEX -> withMotorVehicleNoThruTraffic(true); + } + return instance(); + } + + @SuppressWarnings("unchecked") + final B instance() { + return (B) this; + } +} diff --git a/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdge.java b/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdge.java index eb1e5b4f182..09846bb3aa1 100644 --- a/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdge.java +++ b/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdge.java @@ -2,8 +2,6 @@ import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.LineString; -import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.street.model.vertex.StreetVertex; public final class TemporaryPartialStreetEdge extends StreetEdge implements TemporaryEdge { @@ -21,52 +19,18 @@ public final class TemporaryPartialStreetEdge extends StreetEdge implements Temp * is negative, a new length is calculated from the geometry. The elevation data is calculated * using the 'parentEdge' and given 'length'. */ - private TemporaryPartialStreetEdge( - StreetEdge parentEdge, - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - double length - ) { - super(v1, v2, geometry, name, length, parentEdge.getPermission(), false); - v1.addRentalRestriction(parentEdge.getFromVertex().rentalRestrictions()); - v2.addRentalRestriction(parentEdge.getToVertex().rentalRestrictions()); - this.parentEdge = parentEdge; + TemporaryPartialStreetEdge(TemporaryPartialStreetEdgeBuilder builder) { + super(builder); + builder + .fromVertex() + .addRentalRestriction(builder.parentEdge().getFromVertex().rentalRestrictions()); + builder + .toVertex() + .addRentalRestriction(builder.parentEdge().getToVertex().rentalRestrictions()); + this.parentEdge = builder.parentEdge(); this.geometry = super.getGeometry(); } - /** - * Create a new partial street edge along the given 'parentEdge' from 'v1' to 'v2'. The length is - * calculated using the provided geometry. The elevation data is calculated using the 'parentEdge' - * and the calculated 'length'. - */ - private TemporaryPartialStreetEdge( - StreetEdge parentEdge, - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - boolean back - ) { - super(v1, v2, geometry, name, parentEdge.getPermission(), back); - this.parentEdge = parentEdge; - this.geometry = super.getGeometry(); - } - - public static TemporaryPartialStreetEdge createTemporaryPartialStreetEdge( - StreetEdge parentEdge, - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - double length - ) { - return connectToGraph( - new TemporaryPartialStreetEdge(parentEdge, v1, v2, geometry, name, length) - ); - } - /** * This implementation makes it so that TurnRestrictions on the parent edge are applied to this * edge as well. @@ -144,15 +108,4 @@ public int getInAngle() { public int getOutAngle() { return parentEdge.getInAngle(); } - - static TemporaryPartialStreetEdge createTemporaryPartialStreetEdge( - StreetEdge parentEdge, - StreetVertex v1, - StreetVertex v2, - LineString geometry, - I18NString name, - boolean back - ) { - return connectToGraph(new TemporaryPartialStreetEdge(parentEdge, v1, v2, geometry, name, back)); - } } diff --git a/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilder.java b/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilder.java new file mode 100644 index 00000000000..2f9bb969cbc --- /dev/null +++ b/src/main/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilder.java @@ -0,0 +1,22 @@ +package org.opentripplanner.street.model.edge; + +public class TemporaryPartialStreetEdgeBuilder + extends StreetEdgeBuilder { + + private StreetEdge parentEdge; + + @Override + public TemporaryPartialStreetEdge buildAndConnect() { + return Edge.connectToGraph(new TemporaryPartialStreetEdge(this)); + } + + public StreetEdge parentEdge() { + return parentEdge; + } + + public TemporaryPartialStreetEdgeBuilder withParentEdge(StreetEdge parentEdge) { + this.parentEdge = parentEdge; + withPermission(parentEdge.getPermission()); + return this; + } +} diff --git a/src/test/java/org/opentripplanner/graph_builder/linking/LinkStopToPlatformTest.java b/src/test/java/org/opentripplanner/graph_builder/linking/LinkStopToPlatformTest.java index e72e21d4042..2f02c738b66 100644 --- a/src/test/java/org/opentripplanner/graph_builder/linking/LinkStopToPlatformTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/linking/LinkStopToPlatformTest.java @@ -20,6 +20,7 @@ import org.opentripplanner.routing.linking.VertexLinker; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.AreaEdge; +import org.opentripplanner.street.model.edge.AreaEdgeBuilder; import org.opentripplanner.street.model.edge.AreaEdgeList; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.NamedArea; @@ -84,25 +85,28 @@ private Graph prepareTest(Coordinate[] platform, int[] visible, Coordinate[] sto namedArea.setOriginalEdges(polygon); areaEdgeList.addArea(namedArea); - ArrayList edges = new ArrayList<>(); - for (int i = 0; i < platform.length; i++) { int next_i = (i + 1) % platform.length; - var edge1 = createAreaEdge(vertices.get(i), vertices.get(next_i), areaEdgeList, "edge " + i); - var edge2 = createAreaEdge( + var edgeBuilder1 = createAreaEdge( + vertices.get(i), + vertices.get(next_i), + areaEdgeList, + "edge " + i + ); + var edgeBuilder2 = createAreaEdge( vertices.get(next_i), vertices.get(i), areaEdgeList, "edge " + String.valueOf(i + platform.length) ); - edges.add(edge1); - edges.add(edge2); // make one corner surrounded by walk nothru edges if (i < 2) { - edge1.setWalkNoThruTraffic(true); - edge2.setWalkNoThruTraffic(true); + edgeBuilder1.withWalkNoThruTraffic(true); + edgeBuilder2.withWalkNoThruTraffic(true); } + edgeBuilder1.buildAndConnect(); + edgeBuilder2.buildAndConnect(); } RegularStop[] transitStops = new RegularStop[stops.length]; @@ -282,7 +286,7 @@ private void linkStops(Graph graph) { } } - private AreaEdge createAreaEdge( + private AreaEdgeBuilder createAreaEdge( IntersectionVertex v1, IntersectionVertex v2, AreaEdgeList area, @@ -292,14 +296,13 @@ private AreaEdge createAreaEdge( new Coordinate[] { v1.getCoordinate(), v2.getCoordinate() } ); I18NString name = new LocalizedString(nameString); - return AreaEdge.createAreaEdge( - v1, - v2, - line, - name, - StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE, - false, - area - ); + return new AreaEdgeBuilder() + .withFromVertex(v1) + .withToVertex(v2) + .withGeometry(line) + .withName(name) + .withPermission(StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE) + .withBack(false) + .withArea(area); } } diff --git a/src/test/java/org/opentripplanner/graph_builder/module/ElevationModuleTest.java b/src/test/java/org/opentripplanner/graph_builder/module/ElevationModuleTest.java index 2a8e1b1d2f8..17817212df4 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/ElevationModuleTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/ElevationModuleTest.java @@ -16,6 +16,7 @@ import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.OsmVertex; import org.opentripplanner.transit.model.framework.Deduplicator; @@ -80,15 +81,15 @@ public void testSetElevationOnEdgesUsingS3BucketTiles() { for (int i = 1; i < coordinates.length; ++i) { length += SphericalDistanceLibrary.distance(coordinates[i - 1], coordinates[i]); } - StreetEdge edge = StreetEdge.createStreetEdge( - from, - to, - geometry, - "Southwest College St", - length, - StreetTraversalPermission.ALL, - false - ); + StreetEdge edge = new StreetEdgeBuilder<>() + .withFromVertex(from) + .withToVertex(to) + .withGeometry(geometry) + .withName("Southwest College St") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); // create the elevation module File cacheDirectory = new File(ElevationModuleTest.class.getResource("ned").getFile()); diff --git a/src/test/java/org/opentripplanner/graph_builder/module/linking/LinkingTest.java b/src/test/java/org/opentripplanner/graph_builder/module/linking/LinkingTest.java index 5f45350ffb3..2c2f4092278 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/linking/LinkingTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/linking/LinkingTest.java @@ -23,6 +23,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.edge.StreetTransitStopLink; import org.opentripplanner.street.model.vertex.SplitterVertex; import org.opentripplanner.street.model.vertex.StreetVertex; @@ -49,24 +50,24 @@ public void testSplitting() { new Coordinate[] { v0.getCoordinate(), v1.getCoordinate() } ); double dist = SphericalDistanceLibrary.distance(v0.getCoordinate(), v1.getCoordinate()); - StreetEdge s0 = StreetEdge.createStreetEdge( - v0, - v1, - geom, - "test", - dist, - StreetTraversalPermission.ALL, - false - ); - StreetEdge s1 = StreetEdge.createStreetEdge( - v1, - v0, - geom.reverse(), - "back", - dist, - StreetTraversalPermission.ALL, - true - ); + StreetEdge s0 = new StreetEdgeBuilder<>() + .withFromVertex(v0) + .withToVertex(v1) + .withGeometry(geom) + .withName("test") + .withMeterLength(dist) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); + StreetEdge s1 = new StreetEdgeBuilder<>() + .withFromVertex(v1) + .withToVertex(v0) + .withGeometry(geom.reverse()) + .withName("back") + .withMeterLength(dist) + .withPermission(StreetTraversalPermission.ALL) + .withBack(true) + .buildAndConnect(); // split it but not too close to the end double splitVal = Math.random() * 0.95 + 0.025; diff --git a/src/test/java/org/opentripplanner/graph_builder/module/ned/MissingElevationHandlerTest.java b/src/test/java/org/opentripplanner/graph_builder/module/ned/MissingElevationHandlerTest.java index 640801ed16a..cc2b415100b 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/ned/MissingElevationHandlerTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/ned/MissingElevationHandlerTest.java @@ -9,12 +9,14 @@ import org.junit.jupiter.api.Test; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; +import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.LocalizedStringFormat; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.graph_builder.issue.service.DefaultDataImportIssueStore; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.edge.StreetElevationExtension; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.Vertex; @@ -187,15 +189,15 @@ private IntersectionVertex vertex(String A) { } private StreetEdge edge(IntersectionVertex from, IntersectionVertex to, double length) { - return StreetEdge.createStreetEdge( - from, - to, - null, - new LocalizedStringFormat("%s%s", from.getName(), to.getName()), - length, - StreetTraversalPermission.ALL, - false - ); + return new StreetEdgeBuilder<>() + .withFromVertex(from) + .withToVertex(to) + .withGeometry(null) + .withName(new LocalizedStringFormat("%s%s", from.getName(), to.getName())) + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); } private void assignElevation(StreetEdge edge, Map elevations) { diff --git a/src/test/java/org/opentripplanner/routing/TestHalfEdges.java b/src/test/java/org/opentripplanner/routing/TestHalfEdges.java index 143c216870a..0b0f2133a22 100644 --- a/src/test/java/org/opentripplanner/routing/TestHalfEdges.java +++ b/src/test/java/org/opentripplanner/routing/TestHalfEdges.java @@ -35,6 +35,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.note.StreetNote; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.TemporaryStreetLocation; @@ -76,86 +77,86 @@ public void setUp() { br = factory.intersection("br", -74.00, 40.0); top = - StreetEdge.createStreetEdge( - tl, - tr, - GeometryUtils.makeLineString(-74.01, 40.01, -74.0, 40.01), - "top", - 1500, - StreetTraversalPermission.ALL, - false - ); + new StreetEdgeBuilder<>() + .withFromVertex(tl) + .withToVertex(tr) + .withGeometry(GeometryUtils.makeLineString(-74.01, 40.01, -74.0, 40.01)) + .withName("top") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); bottom = - StreetEdge.createStreetEdge( - br, - bl, - GeometryUtils.makeLineString(-74.01, 40.0, -74.0, 40.0), - "bottom", - 1500, - StreetTraversalPermission.ALL, - false - ); + new StreetEdgeBuilder<>() + .withFromVertex(br) + .withToVertex(bl) + .withGeometry(GeometryUtils.makeLineString(-74.01, 40.0, -74.0, 40.0)) + .withName("bottom") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); left = - StreetEdge.createStreetEdge( - bl, - tl, - GeometryUtils.makeLineString(-74.01, 40.0, -74.01, 40.01), - "left", - 1500, - StreetTraversalPermission.ALL, - false - ); + new StreetEdgeBuilder<>() + .withFromVertex(bl) + .withToVertex(tl) + .withGeometry(GeometryUtils.makeLineString(-74.01, 40.0, -74.01, 40.01)) + .withName("left") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); right = - StreetEdge.createStreetEdge( - br, - tr, - GeometryUtils.makeLineString(-74.0, 40.0, -74.0, 40.01), - "right", - 1500, - StreetTraversalPermission.PEDESTRIAN, - false - ); + new StreetEdgeBuilder<>() + .withFromVertex(br) + .withToVertex(tr) + .withGeometry(GeometryUtils.makeLineString(-74.0, 40.0, -74.0, 40.01)) + .withName("right") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.PEDESTRIAN) + .withBack(false) + .buildAndConnect(); @SuppressWarnings("unused") - StreetEdge topBack = StreetEdge.createStreetEdge( - tr, - tl, - top.getGeometry().reverse(), - "topBack", - 1500, - StreetTraversalPermission.ALL, - true - ); + StreetEdge topBack = new StreetEdgeBuilder<>() + .withFromVertex(tr) + .withToVertex(tl) + .withGeometry(top.getGeometry().reverse()) + .withName("topBack") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(true) + .buildAndConnect(); @SuppressWarnings("unused") - StreetEdge bottomBack = StreetEdge.createStreetEdge( - br, - bl, - bottom.getGeometry().reverse(), - "bottomBack", - 1500, - StreetTraversalPermission.ALL, - true - ); + StreetEdge bottomBack = new StreetEdgeBuilder<>() + .withFromVertex(br) + .withToVertex(bl) + .withGeometry(bottom.getGeometry().reverse()) + .withName("bottomBack") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(true) + .buildAndConnect(); leftBack = - StreetEdge.createStreetEdge( - tl, - bl, - left.getGeometry().reverse(), - "leftBack", - 1500, - StreetTraversalPermission.ALL, - true - ); + new StreetEdgeBuilder<>() + .withFromVertex(tl) + .withToVertex(bl) + .withGeometry(left.getGeometry().reverse()) + .withName("leftBack") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(true) + .buildAndConnect(); rightBack = - StreetEdge.createStreetEdge( - tr, - br, - right.getGeometry().reverse(), - "rightBack", - 1500, - StreetTraversalPermission.ALL, - true - ); + new StreetEdgeBuilder<>() + .withFromVertex(tr) + .withToVertex(br) + .withGeometry(right.getGeometry().reverse()) + .withName("rightBack") + .withMeterLength(1500) + .withPermission(StreetTraversalPermission.ALL) + .withBack(true) + .buildAndConnect(); var s1 = TransitModelForTest.stopForTest("fleem station", 40.0099999, -74.005); var s2 = TransitModelForTest.stopForTest("morx station", 40.0099999, -74.002); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java b/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java index 86965cc1951..9d98dcb4bb5 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java @@ -28,6 +28,7 @@ import org.opentripplanner.street.model.edge.FreeEdge; import org.opentripplanner.street.model.edge.PathwayEdge; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.edge.StreetTransitEntranceLink; import org.opentripplanner.street.model.edge.StreetTransitStopLink; import org.opentripplanner.street.model.edge.StreetVehicleParkingLink; @@ -109,21 +110,31 @@ public IntersectionVertex intersection(String label, double latitude, double lon return vertexFactory.intersection(label, longitude, latitude); } + public StreetEdgeBuilder streetBuilder( + StreetVertex from, + StreetVertex to, + int length, + StreetTraversalPermission permissions + ) { + return new StreetEdgeBuilder<>() + .withFromVertex(from) + .withToVertex(to) + .withGeometry( + GeometryUtils.makeLineString(from.getLat(), from.getLon(), to.getLat(), to.getLon()) + ) + .withName(String.format("%s%s street", from.getLabel(), to.getLabel())) + .withMeterLength(length) + .withPermission(permissions) + .withBack(false); + } + public StreetEdge street( StreetVertex from, StreetVertex to, int length, StreetTraversalPermission permissions ) { - return StreetEdge.createStreetEdge( - from, - to, - GeometryUtils.makeLineString(from.getLat(), from.getLon(), to.getLat(), to.getLon()), - String.format("%s%s street", from.getLabel(), to.getLabel()), - length, - permissions, - false - ); + return streetBuilder(from, to, length, permissions).buildAndConnect(); } public List street( @@ -134,24 +145,28 @@ public List street( StreetTraversalPermission reversePermissions ) { return List.of( - StreetEdge.createStreetEdge( - from, - to, - GeometryUtils.makeLineString(from.getLat(), from.getLon(), to.getLat(), to.getLon()), - String.format("%s%s street", from.getDefaultName(), to.getDefaultName()), - length, - forwardPermissions, - false - ), - StreetEdge.createStreetEdge( - to, - from, - GeometryUtils.makeLineString(to.getLat(), to.getLon(), from.getLat(), from.getLon()), - String.format("%s%s street", from.getDefaultName(), to.getDefaultName()), - length, - reversePermissions, - true - ) + new StreetEdgeBuilder<>() + .withFromVertex(from) + .withToVertex(to) + .withGeometry( + GeometryUtils.makeLineString(from.getLat(), from.getLon(), to.getLat(), to.getLon()) + ) + .withName(String.format("%s%s street", from.getDefaultName(), to.getDefaultName())) + .withMeterLength(length) + .withPermission(forwardPermissions) + .withBack(false) + .buildAndConnect(), + new StreetEdgeBuilder<>() + .withFromVertex(to) + .withToVertex(from) + .withGeometry( + GeometryUtils.makeLineString(to.getLat(), to.getLon(), from.getLat(), from.getLon()) + ) + .withName(String.format("%s%s street", from.getDefaultName(), to.getDefaultName())) + .withMeterLength(length) + .withPermission(reversePermissions) + .withBack(true) + .buildAndConnect() ); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/StreetModeLinkingTest.java b/src/test/java/org/opentripplanner/routing/algorithm/StreetModeLinkingTest.java index bcb7459aaeb..1a00986613c 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/StreetModeLinkingTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/StreetModeLinkingTest.java @@ -54,13 +54,14 @@ public void build() { StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE ); - street( + streetBuilder( intersection("D1", 47.500, 19.03), intersection("D2", 47.502, 19.03), 100, StreetTraversalPermission.PEDESTRIAN ) - .setWheelchairAccessible(false); + .withWheelchairAccessible(false) + .buildAndConnect(); street( intersection("E1", 47.500, 19.04), diff --git a/src/test/java/org/opentripplanner/routing/algorithm/TurnCostTest.java b/src/test/java/org/opentripplanner/routing/algorithm/TurnCostTest.java index 6f3248ecb7f..53e340dcc63 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/TurnCostTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/TurnCostTest.java @@ -20,6 +20,7 @@ import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.StreetSearchBuilder; @@ -247,9 +248,16 @@ private StreetEdge edge(StreetVertex vA, StreetVertex vB, double length, boolean LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); StreetTraversalPermission perm = StreetTraversalPermission.ALL; - StreetEdge pse = StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, back); - pse.setCarSpeed(1.0f); - return pse; + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(back) + .withCarSpeed(1.0f) + .buildAndConnect(); } private void DisallowTurn(StreetEdge from, StreetEdge to) { diff --git a/src/test/java/org/opentripplanner/routing/core/GraphTest.java b/src/test/java/org/opentripplanner/routing/core/GraphTest.java index 6249b22c4da..f264a97293e 100644 --- a/src/test/java/org/opentripplanner/routing/core/GraphTest.java +++ b/src/test/java/org/opentripplanner/routing/core/GraphTest.java @@ -17,6 +17,7 @@ import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.FreeEdge; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.model.vertex.VertexLabel; @@ -155,6 +156,14 @@ private StreetEdge edge(StreetVertex vA, StreetVertex vB, double length) { LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); StreetTraversalPermission perm = StreetTraversalPermission.ALL; - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, false); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(false) + .buildAndConnect(); } } diff --git a/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java b/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java index b1ecfca71a3..49dc42e6f4c 100644 --- a/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java +++ b/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java @@ -22,7 +22,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.Edge; -import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.edge.TemporaryEdge; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TemporaryVertex; @@ -147,7 +147,15 @@ private void createStreetEdge(StreetVertex v0, StreetVertex v1, String name) { new Coordinate[] { v0.getCoordinate(), v1.getCoordinate() } ); double dist = SphericalDistanceLibrary.distance(v0.getCoordinate(), v1.getCoordinate()); - StreetEdge.createStreetEdge(v0, v1, geom, name, dist, StreetTraversalPermission.ALL, false); + new StreetEdgeBuilder<>() + .withFromVertex(v0) + .withToVertex(v1) + .withGeometry(geom) + .withName(name) + .withMeterLength(dist) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); } private void assertVertexEdgeIsNotReferencingTemporaryElements(Vertex src, Edge e, Vertex v) { diff --git a/src/test/java/org/opentripplanner/routing/core/TurnsTest.java b/src/test/java/org/opentripplanner/routing/core/TurnsTest.java index 7ecdb81c4c4..cfbc0792e1d 100644 --- a/src/test/java/org/opentripplanner/routing/core/TurnsTest.java +++ b/src/test/java/org/opentripplanner/routing/core/TurnsTest.java @@ -9,6 +9,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.IntersectionVertex; public class TurnsTest { @@ -24,29 +25,29 @@ public void testIntersectionVertex() { IntersectionVertex v1 = StreetModelForTest.intersectionVertex("v1", -0.10, 0); IntersectionVertex v2 = StreetModelForTest.intersectionVertex("v2", 0, 0); - StreetEdge leftEdge = StreetEdge.createStreetEdge( - v1, - v2, - geometry, - "morx", - 10.0, - StreetTraversalPermission.ALL, - true - ); + StreetEdge leftEdge = new StreetEdgeBuilder<>() + .withFromVertex(v1) + .withToVertex(v2) + .withGeometry(geometry) + .withName("morx") + .withMeterLength(10.0) + .withPermission(StreetTraversalPermission.ALL) + .withBack(true) + .buildAndConnect(); LineString geometry2 = gf.createLineString( new Coordinate[] { new Coordinate(0, 0), new Coordinate(-0.10, 0) } ); - StreetEdge rightEdge = StreetEdge.createStreetEdge( - v1, - v2, - geometry2, - "fleem", - 10.0, - StreetTraversalPermission.ALL, - false - ); + StreetEdge rightEdge = new StreetEdgeBuilder<>() + .withFromVertex(v1) + .withToVertex(v2) + .withGeometry(geometry2) + .withName("fleem") + .withMeterLength(10.0) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); assertEquals(180, Math.abs(leftEdge.getOutAngle() - rightEdge.getOutAngle())); } diff --git a/src/test/java/org/opentripplanner/routing/graph/EdgeTest.java b/src/test/java/org/opentripplanner/routing/graph/EdgeTest.java index bb6bbc0c518..87a9275ec48 100644 --- a/src/test/java/org/opentripplanner/routing/graph/EdgeTest.java +++ b/src/test/java/org/opentripplanner/routing/graph/EdgeTest.java @@ -7,7 +7,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.Edge; -import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.Vertex; @@ -29,33 +29,33 @@ public void testEdgeRemoval() { StreetVertex vb = intersectionVertex("B", 10.1, 10.1); StreetVertex vc = intersectionVertex("C", 10.2, 10.2); StreetVertex vd = intersectionVertex("D", 10.3, 10.3); - Edge eab = StreetEdge.createStreetEdge( - va, - vb, - null, - "AB", - 10, - StreetTraversalPermission.ALL, - false - ); - Edge ebc = StreetEdge.createStreetEdge( - vb, - vc, - null, - "BC", - 10, - StreetTraversalPermission.ALL, - false - ); - Edge ecd = StreetEdge.createStreetEdge( - vc, - vd, - null, - "CD", - 10, - StreetTraversalPermission.ALL, - false - ); + Edge eab = new StreetEdgeBuilder<>() + .withFromVertex(va) + .withToVertex(vb) + .withGeometry(null) + .withName("AB") + .withMeterLength(10) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); + Edge ebc = new StreetEdgeBuilder<>() + .withFromVertex(vb) + .withToVertex(vc) + .withGeometry(null) + .withName("BC") + .withMeterLength(10) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); + Edge ecd = new StreetEdgeBuilder<>() + .withFromVertex(vc) + .withToVertex(vd) + .withGeometry(null) + .withName("CD") + .withMeterLength(10) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); // remove an edge that is not connected to this vertex va.removeOutgoing(ecd); assertEquals(va.getDegreeOut(), 1); diff --git a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java index 32cc71319b3..d0706c03fcd 100644 --- a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java +++ b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java @@ -1,10 +1,11 @@ package org.opentripplanner.routing.vehicle_parking; +import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.street.model.StreetTraversalPermission; -import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -44,14 +45,16 @@ public static void createStreet( StreetVertex to, StreetTraversalPermission permissions ) { - StreetEdge.createStreetEdge( - from, - to, - GeometryUtils.makeLineString(from.getLat(), from.getLon(), to.getLat(), to.getLon()), - String.format("%s%s street", from.getDefaultName(), to.getDefaultName()), - 1, - permissions, - false - ); + new StreetEdgeBuilder<>() + .withFromVertex(from) + .withToVertex(to) + .withGeometry( + GeometryUtils.makeLineString(from.getLat(), from.getLon(), to.getLat(), to.getLon()) + ) + .withName(String.format("%s%s street", from.getDefaultName(), to.getDefaultName())) + .withMeterLength(1) + .withPermission(permissions) + .withBack(false) + .buildAndConnect(); } } diff --git a/src/test/java/org/opentripplanner/street/model/TurnRestrictionTest.java b/src/test/java/org/opentripplanner/street/model/TurnRestrictionTest.java index 6c158679bf6..d40930f8bdc 100644 --- a/src/test/java/org/opentripplanner/street/model/TurnRestrictionTest.java +++ b/src/test/java/org/opentripplanner/street/model/TurnRestrictionTest.java @@ -19,6 +19,7 @@ import org.opentripplanner.routing.api.request.request.StreetRequest; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.StreetSearchBuilder; @@ -199,7 +200,15 @@ private StreetEdge edge(StreetVertex vA, StreetVertex vB, double length, boolean LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); StreetTraversalPermission perm = StreetTraversalPermission.ALL; - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, back); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(back) + .buildAndConnect(); } private void DisallowTurn(StreetEdge from, StreetEdge to) { diff --git a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java index 28a209d71d8..255bf5a71d3 100644 --- a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java +++ b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java @@ -7,6 +7,7 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.LabelledIntersectionVertex; import org.opentripplanner.street.model.vertex.StreetVertex; @@ -32,7 +33,7 @@ public static StreetEdge streetEdge(StreetVertex vA, StreetVertex vB) { return streetEdge(vA, vB, meters, StreetTraversalPermission.ALL); } - public static StreetEdge streetEdge( + public static StreetEdgeBuilder streetEdgeBuilder( StreetVertex vA, StreetVertex vB, double length, @@ -46,6 +47,22 @@ public static StreetEdge streetEdge( coords[1] = vB.getCoordinate(); LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, false); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(false); + } + + public static StreetEdge streetEdge( + StreetVertex vA, + StreetVertex vB, + double length, + StreetTraversalPermission perm + ) { + return streetEdgeBuilder(vA, vB, length, perm).buildAndConnect(); } } diff --git a/src/test/java/org/opentripplanner/street/model/edge/AreaEdgeBuilderTest.java b/src/test/java/org/opentripplanner/street/model/edge/AreaEdgeBuilderTest.java new file mode 100644 index 00000000000..3876b739f16 --- /dev/null +++ b/src/test/java/org/opentripplanner/street/model/edge/AreaEdgeBuilderTest.java @@ -0,0 +1,40 @@ +package org.opentripplanner.street.model.edge; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.LineString; +import org.opentripplanner.framework.geometry.GeometryUtils; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.street.model.StreetTraversalPermission; +import org.opentripplanner.street.model._data.StreetModelForTest; +import org.opentripplanner.street.model.vertex.StreetVertex; + +class AreaEdgeBuilderTest { + + private static final StreetVertex FROM_VERTEX = StreetModelForTest.V1; + private static final StreetVertex TO_VERTEX = StreetModelForTest.V2; + private static final StreetTraversalPermission STREET_TRAVERSAL_PERMISSION = + StreetTraversalPermission.ALL; + + private static final I18NString NAME = I18NString.of("area-edge-name"); + private static final LineString GEOMETRY = GeometryUtils + .getGeometryFactory() + .createLineString(new Coordinate[] { FROM_VERTEX.getCoordinate(), TO_VERTEX.getCoordinate() }); + + private static final AreaEdgeList AREA = new AreaEdgeList(null, null); + + @Test + void buildAndConnect() { + AreaEdge areaEdge = new AreaEdgeBuilder() + .withFromVertex(FROM_VERTEX) + .withToVertex(TO_VERTEX) + .withGeometry(GEOMETRY) + .withPermission(STREET_TRAVERSAL_PERMISSION) + .withName(NAME) + .withArea(AREA) + .buildAndConnect(); + assertEquals(AREA, areaEdge.getArea()); + } +} diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeBuilderTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeBuilderTest.java new file mode 100644 index 00000000000..4b91c008460 --- /dev/null +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeBuilderTest.java @@ -0,0 +1,108 @@ +package org.opentripplanner.street.model.edge; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.LineString; +import org.opentripplanner.framework.geometry.GeometryUtils; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.street.model.StreetTraversalPermission; +import org.opentripplanner.street.model._data.StreetModelForTest; +import org.opentripplanner.street.model.vertex.StreetVertex; + +class StreetEdgeBuilderTest { + + private static final StreetVertex FROM_VERTEX = StreetModelForTest.V1; + private static final StreetVertex TO_VERTEX = StreetModelForTest.V2; + private static final StreetTraversalPermission STREET_TRAVERSAL_PERMISSION = + StreetTraversalPermission.ALL; + + private static final I18NString NAME = I18NString.of("street-edge-name"); + + private static final double LENGTH = 10.5; + private static final LineString GEOMETRY = GeometryUtils + .getGeometryFactory() + .createLineString(new Coordinate[] { FROM_VERTEX.getCoordinate(), TO_VERTEX.getCoordinate() }); + + private static final boolean WHEELCHAIR_ACCESSIBLE = false; + private static final boolean BACK = false; + private static final boolean STAIRS = true; + private static final float CAR_SPEED = 100.1f; + private static final float WALK_SAFETY_FACTOR = 0.5f; + private static final float BICYCLE_SAFETY_FACTOR = 0.4f; + private static final boolean SLOPE_OVERRIDE = false; + private static final boolean BOGUS_NAME = true; + private static final boolean BICYCLE_NO_THRU_TRAFFIC = true; + private static final boolean MOTOR_VEHICLE_NO_THRU_TRAFFIC = true; + private static final boolean WALK_NO_THRU_TRAFFIC = true; + private static final I18NString NEW_NAME = I18NString.of("street-edge-new-name"); + + @Test + void buildWithDefaultLength() { + StreetEdge streetEdge = new StreetEdgeBuilder<>() + .withFromVertex(FROM_VERTEX) + .withToVertex(TO_VERTEX) + .withGeometry(GEOMETRY) + .withName(NAME) + .withPermission(STREET_TRAVERSAL_PERMISSION) + .buildAndConnect(); + assertEquals( + StreetEdge.defaultMillimeterLength(GEOMETRY) / 1000.0, + streetEdge.getDistanceMeters() + ); + } + + @Test + void buildWithCustomLength() { + StreetEdge streetEdge = buildStreetEdge(); + assertEquals(NAME, streetEdge.getName()); + assetAllProperties(streetEdge); + } + + @Test + void buildFromOriginal() { + StreetEdge original = buildStreetEdge(); + StreetEdge streetEdge = new StreetEdgeBuilder<>(original).withName(NEW_NAME).buildAndConnect(); + assertEquals(NEW_NAME, streetEdge.getName()); + assetAllProperties(streetEdge); + } + + private static StreetEdge buildStreetEdge() { + return new StreetEdgeBuilder<>() + .withFromVertex(FROM_VERTEX) + .withToVertex(TO_VERTEX) + .withMeterLength(LENGTH) + .withName(NAME) + .withPermission(STREET_TRAVERSAL_PERMISSION) + .withCarSpeed(CAR_SPEED) + .withWalkSafetyFactor(WALK_SAFETY_FACTOR) + .withBicycleSafetyFactor(BICYCLE_SAFETY_FACTOR) + .withWheelchairAccessible(WHEELCHAIR_ACCESSIBLE) + .withBack(BACK) + .withStairs(STAIRS) + .withSlopeOverride(SLOPE_OVERRIDE) + .withBogusName(BOGUS_NAME) + .withWalkNoThruTraffic(WALK_NO_THRU_TRAFFIC) + .withBicycleNoThruTraffic(BICYCLE_NO_THRU_TRAFFIC) + .withMotorVehicleNoThruTraffic(MOTOR_VEHICLE_NO_THRU_TRAFFIC) + .buildAndConnect(); + } + + private static void assetAllProperties(StreetEdge streetEdge) { + assertEquals(FROM_VERTEX, streetEdge.getFromVertex()); + assertEquals(TO_VERTEX, streetEdge.getToVertex()); + assertEquals(LENGTH, streetEdge.getDistanceMeters()); + assertEquals(STREET_TRAVERSAL_PERMISSION, streetEdge.getPermission()); + assertEquals(WHEELCHAIR_ACCESSIBLE, streetEdge.isWheelchairAccessible()); + assertEquals(STAIRS, streetEdge.isStairs()); + assertEquals(CAR_SPEED, streetEdge.getCarSpeed()); + assertEquals(WALK_SAFETY_FACTOR, streetEdge.getWalkSafetyFactor()); + assertEquals(BICYCLE_SAFETY_FACTOR, streetEdge.getBicycleSafetyFactor()); + assertEquals(SLOPE_OVERRIDE, streetEdge.isSlopeOverride()); + assertEquals(BOGUS_NAME, streetEdge.hasBogusName()); + assertEquals(WALK_NO_THRU_TRAFFIC, streetEdge.isWalkNoThruTraffic()); + assertEquals(BICYCLE_NO_THRU_TRAFFIC, streetEdge.isBicycleNoThruTraffic()); + assertEquals(MOTOR_VEHICLE_NO_THRU_TRAFFIC, streetEdge.isMotorVehicleNoThruTraffic()); + } +} diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java index 3a62a1a6a5a..b054a7771c4 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java @@ -27,15 +27,15 @@ class StreetEdgeCostTest { @VariableSource("walkReluctanceCases") public void walkReluctance(double walkReluctance, long expectedCost) { double length = 100; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "edge", - length, - StreetTraversalPermission.ALL, - false - ); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("edge") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withWalk(w -> w.withReluctance(walkReluctance))); @@ -57,15 +57,15 @@ public void walkReluctance(double walkReluctance, long expectedCost) { @VariableSource("bikeReluctanceCases") public void bikeReluctance(double bikeReluctance, long expectedCost) { double length = 100; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "edge", - length, - StreetTraversalPermission.ALL, - false - ); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("edge") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withBike(b -> b.withReluctance(bikeReluctance))); @@ -88,15 +88,15 @@ public void bikeReluctance(double bikeReluctance, long expectedCost) { @VariableSource("carReluctanceCases") public void carReluctance(double carReluctance, long expectedCost) { double length = 100; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "edge", - length, - StreetTraversalPermission.ALL, - false - ); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("edge") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withCar(c -> c.withReluctance(carReluctance))); @@ -118,27 +118,27 @@ public void carReluctance(double carReluctance, long expectedCost) { @VariableSource("stairsCases") public void stairsReluctance(double stairsReluctance, long expectedCost) { double length = 10; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "stairs", - length, - StreetTraversalPermission.ALL, - false - ); - edge.setStairs(true); + var stairsEdge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("stairs") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .withStairs(true) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withWalk(w -> w.withStairsReluctance(stairsReluctance))); req.withMode(StreetMode.WALK); - var result = traverse(edge, req.build()); + var result = traverse(stairsEdge, req.build()); assertEquals(expectedCost, (long) result.weight); assertEquals(23, result.getElapsedTimeSeconds()); - edge.setStairs(false); - var notStairsResult = traverse(edge, req.build()); + StreetEdge noStairsEdge = stairsEdge.toBuilder().withStairs(false).buildAndConnect(); + var notStairsResult = traverse(noStairsEdge, req.build()); assertEquals(15, (long) notStairsResult.weight); } @@ -152,27 +152,27 @@ public void stairsReluctance(double stairsReluctance, long expectedCost) { @VariableSource("bikeStairsCases") public void bikeStairsReluctance(double stairsReluctance, long expectedCost) { double length = 10; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "stairs", - length, - StreetTraversalPermission.PEDESTRIAN, - false - ); - edge.setStairs(true); + var stairsEdge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("stairs") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.PEDESTRIAN) + .withBack(false) + .withStairs(true) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withBike(b -> b.withStairsReluctance(stairsReluctance))); req.withMode(StreetMode.BIKE); - var result = traverse(edge, req.build()); + var result = traverse(stairsEdge, req.build()); assertEquals(expectedCost, (long) result.weight); assertEquals(23, result.getElapsedTimeSeconds()); - edge.setStairs(false); - var notStairsResult = traverse(edge, req.build()); + StreetEdge noStairsEdge = stairsEdge.toBuilder().withStairs(false).buildAndConnect(); + var notStairsResult = traverse(noStairsEdge, req.build()); assertEquals(37, (long) notStairsResult.weight); } @@ -186,27 +186,27 @@ public void bikeStairsReluctance(double stairsReluctance, long expectedCost) { @VariableSource("walkSafetyCases") public void walkSafetyFactor(double walkSafetyFactor, long expectedCost) { double length = 10; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "test edge", - length, - StreetTraversalPermission.ALL, - false - ); - edge.setWalkSafetyFactor(2); + var safeEdge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("test edge") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .withWalkSafetyFactor(2) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withWalk(w -> w.withSafetyFactor(walkSafetyFactor))); req.withMode(StreetMode.WALK); - var result = traverse(edge, req.build()); + var result = traverse(safeEdge, req.build()); assertEquals(expectedCost, (long) result.weight); assertEquals(8, result.getElapsedTimeSeconds()); - edge.setWalkSafetyFactor(1); - var defaultSafetyResult = traverse(edge, req.build()); + StreetEdge lessSafeEdge = safeEdge.toBuilder().withWalkSafetyFactor(1).buildAndConnect(); + var defaultSafetyResult = traverse(lessSafeEdge, req.build()); assertEquals(15, (long) defaultSafetyResult.weight); } diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java index 01a4c3373b8..a74356d9337 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java @@ -8,6 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.street.model._data.StreetModelForTest.intersectionVertex; import static org.opentripplanner.street.model._data.StreetModelForTest.streetEdge; +import static org.opentripplanner.street.model._data.StreetModelForTest.streetEdgeBuilder; import java.time.Instant; import org.junit.jupiter.api.BeforeEach; @@ -83,8 +84,9 @@ public void testInAndOutAngles() { @Test public void testTraverseAsPedestrian() { - StreetEdge e1 = streetEdge(v1, v2, 100.0, StreetTraversalPermission.ALL); - e1.setCarSpeed(10.0f); + StreetEdge e1 = streetEdgeBuilder(v1, v2, 100.0, StreetTraversalPermission.ALL) + .withCarSpeed(10.0f) + .buildAndConnect(); StreetSearchRequest options = StreetSearchRequest .copyOf(proto) @@ -103,8 +105,9 @@ public void testTraverseAsPedestrian() { @Test public void testTraverseAsCar() { - StreetEdge e1 = streetEdge(v1, v2, 100.0, StreetTraversalPermission.ALL); - e1.setCarSpeed(10.0f); + StreetEdge e1 = streetEdgeBuilder(v1, v2, 100.0, StreetTraversalPermission.ALL) + .withCarSpeed(10.0f) + .buildAndConnect(); State s0 = new State(v1, StreetSearchRequest.copyOf(proto).withMode(StreetMode.CAR).build()); State s1 = e1.traverse(s0)[0]; @@ -321,16 +324,17 @@ public void testBikeOptimizeTriangle() { double length = 650.0; - StreetEdge testStreet = StreetEdge.createStreetEdge( - v1, - v2, - geometry, - "Test Lane", - length, - StreetTraversalPermission.ALL, - false - ); - testStreet.setBicycleSafetyFactor(0.74f); // a safe street + StreetEdge testStreet = new StreetEdgeBuilder<>() + .withFromVertex(v1) + .withToVertex(v2) + .withGeometry(geometry) + .withName("Test Lane") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + // a safe street + .withBicycleSafetyFactor(0.74f) + .buildAndConnect(); Coordinate[] profile = new Coordinate[] { new Coordinate(0, 0), // slope = 0.1 diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java index dfee47aba61..a8c36032945 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java @@ -60,15 +60,15 @@ public StreetEdgeWheelchairCostTest() { @VariableSource("slopeCases") public void shouldScaleCostWithMaxSlope(double slope, double reluctance, long expectedCost) { double length = 1000; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "edge with elevation", - length, - StreetTraversalPermission.ALL, - false - ); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("edge with elevation") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); Coordinate[] profile = new Coordinate[] { new Coordinate(0, 0), @@ -113,16 +113,16 @@ public void shouldScaleCostWithMaxSlope(double slope, double reluctance, long ex @VariableSource("wheelchairStairsCases") public void wheelchairStairsReluctance(double stairsReluctance, long expectedCost) { double length = 10; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "stairs", - length, - StreetTraversalPermission.ALL, - false - ); - edge.setStairs(true); + var stairEdge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("stairs") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .withStairs(true) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withWheelchair(true); @@ -143,11 +143,11 @@ public void wheelchairStairsReluctance(double stairsReluctance, long expectedCos req.withPreferences(pref -> pref.withWalk(w -> w.withReluctance(1.0))); - var result = traverse(edge, req.build()); + var result = traverse(stairEdge, req.build()); assertEquals(expectedCost, (long) result.weight); - edge.setStairs(false); - var notStairsResult = traverse(edge, req.build()); + StreetEdge noStairsEdge = stairEdge.toBuilder().withStairs(false).buildAndConnect(); + var notStairsResult = traverse(noStairsEdge, req.build()); assertEquals(7, (long) notStairsResult.weight); } @@ -163,16 +163,16 @@ public void wheelchairStairsReluctance(double stairsReluctance, long expectedCos @VariableSource("inaccessibleStreetCases") public void inaccessibleStreet(float inaccessibleStreetReluctance, long expectedCost) { double length = 10; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "stairs", - length, - StreetTraversalPermission.ALL, - false - ); - edge.setWheelchairAccessible(false); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("stairs") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .withWheelchairAccessible(false) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withWheelchair(true); @@ -195,8 +195,8 @@ public void inaccessibleStreet(float inaccessibleStreetReluctance, long expected assertEquals(expectedCost, (long) result.weight); // reluctance should have no effect when the edge is accessible - edge.setWheelchairAccessible(true); - var accessibleResult = traverse(edge, req.build()); + StreetEdge accessibleEdge = edge.toBuilder().withWheelchairAccessible(true).buildAndConnect(); + var accessibleResult = traverse(accessibleEdge, req.build()); assertEquals(15, (long) accessibleResult.weight); } @@ -213,15 +213,15 @@ public void inaccessibleStreet(float inaccessibleStreetReluctance, long expected @VariableSource("walkReluctanceCases") public void walkReluctance(double walkReluctance, long expectedCost) { double length = 10; - var edge = StreetEdge.createStreetEdge( - V1, - V2, - null, - "stairs", - length, - StreetTraversalPermission.ALL, - false - ); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(V1) + .withToVertex(V2) + .withGeometry(null) + .withName("stairs") + .withMeterLength(length) + .withPermission(StreetTraversalPermission.ALL) + .withBack(false) + .buildAndConnect(); var req = StreetSearchRequest.of(); req.withPreferences(p -> p.withWalk(w -> w.withReluctance(walkReluctance))); diff --git a/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilderTest.java b/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilderTest.java new file mode 100644 index 00000000000..7040a78ce04 --- /dev/null +++ b/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeBuilderTest.java @@ -0,0 +1,43 @@ +package org.opentripplanner.street.model.edge; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.LineString; +import org.opentripplanner.framework.geometry.GeometryUtils; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.street.model.StreetTraversalPermission; +import org.opentripplanner.street.model._data.StreetModelForTest; +import org.opentripplanner.street.model.vertex.StreetVertex; + +class TemporaryPartialStreetEdgeBuilderTest { + + private static final StreetVertex FROM_VERTEX = StreetModelForTest.V1; + private static final StreetVertex TO_VERTEX = StreetModelForTest.V2; + public static final StreetEdge PARENT_EDGE = StreetModelForTest.streetEdge( + StreetModelForTest.V3, + StreetModelForTest.V4 + ); + private static final StreetTraversalPermission STREET_TRAVERSAL_PERMISSION = + StreetTraversalPermission.ALL; + + private static final I18NString NAME = I18NString.of("temporary-partial-street-edge-name"); + private static final LineString GEOMETRY = GeometryUtils + .getGeometryFactory() + .createLineString(new Coordinate[] { FROM_VERTEX.getCoordinate(), TO_VERTEX.getCoordinate() }); + + @Test + void buildAndConnect() { + TemporaryPartialStreetEdge tpse = new TemporaryPartialStreetEdgeBuilder() + .withFromVertex(FROM_VERTEX) + .withToVertex(TO_VERTEX) + .withGeometry(GEOMETRY) + .withPermission(STREET_TRAVERSAL_PERMISSION) + .withName(NAME) + .withParentEdge(PARENT_EDGE) + .buildAndConnect(); + assertEquals(PARENT_EDGE, tpse.getParentEdge()); + assertEquals(GEOMETRY, tpse.getGeometry()); + } +} diff --git a/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeTest.java index 1859fa906b4..0cd63555a21 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/TemporaryPartialStreetEdgeTest.java @@ -248,14 +248,14 @@ static TemporaryPartialStreetEdge newTemporaryPartialStreetEdge( String name, double length ) { - return TemporaryPartialStreetEdge.createTemporaryPartialStreetEdge( - parentEdge, - v1, - v2, - geometry, - new NonLocalizedString(name), - length - ); + return new TemporaryPartialStreetEdgeBuilder() + .withParentEdge(parentEdge) + .withFromVertex(v1) + .withToVertex(v2) + .withGeometry(geometry) + .withName(new NonLocalizedString(name)) + .withMeterLength(length) + .buildAndConnect(); } private IntersectionVertex vertex(String label, double lat, double lon) { @@ -279,6 +279,14 @@ private StreetEdge edge( coords[1] = vB.getCoordinate(); LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, false); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(false) + .buildAndConnect(); } } diff --git a/src/test/java/org/opentripplanner/street/model/vertex/BarrierVertexTest.java b/src/test/java/org/opentripplanner/street/model/vertex/BarrierVertexTest.java index 57775e95468..ab488bdb82a 100644 --- a/src/test/java/org/opentripplanner/street/model/vertex/BarrierVertexTest.java +++ b/src/test/java/org/opentripplanner/street/model/vertex/BarrierVertexTest.java @@ -14,6 +14,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.TraverseModeSet; @@ -168,6 +169,14 @@ private StreetEdge edge(StreetVertex vA, StreetVertex vB, double length, boolean LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); StreetTraversalPermission perm = StreetTraversalPermission.ALL; - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, back); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(back) + .buildAndConnect(); } } diff --git a/src/test/java/org/opentripplanner/street/model/vertex/IntersectionVertexTest.java b/src/test/java/org/opentripplanner/street/model/vertex/IntersectionVertexTest.java index 133938e1ce3..b175d6180e0 100644 --- a/src/test/java/org/opentripplanner/street/model/vertex/IntersectionVertexTest.java +++ b/src/test/java/org/opentripplanner/street/model/vertex/IntersectionVertexTest.java @@ -12,6 +12,7 @@ import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; public class IntersectionVertexTest { @@ -118,6 +119,14 @@ private StreetEdge edge(StreetVertex vA, StreetVertex vB, double length, boolean LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); StreetTraversalPermission perm = StreetTraversalPermission.ALL; - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, back); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(back) + .buildAndConnect(); } } diff --git a/src/test/java/org/opentripplanner/street/search/intersection_model/SimpleIntersectionTraversalCalculatorTest.java b/src/test/java/org/opentripplanner/street/search/intersection_model/SimpleIntersectionTraversalCalculatorTest.java index 48610dcecd0..7ed8fc12a21 100644 --- a/src/test/java/org/opentripplanner/street/search/intersection_model/SimpleIntersectionTraversalCalculatorTest.java +++ b/src/test/java/org/opentripplanner/street/search/intersection_model/SimpleIntersectionTraversalCalculatorTest.java @@ -12,6 +12,7 @@ import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.LabelledIntersectionVertex; import org.opentripplanner.street.model.vertex.SplitterVertex; @@ -455,6 +456,14 @@ private StreetEdge edge(StreetVertex vA, StreetVertex vB, double length, boolean LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); StreetTraversalPermission perm = StreetTraversalPermission.ALL; - return StreetEdge.createStreetEdge(vA, vB, geom, name, length, perm, back); + return new StreetEdgeBuilder<>() + .withFromVertex(vA) + .withToVertex(vB) + .withGeometry(geom) + .withName(name) + .withMeterLength(length) + .withPermission(perm) + .withBack(back) + .buildAndConnect(); } }