Subversion Repositories mkgmap

Rev

Rev 4382 | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed

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) {
                long oldCount = itemCount;
                for (Coord c : coordList) {
                        add(c);
                }
                return itemCount > oldCount;
        }

        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<>(2000));
        }

        public List<Coord> get(Collection<List<Coord>> polygons) {
                return root.get(new QuadTreePolygon(polygons), new ArrayList<>(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))) {
                        throw new IllegalArgumentException("polygon is not closed");
                }
                List<Coord> points = root.get(new QuadTreePolygon(polygon), new ArrayList<>(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;
        }
}