23. Revit API: 几何对象(四)- BrepBuilder

news2024/9/20 2:20:52

一、前言

上一篇写了Solid的创建、展示、变换、布尔操作,这一篇写另一种Solid的创建方法。

需要再次强调的是,BrepBuilder不适合用来创建Solid。


二、边界表示

【Wiki】:边界表示(Boundary representation,简称B-Rep),是一种通过定义其体积限制来表示3D形状的方法。实体表示为连接的曲面元素的集合,这些曲面元素定义内部点和外部点之间的边界。

还有个叫 CSG(Constructive Solid Geometry)的,和一些其它表示方法。我不知道Revit用的是哪种,当然了,API调用仔调API就行了,也只能按开放的接口用。如果不爽调用这破API,可以去看“Open Cascade”,整会了就可以自个儿玩了。

Brep,简单来讲,就是定义每个面,定义面上的范围(边),再把它们严丝合缝的拼起来。

“Geometric Modeling”里面介绍了一些几何建模的方法,了解一下就行了。


三、BRepBuilder

3.1. 使用流程

以创建一个正方体为例。

Ⅰ 准备阶段:

  1. 创建BRepBuilder实例
  2. 创建Surface,即前后左右上下6个平面。
  3. 创建Curve,即正方体12条直线边。

Ⅱ 组装填充阶段:

  1. AddFace
  2. AddEdge
  3. AddLoop
  4. AddCoEdge
  5. FinishLoop,FinishFace
  6. Finish

3.2. 样例代码解释

正方体生成的代码和其它例子,可以查看SDK目录下的“SDKSample/BRepBuilderExample/CreateCube.cs”,或者查看GitHub。

直接看代码可能有点迷糊,这里对组装填充的步骤进行解释。

请结合图来看。

在这里插入图片描述

// 摘自 RevitSdkSamples 
private BRepBuilder CreateCubeImpl()
{
    // create a BRepBuilder; add faces to build a cube

    // BRepType.Solid,表示面都需要朝外;朝内就是Void
    BRepBuilder brepBuilder = new BRepBuilder(BRepType.Solid);
    
    // a cube 100x100x100, from (0,0,0) to (100, 100, 100)
    
    // 1. Planes.
    // 6个面,面的朝向如图
    Plane bottom = Plane.CreateByOriginAndBasis(new XYZ(50, 50, 0), new XYZ(1, 0, 0), new XYZ(0, 1, 0)); // bottom. XY plane, Z = 0, normal pointing inside the cube.
    Plane top = Plane.CreateByOriginAndBasis(new XYZ(50, 50, 100), new XYZ(1, 0, 0), new XYZ(0, 1, 0)); // top. XY plane, Z = 100, normal pointing outside the cube.
    Plane front = Plane.CreateByOriginAndBasis(new XYZ(100, 50, 50), new XYZ(0, 0, 1), new XYZ(0, 1, 0)); // front side. ZY plane, X = 0, normal pointing inside the cube.
    Plane back = Plane.CreateByOriginAndBasis(new XYZ(0, 50, 50), new XYZ(0, 0, 1), new XYZ(0, 1, 0)); // back side. ZY plane, X = 0, normal pointing outside the cube.
    Plane left = Plane.CreateByOriginAndBasis(new XYZ(50, 0, 50), new XYZ(0, 0, 1), new XYZ(1, 0, 0)); // left side. ZX plane, Y = 0, normal pointing inside the cube
    Plane right = Plane.CreateByOriginAndBasis(new XYZ(50, 100, 50), new XYZ(0, 0, 1), new XYZ(1, 0, 0)); // right side. ZX plane, Y = 100, normal pointing outside the cube
                                                   
    // 2. Faces.
    // 填充Face,注意参数True/False,表示面是否需要翻转
    // 面需要朝外,看图,bottom/front/left 都需要翻转面朝向
    BRepBuilderGeometryId faceId_Bottom = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(bottom, null), true);
    BRepBuilderGeometryId faceId_Top = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(top, null), false);
    BRepBuilderGeometryId faceId_Front = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(front, null), true);
    BRepBuilderGeometryId faceId_Back = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(back, null), false);
    BRepBuilderGeometryId faceId_Left = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(left, null), true);
    BRepBuilderGeometryId faceId_Right = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(right, null), false);
    
    // 3. Edges.
    
    // 3.a (define edge geometry)
    // 定义12条边,边的方向如图
    // walk around bottom face
    BRepBuilderEdgeGeometry edgeBottomFront = BRepBuilderEdgeGeometry.Create(new XYZ(100, 0, 0), new XYZ(100, 100, 0));
    BRepBuilderEdgeGeometry edgeBottomRight = BRepBuilderEdgeGeometry.Create(new XYZ(100, 100, 0), new XYZ(0, 100, 0));
    BRepBuilderEdgeGeometry edgeBottomBack = BRepBuilderEdgeGeometry.Create(new XYZ(0, 100, 0), new XYZ(0, 0, 0));
    BRepBuilderEdgeGeometry edgeBottomLeft = BRepBuilderEdgeGeometry.Create(new XYZ(0, 0, 0), new XYZ(100, 0, 0));
    
    // now walk around top face
    BRepBuilderEdgeGeometry edgeTopFront = BRepBuilderEdgeGeometry.Create(new XYZ(100, 0, 100), new XYZ(100, 100, 100));
    BRepBuilderEdgeGeometry edgeTopRight = BRepBuilderEdgeGeometry.Create(new XYZ(100, 100, 100), new XYZ(0, 100, 100));
    BRepBuilderEdgeGeometry edgeTopBack = BRepBuilderEdgeGeometry.Create(new XYZ(0, 100, 100), new XYZ(0, 0, 100));
    BRepBuilderEdgeGeometry edgeTopLeft = BRepBuilderEdgeGeometry.Create(new XYZ(0, 0, 100), new XYZ(100, 0, 100));
    
    // sides
    BRepBuilderEdgeGeometry edgeFrontRight = BRepBuilderEdgeGeometry.Create(new XYZ(100, 100, 0), new XYZ(100, 100, 100));
    BRepBuilderEdgeGeometry edgeRightBack = BRepBuilderEdgeGeometry.Create(new XYZ(0, 100, 0), new XYZ(0, 100, 100));
    BRepBuilderEdgeGeometry edgeBackLeft = BRepBuilderEdgeGeometry.Create(new XYZ(0, 0, 0), new XYZ(0, 0, 100));
    BRepBuilderEdgeGeometry edgeLeftFront = BRepBuilderEdgeGeometry.Create(new XYZ(100, 0, 0), new XYZ(100, 0, 100));

    // 3.b (define the edges themselves)
    // 填充边
    BRepBuilderGeometryId edgeId_BottomFront = brepBuilder.AddEdge(edgeBottomFront);
    BRepBuilderGeometryId edgeId_BottomRight = brepBuilder.AddEdge(edgeBottomRight);
    BRepBuilderGeometryId edgeId_BottomBack = brepBuilder.AddEdge(edgeBottomBack);
    BRepBuilderGeometryId edgeId_BottomLeft = brepBuilder.AddEdge(edgeBottomLeft);
    BRepBuilderGeometryId edgeId_TopFront = brepBuilder.AddEdge(edgeTopFront);
    BRepBuilderGeometryId edgeId_TopRight = brepBuilder.AddEdge(edgeTopRight);
    BRepBuilderGeometryId edgeId_TopBack = brepBuilder.AddEdge(edgeTopBack);
    BRepBuilderGeometryId edgeId_TopLeft = brepBuilder.AddEdge(edgeTopLeft);
    BRepBuilderGeometryId edgeId_FrontRight = brepBuilder.AddEdge(edgeFrontRight);
    BRepBuilderGeometryId edgeId_RightBack = brepBuilder.AddEdge(edgeRightBack);
    BRepBuilderGeometryId edgeId_BackLeft = brepBuilder.AddEdge(edgeBackLeft);
    BRepBuilderGeometryId edgeId_LeftFront = brepBuilder.AddEdge(edgeLeftFront);

    // 4. Loops.
    // 填充轮廓
    BRepBuilderGeometryId loopId_Bottom = brepBuilder.AddLoop(faceId_Bottom);
    BRepBuilderGeometryId loopId_Top = brepBuilder.AddLoop(faceId_Top);
    BRepBuilderGeometryId loopId_Front = brepBuilder.AddLoop(faceId_Front);
    BRepBuilderGeometryId loopId_Back = brepBuilder.AddLoop(faceId_Back);
    BRepBuilderGeometryId loopId_Right = brepBuilder.AddLoop(faceId_Right);
    BRepBuilderGeometryId loopId_Left = brepBuilder.AddLoop(faceId_Left);
    
    // 5. Co-edges. 
    // 定义轮廓,即 向loop中填充边,
    // ① 边需要首尾相连;② 边按右手螺旋定则,方向需要和面一致(即朝外)
    // Bottom face. All edges reversed
    brepBuilder.AddCoEdge(loopId_Bottom, edgeId_BottomFront, true); // other direction in front loop
    brepBuilder.AddCoEdge(loopId_Bottom, edgeId_BottomLeft, true);  // other direction in left loop
    brepBuilder.AddCoEdge(loopId_Bottom, edgeId_BottomBack, true);  // other direction in back loop
    brepBuilder.AddCoEdge(loopId_Bottom, edgeId_BottomRight, true); // other direction in right loop
    brepBuilder.FinishLoop(loopId_Bottom);  // 完成底面轮廓的定义
    brepBuilder.FinishFace(faceId_Bottom);  // 完成底面的定义
    
    // Top face. All edges NOT reversed.
    brepBuilder.AddCoEdge(loopId_Top, edgeId_TopFront, false);  // other direction in front loop.
    brepBuilder.AddCoEdge(loopId_Top, edgeId_TopRight, false);  // other direction in right loop
    brepBuilder.AddCoEdge(loopId_Top, edgeId_TopBack, false);   // other direction in back loop
    brepBuilder.AddCoEdge(loopId_Top, edgeId_TopLeft, false);   // other direction in left loop
    brepBuilder.FinishLoop(loopId_Top);
    brepBuilder.FinishFace(faceId_Top);
    
    // Front face.
    // 略,详情看源码
    // Back face
    // Right face
    // Left face
    
    brepBuilder.Finish();  // 完成构建
    return brepBuilder;
}
// 获取构件结果
Solid mySolid = CreateCubeImpl().GetResult();

3.3. API实用性分析

第一点就是使用繁杂,容易出错。我们看到了,即使是生成一个最简单的正方体,都要大费周章。

而若是使用上一篇写的“GeometryCreationUtilities”呢?

public Solid CreateBox()
{
    XYZ point1 = XYZ.Zero;
    XYZ point2 = new XYZ(100, 0, 0);
    XYZ point3 = new XYZ(100, 100, 0);
    XYZ point4 = new XYZ(0, 100, 0);

    CurveLoop curveLoop = new CurveLoop();
    curveLoop.Append(Line.CreateBound(point1, point2));
    curveLoop.Append(Line.CreateBound(point2, point3));
    curveLoop.Append(Line.CreateBound(point3, point4));
    curveLoop.Append(Line.CreateBound(point4, point1));

    Solid solid = GeometryCreationUtilities.CreateExtrusionGeometry(new List<CurveLoop>() { curveLoop }, XYZ.BasisZ, 100);

    return solid;
}

第二点就是使用难度高。正方体是简单,但若复杂一点呢?曲面、锥面、直纹面、赫尔米特曲面的组合呢,这些面都有现成的API,但问题在于“Edge”,如何去计算多个曲面的交界边是BrepBuilder使用难度高的主要原因。

我这小卡拉米,是算不出曲面与曲面的交线的,就算是最简单的一个平面斜切圆柱,都得写写画画好一会儿。

虽然 Revit Face类提供了计算面交线的方法,但是Surface可没有。Face没有构造方法,只能从Solid上获取。而要使用Brep生成Solid,就需要知道面的交线。这样就死循环了,所以还是得算,这也就是使用难度高。

当然了,该方法有时还是挺好用的,比如说,对一个现有的曲面进行拉伸。

四、总结

这一篇简单写了BrepBilder的使用流程,结合示例进行了解释。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2135043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

顶刊算法 | 鹈鹕算法POA-Transformer-LSTM多变量回归预测

顶刊算法 | 鹈鹕算法POA-Transformer-LSTM多变量回归预测 目录 顶刊算法 | 鹈鹕算法POA-Transformer-LSTM多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现顶刊算法 | 鹈鹕算法POA-Transformer-LSTM多变量回归预测&#xff08;程序可以作为JCR…

外贸展会全流程、如何高效转化,获取更多名片

马上又到展会季了&#xff0c;九十月份是各行各业的展会旺季&#xff0c;很多伙伴们比较关注的是&#xff0c;展会上如何拿到更多名片&#xff0c;如何高效转化客户 一、展会的好处 1、扩展客户资源&#xff1a;接触潜在客户、扩大市场覆盖 2、提升品牌知名度&#xff1a;展示…

学生学籍管理系统可行性分析报告

引言 一、编写目的 随着科学技术的不断提高,计算机科学日渐成熟,其强大的功能已为人们深刻认识,它已进入人类社会的各个领域并发挥着越来越重要的作用。而学籍管理系统软件&#xff0c;可广泛应用于全日制大、中小学及其他各类学校&#xff0c;系统涵盖了小学、初中、高中学籍…

122.rk3399 uboot(2017.09) 源码分析2-initf_dm(2024-09-09)

这里接着上一篇来吧&#xff1a; https://blog.csdn.net/zhaozhi0810/article/details/141927053 本文主要是dm_init_and_scan函数的分析&#xff0c;这个内容比较复杂&#xff0c;我也是第一次阅读&#xff0c;错误之处在所难免&#xff0c;请多指教。 uboot的dm框架需要了解…

去除单细胞数据中环境游离的RNA污染-decontX工具学习

DecontX 是一种用于单细胞 RNA 测序数据的去除环境污染物&#xff08;decontamination&#xff09;的工具&#xff0c;主要用于减少由细胞外RNA造成的污染效应。 开发者在20年的文章中已经把这个工具适用的情况说的非常清楚了&#xff1a;简单来说就是基于微流控的单细胞技术会…

解决PowerAutomate日期处理报错

问题来源 今天尝试做一个简单到到不能再简单的PowerAutomate流&#xff0c;就是读取一个Sharepoint上的Excle表格里的每一行&#xff0c;然后更新到一个list。然鹅确收到了一个意想不到的报错&#xff0c; 报错信息如下&#xff1a; The runtime value "" to be c…

Android 签名、空包签名 、jarsigner、apksigner

jarsigner是JDK提供的针对jar包签名的通用工具, 位于JDK/bin/jarsigner.exe apksigner是Google官方提供的针对Android apk签名及验证的专用工具, 位于Android SDK/build-tools/SDK版本/apksigner.bat jarsigner&#xff1a; jarsigner签名空包执行的命令&#xff1a; jar…

关于Spring Cloud Gateway中 Filters的理解

Spring Cloud Gateway中 Filters的理解 Filters Filters拦截器的作用是,对请求进行处理 可以进行流量染色 ⭐增加请求头 例子 spring:cloud:gateway:routes:- id: add_request_header_routeuri: http://localhost:8123predicates:- Path=/api/**filters:- AddRequestHea…

嵌入式软件工程师:科技浪潮中的关键角色

嵌入式软件工程师&#xff1a;科技浪潮中的关键角色 一、嵌入式软件工程师的职业魅力 &#xff08;一&#xff09;市场需求旺盛 嵌入式软件工程师在当今科技领域中扮演着至关重要的角色。随着智能化时代的到来&#xff0c;嵌入式系统在各个行业的应用越来越广泛&#xff0c;市…

Java API 搜索引擎测试报告

一、测试项目介绍 基于SpringBoot开发的 Java API 文档搜索引擎&#xff0c;输入具体的类名或包名就能找到对应相关的搜索结果&#xff0c;点击标题即可跳转到对应官方网页。 二、测试 测试环境&#xff1a;Windows11&#xff0c;Google chrome浏览器 128.0.6613.138 (正式版…

jmeter 录制APP脚本

一、手机 1、修改网络 代理选择手动→填写服务器主机名&#xff08;电脑IP&#xff0c;如&#xff1a;192.1xx.x.xx&#xff09;→服务器端口&#xff08;任意未被占用端口&#xff0c;如&#xff1a;8888&#xff09; 2、安装证书 手机浏览器访问服务器主机名:服务器端口&a…

通过mqtt通信远程控制大疆无人机

一、控制大疆无人机通信链路如上图所示 二、大疆无人机pilot指令飞行通信交互逻辑如上图所示 三、实现远程控制步骤 3.1前端单独实现&#xff1a;只通过后端获取控制权&#xff0c;然后前端单独发送mqtt指令&#xff0c;延时较低。 3.2前后端一起实现&#xff1a;前端发送ht…

Leetcode - 周赛414

目录 一&#xff0c;3280. 将日期转换为二进制表示 二&#xff0c;3281. 范围内整数的最大得分 三&#xff0c;3282. 到达数组末尾的最大得分 四&#xff0c;3283. 吃掉所有兵需要的最多移动次数 一&#xff0c;3280. 将日期转换为二进制表示 本题就是简单的字符串和整数之…

产品密封防水设计技术、工艺标准及实施方案解培训

一、课程背景&#xff1a; 当前智能产品密封防水能力成为电子产品营销的重要卖点&#xff0c;虽然我们不需长期带着某种电子设备在水下工作和生活&#xff0c;意外却会令价值不菲的电子产品瞬间报废。时下智能手表和耳机成了慢跑伴侣&#xff0c;汗水或雨水长期的侵润腐蚀&…

查谷歌流量什么最准确,服务商提供的工具为什么不能用?

查网站的SEO流量&#xff0c;Google Search Console是最准确的工具&#xff0c;因为这就是谷歌官方提供的工具&#xff0c;谷歌这方面没必要造假&#xff0c;GSC能直接展示你的网站在谷歌搜索中的表现&#xff0c;包括点击次数、展示次数、点击率和平均排名。因为这些数据直接来…

项目需求 | MySQL增量备份与恢复的完整操作指南

目录 一、MySql数据库增量备份的工作原理 1、全量备份与增量备份 2、增量备份原理 二、进行增量备份 步骤1&#xff1a;启用二进制日志 使用 SHOW VARIABLES 命令查看二进制日志状态 步骤2&#xff1a;执行增量备份脚本 三、使用增量备份恢复损坏的数据库 步骤1&#…

[数据集][目标检测]男女性别检测数据集VOC+YOLO格式9769张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;9769 标注数量(xml文件个数)&#xff1a;9769 标注数量(txt文件个数)&#xff1a;9769 标注…

《程序猿之设计模式实战 · 池化思想》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

春意盎然:SpringBoot在线教育平台设计

第五章 系统实现 5.1用户功能模块 用户点击进入到系统操作界面&#xff0c;可以对首页、个人中心、课程信息管理、我的收藏管理、订单管理等功能模块&#xff0c;个人信息&#xff1a;通过列表可以获取账号、密码、姓名、性别、手机、邮箱、照片、备注并进行修改操作&#xff…

网络药理学:15、草稿暂存区(autodock vina)

TCMSP 韦恩图在线网站 https://bioinfogp.cnb.csic.es/tools/venny/index.html String数据库参数详解&#xff1a;https://www.bilibili.com/video/BV1q64y1k7Zf?p16&vd_sourceaed4c634975918b14b7354ec93ce5389 David数据库可以用基因ID或者基因名。 KEGG数据库使用&am…