Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ public Query getIntersectsQuery(String literal) {
._toQuery();
}

@Override
public Query getBoundingBoxQuery(TopLeftBottomRightGeoBounds tlbr) {
return new GeoBoundingBoxQuery.Builder()
.field(this.searchField)
.boundingBox(builder -> builder.tlbr(tlbr))
.build()
._toQuery();
}

@Override
public Query getIsNullQuery() {
Query fieldExist = ExistsQuery.of(f -> f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.TopLeftBottomRightGeoBounds;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.util.ObjectBuilder;

Expand All @@ -16,4 +17,5 @@ public interface CQLFieldsInterface {
Query getIsNullQuery();
Query getLikeQuery(String literal);
Query getPropertyGreaterThanOrEqualsToQuery(String literal);
Query getBoundingBoxQuery(TopLeftBottomRightGeoBounds tlbr);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package au.org.aodn.ogcapi.server.core.parser.elastic;

import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType;
import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFieldsInterface;
import co.elastic.clients.elasticsearch._types.TopLeftBottomRightGeoBounds;
import org.geotools.filter.spatial.BBOXImpl;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope3D;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.MultiValuedFilter;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.BBOX;
import org.opengis.geometry.BoundingBox;
import org.opengis.geometry.BoundingBox3D;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

/**
* This class support both 2D or 3D query, but now we just implement 2D and support very limited operation for CQL
* which is sufficient for init run.
* example: BBOX(geometry, 105.08984375000037, -45.407201919778046, 163.91015625000117, -5.592798080220254)
* @param <T>
*/
public class BBoxImpl<T extends Enum<T> & CQLFieldsInterface> extends QueryHandler implements BBOX {
protected static final GeometryFactory factory = JTSFactoryFinder.getGeometryFactory();

protected Expression geometry = null;
protected BoundingBox bounds = null;
protected MultiValuedFilter.MatchAction matchAction = MatchAction.ANY;

public BBoxImpl(Expression geometry,
BoundingBox bounds,
MultiValuedFilter.MatchAction matchAction,
Class<T> enumType) {

if(bounds instanceof BoundingBox3D box3D) {
this.create3DCQL(geometry, box3D, matchAction);
}
else {
this.create2DCQL(geometry, bounds, matchAction, enumType);
}
}

public BBoxImpl(Expression geometry, Expression bounds, MultiValuedFilter.MatchAction matchAction) {
if (bounds instanceof Literal literal) {
Object value = literal.getValue();
if (value instanceof BoundingBox3D boundingBox3D) {
this.create3DCQL(geometry, boundingBox3D, matchAction);
}
else if (value instanceof Geometry g && geometry instanceof PropertyName name) {
if (g.getUserData() instanceof CoordinateReferenceSystem crs) {
this.create3DCQL(name, (ReferencedEnvelope3D) JTS.bounds(g, crs), matchAction);
}
}
}
}

public BBoxImpl(
Expression e,
double minx, double miny, double maxx, double maxy, String srs,
MultiValuedFilter.MatchAction matchAction,
Class<T> enumType) {
try {
CoordinateReferenceSystem crs = null;
CQLCrsType cqlCrsType = CQLCrsType.EPSG4326;
if (srs != null && !srs.isEmpty()) {
try {
crs = CRS.decode(srs);
cqlCrsType = CQLCrsType.convertFromUrl(srs);
}
catch (MismatchedDimensionException mde) {
throw new RuntimeException(mde);
}
catch (NoSuchAuthorityCodeException var16) {
crs = CRS.parseWKT(srs);
}
} else {
crs = null;
}
this.bounds = new ReferencedEnvelope(minx, maxx, miny, maxy, crs);
this.create2DCQL(e, bounds , matchAction, enumType);

} catch (FactoryException fe) {
throw new RuntimeException("Failed to setup bbox SRS", fe);
}

}

protected void create2DCQL(
Expression geometry,
BoundingBox bounds,
MultiValuedFilter.MatchAction matchAction,
Class<T> enumType) {

this.matchAction = matchAction;
this.geometry = geometry;
T v = Enum.valueOf(enumType, geometry.toString().toLowerCase());
this.query = v.getBoundingBoxQuery(
TopLeftBottomRightGeoBounds.of(builder -> builder
.topLeft(i -> i.latlon(ll -> ll.lon(bounds.getMinX()).lat(bounds.getMaxY())))
.bottomRight(i -> i.latlon(ll -> ll.lon(bounds.getMaxX()).lat(bounds.getMinY())))));
}

protected void create3DCQL(Expression geometry, BoundingBox3D bounds, MultiValuedFilter.MatchAction matchAction) {
this.matchAction = matchAction;

}

@Override
public BoundingBox getBounds() {
return bounds;
}

@Override
public Expression getExpression1() {
return geometry;
}

@Override
public Expression getExpression2() {
return null;
}

@Override
public MatchAction getMatchAction() {
return this.matchAction;
}

@Override
public boolean evaluate(Object o) {
return false;
}

@Override
public Object accept(FilterVisitor filterVisitor, Object o) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -406,32 +406,54 @@ public PropertyIsNil isNil(Expression expression, Object o) {
}

@Override
public BBOX bbox(String s, double v, double v1, double v2, double v3, String s1) {
return null;
public BBOX bbox(String propertyName, double minx, double miny, double maxx, double maxy, String srs) {
PropertyName name = this.property(propertyName);
return this.bbox(name, minx, miny, maxx, maxy, srs);
}

@Override
public BBOX bbox(Expression expression, Expression expression1) {
return null;
public BBOX bbox(Expression geometry, Expression bounds) {
return this.bbox(geometry, bounds, MultiValuedFilter.MatchAction.ANY);
}

@Override
public BBOX bbox(Expression expression, Expression expression1, MultiValuedFilter.MatchAction matchAction) {
return null;
public BBOX bbox(Expression geometry, Expression bounds, MultiValuedFilter.MatchAction matchAction) {
return new BBoxImpl<>(geometry, bounds, matchAction);
}

@Override
public BBOX3D bbox(String s, BoundingBox3D boundingBox3D) {
return null;
public BBOX bbox(Expression expression, double minx, double miny, double maxx, double maxy, String srs) {
return this.bbox(expression, minx, miny, maxx, maxy, srs, MultiValuedFilter.MatchAction.ANY);
}

@Override
public BBOX3D bbox(String s, BoundingBox3D boundingBox3D, MultiValuedFilter.MatchAction matchAction) {
public BBOX bbox(String propertyName, double minx, double miny, double maxx, double maxy, String srs, MultiValuedFilter.MatchAction matchAction) {
PropertyName name = this.property(propertyName);
return this.bbox(name, minx, miny, maxx, maxy, srs, matchAction);
}

@Override
public BBOX bbox(Expression expression, double minx, double miny, double maxx, double maxy, String srs, MultiValuedFilter.MatchAction matchAction) {
return new BBoxImpl<>(expression, minx, miny, maxx, maxy, srs, matchAction, collectionFieldType);
}

@Override
public BBOX bbox(Expression geometry, BoundingBox bounds) {
return this.bbox(geometry, bounds, MultiValuedFilter.MatchAction.ANY);
}

@Override
public BBOX bbox(Expression geometry, BoundingBox bounds, MultiValuedFilter.MatchAction matchAction) {
return new BBoxImpl<>(geometry, bounds, matchAction, collectionFieldType);
}

@Override
public BBOX3D bbox(String propertyName, BoundingBox3D boundingBox3D) {
return null;
}

@Override
public BBOX bbox(String s, double v, double v1, double v2, double v3, String s1, MultiValuedFilter.MatchAction matchAction) {
public BBOX3D bbox(String s, BoundingBox3D boundingBox3D, MultiValuedFilter.MatchAction matchAction) {
return null;
}

Expand Down Expand Up @@ -830,16 +852,6 @@ public FilterCapabilities capabilities(String s, ScalarCapabilities scalarCapabi
return null;
}

@Override
public BBOX bbox(Expression expression, double v, double v1, double v2, double v3, String s) {
return null;
}

@Override
public BBOX bbox(Expression expression, double v, double v1, double v2, double v3, String s, MultiValuedFilter.MatchAction matchAction) {
return null;
}

@Override
public BBOX3D bbox(Expression expression, BoundingBox3D boundingBox3D) {
return null;
Expand All @@ -850,16 +862,6 @@ public BBOX3D bbox(Expression expression, BoundingBox3D boundingBox3D, MultiValu
return null;
}

@Override
public BBOX bbox(Expression expression, BoundingBox boundingBox) {
return null;
}

@Override
public BBOX bbox(Expression expression, BoundingBox boundingBox, MultiValuedFilter.MatchAction matchAction) {
return null;
}

@Override
public Beyond beyond(Expression expression, Expression expression1, double v, String s) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package au.org.aodn.ogcapi.server.core.parser.stac;

import au.org.aodn.ogcapi.server.core.model.enumeration.CQLCrsType;
import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFieldsInterface;
import au.org.aodn.ogcapi.server.core.util.GeometryUtils;
import lombok.Getter;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.MultiValuedFilter;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.BBOX;
import org.opengis.geometry.BoundingBox;
import org.opengis.geometry.BoundingBox3D;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.locationtech.jts.geom.Geometry;

public class BBoxImpl <T extends Enum<T> & CQLFieldsInterface> implements BBOX {

@Getter
protected Geometry geometry = null;

protected BoundingBox bounds = null;

public BBoxImpl(Expression geometry, Expression bounds, MultiValuedFilter.MatchAction matchAction) {
if (bounds instanceof Literal literal) {
Object value = literal.getValue();
if (value instanceof BoundingBox3D boundingBox3D) {
}
else if (value instanceof Geometry g && geometry instanceof PropertyName name) {
if (g.getUserData() instanceof CoordinateReferenceSystem crs) {
}
}
}
}

public BBoxImpl(
Expression e,
double minx, double miny, double maxx, double maxy, String srs,
MultiValuedFilter.MatchAction matchAction) {
try {
CoordinateReferenceSystem crs = null;
CQLCrsType cqlCrsType = CQLCrsType.EPSG4326;
if (srs != null && !srs.isEmpty()) {
try {
crs = CRS.decode(srs);
cqlCrsType = CQLCrsType.convertFromUrl(srs);
}
catch (MismatchedDimensionException mde) {
throw new RuntimeException(mde);
}
catch (NoSuchAuthorityCodeException var16) {
crs = CRS.parseWKT(srs);
}
} else {
crs = null;
}
this.bounds = new ReferencedEnvelope(minx, maxx, miny, maxy, crs);
this.geometry = GeometryUtils.normalizePolygon(GeometryUtils.createPolygon(minx, maxx, miny, maxy));

} catch (FactoryException fe) {
throw new RuntimeException("Failed to setup bbox SRS", fe);
}

}

@Override
public BoundingBox getBounds() {
return this.bounds;
}

@Override
public Expression getExpression1() {
return null;
}

@Override
public Expression getExpression2() {
return null;
}

@Override
public MatchAction getMatchAction() {
return null;
}

@Override
public boolean evaluate(Object o) {
return false;
}

@Override
public Object accept(FilterVisitor visitor, Object extraData) {
return visitor.visit(this, extraData);
}
}
Loading