googlemaps-kit 0.4.0 → 0.6.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/README.md +228 -27
- package/dist/advanced/http.d.ts +4 -4
- package/dist/advanced/http.d.ts.map +1 -1
- package/dist/advanced/http.js +4 -4
- package/dist/advanced/http.js.map +1 -1
- package/dist/advanced/parsers.d.ts +9 -4
- package/dist/advanced/parsers.d.ts.map +1 -1
- package/dist/advanced/parsers.js +6 -3
- package/dist/advanced/parsers.js.map +1 -1
- package/dist/advanced/rpc.d.ts +12 -12
- package/dist/advanced/rpc.d.ts.map +1 -1
- package/dist/advanced/rpc.js +10 -10
- package/dist/advanced/rpc.js.map +1 -1
- package/dist/advanced/services.d.ts +18 -7
- package/dist/advanced/services.d.ts.map +1 -1
- package/dist/advanced/services.js +18 -7
- package/dist/advanced/services.js.map +1 -1
- package/dist/advanced/utils.d.ts +3 -3
- package/dist/advanced/utils.d.ts.map +1 -1
- package/dist/advanced/utils.js +3 -3
- package/dist/advanced/utils.js.map +1 -1
- package/dist/advanced.d.ts +47 -10
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +13 -6
- package/dist/advanced.js.map +1 -1
- package/dist/auth/auth-status.js +2 -2
- package/dist/auth/auth-status.js.map +1 -1
- package/dist/auth/maps-tokens.js +1 -1
- package/dist/auth/session.d.ts.map +1 -1
- package/dist/auth/session.js +17 -2
- package/dist/auth/session.js.map +1 -1
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +24 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +18 -27
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/output.d.ts +19 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +82 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/run.d.ts +55 -3
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +239 -18
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/tui/app.d.ts +7 -2
- package/dist/cli/tui/app.d.ts.map +1 -1
- package/dist/cli/tui/app.js +116 -31
- package/dist/cli/tui/app.js.map +1 -1
- package/dist/cli/tui/styles.d.ts.map +1 -1
- package/dist/cli/tui/styles.js +13 -10
- package/dist/cli/tui/styles.js.map +1 -1
- package/dist/cli.d.ts +1 -10
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +122 -36
- package/dist/cli.js.map +1 -1
- package/dist/client/gmaps-client.d.ts +14 -31
- package/dist/client/gmaps-client.d.ts.map +1 -1
- package/dist/client/gmaps-client.js +52 -130
- package/dist/client/gmaps-client.js.map +1 -1
- package/dist/client/http-client.d.ts.map +1 -1
- package/dist/client/http-client.js +11 -9
- package/dist/client/http-client.js.map +1 -1
- package/dist/client/intent.d.ts +2 -12
- package/dist/client/intent.d.ts.map +1 -1
- package/dist/client/intent.js +39 -18
- package/dist/client/intent.js.map +1 -1
- package/dist/client/maps-tools.d.ts +19 -3
- package/dist/client/maps-tools.d.ts.map +1 -1
- package/dist/client/maps-tools.js +57 -4
- package/dist/client/maps-tools.js.map +1 -1
- package/dist/client/namespaces.d.ts +125 -16
- package/dist/client/namespaces.d.ts.map +1 -1
- package/dist/client/namespaces.js +189 -23
- package/dist/client/namespaces.js.map +1 -1
- package/dist/client/place-enrichment.js +1 -1
- package/dist/client/place-enrichment.js.map +1 -1
- package/dist/client/place-workflows.d.ts +7 -0
- package/dist/client/place-workflows.d.ts.map +1 -0
- package/dist/client/place-workflows.js +113 -0
- package/dist/client/place-workflows.js.map +1 -0
- package/dist/index.d.ts +54 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/known-surfaces.d.ts +173 -5
- package/dist/known-surfaces.d.ts.map +1 -1
- package/dist/known-surfaces.js +173 -5
- package/dist/known-surfaces.js.map +1 -1
- package/dist/parsers/batch-url.d.ts +10 -1
- package/dist/parsers/batch-url.d.ts.map +1 -1
- package/dist/parsers/batch-url.js +30 -2
- package/dist/parsers/batch-url.js.map +1 -1
- package/dist/parsers/boq-reviews.d.ts +8 -1
- package/dist/parsers/boq-reviews.d.ts.map +1 -1
- package/dist/parsers/boq-reviews.js +50 -8
- package/dist/parsers/boq-reviews.js.map +1 -1
- package/dist/parsers/categories.d.ts.map +1 -1
- package/dist/parsers/categories.js +13 -10
- package/dist/parsers/categories.js.map +1 -1
- package/dist/parsers/directions.d.ts +18 -2
- package/dist/parsers/directions.d.ts.map +1 -1
- package/dist/parsers/directions.js +232 -18
- package/dist/parsers/directions.js.map +1 -1
- package/dist/parsers/geocode.d.ts +20 -2
- package/dist/parsers/geocode.d.ts.map +1 -1
- package/dist/parsers/geocode.js +139 -6
- package/dist/parsers/geocode.js.map +1 -1
- package/dist/parsers/knowledge.js +1 -1
- package/dist/parsers/knowledge.js.map +1 -1
- package/dist/parsers/lists.d.ts.map +1 -1
- package/dist/parsers/lists.js +29 -12
- package/dist/parsers/lists.js.map +1 -1
- package/dist/parsers/local-posts.d.ts.map +1 -1
- package/dist/parsers/local-posts.js +97 -12
- package/dist/parsers/local-posts.js.map +1 -1
- package/dist/parsers/mobility.d.ts +42 -0
- package/dist/parsers/mobility.d.ts.map +1 -0
- package/dist/parsers/mobility.js +130 -0
- package/dist/parsers/mobility.js.map +1 -0
- package/dist/parsers/panorama.d.ts +0 -1
- package/dist/parsers/panorama.d.ts.map +1 -1
- package/dist/parsers/panorama.js +117 -14
- package/dist/parsers/panorama.js.map +1 -1
- package/dist/parsers/photos.d.ts.map +1 -1
- package/dist/parsers/photos.js +15 -8
- package/dist/parsers/photos.js.map +1 -1
- package/dist/parsers/place-attributes.d.ts +12 -3
- package/dist/parsers/place-attributes.d.ts.map +1 -1
- package/dist/parsers/place-attributes.js +48 -2
- package/dist/parsers/place-attributes.js.map +1 -1
- package/dist/parsers/place-extended.d.ts +163 -0
- package/dist/parsers/place-extended.d.ts.map +1 -0
- package/dist/parsers/place-extended.js +741 -0
- package/dist/parsers/place-extended.js.map +1 -0
- package/dist/parsers/place.d.ts +15 -1
- package/dist/parsers/place.d.ts.map +1 -1
- package/dist/parsers/place.js +16 -5
- package/dist/parsers/place.js.map +1 -1
- package/dist/parsers/popular-times.d.ts +35 -0
- package/dist/parsers/popular-times.d.ts.map +1 -0
- package/dist/parsers/popular-times.js +149 -0
- package/dist/parsers/popular-times.js.map +1 -0
- package/dist/parsers/reveal.d.ts +1 -1
- package/dist/parsers/reveal.d.ts.map +1 -1
- package/dist/parsers/reveal.js +3 -2
- package/dist/parsers/reveal.js.map +1 -1
- package/dist/parsers/reviews.d.ts +24 -2
- package/dist/parsers/reviews.d.ts.map +1 -1
- package/dist/parsers/reviews.js +110 -1
- package/dist/parsers/reviews.js.map +1 -1
- package/dist/parsers/search.d.ts +17 -2
- package/dist/parsers/search.d.ts.map +1 -1
- package/dist/parsers/search.js +125 -7
- package/dist/parsers/search.js.map +1 -1
- package/dist/parsers/shared.d.ts +4 -0
- package/dist/parsers/shared.d.ts.map +1 -1
- package/dist/parsers/shared.js +10 -2
- package/dist/parsers/shared.js.map +1 -1
- package/dist/parsers/suggest.d.ts.map +1 -1
- package/dist/parsers/suggest.js +45 -6
- package/dist/parsers/suggest.js.map +1 -1
- package/dist/parsers/tiles.d.ts +13 -0
- package/dist/parsers/tiles.d.ts.map +1 -1
- package/dist/parsers/tiles.js +64 -0
- package/dist/parsers/tiles.js.map +1 -1
- package/dist/parsers/traffic.d.ts +9 -1
- package/dist/parsers/traffic.d.ts.map +1 -1
- package/dist/parsers/traffic.js +129 -2
- package/dist/parsers/traffic.js.map +1 -1
- package/dist/parsers/transit.d.ts +4 -2
- package/dist/parsers/transit.d.ts.map +1 -1
- package/dist/parsers/transit.js +385 -3
- package/dist/parsers/transit.js.map +1 -1
- package/dist/parsers/viewport.d.ts +20 -0
- package/dist/parsers/viewport.d.ts.map +1 -0
- package/dist/parsers/viewport.js +139 -0
- package/dist/parsers/viewport.js.map +1 -0
- package/dist/platform/catalog.d.ts +18 -0
- package/dist/platform/catalog.d.ts.map +1 -0
- package/dist/platform/catalog.js +329 -0
- package/dist/platform/catalog.js.map +1 -0
- package/dist/platform/parity.d.ts +12 -0
- package/dist/platform/parity.d.ts.map +1 -0
- package/dist/platform/parity.js +25 -0
- package/dist/platform/parity.js.map +1 -0
- package/dist/rpc/batch-execute.js +3 -3
- package/dist/rpc/batch-execute.js.map +1 -1
- package/dist/rpc/batch-request-builders.d.ts +12 -14
- package/dist/rpc/batch-request-builders.d.ts.map +1 -1
- package/dist/rpc/batch-request-builders.js +49 -17
- package/dist/rpc/batch-request-builders.js.map +1 -1
- package/dist/rpc/batch-rpc.js +1 -1
- package/dist/rpc/batch-services.d.ts +2 -0
- package/dist/rpc/batch-services.d.ts.map +1 -1
- package/dist/rpc/batch-services.js +4 -0
- package/dist/rpc/batch-services.js.map +1 -1
- package/dist/rpc/{descriptor-registry.d.ts → descriptors.d.ts} +29 -4
- package/dist/rpc/descriptors.d.ts.map +1 -0
- package/dist/rpc/{app-options.js → descriptors.js} +89 -5
- package/dist/rpc/descriptors.js.map +1 -0
- package/dist/rpc/earth-rocktree.d.ts +174 -0
- package/dist/rpc/earth-rocktree.d.ts.map +1 -0
- package/dist/rpc/earth-rocktree.js +468 -0
- package/dist/rpc/earth-rocktree.js.map +1 -0
- package/dist/rpc/feature-pb.d.ts +86 -0
- package/dist/rpc/feature-pb.d.ts.map +1 -0
- package/dist/rpc/feature-pb.js +112 -0
- package/dist/rpc/feature-pb.js.map +1 -0
- package/dist/rpc/feature-rpc.d.ts +15 -0
- package/dist/rpc/feature-rpc.d.ts.map +1 -1
- package/dist/rpc/feature-rpc.js +44 -0
- package/dist/rpc/feature-rpc.js.map +1 -1
- package/dist/rpc/maps-runtime.js +1 -1
- package/dist/rpc/panorama-pb.d.ts +3 -0
- package/dist/rpc/panorama-pb.d.ts.map +1 -1
- package/dist/rpc/panorama-pb.js +35 -3
- package/dist/rpc/panorama-pb.js.map +1 -1
- package/dist/rpc/pb-builders.d.ts +21 -1
- package/dist/rpc/pb-builders.d.ts.map +1 -1
- package/dist/rpc/pb-builders.js +62 -4
- package/dist/rpc/pb-builders.js.map +1 -1
- package/dist/rpc/photos-pb.d.ts +28 -1
- package/dist/rpc/photos-pb.d.ts.map +1 -1
- package/dist/rpc/photos-pb.js +96 -0
- package/dist/rpc/photos-pb.js.map +1 -1
- package/dist/rpc/rpc-methods.d.ts +0 -2
- package/dist/rpc/rpc-methods.d.ts.map +1 -1
- package/dist/rpc/rpc-methods.js +0 -38
- package/dist/rpc/rpc-methods.js.map +1 -1
- package/dist/rpc/search-filters.d.ts +0 -12
- package/dist/rpc/search-filters.d.ts.map +1 -1
- package/dist/rpc/search-filters.js +1 -11
- package/dist/rpc/search-filters.js.map +1 -1
- package/dist/rpc/tile-builders.d.ts +136 -0
- package/dist/rpc/tile-builders.d.ts.map +1 -0
- package/dist/rpc/tile-builders.js +172 -0
- package/dist/rpc/tile-builders.js.map +1 -0
- package/dist/rpc/xsrf-bootstrap.d.ts +0 -2
- package/dist/rpc/xsrf-bootstrap.d.ts.map +1 -1
- package/dist/rpc/xsrf-bootstrap.js +2 -2
- package/dist/rpc/xsrf-bootstrap.js.map +1 -1
- package/dist/services/aerial-view.d.ts +22 -0
- package/dist/services/aerial-view.d.ts.map +1 -0
- package/dist/services/aerial-view.js +107 -0
- package/dist/services/aerial-view.js.map +1 -0
- package/dist/services/ask-maps.d.ts +45 -5
- package/dist/services/ask-maps.d.ts.map +1 -1
- package/dist/services/ask-maps.js +148 -21
- package/dist/services/ask-maps.js.map +1 -1
- package/dist/services/directions.d.ts +17 -1
- package/dist/services/directions.d.ts.map +1 -1
- package/dist/services/directions.js +32 -0
- package/dist/services/directions.js.map +1 -1
- package/dist/services/distance-matrix.d.ts +1 -1
- package/dist/services/distance-matrix.d.ts.map +1 -1
- package/dist/services/distance-matrix.js +1 -1
- package/dist/services/distance-matrix.js.map +1 -1
- package/dist/services/elevation.d.ts +7 -5
- package/dist/services/elevation.d.ts.map +1 -1
- package/dist/services/elevation.js +42 -6
- package/dist/services/elevation.js.map +1 -1
- package/dist/services/environment/air-quality.d.ts +39 -0
- package/dist/services/environment/air-quality.d.ts.map +1 -0
- package/dist/services/environment/air-quality.js +86 -0
- package/dist/services/environment/air-quality.js.map +1 -0
- package/dist/services/environment/weather.d.ts +39 -0
- package/dist/services/environment/weather.d.ts.map +1 -0
- package/dist/services/environment/weather.js +54 -0
- package/dist/services/environment/weather.js.map +1 -0
- package/dist/services/geocode.d.ts +21 -1
- package/dist/services/geocode.d.ts.map +1 -1
- package/dist/services/geocode.js +103 -0
- package/dist/services/geocode.js.map +1 -1
- package/dist/services/keyed.d.ts +80 -0
- package/dist/services/keyed.d.ts.map +1 -0
- package/dist/services/keyed.js +152 -0
- package/dist/services/keyed.js.map +1 -0
- package/dist/services/knowledge.d.ts +6 -2
- package/dist/services/knowledge.d.ts.map +1 -1
- package/dist/services/knowledge.js +30 -5
- package/dist/services/knowledge.js.map +1 -1
- package/dist/services/lists.d.ts +7 -1
- package/dist/services/lists.d.ts.map +1 -1
- package/dist/services/lists.js +45 -1
- package/dist/services/lists.js.map +1 -1
- package/dist/services/map-3d.d.ts +66 -0
- package/dist/services/map-3d.d.ts.map +1 -0
- package/dist/services/map-3d.js +658 -0
- package/dist/services/map-3d.js.map +1 -0
- package/dist/services/map-layers.d.ts +33 -0
- package/dist/services/map-layers.d.ts.map +1 -0
- package/dist/services/map-layers.js +207 -0
- package/dist/services/map-layers.js.map +1 -0
- package/dist/services/meta.d.ts +71 -0
- package/dist/services/meta.d.ts.map +1 -0
- package/dist/services/meta.js +132 -0
- package/dist/services/meta.js.map +1 -0
- package/dist/services/mobility.d.ts +79 -0
- package/dist/services/mobility.d.ts.map +1 -0
- package/dist/services/mobility.js +307 -0
- package/dist/services/mobility.js.map +1 -0
- package/dist/services/nearby-search.d.ts +32 -0
- package/dist/services/nearby-search.d.ts.map +1 -0
- package/dist/services/nearby-search.js +85 -0
- package/dist/services/nearby-search.js.map +1 -0
- package/dist/services/panorama.d.ts +19 -1
- package/dist/services/panorama.d.ts.map +1 -1
- package/dist/services/panorama.js +111 -3
- package/dist/services/panorama.js.map +1 -1
- package/dist/services/photos.d.ts.map +1 -1
- package/dist/services/photos.js +12 -6
- package/dist/services/photos.js.map +1 -1
- package/dist/services/place-attributes.d.ts +31 -0
- package/dist/services/place-attributes.d.ts.map +1 -0
- package/dist/services/place-attributes.js +48 -0
- package/dist/services/place-attributes.js.map +1 -0
- package/dist/services/places.d.ts +13 -0
- package/dist/services/places.d.ts.map +1 -1
- package/dist/services/places.js +7 -4
- package/dist/services/places.js.map +1 -1
- package/dist/services/reviews.d.ts +11 -1
- package/dist/services/reviews.d.ts.map +1 -1
- package/dist/services/reviews.js +36 -12
- package/dist/services/reviews.js.map +1 -1
- package/dist/services/search-along-route.d.ts +33 -0
- package/dist/services/search-along-route.d.ts.map +1 -0
- package/dist/services/search-along-route.js +200 -0
- package/dist/services/search-along-route.js.map +1 -0
- package/dist/services/search.d.ts +29 -2
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +169 -6
- package/dist/services/search.js.map +1 -1
- package/dist/services/static-map.js +1 -1
- package/dist/services/static-map.js.map +1 -1
- package/dist/services/tiles.d.ts +39 -2
- package/dist/services/tiles.d.ts.map +1 -1
- package/dist/services/tiles.js +172 -13
- package/dist/services/tiles.js.map +1 -1
- package/dist/services/traffic.d.ts +12 -1
- package/dist/services/traffic.d.ts.map +1 -1
- package/dist/services/traffic.js +25 -2
- package/dist/services/traffic.js.map +1 -1
- package/dist/services/transit.d.ts +20 -3
- package/dist/services/transit.d.ts.map +1 -1
- package/dist/services/transit.js +69 -1
- package/dist/services/transit.js.map +1 -1
- package/dist/services/viewport.d.ts +76 -0
- package/dist/services/viewport.d.ts.map +1 -0
- package/dist/services/viewport.js +180 -0
- package/dist/services/viewport.js.map +1 -0
- package/dist/services/waypoint-optimizer.d.ts +31 -0
- package/dist/services/waypoint-optimizer.d.ts.map +1 -0
- package/dist/services/waypoint-optimizer.js +235 -0
- package/dist/services/waypoint-optimizer.js.map +1 -0
- package/dist/types/aerial-view.d.ts +39 -0
- package/dist/types/aerial-view.d.ts.map +1 -0
- package/dist/types/aerial-view.js +2 -0
- package/dist/types/aerial-view.js.map +1 -0
- package/dist/types/batch-url.d.ts +31 -0
- package/dist/types/batch-url.d.ts.map +1 -1
- package/dist/types/categories.d.ts +20 -4
- package/dist/types/categories.d.ts.map +1 -1
- package/dist/types/common.d.ts +192 -24
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/common.js +1 -1
- package/dist/types/common.js.map +1 -1
- package/dist/types/directions.d.ts +217 -3
- package/dist/types/directions.d.ts.map +1 -1
- package/dist/types/dx.d.ts +69 -11
- package/dist/types/dx.d.ts.map +1 -1
- package/dist/types/geocode.d.ts +61 -3
- package/dist/types/geocode.d.ts.map +1 -1
- package/dist/types/grid-search.d.ts +66 -0
- package/dist/types/grid-search.d.ts.map +1 -0
- package/dist/types/grid-search.js +2 -0
- package/dist/types/grid-search.js.map +1 -0
- package/dist/types/hooks.d.ts +3 -3
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/links.d.ts +3 -6
- package/dist/types/links.d.ts.map +1 -1
- package/dist/types/lists.d.ts +68 -3
- package/dist/types/lists.d.ts.map +1 -1
- package/dist/types/map-3d.d.ts +126 -0
- package/dist/types/map-3d.d.ts.map +1 -0
- package/dist/types/map-3d.js +2 -0
- package/dist/types/map-3d.js.map +1 -0
- package/dist/types/map-earth.d.ts +34 -0
- package/dist/types/map-earth.d.ts.map +1 -0
- package/dist/types/map-earth.js +2 -0
- package/dist/types/map-earth.js.map +1 -0
- package/dist/types/map-layers.d.ts +63 -0
- package/dist/types/map-layers.d.ts.map +1 -0
- package/dist/types/map-layers.js +2 -0
- package/dist/types/map-layers.js.map +1 -0
- package/dist/types/mobility.d.ts +121 -0
- package/dist/types/mobility.d.ts.map +1 -0
- package/dist/types/mobility.js +3 -0
- package/dist/types/mobility.js.map +1 -0
- package/dist/types/panorama.d.ts +123 -0
- package/dist/types/panorama.d.ts.map +1 -1
- package/dist/types/photos.d.ts +12 -0
- package/dist/types/photos.d.ts.map +1 -1
- package/dist/types/photos.js +2 -1
- package/dist/types/photos.js.map +1 -1
- package/dist/types/place-attributes.d.ts +15 -0
- package/dist/types/place-attributes.d.ts.map +1 -0
- package/dist/types/place-attributes.js +2 -0
- package/dist/types/place-attributes.js.map +1 -0
- package/dist/types/place-extended.d.ts +406 -0
- package/dist/types/place-extended.d.ts.map +1 -0
- package/dist/types/place-extended.js +18 -0
- package/dist/types/place-extended.js.map +1 -0
- package/dist/types/protobuf.d.ts +1 -1
- package/dist/types/protobuf.js +1 -1
- package/dist/types/reviews.d.ts +28 -1
- package/dist/types/reviews.d.ts.map +1 -1
- package/dist/types/reviews.js.map +1 -1
- package/dist/types/route-optimization.d.ts +56 -0
- package/dist/types/route-optimization.d.ts.map +1 -0
- package/dist/types/route-optimization.js +2 -0
- package/dist/types/route-optimization.js.map +1 -0
- package/dist/types/search-along-route.d.ts +49 -0
- package/dist/types/search-along-route.d.ts.map +1 -0
- package/dist/types/search-along-route.js +2 -0
- package/dist/types/search-along-route.js.map +1 -0
- package/dist/types/search-filters.d.ts +1 -1
- package/dist/types/search-filters.js +1 -1
- package/dist/types/suggest.d.ts +23 -2
- package/dist/types/suggest.d.ts.map +1 -1
- package/dist/types/tiles.d.ts +40 -0
- package/dist/types/tiles.d.ts.map +1 -1
- package/dist/types/traffic.d.ts +58 -1
- package/dist/types/traffic.d.ts.map +1 -1
- package/dist/types/transit.d.ts +160 -1
- package/dist/types/transit.d.ts.map +1 -1
- package/dist/types/transit.js +0 -1
- package/dist/types/transit.js.map +1 -1
- package/dist/types/viewport.d.ts +159 -0
- package/dist/types/viewport.d.ts.map +1 -0
- package/dist/types/viewport.js +3 -0
- package/dist/types/viewport.js.map +1 -0
- package/dist/utils/async.d.ts +44 -0
- package/dist/utils/async.d.ts.map +1 -0
- package/dist/utils/async.js +132 -0
- package/dist/utils/async.js.map +1 -0
- package/dist/utils/encoded-polyline.d.ts +43 -0
- package/dist/utils/encoded-polyline.d.ts.map +1 -1
- package/dist/utils/encoded-polyline.js +71 -0
- package/dist/utils/encoded-polyline.js.map +1 -1
- package/dist/utils/env.d.ts +6 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/{load-env.js → env.js} +32 -7
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/geo.d.ts +12 -0
- package/dist/utils/geo.d.ts.map +1 -1
- package/dist/utils/geo.js +20 -0
- package/dist/utils/geo.js.map +1 -1
- package/dist/utils/hooks.d.ts +2 -3
- package/dist/utils/hooks.d.ts.map +1 -1
- package/dist/utils/hooks.js +1 -1
- package/dist/utils/hooks.js.map +1 -1
- package/dist/utils/ids.d.ts +1 -0
- package/dist/utils/ids.d.ts.map +1 -1
- package/dist/utils/ids.js +10 -0
- package/dist/utils/ids.js.map +1 -1
- package/dist/utils/net.d.ts +46 -0
- package/dist/utils/net.d.ts.map +1 -0
- package/dist/utils/net.js +150 -0
- package/dist/utils/net.js.map +1 -0
- package/dist/utils/payload.d.ts +22 -0
- package/dist/utils/payload.d.ts.map +1 -0
- package/dist/utils/{chunked-decoder.js → payload.js} +80 -2
- package/dist/utils/payload.js.map +1 -0
- package/dist/utils/place-ref.d.ts +40 -3
- package/dist/utils/place-ref.d.ts.map +1 -1
- package/dist/utils/place-ref.js +94 -2
- package/dist/utils/place-ref.js.map +1 -1
- package/package.json +8 -5
- package/dist/client/product-namespaces.d.ts +0 -30
- package/dist/client/product-namespaces.d.ts.map +0 -1
- package/dist/client/product-namespaces.js +0 -47
- package/dist/client/product-namespaces.js.map +0 -1
- package/dist/parsers/elevation-directions.d.ts +0 -18
- package/dist/parsers/elevation-directions.d.ts.map +0 -1
- package/dist/parsers/elevation-directions.js +0 -102
- package/dist/parsers/elevation-directions.js.map +0 -1
- package/dist/parsers/passiveassist.d.ts +0 -10
- package/dist/parsers/passiveassist.d.ts.map +0 -1
- package/dist/parsers/passiveassist.js +0 -61
- package/dist/parsers/passiveassist.js.map +0 -1
- package/dist/parsers/review-aggregates.d.ts +0 -7
- package/dist/parsers/review-aggregates.d.ts.map +0 -1
- package/dist/parsers/review-aggregates.js +0 -18
- package/dist/parsers/review-aggregates.js.map +0 -1
- package/dist/parsers/review-client-filters.d.ts +0 -8
- package/dist/parsers/review-client-filters.d.ts.map +0 -1
- package/dist/parsers/review-client-filters.js +0 -28
- package/dist/parsers/review-client-filters.js.map +0 -1
- package/dist/parsers/search-client-filters.d.ts +0 -7
- package/dist/parsers/search-client-filters.d.ts.map +0 -1
- package/dist/parsers/search-client-filters.js +0 -44
- package/dist/parsers/search-client-filters.js.map +0 -1
- package/dist/parsers/search-pagination.d.ts +0 -12
- package/dist/parsers/search-pagination.d.ts.map +0 -1
- package/dist/parsers/search-pagination.js +0 -34
- package/dist/parsers/search-pagination.js.map +0 -1
- package/dist/parsers/timezone-geocode.d.ts +0 -20
- package/dist/parsers/timezone-geocode.d.ts.map +0 -1
- package/dist/parsers/timezone-geocode.js +0 -96
- package/dist/parsers/timezone-geocode.js.map +0 -1
- package/dist/parsers/ugc-aggregates.d.ts +0 -9
- package/dist/parsers/ugc-aggregates.d.ts.map +0 -1
- package/dist/parsers/ugc-aggregates.js +0 -23
- package/dist/parsers/ugc-aggregates.js.map +0 -1
- package/dist/rpc/app-options.d.ts +0 -25
- package/dist/rpc/app-options.d.ts.map +0 -1
- package/dist/rpc/app-options.js.map +0 -1
- package/dist/rpc/batchexecute-args.d.ts +0 -30
- package/dist/rpc/batchexecute-args.d.ts.map +0 -1
- package/dist/rpc/batchexecute-args.js +0 -35
- package/dist/rpc/batchexecute-args.js.map +0 -1
- package/dist/rpc/boq-reviews.d.ts +0 -16
- package/dist/rpc/boq-reviews.d.ts.map +0 -1
- package/dist/rpc/boq-reviews.js +0 -45
- package/dist/rpc/boq-reviews.js.map +0 -1
- package/dist/rpc/descriptor-registry.d.ts.map +0 -1
- package/dist/rpc/descriptor-registry.js +0 -47
- package/dist/rpc/descriptor-registry.js.map +0 -1
- package/dist/rpc/lists-pb.d.ts +0 -20
- package/dist/rpc/lists-pb.d.ts.map +0 -1
- package/dist/rpc/lists-pb.js +0 -20
- package/dist/rpc/lists-pb.js.map +0 -1
- package/dist/rpc/nxa.d.ts +0 -13
- package/dist/rpc/nxa.d.ts.map +0 -1
- package/dist/rpc/nxa.js +0 -44
- package/dist/rpc/nxa.js.map +0 -1
- package/dist/rpc/passiveassist-pb.d.ts +0 -21
- package/dist/rpc/passiveassist-pb.d.ts.map +0 -1
- package/dist/rpc/passiveassist-pb.js +0 -24
- package/dist/rpc/passiveassist-pb.js.map +0 -1
- package/dist/rpc/photo-category-tokens.d.ts +0 -29
- package/dist/rpc/photo-category-tokens.d.ts.map +0 -1
- package/dist/rpc/photo-category-tokens.js +0 -97
- package/dist/rpc/photo-category-tokens.js.map +0 -1
- package/dist/rpc/reveal-pb.d.ts +0 -26
- package/dist/rpc/reveal-pb.d.ts.map +0 -1
- package/dist/rpc/reveal-pb.js +0 -32
- package/dist/rpc/reveal-pb.js.map +0 -1
- package/dist/rpc/suggest-pb.d.ts +0 -34
- package/dist/rpc/suggest-pb.d.ts.map +0 -1
- package/dist/rpc/suggest-pb.js +0 -42
- package/dist/rpc/suggest-pb.js.map +0 -1
- package/dist/rpc/tiles-pb.d.ts +0 -45
- package/dist/rpc/tiles-pb.d.ts.map +0 -1
- package/dist/rpc/tiles-pb.js +0 -71
- package/dist/rpc/tiles-pb.js.map +0 -1
- package/dist/services/batch-url.d.ts +0 -18
- package/dist/services/batch-url.d.ts.map +0 -1
- package/dist/services/batch-url.js +0 -30
- package/dist/services/batch-url.js.map +0 -1
- package/dist/services/categories.d.ts +0 -21
- package/dist/services/categories.d.ts.map +0 -1
- package/dist/services/categories.js +0 -43
- package/dist/services/categories.js.map +0 -1
- package/dist/services/passiveassist.d.ts +0 -21
- package/dist/services/passiveassist.d.ts.map +0 -1
- package/dist/services/passiveassist.js +0 -70
- package/dist/services/passiveassist.js.map +0 -1
- package/dist/services/reveal.d.ts +0 -15
- package/dist/services/reveal.d.ts.map +0 -1
- package/dist/services/reveal.js +0 -41
- package/dist/services/reveal.js.map +0 -1
- package/dist/services/suggest.d.ts +0 -12
- package/dist/services/suggest.d.ts.map +0 -1
- package/dist/services/suggest.js +0 -36
- package/dist/services/suggest.js.map +0 -1
- package/dist/services/timezone.d.ts +0 -19
- package/dist/services/timezone.d.ts.map +0 -1
- package/dist/services/timezone.js +0 -91
- package/dist/services/timezone.js.map +0 -1
- package/dist/services/ugc-aggregates.d.ts +0 -17
- package/dist/services/ugc-aggregates.d.ts.map +0 -1
- package/dist/services/ugc-aggregates.js +0 -30
- package/dist/services/ugc-aggregates.js.map +0 -1
- package/dist/types/distance-matrix.d.ts +0 -40
- package/dist/types/distance-matrix.d.ts.map +0 -1
- package/dist/types/distance-matrix.js +0 -2
- package/dist/types/distance-matrix.js.map +0 -1
- package/dist/types/elevation.d.ts +0 -59
- package/dist/types/elevation.d.ts.map +0 -1
- package/dist/types/elevation.js +0 -2
- package/dist/types/elevation.js.map +0 -1
- package/dist/types/passiveassist.d.ts +0 -50
- package/dist/types/passiveassist.d.ts.map +0 -1
- package/dist/types/passiveassist.js +0 -2
- package/dist/types/passiveassist.js.map +0 -1
- package/dist/types/reveal.d.ts +0 -46
- package/dist/types/reveal.d.ts.map +0 -1
- package/dist/types/reveal.js +0 -2
- package/dist/types/reveal.js.map +0 -1
- package/dist/types/timezone.d.ts +0 -36
- package/dist/types/timezone.d.ts.map +0 -1
- package/dist/types/timezone.js +0 -2
- package/dist/types/timezone.js.map +0 -1
- package/dist/types/ugc-aggregates.d.ts +0 -14
- package/dist/types/ugc-aggregates.d.ts.map +0 -1
- package/dist/types/ugc-aggregates.js +0 -2
- package/dist/types/ugc-aggregates.js.map +0 -1
- package/dist/utils/abort.d.ts +0 -7
- package/dist/utils/abort.d.ts.map +0 -1
- package/dist/utils/abort.js +0 -43
- package/dist/utils/abort.js.map +0 -1
- package/dist/utils/chunked-decoder.d.ts +0 -9
- package/dist/utils/chunked-decoder.d.ts.map +0 -1
- package/dist/utils/chunked-decoder.js.map +0 -1
- package/dist/utils/coords.d.ts +0 -24
- package/dist/utils/coords.d.ts.map +0 -1
- package/dist/utils/coords.js +0 -37
- package/dist/utils/coords.js.map +0 -1
- package/dist/utils/feature-id.d.ts +0 -2
- package/dist/utils/feature-id.d.ts.map +0 -1
- package/dist/utils/feature-id.js +0 -11
- package/dist/utils/feature-id.js.map +0 -1
- package/dist/utils/load-env.d.ts +0 -7
- package/dist/utils/load-env.d.ts.map +0 -1
- package/dist/utils/load-env.js.map +0 -1
- package/dist/utils/pooled.d.ts +0 -8
- package/dist/utils/pooled.d.ts.map +0 -1
- package/dist/utils/pooled.js +0 -27
- package/dist/utils/pooled.js.map +0 -1
- package/dist/utils/request-context.d.ts +0 -9
- package/dist/utils/request-context.d.ts.map +0 -1
- package/dist/utils/request-context.js +0 -12
- package/dist/utils/request-context.js.map +0 -1
- package/dist/utils/request-scheduler.d.ts +0 -28
- package/dist/utils/request-scheduler.d.ts.map +0 -1
- package/dist/utils/request-scheduler.js +0 -58
- package/dist/utils/request-scheduler.js.map +0 -1
- package/dist/utils/response-parser.d.ts +0 -7
- package/dist/utils/response-parser.d.ts.map +0 -1
- package/dist/utils/response-parser.js +0 -50
- package/dist/utils/response-parser.js.map +0 -1
- package/dist/utils/retry-backoff.d.ts +0 -5
- package/dist/utils/retry-backoff.d.ts.map +0 -1
- package/dist/utils/retry-backoff.js +0 -23
- package/dist/utils/retry-backoff.js.map +0 -1
- package/dist/utils/safe-get.d.ts +0 -6
- package/dist/utils/safe-get.d.ts.map +0 -1
- package/dist/utils/safe-get.js +0 -29
- package/dist/utils/safe-get.js.map +0 -1
- package/dist/utils/throttle-detection.d.ts +0 -17
- package/dist/utils/throttle-detection.d.ts.map +0 -1
- package/dist/utils/throttle-detection.js +0 -71
- package/dist/utils/throttle-detection.js.map +0 -1
- package/dist/utils/ttl-cache.d.ts +0 -17
- package/dist/utils/ttl-cache.d.ts.map +0 -1
- package/dist/utils/ttl-cache.js +0 -43
- package/dist/utils/ttl-cache.js.map +0 -1
- /package/{assets → .github/assets}/banner.png +0 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import { GMapsError } from '../types/common.js';
|
|
2
|
+
import { readJpegDimensions } from '../parsers/tiles.js';
|
|
3
|
+
import { EARTH_RADIUS_METERS, NODE_FLAGS, bulkMetadataUrl, ecefToLatLng, latLngToEcef, nodeDataUrl, obbCentrality, obbIntersectsSegment, parseBulkMetadata, parseNodeData, parsePlanetoidMetadata, planetoidMetadataUrl, rocktreeBase, stripToTriangles, } from '../rpc/earth-rocktree.js';
|
|
4
|
+
const ATTRIBUTION = 'Imagery ©2026 Google, Airbus, Maxar Technologies';
|
|
5
|
+
const DETAIL_METERS_PER_TEXEL = {
|
|
6
|
+
low: 40,
|
|
7
|
+
medium: 10,
|
|
8
|
+
high: 2,
|
|
9
|
+
max: 0.25,
|
|
10
|
+
};
|
|
11
|
+
const RESOLUTION_STEP_METERS = { low: 32, medium: 16, high: 8 };
|
|
12
|
+
/** Roof-height jump that splits one flood fill into two structures, in metres. */
|
|
13
|
+
const ROOF_STEP_METERS = 6;
|
|
14
|
+
/** Octree levels described by a single BulkMetadata payload. */
|
|
15
|
+
const BULK_LEVELS = 4;
|
|
16
|
+
/** Overlapping siblings to try per level before giving up on a branch. */
|
|
17
|
+
const MAX_BRANCHES = 8;
|
|
18
|
+
/** Hard cap on sampled terrain-grid cells; beyond this, callers should coarsen the box. */
|
|
19
|
+
const MAX_TERRAIN_GRID_CELLS = 4_000_000;
|
|
20
|
+
/** Throw when a bounds/step combination would rasterise an unmanageable height grid. */
|
|
21
|
+
function assertTerrainGridFits(widthMeters, heightMeters, step) {
|
|
22
|
+
const cells = Math.ceil(widthMeters / step + 1) * Math.ceil(heightMeters / step + 1);
|
|
23
|
+
if (!Number.isFinite(cells)) {
|
|
24
|
+
throw new GMapsError(`Invalid terrain grid dimensions (${widthMeters} x ${heightMeters} m).`);
|
|
25
|
+
}
|
|
26
|
+
if (cells > MAX_TERRAIN_GRID_CELLS) {
|
|
27
|
+
throw new GMapsError(`Requested terrain grid would hold ${(cells / 1e6).toFixed(1)}M cells ` +
|
|
28
|
+
`(${(widthMeters / 1000).toFixed(1)} x ${(heightMeters / 1000).toFixed(1)} km at ${step} m step). ` +
|
|
29
|
+
'Shrink the bounds, raise resolution to "low", or sample with getMesh directly.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Child bulks one descent may fetch before settling for what it has. */
|
|
33
|
+
const MAX_BULK_FETCHES = 24;
|
|
34
|
+
/** Chained bulks to follow; each adds four levels, so this reaches level 32. */
|
|
35
|
+
const MAX_BULK_DEPTH = 8;
|
|
36
|
+
const PROBE_MIN_ALT = -500;
|
|
37
|
+
const PROBE_MAX_ALT = 9000;
|
|
38
|
+
function verticalProbe(lat, lng, radius = EARTH_RADIUS_METERS) {
|
|
39
|
+
return {
|
|
40
|
+
low: latLngToEcef(lat, lng, PROBE_MIN_ALT, radius),
|
|
41
|
+
high: latLngToEcef(lat, lng, PROBE_MAX_ALT, radius),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Sub-segment of `probe` between two parameters, padded so it stays generous. */
|
|
45
|
+
function narrowProbe(probe, tMin, tMax) {
|
|
46
|
+
const pad = Math.max(0.002, (tMax - tMin) * 0.25);
|
|
47
|
+
const lo = Math.max(0, tMin - pad);
|
|
48
|
+
const hi = Math.min(1, tMax + pad);
|
|
49
|
+
return { low: pointAt(probe, lo), high: pointAt(probe, hi) };
|
|
50
|
+
}
|
|
51
|
+
function pointAt(probe, t) {
|
|
52
|
+
return [
|
|
53
|
+
probe.low[0] + (probe.high[0] - probe.low[0]) * t,
|
|
54
|
+
probe.low[1] + (probe.high[1] - probe.low[1]) * t,
|
|
55
|
+
probe.low[2] + (probe.high[2] - probe.low[2]) * t,
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Photorealistic 3D buildings and terrain.
|
|
60
|
+
*
|
|
61
|
+
* Maps renders 3D from Google Earth's "rocktree" octree at
|
|
62
|
+
* `kh.google.com/rt/earth` — the same mesh the Photorealistic 3D Tiles API
|
|
63
|
+
* bills for, served here without a key. Metadata arrives as an oriented
|
|
64
|
+
* bounding-box tree (`BulkMetadata`); each leaf publishes a `NodeData` payload
|
|
65
|
+
* holding a delta-packed vertex cube, a triangle strip and a 512×512 JPEG.
|
|
66
|
+
* See {@link file://src/rpc/earth-rocktree.ts} for the wire format.
|
|
67
|
+
*
|
|
68
|
+
* The mesh is *fused*: buildings, ground and vegetation are one surface, so
|
|
69
|
+
* {@link Map3dService.getBuildings} segments structures out of it rather than
|
|
70
|
+
* reading a building layer. Treat those footprints as derived, not authored.
|
|
71
|
+
*/
|
|
72
|
+
export class Map3dService {
|
|
73
|
+
http;
|
|
74
|
+
/** Per-planet root epochs and reference radii (rocktree serves earth, mars, moon). */
|
|
75
|
+
planetoids = new Map();
|
|
76
|
+
bulkCache = new Map();
|
|
77
|
+
constructor(http, _config) {
|
|
78
|
+
this.http = http;
|
|
79
|
+
}
|
|
80
|
+
async fetchProto(url) {
|
|
81
|
+
try {
|
|
82
|
+
const { bytes } = await this.http.getBytes(url, {
|
|
83
|
+
referer: 'https://earth.google.com/',
|
|
84
|
+
noRetry: true,
|
|
85
|
+
minBytes: 4,
|
|
86
|
+
});
|
|
87
|
+
return bytes;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async getPlanetoid(planet) {
|
|
94
|
+
const cached = this.planetoids.get(planet);
|
|
95
|
+
if (cached)
|
|
96
|
+
return cached;
|
|
97
|
+
const bytes = await this.fetchProto(planetoidMetadataUrl(rocktreeBase(planet)));
|
|
98
|
+
if (!bytes) {
|
|
99
|
+
throw new GMapsError(`${planet} octree unreachable: PlanetoidMetadata returned no payload`);
|
|
100
|
+
}
|
|
101
|
+
const parsed = parsePlanetoidMetadata(bytes, planet);
|
|
102
|
+
const entry = { rootEpoch: parsed.rootEpoch, radius: parsed.radius };
|
|
103
|
+
this.planetoids.set(planet, entry);
|
|
104
|
+
return entry;
|
|
105
|
+
}
|
|
106
|
+
async getBulk(path, epoch, planet) {
|
|
107
|
+
const key = `${planet}:${path}@${epoch}`;
|
|
108
|
+
const cached = this.bulkCache.get(key);
|
|
109
|
+
if (cached !== undefined)
|
|
110
|
+
return cached;
|
|
111
|
+
const bytes = await this.fetchProto(bulkMetadataUrl(path, epoch, rocktreeBase(planet)));
|
|
112
|
+
const parsed = bytes ? parseBulkMetadata(bytes) : null;
|
|
113
|
+
this.bulkCache.set(key, parsed);
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Walk the octree towards a point until the node's ground sampling distance
|
|
118
|
+
* meets `targetMetersPerTexel`, returning the finest node that carries mesh.
|
|
119
|
+
*
|
|
120
|
+
* Sibling octants overlap — their boxes hug the terrain shell instead of
|
|
121
|
+
* tiling space — so a point can sit inside several boxes at one level and
|
|
122
|
+
* only one of those branches continues to street-level detail. The walk
|
|
123
|
+
* therefore tries candidates most-central first and backtracks instead of
|
|
124
|
+
* committing to the first hit.
|
|
125
|
+
*/
|
|
126
|
+
async descend(probe, targetMetersPerTexel, planet) {
|
|
127
|
+
const { rootEpoch } = await this.getPlanetoid(planet);
|
|
128
|
+
return this.descendBulk('', rootEpoch, probe, targetMetersPerTexel, 0, {
|
|
129
|
+
fetches: 0,
|
|
130
|
+
}, planet);
|
|
131
|
+
}
|
|
132
|
+
async descendBulk(bulkPath, bulkEpoch, probe, target, depth, budget, planet) {
|
|
133
|
+
if (depth > MAX_BULK_DEPTH)
|
|
134
|
+
return null;
|
|
135
|
+
// Overlapping siblings make the search a tree, not a path; without a
|
|
136
|
+
// budget a dense city would fan out into thousands of bulk fetches.
|
|
137
|
+
if (depth > 0 && budget.fetches++ >= MAX_BULK_FETCHES)
|
|
138
|
+
return null;
|
|
139
|
+
const bulk = await this.getBulk(bulkPath, bulkEpoch, planet);
|
|
140
|
+
if (!bulk)
|
|
141
|
+
return null;
|
|
142
|
+
const finer = (a, b) => {
|
|
143
|
+
if (!a)
|
|
144
|
+
return b;
|
|
145
|
+
if (!b)
|
|
146
|
+
return a;
|
|
147
|
+
return b.node.metersPerTexel < a.node.metersPerTexel ? b : a;
|
|
148
|
+
};
|
|
149
|
+
const walk = async (relPath, level, node, probe) => {
|
|
150
|
+
let best = node && node.hasData ? { path: bulkPath + relPath, node } : null;
|
|
151
|
+
if (node && node.metersPerTexel > 0 && node.metersPerTexel <= target)
|
|
152
|
+
return best;
|
|
153
|
+
// A bulk only describes four levels; deeper detail lives in a child bulk
|
|
154
|
+
// rooted at this node.
|
|
155
|
+
if (level === BULK_LEVELS) {
|
|
156
|
+
if (!node)
|
|
157
|
+
return best;
|
|
158
|
+
const deeper = await this.descendBulk(bulkPath + relPath, node.bulkMetadataEpoch, probe, target, depth + 1, budget, planet);
|
|
159
|
+
return finer(best, deeper);
|
|
160
|
+
}
|
|
161
|
+
const children = bulk.nodes
|
|
162
|
+
.filter((n) => n.level === level + 1 && n.path.startsWith(relPath))
|
|
163
|
+
.map((n) => ({ node: n, hit: obbIntersectsSegment(n, probe.low, probe.high) }))
|
|
164
|
+
.filter((c) => c.hit.hit)
|
|
165
|
+
.sort((a, b) => obbCentrality(a.node, pointAt(probe, a.hit.t)) -
|
|
166
|
+
obbCentrality(b.node, pointAt(probe, b.hit.t)))
|
|
167
|
+
.slice(0, MAX_BRANCHES);
|
|
168
|
+
for (const { node: child, hit } of children) {
|
|
169
|
+
// Narrow the probe to the slice of the line this box actually covers,
|
|
170
|
+
// so the next level searches the altitude band holding the geometry
|
|
171
|
+
// instead of the whole troposphere.
|
|
172
|
+
const narrowed = narrowProbe(probe, hit.tMin, hit.tMax);
|
|
173
|
+
best = finer(best, await walk(child.path, level + 1, child, narrowed));
|
|
174
|
+
if (best && best.node.metersPerTexel > 0 && best.node.metersPerTexel <= target)
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
return best;
|
|
178
|
+
};
|
|
179
|
+
return walk('', 0, null, probe);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Fetch the photorealistic mesh covering `bounds`.
|
|
183
|
+
*
|
|
184
|
+
* Sampling walks a grid of probe points across the box so a request wider
|
|
185
|
+
* than one octree node still returns every node it touches, deduped by path.
|
|
186
|
+
*/
|
|
187
|
+
async getMesh(options) {
|
|
188
|
+
const bounds = normalizeBounds(options.bounds);
|
|
189
|
+
const target = options.metersPerTexel ?? DETAIL_METERS_PER_TEXEL[options.detail ?? 'high'];
|
|
190
|
+
const maxTiles = options.maxTiles ?? 16;
|
|
191
|
+
const planet = options.planet ?? 'earth';
|
|
192
|
+
const { radius } = await this.getPlanetoid(planet);
|
|
193
|
+
const probes = probeGrid(bounds, maxTiles);
|
|
194
|
+
const resolved = new Map();
|
|
195
|
+
for (const probe of probes) {
|
|
196
|
+
if (resolved.size >= maxTiles)
|
|
197
|
+
break;
|
|
198
|
+
const hit = await this.descend(verticalProbe(probe.lat, probe.lng, radius), target, planet);
|
|
199
|
+
if (hit && !resolved.has(hit.path))
|
|
200
|
+
resolved.set(hit.path, hit);
|
|
201
|
+
}
|
|
202
|
+
if (resolved.size === 0) {
|
|
203
|
+
throw new GMapsError(`No photorealistic 3D coverage for the requested bounds ` +
|
|
204
|
+
`(${bounds.sw.lat.toFixed(4)},${bounds.sw.lng.toFixed(4)} to ` +
|
|
205
|
+
`${bounds.ne.lat.toFixed(4)},${bounds.ne.lng.toFixed(4)}). ` +
|
|
206
|
+
'Coverage is city-scale; oceans and most rural areas publish terrain only at low detail.');
|
|
207
|
+
}
|
|
208
|
+
const tiles = [];
|
|
209
|
+
for (const entry of resolved.values()) {
|
|
210
|
+
const tile = await this.fetchTile(entry, options.includeTextures ?? false, planet, radius);
|
|
211
|
+
if (tile)
|
|
212
|
+
tiles.push(tile);
|
|
213
|
+
}
|
|
214
|
+
if (tiles.length === 0) {
|
|
215
|
+
throw new GMapsError('Octree resolved nodes but none returned mesh data');
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
tiles,
|
|
219
|
+
bounds,
|
|
220
|
+
level: Math.max(...tiles.map((t) => t.path.length)),
|
|
221
|
+
vertexCount: tiles.reduce((sum, t) => sum + t.vertices.length, 0),
|
|
222
|
+
triangleCount: tiles.reduce((sum, t) => sum + t.triangles.length, 0),
|
|
223
|
+
attribution: ATTRIBUTION,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
async fetchTile(entry, includeTextures, planet, radius) {
|
|
227
|
+
const { node, path } = entry;
|
|
228
|
+
// `!3u{imageryEpoch}` is only honoured when the node flags request it —
|
|
229
|
+
// sending it otherwise makes the server answer 404.
|
|
230
|
+
const bytes = await this.fetchProto(nodeDataUrl({
|
|
231
|
+
path,
|
|
232
|
+
epoch: node.epoch,
|
|
233
|
+
textureFormat: 1,
|
|
234
|
+
imageryEpoch: (node.flags & NODE_FLAGS.USE_IMAGERY_EPOCH) !== 0 ? node.imageryEpoch : undefined,
|
|
235
|
+
}, rocktreeBase(planet)));
|
|
236
|
+
if (!bytes)
|
|
237
|
+
return null;
|
|
238
|
+
const data = parseNodeData(bytes);
|
|
239
|
+
const vertices = [];
|
|
240
|
+
const triangles = [];
|
|
241
|
+
let uvs = null;
|
|
242
|
+
let texture = null;
|
|
243
|
+
for (const mesh of data.meshes) {
|
|
244
|
+
const base = vertices.length;
|
|
245
|
+
for (const p of mesh.positions) {
|
|
246
|
+
const ll = ecefToLatLng(p, radius);
|
|
247
|
+
vertices.push({ lat: ll.lat, lng: ll.lng, alt: ll.alt });
|
|
248
|
+
}
|
|
249
|
+
for (const [a, b, c] of stripToTriangles(mesh.strip)) {
|
|
250
|
+
triangles.push([base + a, base + b, base + c]);
|
|
251
|
+
}
|
|
252
|
+
if (mesh.uvs)
|
|
253
|
+
uvs = (uvs ?? []).concat(mesh.uvs);
|
|
254
|
+
if (includeTextures && !texture && mesh.texture) {
|
|
255
|
+
// Some nodes omit the width/height fields — sniff them from the JPEG SOFn header.
|
|
256
|
+
let width = mesh.texture.width;
|
|
257
|
+
let height = mesh.texture.height;
|
|
258
|
+
if (!width || !height) {
|
|
259
|
+
const dims = readJpegDimensions(mesh.texture.data);
|
|
260
|
+
width = width || dims?.width || 0;
|
|
261
|
+
height = height || dims?.height || 0;
|
|
262
|
+
}
|
|
263
|
+
texture = {
|
|
264
|
+
format: mesh.texture.format === 1 ? 'jpeg' : 'unknown',
|
|
265
|
+
width,
|
|
266
|
+
height,
|
|
267
|
+
bytes: mesh.texture.data,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (vertices.length === 0)
|
|
272
|
+
return null;
|
|
273
|
+
return {
|
|
274
|
+
path,
|
|
275
|
+
metersPerTexel: node.metersPerTexel,
|
|
276
|
+
vertices,
|
|
277
|
+
triangles,
|
|
278
|
+
uvs,
|
|
279
|
+
texture,
|
|
280
|
+
bounds: boundsOf(vertices),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Sample the mesh into a height grid.
|
|
285
|
+
*
|
|
286
|
+
* Heights come off the photorealistic surface, so they include buildings and
|
|
287
|
+
* tree canopy. For bare ground use a low `detail` — coarse nodes carry
|
|
288
|
+
* terrain only.
|
|
289
|
+
*/
|
|
290
|
+
async getTerrain(options) {
|
|
291
|
+
const bounds = normalizeBounds(options.bounds);
|
|
292
|
+
const step = RESOLUTION_STEP_METERS[options.resolution ?? 'medium'];
|
|
293
|
+
const frame0 = localFrame(bounds);
|
|
294
|
+
assertTerrainGridFits(frame0.widthMeters, frame0.heightMeters, step);
|
|
295
|
+
const mesh = await this.getMesh({
|
|
296
|
+
bounds,
|
|
297
|
+
detail: options.detail ?? 'high',
|
|
298
|
+
maxTiles: options.maxTiles ?? 16,
|
|
299
|
+
planet: options.planet,
|
|
300
|
+
});
|
|
301
|
+
const frame = localFrame(bounds);
|
|
302
|
+
const cols = Math.max(2, Math.ceil(frame.widthMeters / step) + 1);
|
|
303
|
+
const rows = Math.max(2, Math.ceil(frame.heightMeters / step) + 1);
|
|
304
|
+
const { top: heights, minAlt, maxAlt } = rasterize(mesh, frame, step, cols, rows);
|
|
305
|
+
const objMesh = options.includeMesh === false ? Buffer.alloc(0) : Buffer.from(gridToObj(heights, cols, rows, step), 'utf8');
|
|
306
|
+
return {
|
|
307
|
+
mesh: objMesh,
|
|
308
|
+
format: 'obj',
|
|
309
|
+
bounds,
|
|
310
|
+
grid: { cols, rows, heights, stepMeters: step },
|
|
311
|
+
minAlt: Number.isFinite(minAlt) ? minAlt : 0,
|
|
312
|
+
maxAlt: Number.isFinite(maxAlt) ? maxAlt : 0,
|
|
313
|
+
attribution: ATTRIBUTION,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Segment building-like structures out of the fused mesh.
|
|
318
|
+
*
|
|
319
|
+
* The octree publishes no building layer, so this rasterises mesh vertices
|
|
320
|
+
* into a 4 m grid, estimates local ground from the low percentile of a
|
|
321
|
+
* neighbourhood window, and groups connected cells that stand `minHeight`
|
|
322
|
+
* above it. Outlines are convex hulls of the occupied cells — massing, not
|
|
323
|
+
* surveyed footprints.
|
|
324
|
+
*/
|
|
325
|
+
async getBuildings(options) {
|
|
326
|
+
const bounds = normalizeBounds(options.bounds);
|
|
327
|
+
const minHeight = options.minHeight ?? 4;
|
|
328
|
+
const frame0 = localFrame(bounds);
|
|
329
|
+
assertTerrainGridFits(frame0.widthMeters, frame0.heightMeters, 4);
|
|
330
|
+
const mesh = await this.getMesh({
|
|
331
|
+
bounds,
|
|
332
|
+
detail: options.detail ?? 'high',
|
|
333
|
+
maxTiles: options.maxTiles ?? 16,
|
|
334
|
+
planet: options.planet,
|
|
335
|
+
});
|
|
336
|
+
const cell = 4;
|
|
337
|
+
const frame = localFrame(bounds);
|
|
338
|
+
const cols = Math.max(2, Math.ceil(frame.widthMeters / cell) + 1);
|
|
339
|
+
const rows = Math.max(2, Math.ceil(frame.heightMeters / cell) + 1);
|
|
340
|
+
const { top, low } = rasterize(mesh, frame, cell, cols, rows);
|
|
341
|
+
// Ground = the lowest surface within a ~40 m window, which survives blocks
|
|
342
|
+
// where every cell is roofed.
|
|
343
|
+
const window = Math.round(20 / cell);
|
|
344
|
+
const ground = new Array(cols * rows).fill(null);
|
|
345
|
+
for (let row = 0; row < rows; row++) {
|
|
346
|
+
for (let col = 0; col < cols; col++) {
|
|
347
|
+
let best = null;
|
|
348
|
+
for (let dr = -window; dr <= window; dr++) {
|
|
349
|
+
const r = row + dr;
|
|
350
|
+
if (r < 0 || r >= rows)
|
|
351
|
+
continue;
|
|
352
|
+
for (let dc = -window; dc <= window; dc++) {
|
|
353
|
+
const c = col + dc;
|
|
354
|
+
if (c < 0 || c >= cols)
|
|
355
|
+
continue;
|
|
356
|
+
const value = low[r * cols + c];
|
|
357
|
+
if (value === null || value === undefined)
|
|
358
|
+
continue;
|
|
359
|
+
if (best === null || value < best)
|
|
360
|
+
best = value;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
ground[row * cols + col] = best;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const elevated = new Uint8Array(cols * rows);
|
|
367
|
+
for (let i = 0; i < top.length; i++) {
|
|
368
|
+
const t = top[i];
|
|
369
|
+
const g = ground[i];
|
|
370
|
+
if (t === null || t === undefined || g === null || g === undefined)
|
|
371
|
+
continue;
|
|
372
|
+
if (t - g >= minHeight)
|
|
373
|
+
elevated[i] = 1;
|
|
374
|
+
}
|
|
375
|
+
const buildings = [];
|
|
376
|
+
const seen = new Uint8Array(cols * rows);
|
|
377
|
+
for (let start = 0; start < elevated.length; start++) {
|
|
378
|
+
if (!elevated[start] || seen[start])
|
|
379
|
+
continue;
|
|
380
|
+
const stack = [start];
|
|
381
|
+
seen[start] = 1;
|
|
382
|
+
const component = [];
|
|
383
|
+
while (stack.length) {
|
|
384
|
+
const i = stack.pop();
|
|
385
|
+
component.push(i);
|
|
386
|
+
const row = Math.floor(i / cols);
|
|
387
|
+
const col = i % cols;
|
|
388
|
+
const neighbours = [
|
|
389
|
+
row > 0 ? i - cols : -1,
|
|
390
|
+
row < rows - 1 ? i + cols : -1,
|
|
391
|
+
col > 0 ? i - 1 : -1,
|
|
392
|
+
col < cols - 1 ? i + 1 : -1,
|
|
393
|
+
];
|
|
394
|
+
const here = top[i];
|
|
395
|
+
for (const n of neighbours) {
|
|
396
|
+
if (n < 0 || seen[n] || !elevated[n])
|
|
397
|
+
continue;
|
|
398
|
+
// Adjacent roofs at very different heights are different buildings.
|
|
399
|
+
// Without this, one flood fill swallows a whole city block.
|
|
400
|
+
const there = top[n];
|
|
401
|
+
if (isNumber(here) && isNumber(there) && Math.abs(here - there) > ROOF_STEP_METERS)
|
|
402
|
+
continue;
|
|
403
|
+
seen[n] = 1;
|
|
404
|
+
stack.push(n);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Two cells is noise on a photogrammetric surface; three is a structure.
|
|
408
|
+
if (component.length < 3)
|
|
409
|
+
continue;
|
|
410
|
+
const points = component.map((i) => {
|
|
411
|
+
const row = Math.floor(i / cols);
|
|
412
|
+
const col = i % cols;
|
|
413
|
+
return frame.unproject(col * cell, row * cell);
|
|
414
|
+
});
|
|
415
|
+
const groundAlt = median(component.map((i) => ground[i]).filter(isNumber));
|
|
416
|
+
const roof = percentile(component.map((i) => top[i]).filter(isNumber), 0.95);
|
|
417
|
+
const outline = convexHull(points);
|
|
418
|
+
const centerLat = points.reduce((s, p) => s + p.lat, 0) / points.length;
|
|
419
|
+
const centerLng = points.reduce((s, p) => s + p.lng, 0) / points.length;
|
|
420
|
+
buildings.push({
|
|
421
|
+
id: `mesh-${mesh.tiles[0]?.path ?? '0'}-${start}`,
|
|
422
|
+
outline,
|
|
423
|
+
height: Math.round((roof - groundAlt) * 10) / 10,
|
|
424
|
+
centerLat,
|
|
425
|
+
centerLng,
|
|
426
|
+
areaSqM: component.length * cell * cell,
|
|
427
|
+
groundAlt: Math.round(groundAlt * 10) / 10,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
const sort = options.sort ?? 'height';
|
|
431
|
+
buildings.sort((a, b) => {
|
|
432
|
+
if (sort === 'area')
|
|
433
|
+
return b.areaSqM - a.areaSqM;
|
|
434
|
+
if (sort === 'prominence')
|
|
435
|
+
return b.height * b.areaSqM - a.height * a.areaSqM;
|
|
436
|
+
return b.height - a.height;
|
|
437
|
+
});
|
|
438
|
+
return buildings;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function isNumber(value) {
|
|
442
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
443
|
+
}
|
|
444
|
+
function normalizeBounds(bounds) {
|
|
445
|
+
return {
|
|
446
|
+
ne: { lat: Math.max(bounds.ne.lat, bounds.sw.lat), lng: Math.max(bounds.ne.lng, bounds.sw.lng) },
|
|
447
|
+
sw: { lat: Math.min(bounds.ne.lat, bounds.sw.lat), lng: Math.min(bounds.ne.lng, bounds.sw.lng) },
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function boundsOf(vertices) {
|
|
451
|
+
let minLat = Infinity;
|
|
452
|
+
let maxLat = -Infinity;
|
|
453
|
+
let minLng = Infinity;
|
|
454
|
+
let maxLng = -Infinity;
|
|
455
|
+
for (const v of vertices) {
|
|
456
|
+
if (v.lat < minLat)
|
|
457
|
+
minLat = v.lat;
|
|
458
|
+
if (v.lat > maxLat)
|
|
459
|
+
maxLat = v.lat;
|
|
460
|
+
if (v.lng < minLng)
|
|
461
|
+
minLng = v.lng;
|
|
462
|
+
if (v.lng > maxLng)
|
|
463
|
+
maxLng = v.lng;
|
|
464
|
+
}
|
|
465
|
+
return { ne: { lat: maxLat, lng: maxLng }, sw: { lat: minLat, lng: minLng } };
|
|
466
|
+
}
|
|
467
|
+
/** Probe points spread across the box, centre first so small boxes cost one walk. */
|
|
468
|
+
function probeGrid(bounds, maxTiles) {
|
|
469
|
+
const side = Math.max(1, Math.min(5, Math.ceil(Math.sqrt(maxTiles))));
|
|
470
|
+
const out = [
|
|
471
|
+
{ lat: (bounds.ne.lat + bounds.sw.lat) / 2, lng: (bounds.ne.lng + bounds.sw.lng) / 2 },
|
|
472
|
+
];
|
|
473
|
+
for (let row = 0; row < side; row++) {
|
|
474
|
+
for (let col = 0; col < side; col++) {
|
|
475
|
+
const fy = side === 1 ? 0.5 : (row + 0.5) / side;
|
|
476
|
+
const fx = side === 1 ? 0.5 : (col + 0.5) / side;
|
|
477
|
+
out.push({
|
|
478
|
+
lat: bounds.sw.lat + (bounds.ne.lat - bounds.sw.lat) * fy,
|
|
479
|
+
lng: bounds.sw.lng + (bounds.ne.lng - bounds.sw.lng) * fx,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return out;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Rasterise every mesh triangle into a height grid, keeping the highest and
|
|
487
|
+
* lowest surface per cell.
|
|
488
|
+
*
|
|
489
|
+
* Sampling vertices alone leaves holes: the photogrammetric mesh puts few
|
|
490
|
+
* vertices on flat roofs and vertical walls, which breaks a building into
|
|
491
|
+
* disconnected fragments. Filling triangle interiors keeps surfaces contiguous.
|
|
492
|
+
*/
|
|
493
|
+
function rasterize(mesh, frame, cell, cols, rows) {
|
|
494
|
+
const top = new Array(cols * rows).fill(null);
|
|
495
|
+
const low = new Array(cols * rows).fill(null);
|
|
496
|
+
let minAlt = Infinity;
|
|
497
|
+
let maxAlt = -Infinity;
|
|
498
|
+
const put = (col, row, alt) => {
|
|
499
|
+
if (col < 0 || col >= cols || row < 0 || row >= rows)
|
|
500
|
+
return;
|
|
501
|
+
const i = row * cols + col;
|
|
502
|
+
const t = top[i];
|
|
503
|
+
if (t === null || t === undefined || alt > t)
|
|
504
|
+
top[i] = alt;
|
|
505
|
+
const l = low[i];
|
|
506
|
+
if (l === null || l === undefined || alt < l)
|
|
507
|
+
low[i] = alt;
|
|
508
|
+
if (alt < minAlt)
|
|
509
|
+
minAlt = alt;
|
|
510
|
+
if (alt > maxAlt)
|
|
511
|
+
maxAlt = alt;
|
|
512
|
+
};
|
|
513
|
+
for (const tile of mesh.tiles) {
|
|
514
|
+
const projected = tile.vertices.map((v) => {
|
|
515
|
+
const { x, y } = frame.project(v.lat, v.lng);
|
|
516
|
+
return { col: x / cell, row: y / cell, alt: v.alt };
|
|
517
|
+
});
|
|
518
|
+
for (const [ia, ib, ic] of tile.triangles) {
|
|
519
|
+
const a = projected[ia];
|
|
520
|
+
const b = projected[ib];
|
|
521
|
+
const c = projected[ic];
|
|
522
|
+
if (!a || !b || !c)
|
|
523
|
+
continue;
|
|
524
|
+
const minCol = Math.floor(Math.min(a.col, b.col, c.col));
|
|
525
|
+
const maxCol = Math.ceil(Math.max(a.col, b.col, c.col));
|
|
526
|
+
const minRow = Math.floor(Math.min(a.row, b.row, c.row));
|
|
527
|
+
const maxRow = Math.ceil(Math.max(a.row, b.row, c.row));
|
|
528
|
+
// A triangle spanning the whole grid is a decal or a distant node; it
|
|
529
|
+
// would flatten the raster, so keep it to its corners.
|
|
530
|
+
if ((maxCol - minCol) * (maxRow - minRow) > 4096) {
|
|
531
|
+
put(Math.round(a.col), Math.round(a.row), a.alt);
|
|
532
|
+
put(Math.round(b.col), Math.round(b.row), b.alt);
|
|
533
|
+
put(Math.round(c.col), Math.round(c.row), c.alt);
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const area = (b.col - a.col) * (c.row - a.row) - (c.col - a.col) * (b.row - a.row);
|
|
537
|
+
if (Math.abs(area) < 1e-12) {
|
|
538
|
+
put(Math.round(a.col), Math.round(a.row), a.alt);
|
|
539
|
+
put(Math.round(b.col), Math.round(b.row), b.alt);
|
|
540
|
+
put(Math.round(c.col), Math.round(c.row), c.alt);
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
for (let row = minRow; row <= maxRow; row++) {
|
|
544
|
+
for (let col = minCol; col <= maxCol; col++) {
|
|
545
|
+
const w0 = ((b.col - col) * (c.row - row) - (c.col - col) * (b.row - row)) / area;
|
|
546
|
+
const w1 = ((c.col - col) * (a.row - row) - (a.col - col) * (c.row - row)) / area;
|
|
547
|
+
const w2 = 1 - w0 - w1;
|
|
548
|
+
// A small negative tolerance keeps shared edges from dropping out.
|
|
549
|
+
if (w0 < -0.05 || w1 < -0.05 || w2 < -0.05)
|
|
550
|
+
continue;
|
|
551
|
+
put(col, row, w0 * a.alt + w1 * b.alt + w2 * c.alt);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
top,
|
|
558
|
+
low,
|
|
559
|
+
minAlt: Number.isFinite(minAlt) ? minAlt : 0,
|
|
560
|
+
maxAlt: Number.isFinite(maxAlt) ? maxAlt : 0,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
/** Local east/north metre frame anchored at the box's south-west corner. */
|
|
564
|
+
function localFrame(bounds) {
|
|
565
|
+
const lat0 = bounds.sw.lat;
|
|
566
|
+
const lng0 = bounds.sw.lng;
|
|
567
|
+
const metersPerDegLat = (Math.PI / 180) * EARTH_RADIUS_METERS;
|
|
568
|
+
const metersPerDegLng = metersPerDegLat * Math.cos(((bounds.ne.lat + bounds.sw.lat) / 2 / 180) * Math.PI);
|
|
569
|
+
return {
|
|
570
|
+
widthMeters: Math.abs(bounds.ne.lng - lng0) * metersPerDegLng,
|
|
571
|
+
heightMeters: Math.abs(bounds.ne.lat - lat0) * metersPerDegLat,
|
|
572
|
+
project(lat, lng) {
|
|
573
|
+
return { x: (lng - lng0) * metersPerDegLng, y: (lat - lat0) * metersPerDegLat };
|
|
574
|
+
},
|
|
575
|
+
unproject(x, y) {
|
|
576
|
+
return { lat: lat0 + y / metersPerDegLat, lng: lng0 + x / metersPerDegLng };
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function median(values) {
|
|
581
|
+
if (values.length === 0)
|
|
582
|
+
return 0;
|
|
583
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
584
|
+
return sorted[Math.floor(sorted.length / 2)];
|
|
585
|
+
}
|
|
586
|
+
function percentile(values, p) {
|
|
587
|
+
if (values.length === 0)
|
|
588
|
+
return 0;
|
|
589
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
590
|
+
const index = Math.min(sorted.length - 1, Math.max(0, Math.round(p * (sorted.length - 1))));
|
|
591
|
+
return sorted[index];
|
|
592
|
+
}
|
|
593
|
+
/** Monotone chain hull over lat/lng treated as a plane — fine at block scale. */
|
|
594
|
+
function convexHull(points) {
|
|
595
|
+
if (points.length < 3)
|
|
596
|
+
return boundingRect(points);
|
|
597
|
+
if (points.length === 3)
|
|
598
|
+
return points;
|
|
599
|
+
const sorted = [...points].sort((a, b) => (a.lng === b.lng ? a.lat - b.lat : a.lng - b.lng));
|
|
600
|
+
const cross = (o, a, b) => (a.lng - o.lng) * (b.lat - o.lat) - (a.lat - o.lat) * (b.lng - o.lng);
|
|
601
|
+
const build = (input) => {
|
|
602
|
+
const chain = [];
|
|
603
|
+
for (const p of input) {
|
|
604
|
+
while (chain.length >= 2 && cross(chain[chain.length - 2], chain[chain.length - 1], p) <= 0) {
|
|
605
|
+
chain.pop();
|
|
606
|
+
}
|
|
607
|
+
chain.push(p);
|
|
608
|
+
}
|
|
609
|
+
chain.pop();
|
|
610
|
+
return chain;
|
|
611
|
+
};
|
|
612
|
+
const hull = [...build(sorted), ...build([...sorted].reverse())];
|
|
613
|
+
// Collinear cells collapse the chain; a footprint still has to be a polygon,
|
|
614
|
+
// so fall back to the bounding rectangle.
|
|
615
|
+
return hull.length >= 3 ? hull : boundingRect(points);
|
|
616
|
+
}
|
|
617
|
+
function boundingRect(points) {
|
|
618
|
+
const lats = points.map((p) => p.lat);
|
|
619
|
+
const lngs = points.map((p) => p.lng);
|
|
620
|
+
const minLat = Math.min(...lats);
|
|
621
|
+
const maxLat = Math.max(...lats);
|
|
622
|
+
const minLng = Math.min(...lngs);
|
|
623
|
+
const maxLng = Math.max(...lngs);
|
|
624
|
+
return [
|
|
625
|
+
{ lat: minLat, lng: minLng },
|
|
626
|
+
{ lat: minLat, lng: maxLng },
|
|
627
|
+
{ lat: maxLat, lng: maxLng },
|
|
628
|
+
{ lat: maxLat, lng: minLng },
|
|
629
|
+
];
|
|
630
|
+
}
|
|
631
|
+
function gridToObj(heights, cols, rows, step) {
|
|
632
|
+
const lines = ['# googlemaps-kit terrain sample (Google Earth photorealistic mesh)'];
|
|
633
|
+
const index = new Array(cols * rows).fill(0);
|
|
634
|
+
let n = 0;
|
|
635
|
+
for (let row = 0; row < rows; row++) {
|
|
636
|
+
for (let col = 0; col < cols; col++) {
|
|
637
|
+
const h = heights[row * cols + col];
|
|
638
|
+
if (h === null || h === undefined)
|
|
639
|
+
continue;
|
|
640
|
+
lines.push(`v ${(col * step).toFixed(2)} ${h.toFixed(2)} ${(row * step).toFixed(2)}`);
|
|
641
|
+
index[row * cols + col] = ++n;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
for (let row = 0; row + 1 < rows; row++) {
|
|
645
|
+
for (let col = 0; col + 1 < cols; col++) {
|
|
646
|
+
const a = index[row * cols + col];
|
|
647
|
+
const b = index[row * cols + col + 1];
|
|
648
|
+
const c = index[(row + 1) * cols + col + 1];
|
|
649
|
+
const d = index[(row + 1) * cols + col];
|
|
650
|
+
if (!a || !b || !c || !d)
|
|
651
|
+
continue;
|
|
652
|
+
lines.push(`f ${a} ${b} ${c}`);
|
|
653
|
+
lines.push(`f ${a} ${c} ${d}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return `${lines.join('\n')}\n`;
|
|
657
|
+
}
|
|
658
|
+
//# sourceMappingURL=map-3d.js.map
|