Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Extracting Outer and Inner Wire Loops from Faces in Open CASCADE

Tech 1

Paramteer Space Orientation Rules

In Open CASCADE's geometric modeling kernel, the distinction between outer and inner wire loops relies on the orientation of wires within the face's parameter domain. When traversing a wire in the positive direction, if the region to your left corresponds to the face interior while the region to your right represents the exterior, that wire constitutes an outer loop. Conversely, if the left side lies outside the face and the right side lies inside, the wire represents an inner loop (hole).

This orientation-based classification proves essential for geometric computations on topological faces, ensuring correct results during boolean operations, intersections, and trimming operations on complex 3D models.

Extraction Workflow

Obtaining outer and inner wire loops from a face involves four key stages:

1. Enumerate all wire loops: Extract every wire loop (TopoDS_Wire) belonging to the target face (TopoDS_Face).

2. Locate the outer wire: Identify which wire serves as the outer boundary. In parameter space, counterclockwise-oriented wires typically represent outer boundaries.

3. Compute signed area: Use vector cross-product methods to calculate each wire's signed area. Counterclockwise loops yield positive areas, while clockwise loops produce negative values. This metric aids in distinguishing loop types.

4. Partition the wires: Separate the outer wire from the remaining loops to isolate all inner wires.

Implementation Example

The following code demonstrates wire extraction using the BRepBuilderAPI and ShapeAnalysis components:

#include <gp_Circ.hxx>
#include <gp_Pln.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <ShapeAnalysis.hxx>
#include <TopExp.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopoDS.hxx>

#include "Viewer.h"

int main(int argc, char* argv[])
{
    gp_Pln basePlane;
    
    // Define three circular boundaries at different locations
    gp_Circ outerCircle(gp::XOY(), 2.0);
    outerCircle.SetLocation(gp_Pnt(5.0, 5.0, 0.0));
    
    gp_Circ innerCircle1(gp::XOY(), 0.8);
    innerCircle1.SetLocation(gp_Pnt(4.0, 5.0, 0.0));
    
    gp_Circ innerCircle2(gp::XOY(), 0.8);
    innerCircle2.SetLocation(gp_Pnt(6.0, 5.0, 0.0));
    
    // Construct edges from circles
    BRepBuilderAPI_MakeEdge edgeBuilder1(outerCircle);
    BRepBuilderAPI_MakeEdge edgeBuilder2(innerCircle1);
    BRepBuilderAPI_MakeEdge edgeBuilder3(innerCircle2);
    
    // Convert edges to wire loops
    BRepBuilderAPI_MakeWire wireBuilder1(edgeBuilder1.Edge());
    BRepBuilderAPI_MakeWire wireBuilder2(edgeBuilder2.Edge());
    BRepBuilderAPI_MakeWire wireBuilder3(edgeBuilder3.Edge());
    
    // Initialize face with bounding rectangle
    BRepBuilderAPI_MakeFace faceBuilder(basePlane, 0.0, 10.0, 0.0, 10.0);
    
    // Add wires to face builder (reverse orientation for inner loops)
    if (wireBuilder1.IsDone()) {
        faceBuilder.Add(wireBuilder1.Wire());
    }
    
    if (wireBuilder2.IsDone()) {
        TopoDS_Wire wire2 = wireBuilder2.Wire();
        wire2.Reverse();
        faceBuilder.Add(wire2);
    }
    
    if (wireBuilder3.IsDone()) {
        TopoDS_Wire wire3 = wireBuilder3.Wire();
        wire3.Reverse();
        faceBuilder.Add(wire3);
    }
    
    // Extract outer boundary using ShapeAnalysis utility
    TopoDS_Face targetFace = BRepBuilderAPI_MakeFace(faceBuilder);
    TopoDS_Wire outerLoop = ShapeAnalysis::OuterWire(targetFace);
    
    // Map all wire shapes in the face
    TopTools_IndexedMapOfShape wireMap;
    TopExp::MapShapes(targetFace, TopAbs_WIRE, wireMap);
    
    // Collect inner wires by excluding the outer boundary
    std::vector<TopoDS_Wire> holeLoops;
    for (int i = 1; i <= wireMap.Extent(); i++) {
        if (!wireMap(i).IsSame(outerLoop)) {
            holeLoops.emplace_back(TopoDS::Wire(wireMap(i)));
        }
    }
    
    // Visualize results
    Viewer viewer(50, 50, 500, 500);
    viewer << targetFace;
    viewer << outerLoop;
    for (const auto& hole : holeLoops) {
        viewer << hole;
    }
    viewer.StartMessageLoop();
    
    return 0;
}

Type Conversion Consideration

When populating a container of TopoDS_Wire objects from a shape map, direct insertion causes compilation errors:

// This produces a compile-time error
holeLoops.emplace_back(wireMap(i));

The shape map stores generic TopoDS_Shape objects that require explicit type conversion. Use the TopoDS::Wire cast function to perform the necessary type narrowing:

// Correct approach with explicit type conversion
holeLoops.emplace_back(TopoDS::Wire(wireMap(i)));

The TopoDS::Wire function performs safe down-casting from the general shape type to the wire subtype, resolving the type mismatch issue.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.