Skip to content

Commit

Permalink
Merge branch 'master' into 1912-fix-nested-gtfs-file-detection
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvansson authored Feb 6, 2025
2 parents d445678 + 02c5307 commit 13bf3f5
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,22 @@ public class PointNearOriginNotice extends ValidationNotice {
private final String filename;

/** The row of the faulty row. */
private final int csvRowNumber;
@Nullable private final Integer csvRowNumber;

/** The index of the feature in the feature collection. */
@Nullable private final Integer featureIndex;

/** The id of the faulty entity. */
@Nullable private final String entityId;

/** The name of the field that uses latitude value. */
private final String latFieldName;
@Nullable private final String latFieldName;

/** The latitude of the faulty row. */
private final double latFieldValue;

/** The name of the field that uses longitude value. */
private final String lonFieldName;
@Nullable private final String lonFieldName;

/** The longitude of the faulty row */
private final double lonFieldValue;
Expand All @@ -67,6 +70,7 @@ public PointNearOriginNotice(
this.latFieldValue = latFieldValue;
this.lonFieldName = lonFieldName;
this.lonFieldValue = lonFieldValue;
this.featureIndex = null;
}

public PointNearOriginNotice(
Expand All @@ -83,5 +87,22 @@ public PointNearOriginNotice(
this.latFieldValue = latFieldValue;
this.lonFieldName = lonFieldName;
this.lonFieldValue = lonFieldValue;
this.featureIndex = null;
}

public PointNearOriginNotice(
String filename,
String entityId,
double latFieldValue,
double lonFieldValue,
int featureIndex) {
this.filename = filename;
this.csvRowNumber = null;
this.entityId = entityId;
this.latFieldName = null;
this.latFieldValue = latFieldValue;
this.lonFieldName = null;
this.lonFieldValue = lonFieldValue;
this.featureIndex = featureIndex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,24 @@ public class PointNearPoleNotice extends ValidationNotice {
private final String filename;

/** The row of the faulty row. */
private final int csvRowNumber;
@Nullable private final Integer csvRowNumber;

/** The index of the feature in the feature collection. */
@Nullable private final Integer featureIndex;

/** The id of the faulty entity. */
@Nullable private final String entityId;

/** The name of the field that uses latitude value. */
private final String latFieldName;
@Nullable private final String latFieldName;

/** The latitude of the faulty row. */
private final double latFieldValue;

/** The name of the field that uses longitude value. */
private final String lonFieldName;
@Nullable private final String lonFieldName;

/** The longitude of the faulty row. */
/** The longitude of the faulty row */
private final double lonFieldValue;

public PointNearPoleNotice(
Expand All @@ -67,6 +70,7 @@ public PointNearPoleNotice(
this.latFieldValue = latFieldValue;
this.lonFieldName = lonFieldName;
this.lonFieldValue = lonFieldValue;
this.featureIndex = null;
}

public PointNearPoleNotice(
Expand All @@ -83,5 +87,22 @@ public PointNearPoleNotice(
this.latFieldValue = latFieldValue;
this.lonFieldName = lonFieldName;
this.lonFieldValue = lonFieldValue;
this.featureIndex = null;
}

public PointNearPoleNotice(
String filename,
String entityId,
double latFieldValue,
double lonFieldValue,
int featureIndex) {
this.filename = filename;
this.csvRowNumber = null;
this.entityId = entityId;
this.latFieldName = null;
this.latFieldValue = latFieldValue;
this.lonFieldName = null;
this.lonFieldValue = lonFieldValue;
this.featureIndex = featureIndex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ public GtfsGeoJsonFeature extractFeature(

String type = geometry.get(GtfsGeoJsonFeature.GEOMETRY_TYPE_FIELD_NAME).getAsString();

validateCoordinates(noticeContainer, featureIndex, geometry, gtfsGeoJsonFeature);

if (type.equals(GeometryType.POLYGON.getType())) {
gtfsGeoJsonFeature.setGeometryType(GeometryType.POLYGON);
Polygon polygon =
Expand Down Expand Up @@ -229,6 +231,40 @@ public GtfsGeoJsonFeature extractFeature(
return null;
}

private static void validateCoordinates(
NoticeContainer noticeContainer,
int featureIndex,
JsonObject geometry,
GtfsGeoJsonFeature gtfsGeoJsonFeature) {
// Validate that the coordinates are not near the origin or the poles
JsonArray coordinates =
geometry.getAsJsonArray(GtfsGeoJsonFeature.GEOMETRY_COORDINATES_FIELD_NAME);
for (int i = 0; i < coordinates.size(); i++) {
for (int j = 0; j < coordinates.get(i).getAsJsonArray().size(); j++) {
JsonArray point = coordinates.get(i).getAsJsonArray().get(j).getAsJsonArray();
double lon = point.get(0).getAsDouble();
double lat = point.get(1).getAsDouble();
if (Math.abs(lon) <= 1 && Math.abs(lat) <= 1) {
noticeContainer.addValidationNotice(
new PointNearOriginNotice(
GtfsGeoJsonFeature.FILENAME,
gtfsGeoJsonFeature.featureId(),
lat,
lon,
featureIndex));
} else if (Math.abs(lat) >= 89) {
noticeContainer.addValidationNotice(
new PointNearPoleNotice(
GtfsGeoJsonFeature.FILENAME,
gtfsGeoJsonFeature.featureId(),
lat,
lon,
featureIndex));
}
}
}
}

private static void addMissingRequiredFieldsNotices(
List<String> missingRequiredFields,
NoticeContainer noticeContainer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mobilitydata.gtfsvalidator.notice.DuplicateGeoJsonKeyNotice;
import org.mobilitydata.gtfsvalidator.notice.InvalidGeometryNotice;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.*;

/** Runs GeoJsonFileLoader on test json data. */
@RunWith(JUnit4.class)
Expand All @@ -23,6 +21,7 @@ public class GeoJsonFileLoaderTest {
static String validGeoJsonData;
static String invalidPolygonGeoJsonData;
static String duplicateGeoJsonKeyData;
static String invalidPointsGeoJsonData;
NoticeContainer noticeContainer;

@BeforeClass
Expand Down Expand Up @@ -138,10 +137,54 @@ public static void setUpBeforeClass() {
" ]",
"}");

invalidPointsGeoJsonData =
String.join(
"\n",
"{",
" 'type': 'FeatureCollection',",
" 'features': [",
" {",
" 'id': 'id1',",
" 'type': 'Feature',",
" 'geometry': {",
" 'type': 'Polygon',",
" 'coordinates': [",
" [",
" [0.0, 0.0],",
" [101.0, 0.0],",
" [101.0, 1.0],",
" [100.0, 1.0],",
" [100.0, 0.0]",
" ]",
" ]",
" },",
" 'properties': {}",
" },",
" {",
" 'id': 'id2',",
" 'type': 'Feature',",
" 'geometry': {",
" 'type': 'Polygon',",
" 'coordinates': [",
" [",
" [200.0, 0.0],",
" [201.0, 0.0],",
" [201.0, 2.0],",
" [200.0, -89.75],",
" [200.0, 0.0]",
" ]",
" ]",
" },",
" 'properties': {}",
" }",
" ]",
"}");

// Replace single quotes with double quotes for JSON compliance
validGeoJsonData = validGeoJsonData.replace("'", "\"");
invalidPolygonGeoJsonData = invalidPolygonGeoJsonData.replace("'", "\"");
duplicateGeoJsonKeyData = duplicateGeoJsonKeyData.replace("'", "\"");
invalidPointsGeoJsonData = invalidPointsGeoJsonData.replace("'", "\"");
}

@Before
Expand Down Expand Up @@ -200,6 +243,26 @@ public void testDuplicateGeoJsonKeyNotice() {
assertThat(notices.size()).isGreaterThan(0);
}

@Test
public void testPointNearOriginAndPole() {
// Testing for invalid points near origin and pole
createLoader(invalidPointsGeoJsonData);

// Check if the correct validation notice is generated for the invalid points
List<PointNearOriginNotice> originNotices =
noticeContainer.getValidationNotices().stream()
.filter(PointNearOriginNotice.class::isInstance)
.map(PointNearOriginNotice.class::cast)
.collect(Collectors.toList());
List<PointNearPoleNotice> poleNotices =
noticeContainer.getValidationNotices().stream()
.filter(PointNearPoleNotice.class::isInstance)
.map(PointNearPoleNotice.class::cast)
.collect(Collectors.toList());
assertThat(originNotices.size()).isGreaterThan(0);
assertThat(poleNotices.size()).isGreaterThan(0);
}

private GtfsEntityContainer createLoader(String jsonData) {
GeoJsonFileLoader loader = new GeoJsonFileLoader();
var fileDescriptor = new GtfsGeoJsonFileDescriptor();
Expand Down

0 comments on commit 13bf3f5

Please sign in to comment.