Example #1
0
  it('should choose an insertion node based on minimizing enlargement, then area', assert => {
    const firstPlane = new GeoPlane({ maxChildren: 4 });

    [
      [0, 0, 5, 5], [20, 20, 5, 5], [0, 0, 5, 10], [5, 5, 5, 5],
      [0, 0, 10, 5], [25, 20, 1, 5], [10, 0, 1, 10]

    ].forEach(rectangle => firstPlane.insert(new GeoRectangle(...rectangle)));

    assert.deepEqual(firstPlane.exportBoundingBoxTreeForTesting(), {
      boundingBox: [0, 0, 26, 25],
      height: 2,
      children: [
        { boundingBox: [0, 0, 11, 10], height: 1, children: [ [0, 0, 5, 5], [0, 0, 5, 10], [0, 0, 10, 5], [10, 0, 11, 10] ] },
        { boundingBox: [5, 5, 26, 25], height: 1, children: [ [5, 5, 10, 10], [20, 20, 25, 25], [25, 20, 26, 25] ] },
      ]
    });

    // Classical T-shape split representing Figure 3.1 from the paper.
    const secondPlane = new GeoPlane({ maxChildren: 3, minChildren: 2 });

    [
      [0, 10, 40, 10], [30, 0, 10, 200], [50, 0, 10, 200], [50, 10, 40, 10]

    ].forEach(rectangle => secondPlane.insert(new GeoRectangle(...rectangle)));

    assert.deepEqual(secondPlane.exportBoundingBoxTreeForTesting(), {
      boundingBox: [0, 0, 90, 200],
      height: 2,
      children: [
        { boundingBox: [30, 0, 60, 200], height: 1, children: [ [30, 0, 40, 200], [50, 0, 60, 200] ] },
        { boundingBox: [0, 10, 90, 20], height: 1, children: [ [0, 10, 40, 20], [50, 10, 90, 20] ] }
      ]
    });
  });
Example #2
0
  it('should be able to find points that intersect with a rectangle', assert => {
    const plane = new GeoPlane({ maxChildren: 4 }),
          points = {};

    referencePoints.forEach(position => {
      const point = new GeoPoint(...position);

      points[point.x] = points[point.x] || {};
      points[point.x][point.y] = point;

      plane.insert(point);
    });

    assert.deepEqual(plane.intersect([40, 20, 80, 70]), [
      points[70][70], points[45][70], points[60][60], points[75][25], points[70][20], points[50][25],
      points[45][20], points[75][50], points[70][45], points[60][35], points[45][45], points[50][50]
    ]);

    assert.deepEqual(plane.intersect([0, 0, 10, 100]), [
      points[0][75], points[10][60], points[10][85], points[0][25], points[10][10],
      points[0][0], points[10][35], points[0][50]
    ]);

    assert.deepEqual(plane.intersect([60, 60, 75, 75]), [
      points[70][70], points[75][75], points[60][60]
    ]);
  });
Example #3
0
  it('should split the tree when reaching the maximum number of children in a node', assert => {
    const plane = new GeoPlane();
    for (let i = 0; i < plane.maxChildren + 1; ++i)
      plane.insert(createRectangle());

    assert.equal(plane.height, 2);
  });
Example #4
0
  it('should adjust the bounding box on object modification', assert => {
    const plane = new GeoPlane();

    plane.insert(new GeoRectangle(10, 15, 10, 10));
    assert.deepEqual(plane.boundingBox, [10, 15, 20, 25]);

    plane.insert(new GeoCircle(10, 10, 5));
    assert.deepEqual(plane.boundingBox, [5, 5, 20, 25]);
  });
Example #5
0
    referencePoints.forEach(position => {
      const point = new GeoPoint(...position);

      points[point.x] = points[point.x] || {};
      points[point.x][point.y] = point;

      plane.insert(point);
    });
Example #6
0
  it('should be able to find the nearest neighbours to a point', assert => {
    const plane = new GeoPlane({ maxChildren: 4 }),
          points = {};

    referencePoints.forEach(position => {
      const point = new GeoPoint(...position);

      points[point.x] = points[point.x] || {};
      points[point.x][point.y] = point;

      plane.insert(point);
    });

    assert.deepEqual(plane.nearest([50, 50], 5), [
      points[50][50], points[45][45], points[35][35], points[60][60], points[60][35]
    ]);
  });
Example #7
0
    const createRectangle = (x, y, w, h) => {
      const rectangle = new GeoRectangle(x, y, w, h);

      rectangles[rectangle.x] = rectangles[rectangle.x] || {};
      rectangles[rectangle.x][rectangle.y] = rectangle;

      plane.insert(rectangle);
    };
Example #8
0
 const insertRectangles = (width, height) => {
   depth++;
   for (let x = MAP_BOUNDARIES[0]; x < MAP_BOUNDARIES[2]; x += width) {
     for (let y = MAP_BOUNDARIES[1]; y < MAP_BOUNDARIES[3]; y += height) {
       plane.insert(new GeoRectangle(x, y, width, height));
       counter++;
     }
   }
 };
Example #9
0
 ].forEach(rectangle => secondPlane.insert(new GeoRectangle(...rectangle)));
Example #10
0
 ].forEach(rectangle => firstPlane.insert(new GeoRectangle(...rectangle)));
Example #11
0
  it('should be able to perform rectangles-for-point operations quickly', assert => {
    const IS_PERFORMANCE_TEST = false;

    // This test acts as a performance test to measure how long insertion operations take for large
    // numbers of rectangles, as well as find operations for finding intersecting rectangles for a
    // given point. Note that finding rectangles for rectangles would be equally fast.
    const MAP_BOUNDARIES = [ -3000, -3000, 3000, 3000 ],
          INTERSECT_ITERATIONS = 100000,
          NEAREST_ITERATIONS = 1000,
          NEAREST_COUNT = 100;

    let plane = new GeoPlane(),
        counter = 0,
        depth = 0;

    // Inserts a series of rectangles in |plane| of size [|width|, |height|].
    const insertRectangles = (width, height) => {
      depth++;
      for (let x = MAP_BOUNDARIES[0]; x < MAP_BOUNDARIES[2]; x += width) {
        for (let y = MAP_BOUNDARIES[1]; y < MAP_BOUNDARIES[3]; y += height) {
          plane.insert(new GeoRectangle(x, y, width, height));
          counter++;
        }
      }
    };

    const insertionBegin = highResolutionTime();

    insertRectangles(1000, 1000);  //    36
    insertRectangles( 600,  600);  //   100
    insertRectangles( 300,  300);  //   400
    insertRectangles( 100,  100);  //  3600

    if (IS_PERFORMANCE_TEST) {
      insertRectangles(  50,   50);  // 14400
      insertRectangles(  25,   25);  // 57600
    }

    const insertionEnd = highResolutionTime();
    const intersectBegin = highResolutionTime();

    for (let iteration = 0; iteration < INTERSECT_ITERATIONS; ++iteration) {
      const x = Math.random() * MAP_BOUNDARIES[2] + MAP_BOUNDARIES[0];
      const y = Math.random() * MAP_BOUNDARIES[3] + MAP_BOUNDARIES[1];

      assert.equal(plane.intersect([x, y, x, y]).length, depth);
    }

    const intersectEnd = highResolutionTime();
    const nearestBegin = highResolutionTime();

    for (let iteration = 0; iteration < NEAREST_ITERATIONS; ++iteration) {
      const x = Math.random() * MAP_BOUNDARIES[2] + MAP_BOUNDARIES[0];
      const y = Math.random() * MAP_BOUNDARIES[3] + MAP_BOUNDARIES[1];

      assert.equal(plane.nearest([x, y], NEAREST_COUNT).length, Math.min(counter, NEAREST_COUNT));
    }

    const nearestEnd = highResolutionTime();

    const insertionTime = Math.round((insertionEnd - insertionBegin) * 100) / 100,
          intersectTime = Math.round((intersectEnd - intersectBegin) * 100) / 100,
          nearestTime = Math.round((nearestEnd - nearestBegin) * 100) / 100;

    console.log('[GeoPlane] Insertion (' + counter + '): ' + insertionTime + 'ms; intersect (' +
        INTERSECT_ITERATIONS + '): ' + intersectTime + 'ms; nearest (' + NEAREST_ITERATIONS + ', ' +
        NEAREST_COUNT + '): ' + nearestTime + 'ms');
  });
Example #12
0
  it('should be able to find rectangles that intersect with a given point', assert => {
    const plane = new GeoPlane({ maxChildren: 4 }),
          rectangles = {};

    // Creates a rectangle with the given size, stores it in |points| and adds it to the |plane|.
    const createRectangle = (x, y, w, h) => {
      const rectangle = new GeoRectangle(x, y, w, h);

      rectangles[rectangle.x] = rectangles[rectangle.x] || {};
      rectangles[rectangle.x][rectangle.y] = rectangle;

      plane.insert(rectangle);
    };

    for (let x = 0; x < 100; x += 10) {
      for (let y = 0; y < 100; y += 10)
        createRectangle(x, y, 10, 10);
    }

    for (let x = 1; x < 100; x += 15) {
      for (let y = 1; y < 100; y += 15)
        createRectangle(x, y, 15, 15);
    }

    for (let x = 2; x < 100; x += 20) {
      for (let y = 2; y < 100; y += 20)
        createRectangle(x, y, 20, 20);
    }

    // Utility function to sort an array of rectangles.
    const sortRectangles = rectangles => {
      return rectangles.sort((lhs, rhs) => {
        if (lhs.x == rhs.x) return lhs.y < rhs.y ? -1 : 1;
        return lhs.x < rhs.x ? -1 : 1;
      });
    }

    // Test with a hundred random points, that also do a linear search over the registered |points|
    // in order to figure out whether they're on the plane or not.
    for (let attempt = 0; attempt < 100; ++attempt) {
      const point = new GeoPoint(Math.floor(Math.random() * 100), Math.floor(Math.random() * 100)),
            actual = plane.intersect([point.x, point.y, point.x, point.y]),
            expected = [];

      for (let x in rectangles) {
        for (let y in rectangles[x]) {
          const boundingBox = rectangles[x][y].boundingBox();

          if (point.x < boundingBox[0] || point.y < boundingBox[1] ||
              point.x > boundingBox[2] || point.y > boundingBox[3])
            continue;

          expected.push(rectangles[x][y]);
        }
      }

      // Sort both the |expected| array and the results of |plane.intersect()| to make sure that the
      // deepEqual comparison is done on arrays of equal order.
      assert.deepEqual(sortRectangles(actual), sortRectangles(expected));
    }
  });