export {} // module boundary (stripped by transpiler) // ── MEP Equipment Schedule ────────────────────────────────────────────── // Stakeholder: HVAC / MEP Engineer // // Discovers all MEP/distribution elements in the model, extracts their // properties (manufacturer, model, capacity, pressure, flow rate), and // generates a structured equipment register. The UI's property panel // shows one element at a time — this script scans hundreds of elements // and builds the schedule that would otherwise require a spreadsheet. // ───────────────────────────────────────────────────────────────────────── // ── 1. Query all MEP-related IFC types ────────────────────────────────── const MEP_TYPES = [ // HVAC 'IfcAirTerminal', 'IfcAirTerminalBox', 'IfcFan', 'IfcCoil', 'IfcCompressor', 'IfcCondenser', 'IfcCooledBeam', 'IfcCoolingTower', 'IfcEvaporativeCooler', 'IfcEvaporator', 'IfcHeatExchanger', 'IfcHumidifier', 'IfcUnitaryEquipment', 'IfcBoiler', 'IfcChiller', 'IfcAirToAirHeatRecovery', // Plumbing 'IfcSanitaryTerminal', 'IfcWasteTerminal', 'IfcFireSuppressionTerminal', 'IfcTank', 'IfcPump', 'IfcValve', // Electrical 'IfcElectricDistributionBoard', 'IfcElectricGenerator', 'IfcElectricMotor', 'IfcTransformer', 'IfcSwitchingDevice', 'IfcOutlet', 'IfcLightFixture', 'IfcLamp', 'IfcJunctionBox', // Generic distribution 'IfcDistributionElement', 'IfcDistributionControlElement', 'IfcDistributionFlowElement', 'IfcFlowTerminal', 'IfcFlowMovingDevice', 'IfcFlowController', 'IfcFlowStorageDevice', 'IfcFlowTreatmentDevice', 'IfcFlowFitting', 'IfcFlowSegment', 'IfcEnergyConversionDevice', // Segments 'IfcDuctSegment', 'IfcPipeSegment', 'IfcCableCarrierSegment', 'IfcCableSegment', 'IfcDuctFitting', 'IfcPipeFitting', 'IfcCableCarrierFitting', // Furnishing (often used for MEP equipment in some models) 'IfcFurnishingElement', ] const elements = bim.query.byType(...MEP_TYPES) if (elements.length === 0) { // Fall back: show what types ARE in the model so user can adapt console.warn('No standard MEP element types found.') console.log('') console.log('Available types in this model:') const all = bim.query.all() const types: Record = {} for (const e of all) types[e.Type] = (types[e.Type] || 0) + 1 for (const [t, c] of Object.entries(types).sort((a, b) => b[1] - a[1])) { console.log(' ' + t + ': ' + c) } console.log('') console.log('Tip: edit MEP_TYPES at top of script to match your model\'s types.') throw new Error('no MEP elements') } // ── 2. Group by IFC type ──────────────────────────────────────────────── const byType: Record = {} for (const e of elements) { if (!byType[e.Type]) byType[e.Type] = [] byType[e.Type].push(e) } console.log('═══════════════════════════════════════') console.log(' MEP EQUIPMENT SCHEDULE') console.log('═══════════════════════════════════════') console.log('') console.log('Found ' + elements.length + ' MEP elements across ' + Object.keys(byType).length + ' types') // ── 3. Extract properties for each type ───────────────────────────────── // Properties of interest for MEP equipment const MEP_PROPS = [ 'manufacturer', 'model', 'reference', 'status', 'capacity', 'power', 'voltage', 'current', 'frequency', 'flowrate', 'pressure', 'temperature', 'nominalcapacity', 'nominalpower', ] interface EquipmentEntry { entity: BimEntity props: Record } const schedule: Record = {} // Collect all unique property paths for CSV export columns const propertyColumns = new Set() for (const [type, entities] of Object.entries(byType).sort((a, b) => b[1].length - a[1].length)) { schedule[type] = [] // Cap property extraction at 200 per type const sample = entities.length > 200 ? entities.slice(0, 200) : entities for (const entity of sample) { const entry: EquipmentEntry = { entity, props: {} } const psets = bim.query.properties(entity) for (const pset of psets) { for (const p of pset.properties) { const lower = p.name.toLowerCase() if (MEP_PROPS.some(k => lower.includes(k)) && p.value !== null && p.value !== '') { const path = pset.name + '.' + p.name entry.props[path] = p.value propertyColumns.add(path) } } } schedule[type].push(entry) } } // ── 4. Print schedule ─────────────────────────────────────────────────── for (const [type, entries] of Object.entries(schedule).sort((a, b) => b[1].length - a[1].length)) { console.log('') console.log('── ' + type + ' (' + byType[type].length + ') ──') // Collect all property keys found in this type const allKeys = new Set() for (const entry of entries) { for (const key of Object.keys(entry.props)) allKeys.add(key) } if (allKeys.size === 0) { // Show name grouping even without properties const names: Record = {} for (const entry of entries) { const key = entry.entity.Name || entry.entity.ObjectType || '' names[key] = (names[key] || 0) + 1 } for (const [name, count] of Object.entries(names).sort((a, b) => b[1] - a[1])) { console.log(' ' + name + (count > 1 ? ' (x' + count + ')' : '')) } } else { // Show first 10 entries with their properties for (const entry of entries.slice(0, 10)) { const label = entry.entity.Name || entry.entity.ObjectType || '' console.log(' ' + label) for (const [key, value] of Object.entries(entry.props)) { console.log(' ' + key + ' = ' + value) } } if (entries.length > 10) console.log(' ... and ' + (entries.length - 10) + ' more') } } // ── 5. Color-code by system type ──────────────────────────────────────── const palette = [ '#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#34495e', ] const batches: Array<{ entities: BimEntity[]; color: string }> = [] let colorIdx = 0 for (const [type, entities] of Object.entries(byType).sort((a, b) => b[1].length - a[1].length)) { batches.push({ entities, color: palette[colorIdx % palette.length] }) colorIdx++ } bim.viewer.colorizeAll(batches) bim.viewer.isolate(elements) // ── 6. Summary ────────────────────────────────────────────────────────── console.log('') console.log('── Type Summary ──') for (const [type, entities] of Object.entries(byType).sort((a, b) => b[1].length - a[1].length)) { const color = palette[(Object.keys(byType).sort((a, b) => byType[b].length - byType[a].length).indexOf(type)) % palette.length] console.log(' ' + type + ': ' + entities.length + ' ● ' + color) } // ── 7. Export ──────────────────────────────────────────────────────────── const propCols = Array.from(propertyColumns).sort() bim.export.csv(elements, { columns: ['Name', 'Type', 'ObjectType', 'GlobalId', 'Description', ...propCols], filename: 'mep-equipment-schedule.csv' }) console.log('') console.log('Exported ' + elements.length + ' MEP elements (' + (5 + propCols.length) + ' columns) to mep-equipment-schedule.csv') console.log('Elements are isolated and color-coded by type in 3D view')