All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotools.geometry.jts.TransformedShape Maven / Gradle / Ivy

Go to download

The main module contains the GeoTools public interfaces that are used by other GeoTools modules (and GeoTools applications). Where possible we make use industry standard terms as provided by OGC and ISO standards. The formal GeoTools public api consists of gt-metadata, jts and the gt-main module. The main module contains the default implementations that are available provided to other GeoTools modules using our factory system. Factories are obtained from an appropriate FactoryFinder, giving applications a chance configure the factory used using the Factory Hints facilities. FilterFactory ff = CommonFactoryFinder.getFilterFactory(); Expression expr = ff.add( expression1, expression2 ); If you find yourself using implementation specific classes chances are you doing it wrong: Expression expr = new AddImpl( expression1, expressiom2 );

The newest version!
/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
 *
 *    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;
 *    version 2.1 of the License.
 *
 *    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.
 */
package org.geotools.geometry.jts;

// J2SE dependencies

import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.geotools.referencing.operation.matrix.XAffineTransform;

/**
 * Apply an arbitrary {@link AffineTransform} on a {@link Shape}. This class is used internally by
 * {@link RenderedMarks}. It is designed for reuse with many different affine transforms and shapes.
 * This class is not thread-safe.
 *
 * @version $Id$
 * @author Martin Desruisseaux (IRD)
 */
public final class TransformedShape extends AffineTransform implements Shape {
    /** The wrapped shape. */
    public Shape shape;

    /** A temporary point. */
    private final Point2D.Double point = new Point2D.Double();

    /** A temporary rectangle. */
    private final Rectangle2D.Double rectangle = new Rectangle2D.Double();

    /** Construct a transformed shape initialized to the identity transform. */
    public TransformedShape() {}

    /** Construct a transformed shape */
    public TransformedShape(Shape shape, AffineTransform at) {
        this.shape = shape;
        setTransform(at);
    }

    /** Returns the 6 coefficients values. */
    public void getMatrix(final float[] matrix, int offset) {
        matrix[offset] = (float) getScaleX(); // m00
        matrix[++offset] = (float) getShearY(); // m10
        matrix[++offset] = (float) getShearX(); // m01
        matrix[++offset] = (float) getScaleY(); // m11
        matrix[++offset] = (float) getTranslateX(); // m02
        matrix[++offset] = (float) getTranslateY(); // m12
    }

    /**
     * Set the transform from a flat matrix.
     *
     * @param matrix The flat matrix.
     * @param offset The index of the first element to use in matrix.
     */
    public void setTransform(final float[] matrix, int offset) {
        setTransform(
                matrix[offset],
                matrix[++offset],
                matrix[++offset],
                matrix[++offset],
                matrix[++offset],
                matrix[++offset]);
    }

    /**
     * Set the transform from a flat matrix.
     *
     * @param matrix The flat matrix.
     */
    public void setTransform(final double[] matrix) {
        setTransform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
    }

    /** Apply a uniform scale. */
    public void scale(final double s) {
        scale(s, s);
    }

    /** Tests if the specified coordinates are inside the boundary of the Shape. */
    public boolean contains(double x, double y) {
        point.x = x;
        point.y = y;
        return contains(point);
    }

    /** Tests if a specified {@link Point2D} is inside the boundary of the Shape. */
    public boolean contains(final Point2D p) {
        try {
            return shape.contains(inverseTransform(p, point));
        } catch (NoninvertibleTransformException exception) {
            exceptionOccured(exception, "contains");
            return false;
        }
    }

    /**
     * Tests if the interior of the Shape entirely contains the specified rectangular
     * area.
     */
    public boolean contains(double x, double y, double width, double height) {
        rectangle.x = x;
        rectangle.y = y;
        rectangle.width = width;
        rectangle.height = height;
        return contains(rectangle);
    }

    /**
     * Tests if the interior of the Shape entirely contains the specified 
     * Rectangle2D. This method might conservatively return false.
     */
    public boolean contains(final Rectangle2D r) {
        try {
            return shape.contains(XAffineTransform.inverseTransform(this, r, rectangle));
        } catch (NoninvertibleTransformException exception) {
            exceptionOccured(exception, "contains");
            return false;
        }
    }

    /**
     * Tests if the interior of the Shape intersects the interior of a specified
     * rectangular area.
     */
    public boolean intersects(double x, double y, double width, double height) {
        rectangle.x = x;
        rectangle.y = y;
        rectangle.width = width;
        rectangle.height = height;
        return intersects(rectangle);
    }

    /**
     * Tests if the interior of the Shape intersects the interior of a specified 
     * Rectangle2D. This method might conservatively return true.
     */
    public boolean intersects(final Rectangle2D r) {
        try {
            return shape.intersects(XAffineTransform.inverseTransform(this, r, rectangle));
        } catch (NoninvertibleTransformException exception) {
            exceptionOccured(exception, "intersects");
            return false;
        }
    }

    /** Returns an integer {@link Rectangle} that completely encloses the Shape. */
    public Rectangle getBounds() {
        Rectangle2D rect = getBounds2D();
        int minx = (int) Math.floor(rect.getMinX());
        int miny = (int) Math.floor(rect.getMinY());
        int maxx = (int) Math.ceil(rect.getMaxX());
        int maxy = (int) Math.ceil(rect.getMaxY());
        return new Rectangle(minx, miny, maxx - minx, maxy - miny);
    }

    /**
     * Returns a high precision and more accurate bounding box of the Shape than the
     * getBounds method.
     *
     * @todo REVISIT: tranform currently results in a new rectangle being created, is this a memory
     *     overhead?
     */
    public Rectangle2D getBounds2D() {
        final Rectangle2D rect = shape.getBounds2D();
        return XAffineTransform.transform(this, rect, null);
        // REVISIT: used to read (this,rect,rect) - this can result in an
        // unmidifiable geometry exception
    }

    /**
     * Returns an iterator object that iterates along the Shape boundary and provides
     * access to the geometry of the Shape outline.
     */
    public PathIterator getPathIterator(AffineTransform at) {
        if (!isIdentity()) {
            if (at == null || at.isIdentity()) {
                return shape.getPathIterator(this);
            }
            at = new AffineTransform(at);
            at.concatenate(this);
        }
        return shape.getPathIterator(at);
    }

    /**
     * Returns an iterator object that iterates along the Shape boundary and provides
     * access to a flattened view of the Shape outline geometry.
     */
    public PathIterator getPathIterator(AffineTransform at, final double flatness) {
        if (!isIdentity()) {
            if (at == null || at.isIdentity()) {
                return shape.getPathIterator(this, flatness);
            }
            at = new AffineTransform(at);
            at.concatenate(this);
        }
        return shape.getPathIterator(at, flatness);
    }

    /**
     * Invoked when an inverse transform was required but the transform is not invertible. This
     * error should not happen. However, even if it happen, it will not prevent the application to
     * work since contains(...) method may conservatively return false. We
     * will just log a warning message and continue.
     */
    private static void exceptionOccured(
            final NoninvertibleTransformException exception, final String method) {
        final LogRecord record = new LogRecord(Level.WARNING, exception.getLocalizedMessage());
        record.setSourceClassName(TransformedShape.class.getName());
        record.setSourceMethodName(method);
        record.setThrown(exception);
        org.geotools.util.logging.Logging.getLogger(TransformedShape.class).log(record);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy