Search in sources :

Example 1 with GeometryWrapper

use of org.apache.sis.internal.feature.GeometryWrapper in project sis by apache.

the class BinaryGeometryFilter method optimize.

/**
 * Tries to optimize this filter. This method checks if any expression is a literal.
 * If both expressions are literal, we can evaluate immediately. If any expression
 * is a literal and returns {@code null}, then the result is known in advance too.
 */
@Override
public final Filter<? super R> optimize(final Optimization optimization) {
    Expression<? super R, ?> geometry1 = unwrap(expression1);
    Expression<? super R, ?> geometry2 = unwrap(expression2);
    Expression<? super R, ?> effective1 = optimization.apply(geometry1);
    Expression<? super R, ?> effective2 = optimization.apply(geometry2);
    // The expression which is not literal.
    Expression<? super R, ?> other;
    Expression<? super R, GeometryWrapper<G>> wrapper;
    Literal<? super R, ?> literal;
    // true if the filter should be evaluated immediately.
    boolean immediate;
    // true if one of the literal value is null.
    boolean literalIsNull;
    if (effective2 instanceof Literal<?, ?>) {
        other = effective1;
        wrapper = expression2;
        literal = (Literal<? super R, ?>) effective2;
        immediate = (effective1 instanceof Literal<?, ?>);
    } else if (effective1 instanceof Literal<?, ?>) {
        other = effective2;
        wrapper = expression1;
        literal = (Literal<? super R, ?>) effective1;
        immediate = false;
    } else {
        return this;
    }
    literalIsNull = (literal.getValue() == null);
    final boolean result;
    if (literalIsNull) {
        // If the literal has no value, then the filter will always evaluate to a negative result.
        result = negativeResult();
    } else {
        /*
             * If we are optimizing for a feature type, and if the other expression is a property value,
             * then try to fetch the CRS of the property values. If we can transform the literal to that
             * CRS, do it now in order to avoid doing this transformation for all feature instances.
             */
        final DefaultFeatureType featureType = optimization.getFeatureType();
        if (featureType != null && other instanceof ValueReference<?, ?>)
            try {
                final CoordinateReferenceSystem targetCRS = AttributeConvention.getCRSCharacteristic(featureType, featureType.getProperty(((ValueReference<?, ?>) other).getXPath()));
                if (targetCRS != null) {
                    final GeometryWrapper<G> geometry = wrapper.apply(null);
                    final GeometryWrapper<G> transformed = geometry.transform(targetCRS);
                    if (geometry != transformed) {
                        literal = (Literal<? super R, ?>) Optimization.literal(transformed);
                        if (literal == effective1)
                            effective1 = literal;
                        else
                            effective2 = literal;
                    }
                }
            } catch (IllegalArgumentException | TransformException e) {
                warning(e, true);
            }
        /*
             * If one of the "effective" parameter has been modified, recreate a new filter.
             * If all operands are literal, we can evaluate that filter immediately.
             */
        Filter<? super R> filter = this;
        if ((effective1 != geometry1) || (effective2 != geometry2)) {
            filter = recreate(effective1, effective2);
        }
        if (!immediate) {
            return filter;
        }
        result = filter.test(null);
    }
    return result ? Filter.include() : Filter.exclude();
}
Also used : DefaultFeatureType(org.apache.sis.feature.DefaultFeatureType) Literal(org.apache.sis.internal.geoapi.filter.Literal) GeometryWrapper(org.apache.sis.internal.feature.GeometryWrapper) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem)

Example 2 with GeometryWrapper

use of org.apache.sis.internal.feature.GeometryWrapper in project sis by apache.

the class Factory method createFromComponents.

/**
 * Creates a geometry from components.
 * The expected {@code components} type depend on the target geometry type:
 * <ul>
 *   <li>If {@code type} is a multi-geometry, then the components shall be an array of {@link Shape} elements.</li>
 *   <li>Otherwise the components shall be an array or collection of {@link Point2D} instances.</li>
 * </ul>
 *
 * @param  type        type of geometry to create.
 * @param  components  the components. Valid classes depend on the type of geometry to create.
 * @return geometry built from the given components.
 * @throws ClassCastException if the given object is not an array or a collection of supported geometry components.
 */
@Override
@SuppressWarnings("fallthrough")
public GeometryWrapper<Shape> createFromComponents(final GeometryType type, final Object components) {
    /*
         * No exhaustive `if (x instanceof y)` checks in this method.
         * `ClassCastException` shall be handled by the caller.
         */
    final Collection<?> data = (components instanceof Collection<?>) ? (Collection<?>) components : Arrays.asList((Object[]) components);
    /*
         * Java2D API does not distinguish between single geometry and geometry collection.
         * So if the number of components is 1, there is no reason to create a new geometry object.
         */
    Shape geometry = (Shape) CollectionsExt.singletonOrNull(data);
    if (geometry == null) {
        boolean isFloat = true;
        for (final Object component : data) {
            isFloat = AbstractShape.isFloat(component);
            if (!isFloat)
                break;
        }
        final Path2D path = createPath(isFloat, 20);
        if (type.isCollection()) {
            for (final Object component : data) {
                path.append((Shape) component, false);
            }
        } else {
            final Iterator<?> it = data.iterator();
            if (it.hasNext()) {
                Point2D p = (Point2D) it.next();
                path.moveTo(p.getX(), p.getY());
                while (it.hasNext()) {
                    p = (Point2D) it.next();
                    path.lineTo(p.getX(), p.getY());
                }
                if (type == GeometryType.POLYGON) {
                    path.closePath();
                }
            }
        }
        // path.trimToSize();       // TODO: uncomment with JDK10.
        geometry = path;
    }
    return new Wrapper(geometry);
}
Also used : GeometryWrapper(org.apache.sis.internal.feature.GeometryWrapper) Shape(java.awt.Shape) AbstractShape(org.apache.sis.internal.referencing.j2d.AbstractShape) Point2D(java.awt.geom.Point2D) Path2D(java.awt.geom.Path2D) Collection(java.util.Collection)

Example 3 with GeometryWrapper

use of org.apache.sis.internal.feature.GeometryWrapper in project sis by apache.

the class Factory method createMultiPolygon.

/**
 * Creates a multi-polygon from an array of geometries.
 * Callers must ensure that the given objects are Java2D geometries.
 *
 * @param  geometries  the polygons or linear rings to put in a multi-polygons.
 * @throws ClassCastException if an element in the array is not a Java2D geometry.
 */
@Override
public GeometryWrapper<Shape> createMultiPolygon(final Object[] geometries) {
    if (geometries.length == 1) {
        return new Wrapper((Shape) unwrap(geometries[0]));
    }
    final Shape[] shapes = new Shape[geometries.length];
    for (int i = 0; i < geometries.length; i++) {
        shapes[i] = (Shape) unwrap(geometries[i]);
    }
    boolean isFloat = true;
    for (final Shape geometry : shapes) {
        if (!AbstractShape.isFloat(geometry)) {
            isFloat = false;
            break;
        }
    }
    final Path2D path = createPath(isFloat, 20);
    for (final Shape geometry : shapes) {
        path.append(geometry, false);
    }
    // path.trimToSize();       // TODO: uncomment with JDK10.
    return new Wrapper(path);
}
Also used : GeometryWrapper(org.apache.sis.internal.feature.GeometryWrapper) Shape(java.awt.Shape) AbstractShape(org.apache.sis.internal.referencing.j2d.AbstractShape) Path2D(java.awt.geom.Path2D)

Example 4 with GeometryWrapper

use of org.apache.sis.internal.feature.GeometryWrapper in project sis by apache.

the class Factory method createFromComponents.

/**
 * Creates a geometry from components.
 * The expected {@code components} type depend on the target geometry type:
 * <ul>
 *   <li>If {@code type} is a multi-geometry, then the components shall be an array of {@link Point},
 *       {@link Geometry}, {@link Polyline} or {@link Polygon} elements, depending on the desired target type.</li>
 *   <li>Otherwise the components shall be an array or collection of {@link Point} instances.</li>
 * </ul>
 *
 * @param  type        type of geometry to create.
 * @param  components  the components. Valid classes depend on the type of geometry to create.
 * @return geometry built from the given components.
 * @throws ClassCastException if the given object is not an array or a collection of supported geometry components.
 */
@Override
public GeometryWrapper<Geometry> createFromComponents(final GeometryType type, final Object components) {
    /*
         * No exhaustive `if (x instanceof y)` checks in this method.
         * `ClassCastException` shall be handled by the caller.
         */
    final Collection<?> data = (components instanceof Collection<?>) ? (Collection<?>) components : Arrays.asList((Object[]) components);
    /*
         * ESRI API does not distinguish between single geometry and geometry collection, except MultiPoint.
         * So if the number of components is 1, there is no reason to create a new geometry object.
         */
    Geometry geometry = (Geometry) CollectionsExt.singletonOrNull(data);
    if (geometry == null) {
        boolean isPolygon = false;
        switch(type) {
            case MULTI_LINESTRING:
            case LINESTRING:
                break;
            case MULTI_POLYGON:
            case POLYGON:
                isPolygon = true;
                break;
            case GEOMETRY_COLLECTION:
                {
                    for (final Object component : data) {
                        isPolygon = (((Geometry) component).getType() == Geometry.Type.Polygon);
                        if (!isPolygon)
                            break;
                    }
                    break;
                }
            // Default to multi-points for now.
            case GEOMETRY:
            case POINT:
            case MULTI_POINT:
                {
                    final MultiPoint points = new MultiPoint();
                    for (final Object p : data) {
                        points.add((Point) p);
                    }
                    geometry = points;
                    if (type == GeometryType.POINT) {
                        geometry = new Point(OperatorCentroid2D.local().execute(geometry, null));
                    }
                    break;
                }
            default:
                throw new AssertionError(type);
        }
        if (geometry == null) {
            final MultiPath path = isPolygon ? new Polygon() : new Polyline();
            if (type.isCollection()) {
                for (final Object component : data) {
                    path.add((MultiPath) component, false);
                }
            } else {
                final Iterator<?> it = data.iterator();
                if (it.hasNext()) {
                    final Line segment = new Line();
                    segment.setEnd((Point) it.next());
                    while (it.hasNext()) {
                        segment.setStartXY(segment.getEndX(), segment.getEndY());
                        segment.setEnd((Point) it.next());
                        path.addSegment(segment, false);
                    }
                }
            }
            geometry = path;
        }
    }
    return new Wrapper(geometry);
}
Also used : MultiPoint(com.esri.core.geometry.MultiPoint) MultiPath(com.esri.core.geometry.MultiPath) GeometryWrapper(org.apache.sis.internal.feature.GeometryWrapper) MultiPoint(com.esri.core.geometry.MultiPoint) Point(com.esri.core.geometry.Point) Geometry(com.esri.core.geometry.Geometry) Line(com.esri.core.geometry.Line) Polyline(com.esri.core.geometry.Polyline) Collection(java.util.Collection) Polygon(com.esri.core.geometry.Polygon)

Example 5 with GeometryWrapper

use of org.apache.sis.internal.feature.GeometryWrapper in project sis by apache.

the class JTSTest method testSetCoordinateReferenceSystem.

/**
 * Tests {@link Wrapper#setCoordinateReferenceSystem(CoordinateReferenceSystem)}.
 */
@Test
public void testSetCoordinateReferenceSystem() {
    final GeometryFactory factory = Factory.INSTANCE.factory(false);
    final CoordinateReferenceSystem crs2D = CommonCRS.WGS84.geographic();
    final CoordinateReferenceSystem crs3D = CommonCRS.WGS84.geographic3D();
    {
        /*
             * Test setting a 2D CRS on a 2 dimensional geometry.
             */
        final Geometry geometry = factory.createPoint(new CoordinateXY(5, 6));
        final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get();
        wrapper.setCoordinateReferenceSystem(crs2D);
        assertEquals(crs2D, wrapper.getCoordinateReferenceSystem());
    }
    {
        /*
             * Test setting a 2D CRS on a 3 dimensional geometry.
             */
        final Geometry geometry = factory.createPoint(new Coordinate(5, 6, 7));
        final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get();
        try {
            wrapper.setCoordinateReferenceSystem(crs2D);
            fail("Setting a 2D CRS on a 3D geometry must fail.");
        } catch (MismatchedDimensionException ex) {
            assertTrue(ex.getMessage().contains("crs"));
        // ok
        }
    }
    {
        /*
             * Test setting a 3D CRS on a 3 dimensional geometry.
             */
        final Geometry geometry = factory.createPoint(new Coordinate(5, 6, 7));
        final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get();
        wrapper.setCoordinateReferenceSystem(crs3D);
        assertEquals(crs3D, wrapper.getCoordinateReferenceSystem());
    }
    {
        /*
             * Test setting a 3D CRS on a 2 dimensional geometry.
             */
        final Geometry geometry = factory.createPoint(new CoordinateXY(5, 6));
        final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get();
        try {
            wrapper.setCoordinateReferenceSystem(crs3D);
            fail("Setting a 3D CRS on a 2D geometry must fail.");
        } catch (MismatchedDimensionException ex) {
            assertTrue(ex.getMessage().contains("crs"));
        // ok
        }
    }
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) Coordinate(org.locationtech.jts.geom.Coordinate) CoordinateXY(org.locationtech.jts.geom.CoordinateXY) GeometryWrapper(org.apache.sis.internal.feature.GeometryWrapper) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) MismatchedDimensionException(org.opengis.geometry.MismatchedDimensionException) Test(org.junit.Test)

Aggregations

GeometryWrapper (org.apache.sis.internal.feature.GeometryWrapper)9 MultiPoint (org.locationtech.jts.geom.MultiPoint)3 Point (org.locationtech.jts.geom.Point)3 Shape (java.awt.Shape)2 Path2D (java.awt.geom.Path2D)2 Collection (java.util.Collection)2 AbstractShape (org.apache.sis.internal.referencing.j2d.AbstractShape)2 Coordinate (org.locationtech.jts.geom.Coordinate)2 Geometry (org.locationtech.jts.geom.Geometry)2 LineString (org.locationtech.jts.geom.LineString)2 MultiLineString (org.locationtech.jts.geom.MultiLineString)2 MultiPolygon (org.locationtech.jts.geom.MultiPolygon)2 Polygon (org.locationtech.jts.geom.Polygon)2 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)2 Geometry (com.esri.core.geometry.Geometry)1 Line (com.esri.core.geometry.Line)1 MultiPath (com.esri.core.geometry.MultiPath)1 MultiPoint (com.esri.core.geometry.MultiPoint)1 Point (com.esri.core.geometry.Point)1 Polygon (com.esri.core.geometry.Polygon)1