package com.revolsys.record.query.functions; import java.sql.PreparedStatement; import java.util.Arrays; import java.util.List; import java.util.function.Function; import com.revolsys.datatype.DataType; import com.revolsys.datatype.DataTypes; import com.revolsys.geometry.model.Geometry; import com.revolsys.record.Record; import com.revolsys.record.query.Condition; import com.revolsys.record.query.Query; import com.revolsys.record.query.QueryValue; import com.revolsys.record.schema.RecordStore; import com.revolsys.util.Exceptions; public class WithinDistance implements Condition { private QueryValue distanceValue; private QueryValue geometry1Value; private QueryValue geometry2Value; public WithinDistance(final QueryValue geometry1Value, final QueryValue geometry2Value, final QueryValue distanceValue) { this.geometry1Value = geometry1Value; this.geometry2Value = geometry2Value; this.distanceValue = distanceValue; } @Override public void appendDefaultSql(final Query query, final RecordStore recordStore, final StringBuilder sql) { if (this.geometry1Value == null || this.geometry2Value == null || this.distanceValue == null) { sql.append("1 = 0"); } else { sql.append("ST_DWithin("); this.geometry1Value.appendSql(query, recordStore, sql); sql.append(", "); this.geometry2Value.appendSql(query, recordStore, sql); sql.append(", "); this.distanceValue.appendSql(query, recordStore, sql); sql.append(")"); } } @Override public int appendParameters(int index, final PreparedStatement statement) { if (this.geometry1Value != null) { index = this.geometry1Value.appendParameters(index, statement); } if (this.geometry2Value != null) { index = this.geometry2Value.appendParameters(index, statement); } if (this.distanceValue != null) { index = this.distanceValue.appendParameters(index, statement); } return index; } @Override public WithinDistance clone() { try { final WithinDistance clone = (WithinDistance)super.clone(); if (this.geometry1Value != null) { clone.geometry1Value = this.geometry1Value.clone(); } if (this.geometry2Value != null) { clone.geometry2Value = this.geometry2Value.clone(); } if (this.distanceValue != null) { clone.distanceValue = this.distanceValue.clone(); } return clone; } catch (final CloneNotSupportedException e) { throw Exceptions.wrap(e); } } @Override public boolean equals(final Object obj) { if (obj instanceof WithinDistance) { final WithinDistance condition = (WithinDistance)obj; if (DataType.equal(condition.geometry1Value, this.geometry1Value)) { if (DataType.equal(condition.geometry2Value, this.geometry1Value)) { if (DataType.equal(condition.distanceValue, this.distanceValue)) { return true; } } } } return false; } public QueryValue getDistanceValue() { return this.distanceValue; } public QueryValue getGeometry1Value() { return this.geometry1Value; } public QueryValue getGeometry2Value() { return this.geometry2Value; } @Override public List<QueryValue> getQueryValues() { return Arrays.asList(this.geometry1Value, this.geometry2Value, this.distanceValue); } @Override public boolean test(final Record record) { if (this.geometry1Value == null || this.geometry2Value == null || this.distanceValue == null) { return false; } else { final Geometry geometry1 = this.geometry1Value.getValue(record); final Geometry geometry2 = this.geometry2Value.getValue(record); ; final Number acceptDistance = this.distanceValue.getValue(record); if (acceptDistance == null || geometry1 == null || geometry2 == null) { return false; } else { final double distance = geometry1.distance(geometry2); return distance <= acceptDistance.doubleValue(); } } } @Override public String toString() { final Object value = this.geometry1Value; final Object value1 = this.geometry2Value; final Object value2 = this.distanceValue; return "DWithin(" + DataTypes.toString(value) + "," + DataTypes.toString(value1) + "," + DataTypes.toString(value2) + ")"; } @SuppressWarnings("unchecked") @Override public <QV extends QueryValue> QV updateQueryValues( final Function<QueryValue, QueryValue> valueHandler) { final QueryValue distanceValue = valueHandler.apply(this.distanceValue); final QueryValue geometry1Value = valueHandler.apply(this.geometry1Value); final QueryValue geometry2Value = valueHandler.apply(this.geometry2Value); if (distanceValue == this.distanceValue && geometry1Value == this.geometry1Value && geometry2Value == this.geometry2Value) { return (QV)this; } else { final WithinDistance clone = clone(); clone.distanceValue = distanceValue; clone.geometry1Value = geometry1Value; clone.geometry2Value = geometry2Value; return (QV)clone; } } }