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
@@ -1 +1 @@
1
- {"version":3,"file":"ifc.js","sourceRoot":"","sources":["../../src/data/ifc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * IFC models (the BIM tools' own format: Revit, ArchiCAD, Tekla, Allplan, Bonsai…) read by web-ifc (ThatOpen,\n * MPL-2.0) in a worker of their own, web-ifc fetched on first use from a CDN (or a folder of yours): the model's\n * storeys and elements at once, each storey's geometry when asked (a glTF binary for `map.addModels({ data })`, each\n * element a feature of it, picked by the map: `hit.index` is the element's), the elements' properties on demand, and\n * where the model stands (its map conversion in a projected CRS, else its site's latitude and longitude).\n */\n\nimport { bounds, glbOf } from '../util/gltf.ts';\nimport { getCrs } from './crs.ts';\n\n/** web-ifc's build used by default: its module (`web-ifc-api.js`) and its WebAssembly (`web-ifc.wasm`) */\nexport const WEB_IFC = 'https://cdn.jsdelivr.net/npm/web-ifc@0.0.78/';\n\nexport interface IfcOptions {\n /** Folder of `web-ifc-api.js` and `web-ifc.wasm` (ending with `/`; `WEB_IFC` by default): self-host them for offline\n * or locked-down networks. The worker imports the module from a `blob:` URL: a Content Security Policy needs\n * `blob:` in `worker-src` */\n webIfc?: string;\n /** Request options of the file's fetch (headers of a private source) */\n init?: RequestInit;\n}\n\n/** An element of the model (a wall, a slab, a window, a stair…) */\nexport interface IfcElement {\n /** Its IFC id (STEP line number) */\n id: number;\n /** Its IFC class (`IfcWall`, `IfcSlab`, `IfcWindow`…) */\n type: string;\n name: string;\n /** Its storey in `IfcModel.storeys` */\n storey: number;\n}\n\n/** A storey of the model: its elements, its geometry when asked */\nexport interface IfcStorey {\n id: number;\n name: string;\n /** Metres above the model's origin */\n elevation: number;\n /** Its elements (`IfcModel.elements`' indices) */\n elements: number[];\n /**\n * Its elements' geometry as a glTF binary (their features: `IfcModel.elements`' indices) in the model's frame: y up,\n * its north toward +z (`IfcModel.place.heading` turns it), its origin at the model's; meshed in the worker on the\n * first call (a large model's storeys one at a time, those in view only)\n */\n load(): Promise<Uint8Array<ArrayBuffer>>;\n}\n\n/** An element's properties: its attributes, then its property and quantity sets, by name */\nexport type IfcProperties = Record<string, Record<string, string | number | boolean | null>>;\n\n/** Where a model stands: its origin's position and height, the way its north faces */\nexport interface IfcPlace {\n lonLat: [number, number];\n /** Metres above the sea (its map conversion's height, its site's `RefElevation`) */\n elevation: number;\n /** Degrees clockwise from the north of the model's north (an instance's `heading`) */\n heading: number;\n /** How it is known: its map conversion (exact, `crs` its projected CRS), or its site's latitude and longitude */\n from: 'map' | 'site';\n crs?: string;\n}\n\nexport interface IfcModel {\n /** Its storeys from the lowest up, elements outside any storey (the site's) in one of their own at the start */\n storeys: IfcStorey[];\n /** Its elements, the features of the storeys' models */\n elements: IfcElement[];\n /** Where it stands, if the file says (`IfcMapConversion` in a CRS isard knows, else `IfcSite`'s position) */\n place?: IfcPlace;\n /** An element's properties, read from the file kept open in the worker */\n properties(element: number): Promise<IfcProperties>;\n /** Closes the file and its worker */\n close(): void;\n}\n\n/**\n * The worker's code: web-ifc imported from `base`, the file opened; its storeys, its elements (the spatial structure's\n * products) and what places it (its map conversion, its site, its true north) given at once, a storey's meshes when\n * asked (positions put in the model's frame, colors), the properties asked for\n */\nconst WORKER = `\nlet api, model, W;\nconst text = (v) => (v && typeof v.value !== 'undefined' ? v.value : null);\nconst degrees = (v) => {\n const parts = text(v);\n if (!Array.isArray(parts)) return undefined;\n const [d = 0, m = 0, s = 0, u = 0] = parts.map((p) => text(p) ?? p);\n return d + m / 60 + s / 3600 + u / 3600e6;\n};\nconst plain = (line) => Object.fromEntries(\n Object.entries(line ?? {})\n // Values, not references to other lines (type 5) nor lists\n .filter(([k, v]) => v && typeof v === 'object' && 'value' in v && v.type !== 5 && typeof v.value !== 'object' && k !== 'expressID')\n .map(([k, v]) => [k, v.value]),\n);\nconst ids = (type) => { const v = api.GetLineIDsWithType(model, type); return Array.from({ length: v.size() }, (_, i) => v.get(i)); };\nconst line = (ref) => (ref && ref.value !== undefined ? api.GetLine(model, ref.value) : undefined);\n// The spatial structure's containers, and the products drawn by no element of their own (the site is one when it has\n// a shape: its terrain)\nconst SPATIAL = new Set(['IFCPROJECT', 'IFCBUILDING', 'IFCBUILDINGSTOREY', 'IFCSPACE', 'IFCOPENINGELEMENT']);\nconst PREFIXES = { EXA: 1e18, PETA: 1e15, TERA: 1e12, GIGA: 1e9, MEGA: 1e6, KILO: 1e3, HECTO: 100, DECA: 10, DECI: 0.1, CENTI: 0.01, MILLI: 0.001, MICRO: 1e-6 };\n/** Metres per length unit of the project */\nconst unitScale = () => {\n const project = ids(W.IFCPROJECT).map((id) => api.GetLine(model, id))[0];\n const units = line(project?.UnitsInContext)?.Units ?? [];\n for (const ref of units) {\n const unit = line(ref);\n if (text(unit?.UnitType) !== 'LENGTHUNIT') continue;\n if (unit.Prefix !== undefined || text(unit.Name) === 'METRE') return PREFIXES[text(unit.Prefix)] ?? 1;\n // A conversion-based unit (the foot): its factor, in metres when its unit is\n const factor = line(unit.ConversionFactor);\n const value = Number(text(factor?.ValueComponent) ?? NaN);\n if (Number.isFinite(value)) return value * (PREFIXES[text(line(factor?.UnitComponent)?.Prefix)] ?? 1);\n }\n return 1;\n};\nonmessage = async ({ data }) => {\n try {\n if (data.type === 'open') {\n W = await import(data.base + 'web-ifc-api.js');\n api = new W.IfcAPI();\n api.SetWasmPath(data.base, true);\n await api.Init();\n model = api.OpenModel(new Uint8Array(data.bytes), { COORDINATE_TO_ORIGIN: true });\n const storeys = ids(W.IFCBUILDINGSTOREY).map((id) => {\n const l = api.GetLine(model, id);\n return { id, name: text(l.Name) ?? '', elevation: Number(text(l.Elevation) ?? 0) * unitScale() };\n });\n // The products of the spatial structure and their storeys\n const elements = [];\n const walk = (node, storey) => {\n const type = String(node.type);\n const here = type.toUpperCase() === 'IFCBUILDINGSTOREY' ? node.expressID : storey;\n const drawn = type.toUpperCase() !== 'IFCSITE' || api.GetLine(model, node.expressID)?.Representation;\n if (!SPATIAL.has(type.toUpperCase()) && drawn) {\n elements.push({ id: node.expressID, type, name: text(api.GetLine(model, node.expressID)?.Name) ?? '', storey: here ?? -1 });\n }\n (node.children ?? []).forEach((c) => walk(c, here));\n };\n walk(await api.properties.getSpatialStructure(model), undefined);\n // What places it: the shift web-ifc made to bring it near the origin (metres, its y-up frame), the map\n // conversion and its CRS, the site's latitude and longitude, the true north\n const shift = api.GetCoordinationMatrix(model).slice(12, 15);\n const conversion = ids(W.IFCMAPCONVERSION).map((id) => api.GetLine(model, id))[0];\n const site = ids(W.IFCSITE).map((id) => api.GetLine(model, id))[0];\n const north = ids(W.IFCGEOMETRICREPRESENTATIONCONTEXT)\n .map((id) => line(api.GetLine(model, id).TrueNorth))\n .find((d) => d)?.DirectionRatios?.map((r) => text(r) ?? r);\n const [lat, lon] = [degrees(site?.RefLatitude), degrees(site?.RefLongitude)];\n postMessage({\n type: 'model',\n storeys,\n elements,\n place: {\n shift,\n unit: unitScale(),\n ...(conversion && {\n map: ['Eastings', 'Northings', 'OrthogonalHeight', 'XAxisAbscissa', 'XAxisOrdinate', 'Scale'].map((k) => Number(text(conversion[k]) ?? (k === 'Scale' || k === 'XAxisAbscissa' ? 1 : 0))),\n crs: text(line(conversion.TargetCRS)?.Name),\n }),\n ...(lat !== undefined && lon !== undefined && { site: [lon, lat, Number(text(site.RefElevation) ?? 0) * unitScale()] }),\n ...(north && { north }),\n },\n });\n } else if (data.type === 'storey') {\n const parts = [];\n const feature = new Map(data.ids.map((id, i) => [id, data.features[i]]));\n // web-ifc 0.0.78's browser build takes three arguments where its API passes four: called directly then\n const stream = (callback) => {\n try {\n api.StreamMeshes(model, data.ids, callback);\n } catch (error) {\n if (!/arguments/.test(String(error))) throw error;\n api.wasmModule.StreamMeshes(model, data.ids, callback);\n }\n };\n stream((mesh) => {\n for (let i = 0; i < mesh.geometries.size(); i++) {\n const placed = mesh.geometries.get(i);\n const geometry = api.GetGeometry(model, placed.geometryExpressID);\n const v = api.GetVertexArray(geometry.GetVertexData(), geometry.GetVertexDataSize());\n const indices = api.GetIndexArray(geometry.GetIndexData(), geometry.GetIndexDataSize()).slice();\n const m = placed.flatTransformation;\n const positions = new Float32Array((v.length / 6) * 3);\n for (let k = 0, p = 0; k < v.length; k += 6, p += 3) {\n const [x, y, z] = [v[k], v[k + 1], v[k + 2]];\n // Turned half a turn round y: the model's north (-z of web-ifc's y-up frame) toward +z, glTF's front\n positions[p] = -(m[0] * x + m[4] * y + m[8] * z + m[12]);\n positions[p + 1] = m[1] * x + m[5] * y + m[9] * z + m[13];\n positions[p + 2] = -(m[2] * x + m[6] * y + m[10] * z + m[14]);\n }\n const c = placed.color;\n parts.push({ feature: feature.get(mesh.expressID) ?? 0, color: [c.x, c.y, c.z, c.w], positions, indices });\n geometry.delete();\n }\n });\n postMessage({ type: 'storey', request: data.request, parts }, parts.flatMap((p) => [p.positions.buffer, p.indices.buffer]));\n } else if (data.type === 'properties') {\n const properties = { Attributes: plain(api.GetLine(model, data.id)) };\n const sets = await api.properties.getPropertySets(model, data.id, true);\n for (const set of sets) {\n const values = {};\n for (const p of [...(set.HasProperties ?? []), ...(set.Quantities ?? [])]) {\n const name = text(p.Name);\n if (!name) continue;\n const value = p.NominalValue ?? p.LengthValue ?? p.AreaValue ?? p.VolumeValue ?? p.CountValue ?? p.WeightValue;\n values[name] = text(value);\n }\n properties[text(set.Name) ?? 'Set ' + set.expressID] = values;\n }\n postMessage({ type: 'properties', request: data.request, properties });\n }\n } catch (error) {\n postMessage({ type: 'error', request: data.request, message: String(error?.message ?? error) });\n }\n};\n`;\n\n/** A part of the model: an element's geometry in one color */\ninterface Part {\n feature: number;\n color: [number, number, number, number];\n positions: Float32Array;\n indices: Uint32Array;\n}\n\n/** A storey's parts as a glTF binary: a primitive per color, each vertex its element (`_BATCHID`) */\nexport const storeyModel = (parts: readonly Part[]): Uint8Array<ArrayBuffer> => {\n const byColor = new Map<string, Part[]>();\n\n parts.forEach((p) => {\n const key = p.color.map((c) => c.toFixed(3)).join(',');\n\n byColor.set(key, [...(byColor.get(key) ?? []), p]);\n });\n\n const chunks: Uint8Array[] = [];\n const views: { buffer: 0; byteOffset: number; byteLength: number; target: number }[] = [];\n const accessors: Record<string, unknown>[] = [];\n let offset = 0;\n const append = (bytes: Uint8Array, target: number) => {\n views.push({ buffer: 0, byteOffset: offset, byteLength: bytes.byteLength, target });\n chunks.push(bytes);\n offset += Math.ceil(bytes.byteLength / 4) * 4;\n\n return views.length - 1;\n };\n const groups = [...byColor.values()];\n const primitives = groups.map((group, material) => {\n const count = group.reduce((n, p) => n + p.positions.length / 3, 0);\n const positions = new Float32Array(count * 3);\n const features = new Float32Array(count);\n const indices = new Uint32Array(group.reduce((n, p) => n + p.indices.length, 0));\n let [vertex, index] = [0, 0];\n\n group.forEach((p) => {\n positions.set(p.positions, vertex * 3);\n features.fill(p.feature, vertex, vertex + p.positions.length / 3);\n p.indices.forEach((i, k) => {\n indices[index + k] = i + vertex;\n });\n vertex += p.positions.length / 3;\n index += p.indices.length;\n });\n accessors.push(\n {\n bufferView: append(new Uint8Array(positions.buffer), 34962),\n componentType: 5126,\n count,\n type: 'VEC3',\n ...bounds([...positions]),\n },\n { bufferView: append(new Uint8Array(features.buffer), 34962), componentType: 5126, count, type: 'SCALAR' },\n {\n bufferView: append(new Uint8Array(indices.buffer), 34963),\n componentType: 5125,\n count: indices.length,\n type: 'SCALAR',\n },\n );\n\n const at = accessors.length - 3;\n\n return { attributes: { POSITION: at, _BATCHID: at + 1 }, indices: at + 2, material };\n });\n const bin = new Uint8Array(offset);\n let at = 0;\n\n chunks.forEach((c) => {\n bin.set(c, at);\n at += Math.ceil(c.byteLength / 4) * 4;\n });\n\n return glbOf(\n {\n asset: { version: '2.0', generator: 'isard (IFC)' },\n scene: 0,\n scenes: [{ nodes: [0] }],\n nodes: [{ mesh: 0 }],\n meshes: [{ primitives }],\n materials: groups.map((group) => {\n const color = group[0]?.color ?? [0.8, 0.8, 0.8, 1];\n\n return {\n pbrMetallicRoughness: { baseColorFactor: color, metallicFactor: 0, roughnessFactor: 1 },\n ...(color[3] < 1 && { alphaMode: 'BLEND' }),\n doubleSided: true,\n };\n }),\n accessors,\n bufferViews: views,\n buffers: [{ byteLength: bin.byteLength }],\n },\n bin,\n );\n};\n\n/** What places a model, as the worker reads it: web-ifc's shift of it (metres, its y-up frame), its project's metres\n * per unit, its map conversion (eastings, northings, height, x axis' abscissa and ordinate, scale) and its CRS, its\n * site's longitude, latitude and elevation, its true north (in its plan) */\nexport interface IfcPlacing {\n shift: number[];\n unit: number;\n map?: number[];\n crs?: string | null;\n site?: [number, number, number];\n north?: number[];\n}\n\n/** Degrees clockwise from the north of the true north to (x, y) in a plan whose y would be north */\nconst bearingOf = (x: number, y: number): number => (Math.atan2(x, y) * 180) / Math.PI;\n\n/**\n * Where a model's origin (its glTF's) stands: by its map conversion when its CRS is known (the origin in the file's\n * frame, before web-ifc's shift, taken to the map's eastings and northings, then to longitude and latitude; its north\n * turned by the conversion's x axis and the grid's convergence there), else by its site's latitude and longitude\n * turned by its true north\n */\nexport const placeIfc = ({ shift, unit, map, crs, site, north }: IfcPlacing): IfcPlace | undefined => {\n // The origin in the file's frame (metres, z up): web-ifc's y-up shift undone\n const [sx = 0, sy = 0, sz = 0] = shift;\n const [x, y, z] = [-sx, sz, -sy];\n\n if (map && crs) {\n const projection = (() => {\n try {\n return getCrs(crs);\n } catch {\n return undefined;\n }\n })();\n const [e = 0, n = 0, h = 0, ax = 1, ay = 0, scale = 1] = map;\n\n if (projection) {\n const length = Math.hypot(ax, ay) || 1;\n const [a, b] = [ax / length, ay / length];\n // The conversion's scale takes the project's units to the map's; the geometry is in metres already\n const k = scale / unit;\n const [east, northing] = [e + k * (a * x - b * y), n + k * (b * x + a * y)];\n const [lon = 0, lat = 0] = projection.inverse([east, northing]);\n const [lon2 = 0, lat2 = 0] = projection.inverse([east, northing + 100]);\n // The grid's north from the true north there, and the file's north (its y) from the grid's\n const convergence = bearingOf((lon2 - lon) * Math.cos((lat * Math.PI) / 180), lat2 - lat);\n\n return {\n lonLat: [lon, lat],\n elevation: h + k * z,\n heading: bearingOf(-b, a) + convergence,\n from: 'map',\n crs,\n };\n }\n }\n if (!site) return undefined;\n\n // The true north in the plan: the plan's y turned from it the other way\n const [nx = 0, ny = 1] = north ?? [];\n const heading = -bearingOf(nx, ny);\n const [lon, lat, elevation] = site;\n // The origin's offset from the site's (metres, the plan turned to the north)\n const turn = (heading * Math.PI) / 180;\n const [east, northing] = [x * Math.cos(turn) + y * Math.sin(turn), -x * Math.sin(turn) + y * Math.cos(turn)];\n\n return {\n lonLat: [lon + east / (111320 * Math.cos((lat * Math.PI) / 180)), lat + northing / 111320],\n elevation: elevation + z,\n heading,\n from: 'site',\n };\n};\n\n/** The answer of the worker to a message */\ntype Answer =\n | { type: 'model'; storeys: Omit<IfcStorey, 'elements' | 'load'>[]; elements: IfcElement[]; place: IfcPlacing }\n | { type: 'storey'; request: number; parts: Part[] }\n | { type: 'properties'; request: number; properties: IfcProperties }\n | { type: 'error'; request?: number; message: string };\n\n/**\n * An IFC file (its URL, or its bytes) opened by web-ifc in a worker: its storeys and elements, each storey's geometry\n * when asked, the elements' properties on demand, where it stands\n */\nexport const loadIfc = async (source: string | ArrayBuffer, options: IfcOptions = {}): Promise<IfcModel> => {\n const bytes =\n typeof source === 'string'\n ? await fetch(source, options.init).then((r) => {\n if (!r.ok) throw new Error(`isard: ${source}: ${r.status}`);\n\n return r.arrayBuffer();\n })\n : source;\n const script = URL.createObjectURL(new Blob([WORKER], { type: 'text/javascript' }));\n const worker = new Worker(script, { type: 'module' });\n /** The answers awaited, by request */\n const pending = new Map<number, { resolve: (answer: Answer) => void; reject: (e: Error) => void }>();\n let request = 0;\n const ask = <A extends Answer>(message: Record<string, unknown>): Promise<A> =>\n new Promise((resolve, reject) => {\n request += 1;\n pending.set(request, { resolve: (answer) => resolve(answer as A), reject });\n worker.postMessage({ ...message, request });\n });\n\n URL.revokeObjectURL(script);\n\n const opened = await new Promise<Extract<Answer, { type: 'model' }>>((resolve, reject) => {\n worker.onmessage = ({ data }: MessageEvent<Answer>) => {\n if (data.type === 'model') resolve(data);\n else if (data.request === undefined)\n reject(new Error(`isard: IFC: ${data.type === 'error' ? data.message : ''}`));\n else {\n const waiting = pending.get(data.request);\n\n pending.delete(data.request);\n if (data.type === 'error') waiting?.reject(new Error(`isard: IFC: ${data.message}`));\n else waiting?.resolve(data);\n }\n };\n worker.onerror = (e) => reject(new Error(`isard: IFC worker: ${e.message}`));\n worker.postMessage({ type: 'open', base: options.webIfc ?? WEB_IFC, bytes }, [bytes]);\n }).catch((error: unknown) => {\n worker.terminate();\n throw error;\n });\n\n // The storeys holding elements from the lowest up, the elements outside any in one of their own first (at the\n // lowest storey's elevation)\n const used = new Set(opened.elements.map((e) => e.storey));\n const sorted = opened.storeys.filter((s) => used.has(s.id)).sort((a, b) => a.elevation - b.elevation);\n const outside = opened.elements.some((e) => !sorted.some((s) => s.id === e.storey));\n const list = [...(outside ? [{ id: -1, name: 'Site', elevation: sorted[0]?.elevation ?? 0 }] : []), ...sorted];\n const storeyIndex = new Map(list.map((s, i) => [s.id, i]));\n const elements: IfcElement[] = opened.elements.map((e) => ({ ...e, storey: storeyIndex.get(e.storey) ?? 0 }));\n const storeys: IfcStorey[] = list.map((s, i) => {\n const members = elements.flatMap((e, k) => (e.storey === i ? [k] : []));\n let loaded: Promise<Uint8Array<ArrayBuffer>> | undefined;\n\n return {\n ...s,\n elements: members,\n load: () => {\n loaded ??= ask<Extract<Answer, { type: 'storey' }>>({\n type: 'storey',\n ids: members.map((k) => elements[k]?.id ?? 0),\n features: members,\n }).then(({ parts }) => storeyModel(parts));\n\n return loaded;\n },\n };\n });\n const place = placeIfc(opened.place);\n\n return {\n storeys,\n elements,\n ...(place && { place }),\n properties: (element: number) => {\n const id = elements[element]?.id;\n\n if (id === undefined) return Promise.reject(new Error(`isard: IFC: no element ${element}`));\n\n return ask<Extract<Answer, { type: 'properties' }>>({ type: 'properties', id }).then((a) => a.properties);\n },\n close: () => {\n worker.terminate();\n pending.forEach(({ reject }) => {\n reject(new Error('isard: IFC model closed'));\n });\n pending.clear();\n },\n };\n};\n"]}
1
+ {"version":3,"file":"ifc.js","sourceRoot":"","sources":["../../src/data/ifc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * IFC models (the BIM tools' own format: Revit, ArchiCAD, Tekla, Allplan, Bonsai…) read by web-ifc (ThatOpen,\n * MPL-2.0) in a worker of their own, web-ifc fetched on first use from a CDN (or a folder of yours): the model's\n * storeys and elements at once, each storey's geometry when asked (a glTF binary for `map.addModels({ data })`, each\n * element a feature of it, picked by the map: `hit.index` is the element's), the elements' properties on demand, and\n * where the model stands (its map conversion in a projected CRS, else its site's latitude and longitude).\n */\n\nimport { METRES_PER_DEGREE } from '../util/geo.ts';\nimport { bounds, bufferBuilder, glbOf } from '../util/gltf.ts';\nimport { getCrs } from './crs.ts';\n\n/** web-ifc's build used by default: its module (`web-ifc-api.js`) and its WebAssembly (`web-ifc.wasm`) */\nexport const WEB_IFC = 'https://cdn.jsdelivr.net/npm/web-ifc@0.0.78/';\n\nexport interface IfcOptions {\n /** Folder of `web-ifc-api.js` and `web-ifc.wasm` (ending with `/`; `WEB_IFC` by default): self-host them for offline\n * or locked-down networks. The worker imports the module from a `blob:` URL: a Content Security Policy needs\n * `blob:` in `worker-src` */\n webIfc?: string;\n /** Request options of the file's fetch (headers of a private source) */\n init?: RequestInit;\n}\n\n/** An element of the model (a wall, a slab, a window, a stair…) */\nexport interface IfcElement {\n /** Its IFC id (STEP line number) */\n id: number;\n /** Its IFC class (`IfcWall`, `IfcSlab`, `IfcWindow`…) */\n type: string;\n name: string;\n /** Its storey in `IfcModel.storeys` */\n storey: number;\n}\n\n/** A storey of the model: its elements, its geometry when asked */\nexport interface IfcStorey {\n id: number;\n name: string;\n /** Metres above the model's origin */\n elevation: number;\n /** Its elements (`IfcModel.elements`' indices) */\n elements: number[];\n /**\n * Its elements' geometry as a glTF binary (their features: `IfcModel.elements`' indices) in the model's frame: y up,\n * its north toward +z (`IfcModel.place.heading` turns it), its origin at the model's; meshed in the worker on the\n * first call (a large model's storeys one at a time, those in view only)\n */\n load(): Promise<Uint8Array<ArrayBuffer>>;\n}\n\n/** An element's properties: its attributes, then its property and quantity sets, by name */\nexport type IfcProperties = Record<string, Record<string, string | number | boolean | null>>;\n\n/** Where a model stands: its origin's position and height, the way its north faces */\nexport interface IfcPlace {\n lonLat: [number, number];\n /** Metres above the sea (its map conversion's height, its site's `RefElevation`) */\n elevation: number;\n /** Degrees clockwise from the north of the model's north (an instance's `heading`) */\n heading: number;\n /** How it is known: its map conversion (exact, `crs` its projected CRS), or its site's latitude and longitude */\n from: 'map' | 'site';\n crs?: string;\n}\n\nexport interface IfcModel {\n /** Its storeys from the lowest up, elements outside any storey (the site's) in one of their own at the start */\n storeys: IfcStorey[];\n /** Its elements, the features of the storeys' models */\n elements: IfcElement[];\n /** Where it stands, if the file says (`IfcMapConversion` in a CRS isard knows, else `IfcSite`'s position) */\n place?: IfcPlace;\n /** An element's properties, read from the file kept open in the worker */\n properties(element: number): Promise<IfcProperties>;\n /** Closes the file and its worker */\n close(): void;\n}\n\n/**\n * The worker's code: web-ifc imported from `base`, the file opened; its storeys, its elements (the spatial structure's\n * products) and what places it (its map conversion, its site, its true north) given at once, a storey's meshes when\n * asked (positions put in the model's frame, colors), the properties asked for\n */\nconst WORKER = `\nlet api, model, W;\nconst text = (v) => (v && typeof v.value !== 'undefined' ? v.value : null);\nconst degrees = (v) => {\n const parts = text(v);\n if (!Array.isArray(parts)) return undefined;\n const [d = 0, m = 0, s = 0, u = 0] = parts.map((p) => text(p) ?? p);\n return d + m / 60 + s / 3600 + u / 3600e6;\n};\nconst plain = (line) => Object.fromEntries(\n Object.entries(line ?? {})\n // Values, not references to other lines (type 5) nor lists\n .filter(([k, v]) => v && typeof v === 'object' && 'value' in v && v.type !== 5 && typeof v.value !== 'object' && k !== 'expressID')\n .map(([k, v]) => [k, v.value]),\n);\nconst ids = (type) => { const v = api.GetLineIDsWithType(model, type); return Array.from({ length: v.size() }, (_, i) => v.get(i)); };\nconst line = (ref) => (ref && ref.value !== undefined ? api.GetLine(model, ref.value) : undefined);\n// The spatial structure's containers, and the products drawn by no element of their own (the site is one when it has\n// a shape: its terrain)\nconst SPATIAL = new Set(['IFCPROJECT', 'IFCBUILDING', 'IFCBUILDINGSTOREY', 'IFCSPACE', 'IFCOPENINGELEMENT']);\nconst PREFIXES = { EXA: 1e18, PETA: 1e15, TERA: 1e12, GIGA: 1e9, MEGA: 1e6, KILO: 1e3, HECTO: 100, DECA: 10, DECI: 0.1, CENTI: 0.01, MILLI: 0.001, MICRO: 1e-6 };\n/** Metres per length unit of the project */\nconst unitScale = () => {\n const project = ids(W.IFCPROJECT).map((id) => api.GetLine(model, id))[0];\n const units = line(project?.UnitsInContext)?.Units ?? [];\n for (const ref of units) {\n const unit = line(ref);\n if (text(unit?.UnitType) !== 'LENGTHUNIT') continue;\n if (unit.Prefix !== undefined || text(unit.Name) === 'METRE') return PREFIXES[text(unit.Prefix)] ?? 1;\n // A conversion-based unit (the foot): its factor, in metres when its unit is\n const factor = line(unit.ConversionFactor);\n const value = Number(text(factor?.ValueComponent) ?? NaN);\n if (Number.isFinite(value)) return value * (PREFIXES[text(line(factor?.UnitComponent)?.Prefix)] ?? 1);\n }\n return 1;\n};\nonmessage = async ({ data }) => {\n try {\n if (data.type === 'open') {\n W = await import(data.base + 'web-ifc-api.js');\n api = new W.IfcAPI();\n api.SetWasmPath(data.base, true);\n await api.Init();\n model = api.OpenModel(new Uint8Array(data.bytes), { COORDINATE_TO_ORIGIN: true });\n const unit = unitScale();\n const storeys = ids(W.IFCBUILDINGSTOREY).map((id) => {\n const l = api.GetLine(model, id);\n return { id, name: text(l.Name) ?? '', elevation: Number(text(l.Elevation) ?? 0) * unit };\n });\n // The products of the spatial structure and their storeys\n const elements = [];\n const walk = (node, storey) => {\n const type = String(node.type);\n const here = type.toUpperCase() === 'IFCBUILDINGSTOREY' ? node.expressID : storey;\n const drawn = type.toUpperCase() !== 'IFCSITE' || api.GetLine(model, node.expressID)?.Representation;\n if (!SPATIAL.has(type.toUpperCase()) && drawn) {\n elements.push({ id: node.expressID, type, name: text(api.GetLine(model, node.expressID)?.Name) ?? '', storey: here ?? -1 });\n }\n (node.children ?? []).forEach((c) => walk(c, here));\n };\n walk(await api.properties.getSpatialStructure(model), undefined);\n // What places it: the shift web-ifc made to bring it near the origin (metres, its y-up frame), the map\n // conversion and its CRS, the site's latitude and longitude, the true north\n const shift = api.GetCoordinationMatrix(model).slice(12, 15);\n const conversion = ids(W.IFCMAPCONVERSION).map((id) => api.GetLine(model, id))[0];\n const site = ids(W.IFCSITE).map((id) => api.GetLine(model, id))[0];\n const north = ids(W.IFCGEOMETRICREPRESENTATIONCONTEXT)\n .map((id) => line(api.GetLine(model, id).TrueNorth))\n .find((d) => d)?.DirectionRatios?.map((r) => text(r) ?? r);\n const [lat, lon] = [degrees(site?.RefLatitude), degrees(site?.RefLongitude)];\n postMessage({\n type: 'model',\n storeys,\n elements,\n place: {\n shift,\n unit,\n ...(conversion && {\n map: ['Eastings', 'Northings', 'OrthogonalHeight', 'XAxisAbscissa', 'XAxisOrdinate', 'Scale'].map((k) => Number(text(conversion[k]) ?? (k === 'Scale' || k === 'XAxisAbscissa' ? 1 : 0))),\n crs: text(line(conversion.TargetCRS)?.Name),\n }),\n ...(lat !== undefined && lon !== undefined && { site: [lon, lat, Number(text(site.RefElevation) ?? 0) * unit] }),\n ...(north && { north }),\n },\n });\n } else if (data.type === 'storey') {\n const parts = [];\n const feature = new Map(data.ids.map((id, i) => [id, data.features[i]]));\n // web-ifc 0.0.78's browser build takes three arguments where its API passes four: called directly then\n const stream = (callback) => {\n try {\n api.StreamMeshes(model, data.ids, callback);\n } catch (error) {\n if (!/arguments/.test(String(error))) throw error;\n api.wasmModule.StreamMeshes(model, data.ids, callback);\n }\n };\n stream((mesh) => {\n for (let i = 0; i < mesh.geometries.size(); i++) {\n const placed = mesh.geometries.get(i);\n const geometry = api.GetGeometry(model, placed.geometryExpressID);\n const v = api.GetVertexArray(geometry.GetVertexData(), geometry.GetVertexDataSize());\n const indices = api.GetIndexArray(geometry.GetIndexData(), geometry.GetIndexDataSize()).slice();\n const m = placed.flatTransformation;\n const positions = new Float32Array((v.length / 6) * 3);\n for (let k = 0, p = 0; k < v.length; k += 6, p += 3) {\n const [x, y, z] = [v[k], v[k + 1], v[k + 2]];\n // Turned half a turn round y: the model's north (-z of web-ifc's y-up frame) toward +z, glTF's front\n positions[p] = -(m[0] * x + m[4] * y + m[8] * z + m[12]);\n positions[p + 1] = m[1] * x + m[5] * y + m[9] * z + m[13];\n positions[p + 2] = -(m[2] * x + m[6] * y + m[10] * z + m[14]);\n }\n const c = placed.color;\n parts.push({ feature: feature.get(mesh.expressID) ?? 0, color: [c.x, c.y, c.z, c.w], positions, indices });\n geometry.delete();\n }\n });\n postMessage({ type: 'storey', request: data.request, parts }, parts.flatMap((p) => [p.positions.buffer, p.indices.buffer]));\n } else if (data.type === 'properties') {\n const properties = { Attributes: plain(api.GetLine(model, data.id)) };\n const sets = await api.properties.getPropertySets(model, data.id, true);\n for (const set of sets) {\n const values = {};\n for (const p of [...(set.HasProperties ?? []), ...(set.Quantities ?? [])]) {\n const name = text(p.Name);\n if (!name) continue;\n const value = p.NominalValue ?? p.LengthValue ?? p.AreaValue ?? p.VolumeValue ?? p.CountValue ?? p.WeightValue;\n values[name] = text(value);\n }\n properties[text(set.Name) ?? 'Set ' + set.expressID] = values;\n }\n postMessage({ type: 'properties', request: data.request, properties });\n }\n } catch (error) {\n postMessage({ type: 'error', request: data.request, message: String(error?.message ?? error) });\n }\n};\n`;\n\n/** A part of the model: an element's geometry in one color */\ninterface Part {\n feature: number;\n color: [number, number, number, number];\n positions: Float32Array;\n indices: Uint32Array;\n}\n\n/** A storey's parts as a glTF binary: a primitive per color, each vertex its element (`_BATCHID`) */\nexport const storeyModel = (parts: readonly Part[]): Uint8Array<ArrayBuffer> => {\n const byColor = new Map<string, Part[]>();\n\n parts.forEach((p) => {\n const key = p.color.map((c) => c.toFixed(3)).join(',');\n\n byColor.set(key, [...(byColor.get(key) ?? []), p]);\n });\n\n const { views, append, bin: buffer } = bufferBuilder();\n const accessors: Record<string, unknown>[] = [];\n const groups = [...byColor.values()];\n const primitives = groups.map((group, material) => {\n const count = group.reduce((n, p) => n + p.positions.length / 3, 0);\n const positions = new Float32Array(count * 3);\n const features = new Float32Array(count);\n const indices = new Uint32Array(group.reduce((n, p) => n + p.indices.length, 0));\n let [vertex, index] = [0, 0];\n\n group.forEach((p) => {\n positions.set(p.positions, vertex * 3);\n features.fill(p.feature, vertex, vertex + p.positions.length / 3);\n p.indices.forEach((i, k) => {\n indices[index + k] = i + vertex;\n });\n vertex += p.positions.length / 3;\n index += p.indices.length;\n });\n accessors.push(\n {\n bufferView: append(new Uint8Array(positions.buffer), 34962),\n componentType: 5126,\n count,\n type: 'VEC3',\n ...bounds([...positions]),\n },\n { bufferView: append(new Uint8Array(features.buffer), 34962), componentType: 5126, count, type: 'SCALAR' },\n {\n bufferView: append(new Uint8Array(indices.buffer), 34963),\n componentType: 5125,\n count: indices.length,\n type: 'SCALAR',\n },\n );\n\n const at = accessors.length - 3;\n\n return { attributes: { POSITION: at, _BATCHID: at + 1 }, indices: at + 2, material };\n });\n const bin = buffer();\n\n return glbOf(\n {\n asset: { version: '2.0', generator: 'isard (IFC)' },\n scene: 0,\n scenes: [{ nodes: [0] }],\n nodes: [{ mesh: 0 }],\n meshes: [{ primitives }],\n materials: groups.map((group) => {\n const color = group[0]?.color ?? [0.8, 0.8, 0.8, 1];\n\n return {\n pbrMetallicRoughness: { baseColorFactor: color, metallicFactor: 0, roughnessFactor: 1 },\n ...(color[3] < 1 && { alphaMode: 'BLEND' }),\n doubleSided: true,\n };\n }),\n accessors,\n bufferViews: views,\n buffers: [{ byteLength: bin.byteLength }],\n },\n bin,\n );\n};\n\n/** What places a model, as the worker reads it: web-ifc's shift of it (metres, its y-up frame), its project's metres\n * per unit, its map conversion (eastings, northings, height, x axis' abscissa and ordinate, scale) and its CRS, its\n * site's longitude, latitude and elevation, its true north (in its plan) */\nexport interface IfcPlacing {\n shift: number[];\n unit: number;\n map?: number[];\n crs?: string | null;\n site?: [number, number, number];\n north?: number[];\n}\n\n/** Degrees clockwise from the north of the true north to (x, y) in a plan whose y would be north */\nconst bearingOf = (x: number, y: number): number => (Math.atan2(x, y) * 180) / Math.PI;\n\n/**\n * Where a model's origin (its glTF's) stands: by its map conversion when its CRS is known (the origin in the file's\n * frame, before web-ifc's shift, taken to the map's eastings and northings, then to longitude and latitude; its north\n * turned by the conversion's x axis and the grid's convergence there), else by its site's latitude and longitude\n * turned by its true north\n */\nexport const placeIfc = ({ shift, unit, map, crs, site, north }: IfcPlacing): IfcPlace | undefined => {\n // The origin in the file's frame (metres, z up): web-ifc's y-up shift undone\n const [sx = 0, sy = 0, sz = 0] = shift;\n const [x, y, z] = [-sx, sz, -sy];\n\n if (map && crs) {\n const projection = (() => {\n try {\n return getCrs(crs);\n } catch {\n return undefined;\n }\n })();\n const [e = 0, n = 0, h = 0, ax = 1, ay = 0, scale = 1] = map;\n\n if (projection) {\n const length = Math.hypot(ax, ay) || 1;\n const [a, b] = [ax / length, ay / length];\n // The conversion's scale takes the project's units to the map's; the geometry is in metres already\n const k = scale / unit;\n const [east, northing] = [e + k * (a * x - b * y), n + k * (b * x + a * y)];\n const [lon = 0, lat = 0] = projection.inverse([east, northing]);\n const [lon2 = 0, lat2 = 0] = projection.inverse([east, northing + 100]);\n // The grid's north from the true north there, and the file's north (its y) from the grid's\n const convergence = bearingOf((lon2 - lon) * Math.cos((lat * Math.PI) / 180), lat2 - lat);\n\n return {\n lonLat: [lon, lat],\n elevation: h + k * z,\n heading: bearingOf(-b, a) + convergence,\n from: 'map',\n crs,\n };\n }\n }\n if (!site) return undefined;\n\n // The true north in the plan: the plan's y turned from it the other way\n const [nx = 0, ny = 1] = north ?? [];\n const heading = -bearingOf(nx, ny);\n const [lon, lat, elevation] = site;\n // The origin's offset from the site's (metres, the plan turned to the north)\n const turn = (heading * Math.PI) / 180;\n const [east, northing] = [x * Math.cos(turn) + y * Math.sin(turn), -x * Math.sin(turn) + y * Math.cos(turn)];\n\n return {\n lonLat: [lon + east / (METRES_PER_DEGREE * Math.cos((lat * Math.PI) / 180)), lat + northing / METRES_PER_DEGREE],\n elevation: elevation + z,\n heading,\n from: 'site',\n };\n};\n\n/** The answer of the worker to a message */\ntype Answer =\n | { type: 'model'; storeys: Omit<IfcStorey, 'elements' | 'load'>[]; elements: IfcElement[]; place: IfcPlacing }\n | { type: 'storey'; request: number; parts: Part[] }\n | { type: 'properties'; request: number; properties: IfcProperties }\n | { type: 'error'; request?: number; message: string };\n\n/**\n * An IFC file (its URL, or its bytes) opened by web-ifc in a worker: its storeys and elements, each storey's geometry\n * when asked, the elements' properties on demand, where it stands\n */\nexport const loadIfc = async (source: string | ArrayBuffer, options: IfcOptions = {}): Promise<IfcModel> => {\n const bytes =\n typeof source === 'string'\n ? await fetch(source, options.init).then((r) => {\n if (!r.ok) throw new Error(`isard: ${source}: ${r.status}`);\n\n return r.arrayBuffer();\n })\n : source;\n const script = URL.createObjectURL(new Blob([WORKER], { type: 'text/javascript' }));\n const worker = new Worker(script, { type: 'module' });\n /** The answers awaited, by request */\n const pending = new Map<number, { resolve: (answer: Answer) => void; reject: (e: Error) => void }>();\n let request = 0;\n const ask = <A extends Answer>(message: Record<string, unknown>): Promise<A> =>\n new Promise((resolve, reject) => {\n request += 1;\n pending.set(request, { resolve: (answer) => resolve(answer as A), reject });\n worker.postMessage({ ...message, request });\n });\n\n URL.revokeObjectURL(script);\n\n const opened = await new Promise<Extract<Answer, { type: 'model' }>>((resolve, reject) => {\n // The worker failing: the model not opened, or (once it is) every answer awaited\n const fail = (error: Error) => {\n reject(error);\n pending.forEach((waiting) => {\n waiting.reject(error);\n });\n pending.clear();\n };\n\n worker.onmessage = ({ data }: MessageEvent<Answer>) => {\n if (data.type === 'model') resolve(data);\n else if (data.request === undefined) fail(new Error(`isard: IFC: ${data.type === 'error' ? data.message : ''}`));\n else {\n const waiting = pending.get(data.request);\n\n pending.delete(data.request);\n if (data.type === 'error') waiting?.reject(new Error(`isard: IFC: ${data.message}`));\n else waiting?.resolve(data);\n }\n };\n worker.onerror = (e) => {\n fail(new Error(`isard: IFC worker: ${e.message}`));\n };\n worker.postMessage({ type: 'open', base: options.webIfc ?? WEB_IFC, bytes }, [bytes]);\n }).catch((error: unknown) => {\n worker.terminate();\n throw error;\n });\n\n // The storeys holding elements from the lowest up, the elements outside any in one of their own first (at the\n // lowest storey's elevation)\n const used = new Set(opened.elements.map((e) => e.storey));\n const sorted = opened.storeys.filter((s) => used.has(s.id)).sort((a, b) => a.elevation - b.elevation);\n const outside = opened.elements.some((e) => !sorted.some((s) => s.id === e.storey));\n const list = [...(outside ? [{ id: -1, name: 'Site', elevation: sorted[0]?.elevation ?? 0 }] : []), ...sorted];\n const storeyIndex = new Map(list.map((s, i) => [s.id, i]));\n const elements: IfcElement[] = opened.elements.map((e) => ({ ...e, storey: storeyIndex.get(e.storey) ?? 0 }));\n const storeys: IfcStorey[] = list.map((s, i) => {\n const members = elements.flatMap((e, k) => (e.storey === i ? [k] : []));\n let loaded: Promise<Uint8Array<ArrayBuffer>> | undefined;\n\n return {\n ...s,\n elements: members,\n load: () => {\n loaded ??= ask<Extract<Answer, { type: 'storey' }>>({\n type: 'storey',\n ids: members.map((k) => elements[k]?.id ?? 0),\n features: members,\n }).then(({ parts }) => storeyModel(parts));\n\n return loaded;\n },\n };\n });\n const place = placeIfc(opened.place);\n\n return {\n storeys,\n elements,\n ...(place && { place }),\n properties: (element: number) => {\n const id = elements[element]?.id;\n\n if (id === undefined) return Promise.reject(new Error(`isard: IFC: no element ${element}`));\n\n return ask<Extract<Answer, { type: 'properties' }>>({ type: 'properties', id }).then((a) => a.properties);\n },\n close: () => {\n worker.terminate();\n pending.forEach(({ reject }) => {\n reject(new Error('isard: IFC model closed'));\n });\n pending.clear();\n },\n };\n};\n"]}
@@ -84,17 +84,29 @@ export declare const BATIMENTS_3D_URL = "https://prd-ign-mut-bat3.s3.sbg.io.clou
84
84
  /**
85
85
  * The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),
86
86
  * raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes
87
- * (`cleabs`, `hauteur`, `nature`, `usage_1`…). Its server sends no CORS headers yet: from a page of another origin,
88
- * through a proxy (`url`)
87
+ * (`cleabs`, `hauteur`, `nature`, `usage_1`…). A beta: its server answers the pages of a few origins only (the IGN's
88
+ * sites, isard's documentation); from another, through a proxy (`url`)
89
89
  */
90
90
  export declare const batiments3d: (options?: Partial<Tiles3dOptions>) => Tiles3dOptions;
91
- /** What a building of the BD TOPO gives its extrusion */
91
+ /** What a building of the BD TOPO gives its extrusion: its height to the eaves (`hauteur`), the altitudes of its foot,
92
+ * its eaves and its ridge (metres; the ridge's known in some places only) */
92
93
  export interface BdTopoBuilding {
93
94
  hauteur: number | null;
95
+ altitude_minimale_sol?: number | null;
96
+ altitude_minimale_toit?: number | null;
97
+ altitude_maximale_toit?: number | null;
94
98
  }
99
+ /**
100
+ * A BD TOPO building's height, roof and roof height as `addExtrusions` takes them: raised to its ridge, its roof as
101
+ * high as from its eaves to its ridge (flat under half a metre), where the BD TOPO gives its ridge's altitude (most of
102
+ * the towns, not Paris yet); else to its `hauteur` (`defaultHeight` without one), its roof generated from its outline
103
+ * within it
104
+ */
105
+ export declare const bdtopoRoofs: (defaultHeight?: number) => Pick<ExtrusionOptions<BdTopoBuilding>, "height" | "roof" | "roofHeight">;
95
106
  /**
96
107
  * The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for
97
- * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their `hauteur` (`defaultHeight` without one)
108
+ * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their ridge under a roof of its height where the BD
109
+ * TOPO gives it (`bdtopoRoofs`), else to their `hauteur` (`defaultHeight` without one)
98
110
  */
99
111
  export declare const bdtopoBuildings: (box: [number, number, number, number], options?: Partial<ExtrusionOptions<BdTopoBuilding>> & {
100
112
  defaultHeight?: number;
@@ -134,20 +134,42 @@ export const BATIMENTS_3D_URL = 'https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.ne
134
134
  /**
135
135
  * The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),
136
136
  * raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes
137
- * (`cleabs`, `hauteur`, `nature`, `usage_1`…). Its server sends no CORS headers yet: from a page of another origin,
138
- * through a proxy (`url`)
137
+ * (`cleabs`, `hauteur`, `nature`, `usage_1`…). A beta: its server answers the pages of a few origins only (the IGN's
138
+ * sites, isard's documentation); from another, through a proxy (`url`)
139
139
  */
140
140
  export const batiments3d = (options = {}) => {
141
141
  return { url: BATIMENTS_3D_URL, geoid: true, color: '#e4e1d8', maxScreenSpaceError: 16, ...options };
142
142
  };
143
+ /** Metres under which a BD TOPO roof, from its eaves to its ridge, is drawn flat */
144
+ const FLAT_ROOF_METRES = 0.5;
145
+ /** A BD TOPO building's roof over its eaves (metres, from its ridge's and its eaves' altitudes), undefined unknown */
146
+ const roofOver = (p) => {
147
+ const [eaves, ridge] = [p.altitude_minimale_toit, p.altitude_maximale_toit];
148
+ return typeof eaves === 'number' && typeof ridge === 'number' && ridge >= eaves ? ridge - eaves : undefined;
149
+ };
150
+ /**
151
+ * A BD TOPO building's height, roof and roof height as `addExtrusions` takes them: raised to its ridge, its roof as
152
+ * high as from its eaves to its ridge (flat under half a metre), where the BD TOPO gives its ridge's altitude (most of
153
+ * the towns, not Paris yet); else to its `hauteur` (`defaultHeight` without one), its roof generated from its outline
154
+ * within it
155
+ */
156
+ export const bdtopoRoofs = (defaultHeight = 6) => ({
157
+ height: (p) => (p.hauteur ?? defaultHeight) + (roofOver(p) ?? 0),
158
+ roof: (p) => {
159
+ const over = roofOver(p);
160
+ return over === undefined || over >= FLAT_ROOF_METRES ? 'generated' : 'flat';
161
+ },
162
+ roofHeight: (p) => roofOver(p) ?? Number.NaN,
163
+ });
143
164
  /**
144
165
  * The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for
145
- * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their `hauteur` (`defaultHeight` without one)
166
+ * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their ridge under a roof of its height where the BD
167
+ * TOPO gives it (`bdtopoRoofs`), else to their `hauteur` (`defaultHeight` without one)
146
168
  */
147
169
  export const bdtopoBuildings = async (box, options = {}) => {
148
170
  const { defaultHeight = 6, signal, ...style } = options;
149
171
  const data = await geoplateformeWfs('BDTOPO_V3:batiment', box, signal ? { signal } : {});
150
- return { data, height: (p) => p.hauteur ?? defaultHeight, color: '#e4e1d8', ...style };
172
+ return { data, ...bdtopoRoofs(defaultHeight), color: '#e4e1d8', ...style };
151
173
  };
152
174
  const GEOCODING_URL = 'https://data.geopf.fr/geocodage/completion';
153
175
  /** One result of the completion service: what is read of it, checked (JSON from elsewhere) */
@@ -1 +1 @@
1
- {"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\n\nimport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nimport { withHeaders } from './engine/requests.ts';\nimport type { ExtrusionOptions } from './layers/extrusions.ts';\nimport type { FeatureCollection, Properties } from './layers/features.ts';\nimport type { GeoMapOptions, RasterOptions, Tiles3dOptions } from './types.ts';\nimport { isRecord } from './util/guards.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport const lambert93Grid = (name: string, min: number, max: number): TileGrid => {\n const matrices = Array.from({ length: Math.max(0, max - min + 1) }, (_, i): TileMatrix => {\n const level = min + i;\n\n return { id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] };\n });\n\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n};\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport const geoplateformeWmts = (\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions => {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n};\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport const geoplateformeWms = (\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions => {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n};\n\n/** Features the Géoplateforme's WFS returns per request at most */\nconst WFS_PAGE = 5000;\n\n/** A page of WFS features in GeoJSON, with the number of features matched (a string from some servers) */\ntype WfsPage<P> = FeatureCollection<P> & { numberMatched?: number | string };\n\nconst isWfsPage = <P>(value: unknown): value is WfsPage<P> =>\n typeof value === 'object' && value !== null && 'features' in value && Array.isArray(value.features);\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.\n * The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the\n * features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature\n * layers reproject it by themselves\n */\nexport const geoplateformeWfs = async <P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> => {\n const limit = Math.max(1, options.count ?? 50_000);\n const page = async (start: number, count: number) => {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(count),\n // The first page as a single request always was\n ...(start > 0 ? { STARTINDEX: String(start) } : {}),\n }).toString();\n\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n\n const json: unknown = await response.json();\n\n if (!isWfsPage<P>(json)) throw new Error(`isard: ${typeName}: not a GeoJSON feature collection`);\n\n return json;\n };\n const first = await page(0, Math.min(WFS_PAGE, limit));\n const matched = Number(first.numberMatched);\n const total = Math.min(Number.isFinite(matched) ? matched : 0, limit);\n\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n\n const starts = Array.from(\n { length: Math.ceil((total - first.features.length) / WFS_PAGE) },\n (_, i) => first.features.length + i * WFS_PAGE,\n );\n const rest = await Promise.all(starts.map((start) => page(start, Math.min(WFS_PAGE, total - start))));\n // Pages may overlap where the server's order shifts: each feature once, by its id\n const seen = new Set<unknown>();\n const features = [first, ...rest]\n .flatMap((r) => r.features)\n .filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));\n\n return { ...first, features };\n};\n\n/** Map presets over France, the IGN's data in a word: spread into `GeoMap.create`'s options or named by `preset` */\nexport const IGN_PRESETS = {\n /** PLAN IGN (vector, grey) seen from above */\n ign: { basemap: 'ign-plan-grey-vector', projection: 'mercator' },\n /** PLAN IGN over the IGN relief (RGE ALTI), for 3D: buildings, meshes, viewsheds */\n 'ign-3d': { basemap: 'ign-plan-grey-vector', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },\n /** The IGN orthophotos over the IGN relief */\n 'ign-ortho-3d': { basemap: 'ign-ortho', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },\n} as const satisfies Record<string, GeoMapOptions>;\n\n/** A preset of `IGN_PRESETS` by name */\nexport type IgnPreset = keyof typeof IGN_PRESETS;\n\n/** The IGN's Bâtiments 3D (France, 3D Tiles 1.1): its tileset */\nexport const BATIMENTS_3D_URL = 'https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.net/tileset.json';\n\n/**\n * The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),\n * raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes\n * (`cleabs`, `hauteur`, `nature`, `usage_1`…). Its server sends no CORS headers yet: from a page of another origin,\n * through a proxy (`url`)\n */\nexport const batiments3d = (options: Partial<Tiles3dOptions> = {}): Tiles3dOptions => {\n return { url: BATIMENTS_3D_URL, geoid: true, color: '#e4e1d8', maxScreenSpaceError: 16, ...options };\n};\n\n/** What a building of the BD TOPO gives its extrusion */\nexport interface BdTopoBuilding {\n hauteur: number | null;\n}\n\n/**\n * The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for\n * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their `hauteur` (`defaultHeight` without one)\n */\nexport const bdtopoBuildings = async (\n box: [number, number, number, number],\n options: Partial<ExtrusionOptions<BdTopoBuilding>> & { defaultHeight?: number; signal?: AbortSignal } = {},\n): Promise<ExtrusionOptions<BdTopoBuilding>> => {\n const { defaultHeight = 6, signal, ...style } = options;\n const data = await geoplateformeWfs<BdTopoBuilding>('BDTOPO_V3:batiment', box, signal ? { signal } : {});\n\n return { data, height: (p) => p.hauteur ?? defaultHeight, color: '#e4e1d8', ...style };\n};\n\n/** A place the Géoplateforme's geocoding found: its label, position and kind */\nexport interface GeocodedPlace {\n /** The full label (`10 Rue de Rivoli, 75004 Paris`) */\n label: string;\n lonLat: [lon: number, lat: number];\n /** `'address'` (a street address) or `'place'` (a place name: a town, a monument, a summit) */\n kind: 'address' | 'place';\n}\n\nconst GEOCODING_URL = 'https://data.geopf.fr/geocodage/completion';\n\n/** One result of the completion service: what is read of it, checked (JSON from elsewhere) */\nconst isCompletion = (value: unknown): value is { fulltext: string; x: number; y: number; kind?: unknown } =>\n isRecord(value) && typeof value.fulltext === 'string' && Number.isFinite(value.x) && Number.isFinite(value.y);\n\n/**\n * Places of France matching `text` as it is typed, from the Géoplateforme's completion service (addresses and place\n * names, no key), the best first; an empty list for a text under 3 characters\n */\nexport const geoplateformeGeocode = async (\n text: string,\n options: { count?: number; signal?: AbortSignal } = {},\n): Promise<GeocodedPlace[]> => {\n if (text.trim().length < 3) return [];\n\n const url = `${GEOCODING_URL}?text=${encodeURIComponent(text)}&type=StreetAddress,PositionOfInterest&maximumResponses=${options.count ?? 10}`;\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: geocoding: ${response.status}`);\n\n const json: unknown = await response.json();\n const results = isRecord(json) && Array.isArray(json.results) ? json.results : [];\n\n return results.filter(isCompletion).map((r) => ({\n label: r.fulltext,\n lonLat: [r.x, r.y],\n kind: r.kind === 'StreetAddress' || r.kind === 'housenumber' || r.kind === 'street' ? 'address' : 'place',\n }));\n};\n"]}
1
+ {"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\n\nimport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nimport { withHeaders } from './engine/requests.ts';\nimport type { ExtrusionOptions } from './layers/extrusions.ts';\nimport type { FeatureCollection, Properties } from './layers/features.ts';\nimport type { GeoMapOptions, RasterOptions, Tiles3dOptions } from './types.ts';\nimport { isRecord } from './util/guards.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport const lambert93Grid = (name: string, min: number, max: number): TileGrid => {\n const matrices = Array.from({ length: Math.max(0, max - min + 1) }, (_, i): TileMatrix => {\n const level = min + i;\n\n return { id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] };\n });\n\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n};\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport const geoplateformeWmts = (\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions => {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n};\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport const geoplateformeWms = (\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions => {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n};\n\n/** Features the Géoplateforme's WFS returns per request at most */\nconst WFS_PAGE = 5000;\n\n/** A page of WFS features in GeoJSON, with the number of features matched (a string from some servers) */\ntype WfsPage<P> = FeatureCollection<P> & { numberMatched?: number | string };\n\nconst isWfsPage = <P>(value: unknown): value is WfsPage<P> =>\n typeof value === 'object' && value !== null && 'features' in value && Array.isArray(value.features);\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.\n * The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the\n * features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature\n * layers reproject it by themselves\n */\nexport const geoplateformeWfs = async <P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> => {\n const limit = Math.max(1, options.count ?? 50_000);\n const page = async (start: number, count: number) => {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(count),\n // The first page as a single request always was\n ...(start > 0 ? { STARTINDEX: String(start) } : {}),\n }).toString();\n\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n\n const json: unknown = await response.json();\n\n if (!isWfsPage<P>(json)) throw new Error(`isard: ${typeName}: not a GeoJSON feature collection`);\n\n return json;\n };\n const first = await page(0, Math.min(WFS_PAGE, limit));\n const matched = Number(first.numberMatched);\n const total = Math.min(Number.isFinite(matched) ? matched : 0, limit);\n\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n\n const starts = Array.from(\n { length: Math.ceil((total - first.features.length) / WFS_PAGE) },\n (_, i) => first.features.length + i * WFS_PAGE,\n );\n const rest = await Promise.all(starts.map((start) => page(start, Math.min(WFS_PAGE, total - start))));\n // Pages may overlap where the server's order shifts: each feature once, by its id\n const seen = new Set<unknown>();\n const features = [first, ...rest]\n .flatMap((r) => r.features)\n .filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));\n\n return { ...first, features };\n};\n\n/** Map presets over France, the IGN's data in a word: spread into `GeoMap.create`'s options or named by `preset` */\nexport const IGN_PRESETS = {\n /** PLAN IGN (vector, grey) seen from above */\n ign: { basemap: 'ign-plan-grey-vector', projection: 'mercator' },\n /** PLAN IGN over the IGN relief (RGE ALTI), for 3D: buildings, meshes, viewsheds */\n 'ign-3d': { basemap: 'ign-plan-grey-vector', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },\n /** The IGN orthophotos over the IGN relief */\n 'ign-ortho-3d': { basemap: 'ign-ortho', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },\n} as const satisfies Record<string, GeoMapOptions>;\n\n/** A preset of `IGN_PRESETS` by name */\nexport type IgnPreset = keyof typeof IGN_PRESETS;\n\n/** The IGN's Bâtiments 3D (France, 3D Tiles 1.1): its tileset */\nexport const BATIMENTS_3D_URL = 'https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.net/tileset.json';\n\n/**\n * The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),\n * raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes\n * (`cleabs`, `hauteur`, `nature`, `usage_1`…). A beta: its server answers the pages of a few origins only (the IGN's\n * sites, isard's documentation); from another, through a proxy (`url`)\n */\nexport const batiments3d = (options: Partial<Tiles3dOptions> = {}): Tiles3dOptions => {\n return { url: BATIMENTS_3D_URL, geoid: true, color: '#e4e1d8', maxScreenSpaceError: 16, ...options };\n};\n\n/** What a building of the BD TOPO gives its extrusion: its height to the eaves (`hauteur`), the altitudes of its foot,\n * its eaves and its ridge (metres; the ridge's known in some places only) */\nexport interface BdTopoBuilding {\n hauteur: number | null;\n altitude_minimale_sol?: number | null;\n altitude_minimale_toit?: number | null;\n altitude_maximale_toit?: number | null;\n}\n\n/** Metres under which a BD TOPO roof, from its eaves to its ridge, is drawn flat */\nconst FLAT_ROOF_METRES = 0.5;\n\n/** A BD TOPO building's roof over its eaves (metres, from its ridge's and its eaves' altitudes), undefined unknown */\nconst roofOver = (p: BdTopoBuilding): number | undefined => {\n const [eaves, ridge] = [p.altitude_minimale_toit, p.altitude_maximale_toit];\n\n return typeof eaves === 'number' && typeof ridge === 'number' && ridge >= eaves ? ridge - eaves : undefined;\n};\n\n/**\n * A BD TOPO building's height, roof and roof height as `addExtrusions` takes them: raised to its ridge, its roof as\n * high as from its eaves to its ridge (flat under half a metre), where the BD TOPO gives its ridge's altitude (most of\n * the towns, not Paris yet); else to its `hauteur` (`defaultHeight` without one), its roof generated from its outline\n * within it\n */\nexport const bdtopoRoofs = (\n defaultHeight = 6,\n): Pick<ExtrusionOptions<BdTopoBuilding>, 'height' | 'roof' | 'roofHeight'> => ({\n height: (p) => (p.hauteur ?? defaultHeight) + (roofOver(p) ?? 0),\n roof: (p) => {\n const over = roofOver(p);\n\n return over === undefined || over >= FLAT_ROOF_METRES ? 'generated' : 'flat';\n },\n roofHeight: (p) => roofOver(p) ?? Number.NaN,\n});\n\n/**\n * The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for\n * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their ridge under a roof of its height where the BD\n * TOPO gives it (`bdtopoRoofs`), else to their `hauteur` (`defaultHeight` without one)\n */\nexport const bdtopoBuildings = async (\n box: [number, number, number, number],\n options: Partial<ExtrusionOptions<BdTopoBuilding>> & { defaultHeight?: number; signal?: AbortSignal } = {},\n): Promise<ExtrusionOptions<BdTopoBuilding>> => {\n const { defaultHeight = 6, signal, ...style } = options;\n const data = await geoplateformeWfs<BdTopoBuilding>('BDTOPO_V3:batiment', box, signal ? { signal } : {});\n\n return { data, ...bdtopoRoofs(defaultHeight), color: '#e4e1d8', ...style };\n};\n\n/** A place the Géoplateforme's geocoding found: its label, position and kind */\nexport interface GeocodedPlace {\n /** The full label (`10 Rue de Rivoli, 75004 Paris`) */\n label: string;\n lonLat: [lon: number, lat: number];\n /** `'address'` (a street address) or `'place'` (a place name: a town, a monument, a summit) */\n kind: 'address' | 'place';\n}\n\nconst GEOCODING_URL = 'https://data.geopf.fr/geocodage/completion';\n\n/** One result of the completion service: what is read of it, checked (JSON from elsewhere) */\nconst isCompletion = (value: unknown): value is { fulltext: string; x: number; y: number; kind?: unknown } =>\n isRecord(value) && typeof value.fulltext === 'string' && Number.isFinite(value.x) && Number.isFinite(value.y);\n\n/**\n * Places of France matching `text` as it is typed, from the Géoplateforme's completion service (addresses and place\n * names, no key), the best first; an empty list for a text under 3 characters\n */\nexport const geoplateformeGeocode = async (\n text: string,\n options: { count?: number; signal?: AbortSignal } = {},\n): Promise<GeocodedPlace[]> => {\n if (text.trim().length < 3) return [];\n\n const url = `${GEOCODING_URL}?text=${encodeURIComponent(text)}&type=StreetAddress,PositionOfInterest&maximumResponses=${options.count ?? 10}`;\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: geocoding: ${response.status}`);\n\n const json: unknown = await response.json();\n const results = isRecord(json) && Array.isArray(json.results) ? json.results : [];\n\n return results.filter(isCompletion).map((r) => ({\n label: r.fulltext,\n lonLat: [r.x, r.y],\n kind: r.kind === 'StreetAddress' || r.kind === 'housenumber' || r.kind === 'street' ? 'address' : 'place',\n }));\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ export { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';
18
18
  export { coniferModel, type TreeColors, treeModel } from './basemap/trees.ts';
19
19
  export type { CandidateIcon, CandidateOverlap, Json, LabelCandidate, RasterSource, Style, StyleLayer, } from './basemap/vectorstyle.ts';
20
20
  export type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';
21
+ export type { FurnitureOptions } from './basemap/vectortiles/furniture.ts';
21
22
  export type { LabelsOptions } from './basemap/vectortiles/labels.ts';
22
23
  export type { LampsOptions } from './basemap/vectortiles/lamps.ts';
23
24
  export type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';
@@ -35,7 +36,7 @@ export { parseKml } from './data/kml.ts';
35
36
  export { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';
36
37
  export type { DecoderUrls } from './engine/decoders.ts';
37
38
  export { setRequestHeaders } from './engine/requests.ts';
38
- export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, type GeocodedPlace, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, lambert93Grid, } from './geoplateforme.ts';
39
+ export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, bdtopoRoofs, type GeocodedPlace, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, lambert93Grid, } from './geoplateforme.ts';
39
40
  export { type Grid, windAt, windFields } from './grids.ts';
40
41
  export type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';
41
42
  export { ExtrusionLayer } from './layers/extrusions.ts';
@@ -48,7 +49,7 @@ export { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';
48
49
  export type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';
49
50
  export type { CustomFrame, CustomLayerInterface, GroundOptions, GroundTexture, ModelInstance, ModelOptions, } from './layers/layers.ts';
50
51
  export { CustomLayer, GroundLayer, Layer, ModelLayer, NetworkLayer, RasterLayer, Tiles3dLayer, } from './layers/layers.ts';
51
- export { type Panorama, type PanoramaOptions, Panoramas } from './layers/panoramas.ts';
52
+ export { type CalibratedPanoramaOptions, type Panorama, type PanoramaOptions, type PanoramaPhoto, Panoramas, type PhotoPanoramaOptions, } from './layers/panoramas.ts';
52
53
  export { type PhotoOptions, photoModel } from './layers/photos.ts';
53
54
  export type { ClassStyle, PointCloudOptions, PointCloudStyle, PointColor } from './layers/pointclouds.ts';
54
55
  export { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from './layers/pointclouds.ts';
@@ -58,13 +59,13 @@ export { type TreeKind, type TreeOptions, treeKind } from './layers/trees.ts';
58
59
  export { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';
59
60
  export type { HoverPicking } from './map/hover-pick.ts';
60
61
  export { GeoMap, type LayerSpec } from './map.ts';
61
- export { PANORAMAX_API, type PanoramaxPicture, panoramaxPhoto, panoramaxPicture, panoramaxStyle, } from './panoramax.ts';
62
+ export { PANORAMAX_API, type PanoramaxPicture, type PanoramaxSequenceOptions, panoramaxPanoramas, panoramaxPhoto, panoramaxPicture, panoramaxSequence, panoramaxStyle, } from './panoramax.ts';
62
63
  export type { AnimationOptions, AtmosphereOptions, Basemap, BasemapName, BodyOptions, CelestialBody, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapHoverFeatureEvent, MapPointerEvent, NetworkOptions, NetworkStyle, Point, Projection, RasterGrid, RasterOptions, RasterStyle, SunOptions, SwipeOptions, TerrainEncoding, TerrainModel, TerrainOptions, Tiles3dOptions, Tiles3dStyle, ViewshedOptions, } from './types.ts';
63
64
  export { AttributionControl, type AttributionOptions, type Control, type ControlPosition, NavigationControl, type NavigationOptions, } from './ui/controls.ts';
64
65
  export { MinimapControl, type MinimapOptions } from './ui/minimap.ts';
65
66
  export { type Anchor, Marker, type MarkerEvent, type MarkerEvents, type MarkerOptions, Panel, type PanelOptions, Popup, type PopupEvents, type PopupOptions, } from './ui/overlay.ts';
66
67
  export { lengthLabel, roundLength, ScaleControl, type ScaleOptions } from './ui/scale.ts';
67
68
  export { SearchControl, type SearchOptions } from './ui/search.ts';
69
+ export type { RoofMode } from './util/roofs.ts';
68
70
  export { sunPosition } from './util/sun.ts';
69
71
  export type { Camera, NetworkStats, PickHit, PickResult, PointCloudInfo, PointCloudPoint, PointCloudStats, RasterLayerStats, Tiles3dStats, } from './wasm/isard.js';
70
- export type { RoofMode } from './workers/basemap/geometry.ts';
package/dist/index.js CHANGED
@@ -24,21 +24,21 @@ export { loadIfc, WEB_IFC, } from "./data/ifc.js";
24
24
  export { parseKml } from "./data/kml.js";
25
25
  export { parseTopoJson } from "./data/topojson.js";
26
26
  export { setRequestHeaders } from "./engine/requests.js";
27
- export { BATIMENTS_3D_URL, batiments3d, bdtopoBuildings, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, lambert93Grid, } from "./geoplateforme.js";
27
+ export { BATIMENTS_3D_URL, batiments3d, bdtopoBuildings, bdtopoRoofs, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, lambert93Grid, } from "./geoplateforme.js";
28
28
  export { windAt, windFields } from "./grids.js";
29
29
  export { ExtrusionLayer } from "./layers/extrusions.js";
30
30
  export { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from "./layers/features.js";
31
31
  export { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from "./layers/flow.js";
32
32
  export { DEFAULT_FONT, GLYPHS_URL } from "./layers/glyphs.js";
33
33
  export { CustomLayer, GroundLayer, Layer, ModelLayer, NetworkLayer, RasterLayer, Tiles3dLayer, } from "./layers/layers.js";
34
- export { Panoramas } from "./layers/panoramas.js";
34
+ export { Panoramas, } from "./layers/panoramas.js";
35
35
  export { photoModel } from "./layers/photos.js";
36
36
  export { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from "./layers/pointclouds.js";
37
37
  export { SymbolLayer } from "./layers/symbols.js";
38
38
  export { treeKind } from "./layers/trees.js";
39
39
  export { VectorLayer } from "./layers/vectors.js";
40
40
  export { GeoMap } from "./map.js";
41
- export { PANORAMAX_API, panoramaxPhoto, panoramaxPicture, panoramaxStyle, } from "./panoramax.js";
41
+ export { PANORAMAX_API, panoramaxPanoramas, panoramaxPhoto, panoramaxPicture, panoramaxSequence, panoramaxStyle, } from "./panoramax.js";
42
42
  export { AttributionControl, NavigationControl, } from "./ui/controls.js";
43
43
  export { MinimapControl } from "./ui/minimap.js";
44
44
  export { Marker, Panel, Popup, } from "./ui/overlay.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * isard: a WebGL2 map engine for large, interactive data layers, labels and 3D Tiles.\n *\n * ```ts\n * import { GeoMap } from 'isard';\n * const map = await GeoMap.create(container, { center: [2.4246, 48.8457], zoom: 13 });\n * const network = map.addNetwork({ nodes, edges, max: 1800, contour: 300 });\n * map.on('hover', ({ lonLat }) => lonLat && network.setValues(travelTimes(lonLat)));\n * map.addTiles3d({ url: 'https://…/tileset.json' });\n * map.addControl(new NavigationControl());\n * new Marker().setLonLat([2.4246, 48.8457]).setPopup(new Popup({ offset: [0, -34] }).setText('Here')).addTo(map);\n * ```\n */\nexport { OPENFREEMAP_ATTRIBUTION, TERRAIN_TILES_ATTRIBUTION } from './basemap/basemaps.ts';\nexport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nexport {\n PMTiles,\n type PmtilesEntry,\n type PmtilesHeader,\n type PmtilesTileType,\n tileIdToZxy,\n zxyToTileId,\n} from './basemap/pmtiles.ts';\nexport { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';\nexport { coniferModel, type TreeColors, treeModel } from './basemap/trees.ts';\nexport type {\n CandidateIcon,\n CandidateOverlap,\n Json,\n LabelCandidate,\n RasterSource,\n Style,\n StyleLayer,\n} from './basemap/vectorstyle.ts';\nexport type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';\nexport type { LabelsOptions } from './basemap/vectortiles/labels.ts';\nexport type { LampsOptions } from './basemap/vectortiles/lamps.ts';\nexport type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';\nexport type { LoadedStyle } from './basemap/vectortiles/style.ts';\nexport type { TreesOptions } from './basemap/vectortiles/trees.ts';\nexport type { VectorsOptions } from './basemap/vectortiles/vectors.ts';\nexport type { VectorTilesOptions } from './basemap/vectortiles.ts';\nexport { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';\nexport { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';\nexport { type ColladaImages, colladaImages, loadCollada, parseCollada } from './data/collada.ts';\nexport {\n type Crs,\n type CrsLike,\n getCrs,\n lambertConformalConic,\n registerCrs,\n reproject,\n transverseMercator,\n} from './data/crs.ts';\nexport { parseGpx } from './data/gpx.ts';\nexport {\n type IfcElement,\n type IfcModel,\n type IfcOptions,\n type IfcPlace,\n type IfcProperties,\n type IfcStorey,\n loadIfc,\n WEB_IFC,\n} from './data/ifc.ts';\nexport { parseKml } from './data/kml.ts';\nexport { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';\nexport type { DecoderUrls } from './engine/decoders.ts';\nexport { setRequestHeaders } from './engine/requests.ts';\nexport {\n BATIMENTS_3D_URL,\n type BdTopoBuilding,\n batiments3d,\n bdtopoBuildings,\n type GeocodedPlace,\n geoplateformeGeocode,\n geoplateformeWfs,\n geoplateformeWms,\n geoplateformeWmts,\n IGN_ATTRIBUTION,\n IGN_PRESETS,\n type IgnPreset,\n lambert93Grid,\n} from './geoplateforme.ts';\nexport { type Grid, windAt, windFields } from './grids.ts';\nexport type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';\nexport { ExtrusionLayer } from './layers/extrusions.ts';\nexport type {\n CircleOptions,\n CircleStyle,\n Feature,\n FeatureCollection,\n FeatureData,\n FeatureLayerStyle,\n FillOptions,\n FillStyle,\n Geometry,\n LineOptions,\n LineStyle,\n Placement,\n Position,\n Properties,\n Ramp,\n Size,\n Stops,\n Styled,\n} from './layers/features.ts';\nexport { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './layers/features.ts';\nexport type { FlowField, FlowOptions, FlowStyle, TimedField } from './layers/flow.ts';\nexport { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from './layers/flow.ts';\nexport type { TextPart } from './layers/glyphs.ts';\nexport { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';\nexport type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';\nexport type {\n CustomFrame,\n CustomLayerInterface,\n GroundOptions,\n GroundTexture,\n ModelInstance,\n ModelOptions,\n} from './layers/layers.ts';\nexport {\n CustomLayer,\n GroundLayer,\n Layer,\n ModelLayer,\n NetworkLayer,\n RasterLayer,\n Tiles3dLayer,\n} from './layers/layers.ts';\nexport { type Panorama, type PanoramaOptions, Panoramas } from './layers/panoramas.ts';\nexport { type PhotoOptions, photoModel } from './layers/photos.ts';\nexport type { ClassStyle, PointCloudOptions, PointCloudStyle, PointColor } from './layers/pointclouds.ts';\nexport { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from './layers/pointclouds.ts';\nexport type { Overlap, SymbolOptions, SymbolStyle } from './layers/symbols.ts';\nexport { SymbolLayer } from './layers/symbols.ts';\nexport { type TreeKind, type TreeOptions, treeKind } from './layers/trees.ts';\nexport { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';\nexport type { HoverPicking } from './map/hover-pick.ts';\nexport { GeoMap, type LayerSpec } from './map.ts';\nexport {\n PANORAMAX_API,\n type PanoramaxPicture,\n panoramaxPhoto,\n panoramaxPicture,\n panoramaxStyle,\n} from './panoramax.ts';\nexport type {\n AnimationOptions,\n AtmosphereOptions,\n Basemap,\n BasemapName,\n BodyOptions,\n CelestialBody,\n FeatureHit,\n FirstPersonView,\n FlyToOptions,\n GeoMapOptions,\n LoadingMode,\n LonLat,\n MapEvents,\n MapHoverFeatureEvent,\n MapPointerEvent,\n NetworkOptions,\n NetworkStyle,\n Point,\n Projection,\n RasterGrid,\n RasterOptions,\n RasterStyle,\n SunOptions,\n SwipeOptions,\n TerrainEncoding,\n TerrainModel,\n TerrainOptions,\n Tiles3dOptions,\n Tiles3dStyle,\n ViewshedOptions,\n} from './types.ts';\nexport {\n AttributionControl,\n type AttributionOptions,\n type Control,\n type ControlPosition,\n NavigationControl,\n type NavigationOptions,\n} from './ui/controls.ts';\nexport { MinimapControl, type MinimapOptions } from './ui/minimap.ts';\nexport {\n type Anchor,\n Marker,\n type MarkerEvent,\n type MarkerEvents,\n type MarkerOptions,\n Panel,\n type PanelOptions,\n Popup,\n type PopupEvents,\n type PopupOptions,\n} from './ui/overlay.ts';\nexport { lengthLabel, roundLength, ScaleControl, type ScaleOptions } from './ui/scale.ts';\nexport { SearchControl, type SearchOptions } from './ui/search.ts';\nexport { sunPosition } from './util/sun.ts';\nexport type {\n Camera,\n NetworkStats,\n PickHit,\n PickResult,\n PointCloudInfo,\n PointCloudPoint,\n PointCloudStats,\n RasterLayerStats,\n Tiles3dStats,\n} from './wasm/isard.js';\nexport type { RoofMode } from './workers/basemap/geometry.ts';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * isard: a WebGL2 map engine for large, interactive data layers, labels and 3D Tiles.\n *\n * ```ts\n * import { GeoMap } from 'isard';\n * const map = await GeoMap.create(container, { center: [2.4246, 48.8457], zoom: 13 });\n * const network = map.addNetwork({ nodes, edges, max: 1800, contour: 300 });\n * map.on('hover', ({ lonLat }) => lonLat && network.setValues(travelTimes(lonLat)));\n * map.addTiles3d({ url: 'https://…/tileset.json' });\n * map.addControl(new NavigationControl());\n * new Marker().setLonLat([2.4246, 48.8457]).setPopup(new Popup({ offset: [0, -34] }).setText('Here')).addTo(map);\n * ```\n */\nexport { OPENFREEMAP_ATTRIBUTION, TERRAIN_TILES_ATTRIBUTION } from './basemap/basemaps.ts';\nexport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nexport {\n PMTiles,\n type PmtilesEntry,\n type PmtilesHeader,\n type PmtilesTileType,\n tileIdToZxy,\n zxyToTileId,\n} from './basemap/pmtiles.ts';\nexport { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';\nexport { coniferModel, type TreeColors, treeModel } from './basemap/trees.ts';\nexport type {\n CandidateIcon,\n CandidateOverlap,\n Json,\n LabelCandidate,\n RasterSource,\n Style,\n StyleLayer,\n} from './basemap/vectorstyle.ts';\nexport type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';\nexport type { FurnitureOptions } from './basemap/vectortiles/furniture.ts';\nexport type { LabelsOptions } from './basemap/vectortiles/labels.ts';\nexport type { LampsOptions } from './basemap/vectortiles/lamps.ts';\nexport type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';\nexport type { LoadedStyle } from './basemap/vectortiles/style.ts';\nexport type { TreesOptions } from './basemap/vectortiles/trees.ts';\nexport type { VectorsOptions } from './basemap/vectortiles/vectors.ts';\nexport type { VectorTilesOptions } from './basemap/vectortiles.ts';\nexport { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';\nexport { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';\nexport { type ColladaImages, colladaImages, loadCollada, parseCollada } from './data/collada.ts';\nexport {\n type Crs,\n type CrsLike,\n getCrs,\n lambertConformalConic,\n registerCrs,\n reproject,\n transverseMercator,\n} from './data/crs.ts';\nexport { parseGpx } from './data/gpx.ts';\nexport {\n type IfcElement,\n type IfcModel,\n type IfcOptions,\n type IfcPlace,\n type IfcProperties,\n type IfcStorey,\n loadIfc,\n WEB_IFC,\n} from './data/ifc.ts';\nexport { parseKml } from './data/kml.ts';\nexport { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';\nexport type { DecoderUrls } from './engine/decoders.ts';\nexport { setRequestHeaders } from './engine/requests.ts';\nexport {\n BATIMENTS_3D_URL,\n type BdTopoBuilding,\n batiments3d,\n bdtopoBuildings,\n bdtopoRoofs,\n type GeocodedPlace,\n geoplateformeGeocode,\n geoplateformeWfs,\n geoplateformeWms,\n geoplateformeWmts,\n IGN_ATTRIBUTION,\n IGN_PRESETS,\n type IgnPreset,\n lambert93Grid,\n} from './geoplateforme.ts';\nexport { type Grid, windAt, windFields } from './grids.ts';\nexport type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';\nexport { ExtrusionLayer } from './layers/extrusions.ts';\nexport type {\n CircleOptions,\n CircleStyle,\n Feature,\n FeatureCollection,\n FeatureData,\n FeatureLayerStyle,\n FillOptions,\n FillStyle,\n Geometry,\n LineOptions,\n LineStyle,\n Placement,\n Position,\n Properties,\n Ramp,\n Size,\n Stops,\n Styled,\n} from './layers/features.ts';\nexport { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './layers/features.ts';\nexport type { FlowField, FlowOptions, FlowStyle, TimedField } from './layers/flow.ts';\nexport { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from './layers/flow.ts';\nexport type { TextPart } from './layers/glyphs.ts';\nexport { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';\nexport type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';\nexport type {\n CustomFrame,\n CustomLayerInterface,\n GroundOptions,\n GroundTexture,\n ModelInstance,\n ModelOptions,\n} from './layers/layers.ts';\nexport {\n CustomLayer,\n GroundLayer,\n Layer,\n ModelLayer,\n NetworkLayer,\n RasterLayer,\n Tiles3dLayer,\n} from './layers/layers.ts';\nexport {\n type CalibratedPanoramaOptions,\n type Panorama,\n type PanoramaOptions,\n type PanoramaPhoto,\n Panoramas,\n type PhotoPanoramaOptions,\n} from './layers/panoramas.ts';\nexport { type PhotoOptions, photoModel } from './layers/photos.ts';\nexport type { ClassStyle, PointCloudOptions, PointCloudStyle, PointColor } from './layers/pointclouds.ts';\nexport { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from './layers/pointclouds.ts';\nexport type { Overlap, SymbolOptions, SymbolStyle } from './layers/symbols.ts';\nexport { SymbolLayer } from './layers/symbols.ts';\nexport { type TreeKind, type TreeOptions, treeKind } from './layers/trees.ts';\nexport { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';\nexport type { HoverPicking } from './map/hover-pick.ts';\nexport { GeoMap, type LayerSpec } from './map.ts';\nexport {\n PANORAMAX_API,\n type PanoramaxPicture,\n type PanoramaxSequenceOptions,\n panoramaxPanoramas,\n panoramaxPhoto,\n panoramaxPicture,\n panoramaxSequence,\n panoramaxStyle,\n} from './panoramax.ts';\nexport type {\n AnimationOptions,\n AtmosphereOptions,\n Basemap,\n BasemapName,\n BodyOptions,\n CelestialBody,\n FeatureHit,\n FirstPersonView,\n FlyToOptions,\n GeoMapOptions,\n LoadingMode,\n LonLat,\n MapEvents,\n MapHoverFeatureEvent,\n MapPointerEvent,\n NetworkOptions,\n NetworkStyle,\n Point,\n Projection,\n RasterGrid,\n RasterOptions,\n RasterStyle,\n SunOptions,\n SwipeOptions,\n TerrainEncoding,\n TerrainModel,\n TerrainOptions,\n Tiles3dOptions,\n Tiles3dStyle,\n ViewshedOptions,\n} from './types.ts';\nexport {\n AttributionControl,\n type AttributionOptions,\n type Control,\n type ControlPosition,\n NavigationControl,\n type NavigationOptions,\n} from './ui/controls.ts';\nexport { MinimapControl, type MinimapOptions } from './ui/minimap.ts';\nexport {\n type Anchor,\n Marker,\n type MarkerEvent,\n type MarkerEvents,\n type MarkerOptions,\n Panel,\n type PanelOptions,\n Popup,\n type PopupEvents,\n type PopupOptions,\n} from './ui/overlay.ts';\nexport { lengthLabel, roundLength, ScaleControl, type ScaleOptions } from './ui/scale.ts';\nexport { SearchControl, type SearchOptions } from './ui/search.ts';\nexport type { RoofMode } from './util/roofs.ts';\nexport { sunPosition } from './util/sun.ts';\nexport type {\n Camera,\n NetworkStats,\n PickHit,\n PickResult,\n PointCloudInfo,\n PointCloudPoint,\n PointCloudStats,\n RasterLayerStats,\n Tiles3dStats,\n} from './wasm/isard.js';\n"]}
Binary file
Binary file
Binary file
Binary file
@@ -5,7 +5,8 @@
5
5
  * the node values of a network layer (`linkNetwork`: the travel time to each building, recolored with the network).
6
6
  */
7
7
  import { metresAt, roofNumber } from "../util/roofs.js";
8
- import { evaluate, FLOATS, featuresOf, parseColor, polygonGeometry, rampTexels, stops, } from "./features.js";
8
+ import { FLOATS, STYLE } from "../util/style-floats.js";
9
+ import { evaluate, featuresOf, parseColor, polygonGeometry, rampTexels, stops, } from "./features.js";
9
10
  import { Layer } from "./layers.js";
10
11
  /** TileKey of the set given as `data` */
11
12
  const DATA = Symbol('data');
@@ -196,9 +197,9 @@ export class ExtrusionLayer extends Layer {
196
197
  const fixed = typeof color === 'string' ? parseColor(color) : undefined;
197
198
  tile.properties.forEach((p, i) => {
198
199
  const o = i * FLOATS;
199
- out.set(fixed ?? parseColor(evaluate(color, p, i)), o);
200
- out.set(stops(evaluate(height, p, i)), o + 8);
201
- out.set(stops(evaluate(base, p, i)), o + 16);
200
+ out.set(fixed ?? parseColor(evaluate(color, p, i)), o + STYLE.color);
201
+ out.set(stops(evaluate(height, p, i)), o + STYLE.size);
202
+ out.set(stops(evaluate(base, p, i)), o + STYLE.size2);
202
203
  });
203
204
  engine.setFeatureStyle(id, out, tile.batch);
204
205
  engine.setFeatureMask(id, this.mask(tile), tile.batch);