package uk.me.parabola.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import uk.me.parabola.imgfmt.app.Area; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.util.QuadTreeNode.QuadTreePolygon; public class QuadTree { private final QuadTreeNode root; private long itemCount; public QuadTree(Area bbox) { this.root = new QuadTreeNode(bbox); this.itemCount = 0; } public boolean addAll(Collection<Coord> coordList) { boolean oneAdded = false; for (Coord c : coordList) { oneAdded = add(c) | oneAdded; } return oneAdded; } public boolean add(Coord c) { boolean added = root.add(c); if (added) { itemCount++; } return added; } public List<Coord> get(Area bbox) { return root.get(bbox, new ArrayList<Coord>(2000)); } public List<Coord> get(Collection<List<Coord>> polygons) { return root.get(new QuadTreePolygon(polygons), new ArrayList<Coord>( 2000)); } public List<Coord> get(List<Coord> polygon) { return get(polygon, 0); } public List<Coord> get(List<Coord> polygon, int offset) { if (polygon.size() < 3) { return Collections.emptyList(); } if (polygon.get(0).equals(polygon.get(polygon.size() - 1)) == false) { return null; } ArrayList<Coord> points = root.get(new QuadTreePolygon(polygon), new ArrayList<Coord>(2000)); if (offset > 0) { ListIterator<Coord> pointIter = points.listIterator(); while (pointIter.hasNext()) { if (isCloseToPolygon(pointIter.next(), polygon, offset)) { pointIter.remove(); } } } return points; } public void clear() { itemCount = 0; root.clear(); } public long getSize() { return itemCount; } private static boolean isCloseToPolygon(Coord point, List<Coord> polygon, int gap) { Iterator<Coord> polyIter = polygon.iterator(); Coord c2 = polyIter.next(); while (polyIter.hasNext()) { Coord c1 = c2; c2 = polyIter.next(); double dist = point.shortestDistToLineSegment(c1, c2); if (dist <= gap) { return true; } } return false; } }