WebWorldWind/test/geom/Sector.test.js
Mark Peterson dabcdd1f06 Improve SurfaceShape deep picking performance (#259)
* Frustum culling incorporated into SurfaceShape

* Deep Picking stress test example

* Unit tests for new functionality in Sector and BoundingBox
2017-10-27 11:51:15 -07:00

503 lines
22 KiB
JavaScript

/*
* Copyright (C) 2014 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration. All Rights Reserved.
*/
define([
'src/geom/Sector',
'src/geom/Location',
'src/globe/EarthElevationModel',
'src/geom/BoundingBox',
'src/geom/Vec3',
'src/globe/Globe'
], function (Sector, Location, EarthElevationModel, BoundingBox, Vec3, Globe) {
"use strict";
describe("Sector Tests", function () {
it("Should construct a Sector", function () {
var sector = new Sector(37, 39, 13, 18);
expect(sector.minLatitude).toEqual(37);
expect(sector.maxLatitude).toEqual(39);
expect(sector.minLongitude).toEqual(13);
expect(sector.maxLongitude).toEqual(18);
});
it("Should create a sector initialized with all 0", function () {
var sectorZero = Sector.ZERO;
expect(sectorZero.minLatitude).toEqual(0);
expect(sectorZero.maxLatitude).toEqual(0);
expect(sectorZero.minLongitude).toEqual(0);
expect(sectorZero.maxLongitude).toEqual(0);
});
it("Should create a sector that encompasses the full range of latitude and longitude", function () {
var sectorFull = Sector.FULL_SPHERE;
expect(sectorFull.minLatitude).toEqual(-90);
expect(sectorFull.maxLatitude).toEqual(90);
expect(sectorFull.minLongitude).toEqual(-180);
expect(sectorFull.maxLongitude).toEqual(180);
});
describe("Copies this sector to the latitude and longitude of a specified sector", function () {
it("Copies the sector successfully", function () {
var sector = Sector.ZERO;
var sectorTarget = new Sector(37, 39, 13, 18);
sector.copy(sectorTarget);
expect(sector.minLatitude).toEqual(37);
expect(sector.maxLatitude).toEqual(39);
expect(sector.minLongitude).toEqual(13);
expect(sector.maxLongitude).toEqual(18);
});
it("Should throw an exception on missing sector input", function () {
expect(function () {
var sector = Sector.ZERO;
sector.copy(null);
}).toThrow();
});
});
describe("Indicates whether this sector has width or height", function () {
it("Sector is not empty", function () {
var sector = new Sector(37, 39, 13, 18);
expect(sector.isEmpty()).toBe(false);
});
it("Sector is empty", function () {
var sector = new Sector(37, 37, 13, 13);
expect(sector.isEmpty()).toBe(true);
});
});
it("Returns the angle between this sector's minimum and maximum latitudes, in degrees", function () {
var sector = new Sector(37, 39, 13, 18);
expect(sector.deltaLatitude()).toEqual(2);
});
it("Returns the angle between this sector's minimum and maximum longitude, in degrees", function () {
var sector = new Sector(37, 39, 13, 18);
expect(sector.deltaLongitude()).toEqual(5);
});
it("Returns the angle midway between this sector's minimum and maximum latitudes", function () {
var sector = new Sector(37, 39, 13, 18);
expect(sector.centroidLatitude()).toEqual(38);
});
it("Returns the angle midway between this sector's minimum and maximum longitude", function () {
var sector = new Sector(37, 39, 13, 18);
expect(sector.centroidLongitude()).toEqual(15.5);
});
describe("Computes the location of the angular center of this sector", function () {
it("Computes the location correctly", function () {
var sector = new Sector(37, 39, 13, 18);
var result = new Location(0, 0);
sector.centroid(result);
expect(result.latitude).toEqual(38);
expect(result.longitude).toEqual(15.5);
});
it("Should throw an exception on missing result", function () {
expect(function () {
var sector = new Sector(37, 39, 13, 18);
sector.centroid(null);
}).toThrow();
});
});
it("Returns this sector's minimum latitude in radians", function () {
var sector = new Sector(37, 39, 13, 18);
var minLatitudeRadians = sector.minLatitudeRadians();
expect(minLatitudeRadians).toBeCloseTo(0.645);
});
it("Returns this sector's maximum latitude in radians", function () {
var sector = new Sector(37, 39, 13, 18);
var maxLatitudeRadians = sector.maxLatitudeRadians();
expect(maxLatitudeRadians).toBeCloseTo(0.680);
});
it("Returns this sector's minimum longitude in radians", function () {
var sector = new Sector(37, 39, 13, 18);
var minLongitudeRadians = sector.minLongitudeRadians();
expect(minLongitudeRadians).toBeCloseTo(0.226);
});
it("Returns this sector's minimum longitude in radians", function () {
var sector = new Sector(37, 39, 13, 18);
var maxLongitudeRadians = sector.maxLongitudeRadians();
expect(maxLongitudeRadians).toBeCloseTo(0.314);
});
describe("Modifies this sector to encompass an array of specified locations", function () {
it("Set the bounding correctly", function () {
var sector = new Sector(37, 39, 13, 18);
var locations = [
new Location(37.52, 15.08),
new Location(38.63, 15.32),
new Location(38.72, 16.03),
new Location(38.88, 12.34)
];
sector.setToBoundingSector(locations);
expect(sector.minLatitude).toEqual(37.52);
expect(sector.maxLatitude).toEqual(38.88);
expect(sector.minLongitude).toEqual(12.34);
expect(sector.maxLongitude).toEqual(16.03);
});
it("Should throw an exception on missing locations array", function () {
expect(function () {
var sector = new Sector(37, 39, 13, 18);
sector.setToBoundingSector(null);
}).toThrow();
});
});
describe("Computes bounding sectors from a list of locations that span the dateline", function () {
it("Computes the sectors correctly", function () {
var locations = [
new Location(37.52, 15.08),
new Location(38.63, 15.32),
new Location(38.72, 16.03),
new Location(38.88, 12.34)
];
var resultSector = Sector.splitBoundingSectors(locations);
expect(resultSector.length).toBe(2);
expect(resultSector[0].minLatitude).toEqual(37.52);
expect(resultSector[0].maxLatitude).toEqual(38.88);
expect(resultSector[0].minLongitude).toEqual(12.34);
expect(resultSector[0].maxLongitude).toEqual(180);
expect(resultSector[1].minLatitude).toEqual(37.52);
expect(resultSector[1].maxLatitude).toEqual(38.88);
expect(resultSector[1].minLongitude).toEqual(-180);
expect(resultSector[1].maxLongitude).toEqual(-180);
});
it("Should throw an exception on missing locations array", function () {
expect(function () {
Sector.splitBoundingSectors(null);
}).toThrow();
});
});
describe("Indicates whether this sector intersects a specified sector", function () {
it("The first sector intersects the second one", function () {
var sectorA = new Sector(37, 39, 13, 18);
var sectorB = new Sector(39, 40, 18, 19);
var intersection = sectorA.intersects(sectorB);
expect(intersection).toBe(true);
});
it("The first sector does not intersect the second one", function () {
var sectorA = new Sector(37, 39, 13, 18);
var sectorB = new Sector(42, 44, 15, 19);
var intersection = sectorA.intersects(sectorB);
expect(intersection).toBe(false);
});
});
describe("Indicates whether this sector intersects strictly a specified sector", function () {
it("The first sector intersects the second one", function () {
var sectorA = new Sector(37, 39, 13, 18);
var sectorB = new Sector(38, 40, 17, 19);
var intersection = sectorA.overlaps(sectorB);
expect(intersection).toBe(true);
});
it("The first sector does not intersects the second one", function () {
var sectorA = new Sector(37, 39, 13, 18);
var sectorB = new Sector(39, 40, 18, 19);
var intersection = sectorA.overlaps(sectorB);
expect(intersection).toBe(false);
});
});
describe("Indicates whether this sector fully contains a specified sector", function () {
it("The first sector contains the second one", function () {
var sectorA = new Sector(36, 39, 13, 18);
var sectorB = new Sector(38, 38, 15, 17);
var contains = sectorA.contains(sectorB);
expect(contains).toBe(true);
});
it("The first sector does not contains the second one", function () {
var sectorA = new Sector(37, 39, 13, 18);
var sectorB = new Sector(39, 40, 18, 19);
var contains = sectorA.contains(sectorB);
expect(contains).toBe(false);
});
});
describe("Indicates whether this sector contains a specified geographic location", function () {
it("The sector contains the location", function () {
var sector = new Sector(36, 39, 13, 18);
var contains = sector.containsLocation(37, 15);
expect(contains).toBe(true);
});
it("The sector does not contains the location", function () {
var sector = new Sector(36, 39, 13, 18);
var contains = sector.containsLocation(37, 22);
expect(contains).toBe(false);
});
});
describe("Sets this sector to the intersection of itself and a specified sector", function () {
it("Returns the intersection", function () {
var sectorA = new Sector(36, 39, 13, 18);
var sectorB = new Sector(38, 40, 15, 17);
sectorA.intersection(sectorB);
expect(sectorA.minLatitude).toEqual(38);
expect(sectorA.maxLatitude).toEqual(39);
expect(sectorA.minLongitude).toEqual(15);
expect(sectorA.maxLongitude).toEqual(17);
});
it("Should throw an exception on missing sector input", function () {
expect(function () {
var sector = Sector.ZERO;
sector.intersection(null);
}).toThrow();
});
});
describe("Get corners method", function () {
it("Returns corner points in the correct order", function () {
var sector = new Sector(44, 45, -95, -94);
var corners = sector.getCorners();
expect(corners[0].latitude).toEqual(44);
expect(corners[0].longitude).toEqual(-95);
expect(corners[1].latitude).toEqual(44);
expect(corners[1].longitude).toEqual(-94);
expect(corners[2].latitude).toEqual(45);
expect(corners[2].longitude).toEqual(-94);
expect(corners[3].latitude).toEqual(45);
expect(corners[3].longitude).toEqual(-95);
});
});
describe("Compute bounding points method", function () {
it("Should throw an exception because no globe is provided", function () {
var sector = new Sector(44, 45, -95, -94);
expect(function () {
sector.computeBoundingPoints(null /* globe */, 1 /* verticalExaggeration */)
}).toThrow();
});
it("Computes the correct bounding points for a given sector", function () {
// create a globe that returns mock elevations for a given sector so we don't have to rely on
// asynchronous tile calls to finish.
Globe.prototype.minAndMaxElevationsForSector = function (sector) {
return [125.0, 350.0];
};
var mockGlobe = new Globe(new EarthElevationModel());
var sector = new Sector(44.0, 45.0, -95.0, -94.0);
var boundingPoints = sector.computeBoundingPoints(mockGlobe, 1 /* verticalExaggeration */);
var results = [-4578078.7560, 4408178.4447, -400529.9919, -4578239.9915, 4408334.7429, -400544.0982,
-4584371.7046, 4408178.4447, -320570.4981, -4584533.1618, 4408334.7429, -320581.7883,
-4506674.4276, 4487436.7972, -315137.3752, -4506833.1390, 4487595.8962, -315148.4734,
-4500488.1337, 4487436.7972, -393741.6920, -4500646.6273, 4487595.8962, -393755.5584,
-4542910.2988, 4448133.5080, -357534.7945, -4581561.0285, 4408334.7429, -360576.6729];
var resultCount = 0;
for (var i = 0; i < boundingPoints.length; i++) {
var vec = boundingPoints[i];
for (var j = 0; j < 3; j++) {
expect(vec[j]).toBeCloseTo(results[resultCount], 3);
resultCount++;
}
}
});
it("Computes the correct bounding points for a sector crossing the anti-Meridian", function () {
// create a globe that returns mock elevations for a given sector so we don't have to rely on
// asynchronous tile calls to finish.
Globe.prototype.minAndMaxElevationsForSector = function (sector) {
return [125.0, 350.0];
};
var mockGlobe = new Globe(new EarthElevationModel());
var sector = new Sector(44.0, 45.0, -179, 179.0);
var boundingPoints = sector.computeBoundingPoints(mockGlobe, 1 /* verticalExaggeration */);
var results = [-80203.6904, 4408178.4447, -4594866.3461, -80206.5151, 4408334.7429, -4595028.1729,
80203.6904, 4408178.4447, -4594866.3461, 80206.5151, 4408334.7429, -4595028.1729,
78844.3747, 4487436.7972, -4516991.2028, 78847.1514, 4487595.8962, -4517150.2776,
-78844.3747, 4487436.7972, -4516991.2028, -78847.1514, 4487595.8962, -4517150.2776,
0.0000, 4448133.5080, 4556957.8791, 0.0000, 4408334.7429, 4595728.1245,
-4556784.3641, 4448133.5080, 39766.4547, 4556784.3641, 4448133.5080, 39766.4547,
-79529.8810, 4448133.5080, -4556263.8324, 79529.8810, 4448133.5080, -4556263.8324];
var resultCount = 0;
for (var i = 0; i < boundingPoints.length; i++) {
var vec = boundingPoints[i];
for (var j = 0; j < 3; j++) {
expect(vec[j]).toBeCloseTo(results[resultCount], 3);
resultCount++;
}
}
});
it("Computes the correct bounding points for a sector spanning the globe horizontally", function () {
// create a globe that returns mock elevations for a given sector so we don't have to rely on
// asynchronous tile calls to finish.
Globe.prototype.minAndMaxElevationsForSector = function (sector) {
return [125.0, 350.0];
};
var mockGlobe = new Globe(new EarthElevationModel());
var sector = new Sector(44.0, 45.0, -180, 180.0);
var boundingPoints = sector.computeBoundingPoints(mockGlobe, 1 /* verticalExaggeration */);
var results = [-0.0000, 4408178.4447, -4595566.2731, -0.0000, 4408334.7429, -4595728.1245,
0.0000, 4408178.4447, -4595566.2731, 0.0000, 4408334.7429, -4595728.1245,
0.0000, 4487436.7972, -4517679.2672, 0.0000, 4487595.8962, -4517838.3662,
0.0000, 4487436.7972, -4517679.2672, -0.0000, 4487595.8962, -4517838.3662,
0.0000, 4448133.5080, 4556957.8791, 0.0000, 4408334.7429, 4595728.1245,
0.0000, 4408334.7429, 4595728.1245, 4595728.1245, 4408334.7429, 0.0000,
-4595728.1245, 4408334.7429, 0.0000, 0.0000, 4408334.7429, -4595728.1245,
0.0000, 4487595.8962, 4517838.3662, 4517838.3662, 4487595.8962,
0.0000, -4517838.3662, 4487595.8962, 0.0000, 0.0000, 4487595.8962, -4517838.3662];
var resultCount = 0;
for (var i = 0; i < boundingPoints.length; i++) {
var vec = boundingPoints[i];
for (var j = 0; j < 3; j++) {
expect(vec[j]).toBeCloseTo(results[resultCount], 3);
resultCount++;
}
}
});
it("Computes the correct bounding points for a sector in the southern hemisphere", function () {
// create a globe that returns mock elevations for a given sector so we don't have to rely on
// asynchronous tile calls to finish.
Globe.prototype.minAndMaxElevationsForSector = function (sector) {
return [125.0, 350.0];
};
var mockGlobe = new Globe(new EarthElevationModel());
var sector = new Sector(-45.0, -44.0, -95.0, -94.0);
var boundingPoints = sector.computeBoundingPoints(mockGlobe, 1 /* verticalExaggeration */);
var results = [-4500488.1337, -4487436.7972, -393741.6920, -4500646.6273, -4487595.8962, -393755.5584,
-4506674.4276, -4487436.7972, -315137.3752, -4506833.1390, -4487595.8962, -315148.4734,
-4584371.7046, -4408178.4447, -320570.4981, -4584533.1618, -4408334.7429, -320581.7883,
-4578078.7560, -4408178.4447, -400529.9919, -4578239.9915, -4408334.7429, -400544.0982,
-4542910.2988, -4448133.5080, -357534.7945, -4581561.0285, -4408334.7429, -360576.6729];
var resultCount = 0;
for (var i = 0; i < boundingPoints.length; i++) {
var vec = boundingPoints[i];
for (var j = 0; j < 3; j++) {
expect(vec[j]).toBeCloseTo(results[resultCount], 3);
resultCount++;
}
}
});
it("Computes the correct bounding points for a sector crossing the equator", function () {
// create a globe that returns mock elevations for a given sector so we don't have to rely on
// asynchronous tile calls to finish.
Globe.prototype.minAndMaxElevationsForSector = function (sector) {
return [125.0, 350.0];
};
var mockGlobe = new Globe(new EarthElevationModel());
var sector = new Sector(-10.0, 10.0, -95.0, -94.0);
var boundingPoints = sector.computeBoundingPoints(mockGlobe, 1 /* verticalExaggeration */);
var results = [-6258091.0395, -1100270.2538, -547512.0213, -6258311.7780, -1100309.3246, -547531.3334,
-6266693.3042, -1100270.2538, -438209.8842, -6266914.3462, -1100309.3246, -438225.3410,
-6266693.3042, 1100270.2538, -438209.8842, -6266914.3462, 1100309.3246, -438225.3410,
-6258091.0395, 1100270.2538, -547512.0213, -6258311.7780, 1100309.3246, -547531.3334,
-6358824.2533, 0.0000, -500450.3221, -6262851.5323, -1100309.3246, -492897.1052,
-6262851.5323, 1100309.3246, -492897.1052, -6354214.9312, 0.0000, -555921.7721,
-6362949.3262, 0.0000, -444940.7609];
var resultCount = 0;
for (var i = 0; i < boundingPoints.length; i++) {
var vec = boundingPoints[i];
for (var j = 0; j < 3; j++) {
expect(vec[j]).toBeCloseTo(results[resultCount], 3);
resultCount++;
}
}
});
});
describe("Sets this sector to the union of itself and a specified sector", function () {
it("Returns the intersection", function () {
var sectorA = new Sector(36, 39, 13, 18);
var sectorB = new Sector(38, 40, 15, 17);
sectorA.union(sectorB);
expect(sectorA.minLatitude).toEqual(36);
expect(sectorA.maxLatitude).toEqual(40);
expect(sectorA.minLongitude).toEqual(13);
expect(sectorA.maxLongitude).toEqual(18);
});
it("Should throw an exception on missing sector input", function () {
expect(function () {
var sector = Sector.ZERO;
sector.union(null);
}).toThrow();
});
});
});
});