private void insert1(Point2D p) { if (contains(p)) return; boolean newAdded = false; if (root == null) { initRoot(p); } else { TreeNode curr = root; while (true) { if (TreeNode.slightlyEquals(p, curr.value)) { return; } if (curr.even) { if (p.x() <= curr.value.x()) { if (curr.left == null) { TreeNode left = newNode(p, curr); left.rect = new RectHV(curr.rect.xmin(), curr.rect.ymin(), curr.value.x(), curr.rect.ymax()); curr.left = left; break; } else { curr = curr.left; } } else { if (curr.right == null) { TreeNode right = newNode(p, curr); right.rect = new RectHV(curr.value.x(), curr.rect.ymin(), curr.rect.xmax(), curr.rect.ymax()); curr.right = right; break; } else { curr = curr.right; } } } else { if (p.y() < curr.value.y()) { if (curr.left == null) { TreeNode left = newNode(p, curr); left.rect = new RectHV(curr.rect.xmin(), curr.rect.ymin(), curr.rect.xmax(), curr.value.y()); curr.left = left; break; } else { curr = curr.left; } } else { if (curr.right == null) { TreeNode right = newNode(p, curr); right.rect = new RectHV(curr.rect.xmin(), curr.value.y(), curr.rect.xmax(), curr.rect.ymax()); curr.right = right; break; } else { curr = curr.right; } } } } } size++; }
private KdNode put( KdNode nd, Point2D p, int turn, double xmin, double ymin, double xmax, double ymax) { if (nd == null) { sz++; return new KdNode(p, null, null, new RectHV(xmin, ymin, xmax, ymax)); } // Neglect nodes that collides with one // Already in the tree double ndx = nd.point.x(); double ndy = nd.point.y(); if (nd.point.equals(p)) return nd; else if (turn == 0) { if (p.x() < ndx) { nd.left = put(nd.left, p, 1 - turn, xmin, ymin, Math.min(ndx, xmax), ymax); } else { nd.right = put(nd.right, p, 1 - turn, Math.max(ndx, xmin), ymin, xmax, ymax); } } else { if (p.y() < ndy) { nd.left = put(nd.left, p, 1 - turn, xmin, ymin, xmax, Math.min(ndy, ymax)); } else { nd.right = put(nd.right, p, 1 - turn, xmin, Math.max(ndy, ymin), xmax, ymax); } } return nd; }
public boolean insert(Point2D p) { if (p.equals(value)) { return false; } if (onLeft(p)) { if (left == null) { final TreeNode treeNode = newNode(p, this); treeNode.rect = even ? new RectHV(rect.xmin(), rect.ymin(), value.x(), rect.ymax()) : new RectHV(rect.xmin(), rect.ymin(), rect.xmax(), value.y()); left = treeNode; return true; } else { return left.insert(p); } } else if (onRight(p)) { if (right == null) { TreeNode treeNode = newNode(p, this); treeNode.rect = even ? new RectHV(rect.xmin(), value.y(), rect.xmax(), rect.ymax()) : new RectHV(rect.xmin(), value.y(), rect.xmax(), rect.ymax()); right = treeNode; return true; } else { return right.insert(p); } } return false; }
private int compare(Point2D p, Point2D q, Orientation orientation) { if (orientation == Orientation.LR) { return Double.compare(p.x(), q.x()); } else { return Double.compare(p.y(), q.y()); } }
private boolean onTheRight(final Point2D point, final Point2D current, final boolean vertical) { if (vertical) { return point.x() >= current.x(); } else { return point.y() >= current.y(); } }
private double distanceToVertical(final Point2D p, final Point2D v, final boolean vertical) { if (vertical) { return Math.abs(p.x() - v.x()); } else { return Math.abs(p.y() - v.y()); } }
private boolean onTheRight(final Point2D point, final RectHV rect, final boolean vertical) { if (vertical) { return rect.xmin() > point.x(); } else { return rect.ymin() > point.y(); } }
private boolean onTheLeft(final Point2D point, final RectHV rect, final boolean vertical) { if (vertical) { return rect.xmax() < point.x(); } else { return rect.ymax() < point.y(); } }
private boolean search(KdNode nd, Point2D p, int turn) { if (nd == null) return false; if (nd.point.equals(p)) { return true; } else if (turn == 0) { if (p.x() < nd.point.x()) return search(nd.left, p, 1 - turn); else return search(nd.right, p, 1 - turn); } else { if (p.y() < nd.point.y()) return search(nd.left, p, 1 - turn); else return search(nd.right, p, 1 - turn); } }
// a nearest neighbor in the set to point p; null if the set is empty public Point2D nearest(Point2D p) { if (p == null) throw new NullPointerException("point"); Point2D nearestPoint = null; double nearestDist = MAX_DISTANCE; for (Point2D currPoint : points) { double currDist = currPoint.distanceTo(p); if (currDist < nearestDist) { nearestDist = currDist; nearestPoint = currPoint; } } return nearestPoint; }
private Point2D findNearest( Node x, Point2D p, Point2D nearest, double minDist, Orientation orientation) { if (x == null) { return nearest; } Point2D closest = nearest; double closestDistance = minDist; double distance = x.p.distanceSquaredTo(p); if (distance < minDist) { closest = x.p; closestDistance = distance; } Node first, second; if (orientation == Orientation.LR) { if (p.x() < x.p.x()) { first = x.lb; second = x.rt; } else { first = x.rt; second = x.lb; } } else { if (p.y() < x.p.y()) { first = x.lb; second = x.rt; } else { first = x.rt; second = x.lb; } } Orientation nextOrientation = orientation.next(); if (first != null && first.rect.distanceSquaredTo(p) < closestDistance) { closest = findNearest(first, p, closest, closestDistance, nextOrientation); closestDistance = closest.distanceSquaredTo(p); } if (second != null && second.rect.distanceSquaredTo(p) < closestDistance) { closest = findNearest(second, p, closest, closestDistance, nextOrientation); } return closest; }
public boolean contains(Point2D p) { if (p.equals(value)) { return true; } else if (onLeft(p)) { return left != null && left.contains(p); } else if (onRight(p)) { return right != null && right.contains(p); } else { System.out.println("Impossible!"); return false; } }
private Node put(final Node x, final Point2D key, final boolean vertical) { if (x == null) { return new Node(key, 1); } double cmp; if (vertical) { cmp = key.x() - x.key.x(); } else { cmp = key.y() - x.key.y(); } if (key.equals(x.key)) { // do nothing } else if (cmp <= 0) { x.left = put(x.left, key, !vertical); x.N = 1 + size(x.left) + size(x.right); } else if (cmp > 0) { x.right = put(x.right, key, !vertical); x.N = 1 + size(x.left) + size(x.right); } return x; }
private Point2D get(final Node x, final Point2D key, final boolean vertical) { if (x == null) { return null; } if (x.key.equals(key)) { return x.key; } double cmp; if (vertical) { cmp = key.x() - x.key.x(); } else { cmp = key.y() - x.key.y(); } if (cmp <= 0) { return get(x.left, key, !vertical); } else { return get(x.right, key, !vertical); } }
public Point2D nearest(Point2D p, Point2D nearest) { if (slightlyEquals(p, nearest)) return nearest; double minDistance = p.distanceSquaredTo(nearest); if (left != null) { final double distanceTo = p.distanceTo(left.value); if (distanceTo <= minDistance) { minDistance = distanceTo; nearest = left.value; } } if (right != null) { final double distanceTo = p.distanceTo(right.value); if (distanceTo <= minDistance) { minDistance = distanceTo; nearest = right.value; } } Point2D lnearest = nearest; if (left != null && left.rect.distanceTo(nearest) < minDistance) { lnearest = left.nearest(p, nearest); } Point2D rnearest = nearest; if (right != null && right.rect.distanceTo(nearest) < minDistance) { rnearest = right.nearest(p, nearest); } final double ldist = p.distanceTo(lnearest); final double rdist = p.distanceTo(rnearest); if (ldist < minDistance) { nearest = lnearest; minDistance = ldist; } if (rdist < minDistance) { nearest = rnearest; minDistance = rdist; } return nearest; }
// a nearest neighbor in the set to point p; null if the set is empty public Point2D nearest(Point2D p) { if (p == null) throw new NullPointerException("Point2D cannot be null!"); if (set.isEmpty()) return null; double minDistance = Double.MAX_VALUE; Point2D minPoint = null; for (Point2D point : set) { double distance = p.distanceSquaredTo(point); if (distance < minDistance) { minDistance = distance; minPoint = point; } } return minPoint; }
private void nearest( final Node node, final Holder<Point2D> nearest, final Point2D p, final boolean vertical) { if (node == null) { return; } else if (node.key.compareTo(p) == 0) { nearest.value = node.key; return; } else if (p.distanceTo(node.key) < p.distanceTo(nearest.value)) { nearest.value = node.key; } if (onTheLeft(p, node.key, vertical)) { nearest(node.left, nearest, p, !vertical); if (distanceToVertical(p, node.key, vertical) < p.distanceTo(nearest.value)) { nearest(node.right, nearest, p, !vertical); } } else if (onTheRight(p, node.key, vertical)) { nearest(node.right, nearest, p, !vertical); if (distanceToVertical(p, node.key, vertical) < p.distanceTo(nearest.value)) { nearest(node.left, nearest, p, !vertical); } } }
public Point2D ceiling(Point2D p, boolean inclusive) { requireNonNull(p); if (value.equals(p)) { return value; } else if (onRight(p)) { if (right != null && right.onLeft(p)) { return inclusive ? value : right.value; } else if (right != null && right.onRight(p)) { return right.ceiling(p, inclusive); } else { return inclusive ? value : null; } } else if (onLeft(p)) { return left == null ? inclusive ? null : value : left.ceiling(p, inclusive); } else { return inclusive ? value : null; } }
// draw all points to standard draw public void draw() { for (Point2D point2D : root.subSet(LOWER, HIGHER)) { StdDraw.point(point2D.x(), point2D.y()); } }
private Point2D find(KdNode nd, double curDist, Point2D target, int turn) { Point2D curClosest = null; if (nd == null) return curClosest; // Pruning if (nd.rect.distanceTo(target) > curDist) { return null; } if (nd.point.distanceTo(target) < curDist) { curClosest = nd.point; curDist = nd.point.distanceTo(target); } // Always search the plane that target is on according to // current node if ((turn == 0 && target.x() < nd.point.x()) || (turn == 1 && target.y() < nd.point.y())) { Point2D left = find(nd.left, curDist, target, 1 - turn); if (left != null && left.distanceTo(target) < curDist) { curClosest = left; curDist = left.distanceTo(target); } Point2D right = find(nd.right, curDist, target, 1 - turn); if (right != null && right.distanceTo(target) < curDist) { curClosest = right; curDist = right.distanceTo(target); } } else { Point2D right = find(nd.right, curDist, target, 1 - turn); if (right != null && right.distanceTo(target) < curDist) { curClosest = right; curDist = right.distanceTo(target); } Point2D left = find(nd.left, curDist, target, 1 - turn); if (left != null && left.distanceTo(target) < curDist) { curClosest = left; curDist = left.distanceTo(target); } } return curClosest; }
public static void main(String[] args) { String filename = args[0]; In in = new In(filename); StdDraw.show(0); // initialize the data structures with N points from standard input PointSET brute = new PointSET(); KdTree kdtree = new KdTree(); while (!in.isEmpty()) { double x = in.readDouble(); double y = in.readDouble(); Point2D p = new Point2D(x, y); kdtree.insert(p); brute.insert(p); } double x0 = 0.0, y0 = 0.0; // initial endpoint of rectangle double x1 = 0.0, y1 = 0.0; // current location of mouse boolean isDragging = false; // is the user dragging a rectangle // draw the points StdDraw.clear(); StdDraw.setPenColor(StdDraw.BLACK); StdDraw.setPenRadius(.01); brute.draw(); while (true) { StdDraw.show(40); // user starts to drag a rectangle if (StdDraw.mousePressed() && !isDragging) { x0 = StdDraw.mouseX(); y0 = StdDraw.mouseY(); isDragging = true; continue; } // user is dragging a rectangle else if (StdDraw.mousePressed() && isDragging) { x1 = StdDraw.mouseX(); y1 = StdDraw.mouseY(); continue; } // mouse no longer pressed else if (!StdDraw.mousePressed() && isDragging) { isDragging = false; } RectHV rect = new RectHV(Math.min(x0, x1), Math.min(y0, y1), Math.max(x0, x1), Math.max(y0, y1)); // draw the points StdDraw.clear(); StdDraw.setPenColor(StdDraw.BLACK); StdDraw.setPenRadius(.01); brute.draw(); // draw the rectangle StdDraw.setPenColor(StdDraw.BLACK); StdDraw.setPenRadius(); rect.draw(); // draw the range search results for brute-force data structure in // red StdDraw.setPenRadius(.03); StdDraw.setPenColor(StdDraw.RED); for (Point2D p : brute.range(rect)) p.draw(); // draw the range search results for kd-tree in blue StdDraw.setPenRadius(.02); StdDraw.setPenColor(StdDraw.BLUE); for (Point2D p : kdtree.range(rect)) p.draw(); StdDraw.show(40); } }
private static boolean slightlyEquals(Point2D p1, Point2D p2) { return Math.abs(p1.x() - p2.x()) < 0.000001 && Math.abs(p1.y() - p2.y()) < 0.000001; }
// draw all points to standard draw public void draw() { for (Point2D point : points) { point.draw(); } }
// draw all points to standard draw public void draw() { for (Point2D point : set) { point.draw(); } }
private double distanceTo(Point2D p1, Point2D p2) { if (p2 == null) return Double.MAX_VALUE; return p1.distanceTo(p2); }
private boolean onRight(final Point2D p) { return (even && (p.x() > value.x())) || (!even && (p.y() > value.y())); }
private boolean onLeft(final Point2D p) { return (even && (p.x() <= value.x())) || (!even && (p.y() <= value.y())); }