Open CASCADE notes

A blog about the Open Source 3D modeling kernel: notes from its former developer and project manager

Continued...

OK, let's continue to eat our elephant bit by bit. The next bit is edge. Hope you won't get difficulties with it.


Edge
Edge is a topological entity that corresponds to 1D object – a curve. It may designate a face boundary (e.g. one of the twelve edges of a box) or just a ‘floating' edge not belonging to a face (imagine an initial contour before constructing a prism or a sweep). Face edges can be shared by two (or more) faces (e.g. in a stamp model they represent connection lines between faces) or can only belong to one face (in a stamp model these are boundary edges). I'm sure you saw all of these types – in default viewer, in wireframe mode, they are displayed in red, yellow and green respectively.



Edge contains several geometric representations (refer to the diagram in Part1):
- Curve C(t) in 3D space, encoded as Geom_Curve. This is considered as a primary representation;
- Curve(s) P(t) in parametric 2D space of a surface underlying each face the edge belongs to. These are often called pcurves and are encoded as Geom2d_Curve;
- Polygonal representation as an array of points in 3D, encoded as Poly_Polygon3D;
- Polygonal representation as an array of indexes in array of points of face triangulation, encoded as Poly_PlygonOnTriangulation.

The latter two are tessellation analogues of exact representations with the help of former two.

These representations can be retrieved using already mentioned BRep_Tool, for instance:

Standard_Real aFirst, aLast, aPFirst, aPLast;
Handle(Geom_Curve) aCurve3d = BRep_Tool::Curve (anEdge, aFirst, aLast);
Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (anEdge, aFace, aPFirst, aPLast);

The edge must have pcurves on all surfaces, the only exception is planes where pcurves can be computed on the fly.

The edge curves must be coherent, i.e. go in one direction. Thus, a point on the edge can be computed using any representation - as C(t), t from [first, last]; S1 (P1x (u), P1y(u)), u from [first1, last1], where Pi – pcurve in parametric space of surface Si

Edge flags

Edge has two special flags:
- "same range" (BRep_Tool::SameRange()), which is true when first = first_i and last = last_i, i.e. all geometric representations are within the same range;
- "same parameter" (BRep_Tool::SameParameter()), which is true when C(t) = S1(P1x(t), P1y(t)), i.e. any point along the edge corresponds to the same parameter on any of its curves.

Many algorithms assume that they are both set, therefore it is recommended that you ensure that these conditions are respected and flags are set.

Tolerance
Edge's tolerance is a maximum deviation between its 3D curve and any other representation. Thus, its geometric meaning is a radius of a pipe that goes along its 3D curve and encompass curves restored from all representations.



Special edge types
There are two kinds of edges that are distinct from others. These are:
- seam edge – one which is shared by the same face twice (i.e. has 2 pcurves on the same surface)
- degenerated edge – one which lies on a surface singularity that corresponds to a single point in 3D space.
The sphere contains both of these types. Seam-edge lies on pcurves corresponding to surface U iso-lines with parameters 0 and 2*PI. Degenerated edges lies on North and South poles and correspond to V iso-lines with parameters –PI/2 and PI/2.



Other examples - torus, cylinder, and cone. Torus has two seam-edges – corresponding to its parametric space boundaries; cylinder has a seam-edge. Degenerated edge represents on a cone apex.

To check if the edge is either seam or degenerated, use BRep_Tool::IsClosed(), and BRep_Tool::Degenerated().


Edge orientation
Forward edge orientation means that its logical direction matches direction of its curve(s). Reversed orientation means that logical direction is opposite to curve's direction. Therefore, seam-edge always has 2 orientations within a face – one reversed and one forward.

To be continued...

P.S. As usual, many thanks to those who voted and sent comments. Is this series helpful ?
Share
Tweet
Pin
Share
16 comments
Continued...

Vertex
Vertex has a primary geometric representation which is a point in 3D space encoded as gp_Pnt. It may have other representations but they are virtually never used in practice.

Another important attribute of a vertex is its tolerance which indicates possible inaccuracy of its placement. Geometrical meaning of the vertex tolerance T is a sphere with a radius T centered in vertex’s point. This sphere must encompass curves ends of all edges connected at that point.



Tolerances
Let me elaborate a little bit on tolerances.

Unlike some other geometric libraries which have some global precision (e.g. as 1/1000th of the model bounding box dimension), Open CASCADE treats tolerances as local properties. As indicated in the diagram in Part1, tolerance is a field of any vertex, edge, or face instance. This approach helps to describe the model with higher accuracy in general. Look at the picture below:



Individual tolerances allow to specify local inaccuracies while leaving the rest of the model well defined. If you have to build your shape bottom up, the best approach is to specify the smallest valid tolerance. By default, it is Precision::Confusion() which is 1e-07.

In general some modeling algorithms are quite sensitive to tolerances, especially if they have to work with a single value to be specified by the user. For instance, importing a model from another 3D geometric kernel (via IGES or STEP formats, or directly from native format of other kernels or CAD systems), involves a global precision specified in a file header. The importer tries to be robust regardless of that value, no matter how coarse it is (e.g. it could that big so that some tiny faces are fully encompassed by its boundaries what would even violate the standard).

Another example is Sewing (stitching topologically disconnected faces into a shell). Gaps between faces can be quite different across the model. Specifying too small tolerance would leave too many disconnected faces, specifying too big upfront would connect too distant faces (maybe even implied too be disconnected by user intent, like tiny holes).

Coming back to vertices, let me mention about their orientation field. It does not have a direct geometric meaning, but by convention vertex with TopAbs_FORWARD orientation must match an edge’s end corresponding to the smaller parameter of its curve. Respectively a vertex with TopAbs_REVERSED – to the curve’s end with greater parameter. For instance, if you have an edge lying on a circular arc of radius 1 on plane Z=0 starting at point (1, 0, 0) and moving anti-clockwise (if to look in the direction opposite to Z axis) then its forward vertex will have a point (1, 0, 0) and reversed one – (0, 1, 0):



Building a vertex bottom-up
BRep_Builder is the tool that actually performs low-level operations.

gp_Pnt aPoint (100., 200., 300.);
BRep_Builder aBuilder;
TopoDS_Vertex aVertex;
aBuilder.MakeVertex (aVertex, aPoint, Precision::Confusion());
aVertex.Orientation (TopAbs_REVERSED);

There is a convenience class BRepBuilderAPI_MakeVertex which eventually uses BRep_Builder inside. So, if you have to construct topology bottom up make sure you are familiar with BRep_Builder.

Accessing vertex info
BRep_Tool is the tool that provides access to geometry of the topological entities. Most its methods are static.

Standard_Real aTolerance = BRep_Tool::Tolerance (aVertex);
gp_Pnt aPoint = BRep_Tool::Pnt (aVertex);

To be continued...
Share
Tweet
Pin
Share
11 comments
Let us consider these fundamental concepts of Open CASCADE. From time to time questions about them pop up on the forum, so I hope this post will be useful for many readers. Understanding these concepts is important if you have to work with most modeling algorithms and especially if you want to develop you own. You might also want to re-read various chapters from the Modeling Data User's Guide to refresh you memory.

Abstract topology
Open CASCADE topology is designed with reference to the STEP standard ISO-10303-42. Perhaps reading some its concepts would be helpful (I myself did this once in 1997).

The structure is an oriented one-way graph, where parents refer to their children, and there are no back references. Abstract structure is implemented as C++ classes from the TopoDS package. Here is an inheritance diagram taken from the Doxygen-generated documentation.



TopoDS_Shape is manipulated by value and contains 3 fields – location, orientation and a myTShape handle (of the TopoDS_TShape type) – see the diagram below (this and other contain only most important fields):



myTShape and Location are used to share data between various shapes and thus save huge amounts of memory. For example, an edge belonging to two faces has equal Locations and myTShape fields but different Orientations (Forward in context of one face and Reversed in one of the other).

Connection with Geometry
Now let's consider how this abstract topology structure is connected with geometry.

This is done by inheriting abstract topology classes from the TopoDS package by those implementing a boundary representation model (from the BRep package). Only 3 types of topological objects have geometric representations – vertex, edge, and face (see the diagram below).



Let's consider them more closely.

To be continued...
Share
Tweet
Pin
Share
5 comments
(continued)

Performance considerations
Using progress indicator obviously adds certain overhead as calculating current position and redrawing a widget eats some CPU time. So, be careful to not abuse an indicator by updating it after every tiny operation. Instead you might prefer to request its update after some chunks of operations (e.g. after every 10th).

int aNbOps = ...;
int aThreshold = 10;
int aNbChunks = aNbOps / aThreshold;

anIndicator->SetRange (0, aNbChunks);
for (i = 1; i <= aNbOps; i++) {
if (i % aThreshold)
anIndicator->Increment();
}

Inserting your indicator into Open CASCADE algorithms
Once you have implemented your subclass, you can pass it to OCC algorithms. As I said above, at the moment, Open CASCADE currently supports progress indicators in IGES, STEP and BRep readers and writers.
Here are examples of how you can provide your indicators into IGES and BRep readers.

IGESCAFControl_Reader aReader;
Handle(Message_ProgressIndicator) anIndicator = ...;

//to make progress indicator work more smoothly divide the transfer into
//two steps: loading (30%) and mapping (70%), including shape healing
anIndicator->NewScope (30, (Standard_CString)qApp->translate ("Exchanger", "Loading file").toAscii());
Standard_Boolean aRes = (aReader.ReadFile (theFileName.ToCString()) == IFSelect_RetDone);
anIndicator->EndScope ();
if (aRes) {
//setting progress into the reader object to track every entity
//(using TransientProcess() is possible only after ReadFile())
aReader.WS()->MapReader()->SetProgress (anIndicator);
anIndicator->NewScope (70, (Standard_CString)qApp->translate ("Exchanger", "Translating file").toAscii());
aRes = aReader.Transfer (theDoc);
anIndicator->EndScope ();
//work-around to decremenet reference counter inside TransientProcess
aReader.WS()->MapReader()->SetProgress (NULL);
}

Importing native BRep file is more straightforward:
Standard_Boolean aResult = BRepTools::Read (aShape, theFileName.ToCString(), aBuilder, anIndicator);


Multi-threading issues
In its current implementation Message_ProgressIndicator is exclusively tailored for use within a single thread. This stems from its implementation concept based on a stack of nested sub-ranges – every time you signal a progress (e.g. with Increment() or EndScope()) it applies to the current open sub-range. This makes it unusable for multi-threaded environment where concurrent threads can perform their own chunks of tasks and report progress. I first encountered this working on parallelizing IGES import.

Upon part 1 publication, Andrey from OCC was very kind to let me know that they are prototyping multi-threaded version of the progress indicator. So chances are it can appear in near releases. Anyway, as long as you use the indicator in a single thread even within a multi-threaded environment (e.g. if your OCC-based algorithms run in a separate worker thread) you are safe to go.

So, go and plan your goal, set your range, make your next step and report how closer you are now ;-).
Share
Tweet
Pin
Share
8 comments
Newer Posts
Older Posts

Subscribe for the new posts

Blog Archive

  • August 2015 (2)
  • May 2014 (1)
  • November 2013 (1)
  • June 2013 (1)
  • May 2013 (1)
  • November 2012 (2)
  • November 2011 (1)
  • June 2011 (3)
  • May 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • November 2010 (2)
  • October 2010 (2)
  • September 2010 (1)
  • August 2010 (1)
  • July 2010 (1)
  • June 2010 (1)
  • May 2010 (1)
  • April 2010 (2)
  • March 2010 (2)
  • January 2010 (2)
  • December 2009 (1)
  • November 2009 (2)
  • October 2009 (3)
  • August 2009 (2)
  • July 2009 (3)
  • June 2009 (4)
  • May 2009 (3)
  • April 2009 (2)
  • March 2009 (5)
  • February 2009 (5)
  • January 2009 (5)
  • December 2008 (11)
  • November 2008 (8)

Loading...

Followers

Created by ThemeXpose