Skip to content

Commit

Permalink
Retain up from polygon, add test file and document strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
SeifGhz committed Dec 10, 2024
1 parent f76b247 commit 333f677
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 20 deletions.
21 changes: 21 additions & 0 deletions docs/onebusaway-gtfs-transformer-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* [Path Expressions](#path-expressions-)
* [Retain an Entity](#retain-an-entity)
* [Remove an Entity](#remove-an-entity)
* [Retain Up From Polygon](#retain-up-from-polygon)
* [Trim a Trip](#trim-a-trip)
* [Generate Stop Times](#generate-stop-times)
* [Extend Service Calendars](#extend-service-calendars)
Expand Down Expand Up @@ -270,6 +271,26 @@ You can remove a specific entity from a feed.

Note that removing an entity has a cascading effect. If you remove a trip, all the stop times that depend on that
trip will also be removed. If you remove a route, all the trips and stop times for that route will be removed.

#### Retain Up From Polygon

Retain Up From Polygon is an operation that filters GTFS input data based on a specified geographic area, using a polygon defined in WKT (Well-Known Text) format, which is configurable in the JSON transformer snippet.

This strategy applies two main functions:

* **Retain Function**: retains **up** all stops, trips, and routes that are located inside the defined polygon, then the algorithm automatically applies a retain **down** to these entities.

* **Remove Function**: any entities not retained within the polygon are removed.

This strategy ensures that the GTFS output only contains data relevant to the geographical area concerned.

**Parameters**:

* **polygon**: a required argument, which accepts the polygon in WKT format using the WGS84 coordinate system (SRID: 4326). This polygon defines the area of interest for filtering.

```
{"op":"transform","class":"org.onebusaway.gtfs_transformer.impl.RetainUpFromPolygon","polygon":"POLYGON ((-123.0 37.0, -123.0 38.0, -122.0 38.0, -122.0 37.0, -123.0 37.0))"}
```

#### Trim a Trip

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,27 @@

import org.slf4j.LoggerFactory;

public class RemoveStopsOutsidePolygone implements GtfsTransformStrategy {
private final Logger log = LoggerFactory.getLogger(RemoveStopsOutsidePolygone.class);
public class RetainUpFromPolygon implements GtfsTransformStrategy {
private final Logger log = LoggerFactory.getLogger(RetainUpFromPolygon.class);

@CsvField(optional = true)
private String polygone;
@CsvField(optional = false)
private String polygon;

public void setPolygone(String polygone) {
this.polygone = polygone;
public void setPolygon(String polygon) {
this.polygon = polygon;
}

@Override
public String getName() {
return this.getClass().getSimpleName();
}

/*
* example:
* {"op":"transform","class":"org.onebusaway.gtfs_transformer.impl.RemoveStopsOutsidePolygone","polygone":wkt_polygone ..."}
*/

@Override
@Override
public void run(TransformContext transformContext, GtfsMutableRelationalDao gtfsMutableRelationalDao) {
Geometry geometry = buildPolygone(polygone);
Geometry geometry = buildPolygon(polygon);
EntityRetentionGraph graph = new EntityRetentionGraph(gtfsMutableRelationalDao);
graph.setRetainBlocks(false);
// browse all stops and retain only those inside polygone/multiPolygone
// browse all stops and retain only those inside polygon/multipolygon
if (geometry.isValid() && !geometry.isEmpty()){
for (Stop stop : gtfsMutableRelationalDao.getAllStops()) {
if (insidePolygon(geometry,stop.getLon(),stop.getLat())){
Expand All @@ -70,14 +65,14 @@ public void run(TransformContext transformContext, GtfsMutableRelationalDao gtfs
}

/*
* create polygone/multiPolygone from 'polygone' variable in json file
* create polygon/multiPolygon from 'polygon' variable in json file
* return Geometry variable
* return null if an exception is encountered when parsing the wkt string
*/
private Geometry buildPolygone(String wktPolygone) {
private Geometry buildPolygon(String polygonWKT) {
WKTReader reader = new WKTReader();
try{
return reader.read(wktPolygone);
return reader.read(polygonWKT);
} catch (ParseException e){
String message = String.format("Error parsing WKT string : %s", e.getMessage());
log.error(message);
Expand All @@ -86,9 +81,9 @@ private Geometry buildPolygone(String wktPolygone) {

}
/*
* insidePolygone returns boolean variable
* true: if polygone contains point
* false if point is outside polygone
* insidePolygon returns boolean variable
* true: if polygon contains point
* false if point is outside polygon
*/
private boolean insidePolygon(Geometry geometry, double lon, double lat) {
GeometryFactory geometryFactory = new GeometryFactory();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.onebusaway.gtfs_transformer.impl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.IOException;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.onebusaway.gtfs.services.GtfsMutableRelationalDao;
import org.onebusaway.gtfs.services.MockGtfs;
import org.onebusaway.gtfs_transformer.services.TransformContext;

public class RetainUpFromPolygonTest {

private RetainUpFromPolygon retainUpFromPolygon = new RetainUpFromPolygon();
private TransformContext _context = new TransformContext();
private MockGtfs _gtfs;

@BeforeEach
public void setup() throws IOException{

_gtfs = MockGtfs.create();
// Insert mock data into the GTFS for testing:
// 1 agency
_gtfs.putAgencies(1);
// 4 routes
_gtfs.putRoutes(4);
// 4 trips
_gtfs.putTrips(4, "r$0","sid$0");
// 8 stops
_gtfs.putStops(8);
// 13 stop times
_gtfs.putLines("stop_times.txt",
"trip_id,arrival_time,departure_time,stop_id,stop_sequence,stop_headsign,pickup_type,drop_off_type,shape_dist_traveled",
// Trip t0: sequence of stops s0,s1,s2,s3
"t0,08:00:00,08:25:00,s0,0,,,,",
"t0,08:30:00,08:55:00,s1,1,,,,",
"t0,09:00:00,09:55:00,s2,2,,,,",
"t0,10:00:00,10:30:00,s3,3,,,,",
// Trip t1: reverse sequence of stops s3,s2,s1,s0
"t1,08:00:00,08:25:00,s3,0,,,,",
"t1,08:30:00,08:55:00,s2,1,,,,",
"t1,09:00:00,09:55:00,s1,2,,,,",
"t1,10:00:00,10:00:00,s0,3,,,,",
// Trip t2: sequence of stops s3,s4,s5
"t2,10:00:00,10:55:00,s3,0,,,,",
"t2,11:00:00,11:25:00,s4,1,,,,",
"t2,11:30:00,11:55:00,s5,2,,,,",
// Trip t3: Additional stops
"t3,12:00:00,12:25:00,s6,0,,,,",
"t3,12:30:00,12:55:00,s7,1,,,,");
}

@Test
public void testRetainUpFromPolygonTest() throws IOException {
GtfsMutableRelationalDao dao = _gtfs.read();

// Define a polygon in WKT (Well-Known Text) format
// This polygon is designed to include only the first 4 stops (S0 to S4)
String polygonWKT = "POLYGON ((-122.308 47.653, -122.308 47.666, -122.307 47.666, -122.307 47.665, -122.307 47.661, -122.307 47.657, -122.307 47.653, -122.308 47.653))";
retainUpFromPolygon.setPolygon(polygonWKT);

// Execute the retainUpFromPolygon strategy based on the polygon
retainUpFromPolygon.run(_context, dao);

// Verify that the number of routes is reduced to 3
assertEquals(3,dao.getAllRoutes().size());

// Verify that the number of trips is reduced to 3
assertEquals(3,dao.getAllTrips().size());

// Verify that the number of stops is reduced to 6
assertEquals(6,dao.getAllStops().size());

// Verify that the number of stop times is reduced to 11
assertEquals(11,dao.getAllStopTimes().size());
}
}

0 comments on commit 333f677

Please sign in to comment.