AffineTransformationFunctions.java
/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jtstest.function;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.util.AffineTransformation;
import org.locationtech.jts.geom.util.AffineTransformationFactory;
import org.locationtech.jtstest.geomfunction.Metadata;
public class AffineTransformationFunctions
{
@Metadata(description="Transforms a geometry using 1, 2 or 3 control vectors")
public static Geometry transformByVectors(Geometry g, Geometry control)
{
int nControl = control.getNumGeometries();
Coordinate src[] = new Coordinate[nControl];
Coordinate dest[] = new Coordinate[nControl];
for (int i = 0; i < nControl; i++) {
Geometry contComp = control.getGeometryN(i);
Coordinate[] pts = contComp.getCoordinates();
src[i] = pts[0];
dest[i] = pts[1];
}
AffineTransformation trans = AffineTransformationFactory.createFromControlVectors(src, dest);
System.out.println(trans);
return trans.transform(g);
}
@Metadata(description="Transforms a geometry by mapping envelope baseline to target vector")
public static Geometry transformByBaseline(Geometry g, Geometry destBaseline)
{
Envelope env = g.getEnvelopeInternal();
Coordinate src0 = new Coordinate(env.getMinX(), env.getMinY());
Coordinate src1 = new Coordinate(env.getMaxX(), env.getMinY());
Coordinate[] destPts = destBaseline.getCoordinates();
Coordinate dest0 = destPts[0];
Coordinate dest1 = destPts[1];
AffineTransformation trans = AffineTransformationFactory.createFromBaseLines(src0, src1, dest0, dest1);
return trans.transform(g);
}
private static Coordinate envelopeCentre(Geometry g)
{
return g.getEnvelopeInternal().centre();
}
private static Coordinate envelopeLowerLeft(Geometry g)
{
Envelope env = g.getEnvelopeInternal();
return new Coordinate(env.getMinX(), env.getMinY());
}
public static Geometry transformToViewport(Geometry g, Geometry gViewport)
{
Envelope viewEnv = gViewport.getEnvelopeInternal();
Envelope env = g.getEnvelopeInternal();
AffineTransformation trans = viewportTrans(env, viewEnv, true);
return trans.transform(g);
}
private static AffineTransformation viewportTrans(Envelope srcEnv, Envelope viewEnv, boolean isIsotropic) {
// works even if W or H are zero, thanks to Java infinity value.
double scaleW = viewEnv.getWidth() / srcEnv.getWidth();
double scaleH = viewEnv.getHeight() / srcEnv.getHeight();
double scaleX = scaleW;
double scaleY = scaleH;
if (isIsotropic) {
// choose minimum scale to ensure source fits viewport
double scale = Math.min(scaleW, scaleH);
scaleX = scale;
scaleY = scale;
}
Coordinate centre = srcEnv.centre();
Coordinate viewCentre = viewEnv.centre();
AffineTransformation trans = AffineTransformation.scaleInstance(scaleX, scaleY, centre.x, centre.y);
// translate using envelope centres
trans.translate(viewCentre.x - centre.x, viewCentre.y - centre.y);
return trans;
}
public static Geometry stretchToViewport(Geometry g, Geometry gViewport)
{
Envelope viewEnv = gViewport.getEnvelopeInternal();
Envelope env = g.getEnvelopeInternal();
AffineTransformation trans = viewportTrans(env, viewEnv, false);
return trans.transform(g);
}
public static Geometry scale(Geometry g,
@Metadata(title="Scale factor")
double scale)
{
Coordinate centre = envelopeCentre(g);
AffineTransformation trans = AffineTransformation.scaleInstance(scale, scale, centre.x, centre.y);
return trans.transform(g);
}
public static Geometry reflectInX(Geometry g)
{
Coordinate centre = envelopeCentre(g);
AffineTransformation trans = AffineTransformation.scaleInstance(1, -1, centre.x, centre.y);
return trans.transform(g);
}
public static Geometry reflectInY(Geometry g)
{
Coordinate centre = envelopeCentre(g);
AffineTransformation trans = AffineTransformation.scaleInstance(-1, 1, centre.x, centre.y);
return trans.transform(g);
}
@Metadata(description="Rotate a geometry by an multiple of Pi radians")
public static Geometry rotateByPiMultiple(Geometry g,
@Metadata(title="Angle (multiple of Pi)")
double multipleOfPi)
{
Coordinate centre = envelopeCentre(g);
AffineTransformation trans = AffineTransformation.rotationInstance(multipleOfPi * Math.PI, centre.x, centre.y);
return trans.transform(g);
}
@Metadata(description="Rotate a geometry around a point by an multiple of Pi radians")
public static Geometry rotateByPiMultipleAroundPoint(Geometry g, Geometry pt,
@Metadata(title="Angle (multiple of Pi)")
double multipleOfPi)
{
Coordinate loc;
if (pt == null) {
loc = new Coordinate(0,0);
}
else {
loc = pt.getCoordinates()[0];
}
AffineTransformation trans = AffineTransformation.rotationInstance(multipleOfPi * Math.PI, loc.x, loc.y);
return trans.transform(g);
}
@Metadata(description="Rotate a geometry by an angle in radians")
public static Geometry rotate(Geometry g,
@Metadata(title="Angle (radians)")
double angle)
{
Coordinate centre = envelopeCentre(g);
AffineTransformation trans = AffineTransformation.rotationInstance(angle, centre.x, centre.y);
return trans.transform(g);
}
@Metadata(description="Rotate a geometry around a point by an angle in radians")
public static Geometry rotateAroundPoint(Geometry g, Geometry pt,
@Metadata(title="Angle (radians)")
double angle)
{
Coordinate loc;
if (pt == null) {
loc = new Coordinate(0,0);
}
else {
loc = pt.getCoordinates()[0];
}
AffineTransformation trans = AffineTransformation.rotationInstance(angle, loc.x, loc.y);
return trans.transform(g);
}
public static Geometry translateCentreToOrigin(Geometry g)
{
Coordinate centre = envelopeCentre(g);
AffineTransformation trans = AffineTransformation.translationInstance(-centre.x, -centre.y);
return trans.transform(g);
}
public static Geometry translateToOrigin(Geometry g)
{
Coordinate lowerLeft = envelopeLowerLeft(g);
AffineTransformation trans = AffineTransformation.translationInstance(-lowerLeft.x, -lowerLeft.y);
return trans.transform(g);
}
@Metadata(description="Translates a geometry by an offset (dx,dy)")
public static Geometry translate(Geometry g,
@Metadata(title="dX")
double dx,
@Metadata(title="dY")
double dy)
{
AffineTransformation trans = AffineTransformation.translationInstance(dx, dy);
return trans.transform(g);
}
}