@tileflow/core 0.1.0-alpha.36 → 0.1.0-alpha.38
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 +13 -12
- package/dist/3d-D9c3i78O.d.ts +1080 -0
- package/dist/3d.d.ts +1 -0
- package/dist/3d.js +12082 -0
- package/dist/browser.d.ts +530 -1306
- package/dist/browser.js +7166 -5194
- package/dist/build.d.ts +2 -2
- package/dist/build.js +1707 -824
- package/dist/config-reference.json +3772 -1380
- package/dist/{icon-composition-sN3JkXdb.d.ts → icon-composition-Br4Bd2bY.d.ts} +348 -6
- package/dist/index.d.ts +162 -154
- package/dist/index.js +4003 -2740
- package/dist/worker/camera-tile-worker.global.js +1 -0
- package/docs/application-tile-reading.md +5 -2
- package/docs/authoring-model.md +8 -0
- package/docs/buildings-3d.md +185 -25
- package/docs/compiled-style-performance.md +11 -2
- package/docs/data-is-separate-from-design.md +18 -34
- package/docs/nautical-marks.md +200 -0
- package/docs/public-api-and-browser-subpath.md +8 -1
- package/docs/street-lights.md +5 -1
- package/docs/trees-3d.md +11 -6
- package/package.json +6 -1
- package/dist/worker/buildings-3d-worker.global.js +0 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Nautical marks
|
|
2
|
+
|
|
3
|
+
The `nautical` module draws navigation marks from a `nautical-v1` vector source: buoys, beacons,
|
|
4
|
+
lighthouses, lights, rocks and other hazards, wrecks, reefs, navigation areas, routes, cables,
|
|
5
|
+
harbours, ports, and a restrained indication of where a provider publishes marks. It is reference
|
|
6
|
+
cartography for general-purpose maps. It is not a nautical chart, and a map that draws it always
|
|
7
|
+
shows a "Not for navigation" notice.
|
|
8
|
+
|
|
9
|
+
## Enable Nautical on a map
|
|
10
|
+
|
|
11
|
+
Nautical is opt-in through the map's `marine` option. `'nautical'` adds it alone, `'chart'` adds it
|
|
12
|
+
with Bathymetry, and the object form selects or replaces each member. The official Soundings map
|
|
13
|
+
enables it with its own chart symbols; every other official map draws it with the module's default
|
|
14
|
+
symbology once the map opts in.
|
|
15
|
+
|
|
16
|
+
<!-- docs:check -->
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {defineMap} from '@tileflow/core';
|
|
20
|
+
import {streets} from '@tileflow/maps';
|
|
21
|
+
|
|
22
|
+
export default defineMap({
|
|
23
|
+
id: 'harbour-guide',
|
|
24
|
+
version: 1,
|
|
25
|
+
extends: streets,
|
|
26
|
+
marine: 'nautical',
|
|
27
|
+
view: {center: [-1.3, 50.77], zoom: 12},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`marine` is atomic: declaring it replaces the inherited value. Without a URL, the source is the
|
|
32
|
+
TileJSON at `/tiles/nautical/tiles.json` on the map's API base, with the style source ID
|
|
33
|
+
`tileflow-nautical`. Compiling a map that names this URL does not establish that a hosted Nautical
|
|
34
|
+
source is available to it. To use any schema-compatible source, name its TileJSON or PMTiles
|
|
35
|
+
archive and, when the TileJSON does not carry one, its attribution:
|
|
36
|
+
|
|
37
|
+
<!-- docs:check -->
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import {defineMap} from '@tileflow/core';
|
|
41
|
+
import {streets} from '@tileflow/maps';
|
|
42
|
+
|
|
43
|
+
export default defineMap({
|
|
44
|
+
id: 'harbour-guide',
|
|
45
|
+
version: 1,
|
|
46
|
+
extends: streets,
|
|
47
|
+
marine: {
|
|
48
|
+
bathymetry: false,
|
|
49
|
+
nautical: {
|
|
50
|
+
url: 'https://tiles.example.com/nautical/tiles.json',
|
|
51
|
+
attribution: '© Example © OpenStreetMap contributors',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The selected TileJSON owns the provider credit. Core never invents a nautical provider or
|
|
58
|
+
attribution, and an explicit `attribution` replaces the one the TileJSON supplies.
|
|
59
|
+
|
|
60
|
+
## The "Not for navigation" notice
|
|
61
|
+
|
|
62
|
+
When any layer of the compiled style reads the Nautical source, the style declares a notice in its
|
|
63
|
+
`tileflow:notices` metadata:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
[
|
|
67
|
+
{
|
|
68
|
+
"id": "nautical-not-for-navigation",
|
|
69
|
+
"sources": ["tileflow-nautical"],
|
|
70
|
+
"text": "Not for navigation"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
React, Vue, Svelte, the development preview, and standalone capture render it as a compact,
|
|
76
|
+
always-visible control beside the attribution, and keep it in step with style replacements. A map
|
|
77
|
+
that does not draw Nautical, including one whose `nautical` module is disabled, declares no notice.
|
|
78
|
+
The notice is separate from the source attribution, so the provider credit stays complete.
|
|
79
|
+
|
|
80
|
+
A direct MapLibre integration attaches the same control after constructing the map:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import maplibregl from 'maplibre-gl';
|
|
84
|
+
import {attachTileflowNotices} from '@tileflow/core/browser';
|
|
85
|
+
|
|
86
|
+
const map = new maplibregl.Map({
|
|
87
|
+
container: 'map',
|
|
88
|
+
style: '/tileflow/styles/harbour-guide/light.json',
|
|
89
|
+
});
|
|
90
|
+
const detach = attachTileflowNotices(map, {position: 'bottom-right'});
|
|
91
|
+
// Call detach() to remove the control early; removing the map also removes it.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`readTileflowNotices(style.metadata)` returns the bounded notices of a style for an application
|
|
95
|
+
that draws its own legend or exports images by other means. Show the notice wherever such a map is
|
|
96
|
+
displayed.
|
|
97
|
+
|
|
98
|
+
## Source layers and fields
|
|
99
|
+
|
|
100
|
+
Every feature carries `provider`, `provenance`, `edition`, `coverage`, `licence`, and `min_zoom`,
|
|
101
|
+
the first zoom at which the feature appears. `rank` (1 is the most important feature of its layer)
|
|
102
|
+
and `name` are optional. Colours are S-57 colour names, and multi-valued colours and categories are
|
|
103
|
+
comma-separated in source order, for example `black,yellow`. `tileflowNauticalV1Schema` lists the
|
|
104
|
+
field names, layers, and geometry types.
|
|
105
|
+
|
|
106
|
+
| Source layer | Geometry | Fields the module reads |
|
|
107
|
+
| ----------------- | -------------------------- | -------------------------------------------------------- |
|
|
108
|
+
| `aid` | Point | `class`, `subclass`, `category`, `color`, `rank`, `name` |
|
|
109
|
+
| `light` | Point | `class` (`major` or `minor`), `color`, `label`, `rank` |
|
|
110
|
+
| `hazard` | Point, LineString, Polygon | `class`, `water_level`, `name` |
|
|
111
|
+
| `wreck` | Point, Polygon | `class`, `name` |
|
|
112
|
+
| `reef` | Polygon | `name` |
|
|
113
|
+
| `navigation_area` | Point, LineString, Polygon | `class`, `size`, `rank`, `name` |
|
|
114
|
+
| `coverage` | Polygon | `families` |
|
|
115
|
+
| `sounding` | Point | `depth` |
|
|
116
|
+
|
|
117
|
+
Every layer filters on `min_zoom`, so a compatible source that keeps features in lower-zoom tiles
|
|
118
|
+
still shows each one from its own first zoom. Point groups place a lower `rank` first.
|
|
119
|
+
|
|
120
|
+
## Semantic groups
|
|
121
|
+
|
|
122
|
+
Each group is a style option of `nautical(...)`, with the same marker, symbol, area, and line style
|
|
123
|
+
objects as other modules.
|
|
124
|
+
|
|
125
|
+
| Option | Draws | Default symbology |
|
|
126
|
+
| ----------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
|
127
|
+
| `buoys` | `aid` buoys, light floats, and light vessels | Circle in the first colour, ringed with the second |
|
|
128
|
+
| `beacons` | `aid` beacons and daymarks | Small circle in the first colour |
|
|
129
|
+
| `lighthouses` | `aid` lighthouses | Ink circle and name |
|
|
130
|
+
| `aids` | Other `aid` classes, such as moorings, fog signals, and racons | Small hollow circle |
|
|
131
|
+
| `lights` | `light` points, one per sector | Flare in the light's first colour and its chart `label` |
|
|
132
|
+
| `hazards` | `hazard` points | `+` for rocks, `*` for rocks that show; circled obstacles |
|
|
133
|
+
| `hazardAreas` | `hazard` polygons; the outline also strokes linear hazards | Accent wash with a dotted outline |
|
|
134
|
+
| `wrecks` | `wreck` points | `Wk`, in the accent colour when dangerous |
|
|
135
|
+
| `wreckAreas` | `wreck` polygons | Ink wash with a dashed outline |
|
|
136
|
+
| `reefs` | `reef` polygons | Sand wash with a dotted outline |
|
|
137
|
+
| `navigationAreas` | `navigation_area` polygons | Dashed outlines; accent for operational areas |
|
|
138
|
+
| `routes` | `navigation_area` lines of class `route` and `traffic-separation` | Dashed line; accent for traffic separation |
|
|
139
|
+
| `cables` | `navigation_area` lines of class `cable`, `pipeline`, and their area classes | Fine dashed accent line |
|
|
140
|
+
| `harbours` | `navigation_area` points of class `harbour` | Ink circle and name |
|
|
141
|
+
| `ports` | `navigation_area` points of class `port` | Ink circle and name sized by `size`, from low zooms |
|
|
142
|
+
| `coverage` | `coverage` polygons that cover every family | Faint tint at low zooms only |
|
|
143
|
+
| `soundings` | `sounding` points | Depth figure |
|
|
144
|
+
| `labels` | Names inside hazard, navigation-area, reef, and wreck polygons; coverage opt-in | Collision-aware text |
|
|
145
|
+
|
|
146
|
+
Operational areas are restricted, military, anchorage, anchor-berth, dumping-ground, and
|
|
147
|
+
traffic-separation areas. Marks keep their conventional colours in every theme; a white light is
|
|
148
|
+
drawn as a warm yellow so it remains visible on pale water. Ink, halo, and accent come from the
|
|
149
|
+
theme's `hydro.label`, `hydro.water`, and `poi.transport` colours, so a theme can restyle Nautical
|
|
150
|
+
without new options. Override any group like any other module style:
|
|
151
|
+
|
|
152
|
+
<!-- docs:check -->
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import {defineMap, fixed, nautical} from '@tileflow/core';
|
|
156
|
+
import {streets} from '@tileflow/maps';
|
|
157
|
+
|
|
158
|
+
export default defineMap({
|
|
159
|
+
id: 'harbour-guide',
|
|
160
|
+
version: 1,
|
|
161
|
+
extends: streets,
|
|
162
|
+
marine: 'nautical',
|
|
163
|
+
modules: {
|
|
164
|
+
nautical: nautical({
|
|
165
|
+
buoys: {minZoom: 12},
|
|
166
|
+
cables: {visible: false},
|
|
167
|
+
navigationAreas: {
|
|
168
|
+
fill: {opacity: fixed(0.04, {reason: 'Keep operational areas quiet on the base map'})},
|
|
169
|
+
},
|
|
170
|
+
labels: {coverage: {visible: true}},
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Chart symbols from the theme
|
|
177
|
+
|
|
178
|
+
A theme that declares the image tokens below replaces a point group's circle marker with that icon.
|
|
179
|
+
Buoy variants fall back to `nautical.buoy`. `tileflowNauticalImageRoles` lists the tokens.
|
|
180
|
+
|
|
181
|
+
| Token | Group |
|
|
182
|
+
| ------------------------- | ------------------------------------------ |
|
|
183
|
+
| `nautical.buoy` | `buoys` |
|
|
184
|
+
| `nautical.buoy.port` | Lateral buoys of a port-hand category |
|
|
185
|
+
| `nautical.buoy.starboard` | Lateral buoys of a starboard-hand category |
|
|
186
|
+
| `nautical.buoy.cardinal` | Cardinal buoys |
|
|
187
|
+
| `nautical.beacon` | `beacons` |
|
|
188
|
+
| `nautical.lighthouse` | `lighthouses` |
|
|
189
|
+
| `nautical.light` | `lights` |
|
|
190
|
+
| `nautical.aid` | `aids` |
|
|
191
|
+
| `nautical.wreck` | `wrecks` |
|
|
192
|
+
| `nautical.harbour` | `harbours` |
|
|
193
|
+
| `nautical.port` | `ports` |
|
|
194
|
+
|
|
195
|
+
Buoys, beacons, other aids, and lights colour their icon with the mark's own colour, so declare
|
|
196
|
+
them as [SDF icons](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/docs/native-icons.md)
|
|
197
|
+
that share one representation within each group. The defaults size icons for the SDF profile,
|
|
198
|
+
whose drawing occupies the central 12 of 24 pixels; set `icon.size` for other artwork. Soundings
|
|
199
|
+
declares these tokens with its own buoy, light, lighthouse, wreck, and harbour symbols and keeps
|
|
200
|
+
beacons as coloured dots.
|
|
@@ -79,13 +79,20 @@ import {
|
|
|
79
79
|
attachTileflowAtmosphere,
|
|
80
80
|
attachTileflowFairUseNotice,
|
|
81
81
|
attachTileflowMapLifecycle,
|
|
82
|
+
attachTileflowNotices,
|
|
82
83
|
createTileflowSessionStarter,
|
|
83
84
|
createTileflowTransformRequest,
|
|
84
85
|
registerTileflowWorldRequestBridge,
|
|
85
86
|
} from '@tileflow/core/browser';
|
|
86
87
|
```
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
`@tileflow/core/3d` holds only `createTileflowMap3D` and the 3D renderers it mounts, so an
|
|
90
|
+
application can load them with a dynamic import when a style declares a 3D scene; see
|
|
91
|
+
[3D buildings](buildings-3d.md#the-maps-3d-scene). The browser entry exports the same function.
|
|
92
|
+
|
|
93
|
+
`attachTileflowNotices(map)` renders the notices a compiled style declares, such as Nautical's
|
|
94
|
+
"Not for navigation", as a compact map control; see
|
|
95
|
+
[Nautical marks](nautical-marks.md). The browser entry is not re-exported from the root. It is SSR-safe to import, has no MapLibre
|
|
89
96
|
runtime dependency, and reads no browser global during module evaluation. See the
|
|
90
97
|
[framework browser runtime contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/framework-browser-runtime.md) and the
|
|
91
98
|
[cartographic authoring contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/cartographic-authoring.md). Exact field
|
package/docs/street-lights.md
CHANGED
|
@@ -9,6 +9,9 @@ the lights switch on one by one; they go out as day comes.
|
|
|
9
9
|
Street lights are off by default in the SDK and in Streets. A compiled map must explicitly set
|
|
10
10
|
`roads.streetLights.enabled: true` before the renderer or preview will show lamp glows.
|
|
11
11
|
|
|
12
|
+
React, Vue and Svelte maps light a map that enables street lights automatically, as part of its
|
|
13
|
+
[3D scene](buildings-3d.md#the-maps-3d-scene); the 2D view has no street lights.
|
|
14
|
+
|
|
12
15
|
It is a custom WebGL2 layer for MapLibre GL JS, drawn above the map's buildings and below its
|
|
13
16
|
labels. When `createTileflowBuildings3D` raises the buildings, they hide the lamps behind them. It
|
|
14
17
|
needs WebGL2 and the Mercator projection, and shines from zoom 14 by default.
|
|
@@ -114,7 +117,8 @@ by default, at most 64) bound where and how far the lights shine, `beforeId` pla
|
|
|
114
117
|
another one, and `transformRequest` applies the map's request rules to the tiles it reads.
|
|
115
118
|
|
|
116
119
|
Layers that read the same source share each tile's download, so the street lights and the 3D
|
|
117
|
-
buildings fetch a tile once between them.
|
|
120
|
+
buildings fetch a tile once between them. The lamps are placed in the worker the page's 3D layers
|
|
121
|
+
share, which decodes each tile once for all of them.
|
|
118
122
|
|
|
119
123
|
## Limits
|
|
120
124
|
|
package/docs/trees-3d.md
CHANGED
|
@@ -20,7 +20,8 @@ for its models unless an extension explicitly chooses `flat` or `auto`.
|
|
|
20
20
|
## Visibility and representation
|
|
21
21
|
|
|
22
22
|
Use `createTileflowVegetation` for application controls. React, Vue and Svelte mount it automatically
|
|
23
|
-
in interactive maps
|
|
23
|
+
in interactive maps, as part of the map's [3D scene](buildings-3d.md#the-maps-3d-scene). The map
|
|
24
|
+
chooses `vegetation.mode` independently of visibility:
|
|
24
25
|
|
|
25
26
|
| Mode | 2D view | 3D view |
|
|
26
27
|
| -------------- | ------------------- | ------------------- |
|
|
@@ -28,7 +29,8 @@ in interactive maps. The map chooses `vegetation.mode` independently of visibili
|
|
|
28
29
|
| `flat` | Flat crowns/circles | Flat crowns/circles |
|
|
29
30
|
| `auto` | Flat crowns/circles | Model trees |
|
|
30
31
|
|
|
31
|
-
`viewMode` is explicit application state
|
|
32
|
+
`viewMode` is explicit application state, not a pitch threshold: `2d` by default for
|
|
33
|
+
`createTileflowVegetation`, and `3d` by default in the framework components and `createTileflowMap3D`. Tilting the camera
|
|
32
34
|
does not change representation. Visibility defaults to `vegetation.visible ?? true`; OFF hides every
|
|
33
35
|
representation. Turning trees off releases model buffers and tile readers. Controls apply immediately,
|
|
34
36
|
without a grow/sink animation, and do not change building appearance or lighting.
|
|
@@ -70,7 +72,7 @@ export default defineMap({
|
|
|
70
72
|
Use `refine({visible: false})` for initially hidden vegetation that can be enabled at runtime.
|
|
71
73
|
Use `vegetation: disable()` to remove the module entirely; a runtime toggle cannot restore a module
|
|
72
74
|
that is absent from the compiled map. Browser framework components accept `vegetation={false}` and
|
|
73
|
-
`viewMode="
|
|
75
|
+
`viewMode="2d"` (Vue: `:vegetation="false"`, `view-mode="2d"`). Image mode uses the compiled static
|
|
74
76
|
fallback and does not apply these interactive controls.
|
|
75
77
|
|
|
76
78
|
## Animate trees with the low-level renderer
|
|
@@ -260,7 +262,7 @@ Shadow direction stops lowering at 15° above the horizon; the actual scene ligh
|
|
|
260
262
|
|
|
261
263
|
## Options
|
|
262
264
|
|
|
263
|
-
`minzoom` (15 by default, fading to full coverage at 15.25
|
|
265
|
+
`minzoom` (15 by default, fading to full coverage at 15.25) and `maxTiles` (25 by default, at most 64) bound where and how far trees
|
|
264
266
|
stand; trees thin out and fade with distance from the map's centre, and near trees take more detail
|
|
265
267
|
than far ones. `canopySource` names a vector source with canopy points when they are not in the
|
|
266
268
|
map's World source. `beforeId` places the layer before another one; `transformRequest` applies the
|
|
@@ -270,9 +272,12 @@ tile's download.
|
|
|
270
272
|
## Cost
|
|
271
273
|
|
|
272
274
|
A near tree has 60 to 120 triangles and a far one about 20, and each form is one instanced draw per
|
|
273
|
-
tile.
|
|
275
|
+
tile. Trees are placed in the worker the page's 3D layers share, which decodes each tile once for
|
|
276
|
+
all of them, nearest tiles first. The shared shadow map concentrates resolution on the view when its public camera methods
|
|
274
277
|
provide a safe planar fit. It is drawn again when that focused area, the light, visible tree
|
|
275
|
-
selection, fading or geometry changes. Unchanged views reuse it.
|
|
278
|
+
selection, fading or geometry changes. Unchanged views reuse it. While the camera moves, the trees'
|
|
279
|
+
shadows follow their selection and fading in steps of a sixteenth of a tile, and exactly again once
|
|
280
|
+
it stops. Over the Champ de Mars in Paris,
|
|
276
281
|
where OpenStreetMap maps every tree, about 13,000 trees stand in a pitched view at zoom 16.6.
|
|
277
282
|
|
|
278
283
|
## Limits
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/core",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.38",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Typed Tileflow config and MapLibre style compiler.",
|
|
6
6
|
"type": "module",
|
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
"import": "./dist/index.js",
|
|
36
36
|
"default": "./dist/index.js"
|
|
37
37
|
},
|
|
38
|
+
"./3d": {
|
|
39
|
+
"types": "./dist/3d.d.ts",
|
|
40
|
+
"import": "./dist/3d.js",
|
|
41
|
+
"default": "./dist/3d.js"
|
|
42
|
+
},
|
|
38
43
|
"./browser": {
|
|
39
44
|
"types": "./dist/browser.d.ts",
|
|
40
45
|
"import": "./dist/browser.js",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(()=>{var An=new Set,Dn=!1;function kn(n,e,t=2){let s=e&&e.length,o=s?e[0]*t:n.length;An.size&&An.clear();let r=he(n,0,o,t,!0),i=[];if(!r||r.next===r.prev)return i;let u=0,l=0,c=0;if(s&&(r=_e(n,e,r,t)),n.length>80*t){u=n[0],l=n[1];let a=u,f=l;for(let h=t;h<o;h+=t){let m=n[h],b=n[h+1];m<u&&(u=m),b<l&&(l=b),m>a&&(a=m),b>f&&(f=b)}c=Math.max(a-u,f-l),c=c!==0?32767/c:0}return Wn(r,i,u,l,c),i}function he(n,e,t,s,o){let r=null;if(o===Ye(n,e,t,s)>0)for(let i=e;i<t;i+=s)r=fe(i/s|0,n[i],n[i+1],r);else for(let i=t-s;i>=e;i-=s)r=fe(i/s|0,n[i],n[i+1],r);return r&&In(r,r.next)&&(Tn(r),r=r.next),r}function fn(n,e=n){let t=e===n,s=n,o;do o=!1,s!==s.next&&(An.size===0||!An.has(s))&&(In(s,s.next)||O(s.prev,s,s.next)===0)?((t||s===e)&&(e=s.prev),Dn=!0,Tn(s),s=s.prev,o=!0):(t||s!==e)&&(s=s.next,o=!t);while(o||s!==e);return e}function Wn(n,e,t,s,o){o&&Se(n,t,s,o);let r=n,i=!1;for(;n.prev!==n.next;){let u=n.prev,l=n.next;if(O(u,n,l)<0&&(o?ke(n,t,s,o):Te(n))){e.push(u.i,n.i,l.i),Tn(n),n=l,r=l;continue}if(n=l,n===r){if(Dn=!1,n=fn(n),Dn){r=n;continue}if(!i){n=Be(n,e),r=n,i=!0;continue}Fe(n,e,t,s,o);break}}}function Te(n){let e=n.prev,t=n,s=n.next,o=e.x,r=t.x,i=s.x,u=e.y,l=t.y,c=s.y,a=Math.min(o,r,i),f=Math.min(u,l,c),h=Math.max(o,r,i),m=Math.max(u,l,c),b=s.next;for(;b!==e;){if(b.x>=a&&b.x<=h&&b.y>=f&&b.y<=m&&!(o===b.x&&u===b.y)&&Vn(o,u,r,l,i,c,b.x,b.y)&&O(b.prev,b,b.next)>=0)return!1;b=b.next}return!0}function ke(n,e,t,s){let o=n.prev,r=n,i=n.next,u=o.x,l=r.x,c=i.x,a=o.y,f=r.y,h=i.y,m=Math.min(u,l,c),b=Math.min(a,f,h),d=Math.max(u,l,c),x=Math.max(a,f,h),I=$n(m,b,e,t,s),B=$n(d,x,e,t,s),M=n.prevZ;for(;M&&M.z>=I;){if(M.x>=m&&M.x<=d&&M.y>=b&&M.y<=x&&M!==i&&!(u===M.x&&a===M.y)&&Vn(u,a,l,f,c,h,M.x,M.y)&&O(M.prev,M,M.next)>=0)return!1;M=M.prevZ}let y=n.nextZ;for(;y&&y.z<=B;){if(y.x>=m&&y.x<=d&&y.y>=b&&y.y<=x&&y!==i&&!(u===y.x&&a===y.y)&&Vn(u,a,l,f,c,h,y.x,y.y)&&O(y.prev,y,y.next)>=0)return!1;y=y.nextZ}return!0}function Be(n,e){let t=n,s=!1;do{let o=t.prev,r=t.next.next;xe(o,t,t.next,r,!1)&&Un(o,r)&&Un(r,o)&&(e.push(o.i,t.i,r.i),Tn(t),Tn(t.next),t=n=r,s=!0),t=t.next}while(t!==n);return s?fn(t):t}function Fe(n,e,t,s,o){let r=n;do{let i=r.next.next;for(;i!==r.prev;){if(r.i!==i.i&&He(r,i)){let u=de(r,i);r=fn(r,r.next),u=fn(u,u.next),Wn(r,e,t,s,o),Wn(u,e,t,s,o);return}i=i.next}r=r.next}while(r!==n)}var Kn=!1;function _e(n,e,t,s){let o=[];for(let r=0,i=e.length;r<i;r++){let u=e[r]*s,l=r<i-1?e[r+1]*s:n.length,c=he(n,u,l,s,!1);c===c.next&&An.add(c),o.push(Ee(c))}o.sort(Pe),Le(n.length/s,e.length),be(t,t),Kn=!0;for(let r=0;r<o.length;r++)t=Oe(o[r],t);return Kn=!1,fn(t)}function Pe(n,e){return n.x-e.x||n.y-e.y||(n.next.y-n.y)/(n.next.x-n.x)-(e.next.y-e.y)/(e.next.x-e.x)}function Oe(n,e){let t=ze(n,e);if(!t)return e;let s=de(t,n),o=s.next;return be(t,o.next),fn(s,s.next),fn(t,t.next)}var me=16,_=new Float64Array(0),Nn=0,Jn=[],Qn=[];function Le(n,e){let t=Math.ceil((n+2*e)/me)+e+2;_.length<t*4&&(_=new Float64Array(t*4)),Nn=0}function be(n,e){let t=n;do{let s=Nn++;Jn[s]=t;let o=t.x,r=t.y,i=t.x,u=t.y,l=0;do{let a=t.next;t.z=s,a.x<o&&(o=a.x),a.x>i&&(i=a.x),a.y<r&&(r=a.y),a.y>u&&(u=a.y),t=a}while(++l<me&&t!==e);Qn[s]=t;let c=s*4;_[c]=o,_[c+1]=r,_[c+2]=i,_[c+3]=u}while(t!==e)}function Ce(n,e){let t=n.z*4;e.x<_[t]&&(_[t]=e.x),e.y<_[t+1]&&(_[t+1]=e.y),e.x>_[t+2]&&(_[t+2]=e.x),e.y>_[t+3]&&(_[t+3]=e.y)}function ce(n){let e=Qn[n];for(;e.prev.next!==e;)e=e.next;return Qn[n]=e,e}function ae(n){let e=Jn[n];for(;e.prev.next!==e;)e=e.next;return Jn[n]=e,e}function ze(n,e){let t=e,s=n.x,o=n.y,r=-1/0,i;if(In(n,t))return t;for(let h=0,m=0;h<Nn;h++,m+=4){if(o<_[m+1]||o>_[m+3]||_[m]>s||_[m+2]<=r)continue;let b=ce(h);t=ae(h);do{if(t.prev.next===t){if(In(n,t.next))return t.next;if(o<=t.y&&o>=t.next.y&&t.next.y!==t.y){let d=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(d<=s&&d>r&&(r=d,i=t.x<t.next.x?t:t.next,d===s))return i}}t=t.next}while(t!==b)}if(!i)return null;let u=i.x,l=i.y,c=Math.min(o,l),a=Math.max(o,l),f=1/0;for(let h=0,m=0;h<Nn;h++,m+=4){if(_[m+2]<u||_[m]>s||_[m+3]<c||_[m+1]>a)continue;let b=ce(h);t=ae(h);do{if(t.prev.next===t&&s>=t.x&&t.x>=u&&s!==t.x&&Vn(o<l?s:r,o,u,l,o<l?r:s,o,t.x,t.y)){let d=Math.abs(o-t.y)/(s-t.x);(Un(t,n)||t.y===o&&t.next.y===o&&t.next.x>s)&&(d<f||d===f&&(t.x>i.x||t.x===i.x&&Ze(i,t)))&&(i=t,f=d)}t=t.next}while(t!==b)}return i}function Ze(n,e){return O(n.prev,n,e.prev)<0&&O(e.next,n,n.next)<0}var K=[],dn=[],an=new Uint32Array(0),vn=new Uint32Array(0),Rn=new Uint32Array(256);function Se(n,e,t,s){let o=n,r=0;do o.z=$n(o.x,o.y,e,t,s),K[r++]=o,o=o.next;while(o!==n);je(r);let i=null;for(let u=0;u<r;u++){let l=K[u];l.prevZ=i,i&&(i.nextZ=l),i=l}i.nextZ=null,K.fill(null,0,r),dn.fill(null,0,r)}function je(n){if(n<=32){for(let e=1;e<n;e++){let t=K[e],s=t.z,o=e-1;for(;o>=0&&K[o].z>s;)K[o+1]=K[o],o--;K[o+1]=t}return}an.length<n&&(an=new Uint32Array(n),vn=new Uint32Array(n),dn=new Array(n));for(let e=0;e<n;e++)an[e]=K[e].z;En(n,K,an,dn,vn,0),En(n,dn,vn,K,an,8),En(n,K,an,dn,vn,16),En(n,dn,vn,K,an,24)}function En(n,e,t,s,o,r){Rn.fill(0);for(let u=0;u<n;u++)Rn[t[u]>>>r&255]++;let i=0;for(let u=0;u<256;u++){let l=Rn[u];Rn[u]=i,i+=l}for(let u=0;u<n;u++){let l=t[u],c=Rn[l>>>r&255]++;s[c]=e[u],o[c]=l}}function $n(n,e,t,s,o){return n=(n-t)*o|0,e=(e-s)*o|0,n=(n|n<<8)&16711935,n=(n|n<<4)&252645135,n=(n|n<<2)&858993459,n=(n|n<<1)&1431655765,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,n|e<<1}function Ee(n){let e=n,t=n;do(e.x<t.x||e.x===t.x&&e.y<t.y)&&(t=e),e=e.next;while(e!==n);return t}function Vn(n,e,t,s,o,r,i,u){return(o-i)*(e-u)>=(n-i)*(r-u)&&(n-i)*(s-u)>=(t-i)*(e-u)&&(t-i)*(r-u)>=(o-i)*(s-u)}function He(n,e){let t=In(n,e)&&O(n.prev,n,n.next)>0&&O(e.prev,e,e.next)>0;return n.next.i!==e.i&&(t||Un(n,e)&&Un(e,n)&&(O(n.prev,n,e.prev)!==0||O(n,e.prev,e)!==0))&&!Ne(n,e)&&(t||Ve(n,e))}function O(n,e,t){return(e.y-n.y)*(t.x-e.x)-(e.x-n.x)*(t.y-e.y)}function In(n,e){return n.x===e.x&&n.y===e.y}function xe(n,e,t,s,o=!0){let r=O(n,e,t),i=O(n,e,s),u=O(t,s,n),l=O(t,s,e);return(r>0&&i<0||r<0&&i>0)&&(u>0&&l<0||u<0&&l>0)?!0:o?!!(r===0&&Hn(n,t,e)||i===0&&Hn(n,s,e)||u===0&&Hn(t,n,s)||l===0&&Hn(t,e,s)):!1}function Hn(n,e,t){return e.x<=Math.max(n.x,t.x)&&e.x>=Math.min(n.x,t.x)&&e.y<=Math.max(n.y,t.y)&&e.y>=Math.min(n.y,t.y)}function Ne(n,e){let t=Math.min(n.x,e.x),s=Math.max(n.x,e.x),o=Math.min(n.y,e.y),r=Math.max(n.y,e.y),i=n;do{let u=i.next;if(i.x>s&&u.x>s||i.x<t&&u.x<t||i.y>r&&u.y>r||i.y<o&&u.y<o){i=u;continue}if(i.i!==n.i&&u.i!==n.i&&i.i!==e.i&&u.i!==e.i&&xe(i,u,n,e))return!0;i=u}while(i!==n);return!1}function Un(n,e){return O(n.prev,n,n.next)<0?O(n,e,n.next)>=0&&O(n,n.prev,e)>=0:O(n,e,n.prev)<0||O(n,n.next,e)<0}function Ve(n,e){let t=n,s=!1,o=(n.x+e.x)/2,r=(n.y+e.y)/2;do{let i=t.next;t.y>r!=i.y>r&&o<(i.x-t.x)*(r-t.y)/(i.y-t.y)+t.x&&(s=!s),t=i}while(t!==n);return s}function de(n,e){let t=qn(n.i,n.x,n.y),s=qn(e.i,e.x,e.y),o=n.next,r=e.prev;return n.next=e,e.prev=n,t.next=o,o.prev=t,s.next=t,t.prev=s,r.next=s,s.prev=r,s}function fe(n,e,t,s){let o=qn(n,e,t);return s?(o.next=s.next,o.prev=s,s.next.prev=o,s.next=o):(o.prev=o,o.next=o),o}function Tn(n){n.next.prev=n.prev,n.prev.next=n.next,n.prevZ&&(n.prevZ.nextZ=n.nextZ),n.nextZ&&(n.nextZ.prevZ=n.prevZ),Kn&&Ce(n.prev,n.next)}function qn(n,e,t){return{i:n,x:e,y:t,prev:null,next:null,z:0,prevZ:null,nextZ:null}}function Ye(n,e,t,s){let o=0;for(let r=e,i=t-s;r<t;r+=s)o+=(n[i]-n[r])*(n[r+1]+n[i+1]),i=r;return o}var Xe=.7,Ge=Math.tan(Math.PI/6),De=Math.tan(35*Math.PI/180),We=Math.tan(Math.PI/18),Bn=.65,Fn=.4;function Me(n,e,t,s,o,r,i){let u=String(t.roof_shape??"");if(!u||u==="flat"||u==="sawtooth"||qe(n,i))return;let l=Qe(n);if(!l||Math.abs(ne(n))<Xe*4*l.halfU*l.halfV)return;let c=l.u,a=l.v,f=l.halfU*r,h=l.halfV*r;f<h&&([c,a,f,h]=[a,c,h,f]);let m=ge(t.roof_direction),b=m===void 0?void 0:[Math.sin(m*Math.PI/180),-Math.cos(m*Math.PI/180)];(b!==void 0?Math.abs(b[0]*c[0]+b[1]*c[1])>Math.abs(b[0]*a[0]+b[1]*a[1]):t.roof_orientation==="across")&&u!=="skillion"&&([c,a,f,h]=[a,c,h,f]);let x=Je(u,f,h,b&&[pe(b,c),pe(b,a)]);if(!x)return;let I=Math.max(0,o-s),B=ge(t.roof_height),M,y;if(B!==void 0&&B>0)y=o,M=Math.max(s+Math.min(2,I/2),o-B);else{let p=Math.min(Ke(u,h),I*.6,30);t.height_source==="height"?(y=o,M=o-p):(M=o,y=o+p)}let k=y-M;if(!(k>=.3))return;let[R,N]=l.centre,F=(p,A)=>{let v=(p-R)*r,g=(A-N)*r;return[v*c[0]+g*c[1],v*a[0]+g*a[1]]},S=(p,A)=>[R+(p*c[0]+A*a[0])/r,N+(p*c[1]+A*a[1])/r],J=(p,A)=>{let v=1/0;for(let[g,E,H]of x)v=Math.min(v,g*p+E*A+H);return Math.max(0,v)},Q=(p,A)=>M+k*J(...F(p,A)),L=[];for(let p=0;p+1<e.length;p+=2)L.push(...F(e[p],e[p+1]));ne(L)<0&&nt(L);let C=1.01,$=[-f*C,-h*C,f*C,-h*C,f*C,h*C,-f*C,h*C],V=[];for(let[p,A]of x.entries()){let v=$;for(let[T,j]of x.entries()){if(T===p)continue;let z=A[0]-j[0],nn=A[1]-j[1],en=A[2]-j[2];if(Math.abs(z)+Math.abs(nn)+Math.abs(en)<1e-9){T<p&&(v=[]);continue}if(v=ye(v,z,nn,en),v.length<6)break}if(v.length<6)continue;let g=L,E=v.length/2;for(let T=0;T<E&&g.length>=6;T+=1){let[j,z]=[v[T*2],v[T*2+1]],[nn,en]=[v[(T+1)%E*2],v[(T+1)%E*2+1]];g=ye(g,en-z,j-nn,-(en-z)*j-(j-nn)*z)}if(g.length<6||Math.abs(ne(g))<1e-6)continue;let H=[];for(let T=0;T<g.length;T+=2)H.push(...S(g[T],g[T+1]));let q=kn(H);if(q.length===0)continue;let on=k*A[0],Y=k*A[1],w=on*c[0]+Y*a[0],U=on*c[1]+Y*a[1],rn=Math.hypot(w,U,1);V.push({ring:H,triangles:q,normal:[-w/rn,-U/rn]})}if(V.length!==0)return{eaves:M,ridge:y,faces:V,heightAt:Q,breaks(p,A,v,g){let[E,H]=F(p,A),[q,on]=F(v,g),Y=[];for(let w=0;w<x.length;w+=1)for(let U=w+1;U<x.length;U+=1){let rn=(Z,P)=>(x[w][0]-x[U][0])*Z+(x[w][1]-x[U][1])*P+(x[w][2]-x[U][2]),T=rn(E,H),j=rn(q,on);if(T===j||T*j>0)continue;let z=T/(T-j);if(z<=1e-4||z>=1-1e-4)continue;let nn=E+(q-E)*z,en=H+(on-H)*z;x[w][0]*nn+x[w][1]*en+x[w][2]<=J(nn,en)+1e-6&&Y.push(z)}return[...new Set(Y.map(w=>Math.round(w*1e6)/1e6))].sort((w,U)=>w-U)}}}function Ke(n,e){switch(n){case"skillion":return 2*e*We;case"pyramidal":return e*De;case"gambrel":case"mansard":return e*.8;case"dome":case"onion":case"round":return e;default:return e*Ge}}function Je(n,e,t,s){let o=e,r=t,i=[[0,-1/r,1],[0,1/r,1]],u=c=>c.flatMap(a=>[1,-1].flatMap(f=>{let h=a==="v"?r:o,m=Bn/(Fn*r)*f,b=(1-Bn)/((1-Fn)*r)*f,d=x=>a==="v"?[0,-x]:[-x,0];return[[...d(m),Bn/(Fn*r)*h],[...d(b),Bn+(1-Bn)/((1-Fn)*r)*(h-Fn*r)]]})),l=[.99,.8,.5,.2];switch(n){case"gabled":return i;case"saltbox":{let c=r/3;return[[0,-1/(r-c),1+c/(r-c)],[0,1/(r+c),1-c/(r+c)]]}case"hipped":return[...i,[-1/r,0,o/r],[1/r,0,o/r]];case"half_hipped":return[...i,[-1/r,0,.5+o/r],[1/r,0,.5+o/r]];case"pyramidal":return[...i,[-1/o,0,1],[1/o,0,1]];case"gambrel":return u(["v"]);case"mansard":return u(["v","u"]);case"skillion":{let[c,a]=s??[0,1],f=Math.abs(c)*o+Math.abs(a)*r;return f>0?[[-c/(2*f),-a/(2*f),.5]]:void 0}case"round":return[[0,0,1],...l.flatMap(c=>{let a=Math.sqrt(1-c*c);return[1,-1].map(f=>[0,-f*c/(r*a),1/a])})];case"dome":case"onion":return[[0,0,1],...l.flatMap(c=>{let a=Math.sqrt(1-c*c);return Array.from({length:12},(f,h)=>{let m=h*Math.PI/6;return[-c*Math.cos(m)/(o*a),-c*Math.sin(m)/(r*a),1/a]})})];default:return}}function ye(n,e,t,s){let o=n.length/2,r=[];for(let i=0;i<o;i+=1){let u=n[i*2],l=n[i*2+1],c=n[(i+1)%o*2],a=n[(i+1)%o*2+1],f=e*u+t*l+s,h=e*c+t*a+s;if(f<=0&&r.push(u,l),f<0&&h>0||f>0&&h<0){let m=f/(f-h);r.push(u+(c-u)*m,l+(a-l)*m)}}return r}function Qe(n){let e=$e(n);if(e.length<3)return;let t,s=1/0;for(let o=0;o<e.length;o+=1){let[r,i]=e[o],[u,l]=e[(o+1)%e.length],c=Math.hypot(u-r,l-i);if(c===0)continue;let a=[(u-r)/c,(l-i)/c],f=[-a[1],a[0]],[h,m,b,d]=[1/0,-1/0,1/0,-1/0];for(let[I,B]of e){let M=I*a[0]+B*a[1],y=I*f[0]+B*f[1];h=Math.min(h,M),m=Math.max(m,M),b=Math.min(b,y),d=Math.max(d,y)}let x=(m-h)*(d-b);if(x<s){s=x;let I=(h+m)/2,B=(b+d)/2;t={centre:[I*a[0]+B*f[0],I*a[1]+B*f[1]],u:a,v:f,halfU:(m-h)/2,halfV:(d-b)/2}}}return t&&t.halfU>0&&t.halfV>0?t:void 0}function $e(n){let e=[];for(let r=0;r+1<n.length;r+=2)e.push([n[r],n[r+1]]);e.sort((r,i)=>r[0]-i[0]||r[1]-i[1]);let t=(r,i,u)=>(i[0]-r[0])*(u[1]-r[1])-(i[1]-r[1])*(u[0]-r[0]),s=[];for(let r of e){for(;s.length>=2&&t(s.at(-2),s.at(-1),r)<=0;)s.pop();s.push(r)}let o=[];for(let r of e.reverse()){for(;o.length>=2&&t(o.at(-2),o.at(-1),r)<=0;)o.pop();o.push(r)}return[...s.slice(0,-1),...o.slice(0,-1)]}function qe(n,e){let[t,s,o,r]=[1/0,-1/0,1/0,-1/0];for(let u=0;u+1<n.length;u+=2)t=Math.min(t,n[u]),s=Math.max(s,n[u]),o=Math.min(o,n[u+1]),r=Math.max(r,n[u+1]);let i=n.length/2;for(let u=0;u<i;u+=1){let l=n[u*2],c=n[u*2+1],a=n[(u+1)%i*2],f=n[(u+1)%i*2+1];if(t<0&&l===t&&a===t||s>e&&l===s&&a===s||o<0&&c===o&&f===o||r>e&&c===r&&f===r)return!0}return!1}function ne(n){let e=0,t=n.length/2;for(let s=0;s<t;s+=1){let o=(s+1)%t;e+=n[s*2]*n[o*2+1]-n[o*2]*n[s*2+1]}return e/2}function nt(n){let e=[];for(let t=0;t<n.length;t+=2)e.push([n[t],n[t+1]]);e.reverse(),n.splice(0,n.length,...e.flat())}function pe(n,e){return n[0]*e[0]+n[1]*e[1]}function ge(n){let e=typeof n=="string"?Number(n):n;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var gt=Object.freeze({surface:0,secondary:1,glass:2,accent:3,roof:4}),Mt=Object.freeze({levels:3,vertices:2e5,triangles:2e5,footprintPoints:4096,radius:2e3,height:1e3,models:512,bytes:16*1024*1024});function ee(n,e,t){for(let s of n){let o=!1;for(let r=0,i=s.length-2;r<s.length;i=r,r+=2){let u=s[r],l=s[r+1],c=s[i],a=s[i+1];l>t!=a>t&&e<(c-u)*(t-l)/(a-l)+u&&(o=!o)}if(o)return!0}return!1}function Re(n,e,t){for(let s of e){let[o,r,i,u]=ve(s);for(let l of n){let[c,a,f,h]=ve(l);if(!(c>i-t||f<o+t||a>u-t||h<r+t)&&(we(l,s,t)||we(s,l,t)))return!0}}return!1}function we(n,e,t){let s=(o,r)=>ee([e],o,r)&&tt(e,o,r)>t;for(let o=0;o+1<n.length;o+=2)if(s(n[o],n[o+1]))return!0;for(let o=0,r=n.length-2;o<n.length;r=o,o+=2){let[i,u,l,c]=[n[r],n[r+1],n[o],n[o+1]],a=[0,1];for(let f=0,h=e.length-2;f<e.length;h=f,f+=2){let m=et(i,u,l,c,e[h],e[h+1],e[f],e[f+1]);m!==void 0&&a.push(m)}if(a.length!==2){a.sort((f,h)=>f-h);for(let f=1;f<a.length;f+=1){let h=(a[f-1]+a[f])/2;if(s(i+(l-i)*h,u+(c-u)*h))return!0}}}return!1}function et(n,e,t,s,o,r,i,u){let l=t-n,c=s-e,a=i-o,f=u-r,h=l*f-c*a;if(h===0)return;let m=((o-n)*f-(r-e)*a)/h,b=((o-n)*c-(r-e)*l)/h;return m>0&&m<1&&b>=0&&b<=1?m:void 0}function tt(n,e,t){let s=1/0;for(let o=0,r=n.length-2;o<n.length;r=o,o+=2){let[i,u,l,c]=[n[r],n[r+1],n[o],n[o+1]],a=(l-i)**2+(c-u)**2,f=a>0?Math.max(0,Math.min(1,((e-i)*(l-i)+(t-u)*(c-u))/a)):0;s=Math.min(s,Math.hypot(e-(i+(l-i)*f),t-(u+(c-u)*f)))}return s}function ve(n){let[e,t,s,o]=[1/0,1/0,-1/0,-1/0];for(let r=0;r+1<n.length;r+=2)e=Math.min(e,n[r]),s=Math.max(s,n[r]),t=Math.min(t,n[r+1]),o=Math.max(o,n[r+1]);return[e,t,s,o]}var tn=8192,te=28,ot={commercial:1,active:2,destination:3},rt={residential:1,...Object.fromEntries(["civic","commercial","education","entertainment","medical","transportation"].map(n=>[n,2])),...Object.fromEntries(["agricultural","industrial","military","outbuilding","religious","service"].map(n=>[n,3]))},st={dining:1,entertainment:2,nightlife:3},oe={...Object.fromEntries(["alcoholic_beverage_venue","bar","beer","biergarten","brewery","casino","cocktail_bar","dance_club","karaoke","lounge","music_venue","night_club","nightclub","pub","wine_bar"].map(n=>[n,3])),...Object.fromEntries(["arts_centre","bowling_alley","cinema","comedy_club","concert_hall","movie_theater","opera","performing_arts_venue","theater","theatre","theatre_venue"].map(n=>[n,2])),...Object.fromEntries(["casual_eatery","fast_food","fast_food_restaurant","food_court","restaurant"].map(n=>[n,1]))},ut=6,it=.5,lt=.5;function Ue(n,e){let t=tn/n.extent,s=e.tileMetres/tn,o=e.defaultHeight??5,r=Number.isFinite(e.edgeRadius)?Math.max(0,Math.min(1,e.edgeRadius))/s:0,i=new re,u=new Yn,l=new Yn,c=[],a=[],f=0,h=ht(n,e);for(let[y,k]of n.features.entries()){if(k.type!=="Polygon"||c.length>=65535)continue;let R=k.properties,N=R.hide_3d;if(N===!0||N===1||N==="1"||N==="true")continue;let F=Math.min(6e3,Ae(R.render_height)??o),S=Math.min(F,Ae(R.render_min_height)??0),J=ot[String(R.building_tone??"")]??0,Q=rt[String(R.class??"")]??0,L=h.get(y)??0,C=c.length,$=!1;for(let V of mt(k.geometry,t)){let p=V.map(xt).filter(w=>w.length>=6);if(p.length===0||Xn(p[0])===0)continue;let[A,v]=bt(p[0]);if(e.masks?.length&&(ee(e.masks,A,v)||Re(p,e.masks,lt/s)))continue;let g={cell:Math.min(7,Math.max(0,Math.floor(v/1024)))*8+Math.min(7,Math.max(0,Math.floor(A/1024))),bounds:[1/0,1/0,-1/0,-1/0,F+.1],roofsFrom:u.length,roofsCount:0,wallsFrom:l.length,wallsCount:0};for(let w of p)for(let U=0;U<w.length;U+=2)g.bounds[0]=Math.min(g.bounds[0],w[U]-1),g.bounds[1]=Math.min(g.bounds[1],w[U+1]-1),g.bounds[2]=Math.max(g.bounds[2],w[U]+1),g.bounds[3]=Math.max(g.bounds[3],w[U+1]+1);$=!0,f=Math.max(f,F);let E=Ie(A*.0731+v*.19137+C*1.618),H=p[0].some(w=>w<=0||w>=tn)?Ie(F*7.31+S*3.17+J):E,q={base:S,top:F,jitter:H,seed:E,tone:J,group:Q,use:L,cx:A,cy:v,index:C},on=p.map((w,U)=>ft(w,U,r,e.cornerAngle));p=on.map(({ring:w})=>w);let Y=V.length===1&&p.length===1?Me(V[0],p[0],R,S,F,s,tn):void 0;Y?(f=Math.max(f,Y.ridge),g.bounds[4]=Math.max(g.bounds[4],Y.ridge+.1),at(Y,q,i,u)):ct(p,q,i,u);for(let[w,U]of p.entries()){let rn=Xn(U)>0,T=w===0?rn?-1:1:rn?1:-1,j=U.length/2,z=Z=>{let P=(Z%j+j)%j;return[U[P*2],U[P*2+1]]},nn=Z=>{let[P,D]=z(Z-1),[X,G]=z(Z),[un,mn]=z(Z+1);if(hn(P,D,X,G)||hn(X,G,un,mn))return!1;let bn=Math.hypot(X-P,G-D),ln=Math.hypot(un-X,mn-G);if(!bn||!ln)return!1;let _n=-(G-D)/bn*T,Pn=(X-P)/bn*T;return(_n*(un-X)+Pn*(mn-G))/ln>it},en=(Z,P)=>Y?Y.heightAt(Z,P):F,pn=0;for(let Z=0;Z<j;Z+=1){let[P,D]=z(Z),[X,G]=z(Z+1),un=Math.hypot(X-P,G-D);if(un===0||hn(P,D,X,G))continue;let mn=-(G-D)/un*T,bn=(X-P)/un*T,ln=on[w].normals[Z]??[mn,bn],_n=on[w].normals[(Z+1)%j]??[mn,bn],Pn=W=>{let gn=ln[0]+(_n[0]-ln[0])*W,Mn=ln[1]+(_n[1]-ln[1])*W,cn=Math.hypot(gn,Mn)||1;return[gn/cn,Mn/cn]},sn=[0,...Y?Y.breaks(P,D,X,G):[],1];for(let W=0;W+1<sn.length;W+=1){let gn=W===0,Mn=W+2===sn.length,cn=P+(X-P)*sn[W],On=D+(G-D)*sn[W],Ln=P+(X-P)*sn[W+1],Cn=D+(G-D)*sn[W+1],wn=Math.hypot(Ln-cn,Cn-On)/tn*e.tileMetres,zn=(gn&&nn(Z)?1:0)|(Mn&&nn(Z+1)?2:0)|(w>0?4:0),Zn=(gn&&se(P,D)?1:0)|(Mn&&se(X,G)?2:0),Gn=pn+wn,Sn=Pn(sn[W]),jn=Pn(sn[W+1]),ie=en(cn,On),le=en(Ln,Cn),xn=i.write(q,cn,On,0,Sn[0],Sn[1],1,pn,zn,wn,0,Zn,ie);i.write(q,Ln,Cn,0,jn[0],jn[1],1,Gn,zn,wn,1,Zn,le),i.write(q,cn,On,1,Sn[0],Sn[1],1,pn,zn,wn,0,Zn,ie),i.write(q,Ln,Cn,1,jn[0],jn[1],1,Gn,zn,wn,1,Zn,le),l.push(xn,xn+1,xn+2,xn+1,xn+3,xn+2),pn=Gn}}}g.roofsCount=u.length-g.roofsFrom,g.wallsCount=l.length-g.wallsFrom,a.push(g)}$&&c.push(R)}if(i.count===0)return;let m=new Uint32Array(u.length+l.length),b=[],d=0,x=u.length,I=u.values(),B=l.values();a.sort((y,k)=>y.cell-k.cell);let M=-1;for(let y of a){y.cell!==M&&(M=y.cell,b.push({bounds:[...y.bounds],roofsFrom:d,roofsCount:0,wallsFrom:x,wallsCount:0}));let k=b.at(-1);for(let R=0;R<5;R+=1)k.bounds[R]=R<2?Math.min(k.bounds[R],y.bounds[R]):Math.max(k.bounds[R],y.bounds[R]);m.set(I.subarray(y.roofsFrom,y.roofsFrom+y.roofsCount),d),m.set(B.subarray(y.wallsFrom,y.wallsFrom+y.wallsCount),x),d+=y.roofsCount,x+=y.wallsCount,k.roofsCount+=y.roofsCount,k.wallsCount+=y.wallsCount}return{groups:b,vertices:i.bytes(),indices:m,wallsFrom:u.length,top:f,features:c}}function ct(n,e,t,s){let o=[],r=[];for(let l of n)r.push(o.length/2),o.push(...l);r.push(o.length/2);let i=(l,c)=>{let a=r.findIndex((d,x)=>l>=d&&l<r[x+1]),[f,h]=[r[a],r[a+1]-1];if(c<f||c>h)return!1;let[m,b]=l<c?[l,c]:[c,l];return b-m!==1&&!(m===f&&b===h)?!1:!hn(o[l*2],o[l*2+1],o[c*2],o[c*2+1])},u=kn(o,r.slice(1,-1),2);for(let l=0;l+2<u.length;l+=3){let c=[u[l],u[l+1],u[l+2]],a=0;for(let f=0;f<3;f+=1)i(c[(f+1)%3],c[(f+2)%3])&&(a|=1<<f);for(let[f,h]of c.entries())s.push(t.write(e,o[h*2],o[h*2+1],1,0,0,0,0,0,0,f,a))}}function at(n,e,t,s){for(let o of n.faces){let r=o.ring,i=r.length/2,u=(l,c)=>{let[a,f]=l<c?[l,c]:[c,l];return f-a!==1&&!(a===0&&f===i-1)?!1:!hn(r[l*2],r[l*2+1],r[c*2],r[c*2+1])};for(let l=0;l+2<o.triangles.length;l+=3){let c=[o.triangles[l],o.triangles[l+1],o.triangles[l+2]],a=0;for(let f=0;f<3;f+=1)u(c[(f+1)%3],c[(f+2)%3])&&(a|=1<<f);for(let[f,h]of c.entries()){let m=r[h*2],b=r[h*2+1];s.push(t.write(e,m,b,1,o.normal[0],o.normal[1],0,0,0,0,f,a,n.heightAt(m,b)))}}}}function ft(n,e,t,s=Math.PI/6){if(t<1)return{ring:n,normals:[]};let o=n.length/2,r=Xn(n)>0,i=e===0?r?-1:1:r?1:-1,u=[],l=[],c=(a,f,h)=>{a=yn(a),f=yn(f),!(u.at(-2)===a&&u.at(-1)===f)&&(u.push(a,f),l.push(h))};for(let a=0;a<o;a+=1){let f=(a+o-1)%o,h=(a+1)%o,[m,b]=[n[f*2],n[f*2+1]],[d,x]=[n[a*2],n[a*2+1]],[I,B]=[n[h*2],n[h*2+1]],M=Math.hypot(d-m,x-b),y=Math.hypot(I-d,B-x);if(!M||!y||se(d,x)||hn(m,b,d,x)||hn(d,x,I,B)){c(d,x);continue}let[k,R]=[(d-m)/M,(x-b)/M],[N,F]=[(I-d)/y,(B-x)/y],S=Math.atan2(k*F-R*N,k*N+R*F);if(S*i>=-.08||Math.abs(S)>Math.PI*.85){c(d,x);continue}let J=Math.tan(Math.abs(S)/2),Q=Math.min(t*J,M*.2,y*.2),L=Q/J;if(L<1){c(d,x);continue}let[C,$]=[-R*i,k*i],[V,p]=[d-k*Q-C*L,x-R*Q-$*L],A=Math.atan2($,C),v=Math.max(s<=Math.PI/6?2:1,Math.ceil(Math.abs(S)/Math.max(Math.PI/6,Math.min(Math.PI/3,s))));for(let g=0;g<=v;g+=1){let E=A+S*g/v,H=[Math.cos(E),Math.sin(E)];c(V+H[0]*L,p+H[1]*L,H)}}return u[0]===u.at(-2)&&u[1]===u.at(-1)&&(u.splice(-2),l.pop()),u.length>=6?{ring:u,normals:l}:{ring:n,normals:[]}}var re=class{#n=new ArrayBuffer(4096*te);#e=new DataView(this.#n);count=0;write(e,t,s,o,r,i,u,l,c,a,f=0,h=0,m=e.top){let b=te;if((this.count+1)*b>this.#n.byteLength){let I=new ArrayBuffer(this.#n.byteLength*2);new Uint8Array(I).set(new Uint8Array(this.#n)),this.#n=I,this.#e=new DataView(I)}let d=this.#e,x=this.count*b;return d.setUint16(x,yn(t),!0),d.setUint16(x+2,yn(s),!0),d.setUint16(x+4,Math.min(65535,Math.round(e.base*10)),!0),d.setUint16(x+6,Math.min(65535,Math.max(0,Math.round(m*10))),!0),d.setInt8(x+8,Math.round(r*127)),d.setInt8(x+9,Math.round(i*127)),d.setUint8(x+10,o),d.setUint8(x+11,u),d.setUint16(x+12,Math.round(l*10)%65536,!0),d.setUint8(x+14,Math.round(e.jitter*255)),d.setUint8(x+15,Math.round(e.seed*255)),d.setUint16(x+16,yn(e.cx),!0),d.setUint16(x+18,yn(e.cy),!0),d.setUint8(x+20,e.tone+4*e.group),d.setUint8(x+21,e.use),d.setUint8(x+22,c),d.setUint8(x+23,Math.min(255,Math.round(a))),d.setUint16(x+24,e.index,!0),d.setUint8(x+26,f),d.setUint8(x+27,h),this.count+=1,this.count-1}bytes(){return new Uint8Array(this.#n.slice(0,this.count*te))}},Yn=class{#n=new Uint32Array(8192);length=0;push(...e){if(this.length+e.length>this.#n.length){let t=new Uint32Array(Math.max(this.length+e.length,this.#n.length*2));t.set(this.#n),this.#n=t}for(let t of e)this.#n[this.length++]=t}values(){return this.#n.subarray(0,this.length)}};function ht(n,e){let t=new Map;if(n.features.some(u=>u.properties.night_use!==void 0)){for(let[u,l]of n.features.entries()){let c=st[String(l.properties.night_use??"")];c&&t.set(u,c)}return t}let s=e.places;if(!s||s.features.length===0)return t;let o=ut/e.tileMetres*n.extent,r=[];for(let[u,l]of n.features.entries()){if(l.type!=="Polygon")continue;let c=l.properties.hide_3d;if(c===!0||c===1||c==="1"||c==="true")continue;let a=[1/0,1/0,-1/0,-1/0];for(let f of l.geometry)for(let h=0;h+1<f.length;h+=2)a[0]=Math.min(a[0],f[h]),a[1]=Math.min(a[1],f[h+1]),a[2]=Math.max(a[2],f[h]),a[3]=Math.max(a[3],f[h+1]);r.push({index:u,rings:l.geometry,box:a})}let i=n.extent/s.extent;for(let u of s.features){if(u.type!=="Point")continue;let l=u.properties,c=oe[String(l.type??"")]??oe[String(l.subclass??"")]??oe[String(l.class??"")];if(c)for(let a of u.geometry)for(let f=0;f+1<a.length;f+=2){let h=a[f]*i,m=a[f+1]*i,b,d,x=o;for(let B of r){let[M,y,k,R]=B.box;if(h<M-o||h>k+o||m<y-o||m>R+o)continue;let N=!1;for(let F of B.rings)for(let S=0,J=F.length-2;S+1<F.length;J=S,S+=2){let Q=F[J],L=F[J+1],C=F[S],$=F[S+1];$>m!=L>m&&h<(Q-C)*(m-$)/(L-$)+C&&(N=!N);let V=C-Q,p=$-L,A=V*V+p*p,v=A?Math.min(1,Math.max(0,((h-Q)*V+(m-L)*p)/A)):0,g=Math.hypot(h-Q-v*V,m-L-v*p);g<x&&(x=g,d=B.index)}if(N){b=B.index;break}}let I=b??d;I!==void 0&&t.set(I,Math.max(t.get(I)??0,c))}}return t}function yn(n){return Math.min(tn,Math.max(0,Math.round(n)))}function Ae(n){let e=Number(n);return Number.isFinite(e)&&e>0?e:void 0}function mt(n,e){let t=[],s;for(let o of n){let r=[];for(let u=0;u+1<o.length;u+=2){let l=o[u]*e,c=o[u+1]*e;r.length&&l===r.at(-2)&&c===r.at(-1)||r.push(l,c)}if(r.length>=6&&r[0]===r.at(-2)&&r[1]===r.at(-1)&&(r.length-=2),r.length<6)continue;let i=Math.sign(Xn(r));i&&(s??=i,i===s||t.length===0?t.push([r]):t.at(-1).push(r))}return t}function Xn(n){let e=0,t=n.length/2;for(let s=0;s<t;s+=1){let o=(s+1)%t;e+=n[s*2]*n[o*2+1]-n[o*2]*n[s*2+1]}return e}function bt(n){let e=0,t=0,s=n.length/2;for(let o=0;o<s;o+=1)e+=n[o*2],t+=n[o*2+1];return[e/s,t/s]}function se(n,e){return n<=0||e<=0||n>=tn||e>=tn}function hn(n,e,t,s){let o=tn;return n<=0&&t<=0||n>=o&&t>=o||e<=0&&s<=0||e>=o&&s>=o}function xt(n){let e=tn,t=[...n],s=[[0,0,o=>o>=0],[0,e,o=>o<=e],[1,0,o=>o>=0],[1,e,o=>o<=e]];for(let[o,r,i]of s){let u=[],l=t.length/2;for(let c=0;c<l;c+=1){let a=[t[c*2],t[c*2+1]],f=[t[(c+1)%l*2],t[(c+1)%l*2+1]],h=i(a[o]),m=i(f[o]);if(h&&u.push(a[0],a[1]),h!==m){let b=(r-a[o])/(f[o]-a[o]);u.push(a[0]+(f[0]-a[0])*b,a[1]+(f[1]-a[1])*b)}}if(t=u,t.length<6)return[]}return t}function Ie(n){let e=Math.sin(n*12.9898+78.233)*43758.5453;return e-Math.floor(e)}var ue=globalThis;ue.onmessage=({data:n})=>{try{let e=Ue(n.layer,n.options);ue.postMessage({mesh:e},e?[e.vertices.buffer,e.indices.buffer]:[])}catch(e){ue.postMessage({error:String(e)})}};})();
|