SMLib Functionality



SMLib provides five high level topological operations: Solid Booleans, Merge, Make-Manifold, Topology-Based Filleting and Shell Offset.  Other information about how to create trimmed surfaces and then sew them together into open shells, and about surface-based filleting, is contained in the Trimmed Surfaces Introduction and Tutorial. 

Non-Manifold Topology

This is an introduction to  SMLib Geometric Objects, and how the various pieces of geometry are put together. The relationships between the objects is  the topology and  SMLib topology is similar to that of other systems. This provides a general understanding that will apply to many geometric modeling systems.

When a closed curve lies on a surface, it can be used to trim the surface to that boundary curve and this results in a trimmed surface. If two surfaces share the same segment of a boundary, this is called an edge and the two surfaces are neighbors.  If we have a way to keep track of which surfaces share an edge, we have added a topology to our modeling system. 

A trimmed surface, together with the information about its neighbors is referred to as a face. A face must have an outer boundary and it may have many inner boundaries or "holes".  When two faces are joined along an edge, the result is then referred to as a shell. A shell is just a set of two or more connected faces.

 If a shell is closed then you have a solid. A solid has an outer closed shell and possibly many inner shells that define cavities in the solid. A  "region" encloses space from a closed outer shell  or between two closed shells (one inside the other) and has volume.  The outer region is the infinite region, so a closed box is represented by two regions -  the outer infinite region, and the region within the box.  If there is a box within the box ( a 'thick' box) then there are 3 regions. The inner box may 'float in space' without being attached to the outer may not be physically possible, but it is topologically acceptable.

In a closed solid, each boundary has edges which are shared by two neighboring faces, so this is referred to as a boundary representation or "Brep". The first implementations of a Brep model were Manifold,  that is. ...they allowed for only two faces to share an edge, hence the name "twin-edge boundary representation"....or brep.  If more than two faces can share an Edge, the topology is Non-Manifold. 

It turns out that the manifold restriction that an edge may have only two neighbors is very limiting. Any time you intersect two surfaces, if you look in the neighborhood of a point on the intersection curve, there appear to be four neighboring surfaces at that point. That's what is meant by being "non-manifold".  A manifold edge is restricted to having two neighboring surfaces and a non-manifold edge may have more than two surfaces that share that edge. 

Each boundary of a face consists of a closed loop of edges. In the topology structure each loop has a list of edges, and the same edge may be used by  two or more faces and that's what "EdgeUse" refers to. The term edgeuse has real importance since there could be many uses of an edge.  

If we construct a box (it defines a region) and then if we add another box right next to it, we have another region. Since they share the same face, you can see why we need to have "FaceUses". The face is used on one region, and the face is also used in the other region.

There are many methods for extracting  topological information that defines a Brep.  Down to the FaceUse level, the various methods include:

  • IwBrep::GetRegions()                  Returns the list of regions with the first region being the infinite region
  • IwBrep::GetInfiniteRegion()     May be used to determine which region is the infinite one. 
  • IwRegion::GetShells()                Returns the list of shells for this region. 
  • IwShell::GetFaceuses()               Returns the list of faceuses that define this shell. 
  • IwFaceuse::GetOtherFaceuse()  Returns the faceuse on the other side of this face which will allow us to find which region is next to                                                             the original faceuse. 
To get to the region from a faceuse you use:
  • IwFaceuse::GetShell() .....then
  • IwShell::GetRegion()

Brep - Boundary Representation

 The SMLib Brep model is an instance of a modeling structure called the radial edge structure.

The pieces of the SMLib Brep model include shapes, topology objects, and special connectivity objects called "uses." 

The key idea of Brep modeling is that simple trimmed-shapes connect together through their boundaries to form complex geometry models just as a set of small glass pieces welded together along their edges form a stain glass window.

Shapes are points, curves, and surfaces each of which is a simply connected point set within a 3D space. Shapes can be infinite (planes, cylinders, lines and such) or finite (Bspline curves and surfaces) but have no sense of boundaries. For every shape there is a simple topology object that adds trimming to the shape so that it can be connected into a Brep model. The SMLib simple topology objects are vertices, edges, faces, and regions. Important combinations of simple topology objects forming key boundaries within a geometry model are also represented explicitly; a loop is any closed sequence of connected edges used to bound a face and a shell is any set of faces connected edge-to-edge to bound a region.

We say that a topology object is "used" each time it connects to the geometry model to form a boundary. In general, all of the SMLib simple topology objects participate in a hierarchy of boundaries: regions are bounded by faces (gathered into connected shells), faces are bounded by edges (gathered into connected loops), and edges are bounded by vertices. 

Boundaries are used to establish neighbor relations. Topology objects don't connect directly to their neighbors; rather neighbor relationships are created when two topology objects both use a common boundary. 

A geometry model represented as a hierarchy of boundary connections is referred to as a boundary representation or "Brep" model.

In SMLib, each use of a topology object (that can be used more than one time in one model) is represented by a specialized use object. Each use of a face to bound a region is represented by a Faceuse. Each use of a loop to bound a face is represented by a Loopuse. Each use of an edge to bound a face is represented by an Edgeuse, and each use of a vertex to bound an edge is represented by a Vertexuse. There are no Shelluse objects because shells are used just once per model to bound one region and the shell object can act as its own Shelluse object.

In SMLib, a connection between an object and a boundary is represented as a connection between their use objects.

The following diagram shows the SMLib Brep object model. 


The Brep Object

Now we need to explain some of the details of the SMLib Brep object that is shown in the diagram above. The figures that follow will help us understand how FaceUse, LoopUse, EdgeUse and VertexUse are used in the radial edge structure. 

Faces and FaceUses

Within the SMLib Brep, faces are two sided; each side of a face is represented by a Faceuse and each Faceuse (acting as part of a shell) is used to bound one region. The two Faceuses representing the two sides of a single face are called "mates". Each Faceuse is contained in just one Shell. 

Each Shell has one pointer to its first Faceuse. The first Faceuse has no special significance.
Each Faceuse has a pointer to its owning shell and a doubly linked-list of other Faceuses owned by that shell. 
Each Faceuse has a pointer to its owning face.
Each Face has a pointer to a 3D surface, which defines its 3D shape.

The following diagram represents the connections found between topology objects contained in one Faceuse pointer that has two Loopuses.

This represents the topological information used for one Faceuse on one side of a Face. We are looking at this face from inside the region that this Faceuse bounds. The other side of the face sitting on the other side of this image is not displayed. It is associated with a second Faceuse that contains a mirrored set of all the mate Loopuses, Edgeuses, and Vertexuses shown for this Faceuse. If it were shown, we would be looking at that 2nd Faceuse from a point outside of its region located on the other side of this image.

Note that the Edgeuse only points to one Vertexuse, yet an Edge is (usually) connected to two vertices, one at the start and one at the end. To get both vertices attached to one edge walk the Edgeuse's mate pointer as:

IwVertex *pV1 = pEdge->GetPrimaryEdgeUse()->GetVertexUse()->GetVertex();
IwVertex *pV2 = pEdge->GetPrimaryEdgeUse()->GetMate()->GetVertexUse()->GetVertex();

Shells and Regions

Shells are one sided and are used just once to bound one region. A shell is a set of connected Faceuses all bounding a common region. A region is always bounded by one outer shell defining its overall extent and bounded by any number of inner shells each representing a cavity within the region. There is one special region called the infinite-region that models all space outside of the current model. That one region is an exception in that it has no outer shell, but it may have any number of inner shells marking the distinct pieces of the Brep model as cavities within infinite space. 

When a shell is closed it divides all of space into two regions, inside and out. In SMLib a shell is only connected to its inner region and does not pay attention to outer regions. All of the shells of one region, including the outer shell and all the inner shells, treat that region as their inside region.

For models containing only simply closed shells, the two Faceuses of one face will be contained in different shells. For models with open shells, it is possible to create a face whose two Faceuses are contained in just one shell.

Each region points to one shell that is its first outer shell.
Each shell has a pointer to its owning region and a doubly linked list of other shells owned by that region. The first shell on this list is always the outer shell, the rest are inner shells.

You can pass over to an adjacent shell by moving across a face with the pFaceUse->m_pFUMate Faceuse pointers.

Loops and LoopUses

Faces are bounded by loops. A loop is a closed sequence of connected Edgeuses all bounding a common Faceuse. Loops, like shells, are one sided and bound just one face. A face is always bounded by one outer loop defining its overall extent and bounded by any number of inner loops each representing a hole within the face. Unlike shells Loops are always closed, they are never open. Every Faceuse must have one outer boundary, which is sometimes just the surface boundary edges. SMLib does not allow outer-boundaries to be nested within an inner boundary - in that case it would form a new face.

Since faces are used twice, each loop is also used twice to bound both sides of the face. In SMLib, the actual connection between a face and a loop is made between the Faceuse and the Loopuse. 

One could imagine a face that had different loops on each of its two sides, but in SMLib every loop on a face is represented equally on both sides of the face.

Each Loop has one pointer to its primary Loopuse.
Each Faceuse has a pointer to its first outer loop.
Each Loopuse has a pointer to its owning Loop and to its mate. 
Each Loopuse also has a pointer to its owning Faceuse and a doubly linked list to other Loopuses owned by the same Faceuse. The first Loopuse on this list is always the Faceuse's outer loop and all other Loopuses on this list are inner loops.

The FaceUse points to EdgeUses, not VertexUses. An EdgeUse only points to one VertexUse, yet an Edge has (usually) two vertices, one at the start and one at the end. In order to get the Vertex at one end of an Edge, we get the primary EdgeUse for the Edge, get its VertexUse, and get its Vertex:

  IwVertex *pV1 = pEdge->GetPrimaryEdgeUse()->GetVertexUse()->GetVertex();

To get the other Vertex , we use the mate of the EdgeUse, which is the corresponding oppositely-oriented edge on the other side of the face to provide the VertexUse:

IwVertex *pV2 = pEdge->GetPrimaryEdgeUse()->GetMate()->GetVertexUse()->GetVertex();

Edges and EdgeUses

Edges can be thought of as multi-sided; they may be used to bound any number of faces like a book's spine can bound any number of pages. Each use of an edge (acting as part of a loop) bounds one face. Since faces are two-sided one could again image an edge that bounds only one side of a face and not the other. But in SMLib an edge bounding a face always bounds both sides of that face. So a pair of Edgeuse objects is created every time an edge is used to bound a face. Each Edgeuse is a member of just one Loopuse. The two Edgeuses lie on opposite sides of the face they are bounding, and are called mates. The connection between a face and its edge is represented in SMLib as a pair of connections between the face's two Faceuses and the edge's two Edgeuses.

Edgeuses connect together in two different interesting ways; one is to store the radial/mate information about what faces use this edge (see Radial Edges, below); the other is to store the order of edges ( CW or CCW) that form a Loop boundary (outer or inner) within a face.

Edges themselves are bounded by vertices. An edge is always bounded by two vertices. Edges are always simply connected; there is no concept of a hole in an edge. An edge with a hole is modeled in SMLib as two unconnected edges.

An edge can be open or closed. A closed edge is one where the last point of the edge is the same as the first point of the edge. For closed edges, the start vertex equals the end vertex.

Edges are classified according to how many faces to which they attach.

  •     An edge connected to no faces is called a wire.

  •     An edge connected to just one face is called a lamina edge.
  •     An edge connected to just two faces is called a manifold edge.
  •     An edge connected to more than two faces is called a non-manifold edge.

Each Loopuse will point to its first Edgeuse – which has no special significance.
Each Edgeuse points to its owning Loopuse and has a circular doubly linked list of (CCW and CW) connected Edgeuses all owned by the same Loopuse. The Edgeuse is connected to a face through the Loopuse owner.

Each Edgeuse also has a pointer to its owning edge and has a 2nd circular doubly link list of (radial and mate) connected Edgeuses all owned by the same edge.
Each Edge has a pointer to a 3D curve representing its 3D shape.
Each Edgeuse has a pointer to a Trimcurve used to bound its face's 3D surface.
Note: A manifold modeler assumes every edge will be connected to exactly two faces. The SMLib non-manifold modeler allows any number of faces (from 0 to really large numbers) to be connected to one edge. This difference allows SMLib to model mixed wireframe, surface, manifold, and non-manifold models in one single modeling environment. 

Trimmed Surfaces and Trim Curves

Every Edgeuse has one 2D Trimcurve that marks the bound of the edge's 3D curve in the domain space of the face's 3D surface. Trimcurves turn a surface into a trimmed-surface by dividing a surface into used and unused portions (when rendering a geometry model only the used portions of a trimmed-surface are displayed). Internally, to save space, a Trimcurve is stored just once for every Edgeuse mate pair to prevent storing unnecessary Trimcurve copies 

An Edgeuse's Trimcurve is computed as the projection of an edge's 3D curve onto a face's 3D surface. In SMLib all Trimcurves are represented by 2D Bsplines and care is taken to ensure that the Trimcurve is parameterized in the same manner as the Edge's 3D curve. So, to within tolerance, the point generated by evaluating the Edge's 3D curve for a given parameter, will be the same point generated by evaluating the face's 3D surface at a 2D point found by evaluating the 2D Trimcurve for the common parameter.

Radial Edges

In non-manifold modeling, an Edge may be shared by many different Faces. As a result, it is necessary that we maintain this information in the form of a list of EdgeUses for each Edge. This list of EdgeUses is ordered since it is critical to know the relationship between the Faces that share the same Edge. An Edge together with the ordering of the Faces that share the Edge is referred to as a Radial Edge and it is one of the most important features of this representation. 

This figure shows the radial/mate Edgeuses relationships for one edge shared by two faces.

Here one edge connects to both Face1 and Face2. Face1 and Face2 both have two sides making for 4 Faceuses in total. Each Faceuse is bound by one Edgeuse making for 4 Edgeuses as shown surrounding the Edge between Face1 and Face2. These 4 Edgeuses are connected in a circular sequence of radial and mate relationships.

Note that the 2 EdgeUses of Face1 are associated with each other as Mate so given any EdgeUse


returns the EdgeUse on the other side of the Face. 

EdgeUse2 (eu2) of Face1 and EdgeUse3 (eu3) of Face2 are associated to each other as Radial so given any EdgeUse


returns the EdgeUse on the neighboring Face. 

The real power of this representation is shown by the case where 3 Faces share the same Edge.

Now we see why we needed to introduce FaceUses, LoopUses and EdgeUses. The relationship between all the Faces that share this Edge is now available. Starting with EdgeUse1 (eu1) if we go Mate, Radial, Mate, Radial, Mate, Radial we are back at EdgeUse1.

Note that a single next/previous value in the EdgeUse is used for both the Mate and the Radial pointers. For each EdgeUse either (the next is the radial, and the previous is the mate)  OR  (the next is the mate, and the previous is the radial). Which of these two applies depends on the Orientation -  if it is the same as the primary edgeuse orientation, then the 'next' is the mate.


IwEdge *pE = pEdgeUse->GetEdge();
IwEdgeuse *pPrimEU = pE->GetPrimaryEdgeuse();
if (pPrimEU->GetOrientation() == pEdgeUse->GetOrientation()) 
      pRet = (IwEdgeuse*) (pEdgeUse->GetNext());
      pRet = (IwEdgeuse*)  (pEdgeUse->GetLast);


IwEdgeUse::GetRadial()  is as above with next/last interchanged.

Vertices and Vertex Uses

Vertices, like faces and edges, are also multi-sided in that they can be used to bound any number of edges. One Vertexuse object is created each time a vertex is used to bound an edge. The connection between a vertex and an edge is made between the Vertexuse and the Edgeuse. Edgeuses always come in pairs to match the two sides of a face and it would seem that each connection between a vertex and an edge would require two Vertexuses. In the SMLib internals the number of actual Vertexuses is cut in half by only recording a connection between one Vertexuse and one Edgeuse for each vertex-edge connection. The second connection is deduced when needed at run time by examining the Edgeuse mate relationships. 

The next figure shows the case of 5 Edgeuses starting at one vertex. 

This situation shown in this figure can arise as a planar model in which 5 different faces connect to one vertex through 5 different edges, or it can be thought of, like the last image, as a single vertex attached to one edge that is connected to five different faces oriented so that we see the edge and faces end-on.

In both cases, either 1 edge used 5 times, or 5 edges used 1 time, a total of 10 Edgeuses are bound by this vertex, 5 starting there and 5 ending there. In the figure only those Edgeuses that start at this vertex are shown. The Vertex points to one of the Vertexuses. Each of the Vertexuses points to its owning vertex, to the next and last Vertexuses in the doubly linked list of Vertexuses owned by this vertex, and to an Edgeuse that starts at this vertex.

Walking The Topology Model

There is a set of methods for extracting all of the topological information that defines a Brep. Down to the Faceuse level, the various methods include:

  • IwBrep::GetRegions() Returns the list of regions with one region being the infinite region 
  • IwBrep::GetInfiniteRegion() May be used to determine which region is the infinite one.      
  • IwRegion::GetShells() Returns the list of shells for this region.      
  • IwShell::GetFaceuses() Returns the list of faceuses that define this shell.     
  • IwFaceuse::GetOtherFaceuse() Returns the faceuse on the other side of this face and from this other faceuse you are able to determine which region is next to the original faceuse. 

To get to the region from a Faceuse you use: 

  •  IwFaceuse::GetShell() .....then       
  •  IwShell::GetRegion().


In SMLib, all curves and surfaces are represented by parametric functions. Each curve and surface inherits from its function a natural orientation. 
The parametric functions for curves and surfaces can be written as

    C(t) = [x(t), y(t), z(t)] ;                   t_min <= t <= t_max
    S(u,v) = [x(u,v), y(u,v), z(u,v)];        u_min <= u <= u_max,  v_min <= v <= v_max.

Curves get a direction having a beginning that maps to the curve's smallest parameter value and an end that maps to its largest parameter value. An observer walking along the length of a curve is moving in the positive direction when walking in direction of increasing parameters. At any point, the curve's 1st derivative, d(C(t))/dt, points in the curve's positive direction.

Surfaces get an upward and downward side defined by the parametric surface's oriented surface normal as, 

   surface normal = (d(S(u,v))/du x d(S(u,v))/dv). 

At any point on the surface, the surface normal points to the surface's upward side and away from surface's downward side. An observer located some distance away from a surface at the end of the positive surface normal would be looking back at the upward surface.

Faceuse Orientation:

A Face has an upward Faceuse and a downward Faceuse. Each Faceuse has a normal direction that points into the region that it bounds. The upward Faceuse's normal direction is the SAME as that of Face's Surface Normal. The downward Faceuse's normal direction is the OPPOSITE direction. 

In SMLib, the primary Faceuse pointer stored on a Face is always the upward Faceuse. 
The upward Faceuse's mate is always a Downward Faceuse. Each Faceuse stores an orientation bit whose values is always IW_OT_SAME for upward Faceuses and IW_OT_OPPOSITE for downward Faceuses.

Loop Orientation:

Each Loop stores two Loopuse orientations, one connected to each to the two Faceuses of the face being bounded. By convention the primary Loopuse is always connected to the Face's primary upward Faceuse. The primary Loopuse's mate is always connected to the downward Faceuse stored as the primary Faceuse's mate. 

Loopuse Orientation:

Inner and outer Loopuses have different orientations. Each Loopuse stores an orientation bit whose value is always IW_OT_SAME for outer loops and IW_OT_SAME for inner loops. 

In an outer Loopuse, an observer positioned to look down a Faceuse's normal watching a point traverse the Loopuse's Edgeuses from start to end, will see that point move in a counter-clockwise cycle. The same observer watching a point traverse an inner Loopuse will see that point moving in a clockwise cycle.

Edgeuse Orientation

Every Edgeuse has a direction that marks its beginning and ending vertices and marks which side of the Faceuse it bounds is inside or out. Each Edgeuse stores an orientation bit that is set to IW_TO_SAME when the Edgeuse orientation is the same as the Edge's curve orientation, and IW_TO_OPPOSITE when the Edgeuse's orientation opposes the curve orientation.

LEFT-HAND RULE: The orientation of each Edgeuse is set so that each Edgeuse divides its owning Faceuse into an inside and an outside. The rule is that an observer moving in the positive direction along the length of the Edgeuse and oriented in the same direction as the owning Faceuse's normal will always have the inside of the face on his left hand side. This rule defines a bi-normal vector that always points towards the interior of the face for every point on an Edgeuse.

Bi-normal = cross_product(Faceuse_Normal, Edgeuse_direction).

RADIAL/MATE Edgeuse Orientations:     A pair of mate Edgeuses will always have opposite orientations to one another. Similarly every pair of radial Edgeuses also have opposite orientations to one another. The primary Edgeuse pointed to by an Edge can be oriented in either direction.

CCW/CW or NEXT/LAST Edgeuse Orientations:    The doubly linked list of Edgeuses used to store all the Edgeuses contained in one Loopuse are stored in a pair of pointers called CCW_Edgeuse and CW_Edgeuse. These names are a bit confusing but the pointers are used consistently. 

The CCW_Edgeuse pointer always connects the end of this Edgeuse to the start of the next Edgeuse in the loop. The CW_Edgeuse connects the beginning of this Edgeuse to the end of the previous Edgeuse in the loop. Moving from Edgeuse to Edgeuse through the CCW_Edgeuse point on an outer loop will move an observer around in a Counter-Clockwise cycle of the owning Loopuse. The same traversal on an inner Loopuse will move an observer in a Clockwise cycle.

Vertexuse Orientation

An Edgeuse is bound by two vertices, but is only connected to the vertex at its starting end. All Edgeuses connected to a vertex use that vertex as a starting vertex. The following relation for walking the topology structure from the start vertex of one Edgeuse to the common vertex being used as the end vertex for previous Edgeuse in the owning Loopuse is:

Edge->GetPrimaryEdgeuse()->GetVertexuse()->GetVertex()  ==


The similar relation for moving from an common end-vertex to the next Edgeuse's start-vertex is:



Degenerate Boundaries

In addition to the boundary relationships already discussed, SMLib supports the following boundary relationships,

  • A vertex can bound a face
  • A vertex can bound a region
  • A single open edge can bound a region
These are called degenerate boundary cases because in all these cases some of the intervening levels of the topology model are skipped. In a sense those skipped levels have shrunk to zero area and are now gone.

Vertex/Face Bound Representation

All faces boundaries are represented by Loopuses. When a vertex bounds a face, the Loopuse points to a Vertexuse object (skipping the typical Edgeuse level) and the Vertexuse points back to the Loopuse.

Vertex/Region and Edge/Region Bound Representations

  • All region boundaries are represented by Shells.
  • When a vertex bounds a region, the Shell points to a Vertexuse object (skipping the typical Faceuse, Loopuse, and Edgeuse levels of the topology model) and the Vertexuse points back to the Shell.
  • When an edge bounds a region, the Shell points to an Edgeuse object (skipping the typical Faceuse and Loopuse levels of the topology model) and the Edgeuse points back to the Shell


Boolean operations are supported through the IwMerge::ManifoldBoolean method. You may specify intersection, union or difference. In the case where you have two solids the operation performed is a Regularized Volumetric Boolean. You can also perform Boolean operations between surfaces and solids. The following gives the results for the operations: 
  • Solid Union Surface              yields the solid plus the portion of the surface outside of the solid.
  • Solid Intersect Surface         yields the portion of the surface which is inside of the volume of the solid.
  • Solid Difference Surface      yields the solid plus the portion of the surface inside of the solid. In some cases this may cut the solid into multiple regions (volumes).
  • Surface Difference Solid      yields the portion of the surface not inside the solid.
  • Surface Union Surface         yields the two surfaces plus attached by an intersection curve.
  • Surface Intersect Surface    yields just the intersection curves.
  • Surface Difference Surface yields the first surface with the curves of intersection.
One great thing about having an underlying NMT representation is that the Boolean operation is now a closed operation. In other words you can not do a Boolean that would produce something you can not represent topologically. Under traditional manifold systems the union of two solids which just touch along an edge or at a vertex is not a valid representation. The following code demonstrates how to set up and difference two Breps:
double dAngleTol = 20.0*IW_PI/180.0;  // Angle tolerance used during surface intersection.
double dApproxTol = 1.0e-3;  // Approximation tolerance used during surface intersection
IwBrep *pBrep1 = ...; // base brep in difference
IwBrep *pBrep2 = ...; // subtracted brep
IwMerge  sMerge(crContext, pBrep1, pBrep2, dApproxTol, dAngleTol);   // Initialize merge object
IwBrep *pResult;  // Result of pBrep1 - pBrep2
SER (sMerge.ManifoldBoolean(IW_BO_DIFFERENCE, pResult));  // Perform Boolean operation


The Merge operation is like the Boolean in that it combines the topologies from two separate Breps. The major difference being that the Merge only adds topology it does not remove any topology. For example the Merge of a box and a cylinder may will contain all of the original edges and faces of both the cylinder and box plus any intersection edges. The Merge of two solids will typically create edges which have four or more faces and may have several regions (volumes).

The Non-Manifold Topology enables us to represent the results of the Merge completely and explicitly with a single topological structure. We do not need to break things up into separate volumes. You may merge any combination of wireframe, surfaces, open shells, solids, and non-manifold topology models. To invoke the merge operation you do the same thing as show above in the Boolean except that the operation you send in is "IW_BO_MERGE " instead of "IW_BO_DIFFERENCE ". 


The Make-Manifold operation produces a manifold solid or cellular topology from a non-manifold topology. It deletes excess faces, edges and vertices to get to either a manifold topology or cellular topology. The following shows how to utilize the operation. 
SER(pResult->MakeManifold(NULL, FALSE));
    // Make manifold by default uses all regions 
    // except the infinite region.
    // Do not keep interior faces.
IwTArray<IwRegion*> sRegionsToKeep = ....;
    // Somehow we select which regions to keep in 
    // a cellular topology.
SER (pResult->MakeManifold(sRegionsToKeep, TRUE));
    // Remove all faces not bounding one of
    // sRegionsToKeep.  Note that any faces which
    // between regions will also be kept.


As noted above, the Merge process followed by the Make Manifold operator may be used to create a solid object.  One thing that you should know right away is that solids are not only one of the most powerful representations, they are also the most prone to failure. It is even more difficult to control errors that are found in solids that have been imported from other systems as opposed to those which are built within a given system.  Hence many times the reliability of SMLib in dealing with solid models is dependent upon receiving good data.

SMLib does a lot of work on its own to try to measure the gaps between adjacent edges, vertices and faces and to adjust the tolerances to close the gaps. Although the problem is a difficult one, we have designed SMLib to try to handle many of the problems and to fail gracefully when it can not.  SMLib is also highly dependent upon the initial tolerance set for the IwBrep prior to creation. If the tolerance is too large, it will invalidate small features. If the tolerance is too small you will get warnings when we increase the tolerances to fill the gaps. As a general guideline, a tolerance of 1.0e-3 to 1.0e-6 of the size of the Brep should work the best. The higher the quality (smaller the gaps) of the original Brep the smaller the tolerance should be. 

An additional way to construct a solid is through an indexed tabulated representation of our topology. The tabulated representation can be found in the IwBrepData include and source files. SMLib also includes a non-production IGES reader which demonstrates how to load up the IwBrepData object from an IGES solid and create a IwBrep (see IwIgesReader.h and IwIgesReader.cpp). There is also a section in the TSLib Tutorial which demonstrates creation of a solid box using the IwBrepData object. 

A word about m_bEditingEnabled. We have added a flag to IwBrep which enables editing. There are many of the creation and a few editing operations which require the m_bEditingEnabled flag to be turned on. An example is sewing. This flag needs to be turned off to make many of the evaluation functions work. 

Shell Offset

One of the more difficult operations in solid modeling is the process of offsetting a solid object by a specified distance to create the new offset shell. As the offset distance increases, there may be massive changes in the topology of the object. By using the Merge operation, the SMLib shell offset process is able to correctly process these massive changes in the topology. Access to this functionality is available via the: IwOffsetExecutive, IwOffsetGeometry - two  classes that support offsetting and shelling of solids. See usage examples in iwoffset_test.cpp.

Offset of a Solid

The implementation of the Solid Offsetting Algorithm is  relatively simple given the powerful tools available within SMLib.  Offsetting utilizes facilities from the SMLib Merge and SMLib Filleting to do most of the difficult work.  This unique approach also keeps special case handling to a minimum.  The entire algorithm was implemented with two new classes (IwOffsetExecutive and IwOffsetGeometryCreation) and less than 20 new methods of moderate size.  The basic approach is as follows:

1)       Generate faces representing the offsets of existing faces of a solid. 2)       Insert self-intersection edges of offset faces. 3)       Generate faces representing the offsets of edges of the solid.  This utilizes filleting tools to generate circular blends between corresponding edges of offset faces.  In cases where the offset faces have self-intersections, a single edge may require several blends and corner patches.  4)       Generate offset faces for vertices.  We use a triangular trimmed piece of a sphere for simple cases and a complete sphere for some more difficult cases. 5)       Utilize the “Partial Merge” to put all of the offset faces together.  Note that we utilize existing topological relationships eliminate unnecessary surface/surface intersections and speed up the process several orders of magnitude over a straight “Merge”. 6)       After the “Partial Merge” we need to identify which regions (i.e. volumes) to keep.  In most cases this is just the shell bounding the outer region.  However, it is possible to create void regions within a solid. 7)       Call “Make Manifold” with the selected regions to remove all topology elements not bounding the given regions.

This algorithm lends itself to the creation of very large offsets where the offsets of features of the solid intersect each other.  This type of offset is ideal for various NC operations.  Right now the algorithm works quite well with analytical parts that don’t have freeform fillets, blends, and corner patches.  The proper handling of these things requires identification and special handling.  The best way to do it is to regenerate the fillets, blends, and corner patches directly from the offset surfaces instead of trying to offset the surface directly.  There are also some problems with self-intersecting surfaces that are basically impossible to solve in a reasonable way.  For solids with these type of surfaces, it is only possible to create offsets of relatively small radius.       


Shelling of a Solid

The implementation of a shelling algorithm required only a few slight modifications to the Offset Solid algorithm:

  1. We allow the specification of a zero offset distance for a face (currently required to be planar).
  2. If an edge belongs to the shelling face, we connect the corresponding offsets using a plane instead of a circular blend.
  3. If a vertex belongs to a shelled face.  We blend it using a piece of a plane instead of a sphere.

Once the shelled solid is created it can be used in a number of ways to do very powerful operations.

  1. Subtraction of original solid or smaller radius offset to create a shelled solid.

  2. Ribs can be easily created by subtracting thin boxes from inner solid prior to the final difference operation.

Non-Manifold Sweep

SMLib has the ability to sweep faces, edges, and vertices to the same dimension or to a higher dimension.

  • The sweep of a face to the same dimension produces a copy of the face at the terminal position.
  • The sweep of a face to a higher dimension produces a solid volume between the original face and the terminal position face.
  • The sweep of an edge to the same dimension produces a copy of the edge at the terminal position.<
  • The sweep of an edge to a higher dimension produces a face between the original edge and the terminal position edge.
  • The sweep of a vertex to the same dimension produces a copy of the vertex at the terminal position.
  • The sweep of a vertex to a higher dimension produces an edge between the original vertex and the terminal position vertex.

The Non-Manifold Sweeping is designed as an Object-Oriented Framework. Application developers can easily create new geometric sweeps by implementing a new subclass that produces the geometry for the sweep operation while the Framework builds the topology for the sweep.


Polygon Modeling

SMLib contains NURBS and analytical geometry modeling tools, polygonal modeling tools and functions to convert between the forms.  SMLib's topology-based tessellation enables users to select from a variety of tessellation criteria to produce polygons which are optimized for various applications.  The underlying geometric and topological information is used to produce a minimal number of polygons in a process known as "Polygon Optimization".  SMLib produces "Crack-Free" polygonal meshes for connected sets of trimmed surfaces or solids at all tessellation tolerances.  SMLib also contains a large variety of polygonal modeling functionality including polygon decimation, polygonal Booleans, sectioning, ray-firing, classification functions, etc.  The performance makes it suitable for highly interactive applications.



Tessellation is the process of converting smooth curves, surfaces and faces into linear or polygonal segments. See the SMLib Tutorial section for an example of source code.

This has many uses, primarily in graphics, where curves are represented by a large number of small line segments, and surfaces get converted into planar triangles, which are then passed to a graphics engine for display.

The criteria for tessellation may be selected by the user. In general they relate to curvature, (the flatter the curve, the less line segments are needed), and absolute size (very tiny curves would require less lines than very large curves of the same shape).

  •  Tessellation Criteria
    • Chord Height Tolerance
    • Angular Tolerance
    • Maximum Aspect Ratio
    • Maximum Polygon Edge Length
    • Minimum UV Polygon Edge Length
  • Dynamic tessellation
    • Object Oriented Curve and Surface Subdivision Classes  allow the user to modify the tessellation criteria during the tessellation process.  For example, in a graphical application the user could adjust tessellation criteria based on distance from an "Eye Point" of the geometry being subdivided.  This customizability feature enables the Tessellation Library to easily be adapted to different applications.  See the view dependent tessellation example in the "Tessellation Criteria" image.
  • Tessellation Output:
    • As a topological data structure which contains a connected set of polygons with 3D points, UV points and surface normals.
    • User Call Backs with 3D points and surface normals. You will need to subclass the IwPolygonOutputCallback class and implement the OutputPolygon method on to implement the callback.
  • "Crack-free" Tessellation:
    • SMLib offers a significant upgrade to NLib and OpenGL tessellation, in that it ensures that there are no cracks between tessellations of faces that share a common edge. This ensures that the shaded image will not contain ugly black cracks along the joins in the shaded image.  This process is complex, and may account for some lack of performance, but the results show a significant improvement over competing products.

Polygon Booleans

Polygonal Objects can be read in from external files, or created from an SMLIb Brep object and converted into a IwPolyBrep object, using a routines such as  Brep_to_PolyBrep_Conversion(). The criteria are those used for tessellation. Very large complex models using polygons will show a very significant performance improvement over their precise-geometry counterpart.

Many of the standard operations can be performed on PolyBrep's, such as:

  • Booleans operators:  3-D volumetric Union, Intersection, and  Difference with support for N-sided polygons with multiple holes.
  • Ray firing
  • Closest point calculations

See the SMLib Tutorial section for an example of source code.



Decimation is the process of removing polygons to achieve a significant data reduction with an acceptable loss of accuracy.  This allows very large models to be reduced to a size where the performance of some of these complex operations can be run in real-time.

Two decimation algorithms are available:

  • a vertex removal decimation algorithm that utilizes accumulated error measurement
  • an edge squeezing decimation algorithm that utilizes a fast quadric error distance to choose optimal points.

See the SMLib Tutorial section for an example of source code.




Filleting is the insertion of a connecting surface, called the fillet surface, between two other surfaces to control the shape of how the two surfaces connect to one another.  The common fillet sequence is to replace an existing edge between two surfaces with a new fillet surface and two new rail curves marking where the new fillet surface connects to the original base surfaces.  Typically the original surfaces need to be trimmed back to the new rail curves.  This trimming operation, along with the creation of the fillet surface, the rail curves, and the modification of the topology connections to make sure that all the pieces are connected together within the Brep model, are all parts of the filleting functionality.  Additionally, when working with Brep models, extra care is taken at the ends of the fillets to connect the new fillet geometry (the fillet surface and the rail curves) to the rest of the Brep.  The fillet operation manages this by creating special-case fillet end-cap surfaces, edges, and vertices as necessary.

SMLib supports several different kinds of fillet surface shapes to enable several different styles for connecting one surface to another.  All but the linear cross section blend of these styles connect the surfaces together smoothly, replacing sharp edges with rounded-smooth edges and corners.  The linear cross section blend is used to insert chamfers.  These styles include constant radius blends, variable radius blends, circular cross section blends, linear cross section blends (chamfers), and G1, G2 and G3 continuous blends.  SMLib filleting has been implemented in a modular fashion making it straightforward to add additional fillet styles, potentially including things like elliptical, parabolic, and cubic blends.


Filleting Framework

SMLib has implemented a filleting framework which handles a wide range of topological cases with a reasonable set of geometric cases.  The framework handles the common bookkeeping tasks and has object-oriented handlers to accommodate difficult conditions.  Examples of difficult conditions include fillets rolling off the edge of a surface, and fillet rail curves self-intersecting.  SMLib implements a basic set of default handlers for each of these conditions.  If necessary, end users can change the default behavior by implementing a subclass of the particular handler.  For example, if the fillet rolls off the surface, the user might want to change the default behavior of rolling the fillet over onto the adjacent surface to cutting the fillet, rolling a ball along the edge, or just quitting.  Users can also implement a subclass handler to change the default behavior of correcting for self-intersecting rail curves

The Filleting Framework supports both Surface-Based Filleting and Topology-Based (or Solid-Based) Filleting.  Surface-Based Filleting takes two surfaces and produces a separate fillet surface between them and optionally trims the original surfaces to the new rail curves of the fillet surface.  Topology-Based Filleting takes a single Brep and inserts new topology to round edges and corners.  Topology-Based Filleting can add fillets to any manifold edge within a solid, open shell, or non-manifold Brep.  Because SMLib represents Non-Manifold Topology, SMLib is able to represent results of situations that would normally cause failures in other systems.

SMLib's Filleting Framework is extremely flexible.  Adding new functionality to the Framework is the real power of this software.  It is designed to make adding seamless extensions as easy as possible.  For example, the addition of variable-radius filleting required the implementation of only five methods totaling less than 200 lines of code.  Should you decide to extend the Filleting capabilities of SMLib in your system, there are examples to guide you in extending the existing functionality in the Framework.  In addition, SMS will be glad to offer you guidance in implementing the extension that you want.

The Filleting Framework also supports a simplified filleting interface that removes most of the complexity for an application to add fillets to Brep models for most typical filleting cases.  With a constructor call and two subroutine calls, an application can fillet any selection of edges in a model, with any combination of radius functions and cross section shapes.

This document contains everything you need to know to both utilize existing filleting functionality and to customize the existing functionality to your specific needs.  Let us begin by introducing the basic concepts and terminology used in SMLib.



The following terms will be used in this document:

Fillet Surface: A new surface that is added to the model during the filleting operation.

Filleted Edge, or Edge to be Filleted: The edge of the original Brep to which the fillet is applied.  This edge will disappear during filleting, and be replaced with fillet surfaces.  One filleted edge is usually replaced by one fillet surface, but it can be more than one, or zero, depending on the radius of the fillet and the surrounding geometry and topology.

Rail Curves: The "long edges" of a fillet surface, which run along the two original faces that meet at the filleted edge.  The rail curves are calculated first, before the fillet surface itself, and their intersections with other body topology, and with themselves, largely determine the overall filleting situation.

Fillet Corner: The filleting activity at the vertices of the filleted edges.  In topology-based filleting, this will depend on the number of body edges incident at the vertex, which of those are to be filleted, their relative convexity, and how the rail curves intersect with the surrounding topology.  New edges and faces can be created at fillet corners.

Cross Section: The shape of the cross section of the fillet surface.  This is created after the rail curves are traced out, and is independent of the radius of the fillet.  Fillet surfaces typically have a circular cross section for constant and variable radius rolling ball blends or linear cross sections for chamfers, but other shapes are possible.


Using the Filleting Framework

SMlib uses three concepts to specify how to place the rail curves, form the fillet surface shape, and connect the ends of the fillets to the rest of the Brep geometry.   These concepts are the radius of the fillet, the fillet surface cross section shape, and the fillet corner generation methodology.

Radius Definition: The radius definition controls where SMLib generates the shape of the rail curves on the two underlying surfaces of the edge being filleted.  These rail curves are used both as the fillet surface bounds and to connect the fillet surface to the original underlying surfaces.  Examples of SMLib radius definitions include Constant Radius Rolling Ball, Variable Radius Rolling Ball, and Constant Distance Between Rail Curves.  The Radius Definition is implemented in the classes derived from IwFilletSolver.

Cross Section Type: The cross section type controls the cross section shape of the fillet surface between the two rail curves.  Examples of SMLib cross section types include Circular Cross Section (Round), Linear Cross Section (Chamfer), and G1, G2 and G3 continuous blends.  Other possible cross sections could include elliptical, parabolic, and cubic blends.  Cross section shape is implemented in classes derived from IwFilletSurfaceGenerator. Note that the Radius Definition and the fillet surface Cross Section Type are independent and can be mixed and matched in any way.

Fillet Corner Generation: The fillet corner generation methodology specifies what happens at the ends of topological fillets.  At vertices where only a single edge is filleted, this specifies how the end of the fillet joins the original Topology.  For example, fillets may be extended to intersect adjacent surfaces, or there may be an extension of an adjacent surface to fill a gap.  At vertices where more than one edge is filleted, this specifies how the fillets will join each other.  For example, fillets may be joined by a Bevel or by a Corner Blend.  Fillet corner generation is handled by classes derived from IwFilletCorner.  It is generally done automatically by the system.


Surface-Based Filleting

See the TSNLib Functionality Document for details.


Topology-Based Filleting

Topology-Based Filleting takes as input a single Brep model and modifies that representation to insert fillet topology and geometry.  The algorithm is an edge- and vertex-filleting algorithm.  You choose edges to fillet and attach Fillet Solvers to the edges.  The Fillet Solvers tell the Filleting Framework how the filleting should be done.  A default mechanism is used to either blend or bevel the joints between edge fillets that meet at a vertex.  It is possible to fillet both solids and open shells.

Filleting Process

Applications can fillet any combination of manifold edges within solid, shell, and non-manifold Breps using either SMLib's simplified filleting interface or by calling filleting class methods directly.   The simplified filleting interface should be sufficient for most common filleting operations.

The Simplified Filleting Interface process:

  1. Create an IwFilletExecutive object
  2. Call one of the versions of the Fillet Executive's SetFilletParameters() method, to specify the edges to be filleted, the radius and cross section information for each, and tolerances.
  3. Call the DoFillet() method of the Fillet Executive to perform the filleting operation
The Direct Fillet Class Interface process:
  1. Create an IwFilletExecutive object
  2. Specify the tolerances for the filleting
  3. For each edge to be filleted:
    • Create a Fillet Solver of the appropriate sublcass of IwFilletSolver to specify the radius
    • Create a Fillet Surface Generator of the appropriate subclass of IwFilletSurfaceGenerator to specify the cross section
    • Attach the Fillet Surface Generator to the Fillet Solver
    • Load the Fillet Solver into the Fillet Executive
  4. Call the CreateFilletCorners() method of the Fillet Executive to set up the fillet corners
  5. Call the DoFilleting() method of the Fillet Executive to perform the filleting operation
There are several examples of using both approaches in SMLib's Examples set, and in the source code.


Status of Topology-Based Filleting

In this section we discuss the current state of the three basics of SMLib filleting: radius definition, cross section shapes, and fillet corners. We also discuss the capabilities of SMLib in the case where the specified radius is too large to fit into a rounded inside corner, or interferes with other topology.

Fillet Solvers: Radius Definition

The first step of topology-based filleting is to define and associate a fillet solver to a manifold edge to specify how to construct the fillet's rail curves.  Any manifold edge can be filleted whether that edge is in a manifold, a non-manifold, or shell Brep.  Manifold edges are edges connected to exactly two adjacent faces. The three currently implemented fillet solver types that generate rail curves are:
  • Constant Radius Rolling Ball: a theoretical sphere of constant radius is rolled along between two surfaces.  The points where the ball touches the surfaces defines the rail curves.  In some cases the ball may actually roll onto an adjacent surface or onto adjacent edges.  (See "Constant Radius" in the Figures below.)
  • Variable Radius Rolling Ball: a theoretical sphere that changes radius according to some predefined law is rolled between two surfaces to trace out rail curves.   The law is typically defined relative to the edge being filleted. There are several ways to define the radius function.  (See "Variable Radius" in the Figures below.)  It is possible to have the fillet radius go to zero at one or both ends of the edge.
  • Constant Distance Between Rail Curves: a theoretical sphere that changes radius to keep the distance between two rail curves constant is rolled along to trace the rail curves.  (See "Constant Distance" in the Figures below.)

Fillet Surface Generators: Cross Section Shapes

The second step of topology-based filleting is to define and associate a fillet surface generator to the edge being filleted.  After the edge's fillet solver has been used to define the rail curves, the edge's fillet surface generator is used to specify the shape of the fillet surface that fills in the space between the two rail curves.  The following fillet surface generation techniques have been implemented:
  • Circular cross section – Rolling-ball Fillet: produces a surface whose cross sections are either an exact rational circle, or an approximation of a circle (IwCircularCrossSectionFSG)
  • Linear cross section – Chamfer: produces a surface with a linear cross section. (IwLinearCrossSectionFSG)
  • Higher-continuity blend-curve section: produces a surface that meets the base surfaces with G1, G2, or G3 continuity across the rail curves.  The actual fillet surface cross section shapes are created by skinning the rail curve boundary constraints. (IwBlendCurveCrossSectionFSG)

      Cross section shapes:  Circular (black);   G1 continuity (red);   G2 (green);   G3 (blue).


Fillet Corners

The final step of topology-based filleting is to define and associate a fillet corner object (IwFilletCorner) to every vertex attached to an edge being filleted.  This controls how the edge fillets get connected to pre-existing and other newly created fillet geometry.  SMLib automatically selects the type of fillet corner object to associate with each vertex depending on the number of edges connected to the vertex and the relative convexities of those edges.

SMLib uses the following notation:  a fillet corner where N total edges are incident, and M of them are to be filleted, is denoted an NxM corner.  The following fillet corner cases have been implemented:

  • Nx1 Closed Corner (IwFilletNx1ClosedCorner)  Denotes a case where the edge to be filleted is a closed edge (i.e. top edge of a cylinder) that attaches to the vertex two times.  It can have either zero or one additional edges coming into the vertex.  If the edge meets itself tangentially (as with a cylinder), the fillet surface will be closed and joined without any trimming.  In the non-tangent case (e.g., teardrop shape, extruded), the fillet surface is split in the middle, and the pieces are intersected where they meet.
  • 3x1 Corner (IwFilletNx1Corner)  Denotes a case where there are 3 edges adjacent to a vertex and one of them needs to be filleted.  There are three cases here, depending on the relative convexity of the three edges, and which edge is to be filleted.
    • If all three edges have the same convexity ("univex"), the rail curves intersect nicely with the adjacent Brep edges, and the fillet surface intersects with the untrimmed end face.  The end face will be trimmed back to the fillet surface.
    • If one of the three edges has the opposite convexity to the other two ("mixed convexity"), and the filleted edge is the one with opposite convexity, then the rail curves will still intersect nicely with the adjacent Brep edges, but the end face must be extended to be intersected with the fillet surface.  The end face will be extended out to the fillet surface.
    • In the mixed-convexity case where the filleted edge is one of the two with the same convexity, then one of the rail curves will not intersect with the adjacent Brep edge; that edge must be extended to intersect the rail curve.  Again, the end face must be extended to be intersected with the fillet surface, and will be extended out to the fillet surface.

  • 3x2 Corner (IwFilletNx2Corner)  Denotes a case where three edges are adjacent to a vertex and two of them are to be filleted.
    • If the filleted edges are tangent at the vertex and have the same radius and cross section, the fillet surfaces will be joined tangentially without any trimming or intersection.  (If they have a different radius or cross section, they cannot be filleted.)
    • At a univex corner (all edges with same convexity), adjacent rail curves will intersect each other, the other two rail curves will intersect body edges, and the fillet surfaces will intersect each other.  In this case the fillet surfaces will be intersected and a bevel created.
    • At a mixed-convexity corner where the two filleted edges have opposite convexities, adjacent rail curves will intersect, the fillet surfaces will intersect, and a corner patch will be created.
    • At a mixed-convexity corner where the two filleted edges have the same convexities, the rail curves that are in the same face must be extended and/or blended to meet. A corner patch will also be created.

  • NxN Same-Convexity Corner (IwFilletConvexNxNCorner)  Denotes a case where all edges adjacent to a vertex are to be filleted and all of the rail curves intersect.  This case will create a 3, 4 or N-sided tangential corner blend between all of the adjacent fillet surfaces.  In some cases the corner will be an analytical surface (Sphere).  In the N-sided corner case, when N > 3, multiple four-sided patches will be created to fill the corner.  It is also possible to utilize this corner to produce a beveled case instead of a blend by setting the SetBevelFlag to TRUE for the corner.
  • NxN Mixed-Convexity Corner (IwFilletConcaveNxNCorner)  Denotes a case where all edges adjacent to a vertex are to be filleted and not all of the rail curves intersect. In this case a blend curve will be made between the rail curves on the given face.  The tangential corner blend will then be made between adjacent fillet surfaces and the blend curves.  In some cases the corner will be an analytical surface (Torus).
  • Open Shell Corner (IwFilletOpenCorner)  Denotes a case where there is no ending face.  Two of the edges are lamina edges and the edge to be filleted is the only manifold edge at the vertex.  The fillet will be trimmed by a line in the parameter space of the fillet surface between the vertices.
  • Tangent Surface Corner A corner where the faces adjacent to the filleted edge become tangent.  The fillet surface becomes degenerate where the adjacent faces become tangent.  See the Figure entitled "Disappearing Fillets with Tangent Faces".
  • Degenerate Rail Fillets The case where one of the rail curves degenerates to a point.  An example of this would be filleting the top of a cylinder with a radius the same as the cylinder.


      Examples of 3xN fillets at a mixed-convexity corner.  Note the extensions of body faces and edges in some cases.  A 3x3 (NxN) case is pictured for completeness.


Example: Chamfer, and NxN corners, same- and mixed-convexity cases.


Large Radius Filleting

Standard filleting algorithms assume that the size of the fillet is relatively small compared to the size of the features of the object being filleting.  For example, they assume that the radius of the fillet is smaller than the radius of curvature of the surfaces of the edge being filleted.  They also assume that the rail curves of a fillet surface do not intersect interior features of the face, and that they do intersect the adjacent topological edges at each vertex.  These assumptions make the implementation of filleting easier, but they do not cover an adequate number of cases required by real-world engineering problems.  Therefore SMLib has algorithms to handle large-radius situations.   SMLib's large-radius capabilities in the Filleting Framework include:
  1. Self-Intersecting Rail Curves: If the rail curves of a fillet self-intersect, this generally means that the radius of the fillet is larger than that of one of the original base surfaces.  In this case, the fillet is trimmed back from intersection and a blend surface is inserted.  See the results in the Figure "Self-Intersecting Rail Curves",  below.
  2. Small Adjacent Edges: If the rail curve fails to intersect the adjacent edge at a vertex of the edge to be filleted, SMLib utilizes classification to determine the intersection.
  3. Rail Curves Intersecting Features: this occurs when a fillet rail curve intersects any edge of the original body other than the one that is adjacent at the vertex. There are several classes of this problem, which are pictured below.
  • Tangent Surface Rollover: fillet rolls onto another surface which is tangent to base surface.
  • Cliff Rollover: fillet rolls off the edge of a cliff and gets trimmed by an extension of the cliff face.
  • Positive Fillet/Positive Feature: a positive fillet rolls into positive object like a Boss – fillet is created and flows around the boss.
  • Negative Fillet/Negative Feature: fillet cuts away part of an interior negative feature like a hole in a box near the edge.
  • Negative Fillet/Positive Feature Interaction: a negative fillet runs into a positive feature and the positive feature gets extended down to meet the fillet surface.
  • Positive Fillet/Negative Feature Interaction: fillet rolls over a hole the hole surface gets extended and the fillet gets trimmed just like the Cliff Rollover.
  • Fillet/Fillet Intersection: two fillets applied during the same operation intersect each other – intersection computed and trimming applied to produce a valid solid.


Topology-Based Filleting Figures

Constant Radius

Constant Distance

Variable Radius

Linear Cross section

Self Intersecting Rail Curves

Cliff Rollover

Tangent Surface Rollover

Negative Fillet/Negative Feature

Negative Fillet/Positive Feature

Positive Fillet/Negative Feature

Positive Fillet/Positive Feature

Fillet/Fillet Intersections

Filleting used in Offsetting: Original Solid

Offset Solid/Positive Offset

Offset Solid/Negative Offset

Shelled Solid


More Filleting Figures

NURB_BOX_3.jpg (79043 bytes)

box_linear_different_radii.jpg (87984 bytes)

2x1 Corner_2.jpg (39113 bytes)

l_box_4.jpg (106078 bytes)

box_on_box_4.jpg (83187 bytes)

six_sided_blend_2.jpg (45415 bytes)

ext_w_hole_2.jpg (52809 bytes)

shell_fillet_all_3.jpg (60973 bytes)


Submitting a Filleting Bug

This could be a difficult task if you have added substantial functionality using the customization features.  In that case you may have to ship us some software to test along with model geometry.

For the current time and utilization of trimmed surface filleting the best thing to do is to dump out the two original Breps and send us the information used to generate the surface fillet (radius, surface orientations, tolerances, guess points, etc.).   Optionally if you have created a high level function like the example given above, you should also send us that to utilize with the corresponding arguments.  If the arguments are complex, it might be easier to write them to a Fillet Definition File as specified in the following section.

Fillet Definition File

The Fillet Definition File contains an implicit definition of a set of filleting operations.  It is used primarily for testing and can be used to send a filleting bugs to us.  The following is the definition for the file:
Line 1: // Comment 
Line 2: <unsigned long> - Number of filleting operations.
For each filleting operation section of the file:
Line 1: // Comment
Line 2: // Comment
Line 3: // Comment
Line 4: <string> - File name containing the brep(s) to be 
filleted (*.igs, *.iwb, *.iwp)
Line 5: <ULONG> <ULONG> <double> <double> <double>
       - Fillet operation  (1 - Surface Filleting, 2 - Topology Filleting)
       - Total number of edges expected in result - for validation
       - X, Y, Z of a translation vector to move the results for display purposes
 For Surface Filleting there should be two Breps in the file:

Line 6: <double> <double> <double> <ULONG> <ULONG>
      - Offset Distance Face 1 (signed),
        - Offset Distance Face 2 (signed),
      - Fillet Tolerance - distance between rail curve and original base surfaces, 
      - Boundary Trimming Type (0 - None,
      - Maximal, 2 - Minimal, 3 - Bevel, 4 - Blend)
     - Reverse Trim - flip what gets trimmed away
Line 7:  <ULONG> <double>   <ULONG> <ULONG>
      - Cross Section Type - 1 - Linear, 2 - Circular, 
            3 - Approximate Circular
      - Accuracy specifies relative accuracy of approximation. 
            For example 0.10 means approximation is within 10%
            of the fillet radius.
      - Mirror - 0 - no mirror, 1 - the cross section 
            curve is mirrored
      - Complement - 0 - no complement, 1 - the complement of
            the circle is created. It is possible to both 
            mirror and complement a circle cross section.

For Topology Filleting there should be one Brep in the file:
Line 6: <ULONG>  Number of Topology Fillet Definitions
For Each Topology Fillet Definition:
Line 1: // Comment
Line 2: <ULONG> - Topology Type - 0 - Vertex, 1 - Edge,
         2 - All Edges of Face, 3 - All Edge of Brep,
         4 - Blend Edge and Face, 5 - Blend Vertex and Face
         6 - Blend Vertex and Edge, 7 - Blend 2 Edges, 
         8 - Blend 2 Faces, 9 - Do Regression Test
If Vertex Fillet Definition:
Line 3: <ULONG> <ULONG> <data> - Vertex Index, Vertex Fillet
         Type - 0 - Bevel, 1 - Blend, 2 - Spherical, 3 - Chamfer
If Edge Fillet Definition:
Line 3: <ULONG> <double> <ULONG> <data1> - 
        - Edge Index, 
       -  Fillet tolerance - distance between rail curve of fillet and original base surface
        - Fillet Solver Type
            1 - Constant distance - <data1> contains the distance
            2 - Constant radius - <data1> contains the radius
            3 - Variable radius - <data1> contains the 
                 orientation (1-Same as Edge, 2-Opposite) 
                law type (1 - linear, 2 - B-Spline)
                Linear - Start and end radius <double> <double>
              B-Spline - <data> - defines Cubic B-Spline control polygon
                   Line 1 - <ULONG> - Number of control points
                   Line 2 - <double> <double> - Control point 1
                   Line 3 - <double> <double> - Control point 2
                   ...    additonal control points
Line 4:  <ULONG> <double>   <ULONG> <ULONG>
      - Cross Section Type - 1 - Linear, 2 - Circular, 
            3 - Approximate Circular
      - Accuracy specifies relative accuracy of approximation. 
            For example 0.10 means approximation is within 10%
            of the fillet radius.
      - Mirror - 0 - no mirror, 1 - the cross section 
            curve is mirrored
      - Complement - 0 - no complement, 1 - the complement of
            the circle is created. It is possible to both 
            mirror and complement a circle cross section.

 If All Edges of a Face are Filleted: 

          Line 3: <ULONG> <double> <ULONG> <data1> 
               - Face Index
               - Fillet Tolerance - same as above in Edge Fillet Definition
               - Fillet Solver Type - same as above in Edge Fillet Definition
         Line 4:  Same as above in Edge Fillet Definition

If All Edges of the Brep are Filleted:

         Line 3: <double> <ULONG> <data1> 
               - Fillet Tolerance - same as above in Edge Fillet Definition
               - Fillet Solver Type - same as above in Edge Fillet Definition
         Line 4:  Same as above in Edge Filllet Definition

If Regression Test - does each edge, each face, then all edges and lays them out into a grid for viewing.:

         Line 3: <double> <ULONG> <data1> 
               - Fillet Tolerance - same as above in Edge Fillet Definition
               - Fillet Solver Type - same as above in Edge Fillet Definition
         Line 4:  Same as above in Edge Filllet Definition

Legal Stuff

All of the software and documentation received with this release is copyrighted by Solid Modeling Solutions, Inc. You may not distribute source code or documentation for this software outside of the company and the site which owns the license. The standard license agreement allows you to freely distribute object code in any application which does not contain a programmatic interface. All software and documentation is considered proprietary information and the intellectual property of Solid Modeling Solutions, Inc. This document contains trade secret information which is deemed proprietary.

Copyright © 1998-2010 Solid Modeling Solutions All rights reserved.
Information in this document is subject to change without notice.