Skip to content

Commit

Permalink
Refactor StreetEdge splitting for bike rentals
Browse files Browse the repository at this point in the history
The testing is a work in progress

Refs opentripplanner#2787
  • Loading branch information
evansiroky committed Jul 10, 2019
1 parent 3164244 commit 8db21bf
Show file tree
Hide file tree
Showing 10 changed files with 690 additions and 210 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package org.opentripplanner.routing.edgetype;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineString;
import org.opentripplanner.common.TurnRestriction;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.util.ElevationUtils;
import org.opentripplanner.routing.vertextype.StreetVertex;
import org.opentripplanner.routing.vertextype.TemporaryVertex;
import org.opentripplanner.util.I18NString;

import java.util.List;

/**
* This class is used to model a StreetEdge that has been non-destructively split from another StreetEdge.
*/
public class PartialStreetEdge extends StreetWithElevationEdge {

private static final long serialVersionUID = 1L;

/**
* The edge on which this lies.
*/
protected StreetEdge parentEdge;


/**
* Create a new partial street edge along the given 'parentEdge' from 'v1' to 'v2'.
* If the length is 0, a new length is calculated from the geometry.
* The elevation data is calculated using the 'parentEdge' and given 'length'.
*/
public PartialStreetEdge(StreetEdge parentEdge, StreetVertex v1, StreetVertex v2,
LineString geometry, I18NString name, double length) {
super(v1, v2, geometry, name, length, parentEdge.getPermission(), false);
this.parentEdge = parentEdge;
setCarSpeed(parentEdge.getCarSpeed());

// If length is 0, use the provided geometry to estimate it
if (length == 0) {
calculateLengthFromGeometry();
}

setElevationProfileUsingParents();
}

/**
* Partial edges are always partial.
*/
@Override
public boolean isPartial() {
return true;
}

/**
* Have the ID of their parent.
*/
@Override
public int getId() {
return parentEdge.getId();
}

/**
* Have the inbound angle of their parent.
*/
@Override
public int getInAngle() {
return parentEdge.getInAngle();
}

/**
* Have the outbound angle of their parent.
*/
@Override
public int getOutAngle() {
return parentEdge.getInAngle();
}

/**
* Have the turn restrictions of their parent.
*/
@Override
protected List<TurnRestriction> getTurnRestrictions(Graph graph) {
return graph.getTurnRestrictions(parentEdge);
}

/**
* This implementation makes it so that TurnRestrictions on the parent edge are applied to this edge as well.
*/
@Override
public boolean isEquivalentTo(Edge e) {
return (e == this || e == parentEdge);
}

@Override
public boolean isReverseOf(Edge e) {
Edge other = e;
if (e instanceof PartialStreetEdge) {
other = ((PartialStreetEdge) e).parentEdge;
}

// TODO(flamholz): is there a case where a partial edge has a reverse of its own?
return parentEdge.isReverseOf(other);
}

@Override
public boolean isRoundabout() {
return parentEdge.isRoundabout();
}

/**
* Returns true if this edge is trivial - beginning and ending at the same point.
*/
public boolean isTrivial() {
Coordinate fromCoord = this.getFromVertex().getCoordinate();
Coordinate toCoord = this.getToVertex().getCoordinate();
return fromCoord.equals(toCoord);
}

public StreetEdge getParentEdge() {
return parentEdge;
}

@Override
public String toString() {
return "PartialStreetEdge(" + this.getName() + ", " + this.getFromVertex() + " -> "
+ this.getToVertex() + " length=" + this.getDistance() + " carSpeed="
+ this.getCarSpeed() + " parentEdge=" + parentEdge + ")";
}

private void setElevationProfileUsingParents() {
setElevationProfile(
ElevationUtils.getPartialElevationProfile(
getParentEdge().getElevationProfile(), 0, getDistance()
),
false
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.opentripplanner.routing.edgetype;

import org.locationtech.jts.geom.LineString;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.vertextype.SplitterVertex;
import org.opentripplanner.routing.vertextype.StreetVertex;
import org.opentripplanner.util.I18NString;

/**
* This class is used to model a SemiPermanent StreetEdge that was non-destructively split from another StreetEdge.
* These StreetEdges are typically used to model access to things such as bike rental stations that are dynamically
* created from bike rental updaters and could be subsequently removed from the feed. These edges aid in providing
* access only when needed to the desired bike rental stations and also allow for the isolated removal of these edges
* when they are no longer needed.
*/
public class SemiPermanentPartialStreetEdge extends PartialStreetEdge {
public SemiPermanentPartialStreetEdge(
StreetEdge streetEdge,
StreetVertex v1,
StreetVertex v2,
LineString geometry,
I18NString name
) {
super(streetEdge, v1, v2, geometry, name, 0);
}

/**
* There can often times be requests that do not need to traverse this edge, such as requests that don't want to
* use a bike rental. In those cases, return null to avoid exploring this edge and any connected vertices further.
*/
@Override public State traverse(State s0) {
// TODO: add some conditions that would return null to avoid traversal
return super.traverse(s0);
}
}
32 changes: 24 additions & 8 deletions src/main/java/org/opentripplanner/routing/edgetype/StreetEdge.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.opentripplanner.routing.vertextype.BarrierVertex;
import org.opentripplanner.routing.vertextype.IntersectionVertex;
import org.opentripplanner.routing.vertextype.OsmVertex;
import org.opentripplanner.routing.vertextype.SemiPermanentSplitterVertex;
import org.opentripplanner.routing.vertextype.SplitterVertex;
import org.opentripplanner.routing.vertextype.StreetVertex;
import org.opentripplanner.routing.vertextype.TemporarySplitterVertex;
Expand Down Expand Up @@ -776,7 +777,7 @@ protected void calculateLengthFromGeometry () {
}

/** Split this street edge and return the resulting street edges */
public P2<StreetEdge> split(SplitterVertex v, boolean destructive) {
public P2<StreetEdge> split(SplitterVertex v, boolean destructive, boolean createSemiPermanentEdges) {
P2<LineString> geoms = GeometryUtils.splitGeometryAtPoint(getGeometry(), v.getCoordinate());

StreetEdge e1 = null;
Expand Down Expand Up @@ -837,14 +838,29 @@ public P2<StreetEdge> split(SplitterVertex v, boolean destructive) {
e.setBack(isBack());
}
} else {
if (((TemporarySplitterVertex) v).isEndVertex()) {
e1 = new TemporaryPartialStreetEdge(this, (StreetVertex) fromv, v, geoms.first, name);
e1.setNoThruTraffic(this.isNoThruTraffic());
e1.setStreetClass(this.getStreetClass());
if (createSemiPermanentEdges) {
e1 = new SemiPermanentPartialStreetEdge(this, (StreetVertex) fromv, v, geoms.first, name);
e2 = new SemiPermanentPartialStreetEdge(this, v, (StreetVertex) tov, geoms.second, name);

for (StreetEdge e : new StreetEdge[] { e1, e2 }) {
e.setBicycleSafetyFactor(getBicycleSafetyFactor());
e.setHasBogusName(hasBogusName());
e.setStairs(isStairs());
e.setWheelchairAccessible(isWheelchairAccessible());
e.setBack(isBack());
e.setNoThruTraffic(isNoThruTraffic());
e.setStreetClass(getStreetClass());
}
} else {
e2 = new TemporaryPartialStreetEdge(this, v, (StreetVertex) tov, geoms.second, name);
e2.setNoThruTraffic(this.isNoThruTraffic());
e2.setStreetClass(this.getStreetClass());
if (((TemporarySplitterVertex) v).isEndVertex()) {
e1 = new TemporaryPartialStreetEdge(this, (StreetVertex) fromv, v, geoms.first, name, 0);
e1.setNoThruTraffic(this.isNoThruTraffic());
e1.setStreetClass(this.getStreetClass());
} else {
e2 = new TemporaryPartialStreetEdge(this, v, (StreetVertex) tov, geoms.second, name, 0);
e2.setNoThruTraffic(this.isNoThruTraffic());
e2.setStreetClass(this.getStreetClass());
}
}
}
return new P2<>(e1, e2);
Expand Down
Loading

0 comments on commit 8db21bf

Please sign in to comment.