isard 1.6.0 → 1.8.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/dist/basemap/furniture.d.ts +20 -2
  3. package/dist/basemap/furniture.js +72 -3
  4. package/dist/basemap/furniture.js.map +1 -1
  5. package/dist/basemap/meshes.d.ts +21 -0
  6. package/dist/basemap/meshes.js +159 -0
  7. package/dist/basemap/meshes.js.map +1 -0
  8. package/dist/basemap/placed.d.ts +13 -0
  9. package/dist/basemap/placed.js +14 -0
  10. package/dist/basemap/placed.js.map +1 -0
  11. package/dist/basemap/trees.d.ts +4 -14
  12. package/dist/basemap/trees.js +12 -93
  13. package/dist/basemap/trees.js.map +1 -1
  14. package/dist/basemap/vectortiles/context.d.ts +4 -2
  15. package/dist/basemap/vectortiles/context.js.map +1 -1
  16. package/dist/basemap/vectortiles/extrusions.d.ts +1 -1
  17. package/dist/basemap/vectortiles/extrusions.js +7 -16
  18. package/dist/basemap/vectortiles/extrusions.js.map +1 -1
  19. package/dist/basemap/vectortiles/furniture.d.ts +19 -0
  20. package/dist/basemap/vectortiles/furniture.js +29 -0
  21. package/dist/basemap/vectortiles/furniture.js.map +1 -0
  22. package/dist/basemap/vectortiles/labels.js +8 -1
  23. package/dist/basemap/vectortiles/labels.js.map +1 -1
  24. package/dist/basemap/vectortiles/lamps.js +11 -76
  25. package/dist/basemap/vectortiles/lamps.js.map +1 -1
  26. package/dist/basemap/vectortiles/placed.d.ts +38 -0
  27. package/dist/basemap/vectortiles/placed.js +143 -0
  28. package/dist/basemap/vectortiles/placed.js.map +1 -0
  29. package/dist/basemap/vectortiles/street-wind.js +4 -6
  30. package/dist/basemap/vectortiles/street-wind.js.map +1 -1
  31. package/dist/basemap/vectortiles/trees.d.ts +2 -9
  32. package/dist/basemap/vectortiles/trees.js +34 -165
  33. package/dist/basemap/vectortiles/trees.js.map +1 -1
  34. package/dist/basemap/vectortiles/vectors.d.ts +4 -5
  35. package/dist/basemap/vectortiles/vectors.js +17 -16
  36. package/dist/basemap/vectortiles/vectors.js.map +1 -1
  37. package/dist/basemap/vectortiles.d.ts +14 -4
  38. package/dist/basemap/vectortiles.js +40 -12
  39. package/dist/basemap/vectortiles.js.map +1 -1
  40. package/dist/basemap/wmts.js +2 -2
  41. package/dist/basemap/wmts.js.map +1 -1
  42. package/dist/basemap.worker.js +2 -2
  43. package/dist/basemap.worker.js.map +18 -14
  44. package/dist/bind/layers.d.ts +10 -3
  45. package/dist/bind/layers.js +11 -4
  46. package/dist/bind/layers.js.map +1 -1
  47. package/dist/data/collada.js +3 -17
  48. package/dist/data/collada.js.map +1 -1
  49. package/dist/data/crs.js +1 -1
  50. package/dist/data/crs.js.map +1 -1
  51. package/dist/data/ifc.js +21 -22
  52. package/dist/data/ifc.js.map +1 -1
  53. package/dist/geoplateforme.d.ts +16 -4
  54. package/dist/geoplateforme.js +26 -4
  55. package/dist/geoplateforme.js.map +1 -1
  56. package/dist/index.d.ts +5 -4
  57. package/dist/index.js +3 -3
  58. package/dist/index.js.map +1 -1
  59. package/dist/isard_bg.wasm +0 -0
  60. package/dist/isard_core_bg.wasm +0 -0
  61. package/dist/isard_grid_bg.wasm +0 -0
  62. package/dist/isard_tess_bg.wasm +0 -0
  63. package/dist/layers/extrusions.js +5 -4
  64. package/dist/layers/extrusions.js.map +1 -1
  65. package/dist/layers/features.d.ts +0 -2
  66. package/dist/layers/features.js +5 -6
  67. package/dist/layers/features.js.map +1 -1
  68. package/dist/layers/layers.d.ts +2 -0
  69. package/dist/layers/layers.js +11 -0
  70. package/dist/layers/layers.js.map +1 -1
  71. package/dist/layers/panoramas.d.ts +32 -10
  72. package/dist/layers/panoramas.js +55 -28
  73. package/dist/layers/panoramas.js.map +1 -1
  74. package/dist/layers/photos.js +5 -6
  75. package/dist/layers/photos.js.map +1 -1
  76. package/dist/layers/trees.js +7 -7
  77. package/dist/layers/trees.js.map +1 -1
  78. package/dist/layers/vectors.d.ts +1 -0
  79. package/dist/layers/vectors.js +23 -8
  80. package/dist/layers/vectors.js.map +1 -1
  81. package/dist/map/frame-loop.d.ts +2 -0
  82. package/dist/map/frame-loop.js +3 -3
  83. package/dist/map/frame-loop.js.map +1 -1
  84. package/dist/map.js +17 -0
  85. package/dist/map.js.map +1 -1
  86. package/dist/panoramax.d.ts +19 -0
  87. package/dist/panoramax.js +48 -3
  88. package/dist/panoramax.js.map +1 -1
  89. package/dist/react/CustomLayer.js +5 -4
  90. package/dist/react/CustomLayer.js.map +1 -1
  91. package/dist/react/Layer.d.ts +1 -1
  92. package/dist/react/Layer.js +6 -5
  93. package/dist/react/Layer.js.map +1 -1
  94. package/dist/react/VectorGeometry.d.ts +18 -9
  95. package/dist/react/VectorGeometry.js +30 -15
  96. package/dist/react/VectorGeometry.js.map +1 -1
  97. package/dist/react/VectorTiles.d.ts +65 -0
  98. package/dist/react/VectorTiles.js +112 -0
  99. package/dist/react/VectorTiles.js.map +1 -0
  100. package/dist/react/context.d.ts +12 -0
  101. package/dist/react/context.js +40 -1
  102. package/dist/react/context.js.map +1 -1
  103. package/dist/react/index.d.ts +7 -1
  104. package/dist/react/index.js +7 -1
  105. package/dist/react/index.js.map +1 -1
  106. package/dist/types.d.ts +2 -0
  107. package/dist/types.js.map +1 -1
  108. package/dist/util/geo.d.ts +8 -0
  109. package/dist/util/geo.js +8 -0
  110. package/dist/util/geo.js.map +1 -1
  111. package/dist/util/gltf.d.ts +18 -1
  112. package/dist/util/gltf.js +26 -1
  113. package/dist/util/gltf.js.map +1 -1
  114. package/dist/util/roofs.d.ts +8 -0
  115. package/dist/util/roofs.js +16 -2
  116. package/dist/util/roofs.js.map +1 -1
  117. package/dist/util/style-floats.d.ts +33 -0
  118. package/dist/util/style-floats.js +34 -0
  119. package/dist/util/style-floats.js.map +1 -0
  120. package/dist/util/sun.js +1 -1
  121. package/dist/util/sun.js.map +1 -1
  122. package/dist/workers/basemap/furniture.d.ts +13 -0
  123. package/dist/workers/basemap/geometry.d.ts +2 -5
  124. package/dist/workers/basemap/labels.d.ts +5 -2
  125. package/dist/workers/basemap/lamps.d.ts +3 -3
  126. package/dist/workers/basemap/tiles.d.ts +2 -0
  127. package/dist/workers/basemap/trees.d.ts +3 -0
  128. package/dist/workers/basemap.worker.d.ts +17 -1
  129. package/dist/workers/basemap.worker.js +12 -1
  130. package/dist/workers/basemap.worker.js.map +1 -1
  131. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,76 @@
3
3
  Every notable change of `isard`. The format follows [Keep a Changelog](https://keepachangelog.com), the
4
4
  versions [Semantic Versioning](https://semver.org) (before 1.0.0, a minor version may change an API).
5
5
 
6
+ ## [Unreleased]
7
+
8
+ ### Fixed
9
+
10
+ - React: the layers of the components are drawn in their declared order even when one comes later than another: a
11
+ `<Geometry>` waits for its tiles, so a `<Layer type="tiles3d">` declared after it came first and the ground of the
12
+ geometry was drawn over the buildings. Each component takes its place when it first renders (`LayerOrder.rank`);
13
+ the Bâtiments 3D example drops its `order={1}`.
14
+
15
+ ## [1.8.0] - 2026-10-26
16
+
17
+ ### Added
18
+
19
+ - `panoramaxSequence(sequence, { around, max, api })` reads a long sequence around a photo (the page holding it, then
20
+ half before and half after): a survey car's day is thousands of photos, the 2000 first of them far from the one
21
+ clicked. The Panoramax example walks a 360° photo's sequence from that photo.
22
+ - The Panoramax 360° example (TypeScript and React): a walk in a survey car's 360° photos along the Louvre, each
23
+ projected onto the city around.
24
+ - The Bâtiments 3D example (TypeScript and React): the IGN's buildings of France in 3D (a beta, its server now
25
+ answering isard's documentation) over the 3D vector map in place of its raised buildings, picked with their BD TOPO
26
+ attributes, by day and by night.
27
+
28
+ ## [1.7.0] - 2026-10-26
29
+
30
+ ### Added
31
+
32
+ - 360° photos at street level: `addPanoramas({ photos })` takes equirectangular images (where each was taken, the way
33
+ its middle faces), projected onto the scene around and walked along as a vehicle's panoramas are (the engine's
34
+ panorama pass: a camera without focal read as equirectangular). `panoramaxSequence` reads a Panoramax sequence's
35
+ photos in their order, `panoramaxPanoramas` gives its 360° ones; in the Panoramax example, From there on a 360° photo
36
+ walks in its sequence (the wheel, Z and S).
37
+ - The BD TOPO's roofs at their height: `bdtopoRoofs()` raises a building to its ridge under a roof from its eaves to
38
+ its ridge (`altitude_minimale_toit`, `altitude_maximale_toit`; flat under half a metre) where the BD TOPO gives them
39
+ (most of the towns, not Paris yet), else to its `hauteur` (its eaves) under a roof generated within;
40
+ `bdtopoBuildings` uses it, as the Buildings examples do (the React one now with roofs too).
41
+ - Street furniture: `tiles.furniture()` places, from OpenMapTiles' points of interest of the street, a bus shelter at
42
+ each bus stop, waste baskets, post boxes, drinking fountains (Wallace's) and bicycle racks, each facing the nearest
43
+ street, and benches along the pedestrian streets and the paths of the parks and gardens; made here as glTF models
44
+ (no file to download), one instanced draw a kind, all of them near the camera and fewer away from it. The street lamps and the furniture share their placing
45
+ (`placed`: the workers' things around the view); a model's translucent color is blended. The 3D vector examples show
46
+ them. About 0.7 KB gzipped more for the basemap worker.
47
+
48
+ - React: `<VectorTiles>` holds the vector tiles of a style, its children drawing from them with one set of tiles and
49
+ workers: `<Geometry>`, `<Trees>`, `<Lamps>`, `<Furniture>`, `<Extrusions>`, `<Labels>`, their options as props
50
+ (compared by value: an object written inline keeps the layer); `useVectorTiles()` for a part of your own. The React
51
+ examples drop their components of an effect and a second `vectorTiles()` of the same style (its tiles fetched and
52
+ cut twice); `<VectorGeometry>` stays, a `<Geometry>` with tiles of its own.
53
+ - `Layer.removed`; a layer of a `VectorTiles` removed stops following the view (its tiles no longer asked for), the
54
+ others going on.
55
+
56
+ ### Fixed
57
+
58
+ - A map could be idle before its vector tiles were there: the engine knows only the tiles it holds, so once the
59
+ engine with 3D Tiles came (a model, trees, street lamps added) and the tiles were cut again from the workers' cache
60
+ (nothing on the network meanwhile), 'idle' came with no city drawn (`whenIdle`, the visual tests: Paris by night
61
+ blank now and then on the CI). The map now waits on the work of its vector tiles (the workers' cuts, the uploads
62
+ over frames).
63
+ - An IFC model's worker failing once the model is open rejects the answers awaited (a storey's meshes, an element's
64
+ properties), which hung.
65
+ - A vector layer removed no longer uploads the tiles still waiting (it reached a freed engine after `map.destroy()`).
66
+ - The labels' workers read the buildings' heights only when the labels hide behind them (`occluded`).
67
+ - A `roof:shape` the engine does not know is generated with `roofs: 'generated'` on `extrusions()` too, as on
68
+ `vectors()`; an explicitly flat roof no longer sends its building's whole outline.
69
+
70
+ ### Changed
71
+
72
+ - The trees run on the street lamps' and furniture's placing (`placed`, the simplified trees far away an option of
73
+ it); the code of the vector tiles' workers and of the engine tidied (helpers shared, the style's floats and the
74
+ engine's texture units named). The engine and the basemap worker 0.1 KB gzipped more each.
75
+
6
76
  ## [1.6.0] - 2026-10-26
7
77
 
8
78
  ### Added
@@ -1,8 +1,26 @@
1
1
  /**
2
- * The street furniture of a vector map (`VectorTiles.lamps`): a street lamp made here as a glTF binary (no file to
3
- * download), its pole and its head flat-shaded, the head lit at night (`ModelLayer.setGlow` from `LAMP_HEAD` up).
2
+ * The street furniture of a vector map (`VectorTiles.lamps`, `VectorTiles.furniture`), each made here as a glTF binary
3
+ * (no file to download), flat-shaded: a street lamp (its head lit at night: `ModelLayer.setGlow` from `LAMP_HEAD` up),
4
+ * a bus shelter, a waste basket, a post box, a Wallace fountain, bicycle racks, a bench.
4
5
  */
5
6
  /** Metres from a lamp's foot to its head: the part lit at night */
6
7
  export declare const LAMP_HEAD = 4.6;
7
8
  /** A street lamp as a glTF binary, some 5 metres high: a thin pole, a lantern on top */
8
9
  export declare const lampModel: () => Uint8Array<ArrayBuffer>;
10
+ /** A bus shelter, 3.6 metres wide, 2.5 high: a back and two sides of glass in a steel frame, a roof, an advert at one
11
+ * end; open toward the street (its front) */
12
+ export declare const shelterModel: () => Uint8Array<ArrayBuffer>;
13
+ /** A waste basket of Paris, about a metre high: a green hoop on a post */
14
+ export declare const binModel: () => Uint8Array<ArrayBuffer>;
15
+ /** A post box of La Poste, 1.3 metres high: a yellow box on a foot */
16
+ export declare const postboxModel: () => Uint8Array<ArrayBuffer>;
17
+ /** A Wallace fountain, 2.7 metres high: a base, a column (its four caryatids), a dome, all dark green cast iron */
18
+ export declare const fountainModel: () => Uint8Array<ArrayBuffer>;
19
+ /** Bicycle racks: three steel hoops a metre apart, 0.8 metres high, across the front */
20
+ export declare const rackModel: () => Uint8Array<ArrayBuffer>;
21
+ /** A bench, 1.8 metres wide: a wooden seat and back on dark green feet, facing its front */
22
+ export declare const benchModel: () => Uint8Array<ArrayBuffer>;
23
+ /** The kinds of furniture placed by the workers, in the order of their numbers (`PLACED_KIND`) */
24
+ export declare const FURNITURE: readonly ["shelter", "bin", "postbox", "fountain", "rack", "bench"];
25
+ /** The model of each kind of furniture */
26
+ export declare const FURNITURE_MODELS: Readonly<Record<(typeof FURNITURE)[number], () => Uint8Array<ArrayBuffer>>>;
@@ -1,8 +1,9 @@
1
1
  /**
2
- * The street furniture of a vector map (`VectorTiles.lamps`): a street lamp made here as a glTF binary (no file to
3
- * download), its pole and its head flat-shaded, the head lit at night (`ModelLayer.setGlow` from `LAMP_HEAD` up).
2
+ * The street furniture of a vector map (`VectorTiles.lamps`, `VectorTiles.furniture`), each made here as a glTF binary
3
+ * (no file to download), flat-shaded: a street lamp (its head lit at night: `ModelLayer.setGlow` from `LAMP_HEAD` up),
4
+ * a bus shelter, a waste basket, a post box, a Wallace fountain, bicycle racks, a bench.
4
5
  */
5
- import { glb, revolve } from "./trees.js";
6
+ import { box, glb, join, revolve } from "./meshes.js";
6
7
  /** Colors of a street lamp (linear RGBA, as glTF's `baseColorFactor`): Paris's dark green cast iron */
7
8
  const POLE = [0.04, 0.07, 0.05, 1];
8
9
  const HEAD = [0.55, 0.52, 0.42, 1];
@@ -23,4 +24,72 @@ export const lampModel = () => {
23
24
  ], 6);
24
25
  return glb([pole, head], [POLE, HEAD]);
25
26
  };
27
+ /** Colors of the street furniture (linear RGBA): Paris's dark green cast iron, steel, wood, glass, La Poste's yellow */
28
+ const GREEN = [0.03, 0.08, 0.05, 1];
29
+ const STEEL = [0.32, 0.33, 0.34, 1];
30
+ const WOOD = [0.36, 0.2, 0.09, 1];
31
+ const GLASS = [0.55, 0.7, 0.75, 0.35];
32
+ const POSTER = [0.85, 0.82, 0.72, 1];
33
+ const YELLOW = [0.95, 0.7, 0.02, 1];
34
+ /** A bus shelter, 3.6 metres wide, 2.5 high: a back and two sides of glass in a steel frame, a roof, an advert at one
35
+ * end; open toward the street (its front) */
36
+ export const shelterModel = () => {
37
+ const [w, d, h] = [1.8, 0.7, 2.5];
38
+ const frame = join(box(-w, 0, -d, -w + 0.08, h, -d + 0.08), box(w - 0.08, 0, -d, w, h, -d + 0.08), box(-w, 0, d - 0.08, -w + 0.08, h, d), box(w - 0.08, 0, d - 0.08, w, h, d), box(-w - 0.1, h, -d - 0.1, w + 0.1, h + 0.12, d + 0.25));
39
+ const glass = join(box(-w, 0.15, -d, w, h - 0.1, -d + 0.03), box(-w, 0.15, -d, -w + 0.03, h - 0.1, d - 0.1));
40
+ const advert = box(w - 0.12, 0.3, -d + 0.1, w - 0.04, 2.1, d - 0.1);
41
+ const seat = box(-0.9, 0.42, -d + 0.05, 0.9, 0.48, -d + 0.4);
42
+ return glb([frame, glass, advert, seat], [STEEL, GLASS, POSTER, STEEL]);
43
+ };
44
+ /** A waste basket of Paris, about a metre high: a green hoop on a post */
45
+ export const binModel = () => {
46
+ const post = box(-0.04, 0, -0.32, 0.04, 1.05, -0.24);
47
+ const hoop = revolve([
48
+ [0.35, 0],
49
+ [0.38, 0.2],
50
+ [0.95, 0.24],
51
+ [0.98, 0.25],
52
+ ], 8);
53
+ return glb([post, hoop], [GREEN, GREEN]);
54
+ };
55
+ /** A post box of La Poste, 1.3 metres high: a yellow box on a foot */
56
+ export const postboxModel = () => glb([box(-0.08, 0, -0.08, 0.08, 0.6, 0.08), box(-0.25, 0.6, -0.18, 0.25, 1.3, 0.18)], [STEEL, YELLOW]);
57
+ /** A Wallace fountain, 2.7 metres high: a base, a column (its four caryatids), a dome, all dark green cast iron */
58
+ export const fountainModel = () => glb([
59
+ revolve([
60
+ [0, 0.42],
61
+ [0.35, 0.36],
62
+ [0.5, 0.22],
63
+ [1.9, 0.22],
64
+ [2.05, 0.38],
65
+ [2.3, 0.34],
66
+ [2.55, 0.18],
67
+ [2.75, 0],
68
+ ], 8),
69
+ ], [GREEN]);
70
+ /** Bicycle racks: three steel hoops a metre apart, 0.8 metres high, across the front */
71
+ export const rackModel = () => glb([
72
+ join(...[-1, 0, 1].flatMap((k) => [
73
+ box(k - 0.03, 0, -0.38, k + 0.03, 0.8, -0.32),
74
+ box(k - 0.03, 0, 0.32, k + 0.03, 0.8, 0.38),
75
+ box(k - 0.03, 0.74, -0.38, k + 0.03, 0.8, 0.38),
76
+ ])),
77
+ ], [STEEL]);
78
+ /** A bench, 1.8 metres wide: a wooden seat and back on dark green feet, facing its front */
79
+ export const benchModel = () => {
80
+ const feet = join(box(-0.85, 0, -0.25, -0.75, 0.45, 0.2), box(0.75, 0, -0.25, 0.85, 0.45, 0.2));
81
+ const wood = join(box(-0.9, 0.42, -0.25, 0.9, 0.48, 0.22), box(-0.9, 0.5, -0.3, 0.9, 0.85, -0.25));
82
+ return glb([feet, wood], [GREEN, WOOD]);
83
+ };
84
+ /** The kinds of furniture placed by the workers, in the order of their numbers (`PLACED_KIND`) */
85
+ export const FURNITURE = ['shelter', 'bin', 'postbox', 'fountain', 'rack', 'bench'];
86
+ /** The model of each kind of furniture */
87
+ export const FURNITURE_MODELS = {
88
+ shelter: shelterModel,
89
+ bin: binModel,
90
+ postbox: postboxModel,
91
+ fountain: fountainModel,
92
+ rack: rackModel,
93
+ bench: benchModel,
94
+ };
26
95
  //# sourceMappingURL=furniture.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"furniture.js","sourceRoot":"","sources":["../../src/basemap/furniture.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,uGAAuG;AACvG,MAAM,IAAI,GAAqC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACrE,MAAM,IAAI,GAAqC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAErE,mEAAmE;AACnE,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAE7B,wFAAwF;AACxF,MAAM,CAAC,MAAM,SAAS,GAAG,GAA4B,EAAE;IACrD,MAAM,IAAI,GAAG,OAAO,CAClB;QACE,CAAC,CAAC,EAAE,IAAI,CAAC;QACT,CAAC,GAAG,EAAE,GAAG,CAAC;QACV,CAAC,SAAS,EAAE,IAAI,CAAC;KAClB,EACD,CAAC,CACF,CAAC;IACF,MAAM,IAAI,GAAG,OAAO,CAClB;QACE,CAAC,SAAS,EAAE,IAAI,CAAC;QACjB,CAAC,IAAI,EAAE,IAAI,CAAC;QACZ,CAAC,IAAI,EAAE,IAAI,CAAC;QACZ,CAAC,IAAI,EAAE,CAAC,CAAC;KACV,EACD,CAAC,CACF,CAAC;IAEF,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC,CAAC","sourcesContent":["/**\n * The street furniture of a vector map (`VectorTiles.lamps`): a street lamp made here as a glTF binary (no file to\n * download), its pole and its head flat-shaded, the head lit at night (`ModelLayer.setGlow` from `LAMP_HEAD` up).\n */\n\nimport { glb, revolve } from './trees.ts';\n\n/** Colors of a street lamp (linear RGBA, as glTF's `baseColorFactor`): Paris's dark green cast iron */\nconst POLE: [number, number, number, number] = [0.04, 0.07, 0.05, 1];\nconst HEAD: [number, number, number, number] = [0.55, 0.52, 0.42, 1];\n\n/** Metres from a lamp's foot to its head: the part lit at night */\nexport const LAMP_HEAD = 4.6;\n\n/** A street lamp as a glTF binary, some 5 metres high: a thin pole, a lantern on top */\nexport const lampModel = (): Uint8Array<ArrayBuffer> => {\n const pole = revolve(\n [\n [0, 0.14],\n [0.6, 0.1],\n [LAMP_HEAD, 0.06],\n ],\n 5,\n );\n const head = revolve(\n [\n [LAMP_HEAD, 0.12],\n [4.95, 0.32],\n [5.25, 0.26],\n [5.45, 0],\n ],\n 6,\n );\n\n return glb([pole, head], [POLE, HEAD]);\n};\n"]}
1
+ {"version":3,"file":"furniture.js","sourceRoot":"","sources":["../../src/basemap/furniture.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The street furniture of a vector map (`VectorTiles.lamps`, `VectorTiles.furniture`), each made here as a glTF binary\n * (no file to download), flat-shaded: a street lamp (its head lit at night: `ModelLayer.setGlow` from `LAMP_HEAD` up),\n * a bus shelter, a waste basket, a post box, a Wallace fountain, bicycle racks, a bench.\n */\n\nimport { box, type Color, glb, join, revolve } from './meshes.ts';\n\n/** Colors of a street lamp (linear RGBA, as glTF's `baseColorFactor`): Paris's dark green cast iron */\nconst POLE: Color = [0.04, 0.07, 0.05, 1];\nconst HEAD: Color = [0.55, 0.52, 0.42, 1];\n\n/** Metres from a lamp's foot to its head: the part lit at night */\nexport const LAMP_HEAD = 4.6;\n\n/** A street lamp as a glTF binary, some 5 metres high: a thin pole, a lantern on top */\nexport const lampModel = (): Uint8Array<ArrayBuffer> => {\n const pole = revolve(\n [\n [0, 0.14],\n [0.6, 0.1],\n [LAMP_HEAD, 0.06],\n ],\n 5,\n );\n const head = revolve(\n [\n [LAMP_HEAD, 0.12],\n [4.95, 0.32],\n [5.25, 0.26],\n [5.45, 0],\n ],\n 6,\n );\n\n return glb([pole, head], [POLE, HEAD]);\n};\n\n/** Colors of the street furniture (linear RGBA): Paris's dark green cast iron, steel, wood, glass, La Poste's yellow */\nconst GREEN: Color = [0.03, 0.08, 0.05, 1];\nconst STEEL: Color = [0.32, 0.33, 0.34, 1];\nconst WOOD: Color = [0.36, 0.2, 0.09, 1];\nconst GLASS: Color = [0.55, 0.7, 0.75, 0.35];\nconst POSTER: Color = [0.85, 0.82, 0.72, 1];\nconst YELLOW: Color = [0.95, 0.7, 0.02, 1];\n\n/** A bus shelter, 3.6 metres wide, 2.5 high: a back and two sides of glass in a steel frame, a roof, an advert at one\n * end; open toward the street (its front) */\nexport const shelterModel = (): Uint8Array<ArrayBuffer> => {\n const [w, d, h] = [1.8, 0.7, 2.5];\n const frame = join(\n box(-w, 0, -d, -w + 0.08, h, -d + 0.08),\n box(w - 0.08, 0, -d, w, h, -d + 0.08),\n box(-w, 0, d - 0.08, -w + 0.08, h, d),\n box(w - 0.08, 0, d - 0.08, w, h, d),\n box(-w - 0.1, h, -d - 0.1, w + 0.1, h + 0.12, d + 0.25),\n );\n const glass = join(box(-w, 0.15, -d, w, h - 0.1, -d + 0.03), box(-w, 0.15, -d, -w + 0.03, h - 0.1, d - 0.1));\n const advert = box(w - 0.12, 0.3, -d + 0.1, w - 0.04, 2.1, d - 0.1);\n const seat = box(-0.9, 0.42, -d + 0.05, 0.9, 0.48, -d + 0.4);\n\n return glb([frame, glass, advert, seat], [STEEL, GLASS, POSTER, STEEL]);\n};\n\n/** A waste basket of Paris, about a metre high: a green hoop on a post */\nexport const binModel = (): Uint8Array<ArrayBuffer> => {\n const post = box(-0.04, 0, -0.32, 0.04, 1.05, -0.24);\n const hoop = revolve(\n [\n [0.35, 0],\n [0.38, 0.2],\n [0.95, 0.24],\n [0.98, 0.25],\n ],\n 8,\n );\n\n return glb([post, hoop], [GREEN, GREEN]);\n};\n\n/** A post box of La Poste, 1.3 metres high: a yellow box on a foot */\nexport const postboxModel = (): Uint8Array<ArrayBuffer> =>\n glb([box(-0.08, 0, -0.08, 0.08, 0.6, 0.08), box(-0.25, 0.6, -0.18, 0.25, 1.3, 0.18)], [STEEL, YELLOW]);\n\n/** A Wallace fountain, 2.7 metres high: a base, a column (its four caryatids), a dome, all dark green cast iron */\nexport const fountainModel = (): Uint8Array<ArrayBuffer> =>\n glb(\n [\n revolve(\n [\n [0, 0.42],\n [0.35, 0.36],\n [0.5, 0.22],\n [1.9, 0.22],\n [2.05, 0.38],\n [2.3, 0.34],\n [2.55, 0.18],\n [2.75, 0],\n ],\n 8,\n ),\n ],\n [GREEN],\n );\n\n/** Bicycle racks: three steel hoops a metre apart, 0.8 metres high, across the front */\nexport const rackModel = (): Uint8Array<ArrayBuffer> =>\n glb(\n [\n join(\n ...[-1, 0, 1].flatMap((k) => [\n box(k - 0.03, 0, -0.38, k + 0.03, 0.8, -0.32),\n box(k - 0.03, 0, 0.32, k + 0.03, 0.8, 0.38),\n box(k - 0.03, 0.74, -0.38, k + 0.03, 0.8, 0.38),\n ]),\n ),\n ],\n [STEEL],\n );\n\n/** A bench, 1.8 metres wide: a wooden seat and back on dark green feet, facing its front */\nexport const benchModel = (): Uint8Array<ArrayBuffer> => {\n const feet = join(box(-0.85, 0, -0.25, -0.75, 0.45, 0.2), box(0.75, 0, -0.25, 0.85, 0.45, 0.2));\n const wood = join(box(-0.9, 0.42, -0.25, 0.9, 0.48, 0.22), box(-0.9, 0.5, -0.3, 0.9, 0.85, -0.25));\n\n return glb([feet, wood], [GREEN, WOOD]);\n};\n\n/** The kinds of furniture placed by the workers, in the order of their numbers (`PLACED_KIND`) */\nexport const FURNITURE = ['shelter', 'bin', 'postbox', 'fountain', 'rack', 'bench'] as const;\n\n/** The model of each kind of furniture */\nexport const FURNITURE_MODELS: Readonly<Record<(typeof FURNITURE)[number], () => Uint8Array<ArrayBuffer>>> = {\n shelter: shelterModel,\n bin: binModel,\n postbox: postboxModel,\n fountain: fountainModel,\n rack: rackModel,\n bench: benchModel,\n};\n"]}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Small flat-shaded meshes made in the page (the trees, the street furniture) and their glTF binaries: solids of
3
+ * revolution, boxes, parts joined.
4
+ */
5
+ /** A color: linear RGBA, as glTF's `baseColorFactor` */
6
+ export type Color = [number, number, number, number];
7
+ /** A mesh's triangles: their positions and normals (x, y, z each; one normal per face) */
8
+ export interface Mesh {
9
+ positions: number[];
10
+ normals: number[];
11
+ }
12
+ /** A solid of revolution around the vertical (glTF +Y up), flat-shaded: rings of (height, radius), a point at the
13
+ * top when its radius is 0; the triangles' positions and normals, one normal per face */
14
+ export declare const revolve: (rings: [height: number, radius: number][], sides: number) => Mesh;
15
+ /** A box from (x0, y0, z0) to (x1, y1, z1) (glTF axes: y up, z the model's front, x its left), its faces outward */
16
+ export declare const box: (x0: number, y0: number, z0: number, x1: number, y1: number, z1: number) => Mesh;
17
+ /** Parts of one color joined into one */
18
+ export declare const join: (...parts: Mesh[]) => Mesh;
19
+ /** Parts flat-shaded in their colors as a glTF binary: one mesh of a primitive each, its front +Z
20
+ * (`ModelInstance.heading` turns it), standing on its origin */
21
+ export declare const glb: (parts: Mesh[], colors: Color[]) => Uint8Array<ArrayBuffer>;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Small flat-shaded meshes made in the page (the trees, the street furniture) and their glTF binaries: solids of
3
+ * revolution, boxes, parts joined.
4
+ */
5
+ import { bounds, glbOf } from "../util/gltf.js";
6
+ /** A solid of revolution around the vertical (glTF +Y up), flat-shaded: rings of (height, radius), a point at the
7
+ * top when its radius is 0; the triangles' positions and normals, one normal per face */
8
+ export const revolve = (rings, sides) => {
9
+ const at = (k, [h, r]) => {
10
+ const a = (k / sides) * Math.PI * 2;
11
+ return [Math.cos(a) * r, h, Math.sin(a) * r];
12
+ };
13
+ const positions = [];
14
+ const normals = [];
15
+ const face = (a, b, c) => {
16
+ const u = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
17
+ const v = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
18
+ const n = [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];
19
+ const length = Math.hypot(...n);
20
+ // A degenerate face (two points at the apex) is left out
21
+ if (length === 0)
22
+ return;
23
+ positions.push(...a, ...b, ...c);
24
+ [0, 1, 2].forEach(() => {
25
+ normals.push(n[0] / length, n[1] / length, n[2] / length);
26
+ });
27
+ };
28
+ rings.slice(1).forEach((ring, i) => {
29
+ const below = rings[i] ?? ring;
30
+ Array.from({ length: sides }, (_, k) => k).forEach((k) => {
31
+ const [a, b] = [at(k, below), at(k + 1, below)];
32
+ const [c, d] = [at(k, ring), at(k + 1, ring)];
33
+ // Counter-clockwise seen from outside
34
+ face(a, c, b);
35
+ face(b, c, d);
36
+ });
37
+ });
38
+ // The bottom closed: seen from below
39
+ const base = rings[0];
40
+ if (base && base[1] > 0) {
41
+ Array.from({ length: sides }, (_, k) => k).forEach((k) => {
42
+ face([0, base[0], 0], at(k, base), at(k + 1, base));
43
+ });
44
+ }
45
+ return { positions, normals };
46
+ };
47
+ /** A box from (x0, y0, z0) to (x1, y1, z1) (glTF axes: y up, z the model's front, x its left), its faces outward */
48
+ export const box = (x0, y0, z0, x1, y1, z1) => {
49
+ const positions = [];
50
+ const normals = [];
51
+ // Each face: its normal and its four corners, counter-clockwise seen from outside
52
+ const faces = [
53
+ [
54
+ [1, 0, 0],
55
+ [
56
+ [x1, y0, z0],
57
+ [x1, y1, z0],
58
+ [x1, y1, z1],
59
+ [x1, y0, z1],
60
+ ],
61
+ ],
62
+ [
63
+ [-1, 0, 0],
64
+ [
65
+ [x0, y0, z1],
66
+ [x0, y1, z1],
67
+ [x0, y1, z0],
68
+ [x0, y0, z0],
69
+ ],
70
+ ],
71
+ [
72
+ [0, 1, 0],
73
+ [
74
+ [x0, y1, z0],
75
+ [x0, y1, z1],
76
+ [x1, y1, z1],
77
+ [x1, y1, z0],
78
+ ],
79
+ ],
80
+ [
81
+ [0, -1, 0],
82
+ [
83
+ [x0, y0, z0],
84
+ [x1, y0, z0],
85
+ [x1, y0, z1],
86
+ [x0, y0, z1],
87
+ ],
88
+ ],
89
+ [
90
+ [0, 0, 1],
91
+ [
92
+ [x0, y0, z1],
93
+ [x1, y0, z1],
94
+ [x1, y1, z1],
95
+ [x0, y1, z1],
96
+ ],
97
+ ],
98
+ [
99
+ [0, 0, -1],
100
+ [
101
+ [x1, y0, z0],
102
+ [x0, y0, z0],
103
+ [x0, y1, z0],
104
+ [x1, y1, z0],
105
+ ],
106
+ ],
107
+ ];
108
+ faces.forEach(([n, [a, b, c, d]]) => {
109
+ [a, b, c, a, c, d].forEach((p) => {
110
+ positions.push(...(p ?? [0, 0, 0]));
111
+ normals.push(...n);
112
+ });
113
+ });
114
+ return { positions, normals };
115
+ };
116
+ /** Parts of one color joined into one */
117
+ export const join = (...parts) => ({
118
+ positions: parts.flatMap((p) => p.positions),
119
+ normals: parts.flatMap((p) => p.normals),
120
+ });
121
+ /** Parts flat-shaded in their colors as a glTF binary: one mesh of a primitive each, its front +Z
122
+ * (`ModelInstance.heading` turns it), standing on its origin */
123
+ export const glb = (parts, colors) => {
124
+ // The buffer: each part's positions then normals, 4-byte floats
125
+ const floats = parts.flatMap((p) => [...p.positions, ...p.normals]);
126
+ const bin = new Float32Array(floats);
127
+ const views = parts.flatMap((p, i) => {
128
+ const before = parts.slice(0, i).reduce((n, q) => n + (q.positions.length + q.normals.length) * 4, 0);
129
+ return [
130
+ { buffer: 0, byteOffset: before, byteLength: p.positions.length * 4, target: 34962 },
131
+ { buffer: 0, byteOffset: before + p.positions.length * 4, byteLength: p.normals.length * 4, target: 34962 },
132
+ ];
133
+ });
134
+ const accessors = parts.flatMap((p, i) => [
135
+ { bufferView: i * 2, componentType: 5126, count: p.positions.length / 3, type: 'VEC3', ...bounds(p.positions) },
136
+ { bufferView: i * 2 + 1, componentType: 5126, count: p.normals.length / 3, type: 'VEC3' },
137
+ ]);
138
+ const gltf = {
139
+ asset: { version: '2.0', generator: 'isard' },
140
+ scene: 0,
141
+ scenes: [{ nodes: [0] }],
142
+ nodes: [{ mesh: 0 }],
143
+ meshes: [
144
+ {
145
+ primitives: parts.map((_, i) => ({ attributes: { POSITION: i * 2, NORMAL: i * 2 + 1 }, material: i })),
146
+ },
147
+ ],
148
+ materials: colors.map((color) => ({
149
+ pbrMetallicRoughness: { baseColorFactor: color, metallicFactor: 0, roughnessFactor: 1 },
150
+ // Translucent (a shelter's glass): blended, seen from both sides
151
+ ...(color[3] < 1 && { alphaMode: 'BLEND', doubleSided: true }),
152
+ })),
153
+ accessors,
154
+ bufferViews: views,
155
+ buffers: [{ byteLength: bin.byteLength }],
156
+ };
157
+ return glbOf(gltf, new Uint8Array(bin.buffer));
158
+ };
159
+ //# sourceMappingURL=meshes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshes.js","sourceRoot":"","sources":["../../src/basemap/meshes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAchD;yFACyF;AACzF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAyC,EAAE,KAAa,EAAQ,EAAE;IACxF,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAmB,EAAQ,EAAE;QACvD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAEpC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC;IACF,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,CAAC,CAAO,EAAE,CAAO,EAAE,CAAO,EAAE,EAAE;QACzC,MAAM,CAAC,GAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClG,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAEhC,yDAAyD;QACzD,IAAI,MAAM,KAAK,CAAC;YAAE,OAAO;QACzB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QAE/B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACvD,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YAE9C,sCAAsC;YACtC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACd,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,qCAAqC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEtB,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACvD,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC,CAAC;AAEF,oHAAoH;AACpH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAQ,EAAE;IAClG,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,kFAAkF;IAClF,MAAM,KAAK,GAAqB;QAC9B;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT;gBACE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;aACb;SACF;QACD;YACE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACV;gBACE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;aACb;SACF;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT;gBACE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;aACb;SACF;QACD;YACE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACV;gBACE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;aACb;SACF;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT;gBACE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;aACb;SACF;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACV;gBACE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACZ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;aACb;SACF;KACF,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YAC/B,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC,CAAC;AAEF,yCAAyC;AACzC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,KAAa,EAAQ,EAAE,CAAC,CAAC;IAC/C,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5C,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;CACzC,CAAC,CAAC;AAEH;gEACgE;AAChE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,MAAe,EAA2B,EAAE;IAC7E,gEAAgE;IAChE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAEtG,OAAO;YACL,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE;YACpF,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE;SAC5G,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;QAC/G,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;KAC1F,CAAC,CAAC;IACH,MAAM,IAAI,GAAG;QACX,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE;QAC7C,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACpB,MAAM,EAAE;YACN;gBACE,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;aACvG;SACF;QACD,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAChC,oBAAoB,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE;YACvF,iEAAiE;YACjE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;SAC/D,CAAC,CAAC;QACH,SAAS;QACT,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;KAC1C,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC","sourcesContent":["/**\n * Small flat-shaded meshes made in the page (the trees, the street furniture) and their glTF binaries: solids of\n * revolution, boxes, parts joined.\n */\n\nimport { bounds, glbOf } from '../util/gltf.ts';\n\n/** A point or a vector: x, y, z */\ntype Vec3 = [number, number, number];\n\n/** A color: linear RGBA, as glTF's `baseColorFactor` */\nexport type Color = [number, number, number, number];\n\n/** A mesh's triangles: their positions and normals (x, y, z each; one normal per face) */\nexport interface Mesh {\n positions: number[];\n normals: number[];\n}\n\n/** A solid of revolution around the vertical (glTF +Y up), flat-shaded: rings of (height, radius), a point at the\n * top when its radius is 0; the triangles' positions and normals, one normal per face */\nexport const revolve = (rings: [height: number, radius: number][], sides: number): Mesh => {\n const at = (k: number, [h, r]: [number, number]): Vec3 => {\n const a = (k / sides) * Math.PI * 2;\n\n return [Math.cos(a) * r, h, Math.sin(a) * r];\n };\n const positions: number[] = [];\n const normals: number[] = [];\n const face = (a: Vec3, b: Vec3, c: Vec3) => {\n const u: Vec3 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];\n const v: Vec3 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];\n const n: Vec3 = [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];\n const length = Math.hypot(...n);\n\n // A degenerate face (two points at the apex) is left out\n if (length === 0) return;\n positions.push(...a, ...b, ...c);\n [0, 1, 2].forEach(() => {\n normals.push(n[0] / length, n[1] / length, n[2] / length);\n });\n };\n\n rings.slice(1).forEach((ring, i) => {\n const below = rings[i] ?? ring;\n\n Array.from({ length: sides }, (_, k) => k).forEach((k) => {\n const [a, b] = [at(k, below), at(k + 1, below)];\n const [c, d] = [at(k, ring), at(k + 1, ring)];\n\n // Counter-clockwise seen from outside\n face(a, c, b);\n face(b, c, d);\n });\n });\n // The bottom closed: seen from below\n const base = rings[0];\n\n if (base && base[1] > 0) {\n Array.from({ length: sides }, (_, k) => k).forEach((k) => {\n face([0, base[0], 0], at(k, base), at(k + 1, base));\n });\n }\n\n return { positions, normals };\n};\n\n/** A box from (x0, y0, z0) to (x1, y1, z1) (glTF axes: y up, z the model's front, x its left), its faces outward */\nexport const box = (x0: number, y0: number, z0: number, x1: number, y1: number, z1: number): Mesh => {\n const positions: number[] = [];\n const normals: number[] = [];\n // Each face: its normal and its four corners, counter-clockwise seen from outside\n const faces: [Vec3, Vec3[]][] = [\n [\n [1, 0, 0],\n [\n [x1, y0, z0],\n [x1, y1, z0],\n [x1, y1, z1],\n [x1, y0, z1],\n ],\n ],\n [\n [-1, 0, 0],\n [\n [x0, y0, z1],\n [x0, y1, z1],\n [x0, y1, z0],\n [x0, y0, z0],\n ],\n ],\n [\n [0, 1, 0],\n [\n [x0, y1, z0],\n [x0, y1, z1],\n [x1, y1, z1],\n [x1, y1, z0],\n ],\n ],\n [\n [0, -1, 0],\n [\n [x0, y0, z0],\n [x1, y0, z0],\n [x1, y0, z1],\n [x0, y0, z1],\n ],\n ],\n [\n [0, 0, 1],\n [\n [x0, y0, z1],\n [x1, y0, z1],\n [x1, y1, z1],\n [x0, y1, z1],\n ],\n ],\n [\n [0, 0, -1],\n [\n [x1, y0, z0],\n [x0, y0, z0],\n [x0, y1, z0],\n [x1, y1, z0],\n ],\n ],\n ];\n\n faces.forEach(([n, [a, b, c, d]]) => {\n [a, b, c, a, c, d].forEach((p) => {\n positions.push(...(p ?? [0, 0, 0]));\n normals.push(...n);\n });\n });\n\n return { positions, normals };\n};\n\n/** Parts of one color joined into one */\nexport const join = (...parts: Mesh[]): Mesh => ({\n positions: parts.flatMap((p) => p.positions),\n normals: parts.flatMap((p) => p.normals),\n});\n\n/** Parts flat-shaded in their colors as a glTF binary: one mesh of a primitive each, its front +Z\n * (`ModelInstance.heading` turns it), standing on its origin */\nexport const glb = (parts: Mesh[], colors: Color[]): Uint8Array<ArrayBuffer> => {\n // The buffer: each part's positions then normals, 4-byte floats\n const floats = parts.flatMap((p) => [...p.positions, ...p.normals]);\n const bin = new Float32Array(floats);\n const views = parts.flatMap((p, i) => {\n const before = parts.slice(0, i).reduce((n, q) => n + (q.positions.length + q.normals.length) * 4, 0);\n\n return [\n { buffer: 0, byteOffset: before, byteLength: p.positions.length * 4, target: 34962 },\n { buffer: 0, byteOffset: before + p.positions.length * 4, byteLength: p.normals.length * 4, target: 34962 },\n ];\n });\n const accessors = parts.flatMap((p, i) => [\n { bufferView: i * 2, componentType: 5126, count: p.positions.length / 3, type: 'VEC3', ...bounds(p.positions) },\n { bufferView: i * 2 + 1, componentType: 5126, count: p.normals.length / 3, type: 'VEC3' },\n ]);\n const gltf = {\n asset: { version: '2.0', generator: 'isard' },\n scene: 0,\n scenes: [{ nodes: [0] }],\n nodes: [{ mesh: 0 }],\n meshes: [\n {\n primitives: parts.map((_, i) => ({ attributes: { POSITION: i * 2, NORMAL: i * 2 + 1 }, material: i })),\n },\n ],\n materials: colors.map((color) => ({\n pbrMetallicRoughness: { baseColorFactor: color, metallicFactor: 0, roughnessFactor: 1 },\n // Translucent (a shelter's glass): blended, seen from both sides\n ...(color[3] < 1 && { alphaMode: 'BLEND', doubleSided: true }),\n })),\n accessors,\n bufferViews: views,\n buffers: [{ byteLength: bin.byteLength }],\n };\n\n return glbOf(gltf, new Uint8Array(bin.buffer));\n};\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Things placed by a vector basemap's workers in its tiles (trees, street lamps, street furniture), as they send them
3
+ * to the page: so many numbers each.
4
+ */
5
+ /** Numbers of a thing placed: longitude, latitude, scale, heading (degrees), rank (in [0, 1): far from the view, the
6
+ * page keeps the lowest) and kind (its model among those of its kinds) */
7
+ export declare const PLACED_NUMBERS = 6;
8
+ /** Where its rank is among its numbers */
9
+ export declare const PLACED_RANK = 4;
10
+ /** Where its kind is among its numbers */
11
+ export declare const PLACED_KIND = 5;
12
+ /** A heading for a number, the same each time, near numbers turned far apart (7919, a prime) */
13
+ export declare const turned: (n: number) => number;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Things placed by a vector basemap's workers in its tiles (trees, street lamps, street furniture), as they send them
3
+ * to the page: so many numbers each.
4
+ */
5
+ /** Numbers of a thing placed: longitude, latitude, scale, heading (degrees), rank (in [0, 1): far from the view, the
6
+ * page keeps the lowest) and kind (its model among those of its kinds) */
7
+ export const PLACED_NUMBERS = 6;
8
+ /** Where its rank is among its numbers */
9
+ export const PLACED_RANK = 4;
10
+ /** Where its kind is among its numbers */
11
+ export const PLACED_KIND = 5;
12
+ /** A heading for a number, the same each time, near numbers turned far apart (7919, a prime) */
13
+ export const turned = (n) => (n * 7919) % 360;
14
+ //# sourceMappingURL=placed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placed.js","sourceRoot":"","sources":["../../src/basemap/placed.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;0EAC0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B,gGAAgG;AAChG,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC","sourcesContent":["/**\n * Things placed by a vector basemap's workers in its tiles (trees, street lamps, street furniture), as they send them\n * to the page: so many numbers each.\n */\n\n/** Numbers of a thing placed: longitude, latitude, scale, heading (degrees), rank (in [0, 1): far from the view, the\n * page keeps the lowest) and kind (its model among those of its kinds) */\nexport const PLACED_NUMBERS = 6;\n\n/** Where its rank is among its numbers */\nexport const PLACED_RANK = 4;\n\n/** Where its kind is among its numbers */\nexport const PLACED_KIND = 5;\n\n/** A heading for a number, the same each time, near numbers turned far apart (7919, a prime) */\nexport const turned = (n: number): number => (n * 7919) % 360;\n"]}
@@ -5,27 +5,17 @@
5
5
  */
6
6
  import type { Value } from './mvt.ts';
7
7
  import type { StyleLayer } from './vectorstyle.ts';
8
- /** Numbers of a tree in the workers' answer: longitude, latitude, scale, heading, rank, kind (0 broadleaved, 1
9
- * conifer) */
10
- export declare const TREE_NUMBERS = 6;
11
8
  /** Colors of the trunk, of the broadleaved crown and of the conifers' (linear RGBA, as glTF's `baseColorFactor`) */
12
9
  export interface TreeColors {
13
10
  trunk: [number, number, number, number];
14
11
  crown: [number, number, number, number];
15
12
  conifer: [number, number, number, number];
16
13
  }
17
- /** A solid of revolution around the vertical (glTF +Y up), flat-shaded: rings of (height, radius), a point at the
18
- * top when its radius is 0; the triangles' positions and normals, one normal per face */
19
- export declare const revolve: (rings: [height: number, radius: number][], sides?: number) => {
20
- positions: number[];
21
- normals: number[];
14
+ /** The models' heights (metres): a tree's height from its data scales them by it */
15
+ export declare const TREE_METRES: {
16
+ readonly broadleaved: 10.2;
17
+ readonly conifer: 11;
22
18
  };
23
- /** Parts flat-shaded in their colors as a glTF binary: one mesh of a primitive each, its front +Z
24
- * (`ModelInstance.heading` turns it), standing on its origin */
25
- export declare const glb: (parts: {
26
- positions: number[];
27
- normals: number[];
28
- }[], colors: TreeColors[keyof TreeColors][]) => Uint8Array<ArrayBuffer>;
29
19
  /**
30
20
  * A broadleaved tree as a glTF binary, about 10 metres high: a trunk and a rounded crown in `colors`; `far`: the
31
21
  * same simplified for far away, a few faces (some 30 triangles instead of 100)