@sakuzu/maplibre-gl-draw 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/LICENSE +661 -0
- package/README.ja.md +248 -0
- package/README.md +255 -0
- package/THIRD_PARTY_NOTICES.md +275 -0
- package/dist/api/api.d.ts +1259 -0
- package/dist/api/api.js +86 -0
- package/dist/api/context.d.ts +173 -0
- package/dist/api/context.js +193 -0
- package/dist/api/display-api.d.ts +1 -0
- package/dist/api/display-api.js +23 -0
- package/dist/api/event-api.d.ts +13 -0
- package/dist/api/event-api.js +17 -0
- package/dist/api/extension-api.d.ts +46 -0
- package/dist/api/extension-api.js +85 -0
- package/dist/api/feature-api.d.ts +11 -0
- package/dist/api/feature-api.js +101 -0
- package/dist/api/geometry/apply.d.ts +51 -0
- package/dist/api/geometry/apply.js +114 -0
- package/dist/api/geometry/boolean.d.ts +28 -0
- package/dist/api/geometry/boolean.js +65 -0
- package/dist/api/geometry/buffer.d.ts +11 -0
- package/dist/api/geometry/buffer.js +105 -0
- package/dist/api/geometry/split.d.ts +16 -0
- package/dist/api/geometry/split.js +75 -0
- package/dist/api/geometry/targets.d.ts +76 -0
- package/dist/api/geometry/targets.js +158 -0
- package/dist/api/geometry/types.d.ts +31 -0
- package/dist/api/geometry/types.js +3 -0
- package/dist/api/geometry-operations.d.ts +162 -0
- package/dist/api/geometry-operations.js +94 -0
- package/dist/api/group-api.d.ts +10 -0
- package/dist/api/group-api.js +78 -0
- package/dist/api/import-export/constants.d.ts +29 -0
- package/dist/api/import-export/constants.js +40 -0
- package/dist/api/import-export/embedded-file.d.ts +13 -0
- package/dist/api/import-export/embedded-file.js +31 -0
- package/dist/api/import-export/file-name.d.ts +10 -0
- package/dist/api/import-export/file-name.js +20 -0
- package/dist/api/import-export/format-detection.d.ts +12 -0
- package/dist/api/import-export/format-detection.js +29 -0
- package/dist/api/import-export/geojson-export.d.ts +19 -0
- package/dist/api/import-export/geojson-export.js +262 -0
- package/dist/api/import-export/geojson-import.d.ts +34 -0
- package/dist/api/import-export/geojson-import.js +538 -0
- package/dist/api/import-export/geometry-validation.d.ts +20 -0
- package/dist/api/import-export/geometry-validation.js +107 -0
- package/dist/api/import-export/image-import.d.ts +12 -0
- package/dist/api/import-export/image-import.js +53 -0
- package/dist/api/import-export/index.d.ts +9 -0
- package/dist/api/import-export/index.js +107 -0
- package/dist/api/import-export/native-format.d.ts +15 -0
- package/dist/api/import-export/native-format.js +126 -0
- package/dist/api/import-export/native-validation.d.ts +28 -0
- package/dist/api/import-export/native-validation.js +212 -0
- package/dist/api/import-export/own-property.d.ts +10 -0
- package/dist/api/import-export/own-property.js +19 -0
- package/dist/api/import-export/style-validation.d.ts +27 -0
- package/dist/api/import-export/style-validation.js +49 -0
- package/dist/api/import-export/types.d.ts +26 -0
- package/dist/api/import-export/types.js +3 -0
- package/dist/api/index.d.ts +15 -0
- package/dist/api/index.js +3 -0
- package/dist/api/input-api.d.ts +158 -0
- package/dist/api/input-api.js +144 -0
- package/dist/api/instance-api.d.ts +38 -0
- package/dist/api/instance-api.js +136 -0
- package/dist/api/layer-api.d.ts +12 -0
- package/dist/api/layer-api.js +62 -0
- package/dist/api/selection-api.d.ts +7 -0
- package/dist/api/selection-api.js +78 -0
- package/dist/api/snapping-api.d.ts +125 -0
- package/dist/api/snapping-api.js +50 -0
- package/dist/api/topology-api.d.ts +30 -0
- package/dist/api/topology-api.js +16 -0
- package/dist/api/tracing-api.d.ts +31 -0
- package/dist/api/tracing-api.js +16 -0
- package/dist/dispatcher/hit-test/box-strategies.d.ts +19 -0
- package/dist/dispatcher/hit-test/box-strategies.js +275 -0
- package/dist/dispatcher/hit-test/box-strategy.d.ts +59 -0
- package/dist/dispatcher/hit-test/box-strategy.js +37 -0
- package/dist/dispatcher/hit-test/globe-shape.d.ts +46 -0
- package/dist/dispatcher/hit-test/globe-shape.js +70 -0
- package/dist/dispatcher/hit-test/index.d.ts +14 -0
- package/dist/dispatcher/hit-test/index.js +9 -0
- package/dist/dispatcher/hit-test/local-frame.d.ts +77 -0
- package/dist/dispatcher/hit-test/local-frame.js +112 -0
- package/dist/dispatcher/hit-test/segment-grid.d.ts +32 -0
- package/dist/dispatcher/hit-test/segment-grid.js +79 -0
- package/dist/dispatcher/hit-test/service.d.ts +120 -0
- package/dist/dispatcher/hit-test/service.js +333 -0
- package/dist/dispatcher/hit-test/strategies/base.d.ts +136 -0
- package/dist/dispatcher/hit-test/strategies/base.js +66 -0
- package/dist/dispatcher/hit-test/strategies/circle.d.ts +10 -0
- package/dist/dispatcher/hit-test/strategies/circle.js +56 -0
- package/dist/dispatcher/hit-test/strategies/image.d.ts +22 -0
- package/dist/dispatcher/hit-test/strategies/image.js +115 -0
- package/dist/dispatcher/hit-test/strategies/index.d.ts +11 -0
- package/dist/dispatcher/hit-test/strategies/index.js +10 -0
- package/dist/dispatcher/hit-test/strategies/line.d.ts +17 -0
- package/dist/dispatcher/hit-test/strategies/line.js +30 -0
- package/dist/dispatcher/hit-test/strategies/multi.d.ts +44 -0
- package/dist/dispatcher/hit-test/strategies/multi.js +141 -0
- package/dist/dispatcher/hit-test/strategies/point.d.ts +20 -0
- package/dist/dispatcher/hit-test/strategies/point.js +29 -0
- package/dist/dispatcher/hit-test/strategies/polygon.d.ts +52 -0
- package/dist/dispatcher/hit-test/strategies/polygon.js +138 -0
- package/dist/dispatcher/hit-test/topmost.d.ts +48 -0
- package/dist/dispatcher/hit-test/topmost.js +157 -0
- package/dist/dispatcher/hit-test/visibility-lookup.d.ts +23 -0
- package/dist/dispatcher/hit-test/visibility-lookup.js +40 -0
- package/dist/dispatcher/index.d.ts +15 -0
- package/dist/dispatcher/index.js +3 -0
- package/dist/dispatcher/input-router.d.ts +1 -0
- package/dist/dispatcher/input-router.js +288 -0
- package/dist/dispatcher/normalizer.d.ts +1 -0
- package/dist/dispatcher/normalizer.js +513 -0
- package/dist/dispatcher/types.d.ts +144 -0
- package/dist/dispatcher/types.js +15 -0
- package/dist/display/chunk-set.d.ts +24 -0
- package/dist/display/chunk-set.js +533 -0
- package/dist/display/chunk.d.ts +1 -0
- package/dist/display/chunk.js +104 -0
- package/dist/display/columnar/index.d.ts +12 -0
- package/dist/display/columnar/index.js +13 -0
- package/dist/display/columnar/prepare.d.ts +42 -0
- package/dist/display/columnar/prepare.js +116 -0
- package/dist/display/columnar/source.d.ts +1 -0
- package/dist/display/columnar/source.js +531 -0
- package/dist/display/columnar/table.d.ts +1 -0
- package/dist/display/columnar/table.js +471 -0
- package/dist/display/columnar/types.d.ts +223 -0
- package/dist/display/columnar/types.js +3 -0
- package/dist/display/dataset.d.ts +2 -0
- package/dist/display/dataset.js +891 -0
- package/dist/display/index.d.ts +13 -0
- package/dist/display/index.js +3 -0
- package/dist/display/interaction.d.ts +1 -0
- package/dist/display/interaction.js +90 -0
- package/dist/display/manager.d.ts +1 -0
- package/dist/display/manager.js +440 -0
- package/dist/display/packed-rtree.d.ts +1 -0
- package/dist/display/packed-rtree.js +244 -0
- package/dist/display/partition.d.ts +1 -0
- package/dist/display/partition.js +226 -0
- package/dist/display/provider.d.ts +1 -0
- package/dist/display/provider.js +342 -0
- package/dist/display/retained.d.ts +40 -0
- package/dist/display/retained.js +898 -0
- package/dist/display/selection.d.ts +13 -0
- package/dist/display/selection.js +226 -0
- package/dist/display/source.d.ts +1 -0
- package/dist/display/source.js +119 -0
- package/dist/display/spatial.d.ts +1 -0
- package/dist/display/spatial.js +71 -0
- package/dist/display/style.d.ts +1 -0
- package/dist/display/style.js +126 -0
- package/dist/display/thinning.d.ts +65 -0
- package/dist/display/thinning.js +910 -0
- package/dist/display/triangulation.d.ts +1 -0
- package/dist/display/triangulation.js +0 -0
- package/dist/display/types.d.ts +561 -0
- package/dist/display/types.js +43 -0
- package/dist/extension/feature-handler.d.ts +182 -0
- package/dist/extension/feature-handler.js +3 -0
- package/dist/extension/index.d.ts +9 -0
- package/dist/extension/index.js +3 -0
- package/dist/extension/renderers.d.ts +208 -0
- package/dist/extension/renderers.js +3 -0
- package/dist/geometry/angle.d.ts +47 -0
- package/dist/geometry/angle.js +44 -0
- package/dist/geometry/bbox.d.ts +48 -0
- package/dist/geometry/bbox.js +83 -0
- package/dist/geometry/boolean.d.ts +162 -0
- package/dist/geometry/boolean.js +331 -0
- package/dist/geometry/buffer.d.ts +72 -0
- package/dist/geometry/buffer.js +218 -0
- package/dist/geometry/circle.d.ts +55 -0
- package/dist/geometry/circle.js +107 -0
- package/dist/geometry/coords.d.ts +97 -0
- package/dist/geometry/coords.js +149 -0
- package/dist/geometry/distance.d.ts +79 -0
- package/dist/geometry/distance.js +111 -0
- package/dist/geometry/errors.d.ts +74 -0
- package/dist/geometry/errors.js +104 -0
- package/dist/geometry/index.d.ts +28 -0
- package/dist/geometry/index.js +38 -0
- package/dist/geometry/measure.d.ts +81 -0
- package/dist/geometry/measure.js +236 -0
- package/dist/geometry/predicates.d.ts +62 -0
- package/dist/geometry/predicates.js +132 -0
- package/dist/geometry/simplify.d.ts +74 -0
- package/dist/geometry/simplify.js +159 -0
- package/dist/geometry/split.d.ts +68 -0
- package/dist/geometry/split.js +430 -0
- package/dist/geometry/types.d.ts +95 -0
- package/dist/geometry/types.js +3 -0
- package/dist/geometry/units.d.ts +35 -0
- package/dist/geometry/units.js +41 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +20 -0
- package/dist/maplibre-gl-draw.d.ts +47 -0
- package/dist/maplibre-gl-draw.js +407 -0
- package/dist/messages.d.ts +64 -0
- package/dist/messages.js +36 -0
- package/dist/modes/cursor.d.ts +1 -0
- package/dist/modes/cursor.js +72 -0
- package/dist/modes/draw/circle.d.ts +1 -0
- package/dist/modes/draw/circle.js +222 -0
- package/dist/modes/draw/commit-layer.d.ts +26 -0
- package/dist/modes/draw/commit-layer.js +31 -0
- package/dist/modes/draw/freehand.d.ts +1 -0
- package/dist/modes/draw/freehand.js +264 -0
- package/dist/modes/draw/image.d.ts +1 -0
- package/dist/modes/draw/image.js +60 -0
- package/dist/modes/draw/index.d.ts +9 -0
- package/dist/modes/draw/index.js +11 -0
- package/dist/modes/draw/line.d.ts +1 -0
- package/dist/modes/draw/line.js +363 -0
- package/dist/modes/draw/point.d.ts +1 -0
- package/dist/modes/draw/point.js +87 -0
- package/dist/modes/draw/polygon.d.ts +1 -0
- package/dist/modes/draw/polygon.js +378 -0
- package/dist/modes/draw/trace-support.d.ts +79 -0
- package/dist/modes/draw/trace-support.js +161 -0
- package/dist/modes/handler.d.ts +285 -0
- package/dist/modes/handler.js +3 -0
- package/dist/modes/index.d.ts +7 -0
- package/dist/modes/index.js +3 -0
- package/dist/modes/manager.d.ts +15 -0
- package/dist/modes/manager.js +196 -0
- package/dist/modes/select/box-selection.d.ts +52 -0
- package/dist/modes/select/box-selection.js +140 -0
- package/dist/modes/select/click-handler.d.ts +32 -0
- package/dist/modes/select/click-handler.js +166 -0
- package/dist/modes/select/cursor-handler.d.ts +15 -0
- package/dist/modes/select/cursor-handler.js +59 -0
- package/dist/modes/select/drag/auxiliary.d.ts +26 -0
- package/dist/modes/select/drag/auxiliary.js +56 -0
- package/dist/modes/select/drag/intermediate-writes.d.ts +1 -0
- package/dist/modes/select/drag/intermediate-writes.js +171 -0
- package/dist/modes/select/drag/move.d.ts +24 -0
- package/dist/modes/select/drag/move.js +59 -0
- package/dist/modes/select/drag/operation.d.ts +30 -0
- package/dist/modes/select/drag/operation.js +18 -0
- package/dist/modes/select/drag/radius.d.ts +15 -0
- package/dist/modes/select/drag/radius.js +49 -0
- package/dist/modes/select/drag/transform.d.ts +17 -0
- package/dist/modes/select/drag/transform.js +155 -0
- package/dist/modes/select/drag/vertex.d.ts +17 -0
- package/dist/modes/select/drag/vertex.js +163 -0
- package/dist/modes/select/drag-handler.d.ts +1 -0
- package/dist/modes/select/drag-handler.js +254 -0
- package/dist/modes/select/hit-helpers.d.ts +40 -0
- package/dist/modes/select/hit-helpers.js +51 -0
- package/dist/modes/select/mode.d.ts +1 -0
- package/dist/modes/select/mode.js +397 -0
- package/dist/modes/select/shortcut-handler.d.ts +40 -0
- package/dist/modes/select/shortcut-handler.js +128 -0
- package/dist/operations/index.d.ts +9 -0
- package/dist/operations/index.js +3 -0
- package/dist/operations/layer-operations.d.ts +1 -0
- package/dist/operations/layer-operations.js +350 -0
- package/dist/operations/resize.d.ts +71 -0
- package/dist/operations/resize.js +252 -0
- package/dist/operations/rotate.d.ts +17 -0
- package/dist/operations/rotate.js +166 -0
- package/dist/operations/selection-operations.d.ts +20 -0
- package/dist/operations/selection-operations.js +159 -0
- package/dist/operations/shared-vertex.d.ts +1 -0
- package/dist/operations/shared-vertex.js +210 -0
- package/dist/operations/trace-graph.d.ts +96 -0
- package/dist/operations/trace-graph.js +283 -0
- package/dist/operations/vertex.d.ts +1 -0
- package/dist/operations/vertex.js +538 -0
- package/dist/plugins/index.d.ts +10 -0
- package/dist/plugins/index.js +3 -0
- package/dist/plugins/mutation-hooks.d.ts +28 -0
- package/dist/plugins/mutation-hooks.js +84 -0
- package/dist/plugins/plugin-context.d.ts +1 -0
- package/dist/plugins/plugin-context.js +367 -0
- package/dist/plugins/plugin-manager.d.ts +103 -0
- package/dist/plugins/plugin-manager.js +316 -0
- package/dist/plugins/plugin.d.ts +529 -0
- package/dist/plugins/plugin.js +3 -0
- package/dist/shared/config/constants.d.ts +66 -0
- package/dist/shared/config/constants.js +60 -0
- package/dist/shared/config/feature-style.d.ts +155 -0
- package/dist/shared/config/feature-style.js +154 -0
- package/dist/shared/config/index.d.ts +17 -0
- package/dist/shared/config/index.js +8 -0
- package/dist/shared/config/rendering.d.ts +107 -0
- package/dist/shared/config/rendering.js +33 -0
- package/dist/shared/config/selection-highlight.d.ts +29 -0
- package/dist/shared/config/selection-highlight.js +35 -0
- package/dist/shared/config/selection.d.ts +273 -0
- package/dist/shared/config/selection.js +266 -0
- package/dist/shared/config/topology.d.ts +33 -0
- package/dist/shared/config/topology.js +17 -0
- package/dist/shared/config/trace.d.ts +40 -0
- package/dist/shared/config/trace.js +17 -0
- package/dist/shared/math/angle.d.ts +21 -0
- package/dist/shared/math/angle.js +34 -0
- package/dist/shared/math/circle.d.ts +6 -0
- package/dist/shared/math/circle.js +10 -0
- package/dist/shared/math/constants.d.ts +48 -0
- package/dist/shared/math/constants.js +59 -0
- package/dist/shared/math/distance.d.ts +78 -0
- package/dist/shared/math/distance.js +147 -0
- package/dist/shared/math/globe-subdivision.d.ts +62 -0
- package/dist/shared/math/globe-subdivision.js +99 -0
- package/dist/shared/math/index.d.ts +17 -0
- package/dist/shared/math/index.js +21 -0
- package/dist/shared/math/intersection.d.ts +63 -0
- package/dist/shared/math/intersection.js +236 -0
- package/dist/shared/math/longitude.d.ts +20 -0
- package/dist/shared/math/longitude.js +31 -0
- package/dist/shared/math/mercator-plane.d.ts +27 -0
- package/dist/shared/math/mercator-plane.js +26 -0
- package/dist/shared/math/obb.d.ts +65 -0
- package/dist/shared/math/obb.js +107 -0
- package/dist/shared/math/rotation.d.ts +93 -0
- package/dist/shared/math/rotation.js +186 -0
- package/dist/shared/math/segment-grid.d.ts +69 -0
- package/dist/shared/math/segment-grid.js +159 -0
- package/dist/shared/math/transform.d.ts +140 -0
- package/dist/shared/math/transform.js +189 -0
- package/dist/shared/types/events.d.ts +128 -0
- package/dist/shared/types/events.js +3 -0
- package/dist/shared/types/model.d.ts +950 -0
- package/dist/shared/types/model.js +3 -0
- package/dist/shared/types/selection-box.d.ts +23 -0
- package/dist/shared/types/selection-box.js +3 -0
- package/dist/shared/types/style.d.ts +68 -0
- package/dist/shared/types/style.js +3 -0
- package/dist/shared/utils/color.d.ts +49 -0
- package/dist/shared/utils/color.js +180 -0
- package/dist/shared/utils/coordinates.d.ts +52 -0
- package/dist/shared/utils/coordinates.js +75 -0
- package/dist/shared/utils/embedded-image.d.ts +34 -0
- package/dist/shared/utils/embedded-image.js +161 -0
- package/dist/shared/utils/event-emitter.d.ts +262 -0
- package/dist/shared/utils/event-emitter.js +44 -0
- package/dist/shared/utils/feature-bbox.d.ts +8 -0
- package/dist/shared/utils/feature-bbox.js +207 -0
- package/dist/shared/utils/feature-segments.d.ts +23 -0
- package/dist/shared/utils/feature-segments.js +179 -0
- package/dist/shared/utils/id.d.ts +1 -0
- package/dist/shared/utils/id.js +35 -0
- package/dist/shared/utils/image.d.ts +34 -0
- package/dist/shared/utils/image.js +106 -0
- package/dist/shared/utils/index.d.ts +15 -0
- package/dist/shared/utils/index.js +24 -0
- package/dist/shared/utils/map.d.ts +26 -0
- package/dist/shared/utils/map.js +35 -0
- package/dist/shared/utils/name-generator.d.ts +197 -0
- package/dist/shared/utils/name-generator.js +337 -0
- package/dist/shared/utils/pixel-ratio.d.ts +111 -0
- package/dist/shared/utils/pixel-ratio.js +85 -0
- package/dist/shared/utils/property.d.ts +88 -0
- package/dist/shared/utils/property.js +140 -0
- package/dist/shared/utils/vertex-ref.d.ts +23 -0
- package/dist/shared/utils/vertex-ref.js +20 -0
- package/dist/snapping/custom-targets.d.ts +1 -0
- package/dist/snapping/custom-targets.js +21 -0
- package/dist/snapping/geometry.d.ts +1 -0
- package/dist/snapping/geometry.js +61 -0
- package/dist/snapping/index.d.ts +14 -0
- package/dist/snapping/index.js +4 -0
- package/dist/snapping/indicator.d.ts +19 -0
- package/dist/snapping/indicator.js +145 -0
- package/dist/snapping/providers/display.d.ts +72 -0
- package/dist/snapping/providers/display.js +268 -0
- package/dist/snapping/providers/guide.d.ts +69 -0
- package/dist/snapping/providers/guide.js +187 -0
- package/dist/snapping/providers/intersection.d.ts +1 -0
- package/dist/snapping/providers/intersection.js +92 -0
- package/dist/snapping/providers/shared.d.ts +39 -0
- package/dist/snapping/providers/shared.js +146 -0
- package/dist/snapping/providers/store.d.ts +1 -0
- package/dist/snapping/providers/store.js +132 -0
- package/dist/snapping/service.d.ts +1 -0
- package/dist/snapping/service.js +272 -0
- package/dist/snapping/types.d.ts +267 -0
- package/dist/snapping/types.js +66 -0
- package/dist/store/change-merger.d.ts +1 -0
- package/dist/store/change-merger.js +102 -0
- package/dist/store/draw-store.d.ts +1 -0
- package/dist/store/draw-store.js +396 -0
- package/dist/store/event-bridge.d.ts +1 -0
- package/dist/store/event-bridge.js +161 -0
- package/dist/store/index.d.ts +12 -0
- package/dist/store/index.js +4 -0
- package/dist/store/local-visibility.d.ts +21 -0
- package/dist/store/local-visibility.js +27 -0
- package/dist/store/lock.d.ts +67 -0
- package/dist/store/lock.js +54 -0
- package/dist/store/memory/change-bus.d.ts +60 -0
- package/dist/store/memory/change-bus.js +232 -0
- package/dist/store/memory/file-store.d.ts +15 -0
- package/dist/store/memory/file-store.js +33 -0
- package/dist/store/memory/frozen.d.ts +21 -0
- package/dist/store/memory/frozen.js +51 -0
- package/dist/store/memory/ui-state.d.ts +51 -0
- package/dist/store/memory/ui-state.js +223 -0
- package/dist/store/memory.d.ts +26 -0
- package/dist/store/memory.js +708 -0
- package/dist/store/spatial/index.d.ts +6 -0
- package/dist/store/spatial/index.js +4 -0
- package/dist/store/spatial/spatial-index.d.ts +90 -0
- package/dist/store/spatial/spatial-index.js +148 -0
- package/dist/store/spatial/store-spatial-index.d.ts +60 -0
- package/dist/store/spatial/store-spatial-index.js +125 -0
- package/dist/store/store.d.ts +417 -0
- package/dist/store/store.js +3 -0
- package/dist/store/types.d.ts +8 -0
- package/dist/store/types.js +3 -0
- package/dist/store/writable-layer.d.ts +35 -0
- package/dist/store/writable-layer.js +20 -0
- package/dist/view/cache/buffer.d.ts +28 -0
- package/dist/view/cache/buffer.js +176 -0
- package/dist/view/cache/earcut.d.ts +1 -0
- package/dist/view/cache/earcut.js +122 -0
- package/dist/view/cache/style-rule.d.ts +1 -0
- package/dist/view/cache/style-rule.js +97 -0
- package/dist/view/cache/terrain-fill.d.ts +30 -0
- package/dist/view/cache/terrain-fill.js +60 -0
- package/dist/view/cache/texture.d.ts +14 -0
- package/dist/view/cache/texture.js +292 -0
- package/dist/view/coordinator.d.ts +27 -0
- package/dist/view/coordinator.js +72 -0
- package/dist/view/feature-companion.d.ts +173 -0
- package/dist/view/feature-companion.js +108 -0
- package/dist/view/globe-subdivision.d.ts +78 -0
- package/dist/view/globe-subdivision.js +128 -0
- package/dist/view/index.d.ts +47 -0
- package/dist/view/index.js +20 -0
- package/dist/view/layer/attach.d.ts +20 -0
- package/dist/view/layer/attach.js +47 -0
- package/dist/view/layer/blend.d.ts +57 -0
- package/dist/view/layer/blend.js +14 -0
- package/dist/view/layer/custom-layer.d.ts +1 -0
- package/dist/view/layer/custom-layer.js +509 -0
- package/dist/view/layer/depth-state.d.ts +14 -0
- package/dist/view/layer/depth-state.js +44 -0
- package/dist/view/layer/display-list.d.ts +1 -0
- package/dist/view/layer/display-list.js +111 -0
- package/dist/view/layer/drape-planner.d.ts +139 -0
- package/dist/view/layer/drape-planner.js +726 -0
- package/dist/view/layer/frame-render.d.ts +57 -0
- package/dist/view/layer/frame-render.js +209 -0
- package/dist/view/layer/frame-state.d.ts +147 -0
- package/dist/view/layer/frame-state.js +484 -0
- package/dist/view/layer/gl-state.d.ts +77 -0
- package/dist/view/layer/gl-state.js +132 -0
- package/dist/view/layer/index.d.ts +6 -0
- package/dist/view/layer/index.js +5 -0
- package/dist/view/layer/render-scope.d.ts +30 -0
- package/dist/view/layer/render-scope.js +28 -0
- package/dist/view/layer/render.d.ts +87 -0
- package/dist/view/layer/render.js +187 -0
- package/dist/view/layer/renderers.d.ts +81 -0
- package/dist/view/layer/renderers.js +142 -0
- package/dist/view/layer/slot-manager.d.ts +26 -0
- package/dist/view/layer/slot-manager.js +133 -0
- package/dist/view/layer/slots.d.ts +33 -0
- package/dist/view/layer/slots.js +50 -0
- package/dist/view/layer/store-retained-bbox.d.ts +36 -0
- package/dist/view/layer/store-retained-bbox.js +188 -0
- package/dist/view/layer/store-retained-chunk.d.ts +97 -0
- package/dist/view/layer/store-retained-chunk.js +94 -0
- package/dist/view/layer/store-retained-classify.d.ts +34 -0
- package/dist/view/layer/store-retained-classify.js +88 -0
- package/dist/view/layer/store-retained-collect.d.ts +24 -0
- package/dist/view/layer/store-retained-collect.js +121 -0
- package/dist/view/layer/store-retained-coord-patch.d.ts +119 -0
- package/dist/view/layer/store-retained-coord-patch.js +168 -0
- package/dist/view/layer/store-retained-immediate.d.ts +63 -0
- package/dist/view/layer/store-retained-immediate.js +49 -0
- package/dist/view/layer/store-retained-invalidation.d.ts +96 -0
- package/dist/view/layer/store-retained-invalidation.js +192 -0
- package/dist/view/layer/store-retained.d.ts +198 -0
- package/dist/view/layer/store-retained.js +430 -0
- package/dist/view/layer/terrain-resolver.d.ts +1 -0
- package/dist/view/layer/terrain-resolver.js +174 -0
- package/dist/view/renderers/batch-manager.d.ts +61 -0
- package/dist/view/renderers/batch-manager.js +718 -0
- package/dist/view/renderers/draw-factors.d.ts +60 -0
- package/dist/view/renderers/draw-factors.js +35 -0
- package/dist/view/renderers/drawer.d.ts +1 -0
- package/dist/view/renderers/drawer.js +346 -0
- package/dist/view/renderers/image.d.ts +1 -0
- package/dist/view/renderers/image.js +255 -0
- package/dist/view/renderers/line/dash.d.ts +31 -0
- package/dist/view/renderers/line/dash.js +152 -0
- package/dist/view/renderers/line/line-geometry.d.ts +39 -0
- package/dist/view/renderers/line/line-geometry.js +460 -0
- package/dist/view/renderers/line/line-gl.d.ts +1 -0
- package/dist/view/renderers/line/line-gl.js +236 -0
- package/dist/view/renderers/line/line-shader.d.ts +1 -0
- package/dist/view/renderers/line/line-shader.js +364 -0
- package/dist/view/renderers/line/line-types.d.ts +43 -0
- package/dist/view/renderers/line/line-types.js +3 -0
- package/dist/view/renderers/line/line-uniforms.d.ts +1 -0
- package/dist/view/renderers/line/line-uniforms.js +390 -0
- package/dist/view/renderers/line/sdf-line.d.ts +92 -0
- package/dist/view/renderers/line/sdf-line.js +567 -0
- package/dist/view/renderers/point/billboard-depth.d.ts +10 -0
- package/dist/view/renderers/point/billboard-depth.js +56 -0
- package/dist/view/renderers/point/point-instance.d.ts +124 -0
- package/dist/view/renderers/point/point-instance.js +738 -0
- package/dist/view/renderers/point/point-sdf.d.ts +58 -0
- package/dist/view/renderers/point/point-sdf.js +170 -0
- package/dist/view/renderers/point/point-shape.d.ts +99 -0
- package/dist/view/renderers/point/point-shape.js +504 -0
- package/dist/view/renderers/point/point-style.d.ts +1 -0
- package/dist/view/renderers/point/point-style.js +46 -0
- package/dist/view/renderers/polygon/batch.d.ts +26 -0
- package/dist/view/renderers/polygon/batch.js +336 -0
- package/dist/view/renderers/polygon/earcut-input.d.ts +37 -0
- package/dist/view/renderers/polygon/earcut-input.js +55 -0
- package/dist/view/renderers/polygon/earcut-sliced.d.ts +69 -0
- package/dist/view/renderers/polygon/earcut-sliced.js +960 -0
- package/dist/view/renderers/polygon/fill.d.ts +74 -0
- package/dist/view/renderers/polygon/fill.js +251 -0
- package/dist/view/renderers/polygon/sdf-polygon.d.ts +62 -0
- package/dist/view/renderers/polygon/sdf-polygon.js +919 -0
- package/dist/view/renderers/polygon/terrain-cull.d.ts +3 -0
- package/dist/view/renderers/polygon/terrain-cull.js +14 -0
- package/dist/view/renderers/polygon/triangulator.d.ts +41 -0
- package/dist/view/renderers/polygon/triangulator.js +3 -0
- package/dist/view/renderers/retained.d.ts +43 -0
- package/dist/view/renderers/retained.js +3 -0
- package/dist/view/renderers/stroke.d.ts +121 -0
- package/dist/view/renderers/stroke.js +621 -0
- package/dist/view/shaders/frame.d.ts +8 -0
- package/dist/view/shaders/frame.js +37 -0
- package/dist/view/shaders/helpers.d.ts +238 -0
- package/dist/view/shaders/helpers.js +611 -0
- package/dist/view/shaders/initializer.d.ts +27 -0
- package/dist/view/shaders/initializer.js +125 -0
- package/dist/view/shaders/projection.d.ts +123 -0
- package/dist/view/shaders/projection.js +299 -0
- package/dist/view/shaders/quad-grid.d.ts +77 -0
- package/dist/view/shaders/quad-grid.js +128 -0
- package/dist/view/shaders/quad.d.ts +189 -0
- package/dist/view/shaders/quad.js +582 -0
- package/dist/view/shaders/retained-origin.d.ts +50 -0
- package/dist/view/shaders/retained-origin.js +67 -0
- package/dist/view/shaders/terrain-shade.d.ts +23 -0
- package/dist/view/shaders/terrain-shade.js +93 -0
- package/dist/view/style-rule.d.ts +166 -0
- package/dist/view/style-rule.js +300 -0
- package/dist/view/terrain/anchor.d.ts +135 -0
- package/dist/view/terrain/anchor.js +226 -0
- package/dist/view/terrain/context.d.ts +132 -0
- package/dist/view/terrain/context.js +437 -0
- package/dist/view/terrain/dem-atlas.d.ts +97 -0
- package/dist/view/terrain/dem-atlas.js +534 -0
- package/dist/view/terrain/detect.d.ts +126 -0
- package/dist/view/terrain/detect.js +198 -0
- package/dist/view/terrain/drape/bin-store.d.ts +179 -0
- package/dist/view/terrain/drape/bin-store.js +529 -0
- package/dist/view/terrain/drape/binning.d.ts +259 -0
- package/dist/view/terrain/drape/binning.js +604 -0
- package/dist/view/terrain/drape/edge-constrain.d.ts +37 -0
- package/dist/view/terrain/drape/edge-constrain.js +175 -0
- package/dist/view/terrain/drape/geometry.d.ts +95 -0
- package/dist/view/terrain/drape/geometry.js +260 -0
- package/dist/view/terrain/drape/mesh.d.ts +50 -0
- package/dist/view/terrain/drape/mesh.js +86 -0
- package/dist/view/terrain/drape/pass.d.ts +122 -0
- package/dist/view/terrain/drape/pass.js +379 -0
- package/dist/view/terrain/drape/quad-glyphs.d.ts +64 -0
- package/dist/view/terrain/drape/quad-glyphs.js +117 -0
- package/dist/view/terrain/drape/quad.d.ts +249 -0
- package/dist/view/terrain/drape/quad.js +835 -0
- package/dist/view/terrain/drape/renderer.d.ts +184 -0
- package/dist/view/terrain/drape/renderer.js +706 -0
- package/dist/view/terrain/drape/shared.d.ts +80 -0
- package/dist/view/terrain/drape/shared.js +173 -0
- package/dist/view/terrain/drape/stitch.d.ts +155 -0
- package/dist/view/terrain/drape/stitch.js +228 -0
- package/dist/view/terrain/ground.d.ts +72 -0
- package/dist/view/terrain/ground.js +151 -0
- package/dist/view/terrain/metrics.d.ts +180 -0
- package/dist/view/terrain/metrics.js +231 -0
- package/dist/view/terrain/occlusion.d.ts +11 -0
- package/dist/view/terrain/occlusion.js +129 -0
- package/dist/view/terrain/polygon.d.ts +86 -0
- package/dist/view/terrain/polygon.js +301 -0
- package/dist/view/terrain/shade.d.ts +48 -0
- package/dist/view/terrain/shade.js +45 -0
- package/dist/view/terrain/state.d.ts +99 -0
- package/dist/view/terrain/state.js +186 -0
- package/dist/view/terrain/tessellation.d.ts +265 -0
- package/dist/view/terrain/tessellation.js +924 -0
- package/dist/view/terrain/tiling.d.ts +56 -0
- package/dist/view/terrain/tiling.js +155 -0
- package/dist/view/terrain/upstream-terrain.d.ts +82 -0
- package/dist/view/terrain/upstream-terrain.js +116 -0
- package/dist/view/ui/auxiliary-handles.d.ts +151 -0
- package/dist/view/ui/auxiliary-handles.js +22 -0
- package/dist/view/ui/bounds.d.ts +53 -0
- package/dist/view/ui/bounds.js +149 -0
- package/dist/view/ui/box-selection.d.ts +1 -0
- package/dist/view/ui/box-selection.js +83 -0
- package/dist/view/ui/handle-test.d.ts +1 -0
- package/dist/view/ui/handle-test.js +437 -0
- package/dist/view/ui/handle-thinning.d.ts +122 -0
- package/dist/view/ui/handle-thinning.js +430 -0
- package/dist/view/ui/handles.d.ts +25 -0
- package/dist/view/ui/handles.js +673 -0
- package/dist/view/ui/helper.d.ts +19 -0
- package/dist/view/ui/helper.js +76 -0
- package/dist/view/ui/index.d.ts +15 -0
- package/dist/view/ui/index.js +15 -0
- package/dist/view/ui/selection-scope.d.ts +25 -0
- package/dist/view/ui/selection-scope.js +34 -0
- package/dist/view/ui/selection-ui/bounding-box.d.ts +44 -0
- package/dist/view/ui/selection-ui/bounding-box.js +240 -0
- package/dist/view/ui/selection-ui/extension-registry.d.ts +76 -0
- package/dist/view/ui/selection-ui/extension-registry.js +78 -0
- package/dist/view/ui/selection-ui/index.d.ts +12 -0
- package/dist/view/ui/selection-ui/index.js +12 -0
- package/dist/view/ui/selection-ui/renderer.d.ts +29 -0
- package/dist/view/ui/selection-ui/renderer.js +227 -0
- package/dist/view/ui/selection-ui/types.d.ts +55 -0
- package/dist/view/ui/selection-ui/types.js +3 -0
- package/dist/view/ui/selection-ui-drawer.d.ts +52 -0
- package/dist/view/ui/selection-ui-drawer.js +329 -0
- package/dist/view/ui/tentative.d.ts +1 -0
- package/dist/view/ui/tentative.js +320 -0
- package/dist/view/viewport.d.ts +119 -0
- package/dist/view/viewport.js +254 -0
- package/package.json +113 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* Measurement
|
|
5
|
+
*
|
|
6
|
+
* The length is the sum of haversine distances, and the area is based on the spherical
|
|
7
|
+
* excess of a spherical polygon. The centroid and the representative point are computed
|
|
8
|
+
* on the lng/lat plane, assuming shapes of the scale of an edit.
|
|
9
|
+
*/
|
|
10
|
+
import { boundingBox } from './bbox.js';
|
|
11
|
+
import { normalizeArea } from './boolean.js';
|
|
12
|
+
import { toMultiPolygonCoordinates } from './coords.js';
|
|
13
|
+
import { haversineDistanceMeters } from './distance.js';
|
|
14
|
+
import { pointInPolygon } from './predicates.js';
|
|
15
|
+
import { EARTH_RADIUS_METERS, toRadians } from './units.js';
|
|
16
|
+
/**
|
|
17
|
+
* Returns the geodesic length of a path in meters.
|
|
18
|
+
*
|
|
19
|
+
* The sum of the {@link haversineDistanceMeters} of each section. For the perimeter of a
|
|
20
|
+
* polygon pass its closed ring.
|
|
21
|
+
*
|
|
22
|
+
* @param path The vertices `[lng, lat]` in degrees
|
|
23
|
+
* @returns The length in meters. 0 for fewer than 2 positions. NaN when a position is not
|
|
24
|
+
* finite
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { geodesicLength } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
29
|
+
*
|
|
30
|
+
* geodesicLength([[0, 0], [1, 0], [1, 1]]); // about 222,390 m
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function geodesicLength(path) {
|
|
34
|
+
let total = 0;
|
|
35
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
36
|
+
total += haversineDistanceMeters(path[i], path[i + 1]);
|
|
37
|
+
}
|
|
38
|
+
return total;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The spherical area of a ring (signed, square meters)
|
|
42
|
+
*/
|
|
43
|
+
function sphericalRingArea(ring) {
|
|
44
|
+
if (ring.length < 3) {
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
let total = 0;
|
|
48
|
+
const n = ring.length;
|
|
49
|
+
for (let i = 0; i < n; i++) {
|
|
50
|
+
const lower = ring[i];
|
|
51
|
+
const middle = ring[(i + 1) % n];
|
|
52
|
+
const upper = ring[(i + 2) % n];
|
|
53
|
+
total += (toRadians(upper[0]) - toRadians(lower[0])) * Math.sin(toRadians(middle[1]));
|
|
54
|
+
}
|
|
55
|
+
return (total * EARTH_RADIUS_METERS * EARTH_RADIUS_METERS) / 2;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Returns the area of a polygon on the sphere in square meters.
|
|
59
|
+
*
|
|
60
|
+
* The input is normalized with {@link normalizeArea} first, so self-intersections are
|
|
61
|
+
* resolved, a hole outside its outer ring is dropped, a hole larger than its outer ring
|
|
62
|
+
* empties the part, and rings that cannot bound an area are dropped. The holes of the
|
|
63
|
+
* normalized form lie inside their outer ring, so subtracting them never makes the result
|
|
64
|
+
* negative. For a MultiPolygon the sum of each part is returned. Ring orientation does not
|
|
65
|
+
* matter. The area is based on the spherical excess on a sphere of radius
|
|
66
|
+
* {@link EARTH_RADIUS_METERS}.
|
|
67
|
+
*
|
|
68
|
+
* @param polygon Polygon or MultiPolygon coordinates in degrees
|
|
69
|
+
* @returns The area in square meters. 0 when nothing with an area remains
|
|
70
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
71
|
+
* retry on the 1e-9 degree grid
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { sphericalArea } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
76
|
+
*
|
|
77
|
+
* // A 1 x 1 degree square on the equator
|
|
78
|
+
* sphericalArea([[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]); // about 1.236e10 m²
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function sphericalArea(polygon) {
|
|
82
|
+
let total = 0;
|
|
83
|
+
for (const part of normalizeArea(polygon)) {
|
|
84
|
+
for (let i = 0; i < part.length; i++) {
|
|
85
|
+
const ringArea = Math.abs(sphericalRingArea(part[i]));
|
|
86
|
+
total += i === 0 ? ringArea : -ringArea;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return total;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns the centroid of a ring (weighted by area) and its signed area
|
|
93
|
+
*/
|
|
94
|
+
function ringCentroid(ring) {
|
|
95
|
+
if (ring.length < 3) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
let cx = 0;
|
|
99
|
+
let cy = 0;
|
|
100
|
+
let doubleArea = 0;
|
|
101
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
102
|
+
const cross = ring[j][0] * ring[i][1] - ring[i][0] * ring[j][1];
|
|
103
|
+
doubleArea += cross;
|
|
104
|
+
cx += (ring[j][0] + ring[i][0]) * cross;
|
|
105
|
+
cy += (ring[j][1] + ring[i][1]) * cross;
|
|
106
|
+
}
|
|
107
|
+
if (doubleArea === 0) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const area = doubleArea / 2;
|
|
111
|
+
return { centroid: [cx / (6 * area), cy / (6 * area)], area };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The mean coordinate of all the vertices (the fallback for a shape whose area is 0)
|
|
115
|
+
*/
|
|
116
|
+
function verticesMean(polygon) {
|
|
117
|
+
let sumLng = 0;
|
|
118
|
+
let sumLat = 0;
|
|
119
|
+
let count = 0;
|
|
120
|
+
for (const part of toMultiPolygonCoordinates(polygon)) {
|
|
121
|
+
for (const ring of part) {
|
|
122
|
+
for (const [lng, lat] of ring) {
|
|
123
|
+
sumLng += lng;
|
|
124
|
+
sumLat += lat;
|
|
125
|
+
count++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return count === 0 ? null : [sumLng / count, sumLat / count];
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Returns the area-weighted centroid of a polygon.
|
|
133
|
+
*
|
|
134
|
+
* The area of the holes is subtracted, and the parts of a MultiPolygon are combined with
|
|
135
|
+
* their areas as the weights. The computation is on the lng/lat plane, an approximation
|
|
136
|
+
* meant for shapes of the scale of an edit. The centroid of a concave shape can fall
|
|
137
|
+
* outside it; use {@link pointOnSurface} for a point that is always inside.
|
|
138
|
+
*
|
|
139
|
+
* @param polygon Polygon or MultiPolygon coordinates in degrees
|
|
140
|
+
* @returns The centroid `[lng, lat]` in degrees. The mean of all the vertices when the area
|
|
141
|
+
* is 0. `null` when there is not a single position
|
|
142
|
+
*/
|
|
143
|
+
export function centroid(polygon) {
|
|
144
|
+
let sumLng = 0;
|
|
145
|
+
let sumLat = 0;
|
|
146
|
+
let sumArea = 0;
|
|
147
|
+
for (const part of toMultiPolygonCoordinates(polygon)) {
|
|
148
|
+
for (let i = 0; i < part.length; i++) {
|
|
149
|
+
const result = ringCentroid(part[i]);
|
|
150
|
+
if (result === null) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
// Give the outer ring a positive weight and the inner rings a negative one
|
|
154
|
+
const weight = i === 0 ? Math.abs(result.area) : -Math.abs(result.area);
|
|
155
|
+
sumLng += result.centroid[0] * weight;
|
|
156
|
+
sumLat += result.centroid[1] * weight;
|
|
157
|
+
sumArea += weight;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (sumArea === 0) {
|
|
161
|
+
return verticesMean(polygon);
|
|
162
|
+
}
|
|
163
|
+
return [sumLng / sumArea, sumLat / sumArea];
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Returns, in ascending order, the longitudes of the intersections of the horizontal
|
|
167
|
+
* scanline at the given latitude with each ring
|
|
168
|
+
*/
|
|
169
|
+
function scanlineCrossings(polygon, lat) {
|
|
170
|
+
const crossings = [];
|
|
171
|
+
for (const part of toMultiPolygonCoordinates(polygon)) {
|
|
172
|
+
for (const ring of part) {
|
|
173
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
174
|
+
const [xi, yi] = ring[i];
|
|
175
|
+
const [xj, yj] = ring[j];
|
|
176
|
+
// Counting on a half-open interval avoids double-counting a vertex
|
|
177
|
+
if (yi > lat !== yj > lat) {
|
|
178
|
+
crossings.push(xi + ((lat - yi) / (yj - yi)) * (xj - xi));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return crossings.sort((a, b) => a - b);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns a representative point that lies inside a polygon, such as a label anchor.
|
|
187
|
+
*
|
|
188
|
+
* If the {@link centroid} is inside the polygon, it is returned. If it is outside (a
|
|
189
|
+
* concave shape, or a centroid in a hole), a horizontal scanline is drawn at the latitude of
|
|
190
|
+
* the centroid and the midpoint of the longest interior section is returned. For a
|
|
191
|
+
* degenerate shape the scanline does not cross, the center of the bounding box is returned.
|
|
192
|
+
*
|
|
193
|
+
* @param polygon Polygon or MultiPolygon coordinates in degrees
|
|
194
|
+
* @returns The point `[lng, lat]` in degrees. `null` when there is not a single position
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* import { centroid, pointOnSurface } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
199
|
+
*
|
|
200
|
+
* // A U shape: the centroid falls in the gap between the arms
|
|
201
|
+
* const u: [number, number][][] = [
|
|
202
|
+
* [[0, 0], [3, 0], [3, 3], [2, 3], [2, 1], [1, 1], [1, 3], [0, 3], [0, 0]],
|
|
203
|
+
* ];
|
|
204
|
+
* centroid(u); // [1.5, 1.357...] (outside)
|
|
205
|
+
* pointOnSurface(u); // [0.5, 1.357...] (inside the left arm)
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export function pointOnSurface(polygon) {
|
|
209
|
+
const center = centroid(polygon);
|
|
210
|
+
if (center === null) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
if (pointInPolygon(center, polygon)) {
|
|
214
|
+
return center;
|
|
215
|
+
}
|
|
216
|
+
const lat = center[1];
|
|
217
|
+
const crossings = scanlineCrossings(polygon, lat);
|
|
218
|
+
let bestStart = Number.NaN;
|
|
219
|
+
let bestWidth = -1;
|
|
220
|
+
// By the even-odd rule, the intervals formed by pairing the intersections two at a
|
|
221
|
+
// time in ascending order are the interior
|
|
222
|
+
for (let i = 0; i + 1 < crossings.length; i += 2) {
|
|
223
|
+
const width = crossings[i + 1] - crossings[i];
|
|
224
|
+
if (width > bestWidth) {
|
|
225
|
+
bestWidth = width;
|
|
226
|
+
bestStart = crossings[i];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (bestWidth < 0) {
|
|
230
|
+
// A degenerate shape in which the scanline does not pass through the interior.
|
|
231
|
+
// Fall back to the center of the bbox
|
|
232
|
+
const box = boundingBox(polygon);
|
|
233
|
+
return box === null ? center : [(box[0] + box[2]) / 2, (box[1] + box[3]) / 2];
|
|
234
|
+
}
|
|
235
|
+
return [bestStart + bestWidth / 2, lat];
|
|
236
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { AreaCoordinates, Coordinate } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Determines whether a point is inside a polygon, holes taken into account.
|
|
4
|
+
*
|
|
5
|
+
* The test is ray casting on the lng/lat plane; the result for a point exactly on the
|
|
6
|
+
* boundary is undefined. Ring orientation does not matter. No boolean operation is run, so
|
|
7
|
+
* it never throws.
|
|
8
|
+
*
|
|
9
|
+
* @param point The position `[lng, lat]` in degrees
|
|
10
|
+
* @param polygon Polygon or MultiPolygon coordinates in degrees
|
|
11
|
+
* @returns `true` when the point is inside an outer ring and inside none of its holes (in
|
|
12
|
+
* any part of a MultiPolygon). `false` for empty coordinates
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { pointInPolygon } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
17
|
+
*
|
|
18
|
+
* const square: [number, number][][] = [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]];
|
|
19
|
+
* pointInPolygon([0.5, 0.5], square); // true
|
|
20
|
+
* pointInPolygon([2, 0.5], square); // false
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function pointInPolygon(point: Coordinate, polygon: AreaCoordinates): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Determines whether two polygons overlap with a positive area.
|
|
26
|
+
*
|
|
27
|
+
* A touch that shares only the boundary has no area, so it gives `false`. The bounding boxes
|
|
28
|
+
* are compared first, and the boolean operation runs only when they overlap.
|
|
29
|
+
*
|
|
30
|
+
* @param a Polygon or MultiPolygon coordinates in degrees
|
|
31
|
+
* @param b Polygon or MultiPolygon coordinates in degrees
|
|
32
|
+
* @returns `true` when the common part has an area. `false` when either input has no
|
|
33
|
+
* finite position
|
|
34
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
35
|
+
* retry on the 1e-9 degree grid
|
|
36
|
+
*/
|
|
37
|
+
export declare function intersects(a: AreaCoordinates, b: AreaCoordinates): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Determines whether one polygon completely contains another.
|
|
40
|
+
*
|
|
41
|
+
* Sharing the boundary is allowed. The bounding boxes are compared first.
|
|
42
|
+
*
|
|
43
|
+
* @param outer The containing Polygon or MultiPolygon coordinates, in degrees
|
|
44
|
+
* @param inner The contained Polygon or MultiPolygon coordinates, in degrees
|
|
45
|
+
* @returns `true` when no part of `inner` lies outside `outer`. `false` when `inner` has no
|
|
46
|
+
* area
|
|
47
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
48
|
+
* retry on the 1e-9 degree grid
|
|
49
|
+
*/
|
|
50
|
+
export declare function contains(outer: AreaCoordinates, inner: AreaCoordinates): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Determines whether one polygon lies completely inside another; {@link contains} with its
|
|
53
|
+
* arguments swapped.
|
|
54
|
+
*
|
|
55
|
+
* @param inner The contained Polygon or MultiPolygon coordinates, in degrees
|
|
56
|
+
* @param outer The containing Polygon or MultiPolygon coordinates, in degrees
|
|
57
|
+
* @returns `true` when no part of `inner` lies outside `outer`. `false` when `inner` has no
|
|
58
|
+
* area
|
|
59
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
60
|
+
* retry on the 1e-9 degree grid
|
|
61
|
+
*/
|
|
62
|
+
export declare function within(inner: AreaCoordinates, outer: AreaCoordinates): boolean;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* Predicates
|
|
5
|
+
*
|
|
6
|
+
* A test between polygons returns false early with the preliminary check on the bbox
|
|
7
|
+
* before proceeding to the topological test by polygon-clipping. Every test is
|
|
8
|
+
* area-based, so a touch that shares only the boundary is not regarded as an
|
|
9
|
+
* intersection.
|
|
10
|
+
*/
|
|
11
|
+
import { bboxContains, bboxIntersects, boundingBox } from './bbox.js';
|
|
12
|
+
import { difference, intersection, normalizeArea } from './boolean.js';
|
|
13
|
+
import { toMultiPolygonCoordinates } from './coords.js';
|
|
14
|
+
/**
|
|
15
|
+
* Whether a point is inside a ring (ray casting; the treatment on the boundary is
|
|
16
|
+
* undefined)
|
|
17
|
+
*/
|
|
18
|
+
function pointInRing(point, ring) {
|
|
19
|
+
const [x, y] = point;
|
|
20
|
+
let inside = false;
|
|
21
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
22
|
+
const [xi, yi] = ring[i];
|
|
23
|
+
const [xj, yj] = ring[j];
|
|
24
|
+
// Whether the scanline y crosses the edge (counted on a half-open interval, which
|
|
25
|
+
// avoids double-counting a vertex)
|
|
26
|
+
if (yi > y !== yj > y) {
|
|
27
|
+
const t = (y - yi) / (yj - yi);
|
|
28
|
+
if (x < xi + t * (xj - xi)) {
|
|
29
|
+
inside = !inside;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return inside;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Determines whether a point is inside a polygon, holes taken into account.
|
|
37
|
+
*
|
|
38
|
+
* The test is ray casting on the lng/lat plane; the result for a point exactly on the
|
|
39
|
+
* boundary is undefined. Ring orientation does not matter. No boolean operation is run, so
|
|
40
|
+
* it never throws.
|
|
41
|
+
*
|
|
42
|
+
* @param point The position `[lng, lat]` in degrees
|
|
43
|
+
* @param polygon Polygon or MultiPolygon coordinates in degrees
|
|
44
|
+
* @returns `true` when the point is inside an outer ring and inside none of its holes (in
|
|
45
|
+
* any part of a MultiPolygon). `false` for empty coordinates
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { pointInPolygon } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
50
|
+
*
|
|
51
|
+
* const square: [number, number][][] = [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]];
|
|
52
|
+
* pointInPolygon([0.5, 0.5], square); // true
|
|
53
|
+
* pointInPolygon([2, 0.5], square); // false
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export function pointInPolygon(point, polygon) {
|
|
57
|
+
for (const part of toMultiPolygonCoordinates(polygon)) {
|
|
58
|
+
if (part.length === 0 || !pointInRing(point, part[0])) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
let inHole = false;
|
|
62
|
+
for (let i = 1; i < part.length; i++) {
|
|
63
|
+
if (pointInRing(point, part[i])) {
|
|
64
|
+
inHole = true;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!inHole) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Determines whether two polygons overlap with a positive area.
|
|
76
|
+
*
|
|
77
|
+
* A touch that shares only the boundary has no area, so it gives `false`. The bounding boxes
|
|
78
|
+
* are compared first, and the boolean operation runs only when they overlap.
|
|
79
|
+
*
|
|
80
|
+
* @param a Polygon or MultiPolygon coordinates in degrees
|
|
81
|
+
* @param b Polygon or MultiPolygon coordinates in degrees
|
|
82
|
+
* @returns `true` when the common part has an area. `false` when either input has no
|
|
83
|
+
* finite position
|
|
84
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
85
|
+
* retry on the 1e-9 degree grid
|
|
86
|
+
*/
|
|
87
|
+
export function intersects(a, b) {
|
|
88
|
+
const boxA = boundingBox(a);
|
|
89
|
+
const boxB = boundingBox(b);
|
|
90
|
+
if (boxA === null || boxB === null || !bboxIntersects(boxA, boxB)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return intersection(a, b).length > 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Determines whether one polygon completely contains another.
|
|
97
|
+
*
|
|
98
|
+
* Sharing the boundary is allowed. The bounding boxes are compared first.
|
|
99
|
+
*
|
|
100
|
+
* @param outer The containing Polygon or MultiPolygon coordinates, in degrees
|
|
101
|
+
* @param inner The contained Polygon or MultiPolygon coordinates, in degrees
|
|
102
|
+
* @returns `true` when no part of `inner` lies outside `outer`. `false` when `inner` has no
|
|
103
|
+
* area
|
|
104
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
105
|
+
* retry on the 1e-9 degree grid
|
|
106
|
+
*/
|
|
107
|
+
export function contains(outer, inner) {
|
|
108
|
+
const boxOuter = boundingBox(outer);
|
|
109
|
+
const boxInner = boundingBox(inner);
|
|
110
|
+
if (boxOuter === null || boxInner === null || !bboxContains(boxOuter, boxInner)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
// When inner has no area, it is not subject to the test
|
|
114
|
+
if (normalizeArea(inner).length === 0) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
return difference(inner, outer).length === 0;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Determines whether one polygon lies completely inside another; {@link contains} with its
|
|
121
|
+
* arguments swapped.
|
|
122
|
+
*
|
|
123
|
+
* @param inner The contained Polygon or MultiPolygon coordinates, in degrees
|
|
124
|
+
* @param outer The containing Polygon or MultiPolygon coordinates, in degrees
|
|
125
|
+
* @returns `true` when no part of `inner` lies outside `outer`. `false` when `inner` has no
|
|
126
|
+
* area
|
|
127
|
+
* @throws {@link GeometryError} when the boolean operation engine fails even after the
|
|
128
|
+
* retry on the 1e-9 degree grid
|
|
129
|
+
*/
|
|
130
|
+
export function within(inner, outer) {
|
|
131
|
+
return contains(outer, inner);
|
|
132
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Coordinate, MultiPolygonCoordinates, PolygonCoordinates, Ring } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Simplifies a coordinate sequence by the Douglas-Peucker algorithm.
|
|
4
|
+
*
|
|
5
|
+
* The tolerance is a distance on the lng/lat plane in degrees, not in meters: 0.00001
|
|
6
|
+
* degrees is about 1.1 m of latitude, and a degree of longitude shrinks with `cos(lat)`.
|
|
7
|
+
* The endpoints always remain. When the input is a closed ring, it is returned still
|
|
8
|
+
* closed. When the ring would collapse to fewer than 4 points it would lose its area, so
|
|
9
|
+
* the input is returned as it is. A tolerance that is not a positive number (0, a negative value or NaN) simplifies
|
|
10
|
+
* nothing and returns a copy of the input.
|
|
11
|
+
*
|
|
12
|
+
* @param path The vertices `[lng, lat]` in degrees
|
|
13
|
+
* @param toleranceDegrees The largest distance in degrees a dropped vertex may lie from the
|
|
14
|
+
* simplified line
|
|
15
|
+
* @returns The simplified vertices as a new array. A copy of the input for 2 positions or
|
|
16
|
+
* fewer, for a tolerance that is not positive, and for a ring that would collapse
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { simplify } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
21
|
+
*
|
|
22
|
+
* simplify([[0, 0], [1, 0.00001], [2, 0], [3, 1]], 0.001); // [[0, 0], [2, 0], [3, 1]]
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function simplify(path: Coordinate[], toleranceDegrees: number): Coordinate[];
|
|
26
|
+
/**
|
|
27
|
+
* Returns the signed planar area of a ring in square degrees; counter-clockwise is
|
|
28
|
+
* positive.
|
|
29
|
+
*
|
|
30
|
+
* The shoelace formula on the lng/lat plane, meant for orientation tests. For an area in
|
|
31
|
+
* square meters use {@link sphericalArea}. The ring may be open or closed.
|
|
32
|
+
*
|
|
33
|
+
* @param ring The ring `[lng, lat][]` in degrees
|
|
34
|
+
* @returns The signed area in square degrees. 0 for fewer than 3 positions
|
|
35
|
+
*/
|
|
36
|
+
export declare function signedRingArea(ring: Ring): number;
|
|
37
|
+
/**
|
|
38
|
+
* Determines whether a ring runs clockwise on the lng/lat plane.
|
|
39
|
+
*
|
|
40
|
+
* @param ring The ring `[lng, lat][]` in degrees
|
|
41
|
+
* @returns `true` when it is clockwise. `false` when it is counter-clockwise and for a
|
|
42
|
+
* degenerate ring whose area is 0
|
|
43
|
+
*/
|
|
44
|
+
export declare function isRingClockwise(ring: Ring): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Returns a ring in the given orientation.
|
|
47
|
+
*
|
|
48
|
+
* A degenerate ring with area 0 counts as counter-clockwise.
|
|
49
|
+
*
|
|
50
|
+
* @param ring The ring `[lng, lat][]` in degrees
|
|
51
|
+
* @param clockwise `true` for clockwise and `false` for counter-clockwise
|
|
52
|
+
* @returns The input itself when it already has the orientation, otherwise a new reversed
|
|
53
|
+
* array
|
|
54
|
+
*/
|
|
55
|
+
export declare function normalizeRingOrientation(ring: Ring, clockwise: boolean): Ring;
|
|
56
|
+
/**
|
|
57
|
+
* Orients the rings of a Polygon as GeoJSON (RFC 7946) recommends: the outer ring
|
|
58
|
+
* counter-clockwise and the holes clockwise.
|
|
59
|
+
*
|
|
60
|
+
* Only the orientation changes; self-intersections and degenerate rings are left as they
|
|
61
|
+
* are (use {@link normalizeArea} for those).
|
|
62
|
+
*
|
|
63
|
+
* @param polygon Polygon coordinates in degrees
|
|
64
|
+
* @returns New Polygon coordinates; rings already in the orientation are reused
|
|
65
|
+
*/
|
|
66
|
+
export declare function normalizePolygonOrientation(polygon: PolygonCoordinates): PolygonCoordinates;
|
|
67
|
+
/**
|
|
68
|
+
* Orients the rings of every part of a MultiPolygon as
|
|
69
|
+
* {@link normalizePolygonOrientation} does.
|
|
70
|
+
*
|
|
71
|
+
* @param multiPolygon MultiPolygon coordinates in degrees
|
|
72
|
+
* @returns New MultiPolygon coordinates; rings already in the orientation are reused
|
|
73
|
+
*/
|
|
74
|
+
export declare function normalizeMultiPolygonOrientation(multiPolygon: MultiPolygonCoordinates): MultiPolygonCoordinates;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* Shaping
|
|
5
|
+
*
|
|
6
|
+
* Simplification by Douglas-Peucker, and the normalization of the ring orientations.
|
|
7
|
+
* The tolerance is given in degrees (a distance on the lng/lat plane).
|
|
8
|
+
*/
|
|
9
|
+
import { isRingClosed } from './coords.js';
|
|
10
|
+
/**
|
|
11
|
+
* The square of the distance from a point to a segment (square degrees)
|
|
12
|
+
*/
|
|
13
|
+
function squaredSegmentDistance(point, start, end) {
|
|
14
|
+
let x = start[0];
|
|
15
|
+
let y = start[1];
|
|
16
|
+
const dx = end[0] - x;
|
|
17
|
+
const dy = end[1] - y;
|
|
18
|
+
if (dx !== 0 || dy !== 0) {
|
|
19
|
+
const t = ((point[0] - x) * dx + (point[1] - y) * dy) / (dx * dx + dy * dy);
|
|
20
|
+
if (t > 1) {
|
|
21
|
+
x = end[0];
|
|
22
|
+
y = end[1];
|
|
23
|
+
}
|
|
24
|
+
else if (t > 0) {
|
|
25
|
+
x += dx * t;
|
|
26
|
+
y += dy * t;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const px = point[0] - x;
|
|
30
|
+
const py = point[1] - y;
|
|
31
|
+
return px * px + py * py;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The recursive body of Douglas-Peucker (marks the indices that are adopted)
|
|
35
|
+
*/
|
|
36
|
+
function markKeep(path, first, last, squaredTolerance, keep) {
|
|
37
|
+
let maxSquared = squaredTolerance;
|
|
38
|
+
let index = -1;
|
|
39
|
+
for (let i = first + 1; i < last; i++) {
|
|
40
|
+
const squared = squaredSegmentDistance(path[i], path[first], path[last]);
|
|
41
|
+
if (squared > maxSquared) {
|
|
42
|
+
maxSquared = squared;
|
|
43
|
+
index = i;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (index === -1) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
keep[index] = true;
|
|
50
|
+
if (index - first > 1) {
|
|
51
|
+
markKeep(path, first, index, squaredTolerance, keep);
|
|
52
|
+
}
|
|
53
|
+
if (last - index > 1) {
|
|
54
|
+
markKeep(path, index, last, squaredTolerance, keep);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Simplifies a coordinate sequence by the Douglas-Peucker algorithm.
|
|
59
|
+
*
|
|
60
|
+
* The tolerance is a distance on the lng/lat plane in degrees, not in meters: 0.00001
|
|
61
|
+
* degrees is about 1.1 m of latitude, and a degree of longitude shrinks with `cos(lat)`.
|
|
62
|
+
* The endpoints always remain. When the input is a closed ring, it is returned still
|
|
63
|
+
* closed. When the ring would collapse to fewer than 4 points it would lose its area, so
|
|
64
|
+
* the input is returned as it is. A tolerance that is not a positive number (0, a negative value or NaN) simplifies
|
|
65
|
+
* nothing and returns a copy of the input.
|
|
66
|
+
*
|
|
67
|
+
* @param path The vertices `[lng, lat]` in degrees
|
|
68
|
+
* @param toleranceDegrees The largest distance in degrees a dropped vertex may lie from the
|
|
69
|
+
* simplified line
|
|
70
|
+
* @returns The simplified vertices as a new array. A copy of the input for 2 positions or
|
|
71
|
+
* fewer, for a tolerance that is not positive, and for a ring that would collapse
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { simplify } from '@sakuzu/maplibre-gl-draw/geometry';
|
|
76
|
+
*
|
|
77
|
+
* simplify([[0, 0], [1, 0.00001], [2, 0], [3, 1]], 0.001); // [[0, 0], [2, 0], [3, 1]]
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export function simplify(path, toleranceDegrees) {
|
|
81
|
+
if (path.length <= 2 || !(toleranceDegrees > 0)) {
|
|
82
|
+
return [...path];
|
|
83
|
+
}
|
|
84
|
+
const keep = new Array(path.length).fill(false);
|
|
85
|
+
keep[0] = true;
|
|
86
|
+
keep[path.length - 1] = true;
|
|
87
|
+
markKeep(path, 0, path.length - 1, toleranceDegrees * toleranceDegrees, keep);
|
|
88
|
+
const result = path.filter((_, index) => keep[index]);
|
|
89
|
+
if (isRingClosed(path) && result.length < 4) {
|
|
90
|
+
return [...path];
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns the signed planar area of a ring in square degrees; counter-clockwise is
|
|
96
|
+
* positive.
|
|
97
|
+
*
|
|
98
|
+
* The shoelace formula on the lng/lat plane, meant for orientation tests. For an area in
|
|
99
|
+
* square meters use {@link sphericalArea}. The ring may be open or closed.
|
|
100
|
+
*
|
|
101
|
+
* @param ring The ring `[lng, lat][]` in degrees
|
|
102
|
+
* @returns The signed area in square degrees. 0 for fewer than 3 positions
|
|
103
|
+
*/
|
|
104
|
+
export function signedRingArea(ring) {
|
|
105
|
+
if (ring.length < 3) {
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
let total = 0;
|
|
109
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
110
|
+
total += (ring[j][0] + ring[i][0]) * (ring[j][1] - ring[i][1]);
|
|
111
|
+
}
|
|
112
|
+
return -total / 2;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Determines whether a ring runs clockwise on the lng/lat plane.
|
|
116
|
+
*
|
|
117
|
+
* @param ring The ring `[lng, lat][]` in degrees
|
|
118
|
+
* @returns `true` when it is clockwise. `false` when it is counter-clockwise and for a
|
|
119
|
+
* degenerate ring whose area is 0
|
|
120
|
+
*/
|
|
121
|
+
export function isRingClockwise(ring) {
|
|
122
|
+
return signedRingArea(ring) < 0;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Returns a ring in the given orientation.
|
|
126
|
+
*
|
|
127
|
+
* A degenerate ring with area 0 counts as counter-clockwise.
|
|
128
|
+
*
|
|
129
|
+
* @param ring The ring `[lng, lat][]` in degrees
|
|
130
|
+
* @param clockwise `true` for clockwise and `false` for counter-clockwise
|
|
131
|
+
* @returns The input itself when it already has the orientation, otherwise a new reversed
|
|
132
|
+
* array
|
|
133
|
+
*/
|
|
134
|
+
export function normalizeRingOrientation(ring, clockwise) {
|
|
135
|
+
return isRingClockwise(ring) === clockwise ? ring : [...ring].reverse();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Orients the rings of a Polygon as GeoJSON (RFC 7946) recommends: the outer ring
|
|
139
|
+
* counter-clockwise and the holes clockwise.
|
|
140
|
+
*
|
|
141
|
+
* Only the orientation changes; self-intersections and degenerate rings are left as they
|
|
142
|
+
* are (use {@link normalizeArea} for those).
|
|
143
|
+
*
|
|
144
|
+
* @param polygon Polygon coordinates in degrees
|
|
145
|
+
* @returns New Polygon coordinates; rings already in the orientation are reused
|
|
146
|
+
*/
|
|
147
|
+
export function normalizePolygonOrientation(polygon) {
|
|
148
|
+
return polygon.map((ring, index) => normalizeRingOrientation(ring, index > 0));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Orients the rings of every part of a MultiPolygon as
|
|
152
|
+
* {@link normalizePolygonOrientation} does.
|
|
153
|
+
*
|
|
154
|
+
* @param multiPolygon MultiPolygon coordinates in degrees
|
|
155
|
+
* @returns New MultiPolygon coordinates; rings already in the orientation are reused
|
|
156
|
+
*/
|
|
157
|
+
export function normalizeMultiPolygonOrientation(multiPolygon) {
|
|
158
|
+
return multiPolygon.map(normalizePolygonOrientation);
|
|
159
|
+
}
|