abstract-3d 4.1.1 → 4.1.3

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 (130) hide show
  1. package/lib/renderers/svg/svg-encoding.d.ts +0 -2
  2. package/lib/renderers/svg/svg-encoding.d.ts.map +1 -1
  3. package/lib/renderers/svg/svg-encoding.js +0 -12
  4. package/lib/renderers/svg/svg-encoding.js.map +1 -1
  5. package/lib/renderers/svg/svg-geometries/shared.d.ts +2 -19
  6. package/lib/renderers/svg/svg-geometries/shared.d.ts.map +1 -1
  7. package/lib/renderers/svg/svg-geometries/shared.js +1 -16
  8. package/lib/renderers/svg/svg-geometries/shared.js.map +1 -1
  9. package/lib/renderers/svg/svg-geometries/svg-box.d.ts.map +1 -1
  10. package/lib/renderers/svg/svg-geometries/svg-box.js +30 -44
  11. package/lib/renderers/svg/svg-geometries/svg-box.js.map +1 -1
  12. package/lib/renderers/svg/svg-geometries/svg-cone.d.ts.map +1 -1
  13. package/lib/renderers/svg/svg-geometries/svg-cone.js +3 -3
  14. package/lib/renderers/svg/svg-geometries/svg-cone.js.map +1 -1
  15. package/lib/renderers/svg/svg-geometries/svg-cylinder.d.ts.map +1 -1
  16. package/lib/renderers/svg/svg-geometries/svg-cylinder.js +6 -19
  17. package/lib/renderers/svg/svg-geometries/svg-cylinder.js.map +1 -1
  18. package/lib/renderers/svg/svg-geometries/svg-image.d.ts.map +1 -1
  19. package/lib/renderers/svg/svg-geometries/svg-image.js +2 -3
  20. package/lib/renderers/svg/svg-geometries/svg-image.js.map +1 -1
  21. package/lib/renderers/svg/svg-geometries/svg-line.d.ts.map +1 -1
  22. package/lib/renderers/svg/svg-geometries/svg-line.js +1 -3
  23. package/lib/renderers/svg/svg-geometries/svg-line.js.map +1 -1
  24. package/lib/renderers/svg/svg-geometries/svg-plane.d.ts.map +1 -1
  25. package/lib/renderers/svg/svg-geometries/svg-plane.js +2 -6
  26. package/lib/renderers/svg/svg-geometries/svg-plane.js.map +1 -1
  27. package/lib/renderers/svg/svg-geometries/svg-polygon.d.ts.map +1 -1
  28. package/lib/renderers/svg/svg-geometries/svg-polygon.js +2 -10
  29. package/lib/renderers/svg/svg-geometries/svg-polygon.js.map +1 -1
  30. package/lib/renderers/svg/svg-geometries/svg-shape.d.ts.map +1 -1
  31. package/lib/renderers/svg/svg-geometries/svg-shape.js +2 -5
  32. package/lib/renderers/svg/svg-geometries/svg-shape.js.map +1 -1
  33. package/lib/renderers/svg/svg-geometries/svg-text.js +1 -1
  34. package/lib/renderers/svg/svg-geometries/svg-text.js.map +1 -1
  35. package/lib/renderers/svg/svg-order.d.ts +5 -6
  36. package/lib/renderers/svg/svg-order.d.ts.map +1 -1
  37. package/lib/renderers/svg/svg-order.js +124 -233
  38. package/lib/renderers/svg/svg-order.js.map +1 -1
  39. package/lib/renderers/svg/svg.d.ts.map +1 -1
  40. package/lib/renderers/svg/svg.js +12 -11
  41. package/lib/renderers/svg/svg.js.map +1 -1
  42. package/lib/renderers/svg-bsp/class-names.d.ts +11 -0
  43. package/lib/renderers/svg-bsp/class-names.d.ts.map +1 -0
  44. package/lib/renderers/svg-bsp/class-names.js +11 -0
  45. package/lib/renderers/svg-bsp/class-names.js.map +1 -0
  46. package/lib/renderers/svg-bsp/index.d.ts +5 -0
  47. package/lib/renderers/svg-bsp/index.d.ts.map +1 -0
  48. package/lib/renderers/svg-bsp/index.js +4 -0
  49. package/lib/renderers/svg-bsp/index.js.map +1 -0
  50. package/lib/renderers/svg-bsp/svg-encoding.d.ts +19 -0
  51. package/lib/renderers/svg-bsp/svg-encoding.d.ts.map +1 -0
  52. package/lib/renderers/svg-bsp/svg-encoding.js +135 -0
  53. package/lib/renderers/svg-bsp/svg-encoding.js.map +1 -0
  54. package/lib/renderers/svg-bsp/svg-geometries/shared.d.ts +47 -0
  55. package/lib/renderers/svg-bsp/svg-geometries/shared.d.ts.map +1 -0
  56. package/lib/renderers/svg-bsp/svg-geometries/shared.js +45 -0
  57. package/lib/renderers/svg-bsp/svg-geometries/shared.js.map +1 -0
  58. package/lib/renderers/svg-bsp/svg-geometries/svg-box.d.ts +4 -0
  59. package/lib/renderers/svg-bsp/svg-geometries/svg-box.d.ts.map +1 -0
  60. package/lib/renderers/svg-bsp/svg-geometries/svg-box.js +58 -0
  61. package/lib/renderers/svg-bsp/svg-geometries/svg-box.js.map +1 -0
  62. package/lib/renderers/svg-bsp/svg-geometries/svg-cone.d.ts +4 -0
  63. package/lib/renderers/svg-bsp/svg-geometries/svg-cone.d.ts.map +1 -0
  64. package/lib/renderers/svg-bsp/svg-geometries/svg-cone.js +39 -0
  65. package/lib/renderers/svg-bsp/svg-geometries/svg-cone.js.map +1 -0
  66. package/lib/renderers/svg-bsp/svg-geometries/svg-cylinder.d.ts +4 -0
  67. package/lib/renderers/svg-bsp/svg-geometries/svg-cylinder.d.ts.map +1 -0
  68. package/lib/renderers/svg-bsp/svg-geometries/svg-cylinder.js +62 -0
  69. package/lib/renderers/svg-bsp/svg-geometries/svg-cylinder.js.map +1 -0
  70. package/lib/renderers/svg-bsp/svg-geometries/svg-image.d.ts +4 -0
  71. package/lib/renderers/svg-bsp/svg-geometries/svg-image.d.ts.map +1 -0
  72. package/lib/renderers/svg-bsp/svg-geometries/svg-image.js +44 -0
  73. package/lib/renderers/svg-bsp/svg-geometries/svg-image.js.map +1 -0
  74. package/lib/renderers/svg-bsp/svg-geometries/svg-line.d.ts +4 -0
  75. package/lib/renderers/svg-bsp/svg-geometries/svg-line.d.ts.map +1 -0
  76. package/lib/renderers/svg-bsp/svg-geometries/svg-line.js +12 -0
  77. package/lib/renderers/svg-bsp/svg-geometries/svg-line.js.map +1 -0
  78. package/lib/renderers/svg-bsp/svg-geometries/svg-plane.d.ts +4 -0
  79. package/lib/renderers/svg-bsp/svg-geometries/svg-plane.d.ts.map +1 -0
  80. package/lib/renderers/svg-bsp/svg-geometries/svg-plane.js +24 -0
  81. package/lib/renderers/svg-bsp/svg-geometries/svg-plane.js.map +1 -0
  82. package/lib/renderers/svg-bsp/svg-geometries/svg-polygon.d.ts +4 -0
  83. package/lib/renderers/svg-bsp/svg-geometries/svg-polygon.d.ts.map +1 -0
  84. package/lib/renderers/svg-bsp/svg-geometries/svg-polygon.js +24 -0
  85. package/lib/renderers/svg-bsp/svg-geometries/svg-polygon.js.map +1 -0
  86. package/lib/renderers/svg-bsp/svg-geometries/svg-shape.d.ts +4 -0
  87. package/lib/renderers/svg-bsp/svg-geometries/svg-shape.d.ts.map +1 -0
  88. package/lib/renderers/svg-bsp/svg-geometries/svg-shape.js +19 -0
  89. package/lib/renderers/svg-bsp/svg-geometries/svg-shape.js.map +1 -0
  90. package/lib/renderers/svg-bsp/svg-geometries/svg-text.d.ts +4 -0
  91. package/lib/renderers/svg-bsp/svg-geometries/svg-text.d.ts.map +1 -0
  92. package/lib/renderers/svg-bsp/svg-geometries/svg-text.js +26 -0
  93. package/lib/renderers/svg-bsp/svg-geometries/svg-text.js.map +1 -0
  94. package/lib/renderers/svg-bsp/svg-order.d.ts +10 -0
  95. package/lib/renderers/svg-bsp/svg-order.d.ts.map +1 -0
  96. package/lib/renderers/svg-bsp/svg-order.js +257 -0
  97. package/lib/renderers/svg-bsp/svg-order.js.map +1 -0
  98. package/lib/renderers/svg-bsp/svg.d.ts +16 -0
  99. package/lib/renderers/svg-bsp/svg.d.ts.map +1 -0
  100. package/lib/renderers/svg-bsp/svg.js +120 -0
  101. package/lib/renderers/svg-bsp/svg.js.map +1 -0
  102. package/package.json +6 -1
  103. package/src/renderers/svg/svg-encoding.ts +0 -13
  104. package/src/renderers/svg/svg-geometries/shared.ts +3 -31
  105. package/src/renderers/svg/svg-geometries/svg-box.ts +36 -51
  106. package/src/renderers/svg/svg-geometries/svg-cone.ts +3 -18
  107. package/src/renderers/svg/svg-geometries/svg-cylinder.ts +6 -26
  108. package/src/renderers/svg/svg-geometries/svg-image.ts +2 -3
  109. package/src/renderers/svg/svg-geometries/svg-line.ts +1 -3
  110. package/src/renderers/svg/svg-geometries/svg-plane.ts +2 -12
  111. package/src/renderers/svg/svg-geometries/svg-polygon.ts +2 -10
  112. package/src/renderers/svg/svg-geometries/svg-shape.ts +2 -11
  113. package/src/renderers/svg/svg-geometries/svg-text.ts +1 -1
  114. package/src/renderers/svg/svg.ts +12 -14
  115. package/src/renderers/svg-bsp/class-names.ts +10 -0
  116. package/src/renderers/svg-bsp/index.ts +4 -0
  117. package/src/renderers/svg-bsp/svg-encoding.ts +190 -0
  118. package/src/renderers/svg-bsp/svg-geometries/shared.ts +88 -0
  119. package/src/renderers/svg-bsp/svg-geometries/svg-box.ts +76 -0
  120. package/src/renderers/svg-bsp/svg-geometries/svg-cone.ts +68 -0
  121. package/src/renderers/svg-bsp/svg-geometries/svg-cylinder.ts +82 -0
  122. package/src/renderers/svg-bsp/svg-geometries/svg-image.ts +56 -0
  123. package/src/renderers/svg-bsp/svg-geometries/svg-line.ts +21 -0
  124. package/src/renderers/svg-bsp/svg-geometries/svg-plane.ts +43 -0
  125. package/src/renderers/svg-bsp/svg-geometries/svg-polygon.ts +33 -0
  126. package/src/renderers/svg-bsp/svg-geometries/svg-shape.ts +34 -0
  127. package/src/renderers/svg-bsp/svg-geometries/svg-text.ts +40 -0
  128. package/src/renderers/svg-bsp/svg.ts +183 -0
  129. /package/src/renderers/{svg → svg-bsp}/svg-order.test.ts +0 -0
  130. /package/src/renderers/{svg → svg-bsp}/svg-order.ts +0 -0
@@ -0,0 +1,120 @@
1
+ import { exhaustiveCheck } from "ts-exhaustive-check";
2
+ import { vec2, vec3Rot, vec3Zero, vec3RotCombine, vec3, vec3TransRot, rotationForCameraPos, sizeBoundsForCameraPos, bounds2FromPosAndSize, bounds2ToSize, bounds2Merge, vec2Zero, vec3Flip, dimensionConvertToTypeMesh, } from "../../abstract-3d.js";
3
+ import { calculateVisibleViews, isViewVisible } from "../../utils.js";
4
+ import { svg } from "./svg-encoding.js";
5
+ import { box } from "./svg-geometries/svg-box.js";
6
+ import { cone } from "./svg-geometries/svg-cone.js";
7
+ import { cylinder } from "./svg-geometries/svg-cylinder.js";
8
+ import { image } from "./svg-geometries/svg-image.js";
9
+ import { line } from "./svg-geometries/svg-line.js";
10
+ import { plane } from "./svg-geometries/svg-plane.js";
11
+ import { polygon } from "./svg-geometries/svg-polygon.js";
12
+ import { shape } from "./svg-geometries/svg-shape.js";
13
+ import { text } from "./svg-geometries/svg-text.js";
14
+ import { orderElements } from "./svg-order.js";
15
+ export function renderScenes(scenes, baseOptions) {
16
+ const allElements = Array();
17
+ const bounds = Array();
18
+ for (const view of scenes) {
19
+ const { elements, size, center } = renderInternal(view.scene, { ...baseOptions, ...view.options }, view.pos);
20
+ allElements.push(...elements);
21
+ const newBounds = bounds2FromPosAndSize(center, size);
22
+ bounds.push(newBounds);
23
+ }
24
+ const mergedBounds = bounds2Merge(...bounds);
25
+ const size = bounds2ToSize(mergedBounds);
26
+ const image = svg(mergedBounds.min, size, allElements.reduce((a, { element }) => `${a} ${element}`, ""), baseOptions?.className ?? "");
27
+ return { image, width: size.x, height: size.y };
28
+ }
29
+ export function render(scene, options) {
30
+ const { elements, size, center } = renderInternal(scene, options, vec2Zero);
31
+ const image = svg(vec2(center.x - size.x / 2, center.y - size.y / 2), size, elements.reduce((a, { element }) => `${a} ${element}`, ""), options?.className ?? "");
32
+ return { image, width: size.x, height: size.y };
33
+ }
34
+ function renderInternal(scene, options, offset) {
35
+ const opts = {
36
+ view: options?.view ?? "front",
37
+ stroke_thickness: options?.stroke_thickness ?? 2,
38
+ only_stroke: options?.only_stroke ?? false,
39
+ gray_scale: options?.gray_scale ?? false,
40
+ background: options?.background ?? "rgba(255,255,255,0)",
41
+ font: options?.font ?? "",
42
+ imageDataByUrl: options?.imageDataByUrl ?? {},
43
+ rotation: options?.rotation ?? 0,
44
+ imageBg: options?.imageBg ?? false,
45
+ className: options?.className ?? "",
46
+ };
47
+ // A three-quarter view: the front turned 30° to show the side, and tilted 20° to show the top, the front foremost
48
+ const angled = opts.view === "TopLeft" || opts.view === "TopRight";
49
+ const view = angled ? "front" : opts.view;
50
+ const angledRot = angled
51
+ ? vec3RotCombine(vec3((20 * Math.PI) / 180, 0, 0), vec3(0, ((opts.view === "TopRight" ? -1 : 1) * 30 * Math.PI) / 180, 0))
52
+ : vec3Zero;
53
+ const cameraRot = vec3RotCombine(angledRot, rotationForCameraPos(view));
54
+ const viewRot = opts.rotation ? vec3RotCombine(vec3(0, 0, (opts.rotation * Math.PI) / 180), cameraRot) : cameraRot;
55
+ const unitRot = vec3RotCombine(viewRot, scene.rotation_deprecated ?? vec3Zero);
56
+ const unitCenter = vec3Rot(scene.center_deprecated ?? vec3Zero, vec3Zero, cameraRot);
57
+ const [unitSize] = sizeBoundsForCameraPos(scene.size_deprecated, unitCenter, unitRot);
58
+ const svgSize = vec2(unitSize.x + 1.5 * opts.stroke_thickness, unitSize.y + 1.5 * opts.stroke_thickness);
59
+ const svgCenter = vec2(offset.x + opts.stroke_thickness * 0.75, offset.y + opts.stroke_thickness * 0.75);
60
+ const point = (x, y) => vec2(svgCenter.x + x, svgCenter.y - y);
61
+ const unitCenterFlipped = vec3Flip(unitCenter);
62
+ const elements = [
63
+ ...orderElements(scene.groups.flatMap((g) => svgGroup(g, unitCenterFlipped, unitRot, point, opts)), point),
64
+ ];
65
+ const dimOpts = { ...opts, only_stroke: false, gray_scale: false };
66
+ const visibleViews = calculateVisibleViews(view, scene.rotation_deprecated);
67
+ // Dimensions are drawn for the flat views
68
+ for (const dim of angled ? [] : (scene.dimensions_deprecated?.dimensions ?? [])) {
69
+ const d = dimensionConvertToTypeMesh(dim, scene.rotation_deprecated ?? vec3Zero, scene.dimensions_deprecated?.material);
70
+ if (isViewVisible(d.views[0], visibleViews)) {
71
+ const pos = vec3TransRot(d.pos, unitCenterFlipped, unitRot);
72
+ const rot = vec3RotCombine(unitRot, d.rot);
73
+ for (const m of d.meshes) {
74
+ elements.push(...svgMesh(m, pos, rot, point, scene.dimensions_deprecated?.material ?? { normal: "" }, dimOpts));
75
+ }
76
+ }
77
+ }
78
+ return { elements, size: svgSize, center: svgCenter };
79
+ }
80
+ function svgGroup(g, parentPos, parentRot, point, opts) {
81
+ const pos = vec3TransRot(g.pos, parentPos, parentRot);
82
+ const rot = vec3RotCombine(parentRot, g.rot ?? vec3Zero);
83
+ const elements = Array();
84
+ for (const m of g.meshes ?? []) {
85
+ elements.push(...svgMesh(m, pos, rot, point, m.material, opts));
86
+ }
87
+ for (const sg of g.groups ?? []) {
88
+ elements.push(...svgGroup(sg, pos, rot, point, opts));
89
+ }
90
+ return elements;
91
+ }
92
+ function svgMesh(mesh, parentPos, parentRot, point, material, opts) {
93
+ switch (mesh.geometry.type) {
94
+ case "Box":
95
+ return box(mesh.geometry, point, material, opts, parentPos, parentRot);
96
+ case "Plane":
97
+ return plane(mesh.geometry, point, material, opts, parentPos, parentRot);
98
+ case "Cylinder":
99
+ return cylinder(mesh.geometry, point, material, opts, parentPos, parentRot);
100
+ case "Cone":
101
+ return cone(mesh.geometry, point, material, opts, parentPos, parentRot);
102
+ case "CulledLine":
103
+ case "Line":
104
+ return line(mesh.geometry, point, material.normal, opts, parentPos, parentRot);
105
+ case "Polygon":
106
+ return polygon(mesh.geometry, point, material, opts, parentPos, parentRot);
107
+ case "Shape":
108
+ return shape(mesh.geometry, point, material, opts, parentPos, parentRot);
109
+ case "Text":
110
+ return text(mesh.geometry, point, material.normal, opts, parentPos, parentRot);
111
+ case "Image":
112
+ return image(mesh.geometry, point, opts, parentPos, parentRot);
113
+ case "Tube":
114
+ case "Sphere":
115
+ return [];
116
+ default:
117
+ return exhaustiveCheck(mesh.geometry);
118
+ }
119
+ }
120
+ //# sourceMappingURL=svg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.js","sourceRoot":"","sources":["../../../src/renderers/svg-bsp/svg.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abstract-3d",
3
- "version": "4.1.1",
3
+ "version": "4.1.3",
4
4
  "gitHead": "17921b59da5eee6cc446fd37a2134165af4d1901",
5
5
  "description": "Abstract 3D",
6
6
  "license": "MIT",
@@ -59,6 +59,11 @@
59
59
  "ts": "./src/renderers/svg/index.ts",
60
60
  "types": "./lib/renderers/svg/index.d.ts",
61
61
  "import": "./lib/renderers/svg/index.js"
62
+ },
63
+ "./svg-bsp": {
64
+ "ts": "./src/renderers/svg-bsp/index.ts",
65
+ "types": "./lib/renderers/svg-bsp/index.d.ts",
66
+ "import": "./lib/renderers/svg-bsp/index.js"
62
67
  }
63
68
  },
64
69
  "dependencies": {
@@ -100,19 +100,6 @@ function svgStrokedHoles(pos: Vec2, rot: Vec3, holes: ReadonlyArray<Hole>, strok
100
100
  return svgHoles;
101
101
  }
102
102
 
103
- /** A polygon's edges that are flagged, the edge from each point to the next, as one path, without a fill */
104
- export function svgEdges(points: ReadonlyArray<Vec2>, edges: ReadonlyArray<boolean>, stroke: string, strokeWidth: number): string {
105
- // From after an unflagged edge, so a run of edges isn't broken where the points wrap around
106
- const start = edges.indexOf(false) + 1;
107
- const d = points.reduce((path, _, k) => {
108
- const i = (start + k) % points.length;
109
- const [p, q] = [points[i]!, points[(i + 1) % points.length]!];
110
- const move = k > 0 && edges[(i + points.length - 1) % points.length] ? "" : `M${p.x.toFixed(0)},${p.y.toFixed(0)}`;
111
- return edges[i] ? `${path}${move}L${q.x.toFixed(0)},${q.y.toFixed(0)}` : path;
112
- }, "");
113
- return `<path class="${classNames.stroke}" d="${d}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}" />`;
114
- }
115
-
116
103
  export const svgCircle2 = (radius: number, pos: Vec2, fill: string, stroke: string, strokeWidth: number, _holes?: ReadonlyArray<Hole>): string =>
117
104
  `<circle class="${classNames.stroke}" r="${radius.toFixed(0)}" cx="${pos.x.toFixed(0)}" cy="${pos.y.toFixed(
118
105
  0
@@ -1,36 +1,8 @@
1
1
  import type { Vec2, Vec3, View } from "../../../abstract-3d.js";
2
2
  import { vec3TransRot, vec3Zero } from "../../../abstract-3d.js";
3
3
 
4
- /**
5
- * An element and its mean depth, and the points it covers in view space (x right, y up, z toward the viewer), by which it's ordered when given,
6
- * whether it hides what's behind it, and the style of a plain polygon, without holes, by which its pieces are drawn when it's split
7
- */
8
- export type zOrderElement = {
9
- readonly element: string;
10
- readonly zOrder: number;
11
- readonly polygon?: ReadonlyArray<Vec3>;
12
- readonly opaque?: boolean;
13
- readonly style?: PolygonStyle;
14
- };
15
- export type PolygonStyle = { readonly fill: string; readonly opacity: number; readonly stroke: string; readonly strokeWidth: number };
16
- export const zElem = (element: string, zOrder: number, polygon?: ReadonlyArray<Vec3>, opaque?: boolean, style?: PolygonStyle): zOrderElement => ({
17
- element,
18
- zOrder,
19
- ...(polygon && { polygon }),
20
- ...(opaque && { opaque }),
21
- ...(style && { style }),
22
- });
23
-
24
- /** Whether a fill hides what's behind it: fully opaque, and not transparent, e.g. a sketch's default background */
25
- export const isOpaque = (fill: string, opacity: number): boolean => opacity >= 1 && !/^(transparent|none|rgba\(.*,\s*0(\.0*)?\s*\))$/.test(fill);
26
-
27
- /** Twice the signed area of a polygon on screen */
28
- export function getArea(points: ReadonlyArray<Vec2>): number {
29
- return points.reduce((sum, p, i) => {
30
- const q = points[(i + 1) % points.length]!;
31
- return sum + p.x * q.y - q.x * p.y;
32
- }, 0);
33
- }
4
+ export type zOrderElement = { readonly element: string; readonly zOrder: number };
5
+ export const zElem = (element: string, zOrder: number): zOrderElement => ({ element, zOrder });
34
6
 
35
7
  export const stBW = 0.7;
36
8
  export const stN = 0.1;
@@ -42,7 +14,7 @@ export const black = "rgb(15, 15, 15)";
42
14
 
43
15
  export type ImageDataUri = `data:image/png;base64,${string}` | `data:image/jpeg;base64,${string}` | `data:image/svg+xml,${string}`;
44
16
 
45
- /** A view, or a three-quarter one from the front's top left or top right, which shows the front foremost, the top and that side */
17
+ /** A view, or an isometric one from the front's top left or top right, which shows the front, the top and that side, foreshortened alike */
46
18
  export type SvgView = View | "TopLeft" | "TopRight";
47
19
 
48
20
  export type SvgOptions = {
@@ -3,7 +3,7 @@ import { vec3Scale, vec3TransRot, vec3RotCombine, vec3Zero, vec3, vec3ZMean } fr
3
3
  import { rgbGrayScale } from "../../../utils.js";
4
4
  import { svgPolygon } from "../svg-encoding.js";
5
5
  import type { zOrderElement, SvgOptions } from "./shared.js";
6
- import { gray, black, zElem, getArea, isOpaque } from "./shared.js";
6
+ import { gray, black, zElem } from "./shared.js";
7
7
 
8
8
  export function box(
9
9
  b: Box,
@@ -16,61 +16,46 @@ export function box(
16
16
  const half = vec3Scale(b.size, 0.5);
17
17
  const pos = vec3TransRot(b.pos, parentPos, parentRot);
18
18
  const rot = vec3RotCombine(parentRot, b.rot ?? vec3Zero);
19
- const corners = unitCorners.map((c) => vec3TransRot(vec3(c.x * half.x, c.y * half.y, c.z * half.z), pos, rot));
19
+ const vec3tr = (p: Vec3): Vec3 => vec3TransRot(p, pos, rot);
20
+
21
+ const v1 = vec3tr(vec3(-half.x, -half.y, half.z));
22
+ const v2 = vec3tr(vec3(half.x, -half.y, half.z));
23
+ const v3 = vec3tr(vec3(half.x, half.y, half.z));
24
+ const v4 = vec3tr(vec3(-half.x, half.y, half.z));
25
+ const v5 = vec3tr(vec3(-half.x, -half.y, -half.z));
26
+ const v6 = vec3tr(vec3(half.x, -half.y, -half.z));
27
+ const v7 = vec3tr(vec3(half.x, half.y, -half.z));
28
+ const v8 = vec3tr(vec3(-half.x, half.y, -half.z));
29
+
30
+ const frontMean = vec3ZMean(v1, v2, v3, v4);
31
+ const backMean = vec3ZMean(v5, v6, v7, v8);
32
+ const [frontBackPoints, frontBackMean] =
33
+ frontMean > backMean
34
+ ? [[point(v1.x, v1.y), point(v2.x, v2.y), point(v3.x, v3.y), point(v4.x, v4.y)], frontMean]
35
+ : [[point(v5.x, v5.y), point(v6.x, v6.y), point(v7.x, v7.y), point(v8.x, v8.y)], backMean];
36
+ const topMean = vec3ZMean(v8, v7, v3, v4);
37
+ const botMean = vec3ZMean(v5, v6, v2, v1);
38
+ const [topBotPoints, topBotMean] =
39
+ topMean > botMean
40
+ ? [[point(v8.x, v8.y), point(v7.x, v7.y), point(v3.x, v3.y), point(v4.x, v4.y)], topMean]
41
+ : [[point(v5.x, v5.y), point(v6.x, v6.y), point(v2.x, v2.y), point(v1.x, v1.y)], botMean];
42
+
43
+ const rightMean = vec3ZMean(v6, v2, v3, v7);
44
+ const leftMean = vec3ZMean(v5, v1, v4, v8);
45
+ const [rightLeftPoints, rightLeftMean] =
46
+ rightMean > leftMean
47
+ ? [[point(v6.x, v6.y), point(v2.x, v2.y), point(v3.x, v3.y), point(v7.x, v7.y)], rightMean]
48
+ : [[point(v5.x, v5.y), point(v1.x, v1.y), point(v4.x, v4.y), point(v8.x, v8.y)], leftMean];
20
49
 
21
50
  const color = material.normal;
22
51
  const opacity = material.opacity ?? 1.0;
23
52
  const [strokeColor, fill, strokeUse] = opts.only_stroke
24
53
  ? [opts.gray_scale ? gray : color, opts.background, opts.stroke_thickness]
25
54
  : [black, opts.gray_scale ? rgbGrayScale(color) : color, 0];
26
- const opaque = isOpaque(fill, opacity);
27
55
 
28
- return faces.flatMap(([one, other], i) => {
29
- const polygon = (one.reduce((z, c) => z + corners[c]!.z, 0) > other.reduce((z, c) => z + corners[c]!.z, 0) ? one : other).map((c) => corners[c]!);
30
- const points = polygon.map((c) => point(c.x, c.y));
31
- // Seen edge on, a face is only a line along the edges of the box's other faces
32
- if (Math.abs(getArea(points)) < minArea) {
33
- return [];
34
- }
35
- // Only the front and back have holes, which show what's behind them
36
- const holes = i === 0 ? b.holes : undefined;
37
- const plain = !holes?.length;
38
- return [
39
- zElem(
40
- svgPolygon(rot, points, fill, opacity, strokeColor, strokeUse, holes),
41
- vec3ZMean(...polygon),
42
- polygon,
43
- opaque && plain,
44
- plain ? { fill, opacity, stroke: strokeColor, strokeWidth: strokeUse } : undefined
45
- ),
46
- ];
47
- });
56
+ return [
57
+ zElem(svgPolygon(rot, frontBackPoints, fill, opacity, strokeColor, strokeUse, b.holes, parentPos), frontBackMean),
58
+ zElem(svgPolygon(rot, topBotPoints, fill, opacity, strokeColor, strokeUse), topBotMean),
59
+ zElem(svgPolygon(rot, rightLeftPoints, fill, opacity, strokeColor, strokeUse), rightLeftMean),
60
+ ];
48
61
  }
49
-
50
- const unitCorners = [
51
- vec3(-1, -1, 1),
52
- vec3(1, -1, 1),
53
- vec3(1, 1, 1),
54
- vec3(-1, 1, 1),
55
- vec3(-1, -1, -1),
56
- vec3(1, -1, -1),
57
- vec3(1, 1, -1),
58
- vec3(-1, 1, -1),
59
- ];
60
- /** Pairs of opposite faces by their corners, front and back, top and bottom, right and left, of which the one toward the viewer is drawn */
61
- const faces: ReadonlyArray<readonly [ReadonlyArray<number>, ReadonlyArray<number>]> = [
62
- [
63
- [0, 1, 2, 3],
64
- [4, 5, 6, 7],
65
- ],
66
- [
67
- [7, 6, 2, 3],
68
- [4, 5, 1, 0],
69
- ],
70
- [
71
- [5, 1, 2, 6],
72
- [4, 0, 3, 7],
73
- ],
74
- ];
75
- /** Of a face on screen, in the scene's units squared, below which it's seen edge on */
76
- const minArea = 1e-6;
@@ -3,7 +3,7 @@ import { vec3, vec3TransRot, vec3RotCombine, vec3Zero, vec3ZMean, equals } from
3
3
  import { rgbGrayScale } from "../../../utils.js";
4
4
  import { svgCircle, svgPolygon } from "../svg-encoding.js";
5
5
  import type { zOrderElement, SvgOptions } from "./shared.js";
6
- import { gray, isOpaque, stBW, zElem, transparent } from "./shared.js";
6
+ import { gray, stBW, zElem, transparent } from "./shared.js";
7
7
 
8
8
  export function cone(
9
9
  c: Cone,
@@ -37,15 +37,7 @@ export function cone(
37
37
  if (i !== 0) {
38
38
  const prevBot = botVec3Array[i - 1]!;
39
39
  const points = [point(currBot.x, currBot.y), point(prevBot.x, prevBot.y), point(topPos.x, topPos.y), point(topPos.x, topPos.y)];
40
- zOrderComponents.push(
41
- zElem(
42
- svgPolygon(rot, points, fill, opacity, stroke, stBW),
43
- vec3ZMean(currBot, prevBot, topPos),
44
- [currBot, prevBot, topPos],
45
- isOpaque(fill, opacity),
46
- { fill, opacity, stroke, strokeWidth: stBW }
47
- )
48
- );
40
+ zOrderComponents.push(zElem(svgPolygon(rot, points, fill, opacity, stroke, stBW), vec3ZMean(currBot, prevBot, topPos)));
49
41
  }
50
42
  currentAngle += angleStep;
51
43
  }
@@ -54,14 +46,7 @@ export function cone(
54
46
  const cylTop = vec3tr(vec3(0, half.y, 0));
55
47
  const cylBottom = vec3tr(vec3(0, -half.y, 0));
56
48
  if (equals(cylTop.x, cylBottom.x, 0.1) && equals(cylTop.y, cylBottom.y, 0.1)) {
57
- zOrderComponents.push(
58
- zElem(
59
- svgCircle(c.radius, rot, point(cylBottom.x, cylBottom.y), fill, opacity, stroke, stBW),
60
- cylBottom.z,
61
- botVec3Array,
62
- isOpaque(fill, opacity)
63
- )
64
- );
49
+ zOrderComponents.push(zElem(svgCircle(c.radius, rot, point(cylBottom.x, cylBottom.y), fill, opacity, stroke, stBW), cylBottom.z));
65
50
  }
66
51
 
67
52
  return zOrderComponents;
@@ -3,7 +3,7 @@ import { vec3, vec3TransRot, vec3RotCombine, vec3Zero, vec3ZMean, equals } from
3
3
  import { rgbGrayScale } from "../../../utils.js";
4
4
  import { svgCircle, svgPolygon } from "../svg-encoding.js";
5
5
  import type { SvgOptions, zOrderElement } from "./shared.js";
6
- import { getArea, gray, isOpaque, stBW, transparent, zElem } from "./shared.js";
6
+ import { gray, stBW, transparent, zElem } from "./shared.js";
7
7
 
8
8
  export function cylinder(
9
9
  c: Cylinder,
@@ -24,10 +24,6 @@ export function cylinder(
24
24
  const [stroke, fill] = opts.only_stroke
25
25
  ? [opts.gray_scale ? gray : color, opts.background]
26
26
  : [transparent, opts.gray_scale ? rgbGrayScale(color) : color];
27
- const opaque = isOpaque(fill, opacity);
28
- const style = { fill, opacity, stroke, strokeWidth: stBW };
29
- // A closed opaque cylinder's facets turned away are hidden by those toward the viewer and its near end
30
- const cullBack = opaque && !c.open;
31
27
  const zOrderComponents = Array<zOrderElement>();
32
28
 
33
29
  const sides = 8;
@@ -43,39 +39,23 @@ export function cylinder(
43
39
  const currTop = vec3tr(vec3(sin * radiusEnd, half, cos * radiusEnd));
44
40
  botVec3Array.push(currBot);
45
41
  topVec3Array.push(currTop);
46
- const mid = currentAngle - angleStep / 2;
47
- if (i !== 0 && !(cullBack && vec3TransRot(vec3(Math.sin(mid), 0, Math.cos(mid)), vec3Zero, rot).z < -1e-6)) {
42
+ if (i !== 0) {
48
43
  const prevBot = botVec3Array[i - 1]!;
49
44
  const prevTop = topVec3Array[i - 1]!;
50
45
 
51
46
  const points = [point(currBot.x, currBot.y), point(prevBot.x, prevBot.y), point(prevTop.x, prevTop.y), point(currTop.x, currTop.y)];
52
- const polygon = [currBot, prevBot, prevTop, currTop];
53
- zOrderComponents.push(zElem(svgPolygon(rot, points, fill, opacity, stroke, stBW), vec3ZMean(...polygon), polygon, opaque, style));
47
+ zOrderComponents.push(zElem(svgPolygon(rot, points, fill, opacity, stroke, stBW), vec3ZMean(currBot, prevBot, currTop, prevTop)));
54
48
  }
55
49
  currentAngle += angleStep;
56
50
  }
57
51
  if (!c.open) {
58
- // The near end: a circle when directly facing the camera, else seen at an angle, its ring of facet corners
52
+ // Add circle if direcly facing camera
59
53
  const circleTop = vec3tr(vec3(0, half, 0));
60
54
  const circleBottom = vec3tr(vec3(0, -half, 0));
61
- const [circlePos, circleRadius, ring] =
62
- circleTop.z > circleBottom.z ? [circleTop, radiusEnd, topVec3Array] : [circleBottom, c.radius, botVec3Array];
63
55
  if (equals(circleTop.x, circleBottom.x, 0.1) && equals(circleTop.y, circleBottom.y, 0.1)) {
56
+ const [circlePos, circleRadius] = circleTop.z > circleBottom.z ? [circleTop, radiusEnd] : [circleBottom, c.radius];
64
57
  const holes = radiusEnd === c.radius ? c.holes : undefined;
65
- zOrderComponents.push(
66
- zElem(
67
- svgCircle(circleRadius, rot, point(circlePos.x, circlePos.y), fill, opacity, stroke, stBW, holes),
68
- circlePos.z,
69
- ring,
70
- opaque && !holes?.length
71
- )
72
- );
73
- } else {
74
- const points = ring.map((p) => point(p.x, p.y));
75
- // Not seen edge on, when it's only a line along the facets' edges
76
- if (Math.abs(getArea(points)) >= 1e-6) {
77
- zOrderComponents.push(zElem(svgPolygon(rot, points, fill, opacity, stroke, stBW), circlePos.z, ring, opaque && !c.holes?.length, style));
78
- }
58
+ zOrderComponents.push(zElem(svgCircle(circleRadius, rot, point(circlePos.x, circlePos.y), fill, opacity, stroke, stBW, holes), circlePos.z));
79
59
  }
80
60
  }
81
61
  return zOrderComponents;
@@ -21,7 +21,6 @@ export function image(
21
21
 
22
22
  const v2 = vec3tr(half.x, -half.y);
23
23
  const v4 = vec3tr(-half.x, half.y);
24
- const corners = [vec3tr(-half.x, -half.y), v2, vec3tr(half.x, half.y), v4];
25
24
 
26
25
  switch (i.image.type) {
27
26
  case "AbstractImage": {
@@ -31,7 +30,7 @@ export function image(
31
30
  };
32
31
  const svg = createSVG(i.image.image, opts);
33
32
  const img = svgImage(point(v4.x, v4.y), i.size, rot, { type: "svg", svg }, opts.imageBg ? opts.background : undefined, scale);
34
- return [zElem(img, (v2.z + v4.z) / 2, corners)];
33
+ return [zElem(img, (v2.z + v4.z) / 2)];
35
34
  }
36
35
  case "Url": {
37
36
  const imageData = opts.imageDataByUrl[i.image.url];
@@ -46,7 +45,7 @@ export function image(
46
45
 
47
46
  if (image) {
48
47
  const img = svgImage(point(v4.x, v4.y), i.size, rot, image, opts.imageBg ? opts.background : undefined);
49
- return [zElem(img, (v2.z + v4.z) / 2, corners)];
48
+ return [zElem(img, (v2.z + v4.z) / 2)];
50
49
  }
51
50
  return [];
52
51
  }
@@ -15,7 +15,5 @@ export function line(
15
15
  ): ReadonlyArray<zOrderElement> {
16
16
  const v1 = vec3TransRot(l.start, parentPos, parentRot);
17
17
  const v2 = vec3TransRot(l.end, parentPos, parentRot);
18
- return [
19
- zElem(svgLine(point(v1.x, v1.y), point(v2.x, v2.y), opts.gray_scale ? rgbGrayScale(fill) : fill, l.thickness), vec3ZMean(v1, v2), [v1, v2]),
20
- ];
18
+ return [zElem(svgLine(point(v1.x, v1.y), point(v2.x, v2.y), opts.gray_scale ? rgbGrayScale(fill) : fill, l.thickness), vec3ZMean(v1, v2))];
21
19
  }
@@ -3,7 +3,7 @@ import { vec2Scale, vec3TransRot, vec3RotCombine, vec3Zero, vec3, vec3ZMean } fr
3
3
  import { rgbGrayScale } from "../../../utils.js";
4
4
  import { svgPolygon } from "../svg-encoding.js";
5
5
  import type { zOrderElement, SvgOptions } from "./shared.js";
6
- import { gray, black, isOpaque, zElem } from "./shared.js";
6
+ import { gray, black, zElem } from "./shared.js";
7
7
 
8
8
  export function plane(
9
9
  p: Plane,
@@ -29,15 +29,5 @@ export function plane(
29
29
  const [strokeColor, fill, strokeThickness] = opts.only_stroke
30
30
  ? [opts.gray_scale ? gray : material.normal, opts.background, opts.stroke_thickness]
31
31
  : [black, opts.gray_scale ? rgbGrayScale(material.normal) : material.normal, 0];
32
- const opacity = material.opacity ?? 1.0;
33
- const plain = !holes?.length;
34
- return [
35
- zElem(
36
- svgPolygon(rot, points, fill, opacity, strokeColor, strokeThickness, holes),
37
- vec3ZMean(v1, v2, v3, v4),
38
- [v1, v2, v3, v4],
39
- isOpaque(fill, opacity) && plain,
40
- plain ? { fill, opacity, stroke: strokeColor, strokeWidth: strokeThickness } : undefined
41
- ),
42
- ];
32
+ return [zElem(svgPolygon(rot, points, fill, material.opacity ?? 1.0, strokeColor, strokeThickness, holes), vec3ZMean(v1, v2, v3, v4))];
43
33
  }
@@ -3,7 +3,7 @@ import { vec3ZMean, vec3TransRot, vec3RotCombine, vec3Zero } from "../../../abst
3
3
  import { rgbGrayScale } from "../../../utils.js";
4
4
  import { svgPolygon } from "../svg-encoding.js";
5
5
  import type { zOrderElement, SvgOptions } from "./shared.js";
6
- import { gray, isOpaque, zElem, transparent } from "./shared.js";
6
+ import { gray, zElem, transparent } from "./shared.js";
7
7
 
8
8
  export function polygon(
9
9
  p: Polygon,
@@ -21,13 +21,5 @@ export function polygon(
21
21
  const [strokeColor, fill, strokeThickness] = opts.only_stroke
22
22
  ? [opts.gray_scale ? gray : color, opts.background, opts.stroke_thickness]
23
23
  : [transparent, opts.gray_scale ? rgbGrayScale(color) : color, 0];
24
- const opacity = material.opacity ?? 1.0;
25
- return [
26
- zElem(svgPolygon(rot, points, fill, opacity, strokeColor, strokeThickness), vec3ZMean(...rotatedPoints), rotatedPoints, isOpaque(fill, opacity), {
27
- fill,
28
- opacity,
29
- stroke: strokeColor,
30
- strokeWidth: strokeThickness,
31
- }),
32
- ];
24
+ return [zElem(svgPolygon(rot, points, fill, material.opacity ?? 1.0, strokeColor, strokeThickness), vec3ZMean(...rotatedPoints))];
33
25
  }
@@ -3,7 +3,7 @@ import { vec3ZMean, vec3TransRot, vec3RotCombine, vec3, vec3Zero } from "../../.
3
3
  import { rgbGrayScale } from "../../../utils.js";
4
4
  import { svgPolygon } from "../svg-encoding.js";
5
5
  import type { zOrderElement, SvgOptions } from "./shared.js";
6
- import { gray, isOpaque, zElem, transparent } from "./shared.js";
6
+ import { gray, zElem, transparent } from "./shared.js";
7
7
 
8
8
  export function shape(
9
9
  s: Shape,
@@ -21,14 +21,5 @@ export function shape(
21
21
  const [strokeColor, fill] = opts.only_stroke
22
22
  ? [opts.gray_scale ? gray : color, opts.background]
23
23
  : [transparent, opts.gray_scale ? rgbGrayScale(color) : color];
24
- const opacity = material.opacity ?? 1.0;
25
- return [
26
- zElem(
27
- svgPolygon(rot, points, fill, opacity, strokeColor, 0),
28
- vec3ZMean(...rotatedPoints),
29
- rotatedPoints,
30
- isOpaque(fill, opacity) && !s.holes?.length,
31
- { fill, opacity, stroke: strokeColor, strokeWidth: 0 }
32
- ),
33
- ];
24
+ return [zElem(svgPolygon(rot, points, fill, material.opacity ?? 1.0, strokeColor, 0), vec3ZMean(...rotatedPoints))];
34
25
  }
@@ -32,7 +32,7 @@ export function text(
32
32
  let posY = strings.length === 1 ? 0 : (fontSize * strings.length - fontSize) / 2;
33
33
  for (const s of strings) {
34
34
  const matrix = svgTrsMatrix(point(pos.x, pos.y + posY), rot);
35
- texts.push(zElem(svgText(s, matrix, fill, opts.font, fontSize), pos.z, [pos]));
35
+ texts.push(zElem(svgText(s, matrix, fill, opts.font, fontSize), pos.z));
36
36
  posY -= fontSize * 1.2;
37
37
  }
38
38
 
@@ -29,7 +29,6 @@ import { plane } from "./svg-geometries/svg-plane.js";
29
29
  import { polygon } from "./svg-geometries/svg-polygon.js";
30
30
  import { shape } from "./svg-geometries/svg-shape.js";
31
31
  import { text } from "./svg-geometries/svg-text.js";
32
- import { orderElements } from "./svg-order.js";
33
32
 
34
33
  export type SvgScene = {
35
34
  readonly scene: Scene;
@@ -93,13 +92,13 @@ function renderInternal(
93
92
  imageBg: options?.imageBg ?? false,
94
93
  className: options?.className ?? "",
95
94
  };
96
- // A three-quarter view: the front turned 30° to show the side, and tilted 20° to show the top, the front foremost
97
- const angled = opts.view === "TopLeft" || opts.view === "TopRight";
98
- const view = angled ? "front" : opts.view;
99
- const angledRot = angled
100
- ? vec3RotCombine(vec3((20 * Math.PI) / 180, 0, 0), vec3(0, ((opts.view === "TopRight" ? -1 : 1) * 30 * Math.PI) / 180, 0))
95
+ // Isometric: the front turned 45° to show the side, and tilted by arctan(1/√2) to show the top, so the three axes are foreshortened alike
96
+ const isometric = opts.view === "TopLeft" || opts.view === "TopRight";
97
+ const view = isometric ? "front" : opts.view;
98
+ const isometricRot = isometric
99
+ ? vec3RotCombine(vec3(Math.atan(1 / Math.SQRT2), 0, 0), vec3(0, ((opts.view === "TopRight" ? -1 : 1) * Math.PI) / 4, 0))
101
100
  : vec3Zero;
102
- const cameraRot = vec3RotCombine(angledRot, rotationForCameraPos(view));
101
+ const cameraRot = vec3RotCombine(isometricRot, rotationForCameraPos(view));
103
102
  const viewRot = opts.rotation ? vec3RotCombine(vec3(0, 0, (opts.rotation * Math.PI) / 180), cameraRot) : cameraRot;
104
103
  const unitRot = vec3RotCombine(viewRot, scene.rotation_deprecated ?? vec3Zero);
105
104
 
@@ -110,17 +109,16 @@ function renderInternal(
110
109
  const point = (x: number, y: number): Vec2 => vec2(svgCenter.x + x, svgCenter.y - y);
111
110
  const unitCenterFlipped = vec3Flip(unitCenter);
112
111
 
113
- const elements = [
114
- ...orderElements(
115
- scene.groups.flatMap((g) => svgGroup(g, unitCenterFlipped, unitRot, point, opts)),
116
- point
117
- ),
118
- ];
112
+ const elements = Array<zOrderElement>();
113
+ for (const g of scene.groups) {
114
+ elements.push(...svgGroup(g, unitCenterFlipped, unitRot, point, opts));
115
+ }
119
116
  const dimOpts: SvgOptions = { ...opts, only_stroke: false, gray_scale: false };
117
+ elements.sort((a, b) => a.zOrder - b.zOrder);
120
118
  const visibleViews = calculateVisibleViews(view, scene.rotation_deprecated);
121
119
 
122
120
  // Dimensions are drawn for the flat views
123
- for (const dim of angled ? [] : (scene.dimensions_deprecated?.dimensions ?? [])) {
121
+ for (const dim of isometric ? [] : (scene.dimensions_deprecated?.dimensions ?? [])) {
124
122
  const d = dimensionConvertToTypeMesh(dim, scene.rotation_deprecated ?? vec3Zero, scene.dimensions_deprecated?.material);
125
123
  if (isViewVisible(d.views[0], visibleViews)) {
126
124
  const pos = vec3TransRot(d.pos, unitCenterFlipped, unitRot);
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The classes the svg renderer puts on what it draws, for the page's CSS: `root` on the svg, e.g. sized to fill its box, `stroke` on each stroked
3
+ * element, e.g. as thick at any size by `vector-effect: non-scaling-stroke`, `image` on an embedded picture or svg. Colors and strokes are
4
+ * attributes, which a class overrides
5
+ */
6
+ export const classNames = {
7
+ root: "a3d-root",
8
+ stroke: "a3d-stroke",
9
+ image: "a3d-image",
10
+ } as const;
@@ -0,0 +1,4 @@
1
+ export * from "./svg.js";
2
+ export * from "./class-names.js";
3
+ export { type EmbededImage } from "./svg-encoding.js";
4
+ export type { ImageDataUri, SvgOptions, SvgView } from "./svg-geometries/shared.js";