Creating Bodies using the Facet Modeler

Taras Khalimanenko

ODA’s Facet Modeler uses boundary representation for solid modeling, also called the B-Rep technique. B-Rep is a representation of three-dimensional bodies that describes the boundary of the bodies as a set of connected faces, and each face is a contour on the surface.

Compared to the representation of constructive solid geometry (CSG), in which only primitive objects and logical operations are used to join them, the boundary representation is more flexible and has a much richer set of operations. The relative advantage of systems with B-Reps is the comparative simplicity of converting the boundary representation to the corresponding frame model and vice versa. The reason for this simplicity lies in the fact that the description of boundaries is similar to the description of a frame model, and this facilitates the transformation of a model from one form to another, which makes the systems in the B-Rep representation compatible with existing systems.

There are several ways to create a B-Rep in the Facet Modeler:

1. Creating a primitive body:

There are methods in the interface of the FacetModeler::Body class that allow you to create primitive shapes.

static Body box( const OdGePoint3d& ptOrigin,
const OdGeVector3d& vSizes );
static Body pyramid( const Profile2D& rBase,
const OdGePoint3d& ptApex,
const DeviationParams& devDeviation = FMGeGbl::gDefDev );
static Body extrusion( const Profile2D& rBase,
const OdGeVector3d& vDir,
const DeviationParams& devDeviation = FMGeGbl::gDefDev );
static Body extrusion(const Profile2D& rBase,
const OdGeMatrix3d& mBasePlane,
const OdGeVector3d& vDir,
const DeviationParams& devDeviation = FMGeGbl::gDefDev);
static Body revolution( const Profile2D& rBase,
double dRadius, double dHeight,
const DeviationParams& devDeviation = FMGeGbl::gDefDev );
static Body revolution(
const Profile2D& base,
const OdGeCircArc3d& revolutionAxisAndAngles,
const DeviationParams& deviation = FMGeGbl::gDefDev,
const OdGeMatrix2d* pBaseTransform = 0 );

Example of creating a sphere with the Facet Modeler:

/*
DeviationParams DeviationParams( // structure that stores faceting parameters
  double deviation,              // deviation
  OdUInt16 maxpercircle,         // maximum facets per full circle
  OdUInt16 minpercircle          // minimum facets per full circle
);
*/

Body createSphere(const DeviationParams& devDeviation, double radius)
{
  // Profile2D is a class that represents a set of contours on a plane.
  Profile2D cSphereProfile;            // Create sphere profile
  cSphereProfile.resize(1);            // With one contour

  cSphereProfile.front().appendVertex(OdGePoint2d::kOrigin); // Add first point
  cSphereProfile.front().appendVertex(OdGePoint2d::kOrigin + OdGeVector2d::kXAxis * radius * 2, 1); // Add vertex with bulge == 1 (Arc)

  cSphereProfile.front().setClosed();  // Close profile
  cSphereProfile.front().makeCCW();    // Make contour outer

  // Create revolution body
  return Body::revolution(cSphereProfile, radius, radius * 2, devDeviation);
}

2. It is also possible to create a body according to a given mesh.

static Body createFromMesh(
       const std::vector<OdGePoint3d> & aVertices,
       const std::vector<OdInt32> & aFaceData,
       const std::vector<OdUInt32> * aFaceFlags = 0,
       const std::vector<OdUInt32> * aEdgeFlags = 0,
       const std::vector<OdUInt32> * aVertexFlags = 0,
       const std::vector<OdUInt32> * pFaceColors = 0,
       const std::vector<OdUInt32> * pEdgeColors = 0
);

The main parameters are the vertex array (aVertices) and the array that defines how these vertices form the faces (aFaceData). You can also set additional properties for objects, such as flags (aFaceFlags, aEdgeFlags, aVertexFlags) and colors (pFaceColors, pEdgeColors). Here is an example of using this method:

Body createMeshCube(const DeviationParams& devDeviation)
{
  // Create array of vertices
  std::vector aVertices = {
    OdGePoint3d(0.0, 0.0, 0.0), OdGePoint3d(1.0, 0.0, 0.0),
    OdGePoint3d(1.0, 1.0, 0.0), OdGePoint3d(0.0, 1.0, 0.0),
    OdGePoint3d(0.0, 0.0, 2.0), OdGePoint3d(1.0, 0.0, 2.0),
    OdGePoint3d(1.0, 1.0, 2.0), OdGePoint3d(0.0, 1.0, 2.0)
  };

  // Create array with face data
  // The first number determines how many vertices are in the face.
  // Further ones determine the vertex indices from aVertices.
  std::vector aFaceData = {
    4, 3, 2, 1, 0,
    4, 4, 5, 6, 7,
    4, 2, 3, 7, 6,
    4, 1, 2, 6, 5,
    4, 0, 1, 5, 4,
    4, 3, 0, 4, 7
  };

  Body body = Body::createFromMesh(
    aVertices, aFaceData
  );

  return body;
}

3. A body can be created using Boolean operations on other bodies.

static Body boolOper( BooleanOperation eOperation,
            Body& rOperandA, Body& rOperandB );

Supported operations: Union, Intersection, Difference, XOR.

The following example uses the createSphere function, which we described earlier, to create operands:

Body createSnowman(const DeviationParams& devDeviation, double radius = 100.0, double pressing = 0.1)
{
  // Snowman consists of 3 connected spheres
  Body upper = createSphere(devDeviation, radius / 3); 
  Body middle = createSphere(devDeviation, radius / 2);
  Body lower = createSphere(devDeviation, radius);

  OdGeVector3d vToUp(0.0, 0.0, radius * (1 - pressing));
  middle.transform(OdGeMatrix3d::translation(vToUp * 2)); // Move middle sphere up
  upper.transform(OdGeMatrix3d::translation(vToUp * 3));  // Move upper sphere up

  Body snowman = Body::boolOper(eUnion, upper, middle);   // Merge 2 spheres
  
  // Merge previous result with last sphere
  return Body::boolOper(eUnion, snowman, lower);
}

The result of this example is shown below.

image1

With Boolean operations, you can create a variety of B-Reps (seen in the figure below). Other examples of using Boolean operations can be found in the FacetModeler/examples/FMCreate folder.

image2

 

To learn how to get data from the resulting FacetModeler::Body, see Accessing B-Rep Data Bodies in the Facet Modeler on the ODA blog.