@ifc-lite/export 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/glb.d.ts +10 -0
- package/dist/glb.d.ts.map +1 -1
- package/dist/glb.js +22 -0
- package/dist/glb.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/merged-exporter.d.ts +117 -16
- package/dist/merged-exporter.d.ts.map +1 -1
- package/dist/merged-exporter.js +272 -65
- package/dist/merged-exporter.js.map +1 -1
- package/dist/schema-converter.d.ts +3 -1
- package/dist/schema-converter.d.ts.map +1 -1
- package/dist/schema-converter.js +112 -3
- package/dist/schema-converter.js.map +1 -1
- package/dist/unit-normalize.d.ts +62 -0
- package/dist/unit-normalize.d.ts.map +1 -0
- package/dist/unit-normalize.js +346 -0
- package/dist/unit-normalize.js.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Unit normalization for merged STEP export (issue #1475).
|
|
6
|
+
*
|
|
7
|
+
* When {@link MergedExporter} runs with `unitReconciliation: 'normalize'`, every
|
|
8
|
+
* non-primary model whose length unit differs from the primary model's has all
|
|
9
|
+
* of its length-valued data rescaled into the primary unit, so the models can be
|
|
10
|
+
* unified into ONE `IfcProject` with ONE `IfcUnitAssignment` (rather than
|
|
11
|
+
* federated as separate, mutually mis-scaled projects).
|
|
12
|
+
*
|
|
13
|
+
* This module is the pure, text-level rescaler. It knows WHICH numeric attributes
|
|
14
|
+
* of a STEP entity carry a length (and which carry an area/volume) by deriving the
|
|
15
|
+
* answer from the generated IFC schema registry (`@ifc-lite/parser`
|
|
16
|
+
* `getAllAttributesForEntity`) — the 0-based index into an entity's `allAttributes`
|
|
17
|
+
* is exactly its 0-based STEP attribute index, and each attribute is typed. This
|
|
18
|
+
* avoids a hand-maintained per-entity table and stays correct as the schema evolves.
|
|
19
|
+
*
|
|
20
|
+
* ## Factors
|
|
21
|
+
* The caller passes three *independent* factors (a length datum × `lengthFactor`,
|
|
22
|
+
* an area datum × `areaFactor`, a volume datum × `volumeFactor`). They are NOT
|
|
23
|
+
* `lengthFactor` powers: IFC declares `AREAUNIT`/`VOLUMEUNIT` independently of
|
|
24
|
+
* `LENGTHUNIT` (e.g. Revit exports millimetre lengths but square-/cubic-metre
|
|
25
|
+
* areas/volumes), so each dimension is converted by the ratio of its own declared
|
|
26
|
+
* unit. See {@link MergedExporter} for how the factors are derived.
|
|
27
|
+
*
|
|
28
|
+
* ## What is rescaled
|
|
29
|
+
* - **Coordinate lists** — every number in a `LIST OF IfcLengthMeasure` attribute
|
|
30
|
+
* (`IfcCartesianPoint.Coordinates`, `IfcCartesianPointList2D/3D.CoordList`). × length.
|
|
31
|
+
* - **Scalar lengths** — any attribute typed `IfcLengthMeasure` /
|
|
32
|
+
* `IfcPositiveLengthMeasure` / `IfcNonNegativeLengthMeasure` (extrusion depths,
|
|
33
|
+
* profile dimensions, radii, wall thicknesses, `IfcVector.Magnitude`, CSG
|
|
34
|
+
* primitive sizes, `IfcBuildingStorey.Elevation`, `IfcSite.RefElevation`,
|
|
35
|
+
* `IfcQuantityLength.LengthValue`, …). × length.
|
|
36
|
+
* - **Areas / volumes** — `IfcQuantityArea.AreaValue` (× area),
|
|
37
|
+
* `IfcQuantityVolume.VolumeValue` (× volume).
|
|
38
|
+
* - **Typed measures in property values** — `IFCLENGTHMEASURE(x)` /
|
|
39
|
+
* `IFCPOSITIVELENGTHMEASURE(x)` / `IFCNONNEGATIVELENGTHMEASURE(x)` (× length),
|
|
40
|
+
* `IFCAREAMEASURE(x)` (× area), `IFCVOLUMEMEASURE(x)` (× volume), wherever they
|
|
41
|
+
* appear outside a quoted string.
|
|
42
|
+
*
|
|
43
|
+
* ## What is NOT rescaled
|
|
44
|
+
* - Unit-definition entities (`IfcSIUnit`, `IfcConversionBasedUnit`,
|
|
45
|
+
* `IfcMeasureWithUnit`, `IfcUnitAssignment`, …): their numbers define units, not
|
|
46
|
+
* data, and must survive verbatim.
|
|
47
|
+
* - Georeferencing (`IfcMapConversion`): its offsets are in the map/CRS unit,
|
|
48
|
+
* independent of the project length unit.
|
|
49
|
+
* - A quantity or property that carries its own explicit unit reference (`Unit`,
|
|
50
|
+
* or `DefiningUnit`/`DefinedUnit` on `IfcPropertyTableValue`): its value is
|
|
51
|
+
* already in that unit, not the global one.
|
|
52
|
+
* - Angles, direction ratios, plain `IfcReal` ratios and counts — never typed as a
|
|
53
|
+
* length/area/volume measure, so they are excluded automatically.
|
|
54
|
+
*/
|
|
55
|
+
import { getAllAttributesForEntity } from '@ifc-lite/parser';
|
|
56
|
+
import { splitTopLevelStepArguments } from './step-serialization.js';
|
|
57
|
+
/** IFC defined types whose values are lengths (STEP writes them as bare reals). */
|
|
58
|
+
const LENGTH_MEASURE_TYPES = new Set([
|
|
59
|
+
'IfcLengthMeasure',
|
|
60
|
+
'IfcPositiveLengthMeasure',
|
|
61
|
+
'IfcNonNegativeLengthMeasure',
|
|
62
|
+
]);
|
|
63
|
+
/**
|
|
64
|
+
* Entity types whose numeric content must NEVER be rescaled: unit definitions
|
|
65
|
+
* (the numbers *are* the unit) and georeferencing (offsets live in the CRS unit).
|
|
66
|
+
* `IFCMAPCONVERSION` is matched by prefix to also catch schema variants.
|
|
67
|
+
*/
|
|
68
|
+
const RESCALE_EXCLUDED_TYPES = new Set([
|
|
69
|
+
'IFCUNITASSIGNMENT', 'IFCSIUNIT', 'IFCCONVERSIONBASEDUNIT', 'IFCCONTEXTDEPENDENTUNIT',
|
|
70
|
+
'IFCDERIVEDUNIT', 'IFCDERIVEDUNITELEMENT', 'IFCDIMENSIONALEXPONENTS', 'IFCMONETARYUNIT',
|
|
71
|
+
'IFCMEASUREWITHUNIT',
|
|
72
|
+
]);
|
|
73
|
+
function isRescaleExcluded(typeUpper) {
|
|
74
|
+
return RESCALE_EXCLUDED_TYPES.has(typeUpper) || typeUpper.startsWith('IFCMAPCONVERSION');
|
|
75
|
+
}
|
|
76
|
+
const EMPTY_PLAN = {
|
|
77
|
+
listIdx: [], scalarIdx: [], areaIdx: [], volumeIdx: [], unitGuardIdx: [], empty: true,
|
|
78
|
+
};
|
|
79
|
+
/** Attribute names that hold a self-describing unit override for a value. */
|
|
80
|
+
const UNIT_GUARD_NAMES = new Set(['Unit', 'DefiningUnit', 'DefinedUnit']);
|
|
81
|
+
const planCache = new Map();
|
|
82
|
+
/**
|
|
83
|
+
* The base measure type of an attribute, and whether it is an aggregate. Handles
|
|
84
|
+
* both the compact `"IfcLengthMeasure[]"` encoding and the rare raw EXPRESS form
|
|
85
|
+
* (`"UNIQUE LIST [1:2] OF IfcLengthMeasure"`) the generated registry sometimes
|
|
86
|
+
* carries — the base is the last `Ifc…` token, and an aggregate is signalled by
|
|
87
|
+
* the flags, a `[]` suffix, or a `LIST`/`SET`/`ARRAY` keyword.
|
|
88
|
+
*/
|
|
89
|
+
function attrBaseType(type, flags) {
|
|
90
|
+
const match = type.match(/Ifc[A-Za-z0-9]+/g);
|
|
91
|
+
const base = match ? match[match.length - 1] : type;
|
|
92
|
+
const isList = flags.isList || flags.isArray || flags.isSet
|
|
93
|
+
|| /\[\]/.test(type) || /\b(?:LIST|SET|ARRAY|BAG)\b/i.test(type);
|
|
94
|
+
return { base, isList };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Derive (and cache) the length/area/volume attribute plan for an uppercase STEP
|
|
98
|
+
* type name from the generated schema registry. Excluded types (unit definitions,
|
|
99
|
+
* georeferencing) and unknown/abstract types return the empty plan.
|
|
100
|
+
*/
|
|
101
|
+
export function getEntityLengthPlan(typeUpper) {
|
|
102
|
+
const cached = planCache.get(typeUpper);
|
|
103
|
+
if (cached !== undefined)
|
|
104
|
+
return cached;
|
|
105
|
+
const plan = buildEntityLengthPlan(typeUpper);
|
|
106
|
+
planCache.set(typeUpper, plan);
|
|
107
|
+
return plan;
|
|
108
|
+
}
|
|
109
|
+
function buildEntityLengthPlan(typeUpper) {
|
|
110
|
+
if (isRescaleExcluded(typeUpper))
|
|
111
|
+
return EMPTY_PLAN;
|
|
112
|
+
const attrs = getAllAttributesForEntity(typeUpper);
|
|
113
|
+
if (!attrs || attrs.length === 0)
|
|
114
|
+
return EMPTY_PLAN;
|
|
115
|
+
const listIdx = [];
|
|
116
|
+
const scalarIdx = [];
|
|
117
|
+
const areaIdx = [];
|
|
118
|
+
const volumeIdx = [];
|
|
119
|
+
const unitGuardIdx = [];
|
|
120
|
+
attrs.forEach((a, i) => {
|
|
121
|
+
const { base, isList } = attrBaseType(a.type, a);
|
|
122
|
+
if (LENGTH_MEASURE_TYPES.has(base)) {
|
|
123
|
+
if (isList)
|
|
124
|
+
listIdx.push(i);
|
|
125
|
+
else
|
|
126
|
+
scalarIdx.push(i);
|
|
127
|
+
}
|
|
128
|
+
else if (base === 'IfcAreaMeasure' && !isList) {
|
|
129
|
+
areaIdx.push(i);
|
|
130
|
+
}
|
|
131
|
+
else if (base === 'IfcVolumeMeasure' && !isList) {
|
|
132
|
+
volumeIdx.push(i);
|
|
133
|
+
}
|
|
134
|
+
// A quantity's Unit is typed IfcNamedUnit; a property's Unit is the IfcUnit
|
|
135
|
+
// SELECT; an IfcPropertyTableValue uses DefiningUnit/DefinedUnit. Any of them,
|
|
136
|
+
// when set, means the value carries its own unit.
|
|
137
|
+
if (UNIT_GUARD_NAMES.has(a.name) && (base === 'IfcNamedUnit' || base === 'IfcUnit')) {
|
|
138
|
+
unitGuardIdx.push(i);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
const empty = listIdx.length === 0 && scalarIdx.length === 0
|
|
142
|
+
&& areaIdx.length === 0 && volumeIdx.length === 0 && unitGuardIdx.length === 0;
|
|
143
|
+
return empty ? EMPTY_PLAN : { listIdx, scalarIdx, areaIdx, volumeIdx, unitGuardIdx, empty };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Format a number as a valid ISO-10303-21 STEP REAL, after a unit multiply.
|
|
147
|
+
*
|
|
148
|
+
* Rounds to 12 significant digits first to erase floating-point noise from the
|
|
149
|
+
* multiply (e.g. `0.3048 * 100 = 30.479999999999997` → `30.48`) — 12 digits keeps
|
|
150
|
+
* sub-micron precision at building scale. Always emits a decimal point, and
|
|
151
|
+
* rewrites JavaScript's lowercase exponent (`1.5e-7`) into STEP's uppercase form
|
|
152
|
+
* with a mantissa dot (`1.5E-7`), so small/large magnitudes stay parseable.
|
|
153
|
+
*/
|
|
154
|
+
export function toStepRealScaled(v) {
|
|
155
|
+
if (!Number.isFinite(v))
|
|
156
|
+
return '0.';
|
|
157
|
+
if (v === 0)
|
|
158
|
+
return '0.'; // also normalizes -0
|
|
159
|
+
const s = parseFloat(v.toPrecision(12)).toString();
|
|
160
|
+
const e = s.indexOf('e');
|
|
161
|
+
if (e !== -1) {
|
|
162
|
+
let mantissa = s.slice(0, e);
|
|
163
|
+
const exp = s.slice(e + 1);
|
|
164
|
+
if (!mantissa.includes('.'))
|
|
165
|
+
mantissa += '.';
|
|
166
|
+
return `${mantissa}E${exp}`;
|
|
167
|
+
}
|
|
168
|
+
return s.includes('.') ? s : s + '.';
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Single token matcher used by {@link scaleNumberLiterals}: a full STEP string
|
|
172
|
+
* (kept verbatim, honouring the `''` escape), a `#`-reference (kept verbatim), or
|
|
173
|
+
* a REAL/INTEGER literal (rescaled). Ordering matters — strings and refs are
|
|
174
|
+
* matched first so their inner digits are never treated as numbers. The number
|
|
175
|
+
* alternative consumes an optional exponent as one token, so `1.E-5` / `-2.5E2`
|
|
176
|
+
* scale the mantissa without touching the exponent digits.
|
|
177
|
+
*/
|
|
178
|
+
const NUMBER_TOKEN_RE = /'(?:[^']|'')*'|#\d+|[+-]?(?:\d+\.\d*|\.\d+|\d+)(?:[eE][+-]?\d+)?/g;
|
|
179
|
+
/**
|
|
180
|
+
* Multiply every bare numeric literal in `text` by `factor`, leaving quoted
|
|
181
|
+
* strings and `#`-references untouched. O(n) single pass — safe for the large
|
|
182
|
+
* coordinate lists of tessellated geometry.
|
|
183
|
+
*/
|
|
184
|
+
export function scaleNumberLiterals(text, factor) {
|
|
185
|
+
return text.replace(NUMBER_TOKEN_RE, (tok) => {
|
|
186
|
+
const c = tok.charCodeAt(0);
|
|
187
|
+
if (c === 0x27 /* ' */ || c === 0x23 /* # */)
|
|
188
|
+
return tok;
|
|
189
|
+
return toStepRealScaled(parseFloat(tok) * factor);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Scale the typed measures embedded in property/quantity values. Matches
|
|
194
|
+
* `IFC[POSITIVE|NONNEGATIVE]LENGTHMEASURE(x)` (× lengthFactor), `IFCAREAMEASURE(x)`
|
|
195
|
+
* (× areaFactor) and `IFCVOLUMEMEASURE(x)` (× volumeFactor), but never inside a
|
|
196
|
+
* quoted string (the string alternative is matched first and returned verbatim).
|
|
197
|
+
*
|
|
198
|
+
* A single non-word delimiter (`(`, `,`, whitespace, or start-of-input) is
|
|
199
|
+
* captured before the keyword and restored, so a keyword can never be matched as
|
|
200
|
+
* the suffix of a longer identifier — without a lookbehind, which some engines
|
|
201
|
+
* (older Safari) reject at construction time and would break importing this module.
|
|
202
|
+
*/
|
|
203
|
+
const TYPED_MEASURE_RE = /('(?:[^']|'')*')|(^|[^A-Za-z0-9_])(IFC(?:POSITIVE|NONNEGATIVE)?LENGTHMEASURE|IFCAREAMEASURE|IFCVOLUMEMEASURE)\(([^)]*)\)/gi;
|
|
204
|
+
export function scaleTypedMeasures(text, lengthFactor, areaFactor, volumeFactor) {
|
|
205
|
+
return text.replace(TYPED_MEASURE_RE, (full, str, delim, keyword, num) => {
|
|
206
|
+
if (str !== undefined)
|
|
207
|
+
return full; // inside a quoted string
|
|
208
|
+
const kw = keyword.toUpperCase();
|
|
209
|
+
const factor = kw === 'IFCAREAMEASURE' ? areaFactor
|
|
210
|
+
: kw === 'IFCVOLUMEMEASURE' ? volumeFactor
|
|
211
|
+
: lengthFactor; // any *LENGTHMEASURE
|
|
212
|
+
return `${delim}${keyword}(${scaleMeasureNumber(num, factor)})`;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/** Scale the numeric content of one typed-measure token, preserving non-numeric ($) content. */
|
|
216
|
+
function scaleMeasureNumber(num, factor) {
|
|
217
|
+
const trimmed = num.trim();
|
|
218
|
+
const n = Number(trimmed);
|
|
219
|
+
if (trimmed === '' || !Number.isFinite(n))
|
|
220
|
+
return num;
|
|
221
|
+
return toStepRealScaled(n * factor);
|
|
222
|
+
}
|
|
223
|
+
/** Scale a single scalar attribute token by `factor` (skips `$`/`*`/non-bare-number). */
|
|
224
|
+
function scaleScalarArg(arg, factor) {
|
|
225
|
+
const trimmed = arg.trim();
|
|
226
|
+
if (trimmed === '' || trimmed === '$' || trimmed === '*')
|
|
227
|
+
return arg;
|
|
228
|
+
const n = Number(trimmed);
|
|
229
|
+
// Only a bare real is a directly-typed length; a typed token (IFC…MEASURE(…))
|
|
230
|
+
// is left to the measure pass, so it is never scaled twice.
|
|
231
|
+
if (!Number.isFinite(n))
|
|
232
|
+
return arg;
|
|
233
|
+
return toStepRealScaled(n * factor);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Locate the outer STEP argument list of one entity line: the first `(` (nothing
|
|
237
|
+
* is quoted before the type name) and its matching `)`, honouring quoted strings
|
|
238
|
+
* (with the `''` escape) so a literal `)` inside a string never closes early.
|
|
239
|
+
* Returns `null` for a line without arguments.
|
|
240
|
+
*/
|
|
241
|
+
function findOuterArgs(line) {
|
|
242
|
+
const open = line.indexOf('(');
|
|
243
|
+
if (open === -1)
|
|
244
|
+
return null;
|
|
245
|
+
let depth = 0;
|
|
246
|
+
let inString = false;
|
|
247
|
+
for (let i = open; i < line.length; i++) {
|
|
248
|
+
const ch = line[i];
|
|
249
|
+
if (inString) {
|
|
250
|
+
if (ch === "'") {
|
|
251
|
+
if (line[i + 1] === "'")
|
|
252
|
+
i++; // escaped quote
|
|
253
|
+
else
|
|
254
|
+
inString = false;
|
|
255
|
+
}
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (ch === "'") {
|
|
259
|
+
inString = true;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (ch === '(')
|
|
263
|
+
depth++;
|
|
264
|
+
else if (ch === ')') {
|
|
265
|
+
depth--;
|
|
266
|
+
if (depth === 0)
|
|
267
|
+
return { open, close: i };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Rescale every length/area/volume-valued datum of one STEP entity line.
|
|
274
|
+
*
|
|
275
|
+
* `typeUpper` is the entity's uppercase STEP type (used for the schema-derived
|
|
276
|
+
* plan). The line is expected to be a single `#id=TYPE(...);` statement. Returns
|
|
277
|
+
* the input unchanged when all factors are `1`, the type is excluded (unit
|
|
278
|
+
* definition / georeferencing), or there is nothing to scale.
|
|
279
|
+
*/
|
|
280
|
+
export function rescaleEntityLengths(line, typeUpper, lengthFactor, areaFactor, volumeFactor) {
|
|
281
|
+
if (lengthFactor === 1 && areaFactor === 1 && volumeFactor === 1)
|
|
282
|
+
return line;
|
|
283
|
+
if (!Number.isFinite(lengthFactor) || !Number.isFinite(areaFactor) || !Number.isFinite(volumeFactor))
|
|
284
|
+
return line;
|
|
285
|
+
if (isRescaleExcluded(typeUpper))
|
|
286
|
+
return line;
|
|
287
|
+
const plan = getEntityLengthPlan(typeUpper);
|
|
288
|
+
const hasStructural = plan.listIdx.length > 0 || plan.scalarIdx.length > 0
|
|
289
|
+
|| plan.areaIdx.length > 0 || plan.volumeIdx.length > 0;
|
|
290
|
+
// Fast path: nothing structural, no unit override to weigh, and no typed measure.
|
|
291
|
+
if (!hasStructural && plan.unitGuardIdx.length === 0 && !line.includes('MEASURE'))
|
|
292
|
+
return line;
|
|
293
|
+
const bounds = findOuterArgs(line);
|
|
294
|
+
if (!bounds)
|
|
295
|
+
return line;
|
|
296
|
+
let inner = line.slice(bounds.open + 1, bounds.close);
|
|
297
|
+
let skipValues = false;
|
|
298
|
+
if (hasStructural || plan.unitGuardIdx.length > 0) {
|
|
299
|
+
const args = splitTopLevelStepArguments(inner);
|
|
300
|
+
// A live unit-override reference means the value is already in its own unit.
|
|
301
|
+
skipValues = plan.unitGuardIdx.some((idx) => {
|
|
302
|
+
const u = args[idx]?.trim();
|
|
303
|
+
return u !== undefined && u !== '' && u !== '$' && u !== '*';
|
|
304
|
+
});
|
|
305
|
+
if (!skipValues && hasStructural) {
|
|
306
|
+
for (const idx of plan.listIdx) {
|
|
307
|
+
if (args[idx] !== undefined)
|
|
308
|
+
args[idx] = scaleNumberLiterals(args[idx], lengthFactor);
|
|
309
|
+
}
|
|
310
|
+
for (const idx of plan.scalarIdx) {
|
|
311
|
+
if (args[idx] !== undefined)
|
|
312
|
+
args[idx] = scaleScalarArg(args[idx], lengthFactor);
|
|
313
|
+
}
|
|
314
|
+
for (const idx of plan.areaIdx) {
|
|
315
|
+
if (args[idx] !== undefined)
|
|
316
|
+
args[idx] = scaleScalarArg(args[idx], areaFactor);
|
|
317
|
+
}
|
|
318
|
+
for (const idx of plan.volumeIdx) {
|
|
319
|
+
if (args[idx] !== undefined)
|
|
320
|
+
args[idx] = scaleScalarArg(args[idx], volumeFactor);
|
|
321
|
+
}
|
|
322
|
+
inner = args.join(',');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Typed measures live in property/quantity value slots (an IfcValue SELECT is
|
|
326
|
+
// written with its explicit type). Skipped when the entity declares its own unit.
|
|
327
|
+
if (!skipValues && inner.includes('MEASURE')) {
|
|
328
|
+
inner = scaleTypedMeasures(inner, lengthFactor, areaFactor, volumeFactor);
|
|
329
|
+
}
|
|
330
|
+
return line.slice(0, bounds.open + 1) + inner + line.slice(bounds.close);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Factor that converts a value expressed in `modelScale` units into `primaryScale`
|
|
334
|
+
* units (both are SI-per-unit for the same dimension). Returns `1` when the units
|
|
335
|
+
* already match or either scale is non-positive/non-finite.
|
|
336
|
+
*/
|
|
337
|
+
export function computeNormalizeFactor(modelScale, primaryScale) {
|
|
338
|
+
if (!Number.isFinite(modelScale) || !Number.isFinite(primaryScale))
|
|
339
|
+
return 1;
|
|
340
|
+
if (modelScale <= 0 || primaryScale <= 0)
|
|
341
|
+
return 1;
|
|
342
|
+
if (modelScale === primaryScale)
|
|
343
|
+
return 1;
|
|
344
|
+
return modelScale / primaryScale;
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=unit-normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-normalize.js","sourceRoot":"","sources":["../src/unit-normalize.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/export",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Export formats for IFC-Lite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
"parquet-wasm": "^0.7.1",
|
|
17
17
|
"apache-arrow": "^21.1.0",
|
|
18
18
|
"jszip": "^3.10.0",
|
|
19
|
-
"@ifc-lite/geometry": "^
|
|
20
|
-
"@ifc-lite/data": "^2.
|
|
21
|
-
"@ifc-lite/encoding": "^1.14.
|
|
22
|
-
"@ifc-lite/parser": "^3.5.
|
|
19
|
+
"@ifc-lite/geometry": "^3.0.0",
|
|
20
|
+
"@ifc-lite/data": "^2.3.0",
|
|
21
|
+
"@ifc-lite/encoding": "^1.14.8",
|
|
22
|
+
"@ifc-lite/parser": "^3.5.2",
|
|
23
23
|
"@ifc-lite/mutations": "^1.17.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"typescript": "^6.0.3",
|
|
27
27
|
"vitest": "^4.1.9",
|
|
28
|
-
"@ifc-lite/ifcx": "^2.1.
|
|
28
|
+
"@ifc-lite/ifcx": "^2.1.6"
|
|
29
29
|
},
|
|
30
30
|
"license": "MPL-2.0",
|
|
31
31
|
"author": "Louis True",
|