/* * The JTS Topology Suite is a collection of Java classes that * implement the fundamental operations required to validate a given * geo-spatial data set to a known topological specification. * * Copyright (C) 2001 Vivid Solutions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.revolsys.geometry.model.util; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.impl.PointDoubleXY; import com.revolsys.math.Angle; /** * Supports creating {@link AffineTransformation}s defined by various kinds of * inputs and transformation mapping rules. * * @author Martin Davis * */ public class AffineTransformationFactory { /** * Creates a tranformation from a set of three control vectors. A control * vector consists of a source point and a destination point, which is the * image of the source point under the desired transformation. Three control * vectors allows defining a fully general affine transformation. * * @param src0 * @param src1 * @param src2 * @param dest0 * @param dest1 * @param dest2 * @return the computed transformation */ public static AffineTransformation mnewFromControlVectors(final Point src0, final Point src1, final Point src2, final Point dest0, final Point dest1, final Point dest2) { final AffineTransformationBuilder builder = new AffineTransformationBuilder(src0, src1, src2, dest0, dest1, dest2); return builder.getTransformation(); } /** * Creates an AffineTransformation defined by a maping between two baselines. * The computed transformation consists of: * <ul> * <li>a translation * from the start point of the source baseline to the start point of the destination baseline, * <li>a rotation through the angle between the baselines about the destination start point, * <li>and a scaling equal to the ratio of the baseline lengths. * </ul> * If the source baseline has zero length, an identity transformation is returned. * * @param src0 the start point of the source baseline * @param src1 the end point of the source baseline * @param dest0 the start point of the destination baseline * @param dest1 the end point of the destination baseline * @return the computed transformation */ public static AffineTransformation newFromBaseLines(final Point src0, final Point src1, final Point dest0, final Point dest1) { final Point rotPt = new PointDoubleXY(src0.getX() + dest1.getX() - dest0.getX(), src0.getY() + dest1.getY() - dest0.getY()); final double ang = Angle.angleBetweenOriented(src1, src0, rotPt); final double srcDist = src1.distancePoint(src0); final double destDist = dest1.distancePoint(dest0); // return identity if transformation would be degenerate if (srcDist == 0.0) { return new AffineTransformation(); } final double scale = destDist / srcDist; final AffineTransformation trans = AffineTransformation.translationInstance(-src0.getX(), -src0.getY()); trans.rotate(ang); trans.scale(scale, scale); trans.translate(dest0.getX(), dest0.getY()); return trans; } /** * Creates an AffineTransformation defined by a single control vector. A * control vector consists of a source point and a destination point, which is * the image of the source point under the desired transformation. This * produces a translation. * * @param src0 * the start point of the control vector * @param dest0 * the end point of the control vector * @return the computed transformation */ public static AffineTransformation newFromControlVectors(final Point src0, final Point dest0) { final double dx = dest0.getX() - src0.getX(); final double dy = dest0.getY() - src0.getY(); return AffineTransformation.translationInstance(dx, dy); } /** * Creates an AffineTransformation defined by a pair of control vectors. A * control vector consists of a source point and a destination point, which is * the image of the source point under the desired transformation. The * computed transformation is a combination of one or more of a uniform scale, * a rotation, and a translation (i.e. there is no shear component and no * reflection) * * @param src0 * @param src1 * @param dest0 * @param dest1 * @return the computed transformation * @return null if the control vectors do not determine a well-defined transformation */ public static AffineTransformation newFromControlVectors(final Point src0, final Point src1, final Point dest0, final Point dest1) { final Point rotPt = new PointDoubleXY(dest1.getX() - dest0.getX(), dest1.getY() - dest0.getY()); final double ang = Angle.angleBetweenOriented(src1, src0, rotPt); final double srcDist = src1.distancePoint(src0); final double destDist = dest1.distancePoint(dest0); if (srcDist == 0.0) { return null; } final double scale = destDist / srcDist; final AffineTransformation trans = AffineTransformation.translationInstance(-src0.getX(), -src0.getY()); trans.rotate(ang); trans.scale(scale, scale); trans.translate(dest0.getX(), dest0.getY()); return trans; } /** * Creates an AffineTransformation defined by a set of control vectors. * Between one and three vectors must be supplied. * * @param src * the source points of the vectors * @param dest * the destination points of the vectors * @return the computed transformation * @throws IllegalArgumentException * if the control vector arrays are too short, long or of different * lengths */ public static AffineTransformation newFromControlVectors(final Point[] src, final Point[] dest) { if (src.length != dest.length) { throw new IllegalArgumentException("Src and Dest arrays are not the same length"); } if (src.length <= 0) { throw new IllegalArgumentException("Too few control points"); } if (src.length > 3) { throw new IllegalArgumentException("Too many control points"); } if (src.length == 1) { return newFromControlVectors(src[0], dest[0]); } if (src.length == 2) { return newFromControlVectors(src[0], src[1], dest[0], dest[1]); } return mnewFromControlVectors(src[0], src[1], src[2], dest[0], dest[1], dest[2]); } }