I am trying to build a polygon (with long/lat coordinates) over a line between two points (long/lat as well). Basically what I used is line buffering with meters as an distance.
However I have noticed that my polygon is not exactly created with choosen buffer offset (e.g 100km as buffer gives me like ~75km range polygon on OpenStreetMap). How can I achieve correct precision of buffer in meters?
I am using Java GeoTools.
Line builder:
public GeoLineBuilder() throws SchemaException {
this.lineSchema = DataUtilities.createType(
"",
"Location",
"locations:LineString:srid=4326," + "id:Integer"
);
}
SimpleFeature buildLine(List<LocationPoint> points) {
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(lineSchema);
GeometryFactory geometryFactory = new GeometryFactory();
List<Coordinate> coordinates = points.stream().map(point -> new Coordinate(point.getLongtitude(), point.getLatitude())).collect(Collectors.toList());
LineString line = geometryFactory.createLineString(coordinates.toArray(new Coordinate[] {}));
featureBuilder.add(line);
return featureBuilder.buildFeature(null);
}
Polygon over the line with buffer in meters:
private SimpleFeature bufferLine(SimpleFeature feature, long distance) throws Exception {
GeometryAttribute gProp = feature.getDefaultGeometryProperty();
CoordinateReferenceSystem origCRS = gProp.getDescriptor()
.getCoordinateReferenceSystem();
Geometry geom = (Geometry) feature.getDefaultGeometry();
Geometry pGeom = geom;
MathTransform toTransform, fromTransform = null;
if (!(origCRS instanceof ProjectedCRS)) {
Point c = geom.getCentroid();
double x = c.getCoordinate().x;
double y = c.getCoordinate().y;
String code = "EPSG:3857";
CoordinateReferenceSystem auto = CRS.decode(code, true);
toTransform = CRS.findMathTransform(
DefaultGeographicCRS.WGS84, auto);
fromTransform = CRS.findMathTransform(auto,
DefaultGeographicCRS.WGS84);
pGeom = JTS.transform(geom, toTransform);
}
Geometry out = pGeom.buffer(distance);
Geometry retGeom = out;
if (!(origCRS instanceof ProjectedCRS)) {
retGeom = JTS.transform(out, fromTransform);
}
SimpleFeatureType schema = feature.getFeatureType();
SimpleFeatureTypeBuilder ftBuilder = new SimpleFeatureTypeBuilder();
ftBuilder.setCRS(origCRS);
ftBuilder.addAll(schema.getAttributeDescriptors());
ftBuilder.setName(schema.getName());
SimpleFeatureType nSchema = ftBuilder.buildFeatureType();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(nSchema);
List<Object> atts = feature.getAttributes();
for (int i = 0; i < atts.size(); i++) {
if (atts.get(i) instanceof Geometry) {
atts.set(i, retGeom);
}
}
return builder.buildFeature(null, atts.toArray());
}
Basically:
- I am building a line in EPSG:4326 to have a line with long/lat coordinates
- I am doing an EPSG:4326 -> EPSG:3857 transformation to be able to buffer by meters
- Actual buffering
- Reverse transformation to coordinates EPSG:4326 <- EPSG:3857
- Displaying received polygon on the openstreetmap map
I saw that when I choose Poznan and Paris coordinates as a line pair - received polygon was for sure smaller than selected buffering (100000 meters), it was like ~75000 meters instead.
How to approach this problem?