@ifc-lite/create 2.4.0 → 2.6.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/ifc-creator-cost.d.ts +118 -0
- package/dist/ifc-creator-cost.d.ts.map +1 -0
- package/dist/ifc-creator-cost.js +337 -0
- package/dist/ifc-creator-cost.js.map +1 -0
- package/dist/ifc-creator-definitions.d.ts +21 -0
- package/dist/ifc-creator-definitions.d.ts.map +1 -0
- package/dist/ifc-creator-definitions.js +56 -0
- package/dist/ifc-creator-definitions.js.map +1 -0
- package/dist/ifc-creator-math.d.ts +29 -1
- package/dist/ifc-creator-math.d.ts.map +1 -1
- package/dist/ifc-creator-math.js +78 -0
- package/dist/ifc-creator-math.js.map +1 -1
- package/dist/ifc-creator-scheduling.d.ts +27 -0
- package/dist/ifc-creator-scheduling.d.ts.map +1 -0
- package/dist/ifc-creator-scheduling.js +131 -0
- package/dist/ifc-creator-scheduling.js.map +1 -0
- package/dist/ifc-creator.d.ts +46 -8
- package/dist/ifc-creator.d.ts.map +1 -1
- package/dist/ifc-creator.js +121 -126
- package/dist/ifc-creator.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types-cost.d.ts +134 -0
- package/dist/types-cost.d.ts.map +1 -0
- package/dist/types-cost.js +5 -0
- package/dist/types-cost.js.map +1 -0
- package/dist/types-scheduling.d.ts +169 -0
- package/dist/types-scheduling.d.ts.map +1 -0
- package/dist/types-scheduling.js +5 -0
- package/dist/types-scheduling.js.map +1 -0
- package/dist/types.d.ts +8 -96
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/ifc-creator.js
CHANGED
|
@@ -1,28 +1,12 @@
|
|
|
1
1
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
-
import { esc, stepLine, num, vecLen, vecNorm, vecCross, NON_ELEMENT_TYPES, assertPositiveFinite, assertFinitePoint3, } from './ifc-creator-math.js';
|
|
4
|
+
import { esc, stepLine, num, vecLen, vecNorm, vecCross, optStr, optEnum, NON_ELEMENT_TYPES, assertPositiveFinite, assertFinitePoint3, } from './ifc-creator-math.js';
|
|
5
|
+
import { emitWorkCalendar, emitTaskTime } from './ifc-creator-scheduling.js';
|
|
6
|
+
import { assertCostSchema, emitCostItem, emitCostSchedule, emitCostValue, emitMeasureWithUnit, emitMonetaryUnit, emitPhysicalQuantity, emitRelAssignsToProduct, emitSIUnit, } from './ifc-creator-cost.js';
|
|
7
|
+
import { emitElementQuantity, emitPropertySet } from './ifc-creator-definitions.js';
|
|
5
8
|
import { generateIfcGuid, isValidIfcGuid } from '@ifc-lite/encoding';
|
|
6
9
|
// ============================================================================
|
|
7
|
-
// STEP attribute helpers (scheduling — optional strings / enums / numbers)
|
|
8
|
-
// ============================================================================
|
|
9
|
-
/** Emit an optional STEP string: `'value'` when present, `$` otherwise. */
|
|
10
|
-
function optStr(v) {
|
|
11
|
-
return v === undefined || v === null || v === '' ? '$' : `'${esc(v)}'`;
|
|
12
|
-
}
|
|
13
|
-
/** Emit an optional STEP enum: `.VALUE.` when present, `$` otherwise. */
|
|
14
|
-
function optEnum(v) {
|
|
15
|
-
return v === undefined || v === null || v === '' ? '$' : `.${v}.`;
|
|
16
|
-
}
|
|
17
|
-
/** Emit an optional STEP boolean: `.T.`/`.F.`/`$`. */
|
|
18
|
-
function optBool(v) {
|
|
19
|
-
return v === undefined || v === null ? '$' : v ? '.T.' : '.F.';
|
|
20
|
-
}
|
|
21
|
-
/** Emit an optional STEP real number; `$` when absent. */
|
|
22
|
-
function optReal(v) {
|
|
23
|
-
return v === undefined || v === null || !Number.isFinite(v) ? '$' : num(v);
|
|
24
|
-
}
|
|
25
|
-
// ============================================================================
|
|
26
10
|
// IfcCreator
|
|
27
11
|
// ============================================================================
|
|
28
12
|
/**
|
|
@@ -854,7 +838,6 @@ export class IfcCreator {
|
|
|
854
838
|
const name = params.Name ?? 'Space';
|
|
855
839
|
const desc = params.Description ? `'${esc(params.Description)}'` : '$';
|
|
856
840
|
const objType = params.ObjectType ? `'${esc(params.ObjectType)}'` : '$';
|
|
857
|
-
const tag = params.Tag ? `'${esc(params.Tag)}'` : '$';
|
|
858
841
|
const longName = params.LongName ? `'${esc(params.LongName)}'` : '$';
|
|
859
842
|
this.line(spaceId, 'IFCSPACE', `'${globalId}',#${this.ownerHistoryId},'${esc(name)}',${desc},${objType},#${placementId},#${prodShapeId},${longName},.ELEMENT.,.INTERNAL.,$`);
|
|
860
843
|
this.elementSolids.set(spaceId, [solidId]);
|
|
@@ -1198,39 +1181,16 @@ export class IfcCreator {
|
|
|
1198
1181
|
// ============================================================================
|
|
1199
1182
|
/** Attach a property set to an element */
|
|
1200
1183
|
addIfcPropertySet(elementId, pset) {
|
|
1201
|
-
|
|
1202
|
-
for (const prop of pset.Properties) {
|
|
1203
|
-
const propId = this.id();
|
|
1204
|
-
const valueStr = this.serializePropertyValue(prop);
|
|
1205
|
-
this.line(propId, 'IFCPROPERTYSINGLEVALUE', `'${esc(prop.Name)}',$,${valueStr},$`);
|
|
1206
|
-
propIds.push(propId);
|
|
1207
|
-
}
|
|
1208
|
-
const psetId = this.id();
|
|
1209
|
-
const globalId = this.newGlobalId();
|
|
1210
|
-
const refs = propIds.map(id => `#${id}`).join(',');
|
|
1211
|
-
this.line(psetId, 'IFCPROPERTYSET', `'${globalId}',#${this.ownerHistoryId},'${esc(pset.Name)}',$,(${refs})`);
|
|
1212
|
-
const relId = this.id();
|
|
1213
|
-
const relGlobalId = this.newGlobalId();
|
|
1214
|
-
this.line(relId, 'IFCRELDEFINESBYPROPERTIES', `'${relGlobalId}',#${this.ownerHistoryId},$,$,(#${elementId}),#${psetId}`);
|
|
1215
|
-
return psetId;
|
|
1184
|
+
return emitPropertySet(elementId, pset, this.definitionContext());
|
|
1216
1185
|
}
|
|
1217
1186
|
/** Attach element quantities to an element */
|
|
1218
1187
|
addIfcElementQuantity(elementId, qset) {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
}
|
|
1226
|
-
const qsetId = this.id();
|
|
1227
|
-
const globalId = this.newGlobalId();
|
|
1228
|
-
const refs = qtyIds.map(id => `#${id}`).join(',');
|
|
1229
|
-
this.line(qsetId, 'IFCELEMENTQUANTITY', `'${globalId}',#${this.ownerHistoryId},'${esc(qset.Name)}',$,$,(${refs})`);
|
|
1230
|
-
const relId = this.id();
|
|
1231
|
-
const relGlobalId = this.newGlobalId();
|
|
1232
|
-
this.line(relId, 'IFCRELDEFINESBYPROPERTIES', `'${relGlobalId}',#${this.ownerHistoryId},$,$,(#${elementId}),#${qsetId}`);
|
|
1233
|
-
return qsetId;
|
|
1188
|
+
return emitElementQuantity(elementId, qset, this.definitionContext());
|
|
1189
|
+
}
|
|
1190
|
+
/** The creator hooks `ifc-creator-definitions.ts`'s emitters need. */
|
|
1191
|
+
definitionContext() {
|
|
1192
|
+
return { emit: this.emitEntity, newGlobalId: () => this.newGlobalId(),
|
|
1193
|
+
ownerRef: `#${this.ownerHistoryId}`, ifc4Only: (v) => this.ifc4Only(v) };
|
|
1234
1194
|
}
|
|
1235
1195
|
// ============================================================================
|
|
1236
1196
|
// Public API — Styling
|
|
@@ -1283,7 +1243,7 @@ export class IfcCreator {
|
|
|
1283
1243
|
this.elementMaterials.set(elementId, materialRefId);
|
|
1284
1244
|
}
|
|
1285
1245
|
// ============================================================================
|
|
1286
|
-
// Public API — Scheduling / 4D (IfcWorkSchedule, IfcTask, IfcRelSequence)
|
|
1246
|
+
// Public API — Scheduling / 4D (IfcWorkSchedule, IfcTask, IfcRelSequence, IfcWorkCalendar)
|
|
1287
1247
|
// ============================================================================
|
|
1288
1248
|
/**
|
|
1289
1249
|
* Create an IfcWorkSchedule. Returns its expressId for assigning tasks
|
|
@@ -1299,6 +1259,32 @@ export class IfcCreator {
|
|
|
1299
1259
|
addIfcWorkPlan(params) {
|
|
1300
1260
|
return this.buildWorkControl('IFCWORKPLAN', params);
|
|
1301
1261
|
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Create an IfcWorkCalendar — the working / non-working time calendar an
|
|
1264
|
+
* IfcTask or IfcWorkSchedule can be assigned to. `WorkingTimes` /
|
|
1265
|
+
* `ExceptionTimes` entries become nested IfcWorkTime entities (with their
|
|
1266
|
+
* IfcRecurrencePattern / IfcTimePeriod when the entry carries a
|
|
1267
|
+
* recurrence), the same way `addIfcTask` emits its IfcTaskTime. Assign it
|
|
1268
|
+
* with `assignCalendarToTasks`. Returns the calendar expressId.
|
|
1269
|
+
*/
|
|
1270
|
+
addIfcWorkCalendar(params) {
|
|
1271
|
+
if (this.schema === 'IFC2X3') {
|
|
1272
|
+
throw new Error('addIfcWorkCalendar is not supported for IFC2X3');
|
|
1273
|
+
}
|
|
1274
|
+
const id = emitWorkCalendar(params, this.newGlobalId(), `#${this.ownerHistoryId}`, this.emitEntity);
|
|
1275
|
+
this.entities.push({ expressId: id, type: 'IfcWorkCalendar', Name: params.Name });
|
|
1276
|
+
return id;
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Allocate an express id, write its STEP line, and hand the id back — the
|
|
1280
|
+
* one hook `ifc-creator-scheduling.ts`'s emitters need from the creator.
|
|
1281
|
+
* An arrow property so it can be passed by reference without binding.
|
|
1282
|
+
*/
|
|
1283
|
+
emitEntity = (type, attrs) => {
|
|
1284
|
+
const entityId = this.id();
|
|
1285
|
+
this.line(entityId, type, attrs);
|
|
1286
|
+
return entityId;
|
|
1287
|
+
};
|
|
1302
1288
|
/**
|
|
1303
1289
|
* Create an IfcTask. If any Schedule/Actual/Early/Late time field, IsCritical,
|
|
1304
1290
|
* or Completion attribute is present, an IfcTaskTime is created and linked.
|
|
@@ -1322,7 +1308,7 @@ export class IfcCreator {
|
|
|
1322
1308
|
params.IsCritical !== undefined ||
|
|
1323
1309
|
params.DurationType !== undefined ||
|
|
1324
1310
|
params.Completion !== undefined;
|
|
1325
|
-
const taskTimeId = hasTaskTime ? this.
|
|
1311
|
+
const taskTimeId = hasTaskTime ? emitTaskTime(params, this.emitEntity) : 0;
|
|
1326
1312
|
const taskId = this.id();
|
|
1327
1313
|
const globalId = this.newGlobalId();
|
|
1328
1314
|
const name = params.Name;
|
|
@@ -1340,43 +1326,6 @@ export class IfcCreator {
|
|
|
1340
1326
|
this.entities.push({ expressId: taskId, type: 'IfcTask', Name: name });
|
|
1341
1327
|
return taskId;
|
|
1342
1328
|
}
|
|
1343
|
-
/**
|
|
1344
|
-
* Build an IfcTaskTime from the task params (internal helper — prefer
|
|
1345
|
-
* setting the time fields on the task itself via `addIfcTask`).
|
|
1346
|
-
*/
|
|
1347
|
-
addIfcTaskTime(params) {
|
|
1348
|
-
const ttId = this.id();
|
|
1349
|
-
// [0] Name, [1] DataOrigin, [2] UserDefinedDataOrigin,
|
|
1350
|
-
// [3] DurationType, [4] ScheduleDuration, [5] ScheduleStart, [6] ScheduleFinish,
|
|
1351
|
-
// [7..10] Early/Late Start/Finish, [11] FreeFloat, [12] TotalFloat,
|
|
1352
|
-
// [13] IsCritical, [14] StatusTime,
|
|
1353
|
-
// [15] ActualDuration, [16] ActualStart, [17] ActualFinish,
|
|
1354
|
-
// [18] RemainingTime, [19] Completion
|
|
1355
|
-
const attrs = [
|
|
1356
|
-
'$', // Name
|
|
1357
|
-
'$', // DataOrigin
|
|
1358
|
-
'$', // UserDefinedDataOrigin
|
|
1359
|
-
optEnum(params.DurationType), // DurationType
|
|
1360
|
-
optStr(params.ScheduleDuration), // ScheduleDuration
|
|
1361
|
-
optStr(params.ScheduleStart), // ScheduleStart
|
|
1362
|
-
optStr(params.ScheduleFinish), // ScheduleFinish
|
|
1363
|
-
optStr(params.EarlyStart), // EarlyStart
|
|
1364
|
-
optStr(params.EarlyFinish), // EarlyFinish
|
|
1365
|
-
optStr(params.LateStart), // LateStart
|
|
1366
|
-
optStr(params.LateFinish), // LateFinish
|
|
1367
|
-
optStr(params.FreeFloat), // FreeFloat
|
|
1368
|
-
optStr(params.TotalFloat), // TotalFloat
|
|
1369
|
-
optBool(params.IsCritical), // IsCritical
|
|
1370
|
-
optStr(params.StatusTime), // StatusTime
|
|
1371
|
-
optStr(params.ActualDuration), // ActualDuration
|
|
1372
|
-
optStr(params.ActualStart), // ActualStart
|
|
1373
|
-
optStr(params.ActualFinish), // ActualFinish
|
|
1374
|
-
optStr(params.RemainingTime), // RemainingTime
|
|
1375
|
-
optReal(params.Completion), // Completion
|
|
1376
|
-
];
|
|
1377
|
-
this.line(ttId, 'IFCTASKTIME', attrs.join(','));
|
|
1378
|
-
return ttId;
|
|
1379
|
-
}
|
|
1380
1329
|
/**
|
|
1381
1330
|
* Create an IfcRelSequence between two tasks. The predecessor is `RelatingProcess`
|
|
1382
1331
|
* and the successor is `RelatedProcess`. SequenceType defaults to FINISH_START.
|
|
@@ -1427,6 +1376,15 @@ export class IfcCreator {
|
|
|
1427
1376
|
assignSchedulesToWorkPlan(planId, scheduleIds) {
|
|
1428
1377
|
return this.addIfcRelAssignsToControl(planId, scheduleIds);
|
|
1429
1378
|
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Ergonomic alias — assign an IfcWorkCalendar to tasks (or work
|
|
1381
|
+
* schedules; same relation either way). Delegates to
|
|
1382
|
+
* {@link addIfcRelAssignsToControl}, which accepts a calendar because
|
|
1383
|
+
* IfcWorkCalendar is an IfcControl.
|
|
1384
|
+
*/
|
|
1385
|
+
assignCalendarToTasks(calendarId, taskIds) {
|
|
1386
|
+
return this.addIfcRelAssignsToControl(calendarId, taskIds);
|
|
1387
|
+
}
|
|
1430
1388
|
/**
|
|
1431
1389
|
* Emit an IfcRelAssignsToProcess — binds products (walls, slabs, ...) to an
|
|
1432
1390
|
* IfcProcess (usually an IfcTask). These drive the Gantt 4D animation.
|
|
@@ -1462,6 +1420,68 @@ export class IfcCreator {
|
|
|
1462
1420
|
nestTasks(parentTaskId, childTaskIds) {
|
|
1463
1421
|
return this.addIfcRelNests(parentTaskId, childTaskIds);
|
|
1464
1422
|
}
|
|
1423
|
+
// Public API — Cost / 5D. Every method delegates to `ifc-creator-cost.ts` and refuses
|
|
1424
|
+
// IFC2X3 by name (its cost entity layout differs, so IFC4 records would parse and mislead).
|
|
1425
|
+
/** Create an IfcCostSchedule (IFC4 / IFC4X3 only). Returns its expressId. */
|
|
1426
|
+
addIfcCostSchedule(params) {
|
|
1427
|
+
assertCostSchema(this.schema, 'addIfcCostSchedule');
|
|
1428
|
+
const id = emitCostSchedule(params, this.newGlobalId(), `#${this.ownerHistoryId}`, this.emitEntity);
|
|
1429
|
+
this.entities.push({ expressId: id, type: 'IfcCostSchedule', Name: params.Name });
|
|
1430
|
+
return id;
|
|
1431
|
+
}
|
|
1432
|
+
/** Create an IfcCostItem (IFC4 / IFC4X3 only). Returns its expressId. */
|
|
1433
|
+
addIfcCostItem(params) {
|
|
1434
|
+
assertCostSchema(this.schema, 'addIfcCostItem');
|
|
1435
|
+
const id = emitCostItem(params, this.newGlobalId(), `#${this.ownerHistoryId}`, this.emitEntity);
|
|
1436
|
+
this.entities.push({ expressId: id, type: 'IfcCostItem', Name: params.Name });
|
|
1437
|
+
return id;
|
|
1438
|
+
}
|
|
1439
|
+
/** Create an IfcCostValue (IFC4 / IFC4X3 only). Returns its expressId. */
|
|
1440
|
+
addIfcCostValue(params) {
|
|
1441
|
+
assertCostSchema(this.schema, 'addIfcCostValue');
|
|
1442
|
+
const id = emitCostValue(params, this.schema, this.emitEntity);
|
|
1443
|
+
this.entities.push({ expressId: id, type: 'IfcCostValue', Name: params.Name });
|
|
1444
|
+
return id;
|
|
1445
|
+
}
|
|
1446
|
+
/** Create an IfcMonetaryUnit for `currency`. No default — omit it to leave the currency unstated. */
|
|
1447
|
+
addIfcMonetaryUnit(currency) {
|
|
1448
|
+
assertCostSchema(this.schema, 'addIfcMonetaryUnit');
|
|
1449
|
+
return emitMonetaryUnit(currency, this.emitEntity);
|
|
1450
|
+
}
|
|
1451
|
+
/** Create an IfcSIUnit, for use as an IfcMeasureWithUnit or quantity unit. */
|
|
1452
|
+
addIfcSIUnit(params) {
|
|
1453
|
+
assertCostSchema(this.schema, 'addIfcSIUnit');
|
|
1454
|
+
return emitSIUnit(params, this.emitEntity);
|
|
1455
|
+
}
|
|
1456
|
+
/** Create an IfcMeasureWithUnit — what a UnitBasis or entity-valued AppliedValue points at. */
|
|
1457
|
+
addIfcMeasureWithUnit(value, unitId) {
|
|
1458
|
+
assertCostSchema(this.schema, 'addIfcMeasureWithUnit');
|
|
1459
|
+
return emitMeasureWithUnit(value, unitId, this.schema, this.emitEntity);
|
|
1460
|
+
}
|
|
1461
|
+
/** Create a standalone IfcPhysicalSimpleQuantity for IfcCostItem.CostQuantities. */
|
|
1462
|
+
addIfcPhysicalQuantity(params) {
|
|
1463
|
+
assertCostSchema(this.schema, 'addIfcPhysicalQuantity');
|
|
1464
|
+
return emitPhysicalQuantity(params, this.schema, this.emitEntity);
|
|
1465
|
+
}
|
|
1466
|
+
/** Emit an IfcRelAssignsToProduct — see {@link emitRelAssignsToProduct} for the direction rule. */
|
|
1467
|
+
addIfcRelAssignsToProduct(relatingProductId, relatedObjectIds) {
|
|
1468
|
+
return emitRelAssignsToProduct(relatingProductId, relatedObjectIds, () => this.newGlobalId(), `#${this.ownerHistoryId}`, this.emitEntity);
|
|
1469
|
+
}
|
|
1470
|
+
// Ergonomic aliases over the canonical relationships: cost items under a
|
|
1471
|
+
// schedule, cost items pricing a product, tasks bound to a cost item (an
|
|
1472
|
+
// IfcCostItem is an IfcControl), and the cost breakdown hierarchy.
|
|
1473
|
+
assignCostItemsToSchedule(scheduleId, costItemIds) {
|
|
1474
|
+
return this.addIfcRelAssignsToControl(scheduleId, costItemIds);
|
|
1475
|
+
}
|
|
1476
|
+
assignCostItemsToProduct(productId, costItemIds) {
|
|
1477
|
+
return this.addIfcRelAssignsToProduct(productId, costItemIds);
|
|
1478
|
+
}
|
|
1479
|
+
assignTasksToCostItem(costItemId, taskIds) {
|
|
1480
|
+
return this.addIfcRelAssignsToControl(costItemId, taskIds);
|
|
1481
|
+
}
|
|
1482
|
+
nestCostItems(parentCostItemId, childCostItemIds) {
|
|
1483
|
+
return this.addIfcRelNests(parentCostItemId, childCostItemIds);
|
|
1484
|
+
}
|
|
1465
1485
|
/**
|
|
1466
1486
|
* Internal — emit an IfcWorkSchedule or IfcWorkPlan (identical attribute
|
|
1467
1487
|
* layout). Separate helpers are exposed publicly for ergonomics.
|
|
@@ -1559,7 +1579,7 @@ ENDSEC;
|
|
|
1559
1579
|
this.subContextAxis = this.id();
|
|
1560
1580
|
this.line(this.subContextAxis, 'IFCGEOMETRICREPRESENTATIONSUBCONTEXT', `$,'Axis',*,*,*,*,#${this.contextId},$,.GRAPH_VIEW.,$`);
|
|
1561
1581
|
// Units
|
|
1562
|
-
this.unitAssignmentId = this.buildUnits(params.LengthUnit ?? 'METRE');
|
|
1582
|
+
this.unitAssignmentId = this.buildUnits(params.LengthUnit ?? 'METRE', params.Currency);
|
|
1563
1583
|
// Default surface style — light grey with some specularity
|
|
1564
1584
|
this.defaultStyleId = this.buildDefaultStyle();
|
|
1565
1585
|
// IfcProject
|
|
@@ -1580,7 +1600,7 @@ ENDSEC;
|
|
|
1580
1600
|
this.line(this.buildingId, 'IFCBUILDING', `'${buildingGlobalId}',#${this.ownerHistoryId},'Building',$,$,#${this.worldPlacementId},$,$,.ELEMENT.,$,$,$`);
|
|
1581
1601
|
this.entities.push({ expressId: this.buildingId, type: 'IfcBuilding', Name: 'Building' });
|
|
1582
1602
|
}
|
|
1583
|
-
buildUnits(lengthUnit) {
|
|
1603
|
+
buildUnits(lengthUnit, currency) {
|
|
1584
1604
|
const dimExpId = this.id();
|
|
1585
1605
|
this.line(dimExpId, 'IFCDIMENSIONALEXPONENTS', '0,0,0,0,0,0,0');
|
|
1586
1606
|
const siLengthId = this.id();
|
|
@@ -1597,8 +1617,15 @@ ENDSEC;
|
|
|
1597
1617
|
this.line(siVolumeId, 'IFCSIUNIT', `*,.VOLUMEUNIT.,$,.CUBIC_METRE.`);
|
|
1598
1618
|
const siAngleId = this.id();
|
|
1599
1619
|
this.line(siAngleId, 'IFCSIUNIT', `*,.PLANEANGLEUNIT.,$,.RADIAN.`);
|
|
1620
|
+
// Absent currency stays absent: no IfcMonetaryUnit is written at all, so
|
|
1621
|
+
// the cost read model reports no project currency rather than a guess.
|
|
1622
|
+
const units = [lengthUnitId, siAreaId, siVolumeId, siAngleId];
|
|
1623
|
+
if (currency !== undefined) {
|
|
1624
|
+
assertCostSchema(this.schema, 'ProjectParams.Currency'); // IFC2X3 Currency is an enum
|
|
1625
|
+
units.push(emitMonetaryUnit(currency, this.emitEntity));
|
|
1626
|
+
}
|
|
1600
1627
|
const assignmentId = this.id();
|
|
1601
|
-
this.line(assignmentId, 'IFCUNITASSIGNMENT', `(
|
|
1628
|
+
this.line(assignmentId, 'IFCUNITASSIGNMENT', `(${units.map(id => `#${id}`).join(',')})`);
|
|
1602
1629
|
return assignmentId;
|
|
1603
1630
|
}
|
|
1604
1631
|
/** Create a default IfcSurfaceStyle with a neutral colour (RGB 0.75, 0.73, 0.68) */
|
|
@@ -2138,40 +2165,8 @@ ENDSEC;
|
|
|
2138
2165
|
this.entities.push({ expressId: openingId, type: 'IfcOpeningElement', Name: name });
|
|
2139
2166
|
return openingId;
|
|
2140
2167
|
}
|
|
2141
|
-
//
|
|
2142
|
-
// Internal — Property/quantity serialization
|
|
2143
|
-
// ============================================================================
|
|
2144
|
-
serializePropertyValue(prop) {
|
|
2145
|
-
const val = prop.NominalValue;
|
|
2146
|
-
if (typeof val === 'string') {
|
|
2147
|
-
const typeName = prop.Type ?? 'IfcLabel';
|
|
2148
|
-
return `${typeName.toUpperCase()}('${esc(val)}')`;
|
|
2149
|
-
}
|
|
2150
|
-
if (typeof val === 'number') {
|
|
2151
|
-
const typeName = prop.Type ?? (Number.isInteger(val) ? 'IfcInteger' : 'IfcReal');
|
|
2152
|
-
return typeName === 'IfcInteger' ? `IFCINTEGER(${Math.round(val)})` : `IFCREAL(${num(val)})`;
|
|
2153
|
-
}
|
|
2154
|
-
if (typeof val === 'boolean') {
|
|
2155
|
-
// `Type: 'IfcLogical'` (tri-state) must not be downgraded to IFCBOOLEAN.
|
|
2156
|
-
const typeName = prop.Type === 'IfcLogical' ? 'IFCLOGICAL' : 'IFCBOOLEAN';
|
|
2157
|
-
return `${typeName}(${val ? '.T.' : '.F.'})`;
|
|
2158
|
-
}
|
|
2159
|
-
return '$';
|
|
2160
|
-
}
|
|
2168
|
+
// `serializePropertyValue` / `quantityValueField` moved to `ifc-creator-math.ts`.
|
|
2161
2169
|
ifc4Only(v) { return this.schema === 'IFC2X3' ? '' : `,${v}`; } // trailing IFC4/4X3-only attribute
|
|
2162
|
-
quantityValueField(qty) {
|
|
2163
|
-
switch (qty.Kind) {
|
|
2164
|
-
case 'IfcQuantityLength':
|
|
2165
|
-
case 'IfcQuantityArea':
|
|
2166
|
-
case 'IfcQuantityVolume':
|
|
2167
|
-
case 'IfcQuantityWeight':
|
|
2168
|
-
return `$,${num(qty.Value)}`;
|
|
2169
|
-
case 'IfcQuantityCount':
|
|
2170
|
-
return `$,${Math.round(qty.Value)}`;
|
|
2171
|
-
default:
|
|
2172
|
-
return `$,${num(qty.Value)}`;
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
2170
|
// ============================================================================
|
|
2176
2171
|
// Internal — Relationship finalization
|
|
2177
2172
|
// ============================================================================
|