affinetransform.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 1,366 行 · 第 1/3 页

JAVA
1,366
字号
	}

	/**
	 * Set this transform to the result of performing tx followed by the
	 * original version of this. This is less common than normal concatenation,
	 * but can still be used to chain transformations from one space to another.
	 * In matrix form:
	 * <pre>
	 * [ this ] = [ tx ] x [ this ]
	 * </pre>
	 *
	 * @param tx the transform to concatenate
	 * @throws NullPointerException if tx is null
	 * @see #concatenate(AffineTransform)
	 */
	public void preConcatenate(AffineTransform tx) {
		double n00 = tx.m00 * m00 + tx.m01 * m10;
		double n01 = tx.m00 * m01 + tx.m01 * m11;
		double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02;
		double n10 = tx.m10 * m00 + tx.m11 * m10;
		double n11 = tx.m10 * m01 + tx.m11 * m11;
		double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12;
		m00 = n00;
		m01 = n01;
		m02 = n02;
		m10 = n10;
		m11 = n11;
		m12 = n12;
		updateType();
	}

	/**
	 * Returns a transform, which if concatenated to this one, will result in
	 * the identity transform. This is useful for undoing transformations, but
	 * is only possible if the original transform has an inverse (ie. does not
	 * map multiple points to the same line or point). A transform exists only
	 * if getDeterminant() has a non-zero value.
	 *
	 * @return a new inverse transform
	 * @throws NoninvertibleTransformException if inversion is not possible
	 * @see #getDeterminant()
	 */
	public AffineTransform createInverse() throws NoninvertibleTransformException {
		double det = getDeterminant();
		if (det == 0)
			throw new NoninvertibleTransformException("can't invert transform");
		return new AffineTransform(m11 / det, -m10 / det, m01 / det, -m00 / det, -m02, -m12);
	}

	/**
	 * Perform this transformation on the given source point, and store the
	 * result in the destination (creating it if necessary). It is safe for
	 * src and dst to be the same.
	 *
	 * @param src the source point
	 * @param dst the destination, or null
	 * @return the transformation of src, in dst if it was non-null
	 * @throws NullPointerException if src is null
	 */
	public Point2D transform(Point2D src, Point2D dst) {
		if (dst == null)
			dst = new Point2D.Double();
		double x = src.getX();
		double y = src.getY();
		double nx = m00 * x + m01 * y + m02;
		double ny = m10 * x + m11 * y + m12;
		dst.setLocation(nx, ny);
		return dst;
	}

	/**
	 * Perform this transformation on an array of points, storing the results
	 * in another (possibly same) array. This will not create a destination
	 * array, but will create points for the null entries of the destination.
	 * The transformation is done sequentially. While having a single source
	 * and destination point be the same is safe, you should be aware that
	 * duplicate references to the same point in the source, and having the
	 * source overlap the destination, may result in your source points changing
	 * from a previous transform before it is their turn to be evaluated.
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points (may have null entries)
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null, or src has null
	 *         entries
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 * @throws ArrayStoreException if new points are incompatible with dst
	 */
	public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int num) {
		while (--num >= 0)
			dst[dstOff] = transform(src[srcOff++], dst[dstOff++]);
	}

	/**
	 * Perform this transformation on an array of points, in (x,y) pairs,
	 * storing the results in another (possibly same) array. This will not
	 * create a destination array. All sources are copied before the
	 * transformation, so that no result will overwrite a point that has not yet
	 * been evaluated.
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 */
	public void transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int num) {
		if (srcPts == dstPts && dstOff > srcOff && num > 1 && srcOff + 2 * num > dstOff) {
			float[] f = new float[2 * num];
			System.arraycopy(srcPts, srcOff, f, 0, 2 * num);
			srcPts = f;
		}
		while (--num >= 0) {
			float x = srcPts[srcOff++];
			float y = srcPts[srcOff++];
			dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
			dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
		}
	}

	/**
	 * Perform this transformation on an array of points, in (x,y) pairs,
	 * storing the results in another (possibly same) array. This will not
	 * create a destination array. All sources are copied before the
	 * transformation, so that no result will overwrite a point that has not yet
	 * been evaluated.
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 */
	public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int num) {
		if (srcPts == dstPts && dstOff > srcOff && num > 1 && srcOff + 2 * num > dstOff) {
			double[] d = new double[2 * num];
			System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
			srcPts = d;
		}
		while (--num >= 0) {
			double x = srcPts[srcOff++];
			double y = srcPts[srcOff++];
			dstPts[dstOff++] = m00 * x + m01 * y + m02;
			dstPts[dstOff++] = m10 * x + m11 * y + m12;
		}
	}

	/**
	 * Perform this transformation on an array of points, in (x,y) pairs,
	 * storing the results in another array. This will not create a destination
	 * array.
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 */
	public void transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int num) {
		while (--num >= 0) {
			float x = srcPts[srcOff++];
			float y = srcPts[srcOff++];
			dstPts[dstOff++] = m00 * x + m01 * y + m02;
			dstPts[dstOff++] = m10 * x + m11 * y + m12;
		}
	}

	/**
	 * Perform this transformation on an array of points, in (x,y) pairs,
	 * storing the results in another array. This will not create a destination
	 * array.
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 */
	public void transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int num) {
		while (--num >= 0) {
			double x = srcPts[srcOff++];
			double y = srcPts[srcOff++];
			dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
			dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
		}
	}

	/**
	 * Perform the inverse of this transformation on the given source point,
	 * and store the result in the destination (creating it if necessary). It
	 * is safe for src and dst to be the same.
	 *
	 * @param src the source point
	 * @param dst the destination, or null
	 * @return the inverse transformation of src, in dst if it was non-null
	 * @throws NullPointerException if src is null
	 * @throws NoninvertibleTransformException if the inverse does not exist
	 * @see #getDeterminant()
	 */
	public Point2D inverseTransform(Point2D src, Point2D dst) throws NoninvertibleTransformException {
		double det = getDeterminant();
		if (det == 0)
			throw new NoninvertibleTransformException("couldn't invert transform");
		if (dst == null)
			dst = new Point2D.Double();
		double x = src.getX();
		double y = src.getY();
		double nx = (m11 * x + -m10 * y) / det - m02;
		double ny = (m01 * x + -m00 * y) / det - m12;
		dst.setLocation(nx, ny);
		return dst;
	}

	/**
	 * Perform the inverse of this transformation on an array of points, in
	 * (x,y) pairs, storing the results in another (possibly same) array. This
	 * will not create a destination array. All sources are copied before the
	 * transformation, so that no result will overwrite a point that has not yet
	 * been evaluated.
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 * @throws NoninvertibleTransformException if the inverse does not exist
	 * @see #getDeterminant()
	 */
	public void inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int num) throws NoninvertibleTransformException {
		double det = getDeterminant();
		if (det == 0)
			throw new NoninvertibleTransformException("couldn't invert transform");
		if (srcPts == dstPts && dstOff > srcOff && num > 1 && srcOff + 2 * num > dstOff) {
			double[] d = new double[2 * num];
			System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
			srcPts = d;
		}
		while (--num >= 0) {
			double x = srcPts[srcOff++];
			double y = srcPts[srcOff++];
			dstPts[dstOff++] = (m11 * x + -m10 * y) / det - m02;
			dstPts[dstOff++] = (m01 * x + -m00 * y) / det - m12;
		}
	}

	/**
	 * Perform this transformation, less any translation, on the given source
	 * point, and store the result in the destination (creating it if
	 * necessary). It is safe for src and dst to be the same. The reduced
	 * transform is equivalent to:
	 * <pre>
	 * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
	 * [ y' ]   [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
	 * </pre>
	 *
	 * @param src the source point
	 * @param dst the destination, or null
	 * @return the delta transformation of src, in dst if it was non-null
	 * @throws NullPointerException if src is null
	 */
	public Point2D deltaTransform(Point2D src, Point2D dst) {
		if (dst == null)
			dst = new Point2D.Double();
		double x = src.getX();
		double y = src.getY();
		double nx = m00 * x + m01 * y;
		double ny = m10 * x + m11 * y;
		dst.setLocation(nx, ny);
		return dst;
	}

	/**
	 * Perform this transformation, less any translation, on an array of points,
	 * in (x,y) pairs, storing the results in another (possibly same) array.
	 * This will not create a destination array. All sources are copied before
	 * the transformation, so that no result will overwrite a point that has
	 * not yet been evaluated. The reduced transform is equivalent to:
	 * <pre>
	 * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
	 * [ y' ]   [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
	 * </pre>
	 *
	 * @param src the array of source points
	 * @param srcOff the starting offset into src
	 * @param dst the array of destination points
	 * @param dstOff the starting offset into dst
	 * @param num the number of points to transform
	 * @throws NullPointerException if src or dst is null
	 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
	 */
	public void deltaTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int num) {
		if (srcPts == dstPts && dstOff > srcOff && num > 1 && srcOff + 2 * num > dstOff) {
			double[] d = new double[2 * num];
			System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
			srcPts = d;
		}
		while (--num >= 0) {
			double x = srcPts[srcOff++];
			double y = srcPts[srcOff++];
			dstPts[dstOff++] = m00 * x + m01 * y;
			dstPts[dstOff++] = m10 * x + m11 * y;
		}
	}

	/**
	 * Return a new Shape, based on the given one, where the path of the shape
	 * has been transformed by this transform. Notice that this uses GeneralPath,
	 * which only stores points in float precision.
	 *
	 * @param src the shape source to transform
	 * @return the shape, transformed by this
	 * @throws NullPointerException if src is null
	 * @see GeneralPath#transform(AffineTransform)
	 */
	public Shape createTransformedShape(Shape src) {
		GeneralPath p = new GeneralPath(src);
		p.transform(this);
		return p;
	}

	/**
	 * Returns a string representation of the transform, in the format:
	 * <code>"AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
	 *   + m10 + ", " + m11 + ", " + m12 + "]]"</code>.
	 *
	 * @return the string representation
	 */
	public String toString() {
		return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], [" + m10 + ", " + m11 + ", " + m12 + "]]";
	}

	/**
	 * Tests if this transformation is the identity:
	 * <pre>
	 * [ 1 0 0 ]
	 * [ 0 1 0 ]
	 * [ 0 0 1 ]
	 * </pre>
	 *
	 * @return true if this is the identity transform
	 */
	public boolean isIdentity() {
		// Rather than rely on type, check explicitly.
		return (m00 == 1 && m01 == 0 && m02 == 0 && m10 == 0 && m11 == 1 && m12 == 0);
	}

	/**
	 * Create a new transform of the same run-time type, with the same
	 * transforming properties as this one.
	 *
	 * @return the clone
	 */
	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
			throw (Error) new InternalError().initCause(e); // Impossible
		}
	}

	/**
	 * Return the hashcode for this transformation. The formula is not
	 * documented, but appears to be the same as:
	 * <pre>
	 * long l = Double.doubleToLongBits(getScaleX());
	 * l = l * 31 + Double.doubleToLongBits(getShearY());
	 * l = l * 31 + Double.doubleToLongBits(getShearX());
	 * l = l * 31 + Double.doubleToLongBits(getScaleY());
	 * l = l * 31 + Double.doubleToLongBits(getTranslateX());
	 * l = l * 31 + Double.doubleToLongBits(getTranslateY());
	 * return (int) ((l >> 32) ^ l);
	 * </pre>
	 *
	 * @return the hashcode
	 */
	public int hashCode() {
		long l = Double.doubleToLongBits(m00);
		l = l * 31 + Double.doubleToLongBits(m10);
		l = l * 31 + Double.doubleToLongBits(m01);
		l = l * 31 + Double.doubleToLongBits(m11);
		l = l * 31 + Double.doubleToLongBits(m02);
		l = l * 31 + Double.doubleToLongBits(m12);
		return (int) ((l >> 32) ^ l);
	}

	/**
	 * Compares two transforms for equality. This returns true if they have the
	 * same matrix values.
	 *
	 * @param o the transform to compare
	 * @return true if it is equal
	 */
	public boolean equals(Object obj) {
		if (!(obj instanceof AffineTransform))
			return false;
		AffineTransform t = (AffineTransform) obj;
		return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02 && m10 == t.m10 && m11 == t.m11 && m12 == t.m12);
	}

	/**
	 * Helper to decode the type from the matrix. This is not guaranteed
	 * to find the optimal type, but at least it will be valid.
	 */
	private void updateType() {
		double det = getDeterminant();
		if (det == 0) {
			type = TYPE_GENERAL_TRANSFORM;
			return;
		}
		// Scale (includes rotation by PI) or translation.
		if (m01 == 0 && m10 == 0) {
			if (m00 == m11)
				type = m00 == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE;
			else
				type = TYPE_GENERAL_SCALE;
			if (m02 != 0 || m12 != 0)
				type |= TYPE_TRANSLATION;
		}
		// Rotation.
		else if (m00 == m11 && m01 == -m10) {
			type = m00 == 0 ? TYPE_QUADRANT_ROTATION : TYPE_GENERAL_ROTATION;
			if (det != 1)
				type |= TYPE_UNIFORM_SCALE;
			if (m02 != 0 || m12 != 0)
				type |= TYPE_TRANSLATION;
		} else
			type = TYPE_GENERAL_TRANSFORM;
	}

	/**
	 * Reads a transform from an object stream.
	 *
	 * @param s the stream to read from
	 * @throws ClassNotFoundException if there is a problem deserializing
	 * @throws IOException if there is a problem deserializing
	 */
	private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
		s.defaultReadObject();
		updateType();
	}
} // class AffineTransform

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?