NSDT工具推荐Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

在这个简短的练习中,我们将在 IfcOpenHouse 模型之上构建。 它是首批完全使用程序代码构建的 IFC 模型之一。 这是一个不错的模型,但它有一些缺点:例如,它没有定义一个 IfcSpace 实例来描述由墙壁和屋顶界定的内部空间。 在本练习中,我们将根据边界元素的几何形状自动建模该空间的几何形状,并计算模型的内部体积。

导入到常规 CAD 应用程序中的 IfcOpenHouse 模型

1、快速入门

# Specify to return pythonOCC shapes from ifcopenshell.geom.create_shape()
settings = ifcopenshell.geom.settings()
settings.set(settings.USE_PYTHON_OPENCASCADE, True)

# Initialize a graphical display window
occ_display = ifcopenshell.geom.utils.initialize_display()

# Open the IFC file using IfcOpenShell
ifc_file = ifcopenshell.open("IfcOpenHouse.ifc")
# Display the geometrical contents of the file using Python OpenCascade
products = ifc_file.by_type("IfcProduct")
for product in products:
    if product.is_a("IfcOpeningElement"): continue
    if product.Representation:
        shape = ifcopenshell.geom.create_shape(settings, product).geometry
        display_shape = ifcopenshell.geom.utils.display_shape(shape)
        if product.is_a("IfcPlate"):
            # Plates are the transparent parts of the window assembly
            # in the IfcOpenHouse model
            ifcopenshell.geom.utils.set_shape_transparency(display_shape, 0.8)

导入 IFC 模型非常简单,然后我们得到了对 IfcProduct 子类型实例的引用。 这些类包括所有具有 3d 表示的建筑元素。 这还包括 IfcOpeningElements,这是一种用于提取门窗开口的机制,通常是从墙上提取开口。 不会导入这些元素的几何形状(请注意,continue 表示继续迭代中的下一个元素)。 IfcOpenShell 可用于创建 3d 形状来表示建筑元素。

请注意,在 IFC 中,几何被分解为不同复杂度的 IfcRepresentationItems。 IfcOpenShell 隐藏了这种复杂性,并为每个产品提供统一的边界表示 (BRep)。

在 pythonOCC 环境中导入的 IfcOpenHouse 模型

2、过滤元素

但是,对于本练习,我们并不对所有类型的产品感兴趣。 最初我们只对建筑物的四面墙感兴趣。

# Get a list of all walls in the file
walls = ifc_file.by_type("IfcWall")

# Create a list of wall representation shapes
# and compute the bounding box of these shapes
wall_shapes = []
bbox = OCC.Bnd.Bnd_Box()
for wall in walls:
    shape = ifcopenshell.geom.create_shape(settings, wall).geometry
    
    wall_shapes.append((wall, shape))
    OCC.BRepBndLib.BRepBndLib_Add(shape, bbox)    
    
    ifcopenshell.geom.utils.display_shape(shape)
    
# Calculate the center/average of the bounding box
bounding_box_center = ifcopenshell.geom.utils.get_bounding_box_center(bbox)
print "Bounding box center: %.2f %.2f %.2f" % (
    bounding_box_center.X(), 
    bounding_box_center.Y(),
    bounding_box_center.Z())

occ_display.DisplayMessage(bounding_box_center, "Center", update=True)
IfcOpenHouse 模型的墙壁及其边界框中心点

除了简单地获得墙壁的 3d 形状外,内部空间的中点是通过计算几何边界框的平均值来确定的。 稍后需要这个中间点来确定墙的哪一侧作为内部空间体积的基础。

拓扑和几何的区别

面(Face)是由基准表面(Surface Plane)上的连线(Wire)组成的。 连线由边(Edge)和顶点(Vertex)组成。 边有对应的基础曲线(Curve)。

在OpenCascade和大多数其他几何内核中,几何和拓扑之间存在区别,有关这些概念的更多信息,请阅读这个博客文章

边界墙的内面

3、提取面

# Now create halfspace solids from the inner faces of the wall
halfspaces = []
for wall, shape in wall_shapes:
    topo = OCC.Utils.Topo(shape)
    for face in topo.faces():
        surf = OCC.BRep.BRep_Tool.Surface(face)
        obj = surf.GetObject()
        assert obj.DynamicType().GetObject().Name() == "Geom_Plane"
        
        plane = OCC.Geom.Handle_Geom_Plane.DownCast(surf).GetObject()
        
        if plane.Axis().Direction().Z() == 0:
            face_bbox = OCC.Bnd.Bnd_Box()
            OCC.BRepBndLib.BRepBndLib_Add(face, face_bbox)
            face_center = ifcopenshell.geom.utils.get_bounding_box_center(face_bbox).XYZ()
            
            face_normal = plane.Axis().Direction().XYZ()
            face_towards_center = bounding_box_center.XYZ() - face_center
            face_towards_center.Normalize()
            
            dot = face_towards_center.Dot(face_normal)
            
            if dot < -0.8:
                
                ifcopenshell.geom.utils.display_shape(face)
                
                face_plane = plane.Pln()
                new_face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(face_plane).Face()
                halfspace = OCC.BRepPrimAPI.BRepPrimAPI_MakeHalfSpace(
                    new_face, bounding_box_center).Solid()
                halfspaces.append(halfspace)

我们需要确定墙体积的哪些面指向中间点,以便它们可以成为内部空间边界体积的一部分。

OpenCascade 有几种类型的形状:实体、壳、面、线、边和顶点以及它们的组合。 IfcOpenShell 为墙返回的形状可能是实体,但我们现在真的不需要这样做。 我们可以简单地遍历绑定实体的面。 然后我们可以获得对该面的底层表面的引用。

由于 IfcOpenHouse 模型仅由平面几何组成,我们知道表面符合平面。 如果垂直于平面的法向量的方向指向中点,我们知道它是我们感兴趣的面之一。这是通过计算两个向量的点积来完成的,请在维基百科上阅读更多内容。 请注意,0.8 常数是相当随意的。 从技术上讲,窗户开口减法的一些面也指向空间的中间点。

半空间实体是由某个表面界定的无限实体,在这种情况下是一个无限平面

请注意,人脸不一定需要有界。 从通过迭代边界壁的表面获得的平面方程,我们可以获得半空间实体。 你可以想象所有这些半空间实体的交集形成了我们内部空间的体积。 但首先使用类似的技巧来获取屋顶元素的底面。

# Create halfspace solids from the bottom faces of the roofs
roofs = ifc_file.by_type("IfcRoof")
for roof in roofs:
    shape = ifcopenshell.geom.create_shape(settings, roof).geometry
    
    topo = OCC.Utils.Topo(shape)
    for face in topo.faces():
        surf = OCC.BRep.BRep_Tool.Surface(face)
        plane = OCC.Geom.Handle_Geom_Plane.DownCast(surf).GetObject()
        
        assert obj.DynamicType().GetObject().Name() == "Geom_Plane"
        if plane.Axis().Direction().Z() > 0.7:
            face_plane = plane.Pln()
            new_face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(face_plane).Face()
            halfspace = OCC.BRepPrimAPI.BRepPrimAPI_MakeHalfSpace(
                new_face, bounding_box_center).Solid()
            halfspaces.append(halfspace)

4、创建空间体积

不幸的是,仅从无限实体创建有界实体在 OpenCascade 中效果不佳。 因此,我们从一个我们知道肯定适合我们空间的整个体积的有界实体开始。 从此框中减去从 IFC 文件中的产品创建的半空间。

# Create an initial box from which to cut the halfspaces
common_shape = OCC.BRepPrimAPI.BRepPrimAPI_MakeBox(
    OCC.gp.gp_Pnt(-10, -10, 0),
    OCC.gp.gp_Pnt(10, 10, 10)).Solid()
for halfspace in halfspaces:
    common_shape = OCC.BRepAlgoAPI.BRepAlgoAPI_Common(
        common_shape, halfspace).Shape()

ifcopenshell.geom.utils.display_shape(common_shape)

# Calculate the volume properties of the resulting space shape
props = OCC.GProp.GProp_GProps()
OCC.BRepGProp.BRepGProp_VolumeProperties(shape, props)
print "Space volume: %.3f cubic meter" % props.Mass()
从边界墙和屋顶生成的最终空间体积

这个例子只是触及了 Python、OpenCascade 和 IfcOpenShell 的皮毛。 OpenCascade 提供了多种形状分析和修复工具,可以提取描述性度量,例如本例中的空间体积。


原文链接:Using IfcOpenShell and pythonOCC to construct new geometry

BimAnt翻译整理,转载请标明出处