Discretize a curve

Hi all,

I want to discretize some curves (not surfaces). I tried to use class BRepMesh_Discret, but it seems to work only with surfaces(TopoDS_Face). My current input is an IGES file with four curves, that are translated into TopoDS_Edge instances.
The reading is ok, the four curves are put in a compound shape, using IGESControl_Reader::OneShape ().

Here is what I've done :

BRepMesh_Discret discretizer (0.1, 0.1);
discretizer.Add (compound_of_curves);
int points_count = discretizer.NbPoint3d ();
//points_count is always zero

What is wrong? Please can someone give here the OCC classes to discretize curves?

Thanks for your answers.

Hugues Delorme's picture

Hi,

It seems that nobody here knows already how to do this. I've managed to find some interesting classes and used them.
The key class I found is GCPnts_QuasiUniformDeflection or GCPnts_UniformDeflection (the doc says that the former is faster). From a TopoDS_Edge instance, you need some work to prepare the input to the algorithm :

# include
# include
# include
# include
# include

...

void discretization (const TopoDS_Edge& edge, Real deflection)
{
//prepare input
double first_p = 0;
double last_p = 0;
Handle_Geom_Curve curve = BRep_Tool::Curve (edge, first_p, last_p);
assert (!curve.IsNull ());
GeomAdaptor_Curve curve_adaptator (curve);

//perform discretization
GCPnts_UniformDeflection discretizer;
discretizer.Initialize (curve_adaptator, deflection);
assert (discretizer.IsDone ());
assert (discretizer.NbPoints () > 0);

...
}

The problem I have now is that this does not generate correct points for lines. The algorithm is ok with curves of other types(Bézier, BSpline, etc.) but with lines it just generate 2 points : (0, 0, 0) and (0, 0, 0) and that's all.

I've taken a look at the source code of the algorithm, apparently lines are handled differently(it generated only 2 points, and in most of cases it does not statisfies the deflection criteria). I was a bit disappointed by the poor design of the algorithm, there are switch statements a bit everywhere in order to determine the sub-type of Geom_Curve, OO polymorphism would be cleaner.

OK, from this can someone advise a class that really handles all type of curves correctly?

Hugues Delorme's picture

A little mistake : I do not have points (0, 0, 0) for lines but points with huge huge coordinates like :
-200, -1.9975e+100, 9.98752e+098

Francois Lauzon's picture

Hello Hugues,
in fact, the class you are using is doing just what it is supposed to do, it put points on curve based on the curvature deflection, and since line don't have any deflection, there is only 2 points. You should try one of the Abscissa class (GCPnts_UniformAbscissa for example). Those class puts point on curve at equals distance, which is what you seems to be looking for. You can choose a number of points or a distance.

Good Luck,
Francois.

Hugues Delorme's picture

I've tried this class too(GCPnts_UniformAbscissa) but it always fails (IsDone () returns false after Initalize (...)).

By now, i'm looking to handle by myself when curves are lines. From a Geom_Curve instance I can't find the real type(Line, Circular) there is no ShapeType functions alike. How to cast a Geom_Curve instance to Geom_Line instance?

Francois Lauzon's picture

I've been using this class a lot and it's working for us. Which parameter do you submit to the Initialize method?

To find the type of an Handle class, you should do:

if (anObject->IsKind(STANDARD_TYPE(Geom_Line))) {
// you have a line
Handle_Geom_Line aLine=Handle_Geom_Line::DownCast(anObject);
}

But don't forget you might also find a line in a trimmed curve (Geom_TrimmedCurve).

Good Luck,
Francois.

Hugues Delorme's picture

OK, I've found my big error :
I was initializing the discretizer without giving to him the first and last parameters of the curve to discretize.
For lines, it provokes erroneous results. Now it's ok. Really, thank you for your help.
Here is my code :

//! \brief Uniform distribution of points from \p edge with respect of
//! the \p abscissa criteria (curvilinear distance between two
//! consecutive points of the distribution).
ValueArray& discretization (const TopoDS_Edge& edge,
Real abscissa) const
{
Real first_p = 0;//first parameter of the curve to be initialized
Real last_p = 0;//last parameter of the curve to be initialized

Handle_Geom_Curve curve = BRep_Tool::Curve (edge, first_p, last_p);
check (not curve.IsNull ());

GeomAdaptor_Curve curve_adaptator (curve);
GCPnts_UniformAbscissa discretizer;
discretizer.Initialize (curve_adaptator, abscissa, first_p, last_p);//don't forget parameters!!!
check (discretizer.IsDone ());
check (discretizer.NbPoints () > 0);

ValueArray& result =
*new ValueArray (1, discretizer.NbPoints ());

for (Integer i = 1; i <= result.upper (); i++)
{
gp_Pnt p = curve->Value (discretizer.Parameter (i));
Point3D to_keep (p.X (), p.Y (), p.Z ());
result.enter (to_keep, i);
}

return result;
}

abscissa = 0.5 is a default value that works fine.

"check" is like assert ValueArray is a generic array that stores value objects(whose class defines an empty and copy constructor, and operator=).
Class Point3D is like gp_Pnt.

Francois Lauzon's picture

You could also directly use an adaptor on a TopoDS_Edge:

ValueArray& discretization (const TopoDS_Edge& edge,
Real abscissa) const
{
BRepAdaptor_Curve curve_adaptator (edge);
GCPnts_UniformAbscissa discretizer;
discretizer.Initialize (curve_adaptator, abscissa
check (discretizer.IsDone ());
check (discretizer.NbPoints () > 0);

ValueArray& result =
*new ValueArray (1, discretizer.NbPoints ());

for (Integer i = 1; i <= result.upper (); i++)
{
gp_Pnt p = curve_adaptator.Value (discretizer.Parameter (i));
Point3D to_keep (p.X (), p.Y (), p.Z ());
result.enter (to_keep, i);
}

return result;
}

Hugues Delorme's picture

Thanks, this code is shorter and prevents from mistakes about curves' first and last parameters.

ValueArray use is not correct in the code because this forum eats everything between "less than" and "greater than" characters.

The very final version of the code is :

ValueArray[Point3D]& discretization (const TopoDS_Edge& edge,
Real abscissa) const
{
BRepAdaptor_Curve curve_adaptator (edge);
GCPnts_UniformAbscissa discretizer;
discretizer.Initialize (curve_adaptator, abscissa);
check (discretizer.IsDone ());//computation_ok
check (discretizer.NbPoints () > 0);//positive_count_of_points

ValueArray[Point3D]& result =
*new ValueArray[Point3D] (1, discretizer.NbPoints ());

for (Integer i = 1; i <= result.upper (); i++)
{
gp_Pnt p = curve_adaptator.Value (discretizer.Parameter (i));
Point3D to_keep (p.X (), p.Y (), p.Z ());
result.enter (to_keep, i);
}

return result;
}

Marcel Keller's picture

Thanks for posting the code. It's very useful for me!

Marcel