UNPKG

romgrk-2d-geometry

Version:

Javascript library for 2d geometry

364 lines (326 loc) 16.1 kB
'use strict'; import { expect } from 'chai'; import Flatten from '../../index'; let {Polygon} = Flatten; let {point, vector, circle, line, box} = Flatten; let {relate, disjoint, equal, intersect, touch, inside, contain, covered, cover} = Flatten.Relations; describe('#Algorithms.Relation', function() { it('Function relate defined', () => { expect(relate).to.exist; expect(relate).to.be.a('function'); }); it('Namespace Relations exist on Flatten', () => { expect(Flatten.Relations).to.exist; }); it('Relations may be consumed from Flatten.Relations namespace', () => { expect(Flatten.Relations.disjoint).to.exist; expect(Flatten.Relations.intersect).to.exist; expect(Flatten.Relations.equal).to.exist; expect(Flatten.Relations.touch).to.exist; expect(Flatten.Relations.inside).to.exist; expect(Flatten.Relations.contain).to.exist; expect(Flatten.Relations.covered).to.exist; expect(Flatten.Relations.cover).to.exist; }) it('Functions disjoint,equals,intersects,touches exist', () => { expect(disjoint).to.be.a('function'); expect(equal).to.be.a('function'); expect(intersect).to.be.a('function'); expect(touch).to.be.a('function'); }); it('v1.4 Relations.intersect() doesnt allow Polygon argument #149', () => { const polygon = new Flatten.Polygon(new Flatten.Box(2, 2, 3, 3)); const box = new Flatten.Box(1, 1, 10, 10); const bIntersect = Flatten.Relations.intersect(polygon, box); expect(bIntersect).to.be.true; }) describe('#Algorithms.Relation.Line2Line', function() { it ('Parallel case (disjoint)', () => { let l1 = line( point(10,10), vector(1,1) ); let l2 = line( l1.pt.translate(vector(10,10)), l1.norm ); let de9im = relate(l1, l2); expect(de9im.I2E[0]).to.be.deep.equal(l1); expect(de9im.E2I[0]).to.be.deep.equal(l2); expect(disjoint(l1,l2)).to.be.true; expect(equal(l1,l2)).to.be.false; expect(intersect(l1,l2)).to.be.false; expect(touch(l1,l2)).to.be.false; }); it ('Equal case', () => { let l1 = line( point(10,10), vector(1,1) ); let l2 = line( point(10,10), vector(-1,-1) ); expect(equal(l1,l2)).to.be.true; expect(intersect(l1,l2)).to.be.true; expect(disjoint(l1,l2)).to.be.false; expect(touch(l1,l2)).to.be.false; }); it ('Intersection case', () => { let l1 = line( point(10,10), vector(1,1) ); let l2 = line( point(20,20), vector(1,-1) ); expect(equal(l1,l2)).to.be.false; expect(intersect(l1,l2)).to.be.true; expect(disjoint(l1,l2)).to.be.false; expect(touch(l1,l2)).to.be.false; }); }); describe('#Algorithms.Relation.Line2Circle', function() { it ('Disjoint case', () => { let l = line( point(10,10), vector(1,0) ); let c = circle( point(0,0), 5 ); expect(disjoint(l, c)).to.be.true; expect(equal(l, c)).to.be.false; expect(intersect(l, c)).to.be.false; expect(touch(l, c)).to.be.false; }); it ('Touching case', () => { let l = line( point(10,10), vector(1,0) ); let c = circle( point(0,0), 10 ); expect(equal(l, c)).to.be.false; expect(intersect(l, c)).to.be.true; expect(disjoint(l, c)).to.be.false; expect(touch(l, c)).to.be.true; }); it ('Intersection case', () => { let l = line( point(5,5), vector(1,0) ); let c = circle( point(0,0), 10 ); expect(equal(l, c)).to.be.false; expect(intersect(l, c)).to.be.true; expect(disjoint(l, c)).to.be.false; expect(touch(l, c)).to.be.false; }); }); describe('#Algorithms.Relation.Line2Box', function() { it ('Intersection case', () => { let l = line( point(400,120), vector(0.5,1) ); let b = circle(point(300,150), 100).box; expect(equal(l, b)).to.be.false; expect(intersect(l, b)).to.be.true; expect(disjoint(l, b)).to.be.false; expect(touch(l, b)).to.be.false; }); }); describe('#Algorithms.Relation.Line2Polygon', function() { it ('Disjoint case', () => { let l = line( point(400,0), vector(1,0) ); let points = [point(100, 20), point(250, 75), point(350, 75), point(300, 200), point(170, 200), point(120, 350), point(70, 120) ]; let p = new Polygon(points); expect(disjoint(l, p)).to.be.true; expect(equal(l, p)).to.be.false; expect(intersect(l, p)).to.be.false; expect(touch(l, p)).to.be.false; }); it ('Touching case - touch in one point', () => { let l = line( point(100,350), vector(0,1) ); let points = [point(100, 20), point(250, 75), point(350, 75), point(300, 200), point(170, 200), point(120, 350), point(70, 120) ]; let p = new Polygon(points); expect(equal(l, p)).to.be.false; expect(intersect(l, p)).to.be.true; expect(disjoint(l, p)).to.be.false; expect(touch(l, p)).to.be.true; }); it ('Intersection case - 2 intersection point', () => { let l = line( point(100,175), vector(0,1) ); let points = [point(100, 20), point(250, 75), point(350, 75), point(300, 200), point(170, 200), point(120, 350), point(70, 120) ]; let p = new Polygon(points); let de9im = relate(l, p); expect(de9im.I2I.length).to.equal(1); expect(de9im.I2I[0]).to.be.instanceof(Flatten.Segment); expect(equal(l, p)).to.be.false; expect(intersect(l, p)).to.be.true; expect(disjoint(l, p)).to.be.false; expect(touch(l, p)).to.be.false; }); it('Can properly detect contains / covered relation. Issue #65', () => { function rectangle(xmin, ymin, xmax, ymax) { const box = new Flatten.Box(xmin, ymin, xmax, ymax); return new Flatten.Polygon(box); } const width = 200; const buffer = 60; const height = 20; let poly1 = rectangle( -width / 2 - buffer, -buffer, width / 2 + buffer, height + buffer ) .rotate(Math.PI) .translate(Flatten.vector(180, 150)); let poly2 = rectangle( -width / 2 - buffer, -buffer, width / 2 + buffer, height + buffer ) .rotate(Math.PI) .translate(Flatten.vector(420, 145)); let poly3 = rectangle(0, 0, 800, 500); const combo = Flatten.BooleanOperations.subtract( poly3, Flatten.BooleanOperations.unify(poly1, poly2) ); const seg = Flatten.segment(Flatten.point(255, 65), Flatten.point(390, 215)); // // The created combo polygon is a rectangle with a hole. The segment passes over this hole. // However the checks still show that the segment is contained in the polygon, even though most of it is over the // hole. // const bContains = combo.contains(seg) // Should be false, but is true const bCovered = Flatten.Relations.covered(seg, combo) // Should be false, but is true expect(bContains).to.be.false; expect(bCovered).to.be.false; }); it('Can properly detect touch relation. Issue #65', () => { const poly = new Flatten.Polygon([ Flatten.point(710, 750), Flatten.point(688.9918693812442, 814.656377752172), Flatten.point(633.9918693812442, 854.6162167924668), Flatten.point(566.0081306187558, 854.616216792467), Flatten.point(511.0081306187558, 814.656377752172), Flatten.point(490, 750), Flatten.point(511.0081306187558, 685.343622247828), Flatten.point(566.0081306187558, 645.3837832075332), Flatten.point(633.9918693812442, 645.383783207533), Flatten.point(688.9918693812442, 685.343622247828) ]); const seg = Flatten.segment(Flatten.point(600, 900), Flatten.point(620, 570)); const bTouch = Flatten.Relations.touch(seg, poly); // Should be false, but is true expect(bTouch).to.be.false; }) }); describe('#Algorithms.Relation.Circle2Circle', function() { it ('Intersection case', () => { const c1 = circle(point(250, 150), 100); const c2 = circle(point(350, 150), 50); expect(intersect(c1, c2)).to.be.true; }); it ('Disjoint case', () => { const c1 = circle(point(250, 150), 100); const c2 = circle(point(450, 150), 50); expect(disjoint(c1, c2)).to.be.true; expect(intersect(c1, c2)).to.be.false; }); it ('Touching case', () => { const c1 = circle(point(250, 150), 100); const c2 = circle(point(400, 150), 50); expect(disjoint(c1, c2)).to.be.false; expect(intersect(c1, c2)).to.be.true; expect(touch(c1, c2)).to.be.true; }); it ('Contain case', () => { const c1 = circle(point(250, 150), 100); const c2 = circle(point(275, 150), 50); expect(disjoint(c1, c2)).to.be.false; expect(intersect(c1, c2)).to.be.true; expect(contain(c1, c2)).to.be.true; }); it ('Inside case', () => { const c1 = circle(point(250, 150), 100); const c2 = circle(point(275, 150), 50); expect(disjoint(c1, c2)).to.be.false; expect(intersect(c1, c2)).to.be.true; expect(inside(c2, c1)).to.be.true; }); }); describe('#Algorithms.Relation.Polygon2Polygon', function() { it('May calculate relations. Disjoint case', () => { let p1 = new Polygon(box(0,0,50,100).toSegments()); let p2 = new Polygon(box(100,50,150,150).toSegments()); let de9im = relate(p1, p2); expect(de9im.I2I.length).to.equal(0); expect(disjoint(p1, p2)).to.be.true; expect(equal(p1, p2)).to.be.false; expect(intersect(p1, p2)).to.be.false; expect(touch(p1, p2)).to.be.false; expect(inside(p1, p2)).to.be.false; expect(contain(p1, p2)).to.be.false; }); it('May calculate relations. Touching from outside case', () => { let p1 = new Polygon(box(0,0,50,100).toSegments()); let p2 = new Polygon(box(50,50,100,150).toSegments()); expect(disjoint(p1, p2)).to.be.false; expect(equal(p1, p2)).to.be.false; expect(intersect(p1, p2)).to.be.true; expect(touch(p1, p2)).to.be.true; expect(inside(p1, p2)).to.be.false; expect(contain(p1, p2)).to.be.false; expect(covered(p1,p2)).to.be.false; expect(cover(p1,p2)).to.be.false; }); it('May calculate relations. Case of inclusion', () => { let p1 = new Polygon(box(0,0,50,100).toSegments()); let p2 = new Polygon(box(20,20,30,30).toSegments()); expect(disjoint(p1, p2)).to.be.false; expect(equal(p1, p2)).to.be.false; expect(intersect(p1, p2)).to.be.true; expect(touch(p1, p2)).to.be.false; expect(inside(p1, p2)).to.be.false; expect(contain(p1, p2)).to.be.true; expect(covered(p1,p2)).to.be.false; expect(cover(p1,p2)).to.be.true; }); it('May calculate relations. Case of covered', () => { let p1 = new Polygon(box(0,0,50,100).toSegments()); let p2 = new Polygon(box(20,0,50,30).toSegments()); expect(disjoint(p1, p2)).to.be.false; expect(equal(p1, p2)).to.be.false; expect(intersect(p1, p2)).to.be.true; expect(touch(p1, p2)).to.be.false; expect(inside(p1, p2)).to.be.false; expect(contain(p1, p2)).to.be.true; expect(covered(p1,p2)).to.be.false; expect(cover(p1,p2)).to.be.true; }); it('May calculate relations. Case of intersected polygons', () => { let p1 = new Polygon(box(0,0,50,100).toSegments()); let p2 = new Polygon(box(20,20,150,200).toSegments()); let de9im = relate(p1, p2); expect(disjoint(p1, p2)).to.be.false; expect(equal(p1, p2)).to.be.false; expect(intersect(p1, p2)).to.be.true; expect(touch(p1, p2)).to.be.false; expect(inside(p1, p2)).to.be.false; expect(contain(p1, p2)).to.be.false; expect(covered(p1,p2)).to.be.false; expect(cover(p1,p2)).to.be.false; }); it('Infinite loop error in Relations.relate() issue #63', () => { let polygonA = new Polygon(JSON.parse('[[{"pc":{"x":361.86046511627904,"y":358.1395348837209,"name":"point"},"r":3.7013112186046513,"startAngle":0.8060492302297078,"endAngle":4.549840858948246,"counterClockwise":false,"name":"arc"},{"ps":{"x":361.26146984929693,"y":354.4870139177165,"name":"point"},"pe":{"x":355.3805768669687,"y":355.45145110913296,"name":"point"},"name":"segment"},{"pc":{"x":356.27906976744185,"y":360.93023255813955,"name":"point"},"r":5.551966827906977,"startAngle":4.549840858948247,"endAngle":0.8060492302297152,"counterClockwise":false,"name":"arc"},{"ps":{"x":360.12299918636324,"y":364.936295747922,"name":"point"},"pe":{"x":364.42308472889334,"y":360.8102436769092,"name":"point"},"name":"segment"}]]')); let polygonB = new Polygon(JSON.parse('[[{"pc":{"x":356.27906976744185,"y":360.93023255813955,"name":"point"},"r":5.551966827906977,"startAngle":4.569083935001064,"endAngle":1.9978954813868353,"counterClockwise":false,"name":"arc"},{"ps":{"x":353.979265872936,"y":365.9834728754998,"name":"point"},"pe":{"x":359.7242924817441,"y":368.59811887275936,"name":"point"},"name":"segment"},{"pc":{"x":362.7906976744186,"y":361.86046511627904,"name":"point"},"r":7.402622437209303,"startAngle":1.9978954813868424,"endAngle":4.56908393500106,"counterClockwise":false,"name":"arc"},{"ps":{"x":361.7334917412655,"y":354.5337240561091,"name":"point"},"pe":{"x":355.48616531757705,"y":355.4351767630121,"name":"point"},"name":"segment"}]]')); let de9im = relate(polygonA, polygonB); expect(de9im.intersect()).to.be.true; }); it('Calculate contains relation for multipolygon. Issue #81', function() { const pA = new Flatten.Polygon([ [50, 100], [100, 100], [100, 50], [100, 0], [50, 0], [0, 0], [0, 50], [50, 50], [50, 100] ]); const pB = new Flatten.Polygon([ [50, 50], [100, 50], [100, 0], [50, 0], [50, 50] ]); const pC = new Flatten.Polygon([ [50, 50], [50, 100], [100, 100], [100, 50], [50, 50] ]); const p0 = Flatten.BooleanOperations.subtract(pA, pB); expect(p0.faces.size).to.equal(1); expect(p0.edges.size).to.equal(8); expect(p0.contains(pB)).to.be.false; expect(p0.contains(pC)).to.be.true; }); }); });