@expofp/renderer 0.0.0-experimental.2d6c681
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -0
- package/dist/Renderer.d.ts +102 -0
- package/dist/Renderer.js +96 -0
- package/dist/controls/CameraControls.d.ts +108 -0
- package/dist/controls/CameraControls.js +203 -0
- package/dist/controls/Controls.d.ts +53 -0
- package/dist/controls/Controls.js +54 -0
- package/dist/controls/camera-api.d.ts +226 -0
- package/dist/controls/camera-api.js +179 -0
- package/dist/controls/gestures.d.ts +71 -0
- package/dist/controls/gestures.js +98 -0
- package/dist/controls/handlers/DoubleTapZoom.d.ts +23 -0
- package/dist/controls/handlers/DoubleTapZoom.js +82 -0
- package/dist/controls/handlers/Inertia.d.ts +60 -0
- package/dist/controls/handlers/Inertia.js +222 -0
- package/dist/controls/handlers/Pan.d.ts +23 -0
- package/dist/controls/handlers/Pan.js +212 -0
- package/dist/controls/handlers/Pitch.d.ts +19 -0
- package/dist/controls/handlers/Pitch.js +200 -0
- package/dist/controls/handlers/Roll.d.ts +30 -0
- package/dist/controls/handlers/Roll.js +196 -0
- package/dist/controls/handlers/Zoom.d.ts +28 -0
- package/dist/controls/handlers/Zoom.js +34 -0
- package/dist/controls/hooks.d.ts +136 -0
- package/dist/controls/hooks.js +200 -0
- package/dist/controls/index.d.ts +9 -0
- package/dist/controls/index.js +7 -0
- package/dist/controls/zoom-to.d.ts +89 -0
- package/dist/controls/zoom-to.js +91 -0
- package/dist/core/InstanceUniforms.d.ts +108 -0
- package/dist/core/InstanceUniforms.js +298 -0
- package/dist/core/SquareDataTexture.d.ts +277 -0
- package/dist/core/SquareDataTexture.js +476 -0
- package/dist/core/batch/BatchedMesh.d.ts +74 -0
- package/dist/core/batch/BatchedMesh.js +155 -0
- package/dist/core/instanced/FrustumCulling.d.ts +141 -0
- package/dist/core/instanced/FrustumCulling.js +246 -0
- package/dist/core/instanced/InstancedMesh.d.ts +302 -0
- package/dist/core/instanced/InstancedMesh.js +497 -0
- package/dist/core/instanced/Instances.d.ts +119 -0
- package/dist/core/instanced/Instances.js +230 -0
- package/dist/core/instanced/Raycasting.d.ts +118 -0
- package/dist/core/instanced/Raycasting.js +134 -0
- package/dist/core/instanced/instanced-material.d.ts +77 -0
- package/dist/core/instanced/instanced-material.js +228 -0
- package/dist/core/lines/BatchedLines.d.ts +137 -0
- package/dist/core/lines/BatchedLines.js +215 -0
- package/dist/core/lines/FrustumCullingLines.d.ts +44 -0
- package/dist/core/lines/FrustumCullingLines.js +85 -0
- package/dist/core/lines/RaycastingLines.d.ts +45 -0
- package/dist/core/lines/RaycastingLines.js +91 -0
- package/dist/core/lines/lines-material.d.ts +47 -0
- package/dist/core/lines/lines-material.js +124 -0
- package/dist/core/shader-source.d.ts +70 -0
- package/dist/core/shader-source.js +110 -0
- package/dist/core/sprites/BatchedSprites.d.ts +115 -0
- package/dist/core/sprites/BatchedSprites.js +173 -0
- package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
- package/dist/core/sprites/RaycastingSprites.js +71 -0
- package/dist/core/sprites/sprite-material.d.ts +59 -0
- package/dist/core/sprites/sprite-material.js +192 -0
- package/dist/core/text/BatchedText.d.ts +233 -0
- package/dist/core/text/BatchedText.js +473 -0
- package/dist/core/text/MemberTexture.d.ts +90 -0
- package/dist/core/text/MemberTexture.js +289 -0
- package/dist/core/text/Text.d.ts +88 -0
- package/dist/core/text/Text.js +230 -0
- package/dist/core/text/batched-text-material.d.ts +56 -0
- package/dist/core/text/batched-text-material.js +123 -0
- package/dist/core/text/glyph-packing.d.ts +17 -0
- package/dist/core/text/glyph-packing.js +61 -0
- package/dist/core/typed-array.d.ts +16 -0
- package/dist/core/typed-array.js +20 -0
- package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
- package/dist/debug/components/DebugPanelProvider.js +50 -0
- package/dist/debug/components/DebugTools.d.ts +22 -0
- package/dist/debug/components/DebugTools.js +28 -0
- package/dist/debug/components/Gui.d.ts +22 -0
- package/dist/debug/components/Gui.js +42 -0
- package/dist/debug/components/MemoryInfo.d.ts +22 -0
- package/dist/debug/components/MemoryInfo.js +42 -0
- package/dist/debug/components/Panel.d.ts +31 -0
- package/dist/debug/components/Panel.js +104 -0
- package/dist/debug/components/Stats.d.ts +9 -0
- package/dist/debug/components/Stats.js +24 -0
- package/dist/debug/debug-chunk.d.ts +26 -0
- package/dist/debug/debug-chunk.js +32 -0
- package/dist/debug/debug-context.d.ts +41 -0
- package/dist/debug/debug-context.js +59 -0
- package/dist/debug/index.d.ts +41 -0
- package/dist/debug/index.js +43 -0
- package/dist/events/LayoutDriver.d.ts +36 -0
- package/dist/events/LayoutDriver.js +192 -0
- package/dist/events/PointerMissed.d.ts +23 -0
- package/dist/events/PointerMissed.js +58 -0
- package/dist/events/def-culling.d.ts +46 -0
- package/dist/events/def-culling.js +69 -0
- package/dist/events/layout-targets.d.ts +151 -0
- package/dist/events/layout-targets.js +397 -0
- package/dist/events/placement/box.d.ts +59 -0
- package/dist/events/placement/box.js +96 -0
- package/dist/events/placement/grid.d.ts +161 -0
- package/dist/events/placement/grid.js +235 -0
- package/dist/events/placement/index.d.ts +2 -0
- package/dist/events/placement/index.js +1 -0
- package/dist/events/placement/pass.d.ts +70 -0
- package/dist/events/placement/pass.js +617 -0
- package/dist/events/pointer.d.ts +194 -0
- package/dist/events/pointer.js +356 -0
- package/dist/external/ExternalCanvas.d.ts +56 -0
- package/dist/external/ExternalCanvas.js +177 -0
- package/dist/external/external-camera.d.ts +18 -0
- package/dist/external/external-camera.js +103 -0
- package/dist/external/external-events.d.ts +14 -0
- package/dist/external/external-events.js +33 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/objects/Background.d.ts +31 -0
- package/dist/objects/Background.js +37 -0
- package/dist/objects/containers/SlotContainer.d.ts +312 -0
- package/dist/objects/containers/SlotContainer.js +311 -0
- package/dist/objects/containers/hooks.d.ts +61 -0
- package/dist/objects/containers/hooks.js +196 -0
- package/dist/objects/containers/index.d.ts +6 -0
- package/dist/objects/containers/index.js +4 -0
- package/dist/objects/containers/keys.d.ts +10 -0
- package/dist/objects/containers/keys.js +18 -0
- package/dist/objects/containers/mesh-writes.d.ts +106 -0
- package/dist/objects/containers/mesh-writes.js +97 -0
- package/dist/objects/containers/props.d.ts +33 -0
- package/dist/objects/containers/props.js +1 -0
- package/dist/objects/images/ImageInstance.d.ts +29 -0
- package/dist/objects/images/ImageInstance.js +152 -0
- package/dist/objects/images/Images.d.ts +49 -0
- package/dist/objects/images/Images.js +394 -0
- package/dist/objects/images/atlas-packer.d.ts +129 -0
- package/dist/objects/images/atlas-packer.js +287 -0
- package/dist/objects/images/image-container.d.ts +74 -0
- package/dist/objects/images/image-container.js +100 -0
- package/dist/objects/images/index.d.ts +2 -0
- package/dist/objects/images/index.js +1 -0
- package/dist/objects/images/pack-sources.d.ts +190 -0
- package/dist/objects/images/pack-sources.js +272 -0
- package/dist/objects/images/texture-budget.d.ts +120 -0
- package/dist/objects/images/texture-budget.js +215 -0
- package/dist/objects/images/worker/atlas-worker.d.ts +56 -0
- package/dist/objects/images/worker/atlas-worker.js +123 -0
- package/dist/objects/images/worker/client.d.ts +62 -0
- package/dist/objects/images/worker/client.js +249 -0
- package/dist/objects/images/worker/index.d.ts +10 -0
- package/dist/objects/images/worker/index.js +1 -0
- package/dist/objects/layer/Layer.d.ts +28 -0
- package/dist/objects/layer/Layer.js +134 -0
- package/dist/objects/layer/index.d.ts +2 -0
- package/dist/objects/layer/index.js +1 -0
- package/dist/objects/layer/layer-context.d.ts +74 -0
- package/dist/objects/layer/layer-context.js +82 -0
- package/dist/objects/layer/mount-scheduler.d.ts +131 -0
- package/dist/objects/layer/mount-scheduler.js +289 -0
- package/dist/objects/layer/visibility-gui.d.ts +19 -0
- package/dist/objects/layer/visibility-gui.js +93 -0
- package/dist/objects/lighting/Lighting.d.ts +92 -0
- package/dist/objects/lighting/Lighting.js +384 -0
- package/dist/objects/lighting/OcclusionPasses.d.ts +23 -0
- package/dist/objects/lighting/OcclusionPasses.js +271 -0
- package/dist/objects/lighting/index.d.ts +11 -0
- package/dist/objects/lighting/index.js +10 -0
- package/dist/objects/lighting/lighting-gui.d.ts +24 -0
- package/dist/objects/lighting/lighting-gui.js +114 -0
- package/dist/objects/lighting/occluder.d.ts +34 -0
- package/dist/objects/lighting/occluder.js +62 -0
- package/dist/objects/lighting/occlusion-targets.d.ts +143 -0
- package/dist/objects/lighting/occlusion-targets.js +276 -0
- package/dist/objects/lines/LineInstance.d.ts +21 -0
- package/dist/objects/lines/LineInstance.js +73 -0
- package/dist/objects/lines/Lines.d.ts +17 -0
- package/dist/objects/lines/Lines.js +31 -0
- package/dist/objects/lines/index.d.ts +2 -0
- package/dist/objects/lines/index.js +1 -0
- package/dist/objects/lines/line-container.d.ts +35 -0
- package/dist/objects/lines/line-container.js +40 -0
- package/dist/objects/materials/ColorMaterial.d.ts +92 -0
- package/dist/objects/materials/ColorMaterial.js +124 -0
- package/dist/objects/materials/LineMaterial.d.ts +44 -0
- package/dist/objects/materials/LineMaterial.js +74 -0
- package/dist/objects/materials/ModelMaterial.d.ts +53 -0
- package/dist/objects/materials/ModelMaterial.js +111 -0
- package/dist/objects/materials/TextureMaterial.d.ts +33 -0
- package/dist/objects/materials/TextureMaterial.js +48 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-pass.d.ts +77 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-pass.js +296 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-patch.d.ts +29 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-patch.js +115 -0
- package/dist/objects/materials/effects/ao/blur-pass.d.ts +61 -0
- package/dist/objects/materials/effects/ao/blur-pass.js +101 -0
- package/dist/objects/materials/effects/ao/index.d.ts +129 -0
- package/dist/objects/materials/effects/ao/index.js +72 -0
- package/dist/objects/materials/effects/color-dim.d.ts +115 -0
- package/dist/objects/materials/effects/color-dim.js +206 -0
- package/dist/objects/materials/effects/contact-shadow.d.ts +100 -0
- package/dist/objects/materials/effects/contact-shadow.js +167 -0
- package/dist/objects/materials/effects/effects-context.d.ts +53 -0
- package/dist/objects/materials/effects/effects-context.js +24 -0
- package/dist/objects/materials/shared.d.ts +24 -0
- package/dist/objects/materials/shared.js +72 -0
- package/dist/objects/models/ModelInstance.d.ts +22 -0
- package/dist/objects/models/ModelInstance.js +33 -0
- package/dist/objects/models/Models.d.ts +22 -0
- package/dist/objects/models/Models.js +186 -0
- package/dist/objects/models/gltf-cache.d.ts +17 -0
- package/dist/objects/models/gltf-cache.js +50 -0
- package/dist/objects/models/index.d.ts +2 -0
- package/dist/objects/models/index.js +1 -0
- package/dist/objects/models/model-asset.d.ts +48 -0
- package/dist/objects/models/model-asset.js +77 -0
- package/dist/objects/models/model-container.d.ts +123 -0
- package/dist/objects/models/model-container.js +207 -0
- package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
- package/dist/objects/shapes/ShapeInstance.js +39 -0
- package/dist/objects/shapes/Shapes.d.ts +21 -0
- package/dist/objects/shapes/Shapes.js +131 -0
- package/dist/objects/shapes/index.d.ts +2 -0
- package/dist/objects/shapes/index.js +1 -0
- package/dist/objects/shapes/shape-container.d.ts +141 -0
- package/dist/objects/shapes/shape-container.js +242 -0
- package/dist/objects/shapes/shape-geometry.d.ts +27 -0
- package/dist/objects/shapes/shape-geometry.js +94 -0
- package/dist/objects/text/TextInstance.d.ts +22 -0
- package/dist/objects/text/TextInstance.js +95 -0
- package/dist/objects/text/Texts.d.ts +30 -0
- package/dist/objects/text/Texts.js +43 -0
- package/dist/objects/text/index.d.ts +2 -0
- package/dist/objects/text/index.js +1 -0
- package/dist/objects/text/text-container.d.ts +121 -0
- package/dist/objects/text/text-container.js +229 -0
- package/dist/objects/text/text-layout.d.ts +92 -0
- package/dist/objects/text/text-layout.js +180 -0
- package/dist/space/Camera.d.ts +103 -0
- package/dist/space/Camera.js +321 -0
- package/dist/space/Scene.d.ts +47 -0
- package/dist/space/Scene.js +127 -0
- package/dist/space/Space.d.ts +325 -0
- package/dist/space/Space.js +359 -0
- package/dist/space/VisibleRect.d.ts +45 -0
- package/dist/space/VisibleRect.js +129 -0
- package/dist/space/camera-handle.d.ts +67 -0
- package/dist/space/camera-handle.js +63 -0
- package/dist/space/camera-kind.d.ts +26 -0
- package/dist/space/camera-kind.js +30 -0
- package/dist/space/canvas-size.d.ts +24 -0
- package/dist/space/canvas-size.js +20 -0
- package/dist/space/clipping.d.ts +69 -0
- package/dist/space/clipping.js +130 -0
- package/dist/space/layout-measure.d.ts +67 -0
- package/dist/space/layout-measure.js +175 -0
- package/dist/space/viewport.d.ts +112 -0
- package/dist/space/viewport.js +67 -0
- package/dist/types/defs.d.ts +234 -0
- package/dist/types/defs.js +1 -0
- package/dist/types/events.d.ts +198 -0
- package/dist/types/events.js +1 -0
- package/dist/types/guards.d.ts +21 -0
- package/dist/types/guards.js +52 -0
- package/dist/update/index.d.ts +3 -0
- package/dist/update/index.js +2 -0
- package/dist/update/slot-writers.d.ts +30 -0
- package/dist/update/slot-writers.js +76 -0
- package/dist/update/store.d.ts +41 -0
- package/dist/update/store.js +104 -0
- package/dist/utils/arrays.d.ts +13 -0
- package/dist/utils/arrays.js +20 -0
- package/dist/utils/colors.d.ts +19 -0
- package/dist/utils/colors.js +27 -0
- package/dist/utils/hot-state.d.ts +41 -0
- package/dist/utils/hot-state.js +37 -0
- package/dist/utils/logging.d.ts +29 -0
- package/dist/utils/logging.js +55 -0
- package/dist/utils/math.d.ts +52 -0
- package/dist/utils/math.js +76 -0
- package/package.json +79 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Box, Point, pointRotate, Rect, rectBounds } from '@expofp/geometry';
|
|
2
|
+
import { isImageDef } from '../../types/guards';
|
|
3
|
+
/**
|
|
4
|
+
* The screen rectangle one def occupies, in CSS pixels from the canvas's top-left corner.
|
|
5
|
+
*
|
|
6
|
+
* There is one path, because only a screen-space def is ever tested. Its anchor projects through
|
|
7
|
+
* the camera, and its extent comes from the pixel size rather than from the projection: constant
|
|
8
|
+
* pixel size means a sprite is the same number of pixels across at every depth, so the only
|
|
9
|
+
* camera-dependent term is where the anchor lands.
|
|
10
|
+
*
|
|
11
|
+
* `origin` shifts the rectangle relative to the anchor exactly as it shifts the quad, in the
|
|
12
|
+
* plan's y-down sense, which is also the canvas's. A bottom-center origin therefore puts the
|
|
13
|
+
* anchor on the rectangle's bottom edge and the rectangle above it.
|
|
14
|
+
*
|
|
15
|
+
* This is the def's own extent, without its `placement.padding`: that is what the grid stores, and
|
|
16
|
+
* {@link paddedBox} grows it into the box that is tested. Storing the grown box as well would make
|
|
17
|
+
* two padded defs keep twice the padding apart.
|
|
18
|
+
* @param def - The def to measure.
|
|
19
|
+
* @param space - The scene's space, for the projection.
|
|
20
|
+
* @param camera - The camera in use.
|
|
21
|
+
* @param pixelSize - Plan units per CSS pixel.
|
|
22
|
+
* @param out - The box to write into, reused across a pass.
|
|
23
|
+
* @returns The box, or nothing when the def has no extent or its anchor does not project.
|
|
24
|
+
*/
|
|
25
|
+
export function screenBoxOf(def, space, camera, pixelSize, out) {
|
|
26
|
+
const scale = pixelSize;
|
|
27
|
+
if (!Number.isFinite(scale) || scale <= 0)
|
|
28
|
+
return undefined;
|
|
29
|
+
const bounds = def.bounds;
|
|
30
|
+
const origin = isImageDef(def) ? def.origin : undefined;
|
|
31
|
+
return spriteBoxAt(bounds.center.x, bounds.center.y, bounds.elevation, bounds.size.x / scale, bounds.size.y / scale, origin, bounds.rotation, space, camera, out);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The screen rectangle a constant-pixel-size sprite occupies when its anchor stands at a plan
|
|
35
|
+
* point, in CSS pixels from the canvas's top-left corner.
|
|
36
|
+
*
|
|
37
|
+
* What {@link screenBoxOf} measures a def with, taken apart so that a box can stand at an anchor
|
|
38
|
+
* that is not a def's own: a cluster's marker stands at the mean of its units' anchors.
|
|
39
|
+
* @param x - The anchor's plan x.
|
|
40
|
+
* @param y - The anchor's plan y.
|
|
41
|
+
* @param elevation - The anchor's elevation, in plan units.
|
|
42
|
+
* @param width - The sprite's width in CSS pixels.
|
|
43
|
+
* @param height - The sprite's height in CSS pixels.
|
|
44
|
+
* @param origin - Which point of the sprite stands on the anchor, centered when omitted.
|
|
45
|
+
* @param rotation - Its spin about the screen normal, in radians.
|
|
46
|
+
* @param space - The scene's space, for the projection.
|
|
47
|
+
* @param camera - The camera in use.
|
|
48
|
+
* @param out - The box to write into.
|
|
49
|
+
* @returns The box, or nothing when the sprite has no extent or its anchor does not project.
|
|
50
|
+
*/
|
|
51
|
+
export function spriteBoxAt(x, y, elevation, width, height, origin, rotation, space, camera, out) {
|
|
52
|
+
if (!(width > 0) || !(height > 0))
|
|
53
|
+
return undefined;
|
|
54
|
+
const screen = space.planToCanvas(_anchor.set(x, y, elevation), camera, _screen);
|
|
55
|
+
if (!screen || !Number.isFinite(screen.x) || !Number.isFinite(screen.y))
|
|
56
|
+
return undefined;
|
|
57
|
+
// The sprite's center sits off the anchor by `origin`, and turns with the sprite about it.
|
|
58
|
+
_offset.set((0.5 - (origin?.[0] ?? 0.5)) * width, (0.5 - (origin?.[1] ?? 0.5)) * height);
|
|
59
|
+
pointRotate(_offset, rotation, ZERO, _offset);
|
|
60
|
+
_rect.set(screen.x + _offset.x, screen.y + _offset.y, width, height, rotation, 0);
|
|
61
|
+
const { min, max } = rectBounds(_rect, _bounds);
|
|
62
|
+
out.minX = min.x;
|
|
63
|
+
out.maxX = max.x;
|
|
64
|
+
out.minY = min.y;
|
|
65
|
+
out.maxY = max.y;
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The box a def is tested with: its extent grown by `placement.padding`, by one number on all four
|
|
70
|
+
* sides or by a `[horizontal, vertical]` pair.
|
|
71
|
+
*
|
|
72
|
+
* The grid stores the extent and tests this, so each def's padding applies once, on the side that is
|
|
73
|
+
* testing. A def with no padding gets a copy of its extent.
|
|
74
|
+
* @param def - The def whose padding grows the box.
|
|
75
|
+
* @param box - The def's extent, from {@link screenBoxOf}.
|
|
76
|
+
* @param out - The box to write into, which may be `box` itself.
|
|
77
|
+
* @returns `out`.
|
|
78
|
+
*/
|
|
79
|
+
export function paddedBox(def, box, out) {
|
|
80
|
+
const padding = def.placement?.padding ?? 0;
|
|
81
|
+
const padX = typeof padding === 'number' ? padding : padding[0];
|
|
82
|
+
const padY = typeof padding === 'number' ? padding : padding[1];
|
|
83
|
+
out.minX = box.minX - padX;
|
|
84
|
+
out.maxX = box.maxX + padX;
|
|
85
|
+
out.minY = box.minY - padY;
|
|
86
|
+
out.maxY = box.maxY + padY;
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
/** The point a sprite's center offset turns about. */
|
|
90
|
+
const ZERO = { x: 0, y: 0 };
|
|
91
|
+
// Scratch, each filled and consumed within one synchronous call.
|
|
92
|
+
const _anchor = new Point();
|
|
93
|
+
const _screen = new Point();
|
|
94
|
+
const _offset = new Point();
|
|
95
|
+
const _rect = new Rect({ x: 0, y: 0 }, { x: 0, y: 0 });
|
|
96
|
+
const _bounds = new Box();
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { type OverlapMode } from '../../types/defs';
|
|
2
|
+
/** A rectangle in CSS pixels from the canvas's top-left corner, as the placement pass tests it. */
|
|
3
|
+
export interface PlacementBox {
|
|
4
|
+
/** The left edge. */
|
|
5
|
+
minX: number;
|
|
6
|
+
/** The top edge. */
|
|
7
|
+
minY: number;
|
|
8
|
+
/** The right edge. */
|
|
9
|
+
maxX: number;
|
|
10
|
+
/** The bottom edge. */
|
|
11
|
+
maxY: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Whether a def in mode `a` is allowed to cover one already placed in mode `b`.
|
|
15
|
+
*
|
|
16
|
+
* Ported from maplibre's `overlapAllowed` in `src/symbol/grid_index.ts`. With two modes the rule
|
|
17
|
+
* reduces to `a === 'always'`, and this stays as the one place it is written.
|
|
18
|
+
*
|
|
19
|
+
* The `_b` parameter is unused: an `always` entry is never inserted into the grid, so the mode of
|
|
20
|
+
* the def already there is always `never`. Re-adding a third mode brings it back.
|
|
21
|
+
* @param a - The mode of the def being tested.
|
|
22
|
+
* @param _b - The mode of the def already in the grid. Unused, see above.
|
|
23
|
+
* @returns Whether the overlap is allowed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function overlapAllowed(a: OverlapMode, _b: OverlapMode): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether two boxes overlap, by the rule {@link PlacementGrid.blockerOf} applies: edge contact is
|
|
28
|
+
* clear, so two boxes sharing a border do not overlap.
|
|
29
|
+
* @param a - One box.
|
|
30
|
+
* @param b - The other.
|
|
31
|
+
* @returns Whether they overlap.
|
|
32
|
+
*/
|
|
33
|
+
export declare function overlaps(a: PlacementBox, b: PlacementBox): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* A uniform-cell index of screen rectangles, which answers which rectangle already in it, if any,
|
|
36
|
+
* blocks a new one.
|
|
37
|
+
*
|
|
38
|
+
* Modeled on maplibre's `GridIndex`, without the circle half. Circles exist there for labels that
|
|
39
|
+
* follow a curved line, which this renderer does not draw. Entries live in flat arrays that a reset
|
|
40
|
+
* keeps at their length and refills from the front under a count cursor: setting `length = 0`
|
|
41
|
+
* instead lets V8 trim the backing store, so every pass would grow it again through its doublings.
|
|
42
|
+
* The per-cell id lists are short and are still cleared with `length = 0`, but only the cells an
|
|
43
|
+
* entry was filed under: a pass resets the grid once per collision scope, and every registered
|
|
44
|
+
* layer is a scope, most of them with no participant at all. Clearing all 1820 cells of a 1440 by
|
|
45
|
+
* 900 canvas for each of imexamerica25-3d's 21 scopes was 0.9–1.2 ms of a 1.1–1.4 ms pass.
|
|
46
|
+
*
|
|
47
|
+
* The index covers the canvas plus {@link GRID_MARGIN_PX} on every side, so a def crossing the
|
|
48
|
+
* edge of the screen decides off screen, where the churn is invisible.
|
|
49
|
+
*/
|
|
50
|
+
export declare class PlacementGrid {
|
|
51
|
+
/** Each cell's entry ids. Index is `y * xCells + x`. */
|
|
52
|
+
private cells;
|
|
53
|
+
/** The index of every cell that holds an entry since the last reset, which is all it clears. */
|
|
54
|
+
private readonly filled;
|
|
55
|
+
/**
|
|
56
|
+
* Four numbers per entry: `minX`, `minY`, `maxX`, `maxY`. Only the first `count * 4` are live; the
|
|
57
|
+
* rest are the last pass's, kept so the next pass overwrites them in place.
|
|
58
|
+
*/
|
|
59
|
+
private readonly boxes;
|
|
60
|
+
/** One mode per entry, parallel to {@link boxes} and live up to `count` in the same way. */
|
|
61
|
+
private readonly modes;
|
|
62
|
+
private count;
|
|
63
|
+
private xCells;
|
|
64
|
+
private yCells;
|
|
65
|
+
/** The canvas width the cells were built for. `-1` until the first `reset`, so it always rebuilds. */
|
|
66
|
+
private width;
|
|
67
|
+
/** The canvas height the cells were built for. `-1` until the first `reset`, so it always rebuilds. */
|
|
68
|
+
private height;
|
|
69
|
+
/**
|
|
70
|
+
* @param width - The canvas width in CSS pixels.
|
|
71
|
+
* @param height - The canvas height in CSS pixels.
|
|
72
|
+
*/
|
|
73
|
+
constructor(width: number, height: number);
|
|
74
|
+
/**
|
|
75
|
+
* Empties the index and sizes it for a canvas, which is what every pass starts with.
|
|
76
|
+
*
|
|
77
|
+
* The cell array is rebuilt only when the canvas size changed, so an unresized canvas pays only
|
|
78
|
+
* for clearing the cells the last fill used.
|
|
79
|
+
* @param width - The canvas width in CSS pixels.
|
|
80
|
+
* @param height - The canvas height in CSS pixels.
|
|
81
|
+
*/
|
|
82
|
+
reset(width: number, height: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the box intersects the indexed area, which is the canvas plus its margin. A box that
|
|
85
|
+
* only partly overlaps it passes; only one wholly outside fails.
|
|
86
|
+
*
|
|
87
|
+
* A box wholly outside it is not placed and not inserted. That is a correctness rule rather than a
|
|
88
|
+
* priority one: the index cannot hold it, so it cannot be tested against later defs either.
|
|
89
|
+
* @param box - The box to test.
|
|
90
|
+
* @returns Whether the index covers it.
|
|
91
|
+
*/
|
|
92
|
+
intersects(box: PlacementBox): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* The earliest-inserted entry that blocks this box, or nothing when it is clear.
|
|
95
|
+
*
|
|
96
|
+
* **Earliest, not first found.** The cell walk reaches a box filed under a later cell before one
|
|
97
|
+
* filed under an earlier cell, so returning the first match would make the answer depend on cell
|
|
98
|
+
* iteration order — and the answer is load-bearing: in a clustering scope the blocker is the
|
|
99
|
+
* cluster's seed, and first come, first served means the earliest. Scanning every cell the box
|
|
100
|
+
* touches costs the early exit a boolean test could take, against a few hundred entries in a
|
|
101
|
+
* handful of cells.
|
|
102
|
+
*
|
|
103
|
+
* Edge contact does not block: two boxes sharing a border are treated as clear, so a row of
|
|
104
|
+
* abutting labels is placeable.
|
|
105
|
+
*
|
|
106
|
+
* Test {@link intersects} first: a box wholly outside the indexed area is clamped into an edge cell,
|
|
107
|
+
* which is safe only because stored coordinates are then compared exactly.
|
|
108
|
+
* @param box - The box to test.
|
|
109
|
+
* @param overlap - How the def being tested competes.
|
|
110
|
+
* @returns The blocking entry's id, as {@link insert} returned it, or `undefined` when clear.
|
|
111
|
+
*/
|
|
112
|
+
blockerOf(box: PlacementBox, overlap: OverlapMode): number | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Adds a box, so that later tests see it.
|
|
115
|
+
*
|
|
116
|
+
* Separate from {@link blockerOf} because asking whether a box is blocked and claiming its room are
|
|
117
|
+
* different questions: a group tests its padded union and inserts its plain one, and maplibre
|
|
118
|
+
* separates `placeCollisionBox` from `insertCollisionBox` for the same reason.
|
|
119
|
+
*
|
|
120
|
+
* Only insert a box that {@link intersects} accepted: one wholly outside the indexed area would be
|
|
121
|
+
* clamped into an edge cell, and relies on the exact comparison in {@link blockerOf} to stay
|
|
122
|
+
* harmless.
|
|
123
|
+
* @param box - The box to add.
|
|
124
|
+
* @param overlap - How the def competes.
|
|
125
|
+
* @returns The entry's id: the number of entries inserted before it since the last reset.
|
|
126
|
+
*/
|
|
127
|
+
insert(box: PlacementBox, overlap: OverlapMode): number;
|
|
128
|
+
/**
|
|
129
|
+
* Reads back the box an entry was inserted with.
|
|
130
|
+
* @param id - The entry's id, as {@link insert} returned it since the last reset.
|
|
131
|
+
* @param out - The box to write into.
|
|
132
|
+
* @returns `out`.
|
|
133
|
+
*/
|
|
134
|
+
boxOf(id: number, out: PlacementBox): PlacementBox;
|
|
135
|
+
/**
|
|
136
|
+
* Which cell column a CSS x lands in, clamped into the index.
|
|
137
|
+
* @param x - The coordinate.
|
|
138
|
+
* @returns The column.
|
|
139
|
+
*/
|
|
140
|
+
private cellX;
|
|
141
|
+
/**
|
|
142
|
+
* Which cell row a CSS y lands in, clamped into the index.
|
|
143
|
+
* @param y - The coordinate.
|
|
144
|
+
* @returns The row.
|
|
145
|
+
*/
|
|
146
|
+
private cellY;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* How wide one cell is, in CSS pixels. More cells means fewer boxes to compare per cell, and more
|
|
150
|
+
* cells for one box to be filed under. Maplibre uses 25 against symbols a few pixels across; our
|
|
151
|
+
* pins are 32, so one pin usually touches one cell.
|
|
152
|
+
*/
|
|
153
|
+
export declare const GRID_CELL_PX = 32;
|
|
154
|
+
/**
|
|
155
|
+
* How far past the canvas the index reaches, in CSS pixels.
|
|
156
|
+
*
|
|
157
|
+
* Maplibre's `viewportPadding`, for its reason: a def crossing the edge of the screen decides off
|
|
158
|
+
* screen, so the flicker that a crossing causes happens where nobody sees it.
|
|
159
|
+
*/
|
|
160
|
+
export declare const GRID_MARGIN_PX = 100;
|
|
161
|
+
//# sourceMappingURL=grid.d.ts.map
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a def in mode `a` is allowed to cover one already placed in mode `b`.
|
|
3
|
+
*
|
|
4
|
+
* Ported from maplibre's `overlapAllowed` in `src/symbol/grid_index.ts`. With two modes the rule
|
|
5
|
+
* reduces to `a === 'always'`, and this stays as the one place it is written.
|
|
6
|
+
*
|
|
7
|
+
* The `_b` parameter is unused: an `always` entry is never inserted into the grid, so the mode of
|
|
8
|
+
* the def already there is always `never`. Re-adding a third mode brings it back.
|
|
9
|
+
* @param a - The mode of the def being tested.
|
|
10
|
+
* @param _b - The mode of the def already in the grid. Unused, see above.
|
|
11
|
+
* @returns Whether the overlap is allowed.
|
|
12
|
+
*/
|
|
13
|
+
export function overlapAllowed(a, _b) {
|
|
14
|
+
return a === 'always';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether two boxes overlap, by the rule {@link PlacementGrid.blockerOf} applies: edge contact is
|
|
18
|
+
* clear, so two boxes sharing a border do not overlap.
|
|
19
|
+
* @param a - One box.
|
|
20
|
+
* @param b - The other.
|
|
21
|
+
* @returns Whether they overlap.
|
|
22
|
+
*/
|
|
23
|
+
export function overlaps(a, b) {
|
|
24
|
+
return a.minX < b.maxX && a.maxX > b.minX && a.minY < b.maxY && a.maxY > b.minY;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A uniform-cell index of screen rectangles, which answers which rectangle already in it, if any,
|
|
28
|
+
* blocks a new one.
|
|
29
|
+
*
|
|
30
|
+
* Modeled on maplibre's `GridIndex`, without the circle half. Circles exist there for labels that
|
|
31
|
+
* follow a curved line, which this renderer does not draw. Entries live in flat arrays that a reset
|
|
32
|
+
* keeps at their length and refills from the front under a count cursor: setting `length = 0`
|
|
33
|
+
* instead lets V8 trim the backing store, so every pass would grow it again through its doublings.
|
|
34
|
+
* The per-cell id lists are short and are still cleared with `length = 0`, but only the cells an
|
|
35
|
+
* entry was filed under: a pass resets the grid once per collision scope, and every registered
|
|
36
|
+
* layer is a scope, most of them with no participant at all. Clearing all 1820 cells of a 1440 by
|
|
37
|
+
* 900 canvas for each of imexamerica25-3d's 21 scopes was 0.9–1.2 ms of a 1.1–1.4 ms pass.
|
|
38
|
+
*
|
|
39
|
+
* The index covers the canvas plus {@link GRID_MARGIN_PX} on every side, so a def crossing the
|
|
40
|
+
* edge of the screen decides off screen, where the churn is invisible.
|
|
41
|
+
*/
|
|
42
|
+
export class PlacementGrid {
|
|
43
|
+
/** Each cell's entry ids. Index is `y * xCells + x`. */
|
|
44
|
+
cells = [];
|
|
45
|
+
/** The index of every cell that holds an entry since the last reset, which is all it clears. */
|
|
46
|
+
filled = [];
|
|
47
|
+
/**
|
|
48
|
+
* Four numbers per entry: `minX`, `minY`, `maxX`, `maxY`. Only the first `count * 4` are live; the
|
|
49
|
+
* rest are the last pass's, kept so the next pass overwrites them in place.
|
|
50
|
+
*/
|
|
51
|
+
boxes = [];
|
|
52
|
+
/** One mode per entry, parallel to {@link boxes} and live up to `count` in the same way. */
|
|
53
|
+
modes = [];
|
|
54
|
+
count = 0;
|
|
55
|
+
xCells = 0;
|
|
56
|
+
yCells = 0;
|
|
57
|
+
/** The canvas width the cells were built for. `-1` until the first `reset`, so it always rebuilds. */
|
|
58
|
+
width = -1;
|
|
59
|
+
/** The canvas height the cells were built for. `-1` until the first `reset`, so it always rebuilds. */
|
|
60
|
+
height = -1;
|
|
61
|
+
/**
|
|
62
|
+
* @param width - The canvas width in CSS pixels.
|
|
63
|
+
* @param height - The canvas height in CSS pixels.
|
|
64
|
+
*/
|
|
65
|
+
constructor(width, height) {
|
|
66
|
+
this.reset(width, height);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Empties the index and sizes it for a canvas, which is what every pass starts with.
|
|
70
|
+
*
|
|
71
|
+
* The cell array is rebuilt only when the canvas size changed, so an unresized canvas pays only
|
|
72
|
+
* for clearing the cells the last fill used.
|
|
73
|
+
* @param width - The canvas width in CSS pixels.
|
|
74
|
+
* @param height - The canvas height in CSS pixels.
|
|
75
|
+
*/
|
|
76
|
+
reset(width, height) {
|
|
77
|
+
this.count = 0;
|
|
78
|
+
for (const index of this.filled)
|
|
79
|
+
this.cells[index].length = 0;
|
|
80
|
+
this.filled.length = 0;
|
|
81
|
+
if (width !== this.width || height !== this.height) {
|
|
82
|
+
this.width = width;
|
|
83
|
+
this.height = height;
|
|
84
|
+
this.xCells = Math.max(1, Math.ceil((width + 2 * GRID_MARGIN_PX) / GRID_CELL_PX));
|
|
85
|
+
this.yCells = Math.max(1, Math.ceil((height + 2 * GRID_MARGIN_PX) / GRID_CELL_PX));
|
|
86
|
+
this.cells = [];
|
|
87
|
+
for (let i = 0; i < this.xCells * this.yCells; i++)
|
|
88
|
+
this.cells.push([]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Whether the box intersects the indexed area, which is the canvas plus its margin. A box that
|
|
93
|
+
* only partly overlaps it passes; only one wholly outside fails.
|
|
94
|
+
*
|
|
95
|
+
* A box wholly outside it is not placed and not inserted. That is a correctness rule rather than a
|
|
96
|
+
* priority one: the index cannot hold it, so it cannot be tested against later defs either.
|
|
97
|
+
* @param box - The box to test.
|
|
98
|
+
* @returns Whether the index covers it.
|
|
99
|
+
*/
|
|
100
|
+
intersects(box) {
|
|
101
|
+
return (box.maxX >= -GRID_MARGIN_PX &&
|
|
102
|
+
box.minX <= this.width + GRID_MARGIN_PX &&
|
|
103
|
+
box.maxY >= -GRID_MARGIN_PX &&
|
|
104
|
+
box.minY <= this.height + GRID_MARGIN_PX);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The earliest-inserted entry that blocks this box, or nothing when it is clear.
|
|
108
|
+
*
|
|
109
|
+
* **Earliest, not first found.** The cell walk reaches a box filed under a later cell before one
|
|
110
|
+
* filed under an earlier cell, so returning the first match would make the answer depend on cell
|
|
111
|
+
* iteration order — and the answer is load-bearing: in a clustering scope the blocker is the
|
|
112
|
+
* cluster's seed, and first come, first served means the earliest. Scanning every cell the box
|
|
113
|
+
* touches costs the early exit a boolean test could take, against a few hundred entries in a
|
|
114
|
+
* handful of cells.
|
|
115
|
+
*
|
|
116
|
+
* Edge contact does not block: two boxes sharing a border are treated as clear, so a row of
|
|
117
|
+
* abutting labels is placeable.
|
|
118
|
+
*
|
|
119
|
+
* Test {@link intersects} first: a box wholly outside the indexed area is clamped into an edge cell,
|
|
120
|
+
* which is safe only because stored coordinates are then compared exactly.
|
|
121
|
+
* @param box - The box to test.
|
|
122
|
+
* @param overlap - How the def being tested competes.
|
|
123
|
+
* @returns The blocking entry's id, as {@link insert} returned it, or `undefined` when clear.
|
|
124
|
+
*/
|
|
125
|
+
blockerOf(box, overlap) {
|
|
126
|
+
if (overlap === 'always')
|
|
127
|
+
return undefined;
|
|
128
|
+
const x0 = this.cellX(box.minX);
|
|
129
|
+
const x1 = this.cellX(box.maxX);
|
|
130
|
+
const y0 = this.cellY(box.minY);
|
|
131
|
+
const y1 = this.cellY(box.maxY);
|
|
132
|
+
// Ids are assigned in insert order, so the earliest entry is the lowest id.
|
|
133
|
+
let blocker = -1;
|
|
134
|
+
for (let y = y0; y <= y1; y++) {
|
|
135
|
+
for (let x = x0; x <= x1; x++) {
|
|
136
|
+
for (const id of this.cells[y * this.xCells + x]) {
|
|
137
|
+
if (blocker !== -1 && id >= blocker)
|
|
138
|
+
continue;
|
|
139
|
+
if (overlapAllowed(overlap, this.modes[id]))
|
|
140
|
+
continue;
|
|
141
|
+
const at = id * 4;
|
|
142
|
+
if (box.minX < this.boxes[at + 2] &&
|
|
143
|
+
box.maxX > this.boxes[at] &&
|
|
144
|
+
box.minY < this.boxes[at + 3] &&
|
|
145
|
+
box.maxY > this.boxes[at + 1]) {
|
|
146
|
+
blocker = id;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return blocker === -1 ? undefined : blocker;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Adds a box, so that later tests see it.
|
|
155
|
+
*
|
|
156
|
+
* Separate from {@link blockerOf} because asking whether a box is blocked and claiming its room are
|
|
157
|
+
* different questions: a group tests its padded union and inserts its plain one, and maplibre
|
|
158
|
+
* separates `placeCollisionBox` from `insertCollisionBox` for the same reason.
|
|
159
|
+
*
|
|
160
|
+
* Only insert a box that {@link intersects} accepted: one wholly outside the indexed area would be
|
|
161
|
+
* clamped into an edge cell, and relies on the exact comparison in {@link blockerOf} to stay
|
|
162
|
+
* harmless.
|
|
163
|
+
* @param box - The box to add.
|
|
164
|
+
* @param overlap - How the def competes.
|
|
165
|
+
* @returns The entry's id: the number of entries inserted before it since the last reset.
|
|
166
|
+
*/
|
|
167
|
+
insert(box, overlap) {
|
|
168
|
+
const id = this.count++;
|
|
169
|
+
const at = id * 4;
|
|
170
|
+
this.boxes[at] = box.minX;
|
|
171
|
+
this.boxes[at + 1] = box.minY;
|
|
172
|
+
this.boxes[at + 2] = box.maxX;
|
|
173
|
+
this.boxes[at + 3] = box.maxY;
|
|
174
|
+
this.modes[id] = overlap;
|
|
175
|
+
const x0 = this.cellX(box.minX);
|
|
176
|
+
const x1 = this.cellX(box.maxX);
|
|
177
|
+
const y0 = this.cellY(box.minY);
|
|
178
|
+
const y1 = this.cellY(box.maxY);
|
|
179
|
+
for (let y = y0; y <= y1; y++) {
|
|
180
|
+
for (let x = x0; x <= x1; x++) {
|
|
181
|
+
const index = y * this.xCells + x;
|
|
182
|
+
const cell = this.cells[index];
|
|
183
|
+
if (cell.length === 0)
|
|
184
|
+
this.filled.push(index);
|
|
185
|
+
cell.push(id);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return id;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Reads back the box an entry was inserted with.
|
|
192
|
+
* @param id - The entry's id, as {@link insert} returned it since the last reset.
|
|
193
|
+
* @param out - The box to write into.
|
|
194
|
+
* @returns `out`.
|
|
195
|
+
*/
|
|
196
|
+
boxOf(id, out) {
|
|
197
|
+
const at = id * 4;
|
|
198
|
+
out.minX = this.boxes[at];
|
|
199
|
+
out.minY = this.boxes[at + 1];
|
|
200
|
+
out.maxX = this.boxes[at + 2];
|
|
201
|
+
out.maxY = this.boxes[at + 3];
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Which cell column a CSS x lands in, clamped into the index.
|
|
206
|
+
* @param x - The coordinate.
|
|
207
|
+
* @returns The column.
|
|
208
|
+
*/
|
|
209
|
+
cellX(x) {
|
|
210
|
+
const cell = Math.floor((x + GRID_MARGIN_PX) / GRID_CELL_PX);
|
|
211
|
+
return Math.min(Math.max(cell, 0), this.xCells - 1);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Which cell row a CSS y lands in, clamped into the index.
|
|
215
|
+
* @param y - The coordinate.
|
|
216
|
+
* @returns The row.
|
|
217
|
+
*/
|
|
218
|
+
cellY(y) {
|
|
219
|
+
const cell = Math.floor((y + GRID_MARGIN_PX) / GRID_CELL_PX);
|
|
220
|
+
return Math.min(Math.max(cell, 0), this.yCells - 1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* How wide one cell is, in CSS pixels. More cells means fewer boxes to compare per cell, and more
|
|
225
|
+
* cells for one box to be filed under. Maplibre uses 25 against symbols a few pixels across; our
|
|
226
|
+
* pins are 32, so one pin usually touches one cell.
|
|
227
|
+
*/
|
|
228
|
+
export const GRID_CELL_PX = 32;
|
|
229
|
+
/**
|
|
230
|
+
* How far past the canvas the index reaches, in CSS pixels.
|
|
231
|
+
*
|
|
232
|
+
* Maplibre's `viewportPadding`, for its reason: a def crossing the edge of the screen decides off
|
|
233
|
+
* screen, so the flicker that a crossing causes happens where nobody sees it.
|
|
234
|
+
*/
|
|
235
|
+
export const GRID_MARGIN_PX = 100;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createPlacement } from './pass';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type Camera } from 'three';
|
|
2
|
+
import { type Space } from '../../space/Space';
|
|
3
|
+
import { type Cluster, type ClusterOptions, type ImageDef, type LayerDef, type RenderableDef, type TextDef } from '../../types/defs';
|
|
4
|
+
/** What one placement pass needs to know about the frame it runs for. */
|
|
5
|
+
export interface PlacementContext {
|
|
6
|
+
/** The scene's space, for the projection. */
|
|
7
|
+
space: Space;
|
|
8
|
+
/** The camera in use. */
|
|
9
|
+
camera: Camera;
|
|
10
|
+
/** Plan units per CSS pixel. */
|
|
11
|
+
pixelSize: number;
|
|
12
|
+
/** The canvas width in CSS pixels. */
|
|
13
|
+
width: number;
|
|
14
|
+
/** The canvas height in CSS pixels. */
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The renderer's placement pass: which screen-space defs win room on screen, and which stand down.
|
|
19
|
+
*
|
|
20
|
+
* One object per renderer, holding the grid and the verdict each def was last given. A pass is
|
|
21
|
+
* synchronous and complete, so there is no partial index for anything to read: the cost of that is
|
|
22
|
+
* paid by running the pass at most a few times a second rather than every frame, which is the
|
|
23
|
+
* driver's business rather than this object's.
|
|
24
|
+
*/
|
|
25
|
+
export interface Placement {
|
|
26
|
+
/**
|
|
27
|
+
* Runs a whole pass and reports the defs whose verdict changed, and the clusters of each scope
|
|
28
|
+
* whose set changed.
|
|
29
|
+
*
|
|
30
|
+
* The registered arrays are bucketed into **collision scopes** first: one per
|
|
31
|
+
* {@link LayerDef.collisionGroup} key, and one per layer that names none. A def competes for room
|
|
32
|
+
* with the defs of its own scope and with nothing else, so each scope starts from an empty grid.
|
|
33
|
+
*
|
|
34
|
+
* Order is the argument's own iteration and nothing else: the scopes in the order their first array
|
|
35
|
+
* was registered, within a scope its arrays in registration order, and each array in the order
|
|
36
|
+
* its defs were authored. First come, first served, as maplibre does it, so a caller ranks its defs
|
|
37
|
+
* by ordering its layers and its children.
|
|
38
|
+
*
|
|
39
|
+
* A scope where any layer declares {@link LayerDef.clustering} **clusters**: a participant that
|
|
40
|
+
* collides hides together with the one it collided with, which becomes the seed of a cluster that
|
|
41
|
+
* later colliders join. A seed's verdict is therefore revised after it was decided, so nothing is
|
|
42
|
+
* reported during the walk. Once a scope's walk ends, each cluster's marker box absorbs the
|
|
43
|
+
* placed units it overlaps and merges with the clusters whose marker boxes it overlaps, until
|
|
44
|
+
* nothing changes (see {@link ClusterOptions.marker}). Only then are its flips reported, first,
|
|
45
|
+
* in walk order, and then its cluster set, to every clustering layer in it.
|
|
46
|
+
* @param entries - Each registered def array with the layer that registered it, in registration
|
|
47
|
+
* order. The registry's own map entries, so calling this allocates nothing.
|
|
48
|
+
* @param context - What the camera shows this pass.
|
|
49
|
+
* @param onFlip - Called for each def whose verdict differs from the one it last had.
|
|
50
|
+
* @param onCluster - Called once per clustering layer of a scope whose cluster set differs from
|
|
51
|
+
* the one last reported for it, with a fresh array each time; also with the current set for a
|
|
52
|
+
* clustering layer that joined a scope after its last report, and with an empty array for each
|
|
53
|
+
* layer that was told of clusters and has since left: its scope is no longer registered, the
|
|
54
|
+
* layer is no longer in it, or it no longer declares `clustering`. The third argument is the
|
|
55
|
+
* {@link ClusterOptions} the layer was told under, which is the one to call even where the
|
|
56
|
+
* layer has dropped it since.
|
|
57
|
+
*/
|
|
58
|
+
run(entries: Iterable<readonly [readonly RenderableDef[], LayerDef]>, context: PlacementContext, onFlip: (def: ImageDef | TextDef, placed: boolean) => void, onCluster?: (layer: LayerDef, clusters: readonly Cluster[], clustering: ClusterOptions) => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Drops a def's verdict, so that registering the same object again reports its verdict afresh.
|
|
61
|
+
* @param def - The def to forget.
|
|
62
|
+
*/
|
|
63
|
+
forget(def: RenderableDef): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Builds a renderer's placement pass.
|
|
67
|
+
* @returns The pass.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createPlacement(): Placement;
|
|
70
|
+
//# sourceMappingURL=pass.d.ts.map
|