ProjectionTransformer.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.calcite.runtime;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.CoordinateSequence;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.geom.MultiPoint;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.impl.CoordinateArraySequence;
import org.locationtech.jts.geom.util.GeometryTransformer;
import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.CoordinateTransform;
import org.locationtech.proj4j.CoordinateTransformFactory;
import org.locationtech.proj4j.ProjCoordinate;
import java.util.Locale;
import java.util.stream.Stream;
/**
* Transforms the projection of a geometry.
*/
public class ProjectionTransformer extends GeometryTransformer {
private final CoordinateTransform coordinateTransform;
/**
* Creates a transformer that reprojects geometries with the provided SRIDs.
*
* @param sourceSrid the source SRID
* @param targetSrid the target SRID
*/
public ProjectionTransformer(int sourceSrid, int targetSrid) {
CRSFactory crsFactory = new CRSFactory();
CoordinateReferenceSystem source = crsFactory
.createFromName(String.format(Locale.ROOT, "epsg:%s", sourceSrid));
CoordinateReferenceSystem target = crsFactory
.createFromName(String.format(Locale.ROOT, "epsg:%s", targetSrid));
CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
coordinateTransform = ctFactory.createTransform(source, target);
}
@Override protected CoordinateSequence transformCoordinates(
CoordinateSequence coordinateSequence, Geometry parent) {
Coordinate[] coordinateArray =
Stream.of(coordinateSequence.toCoordinateArray())
.map(this::transformCoordinate)
.toArray(Coordinate[]::new);
return new CoordinateArraySequence(coordinateArray);
}
private Coordinate transformCoordinate(Coordinate coordinate) {
ProjCoordinate c1 = new ProjCoordinate(coordinate.x, coordinate.y);
ProjCoordinate c2 = coordinateTransform.transform(c1, new ProjCoordinate());
return new Coordinate(c2.x, c2.y);
}
@Override protected Geometry transformPoint(Point geom, Geometry parent) {
try {
Geometry geometry = super.transformPoint(geom, parent);
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformMultiPoint(MultiPoint geom, Geometry parent) {
try {
Geometry geometry = super.transformMultiPoint(geom, parent);
if (geometry instanceof Point) {
geometry = factory.createMultiPoint(new Point[]{(Point) geometry});
}
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformLinearRing(LinearRing geom, Geometry parent) {
try {
Geometry geometry = super.transformLinearRing(geom, parent);
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformLineString(LineString geom, Geometry parent) {
try {
Geometry geometry = super.transformLineString(geom, parent);
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformMultiLineString(MultiLineString geom, Geometry parent) {
try {
Geometry geometry = super.transformMultiLineString(geom, parent);
if (geometry instanceof LineString) {
geometry = factory.createMultiLineString(new LineString[]{(LineString) geometry});
}
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformPolygon(Polygon geom, Geometry parent) {
try {
Geometry geometry = super.transformPolygon(geom, parent);
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) {
try {
Geometry geometry = super.transformMultiPolygon(geom, parent);
if (geometry instanceof Polygon) {
geometry = factory.createMultiPolygon(new Polygon[]{(Polygon) geometry});
}
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
@Override protected Geometry transformGeometryCollection(
GeometryCollection geom, Geometry parent) {
try {
Geometry geometry = super.transformGeometryCollection(geom, parent);
return withTargetSRID(geometry);
} catch (Exception e) {
return parent.getFactory().createEmpty(0);
}
}
private Geometry withTargetSRID(Geometry outputGeom) {
int srid = coordinateTransform.getTargetCRS().getProjection().getEPSGCode();
outputGeom.setSRID(srid);
return outputGeom;
}
}