zoukankan      html  css  js  c++  java
  • TS 四叉树 圆


    namespace QuadtreeCircle{

      export class Point {
          x = 0;
          y = 0;
          userData = null;
          constructor(x, y, data) {
            this.x = x;
            this.y = y;
            this.userData = data;
          }
      }
            
      export class Rectangle {
        x = 0;
        y = 0;
        w = 0;
        h = 0;

        constructor(x, y, w, h) {
          this.x = x;
          this.y = y;
          this.w = w;
          this.h = h;
        }

        get left() {
          return this.x - this.w / 2;
        }

        get right() {
          return this.x + this.w / 2;
        }

        get top() {
          return this.y - this.h / 2;
        }

        get bottom() {
          return this.y + this.h / 2;
        }

        contains(point) {
          return (point.x >= this.x - this.w &&
            point.x <= this.x + this.w &&
            point.y >= this.y - this.h &&
            point.y <= this.y + this.h);
        }

        intersects(range) {
          return !(range.x - range.w > this.x + this.w ||
            range.x + range.w < this.x - this.w ||
            range.y - range.h > this.y + this.h ||
            range.y + range.h < this.y - this.h);
        }
      }
            
      // circle class for a circle shaped query
      export class Circle {
          x = 0;
          y = 0;
          r = 0;
          rSquared = 0;
        constructor(x, y, r) {
          this.x = x;
          this.y = y;
          this.r = r;
          this.rSquared = this.r * this.r;
        }

        contains(point) {
          // check if the point is in the circle by checking if the euclidean distance of
          // the point and the center of the circle if smaller or equal to the radius of
          // the circle
          let d = Math.pow((point.x - this.x), 2) + Math.pow((point.y - this.y), 2);
          return d <= this.rSquared;
        }

        intersects(range) {

          let xDist = Math.abs(range.x - this.x);
          let yDist = Math.abs(range.y - this.y);

          // radius of the circle
          let r = this.r;

          let w = range.w;
          let h = range.h;

          let edges = Math.pow((xDist - w), 2) + Math.pow((yDist - h), 2);

          // no intersection
          if (xDist > (r + w) || yDist > (r + h))
            return false;

          // intersection within the circle
          if (xDist <= w || yDist <= h)
            return true;

          // intersection on the edge of the circle
          return edges <= this.rSquared;
        }
      }
            
      export class QuadTree {
          boundary : Rectangle = null;
          capacity = 1;
          points = [];
          divided = false;
          width = 0;
          northeast : QuadTree = null;
          northwest : QuadTree = null;
          southeast : QuadTree = null;
          southwest : QuadTree = null;
          constructor(boundary, capacity) {
            if (!boundary) {
              throw TypeError('boundary is null or undefined');
            }
            if (!(boundary instanceof Rectangle)) {
              throw TypeError('boundary should be a Rectangle');
            }
            if (typeof capacity !== 'number') {
              throw TypeError(`capacity should be a number but is a ${typeof capacity}`);
            }
            if (capacity < 1) {
              throw RangeError('capacity must be greater than 0');
            }
            this.boundary = boundary;
            this.capacity = capacity;
            this.points = [];
            this.divided = false;
          }
        
          subdivide() {
            let x = this.boundary.x;
            let y = this.boundary.y;
            let w = this.boundary.w / 2;
            let h = this.boundary.h / 2;
        
            let ne = new Rectangle(x + w, y - h, w, h);
            this.northeast = new QuadTree(ne, this.capacity);
            let nw = new Rectangle(x - w, y - h, w, h);
            this.northwest = new QuadTree(nw, this.capacity);
            let se = new Rectangle(x + w, y + h, w, h);
            this.southeast = new QuadTree(se, this.capacity);
            let sw = new Rectangle(x - w, y + h, w, h);
            this.southwest = new QuadTree(sw, this.capacity);
        
            this.divided = true;
          }
        
          insert(point) {
            if (!this.boundary.contains(point)) {
              return false;
            }
        
            if (this.points.length < this.capacity) {
              this.points.push(point);
              return true;
            }
        
            if (!this.divided) {
              this.subdivide();
            }
        
            return (this.northeast.insert(point) || this.northwest.insert(point) ||
              this.southeast.insert(point) || this.southwest.insert(point));
          }
        
          query(range : Circle, found = []) {
        
            if (!range.intersects(this.boundary)) {
              return found;
            }
        
            for (let p of this.points) {
              if (range.contains(p)) {
                found.push(p);
              }
            }
            
            if (this.divided) {
              this.northwest.query(range, found);
              this.northeast.query(range, found);
              this.southwest.query(range, found);
              this.southeast.query(range, found);
            }
        
            return found;
          }
        
          closest(point, count, maxDistance) {
            if (typeof point === "undefined") {
              throw TypeError("Method 'closest' needs a point");
            }
            if (typeof count === "undefined") {
              count = 1;
            }
        
            // Limit to number of points in this QuadTree
            if (this.length == 0) {
              return [];
            }
            if (this.length < count) {
              return this.points;
            }
        
            if (typeof maxDistance === "undefined") {
              // A circle that contains the entire QuadTree
              const outerReach = Math.sqrt(
                Math.pow(this.boundary.w, 2) + Math.pow(this.boundary.h, 2)
              );
              // Distance of query point from center
              const pointDistance = Math.sqrt(
                Math.pow(point.x, 2) + Math.pow(point.y, 2)
              );
              // One QuadTree size away from the query point
              maxDistance = outerReach + pointDistance;
            }
        
            // Binary search with Circle queries
            let inner = 0;
            let outer = maxDistance;
            let limit = 8; // Limit to avoid infinite loops caused by ties
            let points;
            while (limit > 0) {
              const radius = (inner + outer) / 2;
              const range = new Circle(point.x, point.y, radius);
              points = this.query(range);
              if (points.length === count) {
                return points; // Return when we hit the right size
              } else if (points.length < count) {
                inner = radius;
              } else {
                outer = radius;
                limit --;
              }
            }
            // Sort by squared distance
            points.sort(
              (a, b) => {
                const aDist = Math.pow(point.x - a.x, 2) +
                  Math.pow(point.y - a.y, 2);
                const bDist = Math.pow(point.x - b.x, 2) +
                  Math.pow(point.y - b.y, 2);
                return aDist - bDist;
              }
            );
            // Slice to return correct count (breaks ties)
            return points.slice(0, count);
          }
        
          forEach(fn) {
            this.points.forEach(fn);
            if (this.divided) {
              this.northeast.forEach(fn);
              this.northwest.forEach(fn);
              this.southeast.forEach(fn);
              this.southwest.forEach(fn);
            }
          }
        
          merge(other, capacity) {
            let left = Math.min(this.boundary.left, other.boundary.left);
            let right = Math.max(this.boundary.right, other.boundary.right);
            let top = Math.min(this.boundary.top, other.boundary.top);
            let bottom = Math.max(this.boundary.bottom, other.boundary.bottom);
            let height = bottom - top;
            let width = right - left;
            let midX = left + width / 2;
            let midY = top + height / 2;
            let boundary = new Rectangle(midX, midY, width, height);
            let result = new QuadTree(boundary, capacity);
            this.forEach(point => result.insert(point));
            other.forEach(point => result.insert(point));
        
            return result;
          }
        
          get length() {
            let count = this.points.length;
            if (this.divided) {
              count += this.northwest.length;
              count += this.northeast.length;
              count += this.southwest.length;
              count += this.southeast.length;
            }
            return count;
          }
      }
    }
  • 相关阅读:
    iOS加载动态图的两种方法
    python初探
    博客园封笔
    office的分栏技巧
    关于排序...
    LaTex 学习笔记
    vim 学习笔记
    iOS 编程学习笔记之Foundation框架
    数论
    扫描线概览
  • 原文地址:https://www.cnblogs.com/alps/p/14670793.html
Copyright © 2011-2022 走看看