package com.revolsys.geometry.index.quadtree; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.BoundingBoxProxy; import com.revolsys.geometry.model.Geometry; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.record.Record; import com.revolsys.record.Records; import com.revolsys.record.filter.RecordEqualsFilter; import com.revolsys.visitor.CreateListVisitor; public class RecordQuadTree<R extends Record> extends QuadTree<R> { private static final long serialVersionUID = 1L; public RecordQuadTree(final GeometryFactory geometryFactory) { super(geometryFactory); } public RecordQuadTree(final GeometryFactory geometryFactory, final Iterable<? extends R> records) { super(geometryFactory); addRecords(records); } public void addRecord(final R record) { if (record != null) { final Geometry geometry = record.getGeometry(); if (geometry != null && !geometry.isEmpty()) { final BoundingBox boundingBox = geometry.getBoundingBox(); insertItem(boundingBox, record); } } } public void addRecords(final Iterable<? extends R> records) { if (records != null) { for (final R record : records) { addRecord(record); } } } @Override public List<R> getItems(final BoundingBoxProxy boundingBoxProxy) { final BoundingBox boundingBox = boundingBoxProxy.getBoundingBox(); final List<R> results = super.getItems(boundingBoxProxy); for (final Iterator<R> iterator = results.iterator(); iterator.hasNext();) { final R record = iterator.next(); final Geometry geometry = record.getGeometry(); if (geometry == null) { iterator.remove(); } else { final BoundingBox recordBoundingBox = geometry.getBoundingBox(); if (!boundingBox.intersects(recordBoundingBox)) { iterator.remove(); } } } return results; } public List<R> getRecordsDistance(final Geometry geometry, final double distance) { if (geometry == null) { return Collections.emptyList(); } else { BoundingBox boundingBox = geometry.getBoundingBox(); boundingBox = boundingBox.expand(distance); final Predicate<R> filter = Records.newFilter(geometry, distance); return queryList(boundingBox, filter); } } public void query(final Geometry geometry, final Consumer<R> visitor) { final BoundingBox boundingBox = geometry.getBoundingBox(); forEach(boundingBox, visitor); } public List<R> queryEnvelope(final R record) { if (record == null) { return Collections.emptyList(); } else { final Geometry geometry = record.getGeometry(); return queryBoundingBox(geometry); } } public R queryFirst(final R record, final Predicate<R> filter) { if (record == null) { return null; } else { final Geometry geometry = record.getGeometry(); return getFirstBoundingBox(geometry, filter); } } public R queryFirstEquals(final R record, final Collection<String> excludedAttributes) { if (record == null) { return null; } else { final RecordEqualsFilter<R> filter = new RecordEqualsFilter<>(record, excludedAttributes); return queryFirst(record, filter); } } public List<R> queryIntersects(final BoundingBox boundingBox) { final GeometryFactory geometryFactory = getGeometryFactory(); final BoundingBox convertedBoundingBox = boundingBox.convert(geometryFactory); if (convertedBoundingBox.isEmpty()) { return Arrays.asList(); } else { final Predicate<R> filter = Records.newFilter(convertedBoundingBox); return queryList(convertedBoundingBox, filter); } } public List<R> queryIntersects(Geometry geometry) { final GeometryFactory geometryFactory = getGeometryFactory(); if (geometryFactory != null) { geometry = geometry.convertGeometry(geometryFactory); } final Predicate<R> filter = Records.newFilterGeometryIntersects(geometry); return queryList(geometry, filter); } public List<R> queryList(final BoundingBox boundingBox, final Predicate<R> filter) { return queryList(boundingBox, filter, null); } public List<R> queryList(final BoundingBox boundingBox, final Predicate<R> filter, final Comparator<R> comparator) { final CreateListVisitor<R> listVisitor = new CreateListVisitor<>(filter); forEach(boundingBox, listVisitor); final List<R> list = listVisitor.getList(); if (comparator != null) { Collections.sort(list, comparator); } return list; } public List<R> queryList(final Geometry geometry, final Predicate<R> filter) { final BoundingBox boundingBox = geometry.getBoundingBox(); return queryList(boundingBox, filter); } public List<R> queryList(final Geometry geometry, final Predicate<R> filter, final Comparator<R> comparator) { final BoundingBox boundingBox = geometry.getBoundingBox(); return queryList(boundingBox, filter, comparator); } public List<R> queryList(final R record, final Predicate<R> filter) { final Geometry geometry = record.getGeometry(); return queryList(geometry, filter); } public boolean removeRecord(final R record) { if (record != null) { final Geometry geometry = record.getGeometry(); if (geometry != null) { final BoundingBox boundinBox = geometry.getBoundingBox(); return super.removeItem(boundinBox, record); } } return false; } public void removeRecords(final Iterable<? extends R> records) { if (records != null) { for (final R record : records) { removeRecord(record); } } } }