Skip to content

Commit 760c210

Browse files
authored
Merge pull request opentripplanner#7357 from entur/reduce-coordinate-allocation
Reduce coordinate allocation during response geometry construction
2 parents ac920fa + e6578c0 commit 760c210

4 files changed

Lines changed: 99 additions & 53 deletions

File tree

application/src/test/java/org/opentripplanner/model/plan/leg/ScheduledTransitLegTest.java

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import static org.junit.jupiter.api.Assertions.assertNotNull;
66
import static org.junit.jupiter.api.Assertions.assertNull;
77
import static org.junit.jupiter.api.Assertions.assertTrue;
8-
import static org.opentripplanner.transit.model._data.TimetableRepositoryForTest.id;
8+
import static org.opentripplanner.transit.model._data.FeedScopedIdForTestFactory.id;
99

1010
import java.time.Duration;
1111
import java.time.OffsetDateTime;
@@ -20,32 +20,41 @@
2020
import org.opentripplanner.model.fare.FareProduct;
2121
import org.opentripplanner.model.plan.Emission;
2222
import org.opentripplanner.routing.alertpatch.TransitAlert;
23-
import org.opentripplanner.transit.model._data.TimetableRepositoryForTest;
23+
import org.opentripplanner.transit.model._data.TransitTestEnvironment;
24+
import org.opentripplanner.transit.model._data.TransitTestEnvironmentBuilder;
25+
import org.opentripplanner.transit.model._data.TripInput;
26+
import org.opentripplanner.transit.model._data.TripOnDateDataFetcher;
2427
import org.opentripplanner.transit.model.basic.Money;
25-
import org.opentripplanner.transit.model.network.Route;
2628
import org.opentripplanner.transit.model.network.TripPattern;
29+
import org.opentripplanner.transit.model.site.RegularStop;
2730
import org.opentripplanner.transit.model.timetable.RealTimeTripTimes;
28-
import org.opentripplanner.transit.model.timetable.ScheduledTripTimes;
29-
import org.opentripplanner.transit.model.timetable.Trip;
31+
import org.opentripplanner.transit.model.timetable.TripTimes;
3032

3133
class ScheduledTransitLegTest {
3234

3335
private static final ZonedDateTime START_TIME = OffsetDateTime.parse(
3436
"2023-04-17T17:49:06+02:00"
3537
).toZonedDateTime();
3638
private static final ZonedDateTime END_TIME = START_TIME.plusMinutes(10);
37-
private static final TimetableRepositoryForTest TEST_MODEL = TimetableRepositoryForTest.of();
38-
private static final Route ROUTE = TimetableRepositoryForTest.route(id("2")).build();
39-
private static final TripPattern PATTERN = TimetableRepositoryForTest.tripPattern("1", ROUTE)
40-
.withStopPattern(TEST_MODEL.stopPattern(3))
41-
.build();
42-
private static final Trip TRIP = TimetableRepositoryForTest.trip("trip1").build();
43-
44-
private static final ScheduledTripTimes TRIP_TIMES = ScheduledTripTimes.of()
45-
.withArrivalTimes("10:00 11:00 12:00")
46-
.withDepartureTimes("10:01 11:02 12:03")
47-
.withTrip(TRIP)
48-
.build();
39+
private static final TransitTestEnvironmentBuilder ENV_BUILDER = TransitTestEnvironment.of();
40+
private static final RegularStop STOP_0 = ENV_BUILDER.stop("Stop_0", b ->
41+
b.withCoordinate(60.0, 10.0)
42+
);
43+
private static final RegularStop STOP_1 = ENV_BUILDER.stop("Stop_1", b ->
44+
b.withCoordinate(60.0, 10.01)
45+
);
46+
private static final RegularStop STOP_2 = ENV_BUILDER.stop("Stop_2", b ->
47+
b.withCoordinate(60.0, 10.02)
48+
);
49+
private static final TransitTestEnvironment ENV = ENV_BUILDER.addTrip(
50+
TripInput.of("trip1")
51+
.addStop(STOP_0, "10:00", "10:01")
52+
.addStop(STOP_1, "11:00", "11:02")
53+
.addStop(STOP_2, "12:00", "12:03")
54+
).build();
55+
private static final TripOnDateDataFetcher TRIP_DATA = ENV.tripData("trip1");
56+
private static final TripPattern PATTERN = TRIP_DATA.tripPattern();
57+
private static final TripTimes TRIP_TIMES = TRIP_DATA.scheduledTripTimes();
4958

5059
private static final int BOARD_STOP_INDEX_IN_PATTERN = 0;
5160
private static final int ALIGHT_STOP_INDEX_IN_PATTERN = 2;
@@ -174,14 +183,14 @@ void testToString() {
174183
assertEquals(
175184
"ScheduledTransitLeg{" +
176185
"from: Place{name: Stop_0, stop: RegularStop{F:Stop_0 Stop_0}, coordinate: (60.0, 10.0), vertexType: TRANSIT, viaLocationType: PASS_THROUGH}, " +
177-
"to: Place{name: Stop_2, stop: RegularStop{F:Stop_2 Stop_2}, coordinate: (60.0, 10.0), vertexType: TRANSIT, viaLocationType: VISIT}, " +
186+
"to: Place{name: Stop_2, stop: RegularStop{F:Stop_2 Stop_2}, coordinate: (60.0, 10.02), vertexType: TRANSIT, viaLocationType: VISIT}, " +
178187
"startTime: 2023-04-17T17:49:06, " +
179188
"endTime: 2023-04-17T17:59:06, " +
180189
"realTime: true, " +
181190
"distance: 900.0m, " +
182191
"generalizedCost: $980, " +
183-
"agencyId: F:A1, " +
184-
"routeId: F:Rtrip1, " +
192+
"agencyId: F:Agency1, " +
193+
"routeId: F:Route1, " +
185194
"tripId: F:trip1, " +
186195
"serviceDate: 2023-04-17, " +
187196
"boardRule: SCHEDULED, " +

street/src/main/java/org/opentripplanner/street/geometry/CompactLineStringUtils.java

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -141,39 +141,61 @@ public static LineString uncompactLineString(
141141
boolean reverse
142142
) {
143143
int[] coords = DlugoszVarLenIntPacker.unpack(packedCoords);
144-
int size = coords == null ? 2 : (coords.length / 2) + 2;
145-
Coordinate[] c = new Coordinate[size];
146144
double x0 = reverse ? xb : xa;
147145
double y0 = reverse ? yb : ya;
148146
double x1 = reverse ? xa : xb;
149147
double y1 = reverse ? ya : yb;
148+
int intermediateCount = coords == null ? 0 : coords.length / 2;
149+
Coordinate[] c = new Coordinate[intermediateCount + 2];
150150
c[0] = new Coordinate(x0, y0);
151151
if (coords != null) {
152152
int oix = IntUtils.round(x0 * FIXED_FLOAT_MULT);
153153
int oiy = IntUtils.round(y0 * FIXED_FLOAT_MULT);
154-
for (int i = 1; i < c.length - 1; i++) {
155-
int ix = oix + coords[(i - 1) * 2];
156-
int iy = oiy + coords[(i - 1) * 2 + 1];
157-
c[i] = new Coordinate(ix / FIXED_FLOAT_MULT, iy / FIXED_FLOAT_MULT);
158-
oix = ix;
159-
oiy = iy;
160-
}
154+
decodeDeltaCoordinates(coords, c, 1, oix, oiy);
161155
}
162156
c[c.length - 1] = new Coordinate(x1, y1);
163157
LineString out = GeometryUtils.makeLineString(c);
164-
if (reverse) {
165-
out = out.reverse();
166-
}
167-
return out;
158+
return reverse ? out.reverse() : out;
168159
}
169160

170161
/**
171-
* Wrapper for the above method in the case where there are no start/end coordinates provided.
172-
* 0-coordinates are added and then removed in order for the delta encoding to work correctly.
173-
* Same as the other version, but in a var-len int packed form (Dlugosz coding).
162+
* Uncompact a line string that was compacted without start/end endpoint context. Decodes the
163+
* delta-encoded coordinates directly without adding/removing dummy endpoints.
174164
*/
175165
public static LineString uncompactLineString(byte[] packedCoords, boolean reverse) {
176-
LineString lineString = uncompactLineString(0.0, 0.0, 0.0, 0.0, packedCoords, reverse);
177-
return GeometryUtils.removeStartEndCoordinatesFromLineString(lineString);
166+
int[] coords = DlugoszVarLenIntPacker.unpack(packedCoords);
167+
if (coords == null || coords.length == 0) {
168+
return GeometryUtils.makeLineString(new Coordinate[0]);
169+
}
170+
Coordinate[] c = new Coordinate[coords.length / 2];
171+
decodeDeltaCoordinates(coords, c, 0, 0, 0);
172+
LineString out = GeometryUtils.makeLineString(c);
173+
return reverse ? out.reverse() : out;
174+
}
175+
176+
/**
177+
* Decode delta-encoded coordinate pairs into a Coordinate array.
178+
*
179+
* @param coords Delta-encoded int pairs [dx0, dy0, dx1, dy1, ...]
180+
* @param out Target array to write decoded coordinates into
181+
* @param offset Starting index in {@code out} to write to
182+
* @param oix Initial x in fixed-point (start of delta chain)
183+
* @param oiy Initial y in fixed-point (start of delta chain)
184+
*/
185+
private static void decodeDeltaCoordinates(
186+
int[] coords,
187+
Coordinate[] out,
188+
int offset,
189+
int oix,
190+
int oiy
191+
) {
192+
int count = coords.length / 2;
193+
for (int i = 0; i < count; i++) {
194+
int ix = oix + coords[i * 2];
195+
int iy = oiy + coords[i * 2 + 1];
196+
out[offset + i] = new Coordinate(ix / FIXED_FLOAT_MULT, iy / FIXED_FLOAT_MULT);
197+
oix = ix;
198+
oiy = iy;
199+
}
178200
}
179201
}

street/src/main/java/org/opentripplanner/street/geometry/GeometryUtils.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,12 @@ public static LineString addStartEndCoordinatesToLineString(
105105
LineString lineString,
106106
Coordinate endCoord
107107
) {
108-
Coordinate[] coordinates = new Coordinate[lineString.getCoordinates().length + 2];
109-
coordinates[0] = startCoord;
110-
for (int j = 0; j < lineString.getCoordinates().length; j++) {
111-
coordinates[j + 1] = lineString.getCoordinates()[j];
112-
}
113-
coordinates[lineString.getCoordinates().length + 1] = endCoord;
114-
return makeLineString(coordinates);
115-
}
116-
117-
public static LineString removeStartEndCoordinatesFromLineString(LineString lineString) {
118-
Coordinate[] coordinates = new Coordinate[lineString.getCoordinates().length - 2];
119-
for (int j = 1; j < lineString.getCoordinates().length - 1; j++) {
120-
coordinates[j - 1] = lineString.getCoordinates()[j];
121-
}
122-
return makeLineString(coordinates);
108+
Coordinate[] c = lineString.getCoordinates();
109+
Coordinate[] result = new Coordinate[c.length + 2];
110+
result[0] = startCoord;
111+
System.arraycopy(c, 0, result, 1, c.length);
112+
result[c.length + 1] = endCoord;
113+
return makeLineString(result);
123114
}
124115

125116
public static GeometryFactory getGeometryFactory() {

street/src/test/java/org/opentripplanner/street/geometry/CompactLineStringUtilsTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,30 @@ public final void testCompactString() {
8080
assertTrue(lsi.equalsExact(ls2, 0.00000015));
8181
}
8282

83+
@Test
84+
public void testNoEndpointRoundTrip() {
85+
GeometryFactory gf = new GeometryFactory();
86+
87+
Coordinate[] points = {
88+
new Coordinate(-179.99, 1.12345),
89+
new Coordinate(10.123456, 59.654321),
90+
new Coordinate(179.99, 1.12345),
91+
};
92+
LineString original = gf.createLineString(points);
93+
94+
// Forward
95+
byte[] packed = CompactLineStringUtils.compactLineString(original, false);
96+
LineString result = CompactLineStringUtils.uncompactLineString(packed, false);
97+
assertEquals(original.getNumPoints(), result.getNumPoints());
98+
assertTrue(original.equalsExact(result, 0.0000015));
99+
100+
// Reverse
101+
LineString reversed = (LineString) original.reverse();
102+
result = CompactLineStringUtils.uncompactLineString(packed, true);
103+
assertEquals(reversed.getNumPoints(), result.getNumPoints());
104+
assertTrue(reversed.equalsExact(result, 0.0000015));
105+
}
106+
83107
@Test
84108
public final void testDlugoszVarLenIntPacker() {
85109
packTest(new int[] {}, 0);

0 commit comments

Comments
 (0)