M-Scott-Lassiter / jest-geojson

GeoJSON Validation Matchers for Jest
https://m-scott-lassiter.github.io/jest-geojson/
MIT License
9 stars 0 forks source link

isValid3DBoundingBox #7

Closed M-Scott-Lassiter closed 2 years ago

M-Scott-Lassiter commented 2 years ago

Description

Bounding boxes are an optional GeoJSON property that describe a box of longitude boundaries that run along meridians and latitude boundaries that are parallel to the equator. A 2D Bounding Box only describes longitude and latitude boundaries, whereas a 3D BBox describes an additional min and max altitude/depth value.

A GeoJSON object MAY have a member named "bbox" to include information on the coordinate range for its Geometries, Features, or FeatureCollections. The value of the bbox member MUST be an array of length 2*n where n is the number of dimensions represented in the contained geometries, with all axes of the most southwesterly point followed by all axes of the more northeasterly point. The axes order of a bbox follows the axes order of geometries.

The "bbox" values define shapes with edges that follow lines of constant longitude, latitude, and elevation. ~ https://datatracker.ietf.org/doc/html/rfc7946#section-5

Format

The values of a "bbox" array are [west, south, east, north], not [minx, miny, maxx, maxy]. ~https://datatracker.ietf.org/doc/html/rfc7946#appendix-B.1

The 3D BBox spec is not explicit, but can be inferred as: [west, south, depth, east, north, altitude].

The Antimeridian

In the case of objects spanning the antimeridian, a bounding box becomes required.

Consider a set of point Features within the Fiji archipelago, straddling the antimeridian between 16 degrees S and 20 degrees S. The southwest corner of the box containing these Features is at 20 degrees S and 177 degrees E, and the northwest corner is at 16 degrees S and 178 degrees W. The antimeridian-spanning GeoJSON bounding box for this FeatureCollection is

"bbox": [177.0, -20.0, -178.0, -16.0]

and covers 5 degrees of longitude. The complementary bounding box for the same latitude band, not crossing the antimeridian, is

"bbox": [-178.0, -20.0, 177.0, -16.0]

and covers 355 degrees of longitude.

The latitude of the northeast corner is always greater than the latitude of the southwest corner, but bounding boxes that cross the antimeridian have a northeast corner longitude that is less than the longitude of the southwest corner. ~https://datatracker.ietf.org/doc/html/rfc7946#section-5.2

The Poles

An area that encompasses either the north or south pole will also require a bounding box that meets special use cases.

A bounding box that contains the North Pole extends from a southwest corner of "minlat" degrees N, 180 degrees W to a northeast corner of 90 degrees N, 180 degrees E. Viewed on a globe, this bounding box approximates a spherical cap bounded by the "minlat" circle of latitude.

"bbox": [-180.0, minlat, 180.0, 90.0]

A bounding box that contains the South Pole extends from a southwest corner of 90 degrees S, 180 degrees W to a northeast corner of "maxlat" degrees S, 180 degrees E.

"bbox": [-180.0, -90.0, 180.0, maxlat]

A bounding box that just touches the North Pole and forms a slice of an approximate spherical cap when viewed on a globe extends from a southwest corner of "minlat" degrees N and "westlon" degrees E to a northeast corner of 90 degrees N and "eastlon" degrees E.

"bbox": [westlon, minlat, eastlon, 90.0]

Similarly, a bounding box that just touches the South Pole and forms a slice of an approximate spherical cap when viewed on a globe has the following representation in GeoJSON.

"bbox": [westlon, -90.0, eastlon, maxlat]

Implementers MUST NOT use latitude values greater than 90 or less than -90 to imply an extent that is not a spherical cap. ~https://datatracker.ietf.org/doc/html/rfc7946#section-5.3

Boundaries

Any values outside of the WGS-84 standards should fail.

WGS84 Bounds: -180.0000, -90.0000, 180.0000, 90.0000 Projected Bounds: -180.0000, -90.0000, 180.0000, 90.0000 ~ https://spatialreference.org/ref/epsg/wgs-84/ Also, see https://datatracker.ietf.org/doc/html/rfc7946#section-4

Although not explicitly stated, it can be inferred that altitude must be greater than or equal to depth.

Units

The GeoJSON standard does not mandate any particular units for the depth and height, but meters is a common reference and matches well with typical geodesy tools.

Valid GeoJSON Examples

Example of a 3D bbox member with a depth of 100 meters:

   {
       "type": "FeatureCollection",
       "bbox": [100.0, 0.0, -100.0, 105.0, 1.0, 0.0],
       "features": [
       //...
       ]
   }

Example of a 3D bbox member with an altitude between 100 and 950 meters:

   {
       "type": "FeatureCollection",
       "bbox": [100.0, 0.0, 100, 105.0, 1.0, 950],
       "features": [
       //...
       ]
   }

Example of a 3D bbox on features with a FeatureCollection that also has a bounding box:

{
    "type": "FeatureCollection",
    "bbox":  [-10, -10, -100, 10, 10, 950], // -167 to 950meters
         "features": [
             {
                 "type": "Feature",
                 "bbox": [-10.0, -10.0, -167, 10.0, 10.0, 0], // -167 to 0 meters
                 "geometry": {
                     ...
                 }
             },
             {
                 "type": "Feature",
                 "bbox": [-10.0, -10.0, 0, 10.0, 10.0, 800], // 0 to 800 meters
                 "geometry": {
                     ...
                 }
             },
             ...
         ]
}

Example of a 3D bbox that crosses the antimeridian:

{
    "type": "FeatureCollection",
    "bbox": [177.0, -20.0, 0, -178.0, -16.0, 25000], // 0 to 25,000 meters
         "features": [
             ...
         ]
}

Example Matcher Usage

expect([-10.0, -10.0, 0, 10.0, 10.0, 10000]).isValid3DBoundingBox()
expect([100.0, 0.0, -100.0, 105.0, 1.0, 0.0]).isValid3DBoundingBox()
expect([177.0, -20.0, -250, -178.0, -16.0, 300]).isValid3DBoundingBox() // Crosses antimeridian and spans 5 degrees, -250 to 300 meters

expect([-10.0, -10.0, 0, 10.0, 100.0, 0]).not.isValid3DBoundingBox() // North out of bounds
expect([100.0, 0.0, 105.0, 1.0]).not.isValid3DCoordinate() // 2D bounding box
expect({ bbox: [-10.0, -10.0, 0, 10.0, 10.0, 0] }).not.isValid3DCoordinate() // Object instead of bbox array

Passing Tests

Values in Range

Values at Edge Cases

Failing Tests

Bbox input not an array

Incorrect number of array elements

Coordinates out of range

Illogical BBox

BBox has non-numeric values

BBox values are arrays of numbers

[[-20], [10], [0], [-10], [20], [0]]

M-Scott-Lassiter commented 2 years ago

:tada: This issue has been resolved in version 1.0.0-beta.4 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

M-Scott-Lassiter commented 2 years ago

:tada: This issue has been resolved in version 1.0.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket: