原创作者:flowell,转载请标明出处:https://www.cnblogs.com/flowell/p/10839179.html


IFC

IFC是建筑信息模型(BIM)数据开放的国际标准,在建筑行业或设施管理行业的各个参与者使用的软件应用程序之间作为中间媒介交换和共享。该标准涵盖建筑物生命周期所需数据的定义和管理流程,对建筑信息进行有组织的高效管理。

对于本文而言,IFC更重要的特性之一便是IFC作为一种平台中立的开放文件格式规范,不受单个供应商或供应商组的控制。它是一种基于对象的文件格式,具有由特殊组织BuildingSMART(以前称为国际互操作性联盟,IAI)开发的数据模型,以促进组织架构,工程和构造(AEC)行业中的互操作性,并且是建筑信息中常用的协作格式。基于建筑建模(BIM)的项目。这意味着IFC模型规范是开放的并且是可重用的。研究IFC格式对于加强不同行业的建模或是不同建模软件之间的交流都有极为重要的意义。

例如,由于丹麦政府专注于软件平台之间的互操作性,因此丹麦政府已将IFC格式强制用于公共辅助建筑项目。此外,芬兰国有设施管理公司Senate Properties要求在所有项目中使用IFC兼容软件和BIM。[3]挪威政府,卫生和国防客户组织也要求在所有项目中使用IFC BIM,以及许多市政当局,私人客户,承包商和设计师在其业务中整合了IFC BIM。IFC作为一种通用的建模信息交流中间媒介,在建筑建模和模型展示之间起到了承上启下的重要意义。

IFC可以以多种格式编码,每种格式都具有软件支持,可伸缩性和可读性的益处和权衡。这些格式表示数据如何以电子形式编码。由于建筑数据可能非常大(即千兆字节),因此格式的选择可能具有实际考虑因素。本文参考的IFC文件是基于Revit项目导出的IFC文件,具有.ifc拓展名的后缀,是IFC在实践中使用最广泛的格式,同时也是作为文本读取的格式中最紧凑的格式,并且还具有最大的兼容性和支持性。

IFC数据以对象实例为结点构成层次结构,其中所有可识别对象都派生自IfcRoot类。每个对象都有一个128位数字(GUID)形式的GlobalID,它永远不会在整个生命周期中发生变化,一个用于人类识别的名称(Name)或将在施工计划中显示的名称,一个用于捕获杂项信息的描述(Description),以及一个可以使用的所有者历史记录(Tag)。指示对象的创建和最后修改的对象,时间和方式,以及指示锁定状态和合并状态(创建,修改,删除或无更改)的版本控制属性。IFC中的实体(Entity)涵盖了建筑生命流程中所必需的绝大部分元素,包括IfcActor,表示承包商或建筑物占用者等个人或组织。IfcControl表示指令,例如工单,许可,工作计划或投标提交。IfcGroup表示相关产品的集合,例如机械系统。IfcProduct表示在空间中构件的实例,例如物理产品或建筑物中的房间。IfcProcess指示当时发生的事情,例如任务或事件。IfcResource表示使用材料,人工或设备等可用性有限的东西。IfcRelationShip表示对象是如何组织起来的,如聚集,包含,连接,依赖等概念上或空间上的组织关系。因为本文关注的是BIM三维模型在转换处理过程中的数据流向,所以本文将重点关注于IFC中的物理实体(IfcProduct)和关系实体(IfcRelationShip)。通过遍历单个IFC文件中的关系层次树,我们将依次抵达一个个连接在一起的物理实体,通过输出物理实体的模型信息和属性信息,同时输出物理实体间的组织关系,我们将可以通过IFC重构原有的建筑模型信息。

IFC物理实体

IFC Schema规定的700多个类里,继承自IfcElement的类和建筑行业的具体构建对应,比如继承自IfcSpatialElement的类和建筑中的空间部件对应。在我们要处理的IFC文件中,主要关注属于物理实体类型的继承自IfcElement的类和继承自IfcSpatialElement的类,此类均属于建筑场景中的建筑构件或空间构建,我们将其称之为IFC物理实体。例如,IfcWall的实例就是建筑空间中的一堵墙,IfcSpace实例代表一个建筑空间。在提取IFC文件时,我们重点关注IFC物理实体。特别的,继承自IfcElement的物理实体都有对应的Type表示该实体拥有的属性,材质信息,几何展示等相关信息,在提取IFC文件时也要一并关注这些信息。

图1 IFC物理实体的继承树

IFC关系实体

IFC遵循面向对象的设计模式,除了IFC物理实体之外,IFC还定义了IFC关系实体来表达物理实体或其他实体之间的关联,依赖,聚合,组合,包含等关系。IFC关系实体通常以“IfcRel”前缀开头,它对应的实例为IFC关系实例。

图2 IFC关系实体的继承树

例如,IfcRelAggregates是IfcRelComposes的子类,用以表达聚合关系,通常是一对多。通过解析IfcRelAggregates实例的连接上级的RelatingObject和连接下级的RelatedObject属性可以获取在聚合关系两端的实体,空间实例通常以聚合关系连接起来。而IfcRelContainedInSpatialStructure这个关系实体是我们要重点关注的,它代表了建筑的包含关系,用以将一个建筑元素(物理实体)分配给空间上的某个部件,以连接物理实体中IfcSpatialElement和IfcElement,。并且任何元素只能分配给某个级别的空间结构唯一一次,使得元素只能被包含于单个空间结构中。类似的关系实体还有表示引用关系的IfcRelReferencedInSpatialStructure,但是引用关系不必是一对一的,它可以引用零个,一个或者多个。

图3 IFC关系实体的应用

如图3所示,图中的场景实例包含了代表建筑空间的三个IfcBuilding实例,以及两个IfcBuildingSteroy实例和代表建筑关系的两个IfcAggregates实例,代表包含关系的两个IfcRelContainedInSpatialStructure实例。而作为建筑元素之一的两个IfcWall实例和IfcStair实例通过建筑关系被包含于建筑空间中。由此可知,IFC标准通过IFC的关系实例将模型组织成井然有序的空间层次关系,所有的建筑信息和构建信息都能有被有效地组织和管理,因此IFC标准为BIM模型的信息描述和信息交换都提供了坚实的保障。而由此也可以提出,基于构件之间的包含和聚集关系,本文如果立足于IFC的根节点,按照关系层次一层一层地去遍历IFC节点树,是可以做到将IFC的每一个构件生成在同一棵节点树内,从而实现IFC文件中所有构件按层次地导出。IFC标准中对构件之间的关系的定义,将是本文模型提取的理论前提。

GLTF

GLTF(GL TransmissionFormat)即图形语言交换格式,它是一种3D内容的格式标准,由Khronos Group管理(Khronos Group还管理着OpenGL系列、OpenCL等重要的行业标准)。GLTF用于应用之间的模型高效传输和加载3D场景和模型。GLTF最大限度地减少了3D模型的大小,以及解压缩和使用模型所需的运行时处理,同时以最大的限度保障模型信息的完整度。GLTF为三维内容工具和服务定义了一种可扩展的通用发布格式,可简化创作的工作流程并实现整个行业内容的可互操作使用。GLTF一直致力于成为三维图形界的JPEG,可见它在信息传输和存储中所包含的强大特性和无穷的发展力。

GLTF格式将易于解析的JSON场景描述与一个或多个几何的表示,与动画和其他丰富数据的二进制文件相结合。数据以二进制的方式存储,即它可以直接加载到GPU缓冲区中而无需额外的解析或其他操作。同时结构信息又以JSON格式组织,即保证了可读性又保证了解析的快速性。使用这种方法,GLTF能够在具有Node,Mesh,Camera,Material和Animation的完整分层展示场景,同时实现高效传输和快速加载。

图4 GLTF实体间的组织关系

GLTF按照Scene-Node-Mesh-Accessor-BufferView-Buffer由高到低的层次关系来组织三维模型信息。

Scene:GLTF包括场景定义数据,使用一棵场景树来组织定义场景。Scene中的节点包含Transform矩阵(也就是位置、旋转、缩放)以及场景节点父子关系的描述,以及该场景包含的功能(mesh、camera等);通常意义上的Scene是一种常用的场景对象组织方式。我们把场景中的对象,按照一定的规则(通常是空间关系)组织成一棵树,树上的每个节点代表场景中的一个对象。每个节点都可以有零到多个子节点,但只有一个父节点。 每个节点都包含多个对“空间的定义”的属性,如Transform属性,通过一个 4x4 的矩阵表示,也可以通过位置、旋转、缩放三个分量来表示,它代表该场景相对世界坐标系的转换。如Nodes属性,则代表该场景中的子节点,根据Node的索引指向同一个GLTF文件中的Node数组中的某个或多个Node。

Node:Node是场景中的节点,被Scene包含或指向,通常对应于模型中的一个建筑构件。如果Scene代表一个建筑场景,如一个房子及房子周边的场地,那么Node的细度就是这个房子里的一把椅子,一张桌子,一扇门,甚至这件房子在整体上也可以当做是一个Nod。Node可以主要包含的属性有Children,定义了该节点所包含的子节点。Mesh属性则是该节点所包含的模型信息,具体地说可以包含顶点,法向量,材质,纹理等信息。延续刚才的例子来讲,如果房子是一个Node,那么它的Children属性应该指向房子里的构件比如椅子,桌子等。而这些椅子,桌子本身也是Node,它被房子的Node指向,同时也可以指向更细层次的子节点,如椅子的椅子腿,椅子的靠背等。通常高层次的Node都不包含Mesh属性,最深层次的Node节点,也就是叶节点,会包含Mesh属性,它指向同一个GLTF文件中的Mesh数组中的某个Mesh,它包含了刻画该节点的模型的信息。

Mesh:Mesh在GLTF中代表要渲染的三维空间中的物体的模型信息。具体代表三维空间中表示物体的造型。GLTF按照目前图形学中最常用的方法边界表示法,即用一组多边形或者曲面来定义物体的边界,并用以区分了空间中哪些部分是物体的内部和物体的外部。构造一个物体边界的一组多边形就被称为Mesh。在GLTF中,Mesh主要包含Primitives属性和Index属性。Primitives属性包含物体边界的顶点信息和法向量信息,它存储对应Accessor索引,以找到对应的信息。Index则是关于边界曲面的拓扑顺序,具体的顺序以Primitives中的Mode属性定义,可以定义的顺序包括:POINTS,LINES,TRIANGLES,TRIANGLES_STRIP,TRIANGLES_FAN。

Accessor:Accessor是BufferView中数据的访问器,一个BufferView可以同时存储多组同类数据,因此需要用不同的访问器以获得不同的数据。通过Accessor对BufferView的数据进行划分,以获得不同的访问效果。

BufferView:BufferView可以比作数据视图,一个BufferView通常会对应一种数据,如浮点数,整数。这些数据从BufferView的角度来看是单纯的数组。

Buffer:Buffer是存储数据的数组,在这里,数据以二进制形式存储,通过Base64的编码形式编码。

IFC-GLTF对应关系

如我们在上一章讨论的,IFC是建筑行业的标准,包含了很多的非几何信息,而我们导出的GLTF只包含几何信息,因此在转换时应关注几何信息。

IFC中所有的对象都组织在同一棵树中,这颗树的根是一个IfcProject对象,存储该模型的元信息。由根出发,IFC对象尤其是建筑构件由聚合关系或者包含等关系按照空间上的关系聚集在这棵树上,因此在装载成GLTF时也要注意保存这种组织顺序。在对象树中的IFC建筑构件,都拥有它对应的图元信息,这些图元信息将被我们提取,转换成GLTF对象,一个建筑构件在IFC中是一个IfcProduct的子类(如IfcElement),而在GLTF中是一个Node结点。IfcProduct的成员中包含它的图元信息的链接,通过链接找到它对应的图元信息,对应的是多个IfcShape对象,而在GLTF中则是多个Mesh,一个IfcShape对应一个Mesh。因此,一个IfcProduct拥有多个IfcShape,在GLTF中则是一个Node的children属性指向多个Mesh(其实是指向Node,但是这些node是叶子节点,只包含一个Mesh),在现实世界中,对应的概念则如一个椅子(IfcProduct)拥有多个构件,如凳腿,靠背,座板等。

在处理的时候,以递归的方式访问IFC对象树,然后对于每一个访问的对象,创建一个Node节点,并且找到该对象对应的Shape,创建Mesh节点。下图中以队列的方式实现对IFC对象树的递归访问。

Xbim.GLTF源码解析(二):IFC和GLTF的对应关系的更多相关文章

  1. Mybatis源码解析(二) —— 加载 Configuration

    Mybatis源码解析(二) -- 加载 Configuration    正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...

  2. RxJava2源码解析(二)

    title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...

  3. Sentinel源码解析二(Slot总览)

    写在前面 本文继续来分析Sentinel的源码,上篇文章对Sentinel的调用过程做了深入分析,主要涉及到了两个概念:插槽链和Node节点.那么接下来我们就根据插槽链的调用关系来依次分析每个插槽(s ...

  4. iOS即时通讯之CocoaAsyncSocket源码解析二

    原文 前言 本文承接上文:iOS即时通讯之CocoaAsyncSocket源码解析一 上文我们提到了GCDAsyncSocket的初始化,以及最终connect之前的准备工作,包括一些错误检查:本机地 ...

  5. jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

    终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...

  6. Common.Logging源码解析二

    Common.Logging源码解析一分析了LogManager主入口的整个逻辑,其中第二步生成日志实例工厂类接口分析的很模糊,本随笔将会详细讲解整个日志实例工厂类接口的生成过程! (1).关于如何生 ...

  7. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

  8. element-ui 源码解析 二

    Carousel 走马灯源码解析 1. 基本原理:页面切换 页面切换使用的是 transform 2D 转换和 transition 过渡 可以看出是采用内联样式来实现的 举个栗子 <div : ...

  9. ArrayList源码解析(二)

    欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html 自己学习ArrayList源码的一些心得记录. 继续上一篇,Arra ...

  10. React的Component,PureComponent源码解析(二)

    1.什么是Component,PureComponent? 都是class方式定义的基类,两者没有什么大的区别,只是PureComponent内部使用shouldComponentUpdate(nex ...

随机推荐

  1. Linux下查看版本信息

    Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等.   1.# uname -a   (Linux查看版本当前操作系统内核信息)   2.# cat /proc/ ...

  2. 【爬虫小程序:爬取斗鱼所有房间信息】Xpath(多进程版)

    # 本程序亲测有效,用于理解爬虫相关的基础知识,不足之处希望大家批评指正 import requests from lxml import etree from multiprocessing imp ...

  3. 使用.NET Core中创建Windows服务(一) - 使用官方推荐方式

    原文:Creating Windows Services In .NET Core – Part 1 – The "Microsoft" Way 作者:Dotnet Core Tu ...

  4. DevExpress GridControl导出ExportToXls 数字类型显示成货币格式

    用Dev开发很习惯直接用自带控件导出Excel,现在很少使用原生的Excel API去操作了.除非需要详细的控制. 但别人家封装好的就得按人家的规则的.在使用GridControl导出Excel时发现 ...

  5. 模拟实现JSON.stringiry 的格式化输出

    前言 这是一道笔试题,要求模拟实现JSON.stringiry 的格式化输出,按照层级缩进,输出易读格式,即完成以下方法 JSON.stringify(jsObj, null, 4); // 缩进4个 ...

  6. Scala 学习笔记之implicit

    implicit 分为隐式转换和隐式参数,下面例子展现了两种方式的用法: package com.citi.scala class Man(val name: String) { def talkWi ...

  7. MongoDB 学习笔记之 Aggregation Pipeline

    Aggregation Pipeline: 常用操作符介绍: $project:包含.排除.重命名和显示字段 $match:查询,需要同find()一样的参数 $limit:限制结果数量 $skip: ...

  8. GoLang 获取两个时间相差多少小时

    package main import ( "fmt" "time" ) func main() { fmt.Println(getHourDiffer(&qu ...

  9. 机器学习中梯度下降法原理及用其解决线性回归问题的C语言实现

    本文讲梯度下降(Gradient Descent)前先看看利用梯度下降法进行监督学习(例如分类.回归等)的一般步骤: 1, 定义损失函数(Loss Function) 2, 信息流forward pr ...

  10. insert增数据详解

    查看表结构: desc 表名; describe的缩写,意为描述 增加数据不会改变表的结构,只是增加了行. 创建一张表: mysql> create table class( -> id ...