UNPKG

circle-to-polygon

Version:

Receives a Coordinate, a Radius and a Number of edges and aproximates a circle by creating a polygon that fills its area

631 lines (563 loc) 22.3 kB
const { expect } = require("chai"); const circleToPolygon = require("../index.js"); describe("Output verification", () => { describe("Polygon should have correct attributes", () => { let result; beforeEach(() => { result = circleToPolygon([16.226412, 58.556493], 138, 3); }); it("should have atribute 'type' with value 'Polygon'", () => { expect(result).to.haveOwnProperty("type", "Polygon"); }); it("should have atribute 'coordinates' of type 'array'", () => { expect(result).to.haveOwnProperty("coordinates"); expect(result.coordinates).to.be.an("array"); }); it("coordinates should be an 'array of an array of arrays' of '2d-points'", () => { expect(result.coordinates[0]).to.be.an("array"); expect(result.coordinates.length).to.equal(1); result.coordinates[0].forEach(coordinate => { expect(coordinate).to.be.an("array"); // 2d-point? expect(coordinate.length).to.equal(2); coordinate.forEach(value => { expect(value).to.be.a("number"); }); }); }); }); describe("Polygon should have valid coordinates", () => { /* Not all engins get the same value, so we use rounded values. 6 decimal points is about 11 cm (true for both lat/lng and geoJSON coordinates). */ describe("Testing trivial points", () => { it("should give correct coordinates for point east of GMT, north of equator", () => { const coordinates = circleToPolygon([16.226412, 58.556493], 138, 10).coordinates[0]; const expectedCoordinates = [ [16.226412, 58.557732], [16.225015, 58.557495], [16.224151, 58.556876], [16.224151, 58.556109], [16.225015, 58.55549], [16.226412, 58.555253], [16.227808, 58.55549], [16.228672, 58.556109], [16.228672, 58.556876], [16.227808, 58.557495], [16.226412, 58.557732] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give correct coordinates for center in [0, 0]", () => { const coordinates = circleToPolygon([0, 0], 13, 12).coordinates[0]; const expectedCoordinates = [ [0, 0.000116], [-0.000058, 0.000101], [-0.000101, 0.000058], [-0.000116, 0], [-0.000101, -0.000058], [-0.000058, -0.000101], [0, -0.000116], [0.000058, -0.000101], [0.000101, -0.000058], [0.000116, 0], [0.000101, 0.000058], [0.000058, 0.000101], [0, 0.000116] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give correct coordinates for point east of GMT, south of equator", () => { const coordinates = circleToPolygon([131.034184, -25.343467], 5000, 32).coordinates[0]; const expectedCoordinates = [ [131.034184, -25.298551], [131.024491, -25.299413], [131.015171, -25.301969], [131.006581, -25.306118], [130.99905, -25.311702], [130.992869, -25.318507], [130.988274, -25.326271], [130.985443, -25.334696], [130.984485, -25.343458], [130.985436, -25.352221], [130.988261, -25.360648], [130.992852, -25.368415], [130.999032, -25.375223], [131.006564, -25.38081], [131.015158, -25.384962], [131.024484, -25.387519], [131.034184, -25.388382], [131.043883, -25.387519], [131.053209, -25.384962], [131.061803, -25.38081], [131.069335, -25.375223], [131.075515, -25.368415], [131.080106, -25.360648], [131.082931, -25.352221], [131.083882, -25.343458], [131.082924, -25.334696], [131.080093, -25.326271], [131.075498, -25.318507], [131.069317, -25.311702], [131.061786, -25.306118], [131.053196, -25.301969], [131.043876, -25.299413], [131.034184, -25.298551] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give same value when numberOfSegemnts is undefined or 32", () => { const expectedCoordinates = circleToPolygon([131.034184, -25.343467], 5000, 32) .coordinates[0]; const coordinates = circleToPolygon([131.034184, -25.343467], 5000, undefined) .coordinates[0]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give same value when numberOfSegemnts is { numberOfEdges: undefined } or 32", () => { const expectedCoordinates = circleToPolygon([131.034184, -25.343467], 5000, 32) .coordinates[0]; const coordinates = circleToPolygon([131.034184, -25.343467], 5000, { numberOfEdges: undefined }).coordinates[0]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give same value when options is null as when undefined", () => { const expectedCoordinates = circleToPolygon([131.034184, -25.343467], 5000, 32) .coordinates[0]; const coordinates = circleToPolygon([131.034184, -25.343467], 5000, null).coordinates[0]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give correct coordinates for point west of GMT, north of equator", () => { const coordinates = circleToPolygon([-121.003331, 66.001764], 50000, 64).coordinates[0]; const expectedCoordinates = [ [-121.003331, 66.450921], [-121.113511, 66.44872], [-121.222573, 66.442137], [-121.329411, 66.431241], [-121.432946, 66.416142], [-121.532136, 66.396992], [-121.625992, 66.373985], [-121.713583, 66.347352], [-121.794052, 66.317362], [-121.866619, 66.284315], [-121.930593, 66.24854], [-121.985376, 66.210392], [-122.030471, 66.170249], [-122.065479, 66.128506], [-122.090108, 66.085572], [-122.104172, 66.041865], [-122.107589, 65.997809], [-122.10038, 65.953829], [-122.082669, 65.910347], [-122.054678, 65.867778], [-122.016723, 65.826527], [-121.96921, 65.786983], [-121.912629, 65.749519], [-121.847547, 65.714486], [-121.774605, 65.68221], [-121.694509, 65.652991], [-121.608023, 65.627101], [-121.515964, 65.604777], [-121.419191, 65.586227], [-121.318604, 65.571619], [-121.215128, 65.561089], [-121.109716, 65.554731], [-121.003331, 65.552606], [-120.896945, 65.554731], [-120.791533, 65.561089], [-120.688057, 65.571619], [-120.58747, 65.586227], [-120.490697, 65.604777], [-120.398638, 65.627101], [-120.312152, 65.652991], [-120.232056, 65.68221], [-120.159114, 65.714486], [-120.094032, 65.749519], [-120.037451, 65.786983], [-119.989938, 65.826527], [-119.951983, 65.867778], [-119.923992, 65.910347], [-119.906281, 65.953829], [-119.899072, 65.997809], [-119.902489, 66.041865], [-119.916553, 66.085572], [-119.941182, 66.128506], [-119.97619, 66.170249], [-120.021285, 66.210392], [-120.076068, 66.24854], [-120.140042, 66.284315], [-120.212609, 66.317362], [-120.293078, 66.347352], [-120.380669, 66.373985], [-120.474525, 66.396992], [-120.573715, 66.416142], [-120.67725, 66.431241], [-120.784088, 66.442137], [-120.89315, 66.44872], [-121.003331, 66.450921] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give correct coordinates for point west of GMT, south of equator", () => { const coordinates = circleToPolygon([-75.1299566, -14.7391814], 5000, 12).coordinates[0]; const expectedCoordinates = [ [-75.129956, -14.694265], [-75.153174, -14.700282], [-75.170174, -14.71672], [-75.1764, -14.739176], [-75.170182, -14.761635], [-75.153182, -14.778078], [-75.129956, -14.784097], [-75.10673, -14.778078], [-75.08973, -14.761635], [-75.083512, -14.739176], [-75.089739, -14.71672], [-75.106738, -14.700282], [-75.129956, -14.694265] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should pass the pentagon test", () => { // A pentagon on Pentagon, Virginia const coordinates = circleToPolygon([-77.055961, 38.870996], 200, 5).coordinates[0]; const expectedCoordinates = [ [-77.055961, 38.872792], [-77.058155, 38.871551], [-77.057317, 38.869542], [-77.054604, 38.869542], [-77.053766, 38.871551], [-77.055961, 38.872792] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should accept coordinates with 'Altitude' or 'Elevation' attribute", () => { const coordinates = circleToPolygon([0, 0, 34], 13, 12).coordinates[0]; const expectedCoordinates = [ [0, 0.000116], [-0.000058, 0.000101], [-0.000101, 0.000058], [-0.000116, 0], [-0.000101, -0.000058], [-0.000058, -0.000101], [0, -0.000116], [0.000058, -0.000101], [0.000101, -0.000058], [0.000116, 0], [0.000101, 0.000058], [0.000058, 0.000101], [0, 0.000116] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give correct coordinates for center in [0, 0] and equatorial Earth radius", () => { const coordinates = circleToPolygon([0, 0], 1000000, { numberOfEdges: 12, earthRadius: 6378137 }).coordinates[0]; const expectedCoordinates = [ [ 0, 8.983152 ], [ -4.519349, 7.771613 ], [ -7.795555, 4.477753 ], [ -8.983152, 0 ], [ -7.795555, -4.477753 ], [ -4.519349, -7.771613 ], [ 0, -8.983152 ], [ 4.519349, -7.771613 ], [ 7.795555, -4.477753 ], [ 8.983152, 0 ], [ 7.795555, 4.477753 ], [ 4.519349, 7.771613 ], [ 0, 8.983152 ] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give correct coordinates for center in [0, 0] and mean Earth radius", () => { const coordinates = circleToPolygon([0, 0], 1000000, { numberOfEdges: 12, earthRadius: 6371008.8 }).coordinates[0]; const expectedCoordinates = [ [ 0, 8.993203 ], [ -4.524468, 7.780290 ], [ -7.804312, 4.482732 ], [ -8.993203, 0 ], [ -7.804312, -4.482732 ], [ -4.524468, -7.780290 ], [ 0, -8.993203 ], [ 4.524468, -7.780290 ], [ 7.804312, -4.482732 ], [ 8.993203, 0 ], [ 7.804312, 4.482732 ], [ 4.524468, 7.780290 ], [ 0, 8.993203 ] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give rotated coordinates for bearing 90", () => { const coordinates = circleToPolygon([0, 0], 13, { numberOfEdges: 12, bearing: 90 }).coordinates[0]; const expectedCoordinates = [ [0.000116, 0], [0.000101, 0.000058], [0.000058, 0.000101], [0, 0.000116], [-0.000058, 0.000101], [-0.000101, 0.000058], [-0.000116, 0], [-0.000101, -0.000058], [-0.000058, -0.000101], [0, -0.000116], [0.000058, -0.000101], [0.000101, -0.000058], [0.000116, 0] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give rotated coordinates for bearing 180", () => { const coordinates = circleToPolygon([0, 0], 13, { numberOfEdges: 12, bearing: 180 }).coordinates[0]; const expectedCoordinates = [ [0, -0.000116], [0.000058, -0.000101], [0.000101, -0.000058], [0.000116, 0], [0.000101, 0.000058], [0.000058, 0.000101], [0, 0.000116], [-0.000058, 0.000101], [-0.000101, 0.000058], [-0.000116, 0], [-0.000101, -0.000058], [-0.000058, -0.000101], [0, -0.000116] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give rotated coordinates for bearing 270", () => { const coordinates = circleToPolygon([0, 0], 13, { numberOfEdges: 12, bearing: 270 }).coordinates[0]; const expectedCoordinates = [ [-0.000116, 0], [-0.000101, -0.000058], [-0.000058, -0.000101], [0, -0.000116], [0.000058, -0.000101], [0.000101, -0.000058], [0.000116, 0], [0.000101, 0.000058], [0.000058, 0.000101], [0, 0.000116], [-0.000058, 0.000101], [-0.000101, 0.000058], [-0.000116, 0] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("should give rotated coordinates for bearing 45", () => { const coordinates = circleToPolygon([0, 0], 13, { numberOfEdges: 12, bearing: 45 }).coordinates[0]; const expectedCoordinates = [ [ 0.000082, 0.000082 ], [ 0.000030, 0.000112 ], [ -0.000030, 0.000112 ], [ -0.000082, 0.000082 ], [ -0.000112, 0.000030 ], [ -0.000112, -0.000030 ], [ -0.000082, -0.000082 ], [ -0.000030, -0.000112 ], [ 0.000030, -0.000112 ], [ 0.000082, -0.000082 ], [ 0.000112, -0.000030 ], [ 0.000112, 0.000030 ], [ 0.000082, 0.000082 ] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); }); xdescribe("Testing non-trivial points", () => { xit("should return corret circle for center in lat -90", () => {}); xit("should return corret circle for center in lat 90 ", () => {}); xit("should return corret circle for center in lng 180 ", () => {}); xit("should return corret circle for center in lng -180 ", () => {}); xit("should return corret circle for center in lat 90 lng 180 ", () => {}); xit("should return corret circle for center in lat 90 lng -180 ", () => {}); xit("should return corret circle for center in lat -90 lng 180 ", () => {}); xit("should return corret circle for center in lat -90 lng -180 ", () => {}); }); xdescribe("Testing circles crossing the 180th Meridian", () => { xit("center's longitude value is close to 180", () => {}); xit("center's longitude value is close to -180", () => {}); }); xdescribe("Testing circles where the north pole is inside the circle's radius", () => { xit("test 1", () => {}); xit("test 2", () => {}); }); xdescribe("Testing circles where the south pole is inside the circle's radius", () => { xit("test 1", () => {}); xit("test 2", () => {}); }); }); describe("Testing Different Options", () => { it("should give same result when passing numberOfEdges as number or as object", () => { const sentAsNumber = circleToPolygon([7.023961, 38.870996], 64, 23).coordinates[0]; const sentAsObject = circleToPolygon([7.023961, 38.870996], 64, { numberOfEdges: 23 }).coordinates[0]; expect(sentAsObject).to.eql(sentAsNumber); }); describe("should return circle drawn using right-hand rule if passed `{ rightHandRuleRule: true }`", () => { it("Test 1: Pentagon", () => { const coordinates = circleToPolygon( [-77.055961, 38.870996], 200, { numberOfEdges: 5, rightHandRule: true } ).coordinates[0]; // This is the same coordinates as the pentagon test // but in opposite direction const expectedCoordinates = [ [-77.055961, 38.872792], [-77.053766, 38.871551], [-77.054604, 38.869542], [-77.057317, 38.869542], [-77.058155, 38.871551], [-77.055961, 38.872792] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("Test 2: 12 edges, center in [0, 0]", () => { const coordinates = circleToPolygon( [0, 0], 13, { numberOfEdges: 12, rightHandRule: true } ).coordinates[0]; const expectedCoordinates = [ [0, 0.000116], [0.000058, 0.000101], [0.000101, 0.000058], [0.000116, 0], [0.000101, -0.000058], [0.000058, -0.000101], [0, -0.000116], [-0.000058, -0.000101], [-0.000101, -0.000058], [-0.000116, 0], [-0.000101, 0.000058], [-0.000058, 0.000101], [0, 0.000116] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); it("Test 3: With bearing", () => { const coordinates = circleToPolygon( [0, 0], 13, { numberOfEdges: 12, bearing: 90, rightHandRule: true } ).coordinates[0]; // Same as should give rotated coordinates for bearing 90 // but in opposite direction const expectedCoordinates = [ [0.000116, 0], [0.000101, -0.000058], [0.000058, -0.000101], [0, -0.000116], [-0.000058, -0.000101], [-0.000101, -0.000058], [-0.000116, 0], [-0.000101, 0.000058], [-0.000058, 0.000101], [0, 0.000116], [0.000058, 0.000101], [0.000101, 0.000058], [0.000116, 0] ]; coordinates.forEach((cord, cordIndex) => { cord.forEach((value, valueIndex) => { const expectedValue = expectedCoordinates[cordIndex][valueIndex]; expect(value).to.be.closeTo(expectedValue, 0.00001); }); }); }); }); }); });