3DXML文件格式是一种重要的轻量化CAD数据格式,通过对3DXML文件格式的分析,论述了一种基于MSXML解析器的文件解析技术。这种解析方式可以快速提取3DXML文件中的重要信息,通过对几何及属性信息的重构,建立整个装配体场景,使用文件中的多分辨率模型,可以提高较大模型的渲染速度。最后给出了基于3DXML文件格式的轻量化CAD浏览器的应用实例。
3DXML是一种完全开放的数据格式,不同于一般的CAD文件,3DXML文件中不含有几何信息,只包含模型实体信息,同时保有装配信息。这使3DXML的文件尺寸远远小于一般的CAD文件,同时3DXML对文件近一步压缩,使其能够提供更快的文件传输速度和更短的储存时间。 3DXML完全遵循XML语法,使用任何的标准XML解析器都可以对其进行解析,提取需要的信息。
3DXML文件是一种多文档格式,并采用ZIP算法压缩成一个文件。Manifest文件中的<Root>元素结点值为装配信息文件名,即扩展名为3dxml的文件。扩展名为3drep的文件保存图形数据及属性信息。在本文的解析器中,有两个主要的类,都派生自接口ISAXContentHandler,分别用来解析装配和图形文件。
<?xml version='1.0' encoding='UTF-8' ?>
<Manifest>
<!--装配信息文件名-->
<Root>PRODUCT.3dxml</Root>
<!---->
<Date>2020-08-24</Date>
<!---->
<WithAuthoringData>true</WithAuthoringData>
<!---->
<From>804120</From>
<!---->
<Destination>(要编辑)</Destination>
<!---->
<Title>SNY0001</Title>
<!---->
<Comment>(要编辑)</Comment>
<!---->
<Copyright>长江勘测规划设计研究院</Copyright>
</Manifest>
在解析的过程中,首先对文件进行解压缩,然后读取Manifest文件,获取装配信息文件名。读取装配信息,生成产品结构树,同时获取所有的图形数据文件名,最后依次解析图形文件。
产品结构信息由XML元素<ProductStructure >标识其开始,该结点有4类子结点,<Reference3D>,<Instance3D>,<ReferenceRep>,<InstanceRep>。每个结点具有唯一的ID值。<Instance3D>结点有3个子结点,<IsAggregatedBy>,<IsInstanceOf>,<RelativeMatrix>,前两个子结点中分别保存了一个ID值,表示该实例结点是哪个引用结点的组成部分,该实例结点是哪个引用结点的一个实例,最后一个子节点存储了该实例结点相对其上层引用结点的相对位置矩阵。<ReferenceRep>结点保存了图形数据的文件名,<InstanceRep>结点作为连接图形结点和零件引用结点的中间结点。其两个子结点保存的信息与<Instance3D>的前两个子节点的信息相同。在本文的解析器中,有向非循环图中的结点为<Reference3D>和<Instance3D>两个元素结点。
<?xml version="1.0" encoding="UTF-8" ?>
<Model_3dxml xmlns="http://www.3ds.com/xsd/3DXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header>
<SchemaVersion>4.3</SchemaVersion>
<Title>PRODUCT</Title>
<Author>804120</Author>
<Generator>Dassault Systemes V6</Generator>
<Created>2020-08-24</Created>
</Header>
<ProductStructure root="1" xmlns:_3DShape="http://www.3ds.com/xsd/3DXML/PRODUCT/3DShape" xsi:schemaLocation="http://www.3ds.com/xsd/3DXML/PRODUCT/3DShape 3DShape.xsd ">
<Reference3D xsi:type="Reference3DType" id="5" name="prd-54462602-00273241">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273241</PLM_ExternalID>
<V_Name>ImportedAsNew-控制段</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="15" name="prd-54462602-00273245">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273245</PLM_ExternalID>
<V_Name>ImportedAsNew-闸门整体参数.1</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="21" name="prd-54462602-00273246">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273246</PLM_ExternalID>
<V_Name>ImportedAsNew-门叶</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="33" name="prd-54462602-00273247">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273247</PLM_ExternalID>
<V_Name>ImportedAsNew-止水</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="1" name="prd-54462602-00273238">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273238</PLM_ExternalID>
<V_Name>ImportedAsNew-实例-控制段</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="3" name="prd-54462602-00273239">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273239</PLM_ExternalID>
<V_Name>ImportedAsNew-溢洪道</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="9" name="prd-54462602-00273240">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273240</PLM_ExternalID>
<V_Name>ImportedAsNew-事故检修门</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="13" name="prd-54462602-00273242">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273242</PLM_ExternalID>
<V_Name>ImportedAsNew-整体参数</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="19" name="prd-54462602-00273243">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273243</PLM_ExternalID>
<V_Name>ImportedAsNew-门叶结构</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Reference3D xsi:type="Reference3DType" id="31" name="prd-54462602-00273244">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>prd-54462602-00273244</PLM_ExternalID>
<V_Name>ImportedAsNew-止水装置.3</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</Reference3D>
<Instance3D xsi:type="Instance3DType" id="2" name="溢洪道.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>溢洪道.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>1</IsAggregatedBy>
<IsInstanceOf>3</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="8" name="底节门体.1">
<C_created>1598230004</C_created>
<C_modified>1598230132</C_modified>
<PLM_ExternalID>底节门体.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>1</IsAggregatedBy>
<IsInstanceOf>9</IsInstanceOf>
<RelativeMatrix>-1 5.160802341031e-17 0 -5.160802341031e-17 -1 0 0 0 1 -18700 -6000 966.293783772517</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="4" name="控制段.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>控制段.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>3</IsAggregatedBy>
<IsInstanceOf>5</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="12" name="总体参数">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>总体参数</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>9</IsAggregatedBy>
<IsInstanceOf>13</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="18" name="门叶结构">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>门叶结构</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>9</IsAggregatedBy>
<IsInstanceOf>19</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="30" name="Product4.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>Product4.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>9</IsAggregatedBy>
<IsInstanceOf>31</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="14" name="总体参数">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>总体参数</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>13</IsAggregatedBy>
<IsInstanceOf>15</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="20" name="底节门叶.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>底节门叶.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>19</IsAggregatedBy>
<IsInstanceOf>21</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<Instance3D xsi:type="Instance3DType" id="32" name="止水.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>止水.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>31</IsAggregatedBy>
<IsInstanceOf>33</IsInstanceOf>
<RelativeMatrix>1 0 0 0 1 0 0 0 1 0 0 0</RelativeMatrix>
</Instance3D>
<ReferenceRep xsi:type="_3DShape:_AddedPrefix_3DShape" id="7" name="3sh-54462602-00478836" format="UVR" associatedFile="urn:3DXML:3sh-54462602-00478836_2_59f56c0e_1ce4_5f430e97_36ada.3DRep" version="1.0">
<C_created>1598230003</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>3sh-54462602-00478836</PLM_ExternalID>
<V_discipline>Design</V_discipline>
<V_Name>ImportedAsNew-3D 形状00030772</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</ReferenceRep>
<ReferenceRep xsi:type="_3DShape:_AddedPrefix_3DShape" id="17" name="3sh-54462602-00478837" format="UVR" associatedFile="urn:3DXML:3sh-54462602-00478837_2_59f56c0e_1ce4_5f430e97_36afa.3DRep" version="1.0">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>3sh-54462602-00478837</PLM_ExternalID>
<V_discipline>Design</V_discipline>
<V_Name>ImportedAsNew-闸门整体参数.1</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</ReferenceRep>
<ReferenceRep xsi:type="_3DShape:_AddedPrefix_3DShape" id="23" name="3sh-54462602-00478838" format="UVR" associatedFile="urn:3DXML:3sh-54462602-00478838_2_59f56c0e_1ce4_5f430e97_36b1a.3DRep" version="1.0">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>3sh-54462602-00478838</PLM_ExternalID>
<V_discipline>Design</V_discipline>
<V_Name>ImportedAsNew-门叶</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</ReferenceRep>
<ReferenceRep xsi:type="_3DShape:_AddedPrefix_3DShape" id="35" name="3sh-54462602-00478839" format="UVR" associatedFile="urn:3DXML:3sh-54462602-00478839_2_59f56c0e_1ce4_5f430e97_36b3a.3DRep" version="1.0">
<C_created>1598230004</C_created>
<C_modified>1598230005</C_modified>
<PLM_ExternalID>3sh-54462602-00478839</PLM_ExternalID>
<V_discipline>Design</V_discipline>
<V_Name>ImportedAsNew-止水</V_Name>
<V_nature>2</V_nature>
<V_version>A</V_version>
<V_maturity>IN_WORK</V_maturity>
</ReferenceRep>
<InstanceRep xsi:type="InstanceRepType" id="6" name="3sh-tmp-50854975-00030772.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>3sh-tmp-50854975-00030772.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>5</IsAggregatedBy>
<IsInstanceOf>7</IsInstanceOf>
</InstanceRep>
<InstanceRep xsi:type="InstanceRepType" id="16" name="3sh-tmp-50854975-00028655.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>3sh-tmp-50854975-00028655.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>15</IsAggregatedBy>
<IsInstanceOf>17</IsInstanceOf>
</InstanceRep>
<InstanceRep xsi:type="InstanceRepType" id="22" name="3sh-tmp-50854975-00028657.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>3sh-tmp-50854975-00028657.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>21</IsAggregatedBy>
<IsInstanceOf>23</IsInstanceOf>
</InstanceRep>
<InstanceRep xsi:type="InstanceRepType" id="34" name="3sh-tmp-50854975-00028659.1">
<C_created>1598230004</C_created>
<C_modified>1598230004</C_modified>
<PLM_ExternalID>3sh-tmp-50854975-00028659.1</PLM_ExternalID>
<V_nature>2</V_nature>
<IsAggregatedBy>33</IsAggregatedBy>
<IsInstanceOf>35</IsInstanceOf>
</InstanceRep>
</ProductStructure>
</Model_3dxml>
解析过程主要针对上图中的4类结点进行解析,重点解析Reference3D和Instance3D结点。为了便于结点的查询,创建一张结点指针表,保存结点指针,即Reference3D和Instance3D。在读取到引用结点开始元素时,检测指针表中对应ID的结点是否创建,若指针为空,则创建,然后读取相应的属性信息。在读取到实例结点时,同样检测对应指针是否为空并读取属性信息,对于实例结点的前两个子节点,只判断对应ID的结点是否为空,为空则只分配内存,不为其填入属性信息。
有向非循环图结构可以大大减少文件的尺寸,但不便于图形的绘制和属性的传递。为此,需要将图形结构装换成常用的树形结构。采用深度优先原则遍历图,遍历过程中,将每条路径中出现的Instance3D结点做为树结点添加到树结构中。
图形数据解析
在装配文件中,每个<ReferenceRep>元素结点对应一个3drep文件,即图形文件。 3DXML的一个图形文件中可能包含多个零件的图形数据,这些零件在装配体结构中,可以看作是一个完整的零件,而不会影响装配结构的表达。其文件数据结构如下图所示
每个零件的图形数据由XML元素<Rep xsi:type="PolygonalRepType">标识其开始,由面片集合<Faces>,边集合<Edges>和顶点信息<VertexBuffer>组成。顶点缓存中保存该零件所有顶点的坐标和法线,在面片信息中只保存组成面的三角形(条带,扇)的索引,可以大大减少了图形文件的尺寸。在边集合中的点则直接保存为点的坐标值。为了加快图形绘制的速度,面片信息中使用了LOD(多细节层次)模型,每个零件最多有8个LOD模型,由元素<PolygonalLOD>标识。在图形绘制过程中,计算该零件到视点的距离,然后根据文件中每个细节层次所提供的临界选取值,即<PolygonalLOD>的属性accuracy,选择相应的LOD模型绘制,可以大大提高渲染的效率。图形文件中没有存储各基础图元的数量,为了加快解析速度,减少内存使用,可预先分配一块足够大的缓存,每次将某种图元数据全部读取到缓存并计算出图元数量[5]。在读取到该图元结点结束的位置时,为相应的图形结点分配内存,将缓存中的数据拷贝至其中,并将缓存清空,为下个图元结点数据加载做准备。
解压缩
3DXML文件是采用ZIP压缩算法进行压缩的。通过文本编辑器打开3DXML文件,可以看到文本的前两个字符为PK,所有采用ZIP算法压缩后的文件,其前两个字符都以PK作为标识。可以采用了Zlib库进行解压,Zlib库是一个开源的免费的商用程序库,主要用来解压/压缩字符串。