Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.dedicatedcode.paikka.service.BuildingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -38,6 +39,7 @@
@RestController
@RequestMapping("/admin")
@ConditionalOnProperty(name = "paikka.import-mode", havingValue = "false", matchIfMissing = true)
@ConditionalOnExpression("!'${paikka.admin.password}'.trim().isEmpty()")
public class AdminController {

private static final Logger logger = LoggerFactory.getLogger(AdminController.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ public ResponseEntity<Map<String, Object>> reverse(
"lang", lang,
"limit", effectiveLimit
));

Map<String, Object> metadata = metadataService.getMetadata();
response.put("metadata", metadata);
response.put("dataSources", Map.of("OpenStreetMap", "https://openstreetmap.org/copyright"));

return ResponseEntity.ok()
.header("X-Result-Count", String.valueOf(results.size()))
.header("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0") // No caching
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public GeoJsonGeometry getBoundaryGeometry(long osmId) {
WKBReader wkbReader = new WKBReader();
org.locationtech.jts.geom.Geometry jtsGeometry = wkbReader.read(geometryData);

return convertJtsToGeoJson(jtsGeometry);
return GeometryHelper.convertJtsToGeoJson(jtsGeometry);

} catch (RocksDBException e) {
logger.error("RocksDB error retrieving boundary for OSM ID {}: {}", osmId, e.getMessage());
Expand Down Expand Up @@ -175,68 +175,4 @@ private byte[] longToByteArray(long value) {
(byte) value
};
}

/**
* Convert JTS Geometry to GeoJSON format.
* This is a simplified conversion that handles basic geometry types.
*/
private GeoJsonGeometry convertJtsToGeoJson(org.locationtech.jts.geom.Geometry geometry) {
String geometryType = geometry.getGeometryType();
Object coordinates = null;

switch (geometryType) {
case "Point":
coordinates = new double[]{geometry.getCoordinate().x, geometry.getCoordinate().y};
break;
case "Polygon":
coordinates = extractPolygonCoordinates(geometry);
break;
case "MultiPolygon":
coordinates = extractMultiPolygonCoordinates(geometry);
break;
default:
logger.debug("Unsupported geometry type for GeoJSON conversion: {}", geometryType);
return new GeoJsonGeometry("Unknown", null);
}

return new GeoJsonGeometry(geometryType, coordinates);
}

private Object extractPolygonCoordinates(org.locationtech.jts.geom.Geometry polygon) {
try {
// Get exterior ring coordinates
org.locationtech.jts.geom.Coordinate[] coords = polygon.getCoordinates();
double[][] ring = new double[coords.length][2];

for (int i = 0; i < coords.length; i++) {
ring[i][0] = coords[i].x; // longitude
ring[i][1] = coords[i].y; // latitude
}

// GeoJSON polygon format: [[[x,y],[x,y],...]]
return new double[][][]{ring};
} catch (Exception e) {
logger.warn("Failed to extract polygon coordinates: {}", e.getMessage());
return null;
}
}

private Object extractMultiPolygonCoordinates(org.locationtech.jts.geom.Geometry multiPolygon) {
try {
List<double[][][]> polygons = new ArrayList<>();

for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
org.locationtech.jts.geom.Geometry polygon = multiPolygon.getGeometryN(i);
Object polyCoords = extractPolygonCoordinates(polygon);
if (polyCoords instanceof double[][][]) {
polygons.add((double[][][]) polyCoords);
}
}

return polygons.toArray(new double[0][][][]);
} catch (Exception e) {
logger.warn("Failed to extract multipolygon coordinates: {}", e.getMessage());
return null;
}
}
}
94 changes: 94 additions & 0 deletions src/main/java/com/dedicatedcode/paikka/service/GeometryHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* This file is part of paikka.
*
* Paikka is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 or
* any later version.
*
* Paikka is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
*/

package com.dedicatedcode.paikka.service;

import com.dedicatedcode.paikka.dto.GeoJsonGeometry;
import org.locationtech.jts.geom.Geometry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

public class GeometryHelper {
private static final Logger logger = LoggerFactory.getLogger(GeometryHelper.class);

public static GeoJsonGeometry convertJtsToGeoJson(Geometry geometry) {
String geometryType = geometry.getGeometryType();
Object coordinates = null;

switch (geometryType) {
case "Point":
coordinates = new double[]{geometry.getCoordinate().x, geometry.getCoordinate().y};
break;
case "Polygon":
// For polygons, we need to extract the exterior ring coordinates
// This is a simplified implementation
coordinates = extractPolygonCoordinates(geometry);
break;
case "MultiPolygon":
// For multipolygons, extract all polygon coordinates
coordinates = extractMultiPolygonCoordinates(geometry);
break;
default:
// For other geometry types, just indicate the type
logger.debug("Unsupported geometry type for GeoJSON conversion: {}", geometryType);
return new GeoJsonGeometry("Unknown", null);
}

return new GeoJsonGeometry(geometryType, coordinates);
}


private static Object extractPolygonCoordinates(Geometry polygon) {
try {
// Get exterior ring coordinates
org.locationtech.jts.geom.Coordinate[] coords = polygon.getCoordinates();
double[][] ring = new double[coords.length][2];

for (int i = 0; i < coords.length; i++) {
ring[i][0] = coords[i].x; // longitude
ring[i][1] = coords[i].y; // latitude
}

// GeoJSON polygon format: [[[x,y],[x,y],...]]
return new double[][][]{ring};
} catch (Exception e) {
logger.warn("Failed to extract polygon coordinates: {}", e.getMessage());
return null;
}
}

private static Object extractMultiPolygonCoordinates(Geometry multiPolygon) {
try {
List<double[][][]> polygons = new ArrayList<>();

for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
Geometry polygon = multiPolygon.getGeometryN(i);
Object polyCoords = extractPolygonCoordinates(polygon);
if (polyCoords instanceof double[][][]) {
polygons.add((double[][][]) polyCoords);
}
}

return polygons.toArray(new double[0][][][]);
} catch (Exception e) {
logger.warn("Failed to extract multipolygon coordinates: {}", e.getMessage());
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.dedicatedcode.paikka.config.PaikkaConfiguration;
import com.dedicatedcode.paikka.dto.GeoJsonGeometry;
import com.dedicatedcode.paikka.dto.POIResponse;
import com.dedicatedcode.paikka.exception.POINotFoundException;
import com.dedicatedcode.paikka.flatbuffers.*;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKBReader;
Expand Down Expand Up @@ -105,18 +104,7 @@ public synchronized void reloadDatabase() {
logger.warn("POI shards database reload completed but database is not available");
}
}

/**
* Find the nearest POI to the given coordinates.
*/
public POIResponse findNearestPOI(double lat, double lon, String lang) {
List<POIResponse> results = findNearbyPOIs(lat, lon, lang, 1);
if (results.isEmpty()) {
throw new POINotFoundException(String.format("No POI found within search radius for coordinates lat=%.6f, lon=%.6f", lat, lon));
}
return results.getFirst();
}


/**
* Find nearby POIs to the given coordinates.
*
Expand Down Expand Up @@ -411,7 +399,7 @@ private POIResponse convertPOIToResponse(POIData poi, double queryLat, double qu
Geometry geometry = wkbReader.read(poi.boundary());

// Create a simple GeoJSON representation
GeoJsonGeometry geoJsonGeometry = convertJtsToGeoJson(geometry);
GeoJsonGeometry geoJsonGeometry = GeometryHelper.convertJtsToGeoJson(geometry);
response.setBoundary(geoJsonGeometry);

logger.debug("POI {} has boundary geometry converted to GeoJSON", poi.id());
Expand Down Expand Up @@ -444,7 +432,7 @@ private void enhanceWithBuildingInfo(POIResponse response, POIData poi) {
try {
WKBReader wkbReader = new WKBReader();
Geometry geometry = wkbReader.read(buildingInfo.getBoundaryWkb());
GeoJsonGeometry geoJsonGeometry = convertJtsToGeoJson(geometry);
GeoJsonGeometry geoJsonGeometry = GeometryHelper.convertJtsToGeoJson(geometry);
response.setBoundary(geoJsonGeometry);
logger.debug("Enhanced POI {} with building boundary", poi.id());
} catch (Exception e) {
Expand All @@ -467,75 +455,7 @@ private record HierarchyData(int level, String type, String name, String code, l

private record POIWithDistance(POIData poi, double distance) {
}

/**
* Convert JTS Geometry to GeoJSON format.
* This is a simplified conversion that handles basic geometry types.
*/
private GeoJsonGeometry convertJtsToGeoJson(Geometry geometry) {
String geometryType = geometry.getGeometryType();
Object coordinates = null;

switch (geometryType) {
case "Point":
coordinates = new double[]{geometry.getCoordinate().x, geometry.getCoordinate().y};
break;
case "Polygon":
// For polygons, we need to extract the exterior ring coordinates
// This is a simplified implementation
coordinates = extractPolygonCoordinates(geometry);
break;
case "MultiPolygon":
// For multipolygons, extract all polygon coordinates
coordinates = extractMultiPolygonCoordinates(geometry);
break;
default:
// For other geometry types, just indicate the type
logger.debug("Unsupported geometry type for GeoJSON conversion: {}", geometryType);
return new GeoJsonGeometry("Unknown", null);
}

return new GeoJsonGeometry(geometryType, coordinates);
}

private Object extractPolygonCoordinates(Geometry polygon) {
try {
// Get exterior ring coordinates
org.locationtech.jts.geom.Coordinate[] coords = polygon.getCoordinates();
double[][] ring = new double[coords.length][2];

for (int i = 0; i < coords.length; i++) {
ring[i][0] = coords[i].x; // longitude
ring[i][1] = coords[i].y; // latitude
}

// GeoJSON polygon format: [[[x,y],[x,y],...]]
return new double[][][]{ring};
} catch (Exception e) {
logger.warn("Failed to extract polygon coordinates: {}", e.getMessage());
return null;
}
}

private Object extractMultiPolygonCoordinates(Geometry multiPolygon) {
try {
List<double[][][]> polygons = new ArrayList<>();

for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
Geometry polygon = multiPolygon.getGeometryN(i);
Object polyCoords = extractPolygonCoordinates(polygon);
if (polyCoords instanceof double[][][]) {
polygons.add((double[][][]) polyCoords);
}
}

return polygons.toArray(new double[0][][][]);
} catch (Exception e) {
logger.warn("Failed to extract multipolygon coordinates: {}", e.getMessage());
return null;
}
}


/**
* Build the geometry URL using the configured base URL and current data version.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ paikka.data-dir=./data
paikka.import.threads=16
paikka.import.chunk-size=100000

paikka.admin.password=

paikka.query.max-results=500
paikka.query.default-results=10
paikka.query.base-url=http://localhost:8080
Expand Down
Loading