ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

IFC 建筑模型转 Pascal 场景图:ifc-converter 的架构、转换流程与实战指南

2026/9/12 8:41:53 拓冰建站 浏览量
IFC 建筑模型转 Pascal 场景图:ifc-converter 的架构、转换流程与实战指南 IFC 建筑模型转 Pascal 场景图ifc-converter 的架构、转换流程与实战指南【免费下载链接】editorOpen-source 3D architectural editor with a local CLI, MCP tools, and practical workflows for humans and AI agents.项目地址: https://gitcode.com/GitHub_Trending/editor93/editor导读本文围绕apps/ifc-converter这个 Web 应用展开讲解如何把 IFCIndustry Foundation Classes建筑模型转换为 Pascal 场景图 JSON并在真实pascal-app/viewer中预览。读完本文你将掌握转换器前端应用与纯逻辑包的职责划分、IFC 到 Pascal 节点的一一映射规则墙/板/门/窗/楼梯/屋顶/柱、convertIfcToPascal的调用方式与转换选项、WASM 资源与示例模型的加载机制以及当前已知的转换局限与可参与的改进方向。项目定位从 IFC 到 Pascal 场景图的桥梁apps/ifc-converter/README.md对它的定义非常清晰这是一个把 IFC 建筑模型转换为 Pascal 场景图 JSON、并在真实pascal-app/viewer中预览结果的 Web 应用。用户拖入一个.ifc文件或从内置示例中选择一个即可检查提取出的元素并下载 JSON 加载到 Pascal 编辑器中继续编辑。整个方案被拆成两层职责非常干净纯转换逻辑包pascal-app/ifc-converterpackages/ifc-converter通过 web-ifc 解析 IFC把元素映射到来自pascal-app/core的 Pascal 节点 schema 上。无 DOM、无 React可在任何 JS 运行时中调用。Web 应用层apps/ifc-converter提供拖放上传区、示例选择器、元素搜索/过滤、3D 预览与 JSON 下载等 UI 能力。这种“逻辑包 薄 UI”的架构意味着转换核心可以被 CLI、脚本、Agent 或其他宿主环境直接复用而不被浏览器绑定。转换器整体工作流从源码看convertIfcToPascalpackages/ifc-converter/src/index.ts是核心入口整个转换过程按进度回调分为如下阶段进度阶段说明0%初始化创建WebIFC.IfcAPI实例并调用Init()加载 WASM10%打开模型OpenModel(ifcData)载入 Uint8Array 形式的 IFC 字节20%空间关系分析读取IFCRELAGGREGATES、IFCRELCONTAINEDINSPATIALSTRUCTURE构建父子关系映射探测长度单位换算因子计算场景原点偏移30%SiteIFCSITE→site节点40%BuildingIFCBUILDING→building节点50%LevelIFCBUILDINGSTOREY→level节点含标高解析60%WallIFCWALL/IFCWALLSTANDARDCASE→wall节点含轴线、厚度、高度提取—Door / Window通过 void/fill 关系链挂载到墙缺失关系时按最近墙投影回退—SlabIFCSLAB→slab节点轮廓多边形 标高—Stair / RoofIFCSTAIR/IFCROOF→ 占位节点包围盒/扁平多边形进 metadata—ColumnIFCCOLUMN/IFCCOLUMNSTANDARDCASE→column节点含截面形状识别—Beam / Item计数后跳过见下文局限—后处理解析levelId、属性集、材质、类型名IFCRELDEFINESBYPROPERTIES、IFCRELASSOCIATESMATERIAL、IFCRELDEFINESBYTYPE94%简化simplifyConvertedSceneGraph合并墙体碎片、去重洞口95%收尾CloseModel、构建PascalSceneGraph返回最终返回的结构为interface PascalSceneGraph { nodes: RecordAnyNodeId, AnyNode rootNodeIds: AnyNodeId[] collections?: Recordstring, unknown }nodes是 id 到节点的扁平映射rootNodeIds记录顶层节点site层级关系通过每个节点的parentId与children表达。单位换算与坐标变换转换的第一步IFC 文件可能使用毫米、英寸、英尺甚至自定义换算单位而 Pascal 场景统一以米为单位。getLengthUnitFactorpackages/ifc-converter/src/index.ts负责从IFCPROJECT.UnitsInContext中解析LENGTHUNIT米制前缀MILLI1e-3、CENTI1e-2、KILO1e3 等直接换算英制FOOT/FEET0.3048、INCH0.0254写死换算ConversionBasedUnit则读取ConversionFactor.ValueComponent作为因子解析失败时返回 1视为单位即米。坐标变换方面转换器实现了一套 4×4 矩阵栈identity/multiply/transformPoint3/buildAxis2Placement3DMatrixresolveWorldTransform会沿着PlacementRelTo链从根到叶逐级乘算把每个元素的局部ObjectPlacement解析为世界矩阵。此外为了把地理参考模型居中到原点附近转换器以第一个IFCSITE的放置原点作为originOffset所有世界坐标经worldToScene减去该偏移并乘以unitFactor后写入场景。各元素类型的映射规则Site / Building / LevelIFCSITE→site节点直接作为rootNodeIds根。转换器目前不读取 IFC 场地几何而是注入 PascalSiteNode要求的默认 30×30 属性线多边形源码中标注了TODO(ifc-fix): derive from IfcSite.SiteAddress or building footprints.。IFCBUILDING→building节点父节点为空间层级中的 site。IFCBUILDINGSTOREY→level节点。标高优先从放置链解析resolveWorldTransform后取 Z失败时回退到storey.Elevation * unitFactor并写入 metadata 的elevation字段。Wall墙墙是转换的核心难点处理流程为从Representation中寻找RepresentationIdentifier Axis的表示读取IFCPOLYLINE/IFCINDEXEDPOLYCURVE/IFCGEOMETRICSET得到轴线点列从而确定start/end从Body表示中读取IfcExtrudedAreaSolid的Depth按选项解释为高度或厚度、剖面XDim/YDim矩形剖面或Radius圆形剖面并支持沿BooleanClippingResult.FirstOperand链解包和MappedRepresentation展开若高度/厚度仍缺失常见于普通IFCWALL携带 Brep/映射几何的情况调用measureWallLocalExtents用GetFlatMesh读取网格顶点并把顶点投影到墙体自身轴线上测量沿轴/垂直/竖直三个方向的跨度——源码注释特别强调投影到真实轴线是旋转不变的而世界空间 AABB 会把旋转墙的长与厚混为一谈最后仍未解析出数值时回退到pascal-app/core的默认值DEFAULT_WALL_HEIGHT 2.5、DEFAULT_WALL_THICKNESS 0.1见 packages/core/src/systems/wall/wall-footprint.ts——这正是 README 所述“walls that default to a fixed height”的实现位置无法确定end的墙会被直接跳过。Door / Window门与窗门与窗的处理体现了 IFC 关系链的完整利用首选路径void/fill 关系链通过IFCRELVOIDSELEMENT墙→洞口与IFCRELFILLSELEMENT洞口→填充元素建立wall → opening → fill的映射。填充元素的OverallWidth/OverallHeight提供宽高洞口在世界空间的位置投影到墙轴线得到position沿墙距离并进行钳制避免 CSG 开洞溢出墙体外窗还会从洞口放置 Z 与墙基 Z 的差计算sillHeight暂存于 metadata。回退路径最近墙投影部分导出器如巴黎示例只写 void 不写 fill因此转换器把所有未关联的门窗按世界位置投影到最近的墙段HOST_WALL_MAX_DIST 1.0米内并优先选择能容纳洞口宽度的墙避免把小门吸附到墙角碎墙上导致 CSG 溢出。既无关系链又找不到宿主墙的元素则挂回其空间容器。每个门窗通过expressIdToNodeId去重确保同一填充元素只生成一个节点tests/openings.test.tspackages/ifc-converter/tests/openings.test.ts专门用04-ifc-open-house.ifc断言 6 个填充元素在“关系重复出现”的恶意输入下仍恰好各生成一次且父墙的children无重复。Slab / Stair / Roof / ColumnIFCSLAB→slab节点从Body剖面轮廓点或XDim/YDim矩形生成多边形去掉首尾重合点标高取放置 Z厚度暂存 metadataPascalSlabNode尚无thickness字段。IFCSTAIR→stair节点优先取自身 Body 包围盒失败则遍历楼梯段子元素利用NumberOfRisers/RiserHeight/TreadLength估算总高与总进深均失败时保留原点占位。包围盒信息存放在 metadataPascalStairNode是参数化楼梯转换器尚未映射。IFCROOF→roof节点提取扁平多边形与高度进 metadataPascalRoofNode由 roof-segments 组成目前仅作占位。IFCCOLUMN→column节点通过剖面字段检测round/rectangular形状剥除装饰性默认样式style: plain、baseStyle: none、capitalStyle: none用 IFC 剖面的宽/深/半径或宽深比决定crossSection。Beam / Item当前被跳过的类型IFCBEAM及IFCBEAMSTANDARDCASE因为 Pascal 还没有beam节点类型而被跳过仅统计数量并在控制台告警。IFCFURNISHINGELEMENT、IFCBUILDINGELEMENTPROXY、IFCRAILING、IFCCOVERING、IFCCURTAINWALL、IFCPLATE、IFCMEMBER、IFCFOOTING等家具/构件类实体同理——Pascal 的ItemNode需要一个包含 id/src/dimensions 等信息的目录资产catalog asset转换器无法从裸 IFC 几何合成因此也仅计数跳过。后处理属性集、材质与类型名转换完成后转换器把 IFC 的语义信息尽力保留进节点的metadata类型定义为ConverterMetadata属性集遍历IFCRELDEFINESBYPROPERTIES把每个属性集Pset_*下的属性IFCPROPERTYSINGLEVALUE的NominalValue与工程量LengthValue/AreaValue/VolumeValue/WeightValue/CountValue写入metadata.properties[psetName]材质遍历IFCRELASSOCIATESMATERIAL支持IfcMaterialLayerSet层名 LayerThickness×unitFactor 换算为米、IfcMaterialLayerSetUsage、单材质三种情况写入metadata.material与metadata.materialLayers类型名遍历IFCRELDEFINESBYTYPE把类型对象的Name写入metadata.typeName楼层归属沿父子链上溯为每个元素解析所属 storey写入metadata.levelId。UI 层的元素搜索apps/ifc-converter/components/IfcConverter.tsx正是靠这些 metadata 实现的——按名称、类型、IFC 类型、材质、GlobalId、属性键值多维度匹配点击搜索结果还会在 3D 视图中选中对应节点并弹出属性面板。场景简化清理转换产物IFC 中的墙经常被切成大量共线碎片导致转换结果碎片化。simplifyConvertedSceneGraphpackages/ifc-converter/src/cleanup.ts按顺序执行四步剔除微小墙长度小于MIN_WALL_LENGTH 0.08米且无子元素的墙删除合并共线墙碎片按“父节点 角度桶1° 粒度 中心线偏移 高度 材质签名”分组判并查集合并。材质签名会序列化material与materialLayers因此不同材质的墙绝不合并tests/cleanup.test.ts中多组用例专门验证了这一点合并时把门/窗重投影rehostOpeningToWall到保留墙上并把被合并墙的expressID记入metadata.ifcSimplification同步洞口子级确保每个门/窗在宿主墙的children中恰好出现一次去重洞口对同一墙上的门/窗按类型、家族、位置0.05 米容差、宽高生成签名删除重复项。合并可跨“门洞大小”的间隙默认maxWallJoinGap 1.25米可通过IfcConversionSimplificationOptions调整。每次简化都会返回一份IfcConversionSimplificationStats统计包括输入/输出墙体数、合并组数、删除的微墙与重复洞口数。调用方式与转换选项convertIfcToPascal的完整签名如下见 packages/ifc-converter/src/index.tsexport interface ConversionOptions { swapYZ?: boolean // 默认 trueY-up 坐标Pascal 约定把 IFC 的 Z-up 交换到 Y extrusionDepthIsHeight?: boolean // 默认 true拉伸深度解释为高度而非厚度 swapProfileDimensions?: boolean // 默认 false是否交换剖面的 XDim/YDim 解释 simplify?: boolean | IfcConversionSimplificationOptions // 默认启用场景简化 label?: string } export async function convertIfcToPascal( ifcData: Uint8Array, onProgress?: (message: string, percent: number) void, options?: ConversionOptions, ): PromisePascalSceneGraph仓库预置了两个变体预设VARIANT_PRESETS.AswapYZ: true、extrusionDepthIsHeight: true标签 “Default (Y-up, depthheight)”——默认形态VARIANT_PRESETS.BswapYZ: false标签 “Z-Up (no axis swap)”——保留 IFC 原始 Z-up 坐标。需要说明的是IfcExtrudedAreaSolid的深度语义在 IFC 中本意是拉伸厚度而 Pascal 墙以“高度”为第一属性因此默认把深度当高度使用swapProfileDimensions则解决某些导出器中剖面 XDim/YDim 与墙长/厚约定相反的情况。进度回调接收(message, percent)二元组UI 层用它渲染进度条。在纯 Node 环境中调用时注意 web-ifc 需要 WASM测试如 packages/ifc-converter/tests/openings.test.ts通过拦截SetWasmPath指向node_modules中 web-ifc 包的目录来完成初始化。Web 应用层上传、预览与下载依赖与资源加载apps/ifc-converter/package.json声明了转换应用核心依赖为pascal-app/ifc-converter、pascal-app/corescene registry 与节点 schema与pascal-app/viewer3D 渲染。web-ifc 的 WASM 二进制web-ifc.wasm、web-ifc-mt.wasm、web-ifc-node.wasm由 apps/ifc-converter/scripts/copy-web-ifc-wasm.mjs 在postinstall/predev/prebuild时自动复制到public/按大小幂等跳过已存在文件因为 web-ifc 默认从应用根路径加载/web-ifc*.wasm。开发与运行bun dev # 在 apps/ifc-converter 目录下运行 # 或在仓库根目录turbo run dev由于查看器使用 three 的 WebGPU 渲染器与基于 registry 的场景 store两者都不适合 SSR因此PascalViewer通过 Next.js 的dynamic(..., { ssr: false })懒加载见 apps/ifc-converter/components/IfcConverter.tsx。示例文件与环境变量小体积示例 IFC 已提交到apps/ifc-converter/public/test-ifc-files/如01-duplex.ifc、04-ifc-open-house.ifc、05-paris-ground-floor.ifc、10-sample-house.ifc大体积示例几十 MB 级如 Schependomlaan、RAC Sample Project、Sample Castle 等则托管在公开的 Supabase Storage bucket运行时按需拉取避免仓库臃肿。示例清单与说明见 apps/ifc-converter/lib/test-files.ts。环境变量NEXT_PUBLIC_IFC_EXAMPLES_BASE_URL可覆盖远程示例的存储桶地址置为空字符串会隐藏全部远程示例避免未配置环境时出现 404 卡片。应用还支持?filename查询参数直达某个示例并自动滚动到转换区且会把选择同步回 URLhistory.replaceState。交互与导出转换完成后用户可通过左侧 3D 预览Orbit 左键旋转 / 右键平移 / 滚轮缩放检查结果点击元素弹出属性面板类型、IFC 类型、GlobalId、ExpressID、所在楼层、几何数值、材质层与属性集用类型过滤wall/slab/door/window/stair/roof/column与楼层过滤按需显隐用搜索框跨名称/类型/材质/属性检索下载 Pascal JSON${原文件名去掉.ifc}_pascal.json、下载原始 IFC或复制 JSON 到剪贴板随后把 JSON 加载进 Pascal 编辑器继续设计。预览组件 apps/ifc-converter/components/PascalSceneViewer.tsx 直接把场景推入useScenestore并用真实pascal-app/viewer的ViewerCameraControls渲染AutoFit会延迟两帧等待墙体斜接、楼板构建等逐帧几何系统稳定后再计算包围盒取景LevelFocus则在切换楼层时沿 Y 轴平移相机目标。已知局限与改进方向README 明确列出README 以“Early alpha”诚实标注了当前边界这些局限也都能在源码中找到对应位置普通IFCWALLBrep/映射几何回退到固定高度精确的逐墙高度需要基于几何 AABB 提取。源码中measureWallLocalExtentswallHeightThicknessFromExtents已部分弥补——只要墙自身网格可读就会用旋转不变的轴向投影恢复真实高/厚只有完全失败才落到DEFAULT_WALL_HEIGHT2.5 米/DEFAULT_WALL_THICKNESS0.1 米家具等物品被跳过Pascal 的ItemNode需要目录资产catalog asset转换器无法从裸 IFC 几何合成因此IFCFURNISHINGELEMENT等实体仅计数并告警梁被跳过Pascal 尚无beam节点类型源码中保留了恢复映射的注释说明轴点列→start/end、剖面 XDim/YDim→宽/深、拉伸深度→轴线长度的映射思路门/窗与墙的匹配当 IFC 省略 fill 关系时按 1 米范围内的最近墙投影匹配匹配并非完美楼梯/屋顶为占位目前只在 metadata 中保留包围盒楼梯或扁平多边形 高度屋顶尚未映射到 Pascal 的参数化StairNode/ 分段式RoofNode。正因如此README 明确欢迎贡献遇到转换效果差的文件提供“示例 IFC 问题说明”最有帮助改进几何提取、补充更多元素类型、处理边界情况的 PR 正是这个项目最需要的。结语apps/ifc-converter是一个将“标准解析能力”与“领域场景模型”结合的完整示例web-ifc 负责 IFC 的复杂解析pascal-app/core提供 Pascal 节点 schema 与 registrypascal-app/viewer提供渲染转换器本体则专注于单位换算、坐标变换、关系链解析与几何提取这一层纯逻辑。无论你想把 IFC 导入 Pascal 编辑器继续设计还是想在自有管线中复用pascal-app/ifc-converter的转换能力本文梳理的映射规则、选项语义与局限边界都可以作为直接参考。【免费下载链接】editorOpen-source 3D architectural editor with a local CLI, MCP tools, and practical workflows for humans and AI agents.项目地址: https://gitcode.com/GitHub_Trending/editor93/editor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考