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

下面是一段有趣的代码片段,说明了如何使用 BRepBuilder 和布尔运算来生成 DirectShape。

它可能会在某个地方派上用场,尽管这种方法对于解决手头的任务来说并不是最佳的,如下所述。

问题:我想创建一个由 void geometry 切割的 DirectShape 对象。

我发现 BRepBuilder 构造函数接受 BRepType.Void 和 BRepType.Solid,所以我测试了我是否可以使用它。

但是,到目前为止,我的尝试导致了内部错误。

我的测试代码有没有错误?

DirectShape.AppendShape 方法不接受空形状吗?

答案:在我看来,你实际上想要做的是创建两个实体几何体,然后使用布尔运算将一个减去另一个。

这将给出所需的形状。

查看代码,我注意到函数 CreateBrepVoid 是不正确的——它告诉 BRepBuilder 它想要创建一个空心,但几何定义了一个实体,而不是一个空心。 这是由面和边循环方向决定的。 我假设 BRepBuilder 在过程中的某个时刻抱怨无效输入。

在 BRepBuilder AddFace 和 AddCoEdge 方法的描述中讨论了方向约定。

请注意,BRepBuilder 并不是真正用于“手动”构建几何体。 为此,它的API非常繁琐。 它旨在将现有几何图形转换为 Revit,并对输入几何图形进行相当彻底的验证。

下面是构造两个实体几何图形然后应用布尔运算找出差异的代码。

该代码构建了上图中所示的所需 DirectShape:

[Transaction( TransactionMode.Manual )]
class CmdBrepBuilder : IExternalCommand
{
  /// <summary>
  /// Create a cube 100 x 100 x 100, from 
  /// (0,0,0) to (100, 100, 100).
  /// </summary>
  public BRepBuilder CreateBrepSolid()
  {
    BRepBuilder b = new BRepBuilder( BRepType.Solid );

    // 1. Planes.
    // naming convention for faces and planes:
    // We are looking at this cube in an isometric view. 
    // X is down and to the left of us, Y is horizontal 
    // and points to the right, Z is up.
    // front and back faces are along the X axis, left 
    // and right are along the Y axis, top and bottom 
    // are along the Z axis.
    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.
    BRepBuilderGeometryId faceId_Bottom = b.AddFace( BRepBuilderSurfaceGeometry.Create( bottom, null ), true );
    BRepBuilderGeometryId faceId_Top = b.AddFace( BRepBuilderSurfaceGeometry.Create( top, null ), false );
    BRepBuilderGeometryId faceId_Front = b.AddFace( BRepBuilderSurfaceGeometry.Create( front, null ), true );
    BRepBuilderGeometryId faceId_Back = b.AddFace( BRepBuilderSurfaceGeometry.Create( back, null ), false );
    BRepBuilderGeometryId faceId_Left = b.AddFace( BRepBuilderSurfaceGeometry.Create( left, null ), true );
    BRepBuilderGeometryId faceId_Right = b.AddFace( BRepBuilderSurfaceGeometry.Create( right, null ), false );

    // 3. Edges.

    // 3.a (define edge geometry)
    // 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 = b.AddEdge( edgeBottomFront );
    BRepBuilderGeometryId edgeId_BottomRight = b.AddEdge( edgeBottomRight );
    BRepBuilderGeometryId edgeId_BottomBack = b.AddEdge( edgeBottomBack );
    BRepBuilderGeometryId edgeId_BottomLeft = b.AddEdge( edgeBottomLeft );
    BRepBuilderGeometryId edgeId_TopFront = b.AddEdge( edgeTopFront );
    BRepBuilderGeometryId edgeId_TopRight = b.AddEdge( edgeTopRight );
    BRepBuilderGeometryId edgeId_TopBack = b.AddEdge( edgeTopBack );
    BRepBuilderGeometryId edgeId_TopLeft = b.AddEdge( edgeTopLeft );
    BRepBuilderGeometryId edgeId_FrontRight = b.AddEdge( edgeFrontRight );
    BRepBuilderGeometryId edgeId_RightBack = b.AddEdge( edgeRightBack );
    BRepBuilderGeometryId edgeId_BackLeft = b.AddEdge( edgeBackLeft );
    BRepBuilderGeometryId edgeId_LeftFront = b.AddEdge( edgeLeftFront );

    // 4. Loops.
    BRepBuilderGeometryId loopId_Bottom = b.AddLoop( faceId_Bottom );
    BRepBuilderGeometryId loopId_Top = b.AddLoop( faceId_Top );
    BRepBuilderGeometryId loopId_Front = b.AddLoop( faceId_Front );
    BRepBuilderGeometryId loopId_Back = b.AddLoop( faceId_Back );
    BRepBuilderGeometryId loopId_Right = b.AddLoop( faceId_Right );
    BRepBuilderGeometryId loopId_Left = b.AddLoop( faceId_Left );

    // 5. Co-edges. 
    // Bottom face. All edges reversed
    b.AddCoEdge( loopId_Bottom, edgeId_BottomFront, true ); // other direction in front loop
    b.AddCoEdge( loopId_Bottom, edgeId_BottomLeft, true );  // other direction in left loop
    b.AddCoEdge( loopId_Bottom, edgeId_BottomBack, true );  // other direction in back loop
    b.AddCoEdge( loopId_Bottom, edgeId_BottomRight, true ); // other direction in right loop
    b.FinishLoop( loopId_Bottom );
    b.FinishFace( faceId_Bottom );

    // Top face. All edges NOT reversed.
    b.AddCoEdge( loopId_Top, edgeId_TopFront, false );  // other direction in front loop.
    b.AddCoEdge( loopId_Top, edgeId_TopRight, false );  // other direction in right loop
    b.AddCoEdge( loopId_Top, edgeId_TopBack, false );   // other direction in back loop
    b.AddCoEdge( loopId_Top, edgeId_TopLeft, false );   // other direction in left loop
    b.FinishLoop( loopId_Top );
    b.FinishFace( faceId_Top );

    // Front face.
    b.AddCoEdge( loopId_Front, edgeId_BottomFront, false ); // other direction in bottom loop
    b.AddCoEdge( loopId_Front, edgeId_FrontRight, false );  // other direction in right loop
    b.AddCoEdge( loopId_Front, edgeId_TopFront, true ); // other direction in top loop.
    b.AddCoEdge( loopId_Front, edgeId_LeftFront, true ); // other direction in left loop.
    b.FinishLoop( loopId_Front );
    b.FinishFace( faceId_Front );

    // Back face
    b.AddCoEdge( loopId_Back, edgeId_BottomBack, false ); // other direction in bottom loop
    b.AddCoEdge( loopId_Back, edgeId_BackLeft, false );   // other direction in left loop.
    b.AddCoEdge( loopId_Back, edgeId_TopBack, true ); // other direction in top loop
    b.AddCoEdge( loopId_Back, edgeId_RightBack, true ); // other direction in right loop.
    b.FinishLoop( loopId_Back );
    b.FinishFace( faceId_Back );

    // Right face
    b.AddCoEdge( loopId_Right, edgeId_BottomRight, false ); // other direction in bottom loop
    b.AddCoEdge( loopId_Right, edgeId_RightBack, false );  // other direction in back loop
    b.AddCoEdge( loopId_Right, edgeId_TopRight, true );   // other direction in top loop
    b.AddCoEdge( loopId_Right, edgeId_FrontRight, true ); // other direction in front loop
    b.FinishLoop( loopId_Right );
    b.FinishFace( faceId_Right );

    // Left face
    b.AddCoEdge( loopId_Left, edgeId_BottomLeft, false ); // other direction in bottom loop
    b.AddCoEdge( loopId_Left, edgeId_LeftFront, false ); // other direction in front loop
    b.AddCoEdge( loopId_Left, edgeId_TopLeft, true );   // other direction in top loop
    b.AddCoEdge( loopId_Left, edgeId_BackLeft, true );  // other direction in back loop
    b.FinishLoop( loopId_Left );
    b.FinishFace( faceId_Left );

    b.Finish();

    return b;
  }

  /// <summary>
  /// Create a cylinder to subtract from the cube.
  /// </summary>
  public BRepBuilder CreateBrepVoid()
  {
    // Naming convention for faces and edges: we 
    // assume that x is to the left and pointing down, 
    // y is horizontal and pointing to the right, 
    // z is up.

    BRepBuilder b = new BRepBuilder( BRepType.Solid );

    // The surfaces of the four faces.
    Frame basis = new Frame( new XYZ( 50, 0, 0 ), new XYZ( 0, 1, 0 ), new XYZ( -1, 0, 0 ), new XYZ( 0, 0, 1 ) );
    CylindricalSurface cylSurf = CylindricalSurface.Create( basis, 40 );
    Plane top1 = Plane.CreateByNormalAndOrigin( new XYZ( 0, 0, 1 ), new XYZ( 0, 0, 100 ) );  // normal points outside the cylinder
    Plane bottom1 = Plane.CreateByNormalAndOrigin( new XYZ( 0, 0, 1 ), new XYZ( 0, 0, 0 ) ); // normal points inside the cylinder

    // Add the four faces
    BRepBuilderGeometryId frontCylFaceId = b.AddFace( BRepBuilderSurfaceGeometry.Create( cylSurf, null ), false );
    BRepBuilderGeometryId backCylFaceId = b.AddFace( BRepBuilderSurfaceGeometry.Create( cylSurf, null ), false );
    BRepBuilderGeometryId topFaceId = b.AddFace( BRepBuilderSurfaceGeometry.Create( top1, null ), false );
    BRepBuilderGeometryId bottomFaceId = b.AddFace( BRepBuilderSurfaceGeometry.Create( bottom1, null ), true );

    // Geometry for the four semi-circular edges and two vertical linear edges
    BRepBuilderEdgeGeometry frontEdgeBottom = BRepBuilderEdgeGeometry.Create( Arc.Create( new XYZ( 10, 0, 0 ), new XYZ( 90, 0, 0 ), new XYZ( 50, 40, 0 ) ) );
    BRepBuilderEdgeGeometry backEdgeBottom = BRepBuilderEdgeGeometry.Create( Arc.Create( new XYZ( 90, 0, 0 ), new XYZ( 10, 0, 0 ), new XYZ( 50, -40, 0 ) ) );

    BRepBuilderEdgeGeometry frontEdgeTop = BRepBuilderEdgeGeometry.Create( Arc.Create( new XYZ( 10, 0, 100 ), new XYZ( 90, 0, 100 ), new XYZ( 50, 40, 100 ) ) );
    BRepBuilderEdgeGeometry backEdgeTop = BRepBuilderEdgeGeometry.Create( Arc.Create( new XYZ( 10, 0, 100 ), new XYZ( 90, 0, 100 ), new XYZ( 50, -40, 100 ) ) );

    BRepBuilderEdgeGeometry linearEdgeFront = BRepBuilderEdgeGeometry.Create( new XYZ( 90, 0, 0 ), new XYZ( 90, 0, 100 ) );
    BRepBuilderEdgeGeometry linearEdgeBack = BRepBuilderEdgeGeometry.Create( new XYZ( 10, 0, 0 ), new XYZ( 10, 0, 100 ) );

    // Add the six edges
    BRepBuilderGeometryId frontEdgeBottomId = b.AddEdge( frontEdgeBottom );
    BRepBuilderGeometryId frontEdgeTopId = b.AddEdge( frontEdgeTop );
    BRepBuilderGeometryId linearEdgeFrontId = b.AddEdge( linearEdgeFront );
    BRepBuilderGeometryId linearEdgeBackId = b.AddEdge( linearEdgeBack );
    BRepBuilderGeometryId backEdgeBottomId = b.AddEdge( backEdgeBottom );
    BRepBuilderGeometryId backEdgeTopId = b.AddEdge( backEdgeTop );

    // Loops of the four faces
    BRepBuilderGeometryId loopId_Top = b.AddLoop( topFaceId );
    BRepBuilderGeometryId loopId_Bottom = b.AddLoop( bottomFaceId );
    BRepBuilderGeometryId loopId_Front = b.AddLoop( frontCylFaceId );
    BRepBuilderGeometryId loopId_Back = b.AddLoop( backCylFaceId );

    // Add coedges for the loop of the front face
    b.AddCoEdge( loopId_Front, linearEdgeBackId, false );
    b.AddCoEdge( loopId_Front, frontEdgeTopId, false );
    b.AddCoEdge( loopId_Front, linearEdgeFrontId, true );
    b.AddCoEdge( loopId_Front, frontEdgeBottomId, true );
    b.FinishLoop( loopId_Front );
    b.FinishFace( frontCylFaceId );

    // Add coedges for the loop of the back face
    b.AddCoEdge( loopId_Back, linearEdgeBackId, true );
    b.AddCoEdge( loopId_Back, backEdgeBottomId, true );
    b.AddCoEdge( loopId_Back, linearEdgeFrontId, false );
    b.AddCoEdge( loopId_Back, backEdgeTopId, true );
    b.FinishLoop( loopId_Back );
    b.FinishFace( backCylFaceId );

    // Add coedges for the loop of the top face
    b.AddCoEdge( loopId_Top, backEdgeTopId, false );
    b.AddCoEdge( loopId_Top, frontEdgeTopId, true );
    b.FinishLoop( loopId_Top );
    b.FinishFace( topFaceId );

    // Add coedges for the loop of the bottom face
    b.AddCoEdge( loopId_Bottom, frontEdgeBottomId, false );
    b.AddCoEdge( loopId_Bottom, backEdgeBottomId, false );
    b.FinishLoop( loopId_Bottom );
    b.FinishFace( bottomFaceId );

    b.Finish();

    return b;
  }

  public Result Execute( 
    ExternalCommandData commandData,
    ref string message, 
    ElementSet elements )
  {
    UIApplication app = commandData.Application;
    UIDocument uidoc = app.ActiveUIDocument;
    Document doc = uidoc.Document;

    // Execute the BrepBuilder methods.

    BRepBuilder brepBuilderSolid = CreateBrepSolid();
    BRepBuilder brepBuilderVoid = CreateBrepVoid();

    Solid cube = brepBuilderSolid.GetResult();
    Solid cylinder = brepBuilderVoid.GetResult();

    // Determine their Boolean difference.

    Solid difference 
      = BooleanOperationsUtils.ExecuteBooleanOperation( 
        cube, cylinder, BooleanOperationsType.Difference );

    IList<GeometryObject> list = new List<GeometryObject>();
    list.Add( difference );

    using( Transaction tr = new Transaction( doc ) )
    {
      tr.Start( "Create a DirectShape" );

      // Create a direct shape.

      DirectShape ds = DirectShape.CreateElement( doc, 
        new ElementId( BuiltInCategory.OST_GenericModel ) );

      ds.SetShape( list );

      tr.Commit();
    }
    return Result.Succeeded;
  }
}

请注意,使用 GeometryCreationUtilities 函数创建拉伸比使用 BRepBuilder 更容易,除非本练习的重点是使用后者。

如前所述,使用 BRepBuilder 来“手动”构造几何体非常不方便且容易出错,这不是它的目的。


原文链接:DirectShape from BrepBuilder and Boolean

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