我目前正在尝试开发一种功能,必须返回特定半径内(例如10公里内)的所有位置。我正在使用hibernate的空间依赖关系。 这是我的实体的样子:
public class LocationEntity {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name = "LOCATION", columnDefinition = "geometry")
private Point location;
}
这是实体的存储库:
public interface LocationRepository extends JpaRepository<LocationEntity, Integer> {
@Query(value = "SELECT l from LocationEntity l WHERE within(l.location, :bounds) = true")
public List<LocationEntity> findWithin(@Param("bounds") Geometry bounds); }
这是调用存储库方法的方式:
GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
shapeFactory.setNumPoints(100);
shapeFactory.setCentre(new Coordinate(27.174835, 78.040753));
shapeFactory.setSize(2*10);
List<LocationEntity> locations = repository.findWithin(shapeFactory.createCircle());
我面临的问题是此方法返回的一些位置不在此radius之内。这是解决问题陈述的正确方法吗?
答案 0 :(得分:0)
最终找到了可行的解决方案。万一其他人遇到这个问题,请留我的方法。 代码来自问题的答案 here。
final GeometricShapeFactory shape = new GeometricShapeFactory(new GeometryFactory());// INFO :jts lib
GeometryFactory factory = new GeometryFactory();
Point center = factory.createPoint(new Coordinate(latitude, longitude));
center.setSRID(4326);
final Coordinate centreInUTM = new Coordinate(projectedToGeographic(center.getX(), center.getY()));
shape.setCentre(centreInUTM);
shape.setSize(2 * radius);// distance in meters e.g 10000 for 10 km
shape.setNumPoints(64);
String UtmZone = degreeToUtmConverter(latitude, longitude);
Integer longitudeZone = Integer.parseInt(UtmZone.split(",")[0]);
char latitudeZone = UtmZone.split(",")[1].charAt(0);
logger.info("longitude zone:" + longitudeZone);
logger.info("latitude zone:" + latitudeZone);
// WGS 1984 is a geographic coordinate system, and UTM is a projected coordinate
// system
Polygon polygon = new GeometryFactory().createPolygon(Arrays.stream(shape.createEllipse().getCoordinates())
.map(c -> geographicToProjected(c.getOrdinate(0), c.getOrdinate(1), longitudeZone, latitudeZone)).toArray(Coordinate[]::new));
List<LocationEntity> locations = repository.findWithin(polygon);
添加了将{/ {3}}中获取的经/纬度转换为UTM经/纬度区域的功能
private Coordinate projectedToGeographic(double latitude, double longitude) {
LatLong latlong = LatLong.valueOf(latitude, longitude, NonSI.DEGREE_ANGLE);
UTM utm = UTM.latLongToUtm(latlong, ReferenceEllipsoid.WGS84);
double cX = utm.getCoordinates()[0];
double cY = utm.getCoordinates()[1];
return new Coordinate(cX, cY);
}
private Coordinate geographicToProjected(double easting, double northing, Integer longitudeZone, char latitudeZone) {
UTM utm = UTM.valueOf(longitudeZone, latitudeZone, easting, northing, SI.METER);// INFO :18T UTM for NYC
CoordinatesConverter<UTM, LatLong> utmToLatLong = UTM.CRS.getConverterTo(LatLong.CRS);
LatLong latLong = utmToLatLong.convert(utm);
double cX = latLong.getCoordinates()[0];
double cY = latLong.getCoordinates()[1];
return new Coordinate(cX, cY);
}
private String degreeToUtmConverter(double Lat, double Lon) {
Integer zone;
char letter;
zone = (int) Math.floor(Lon / 6 + 31);
if (Lat < -72)
letter = 'C';
else if (Lat < -64)
letter = 'D';
else if (Lat < -56)
letter = 'E';
else if (Lat < -48)
letter = 'F';
else if (Lat < -40)
letter = 'G';
else if (Lat < -32)
letter = 'H';
else if (Lat < -24)
letter = 'J';
else if (Lat < -16)
letter = 'K';
else if (Lat < -8)
letter = 'L';
else if (Lat < 0)
letter = 'M';
else if (Lat < 8)
letter = 'N';
else if (Lat < 16)
letter = 'P';
else if (Lat < 24)
letter = 'Q';
else if (Lat < 32)
letter = 'R';
else if (Lat < 40)
letter = 'S';
else if (Lat < 48)
letter = 'T';
else if (Lat < 56)
letter = 'U';
else if (Lat < 64)
letter = 'V';
else if (Lat < 72)
letter = 'W';
else
letter = 'X';
return zone.toString() + "," + letter;
}