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();
}
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);
}
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);
}
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);
}
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
}
}
}
Aggregations