@treasuryspatial/rhino-bridge 0.1.5 → 0.1.6

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/dist/index.d.ts CHANGED
@@ -13,6 +13,14 @@ export type GeometryBridgeOptions = {
13
13
  layerKey?: string;
14
14
  materialKey?: string;
15
15
  curveMode?: "auto" | "always" | "never";
16
+ zFightMitigation?: boolean | ZFightMitigationOptions;
17
+ };
18
+ export type ZFightMitigationOptions = {
19
+ enabled?: boolean;
20
+ dedupe?: boolean;
21
+ polygonOffset?: boolean;
22
+ polygonOffsetFactor?: number;
23
+ polygonOffsetUnits?: number;
16
24
  };
17
25
  export type LayeredGeometryOptions = {
18
26
  mapLayerToId?: (layerName: string, attributes: any) => string | null;
@@ -24,6 +32,10 @@ export type LayeredGeometryOptions = {
24
32
  layerKey?: string;
25
33
  materialKey?: string;
26
34
  };
35
+ export declare const sanitizeObject3d: (root?: THREE.Object3D | null) => void;
36
+ export declare const dedupeMeshesInGroup: (group?: THREE.Group | null) => void;
37
+ export declare const applyPolygonOffsetToGroup: (group?: THREE.Group | null, factor?: number, units?: number) => void;
38
+ export declare const applyZFightMitigation: (group?: THREE.Group | null, options?: boolean | ZFightMitigationOptions) => void;
27
39
  export declare function threeGroupFrom3dm(base64: string, options?: GeometryBridgeOptions): Promise<THREE.Group>;
28
40
  export type Geometry3dmInspection = {
29
41
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -18,6 +18,26 @@ const resolveBrowserWasmUrl = (path, override) => {
18
18
  return DEFAULT_BROWSER_WASM_PATH;
19
19
  };
20
20
  let geometryModulePromise = null;
21
+ const DEFAULT_Z_FIGHT_OPTIONS = {
22
+ enabled: true,
23
+ dedupe: true,
24
+ polygonOffset: true,
25
+ polygonOffsetFactor: 0.5,
26
+ polygonOffsetUnits: 0.5,
27
+ };
28
+ const resolveZFightOptions = (input) => {
29
+ if (input === false || input === undefined || input === null)
30
+ return null;
31
+ if (input === true)
32
+ return { ...DEFAULT_Z_FIGHT_OPTIONS };
33
+ if (input.enabled === false)
34
+ return null;
35
+ return {
36
+ ...DEFAULT_Z_FIGHT_OPTIONS,
37
+ ...input,
38
+ enabled: input.enabled ?? true,
39
+ };
40
+ };
21
41
  async function getGeometryModule(options) {
22
42
  if (!geometryModulePromise) {
23
43
  if (typeof window === "undefined") {
@@ -108,6 +128,94 @@ const resolveUserString = (attributes, keys) => {
108
128
  }
109
129
  return null;
110
130
  };
131
+ export const sanitizeObject3d = (root) => {
132
+ if (!root || !Array.isArray(root.children))
133
+ return;
134
+ const children = root.children;
135
+ for (let i = children.length - 1; i >= 0; i -= 1) {
136
+ const child = children[i];
137
+ if (!child || !child.isObject3D) {
138
+ children.splice(i, 1);
139
+ continue;
140
+ }
141
+ sanitizeObject3d(child);
142
+ }
143
+ };
144
+ const buildGeometrySignature = (geometry) => {
145
+ const position = geometry.getAttribute("position");
146
+ if (!position || position.count === 0)
147
+ return null;
148
+ const index = geometry.getIndex();
149
+ const box = new THREE.Box3().setFromBufferAttribute(position);
150
+ const sampleCount = Math.min(position.count, 30);
151
+ const indexCount = index ? Math.min(index.count, 30) : 0;
152
+ let signature = `${position.count}|${index?.count ?? 0}|`;
153
+ signature += `${box.min.x.toFixed(4)},${box.min.y.toFixed(4)},${box.min.z.toFixed(4)}|`;
154
+ signature += `${box.max.x.toFixed(4)},${box.max.y.toFixed(4)},${box.max.z.toFixed(4)}`;
155
+ for (let i = 0; i < sampleCount; i += 1) {
156
+ signature += `|${position.getX(i).toFixed(4)},${position.getY(i).toFixed(4)},${position.getZ(i).toFixed(4)}`;
157
+ }
158
+ for (let i = 0; i < indexCount; i += 1) {
159
+ signature += `:${index?.getX(i) ?? 0}`;
160
+ }
161
+ return signature;
162
+ };
163
+ export const dedupeMeshesInGroup = (group) => {
164
+ if (!group || typeof group.traverse !== "function")
165
+ return;
166
+ sanitizeObject3d(group);
167
+ const seen = new Map();
168
+ const duplicates = [];
169
+ group.traverse((object) => {
170
+ if (!(object instanceof THREE.Mesh))
171
+ return;
172
+ const geometry = object.geometry;
173
+ if (!(geometry instanceof THREE.BufferGeometry))
174
+ return;
175
+ const signature = buildGeometrySignature(geometry);
176
+ if (!signature)
177
+ return;
178
+ const existing = seen.get(signature);
179
+ if (existing) {
180
+ duplicates.push(object);
181
+ }
182
+ else {
183
+ seen.set(signature, object);
184
+ }
185
+ });
186
+ if (duplicates.length > 0) {
187
+ duplicates.forEach((object) => {
188
+ object.parent?.remove(object);
189
+ });
190
+ }
191
+ };
192
+ export const applyPolygonOffsetToGroup = (group, factor = DEFAULT_Z_FIGHT_OPTIONS.polygonOffsetFactor, units = DEFAULT_Z_FIGHT_OPTIONS.polygonOffsetUnits) => {
193
+ if (!group || typeof group.traverse !== "function")
194
+ return;
195
+ group.traverse((object) => {
196
+ if (!(object instanceof THREE.Mesh))
197
+ return;
198
+ const materials = Array.isArray(object.material) ? object.material : [object.material];
199
+ materials.forEach((material) => {
200
+ if (!material)
201
+ return;
202
+ material.polygonOffset = true;
203
+ material.polygonOffsetFactor = factor;
204
+ material.polygonOffsetUnits = units;
205
+ });
206
+ });
207
+ };
208
+ export const applyZFightMitigation = (group, options) => {
209
+ const resolved = resolveZFightOptions(options);
210
+ if (!resolved || !group)
211
+ return;
212
+ if (resolved.dedupe) {
213
+ dedupeMeshesInGroup(group);
214
+ }
215
+ if (resolved.polygonOffset) {
216
+ applyPolygonOffsetToGroup(group, resolved.polygonOffsetFactor, resolved.polygonOffsetUnits);
217
+ }
218
+ };
111
219
  export async function threeGroupFrom3dm(base64, options) {
112
220
  const rhino = await getGeometryModule(options);
113
221
  const bytes = base64ToUint8Array(base64);
@@ -171,6 +279,10 @@ export async function threeGroupFrom3dm(base64, options) {
171
279
  group.add(threeObject);
172
280
  }
173
281
  }
282
+ sanitizeObject3d(group);
283
+ if (options?.zFightMitigation) {
284
+ applyZFightMitigation(group, options.zFightMitigation);
285
+ }
174
286
  return group;
175
287
  }
176
288
  export async function grasshopperResultTo3dmBase64(result) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treasuryspatial/rhino-bridge",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "main": "./dist/index.js",