package com.revolsys.record.filter; import java.util.function.Predicate; import com.revolsys.geometry.index.quadtree.RecordQuadTree; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.Geometry; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.Point; import com.revolsys.predicate.Predicates; import com.revolsys.record.Record; import com.revolsys.util.Property; public class ClosestRecordFilter implements Predicate<Record> { public static ClosestRecordFilter query(final RecordQuadTree<Record> index, final Geometry geometry, final double maxDistance) { final ClosestRecordFilter closestFilter = new ClosestRecordFilter(geometry, maxDistance); final BoundingBox boundingBox = closestFilter.getFilterBoundingBox(); index.queryList(boundingBox, closestFilter); return closestFilter; } public static ClosestRecordFilter query(final RecordQuadTree<Record> index, final Geometry geometry, final double maxDistance, final Predicate<Record> filter) { final ClosestRecordFilter closestFilter = new ClosestRecordFilter(geometry, maxDistance, filter); final BoundingBox boundingBox = closestFilter.getFilterBoundingBox(); index.queryList(boundingBox, closestFilter); return closestFilter; } private double closestDistance = Double.MAX_VALUE; private Record closestRecord; private final Predicate<Record> filter; private final Geometry geometry; private final double maxDistance; public ClosestRecordFilter(final Geometry geometry, final double maxDistance) { this(geometry, maxDistance, Predicates.all()); } public ClosestRecordFilter(final Geometry geometry, final double maxDistance, final Predicate<Record> filter) { this.geometry = geometry; this.maxDistance = maxDistance; this.filter = filter; } public double getClosestDistance() { return this.closestDistance; } public Record getClosestRecord() { return this.closestRecord; } public BoundingBox getFilterBoundingBox() { final BoundingBox boundingBox = GeometryFactory.boundingBox(this.geometry); return boundingBox.expand(this.maxDistance); } @Override public boolean test(final Record record) { if (this.filter.test(record)) { final Geometry geometry = record.getGeometry(); if (Property.hasValue(geometry)) { if (!(geometry instanceof Point)) { final BoundingBox boundingBox = geometry.getBoundingBox(); if (!boundingBox.isWithinDistance(this.geometry, this.maxDistance)) { return false; } } final double distance = geometry.distance(this.geometry); if (distance < this.closestDistance) { this.closestDistance = distance; this.closestRecord = record; return true; } } } return false; } }