diff --git a/.github/remark.yaml b/.github/remark.yaml index b0dd538..331dda5 100644 --- a/.github/remark.yaml +++ b/.github/remark.yaml @@ -1,4 +1,6 @@ plugins: +# Support Github-flavored Markdown + - remark-gfm # Check links - validate-links # Apply some recommended defaults for consistency @@ -37,7 +39,7 @@ plugins: - - remark-lint-unordered-list-marker-style - '-' - - remark-lint-list-item-indent - - space + - one # Tables - remark-lint-table-pipes - remark-lint-no-literal-urls \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3838a69..980887d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), @@ -6,16 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Added +## [v2.0.0] - 2024-08-21 ### Changed -- Required properties of type `string` require a minimum length of `1`. - -### Deprecated +- Updated to "Pilot" maturity +- Required properties of type `string` require a minimum length of `1` +- `pc:schemas` is no longer required ### Removed +- `pc:encoding` because there is an encoding key in the asset + ### Fixed - Fixed JSON Schema, which allowed pointcloud fields in the top-level of Collections @@ -24,5 +27,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Initial independent release, see [previous history](https://github.com/radiantearth/stac-spec/commits/v1.0.0-rc.1/extensions/pointcloud) -[Unreleased]: +[Unreleased]: +[v2.0.0]: [v1.0.0]: diff --git a/README.md b/README.md index 44eb758..b0b2fda 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ LiDAR or coincidence-matched imagery. | ------------- | --------------------------------- | ----------- | | pc:count | integer | **REQUIRED.** The number of points in the Item. | | pc:type | string | **REQUIRED.** Phenomenology type for the point cloud. Possible valid values might include `lidar`, `eopc`, `radar`, `sonar`, or `other` | -| pc:schemas | [[Schema Object](#schema-object)] | A sequential array of Items that define the dimensions and their types. | +| pc:schemas | \[[Schema Object](#schema-object)\] | A sequential array of Items that define the dimensions and their types. | | pc:density | number | Number of points per square unit area. | -| pc:statistics | [[Stats Object](#stats-object)] | A sequential array of Items mapping to `pc:schemas` defines per-channel statistics. | +| pc:statistics | \[[Stats Object](#stats-object)\] | A sequential array of Items mapping to `pc:schemas` defines per-channel statistics. | ### Schema Object @@ -71,11 +71,13 @@ To run tests locally, you'll need `npm`, which is a standard part of any [node.j First you'll need to install everything with npm once. Just navigate to the root of this repository and on your command line run: + ```bash npm install ``` Then to check markdown formatting and test the examples against the JSON schema, you can run: + ```bash npm test ``` @@ -83,6 +85,7 @@ npm test This will spit out the same texts that you see online, and you can then go and fix your markdown or examples. If the tests reveal formatting problems with the examples, you can fix them with: + ```bash npm run format-examples ``` diff --git a/examples/example-autzen-on-asset.json b/examples/example-autzen-on-asset.json new file mode 100644 index 0000000..7515290 --- /dev/null +++ b/examples/example-autzen-on-asset.json @@ -0,0 +1,381 @@ +{ + "assets": { + "data": { + "href": "https://github.com/PDAL/data/raw/master/autzen/autzen-classified.copc.laz", + "pc:count": 10653336, + "pc:density": 4.664071112, + "pc:schemas": [ + { + "name": "X", + "size": 8, + "type": "floating" + }, + { + "name": "Y", + "size": 8, + "type": "floating" + }, + { + "name": "Z", + "size": 8, + "type": "floating" + }, + { + "name": "Intensity", + "size": 2, + "type": "unsigned" + }, + { + "name": "ReturnNumber", + "size": 1, + "type": "unsigned" + }, + { + "name": "NumberOfReturns", + "size": 1, + "type": "unsigned" + }, + { + "name": "ScanDirectionFlag", + "size": 1, + "type": "unsigned" + }, + { + "name": "EdgeOfFlightLine", + "size": 1, + "type": "unsigned" + }, + { + "name": "Classification", + "size": 1, + "type": "unsigned" + }, + { + "name": "ScanAngleRank", + "size": 4, + "type": "floating" + }, + { + "name": "UserData", + "size": 1, + "type": "unsigned" + }, + { + "name": "PointSourceId", + "size": 2, + "type": "unsigned" + }, + { + "name": "GpsTime", + "size": 8, + "type": "floating" + }, + { + "name": "ScanChannel", + "size": 1, + "type": "unsigned" + }, + { + "name": "ClassFlags", + "size": 1, + "type": "unsigned" + }, + { + "name": "Red", + "size": 2, + "type": "unsigned" + }, + { + "name": "Green", + "size": 2, + "type": "unsigned" + }, + { + "name": "Blue", + "size": 2, + "type": "unsigned" + } + ], + "pc:statistics": [ + { + "average": 637294.1783, + "count": 10653336, + "maximum": 639003.73, + "minimum": 635577.79, + "name": "X", + "position": 0, + "stddev": 948.0423248, + "variance": 898784.2496 + }, + { + "average": 851247.6953, + "count": 10653336, + "maximum": 853537.66, + "minimum": 848882.15, + "name": "Y", + "position": 1, + "stddev": 1296.496683, + "variance": 1680903.65 + }, + { + "average": 434.1025002, + "count": 10653336, + "maximum": 615.26, + "minimum": 406.14, + "name": "Z", + "position": 2, + "stddev": 24.67860061, + "variance": 609.033328 + }, + { + "average": 19749.74032, + "count": 10653336, + "maximum": 65024, + "minimum": 0, + "name": "Intensity", + "position": 3, + "stddev": 16031.7912, + "variance": 257018329 + }, + { + "average": 1.17801438, + "count": 10653336, + "maximum": 4, + "minimum": 1, + "name": "ReturnNumber", + "position": 4, + "stddev": 0.4653415116, + "variance": 0.2165427224 + }, + { + "average": 1.358579791, + "count": 10653336, + "maximum": 4, + "minimum": 1, + "name": "NumberOfReturns", + "position": 5, + "stddev": 0.6656062384, + "variance": 0.4430316645 + }, + { + "average": 0.4989654884, + "count": 10653336, + "maximum": 1, + "minimum": 0, + "name": "ScanDirectionFlag", + "position": 6, + "stddev": 0.4999989533, + "variance": 0.2499989533 + }, + { + "average": 0, + "count": 10653336, + "maximum": 0, + "minimum": 0, + "name": "EdgeOfFlightLine", + "position": 7, + "stddev": 0, + "variance": 0 + }, + { + "average": 3.225117841, + "count": 10653336, + "maximum": 77, + "minimum": 0, + "name": "Classification", + "position": 8, + "stddev": 3.900433841, + "variance": 15.21338415 + }, + { + "average": -0.8120596266, + "count": 10653336, + "maximum": 19.99799919, + "minimum": -21, + "name": "ScanAngleRank", + "position": 9, + "stddev": 8.484304657, + "variance": 71.98342551 + }, + { + "average": 126.4052859, + "count": 10653336, + "maximum": 156, + "minimum": 115, + "name": "UserData", + "position": 10, + "stddev": 3.832798034, + "variance": 14.69034077 + }, + { + "average": 7329.903705, + "count": 10653336, + "maximum": 7334, + "minimum": 7326, + "name": "PointSourceId", + "position": 11, + "stddev": 2.149008526, + "variance": 4.618237646 + }, + { + "average": 27984.58978, + "count": 10653336, + "maximum": 63744, + "minimum": 2048, + "name": "Red", + "position": 12, + "stddev": 12894.81504, + "variance": 166276254.9 + }, + { + "average": 33420.41971, + "count": 10653336, + "maximum": 65024, + "minimum": 8704, + "name": "Green", + "position": 13, + "stddev": 10300.57025, + "variance": 106101747.4 + }, + { + "average": 33500.94035, + "count": 10653336, + "maximum": 63488, + "minimum": 18688, + "name": "Blue", + "position": 14, + "stddev": 8035.931367, + "variance": 64576192.94 + }, + { + "average": 247608.4011, + "count": 10653336, + "maximum": 249783.7031, + "minimum": 245369.8966, + "name": "GpsTime", + "position": 15, + "stddev": 1176.138454, + "variance": 1383301.664 + }, + { + "average": 0, + "count": 10653336, + "maximum": 0, + "minimum": 0, + "name": "ScanChannel", + "position": 16, + "stddev": 0, + "variance": 0 + }, + { + "average": 0.00571651922, + "count": 10653336, + "maximum": 2, + "minimum": 0, + "name": "ClassFlags", + "position": 17, + "stddev": 0.1067724727, + "variance": 0.01140036092 + } + ], + "pc:type": "lidar" + } + }, + "bbox": [ + -123.075535, + 44.04971459, + 406.14, + -123.0619527, + 44.06277605, + 615.26 + ], + "geometry": { + "coordinates": [ + [ + [ + -123.0629545825049, + 44.04938482313105 + ], + [ + -123.06181648769092, + 44.050914907404575 + ], + [ + -123.06249957584173, + 44.062720268425046 + ], + [ + -123.0721268140624, + 44.062503129369155 + ], + [ + -123.07283313916145, + 44.06291701279292 + ], + [ + -123.07523995384831, + 44.06286258591127 + ], + [ + -123.07499706515674, + 44.05728007061464 + ], + [ + -123.0756659740761, + 44.05683508790114 + ], + [ + -123.07518580339425, + 44.04975347271782 + ], + [ + -123.07277952150108, + 44.049807898349336 + ], + [ + -123.0720733531486, + 44.049394013909115 + ], + [ + -123.06400444297464, + 44.049791019719 + ], + [ + -123.0629545825049, + 44.04938482313105 + ] + ] + ], + "type": "Polygon" + }, + "id": "autzen-classified.copc.laz", + "links": [ + { + "href": "./example-autzen.json", + "rel": "self" + }, + { + "href": "https://github.com/PDAL/data/blob/master/LICENSE", + "rel": "license" + } + ], + "properties": { + "datetime": "0001-01-02T00:00:00Z", + "providers": [ + { + "description": "United States Geological Survey", + "name": "USGS", + "roles": [ + "producer" + ], + "url": "https://www.usgs.gov" + } + ], + "title": "USGS 3DEP LiDAR" + }, + "stac_extensions": [ + "https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json" + ], + "stac_version": "1.0.0", + "type": "Feature" +} \ No newline at end of file diff --git a/examples/example-autzen.json b/examples/example-autzen.json index be33e91..1eef3be 100644 --- a/examples/example-autzen.json +++ b/examples/example-autzen.json @@ -374,7 +374,7 @@ "title": "USGS 3DEP LiDAR" }, "stac_extensions": [ - "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json" + "https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json" ], "stac_version": "1.0.0", "type": "Feature" diff --git a/examples/example-collection.json b/examples/example-collection.json new file mode 100644 index 0000000..4d524b5 --- /dev/null +++ b/examples/example-collection.json @@ -0,0 +1,130 @@ +{ + "type": "Collection", + "stac_version": "1.0.0", + "stac_extensions": [ + "https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json" + ], + "id": "example-colleciton", + "description": "An example collection to demonstrate use of item assets", + "license": "other", + "extent": { + "spatial": { + "bbox": [ + [ + -123.075535, + 44.04971459, + 406.14, + -123.0619527, + 44.06277605, + 615.26 + ] + ] + }, + "temporal": { + "interval": [ + [ + null, + null + ] + ] + } + }, + "links": [], + "item_assets": { + "data": { + "pc:schemas": [ + { + "name": "X", + "size": 8, + "type": "floating" + }, + { + "name": "Y", + "size": 8, + "type": "floating" + }, + { + "name": "Z", + "size": 8, + "type": "floating" + }, + { + "name": "Intensity", + "size": 2, + "type": "unsigned" + }, + { + "name": "ReturnNumber", + "size": 1, + "type": "unsigned" + }, + { + "name": "NumberOfReturns", + "size": 1, + "type": "unsigned" + }, + { + "name": "ScanDirectionFlag", + "size": 1, + "type": "unsigned" + }, + { + "name": "EdgeOfFlightLine", + "size": 1, + "type": "unsigned" + }, + { + "name": "Classification", + "size": 1, + "type": "unsigned" + }, + { + "name": "ScanAngleRank", + "size": 4, + "type": "floating" + }, + { + "name": "UserData", + "size": 1, + "type": "unsigned" + }, + { + "name": "PointSourceId", + "size": 2, + "type": "unsigned" + }, + { + "name": "GpsTime", + "size": 8, + "type": "floating" + }, + { + "name": "ScanChannel", + "size": 1, + "type": "unsigned" + }, + { + "name": "ClassFlags", + "size": 1, + "type": "unsigned" + }, + { + "name": "Red", + "size": 2, + "type": "unsigned" + }, + { + "name": "Green", + "size": 2, + "type": "unsigned" + }, + { + "name": "Blue", + "size": 2, + "type": "unsigned" + } + ], + "pc:type": "lidar" + } + } +} \ No newline at end of file diff --git a/json-schema/schema.json b/json-schema/schema.json index 544b11e..d6199dd 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -1,93 +1,145 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json#", + "$id": "https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json#", "title": "Point Cloud Extension", - "description": "STAC Point Cloud Extension for STAC Items and STAC Collections.", - "oneOf": [ + "description": "STAC Point Cloud Extension for STAC Items and Collections.", + "type": "object", + "required": [ + "stac_extensions", + "type" + ], + "properties": { + "stac_extensions": { + "type": "array", + "contains": { + "const": "https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json" + } + } + }, + "allOf": [ { - "$comment": "This is the schema for STAC Items.", - "allOf": [ - { - "type": "object", - "required": [ - "type", - "properties", - "assets" - ], - "properties": { - "type": { - "const": "Feature" - }, + "$comment": "Item", + "if": { + "properties": { + "type": { + "const": "Feature" + } + } + }, + "then": { + "allOf": [ + { "properties": { - "allOf": [ - { - "$comment": "Require fields here for item properties.", - "required": [ - "pc:count", - "pc:type" - ] - }, - { - "$ref": "#/definitions/fields" - } - ] - }, - "assets": { - "type": "object", - "additionalProperties": { + "properties": { "$ref": "#/definitions/fields" } } + }, + { + "$ref": "#/definitions/validate_assets" } - }, - { - "$ref": "#/definitions/stac_extensions" - } - ] + ], + "anyOf": [ + { + "required": [ + "properties" + ], + "properties": { + "properties": { + "$ref": "#/definitions/require_fields" + } + } + }, + { + "$ref": "#/definitions/require_assets" + } + ] + } }, { - "$comment": "This is the schema for STAC Collections.", - "allOf": [ - { - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "const": "Collection" - }, - "assets": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/fields" + "$comment": "Collections", + "if": { + "properties": { + "type": { + "const": "Collection" + } + } + }, + "then": { + "allOf": [ + { + "$ref": "#/definitions/validate_assets" + }, + { + "properties": { + "item_assets": { + "additionalProperties": { + "$ref": "#/definitions/fields" + } } - }, - "item_assets": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/fields" + } + } + ], + "anyOf": [ + { + "$ref": "#/definitions/require_assets" + }, + { + "required": [ + "item_assets" + ], + "properties": { + "item_assets": { + "$ref": "#/definitions/asset_contains" + } + } + }, + { + "required": [ + "summaries" + ], + "properties": { + "summaries": { + "$ref": "#/definitions/require_fields" } } } - }, - { - "$ref": "#/definitions/stac_extensions" - } - ] + ] + } } ], "definitions": { - "stac_extensions": { - "type": "object", + "require_fields": { "required": [ - "stac_extensions" + "pc:count", + "pc:type" + ] + }, + "require_assets": { + "required": [ + "assets" ], "properties": { - "stac_extensions": { - "type": "array", - "contains": { - "const": "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json" + "assets": { + "$ref": "#/definitions/asset_contains" + } + } + }, + "validate_assets": { + "properties": { + "assets": { + "additionalProperties": { + "$ref": "#/definitions/fields" + } + } + } + }, + "asset_contains": { + "type": "object", + "not": { + "additionalProperties": { + "not": { + "$ref": "#/definitions/fields" } } } @@ -96,12 +148,10 @@ "type": "object", "properties": { "pc:count": { - "type": "integer", - "minimum": 0 + "$ref": "#/definitions/pc:count" }, "pc:type": { - "type": "string", - "minLength": 1 + "$ref": "#/definitions/pc:type" }, "pc:schemas": { "type": "array", @@ -111,8 +161,7 @@ } }, "pc:density": { - "type": "number", - "minimum": 0 + "$ref": "#/definitions/pc:density" }, "pc:statistics": { "type": "array", @@ -127,7 +176,39 @@ }, "additionalProperties": false }, + "pc:count": { + "title": "The number of points", + "type": "integer", + "minimum": 0 + }, + "pc:type": { + "title": "Phenomenology type for the point cloud", + "type": "string", + "minLength": 1 + }, + "pc:schemas": { + "title": "A sequential array of Items that define the dimensions and their types", + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "pc:density": { + "title": "Number of points per square unit area", + "type": "number", + "minimum": 0 + }, + "pc:statistics": { + "title": "A sequential array of Items mapping to pc:schemas defines per-channel statistics", + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/stats" + } + }, "schema": { + "title": "A sequential array of Items that define the dimensions or channels of the point cloud, their types, and their sizes (in full bytes)", "type": "object", "required": [ "name", @@ -153,6 +234,7 @@ } }, "stats": { + "title": "A sequential array of Items mapping to pc:schemas defines per-channel statistics", "type": "object", "minProperties": 2, "required": [ diff --git a/package.json b/package.json index 496ebef..dd0c152 100644 --- a/package.json +++ b/package.json @@ -4,17 +4,18 @@ "scripts": { "test": "npm run check-markdown && npm run check-examples", "check-markdown": "remark . -f -r .github/remark.yaml", - "check-examples": "stac-node-validator . --lint --verbose --schemaMap https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json=./json-schema/schema.json", - "format-examples": "stac-node-validator . --format --schemaMap https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json=./json-schema/schema.json" + "check-examples": "stac-node-validator . --lint --verbose --schemaMap https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json=./json-schema/schema.json", + "format-examples": "stac-node-validator . --format --schemaMap https://stac-extensions.github.io/pointcloud/v2.0.0/schema.json=./json-schema/schema.json" }, "dependencies": { - "remark-cli": "^8.0.0", - "remark-lint": "^7.0.0", - "remark-lint-no-html": "^2.0.0", - "remark-preset-lint-consistent": "^3.0.0", - "remark-preset-lint-markdown-style-guide": "^3.0.0", - "remark-preset-lint-recommended": "^4.0.0", - "remark-validate-links": "^10.0.0", + "remark-cli": "^12.0.0", + "remark-gfm": "^4.0.0", + "remark-lint": "^10.0.0", + "remark-lint-no-html": "^4.0.0", + "remark-preset-lint-consistent": "^6.0.0", + "remark-preset-lint-markdown-style-guide": "^6.0.0", + "remark-preset-lint-recommended": "^7.0.0", + "remark-validate-links": "^13.0.0", "stac-node-validator": "^1.0.0" } -} +} \ No newline at end of file