Open CASCADE notes

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

How to import SOLIDWORKS (or Parasolid, JT, NX, Creo) files into Open CASCADE


Rotor Open CASCADE model


What is Open CASCADE

If you are reading this blog post, you most likely already use Open CASCADE in your app and are well familiar with it. For those who are not, Open CASCADE is an open-source modeling kernel which can be used as a foundation to build 3D apps. In that sense, OCC competes with commercial kernels such as Parasolid, ACIS, CGM, or C3D.

OCC has data structures to describe 3D models with precise B-Rep and various API to perform modeling operations (fillets and chamfers, Boolean operations, etc.). For the last 20+ years the OCC company has been focusing on rendering custom development services. So development of the kernel is mainly driven by those customer projects. Although some core modules are mainly in the maintenance mode, the kernel can still be a viable option for businesses evaluating the development platform for their apps.

CAD file formats supported by Open CASCADE

Out of the box, OCC supports a few neutral file formats, including IGES, STEP, STL, VRML. As paid add-ons, the OCC company offers interfaces with Parasolid, ACIS, DXF, JT. When I worked at the OCC company in the late 1990s and early 2000s, I led the engineering team which owned the development of many of those components, and I contributed lots of C++ code thereto myself. That’s when my passion for CAD data exchange started and over time drove me to start CAD Exchanger and founding the CADEX company in the early 2010s.

CAD Exchanger components vs Open CASCADE’s

In some sense, CAD Exchanger certainly overlaps with those ‘native’ offerings. However, our focus at CADEX is primarily CAD data conversion and doing it right and most efficiently, so we invested a lot into our own implementations. Whereas the OCC company switched to service-oriented business in the early 2000s and therefore has to be driven by on-demand customer projects, our primary focus is product development.

We have to have a long-term predictable R&D roadmap, invest a far greater amount of human talents into product development, and be more responsive to numerous corner cases reported by our customers. Those focused efforts result in a broader amount of formats (20+ at the time of this writing), a broader range of format versions, more efficient implementations (including two hold patents related to parallel computing), and eventually quality. With millions of users using CAD Exchanger-based applications, the stream of CAD files going through CAD Exchanger codes is in dozens of millions every year! That challenge does require us to provide world-class CAD data converters in order to be a successful sustainable business.

We have multiple clients who decided to base their apps on Open CASCADE and they use some of the techniques described below to take advantage of the two worlds – OCC and CAD Exchanger.

Integration of CAD Exchanger into an OpenCASCADE-based app

With CAD Exchanger SDK, every developer using OCC to develop his/her application has an option to support a broader range of 3D file formats and thus to make the application more appealing to the end-users. And this integration is truly seamless and only takes a few lines of codes, and minutes.

Let’s consider some technical details.

How to read SOLIDWORKS file into Open CASCADE
Let’s take an example of how you could import a SOLIDWORKS file into your Open CASCADE-based app. (Instead of Solidworks, you could read NX, Creo, JT, IFC, or any other supported file format). It only takes a single line of code to replace the respective reader class (with NX_Reader, Creo_Reader, JT_Reader, and so on).


Option 1. Topology and geometry only

If you work with OCC at the level of geometry and topology (feel free to check out my older blog posts series explaining this vital difference), then you must be using the TopoDS_Shape base class instance as a primary object holding your topological tree.

In this case, your simplest code might look as follows:

#include <cadex/SDL_Reader.hxx>

cadex::SLD_Reader aReader;
TopoDS_Shape aShape;
if (!aReader.ReadFile (“myfile.ldprt”s) || !aReader.Transfer (aShape)) 
{
    //some error happened
    return false;
}
//here aShape contains a full OCC shape
    


Option 2. Open CASCADE XDE

If your OCC-based application uses XDE (eXtended Data Exchange), an OCAF (Open CASCADE Application Framework) extension, then you can import a SOLIDWORKS file into your XDE document very much like with the previous approach. The only difference is to convert an instance of cadex::ModelData_Data into OCC’s TDocStd_Document instance.

In this case, the contents of the CAD Exchanger model will be appended to the contents of aDoc: the assembly structure, colors, names, layers.

//convert CAD Exchanger document to OCC XDE document
Handle(TDocStd_Document) aDoc = ...; //
cadex::ModelXDE_Converter::Convert (aModel, aDoc);
    


Option 3. Open CASCADE topology and your own meta-data

If your application works with meta-data (id’s, names, colors, materials, etc.) but you do not use XDE, then probably you have your own C++ classes that bind meta-data and OCC topology. In this case, you will just need to traverse the CAD Exchanger document and retrieve both the OCC topology and meta-data.

The following code snippet demonstrates how this could be done.

class SceneGraphVisitor : public ModelData_Model::VoidElementVisitor
{
...
    void operator() (const ModelData_Part& thePart) override
    {
        auto aBRep = thePart.BRepRepresentation();
        if (aBRep) {
            const auto& aRootList = aBRep.Get();
            const TopoDS_Shape& aShape = aBRep.ToOCC(); //convert to OCC shape
            Base_UTF16String aName = thePart.Name();
            //bind aShape and aName in your data structures...
        }
    }
...
}
    
...
SceneGraphVisitor aVisitor;
aModel.Accept (aVisitor); //traverse model and retrieve data
    


Exporting Open CASCADE data into CAD files

Writing Open CASCADE geometries into external CAD files (e.g., JT, or Parasolid, ACIS, etc.) is done very much like reading, considered above. Depending on your preferred usage of OCC API (TopoDS_Shape only, XDE or mix with your own API), you basically just need to perform the workflow opposite to reading – create and populate cadex::ModelData_Model object and feed it to the cadex::JT_Writer (or alike) instance:

TopoDS_Shape aShape = ...;
cadex::ModelData_Model aModel;
cadex::ModelData_ShapeConverter::Add (aShape, aModel);

cadex::JT_Writer aWriter;
if (!aWriter.Transfer (aModel) || !aReader.WriteFile (“myfile.jt”)) {
    //some error happened
    return false;
}
    


Benefits of CAD Exchanger

If you decide to consider using CAD Exchanger SDK with Open CASCADE then here are a few key benefits you might expect to get:

  • Truly seamless integration. It takes less than 5-10 lines of C++ code as explained above. Overall, perhaps sometimes it can be even more compact than using native OCC converters.
  • Single API. The conversion between CAD Exchanger SDK and OCC objects is totally format-agnostic. So if over time, you want to add new formats (e.g., NX after Solidworks) that will take a couple of extra lines (to add cadex::NX_Reader). We plan to achieve that extra amount to be zero (yes, zero!). In that case, even recompilation will not be required!
  • Single vendor. As I said, data conversion is our core business and our core architecture is shared across all formats. Although you can mix CAD Exchanger-based components with native OCC, preferring the former gives you consistent behavior, user experience, and benefits (such as delayed loading, CPU multi-threading, etc.). Price-wise, this can be even zero extra cost – e.g., when using our bundles, you get access to all formats.
  • Support. Again, due to very different business models, it is in our best interests to keep the quality of the converters as high as possible. So whenever you might encounter a very specific corner case, that report immediately goes into our tracker and will be picked up during upcoming development sprints.
  • Performance and Quality. Multi-core parallelism was my second professional passion (developed during ten years work in Intel software group), and multi-threading and high performance were in the DNA of CAD Exchanger from day one. We received two patents related to parallel computing, and this parallelism is part of the core architecture. Therefore even those overlapping formats (e.g., STEP, IGES, etc.) are implemented in a much more scalable way than legacy OCC codes. However, I remain fully open to counter-examples: if you come across any file where CAD Exchanger will demonstrate weaker results, drop me a line and our team will gladly review.

Conclusion

As you have seen, integrating CAD Exchanger SDK with your Open CASCADE based app is really seamless and does not require any significant effort. The SDK comes with numerous examples demonstrating the above OCC-focused scenarios as well as many others dedicated to exploring the model (assembly structure, geometries, meta-data), working with PMI (Product and Manufacturing), generating meshes, visualizing 3D models and many more.

To evaluate CAD Exchanger SDK, please just fill out a brief evaluation form and you will receive further instructions to guide you step by step. Should you have any questions on this topic or any other, feel free to drop me an email at roman dot lygin at cadexchanger dot com. Either myself or my support team will be happy to help.

Thanks for reading!

Share
Tweet
Pin
Share
No comments
CAD Exchanger is now available in Google Play. Free, with in-app purchase (larger file size support, export to B-Rep formats, and more features in the future). OCC 6.9.0+ and Qt (QML) 5.5.0 based.

I would like to thank again the OCC development team (Andrey B, Kirill G, Sergey A, Ivan and others) and management (Alexander T and Michael K) for their support in porting the OCC platform as a prerequisite. See more details in the official press-release.

We met for the first time in August 2014 and the folks did their major part in a couple of months or so. Sometimes it was a bumpy road with some hot discussions but all is well that ends well. On our side we were doing a parallel port of a major version 3.0 to a totally new data model and UI, as a prerequisite to Android port. With parallel jumps between Windows, Linux and Android, with their different IDE's and toolchains - all pleasures of cross-platform development. That took us way too much time and we missed the schedule a few times. I regret we did this 6+ months later than originally planned but still would like to thank my team - Sergey, Denis and others for their extra efforts. There were multiple fruitful forum topics, bug reports and fixes - some are here, here or in Mantis, so good working relationship between the teams has been strengthened.

Among technical highlights there are probably a few interesting items - for instance an asynchronous, non-blocking visualization workflow (see discussion preview here). When we have some free cycles, we will try to share more technical details.

Meanwhile, if you have some spare time, please give a try to a brand new CAD Exchanger version and share your thoughts via Google Play, here or just email us at info@cadexhanger.com. We'd *really* be happy to hear from the community. Constructive critic, recommendations or positive comments are all valuable.

And please do keep CAD Exchanger on your device, you now know some people behind it ;-).

Thanks for your time and take care,
Roman




Share
Tweet
Pin
Share
17 comments
(Continuation of part1)
 Same approach works for surfaces. In this case GeomConvert_ApproxSurface and Adaptor3d_Surface classes should be used in exact same manner.

Below are a few examples of creating law surfaces.

The first case is an example of creating a variable offset surface, where a surface is defined as follows:
S(u,v) = B(u,v) + Offset(u,v) * N (u,v), where
B(u,v) is a basis surface,
N (u,v) is a unit normal to the basis surface,
Offset (u,v) is a function C + u ^ 2 + v ^ 2, where C is constant.

The two below examples apply such offset laws to plane and sphere respectively. The basis surface B is in red, and the resulting surface S – in green.





The other example below demonstrates surface warping, where a planar face is twisted along one of its directions:



Enjoy! :-)
Roman
Share
Tweet
Pin
Share
No comments
A recent case with enhancing CAD Exchanger ACIS importer to broaden support of ACIS primitives inspired me to write this post.

Like other modeling kernels, Open CASCADE comes with a finite set of supported types of curves and surfaces. For instance, for curves this includes lines and conic curves (circles, ellipses, parabolas and hyperbolas), B-Splines, Bezier curves, offset curves plus explicitly trimmed curves. OCC supports parametrics definition where 3D coordinate (x,y,z) is evaluated via parameter t, for surface it is calculated from a pair (u,v).

For instance, for line it is:
C(t) = O + Dt, where O is an origin and D is a unit vector.

Thus, a line in OCC is parametrized by its length.

ACIS and Parasolid additionally support so called procedural geometries (e.g. intersection curve or rolling ball surface) when there is no explicit formula but each point is still unambiguously calculated from parameters t or (u,v).

However, a limited set of explicitly supported types does not allow to express other possible types of curves and surfaces which could be easily represented in parametric definition. For instance, there were a few questions on the OCC forum how to model a helix curve with the help of OCC.

Let us consider how you could that indeed.

Say, a helix is parametrized as follows:

X(t) = O + Rcos(u) X
Y(t) = O + Rsin(u) Y
Z(t) = O + (pitch/(2*PI) * v Z

Where {O ,X, Y, Z} is a local axis system (origin and 3 unit vectors). Pitch – is a helix step along the Z axis. See the below screenshot (taken from ACIS documentation):


Now given this explicit definition (or law) how could you map this to Open CASCADE ?

One option would be to subclass Geom_Curve and implement respective methods (D0(), D1(), ..., Continuity(), etc). That would be fine if you only need a limited time span of such an object and won’t feed it into various OCC modeling algorithms. The OCC classes ShapeExtend_ComplexCurve and _CompositeSurface follow this approach.

However, although you could create an edge on such a curve, you would not be able to save it in a .brep file right away (you would need to enable a vehicle for saving/retrieving user-defined types). Some algorithms may throw an exception on an unrecognized type and so on.

Another option is to do one time approximation with B-Spline and keep the B-Spline representation after that. You would certainly lose original definition and evaluation of a point and derivative would be times more expensive. However you could keep this representation in persistent representation and confidently use it anywhere. By the way ACIS does support helix type and combines both the original definition and its B-Spline approximation.

To approximate with B-Spline, the GeomConvert_ApproxCurve class will do the job.

GeomConvert_ApproxCurve accepts a curve adaptor which essentially implements an Adaptor design pattern and produces a B-Spline curve. You would essentially need to create a subclass of Adaptor3d_Curve and implement respective methods (D0(), D1(), Intervals(), etc). You could possibly mix this approach with the former and create GeomAdaptor_Curve which would accept your Geom_Curve subclass.

Below is an excerpt from CAD Exchanger that approximates a helix with OCC B-Spline:
/*! Uses adaptor classes and invokes GeomConvert_ApproxCurve to approximate with a B-Spline.
    Created B-Spline is polynomial and is of C2-continuity.
    Returns true if the B-Spline has been successfully created and false otherwise.
*/
bool ACISAlgo_Helix::MakeHelix (const ACISGeom_HelixData& theSource,
    Handle_Geom_BSplineCurve& theTarget)
{
    Handle_ACISAlgo_HHelixCurveAdaptor anAdaptor = new ACISAlgo_HHelixCurveAdaptor (theSource);
    Standard_Real aTol = Precision::Confusion();
    GeomAbs_Shape aContinuity = GeomAbs_C2 /*highest supported continuity*/;
    Standard_Integer aMaxSeg = 10000, /*max number of spans*/
                     aMaxDeg = 9; /*max degree, consistent with settings in Algo*/
    GeomConvert_ApproxCurve anApprox (anAdaptor, aTol,
        aContinuity,
        aMaxSeg,
        aMaxDeg);
    if (anApprox.HasResult()) {
        theTarget = anApprox.Curve();
        Base_Debugger& aDebugger = Base_Debugger::GlobalInstance();
        aDebugger.Save (theTarget, "curve");
    }
    return !theTarget.IsNull();
 }
//! Defines data elements that can be reused for both common ACIS 'helix' and ASM 'helix_int_cur'.
struct ACISGeom_HelixData
{
    ACISGeom_HelixData() :
        myXRadius(0.),
        myYRadius(0.),
        myPitch(0.),
        myTaper(0.),
        myRangeMin (0.),
        myRangeMax (2 * M_PI),
        myScaleFactor (1.)
    {}

    __CADEX_DEFINE_PROPERTY(gp_Ax3,Position) //can be right- or left-handed
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,XRadius)
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,YRadius)
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,Pitch)  //must be >= 0, if = 0 then is planar
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,Taper) //if > 0, helix widens along the Z-axis, if 0 - then lies on a cylinder
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,RangeMin)
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,RangeMax)
    __CADEX_DEFINE_PRIMITIVE_PROPERTY(double,ScaleFactor)
};

/*! A few methods in OCC 6.9.0 have been made const.*/
#if OCC_VERSION_HEX < 0x060900
#define __CADEX_ADAPTOR3D_CURVE_CONST
#else
#define __CADEX_ADAPTOR3D_CURVE_CONST const
#endif

/* \class ACISAlgo_HelixCurveAdaptor
   \brief Defines an adaptor to represent a helix curve.

   Helix data is defined by ACISGeom_HelixData.
   Evaluation is performed in the Evaluator subclass which can either represent a helix lying on a
   cylinder (if taper is 0) or on a cone (if taper is not 0).

   Helix can have distinct radii along X and Y axes, i.e. to have an elliptical section.
*/
class ACISAlgo_HelixCurveAdaptor : public Adaptor3d_Curve
{
public:

    class Evaluator;

    //! Constructor.
    ACISAlgo_HelixCurveAdaptor (const ACISGeom_HelixData& theData);

    //! Constructor
    ACISAlgo_HelixCurveAdaptor (const std::shared_ptr& theEvaluator,
        Standard_Real theMin,
        Standard_Real theMax);

    virtual Standard_Real FirstParameter()const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual Standard_Real LastParameter() const __CADEX_OVERRIDE_ATTRIBUTE;

    virtual GeomAbs_Shape Continuity() const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual Standard_Integer NbIntervals (const GeomAbs_Shape S) __CADEX_ADAPTOR3D_CURVE_CONST
        __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void Intervals (TColStd_Array1OfReal& T, const GeomAbs_Shape S) __CADEX_ADAPTOR3D_CURVE_CONST
        __CADEX_OVERRIDE_ATTRIBUTE;
    virtual Handle(Adaptor3d_HCurve) Trim (const Standard_Real First,
        const Standard_Real Last,
        const Standard_Real Tol) const __CADEX_OVERRIDE_ATTRIBUTE;
  
    virtual Standard_Boolean IsClosed() const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual Standard_Boolean IsPeriodic() const __CADEX_OVERRIDE_ATTRIBUTE;

    virtual gp_Pnt Value (const Standard_Real U) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D0 (const Standard_Real U, gp_Pnt& P) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D1 (const Standard_Real U, gp_Pnt& P, gp_Vec& V) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D2 (const Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D3 (const Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2, gp_Vec& V3) const
        __CADEX_OVERRIDE_ATTRIBUTE;
    virtual gp_Vec DN (const Standard_Real U, const Standard_Integer N) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual Standard_Real Resolution (const Standard_Real R3d) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual GeomAbs_CurveType GetType() const __CADEX_OVERRIDE_ATTRIBUTE;

protected:
    std::shared_ptr  myEvaluator;
    Standard_Real               myMin;
    Standard_Real               myMax;
};
DEFINE_STANDARD_HANDLE(ACISAlgo_HHelixCurveAdaptor,Adaptor3d_HCurve)
class ACISAlgo_HHelixCurveAdaptor : public Adaptor3d_HCurve
{
public:

    //! Constructor.
    ACISAlgo_HHelixCurveAdaptor (const ACISGeom_HelixData& theData) : myAdaptor (theData) {}

    //! Constructor.
    ACISAlgo_HHelixCurveAdaptor (const std::shared_ptr& theEvaluator,
        Standard_Real theMin,
        Standard_Real theMax) : myAdaptor (theEvaluator, theMin, theMax) {}

    //! Returns the adaptor as Adaptor3d_Curve.
    /*! Return the internal ACISAlgo_HelixCurveAdaptor object.*/
    virtual const Adaptor3d_Curve& Curve() const __CADEX_OVERRIDE_ATTRIBUTE { return myAdaptor; }

    //! Returns the adaptor as Adaptor3d_Curve.
    /*! Return the internal ACISAlgo_HelixCurveAdaptor object.*/
    virtual Adaptor3d_Curve& GetCurve() __CADEX_OVERRIDE_ATTRIBUTE  { return myAdaptor; }
  
public:
    DEFINE_STANDARD_RTTI(ACISAlgo_HelixCurveAdaptor)

protected:
    ACISAlgo_HelixCurveAdaptor  myAdaptor;
};

__CADEX_IMPLEMENT_HANDLE(ACISAlgo_HHelixCurveAdaptor,Adaptor3d_HCurve)
/*********************************************************************************************/


/*! \class ACISAlgo_HelixCurveAdaptor::Evaluator
    \brief Base abstract class to evaluate helix.
*/
class ACISAlgo_HelixCurveAdaptor::Evaluator
{
public:
    __CADEX_DEFINE_MEMORY_MANAGEMENT

    Evaluator (const ACISGeom_HelixData& theData) : myData (theData), myVCoef (1.) {}
    virtual ~Evaluator() {}

    const ACISGeom_HelixData& Data() const { return myData; }

    double VParameter (Standard_Real U) const { return U * myVCoef; }
    virtual void D0 (Standard_Real U, gp_Pnt& P) const = 0;
    virtual void D1 (Standard_Real U, gp_Pnt& P, gp_Vec& V) const = 0;
    virtual void D2 (Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const = 0;
    virtual void D3 (Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2, gp_Vec& V3) const = 0;
    virtual gp_Vec DN (Standard_Real U, Standard_Integer N) const = 0;

protected:
    const gp_XYZ& Loc()  const { return myData.Position().Location().XYZ(); }
    const gp_XYZ& XDir() const { return myData.Position().XDirection().XYZ(); }
    const gp_XYZ& YDir() const { return myData.Position().YDirection().XYZ(); }
    const gp_XYZ& ZDir() const { return myData.Position().Direction().XYZ(); }

    ACISGeom_HelixData  myData;
    double              myVCoef; //coefficient to multiply U to get a V parameter on a respective surface
};
/*! \class ACISAlgo_HelixCurveAdaptor_CylinderEvaluator
    \brief Evaluates a helix lying on a cylinder.
*/
class ACISAlgo_HelixCurveAdaptor_CylinderEvaluator : public ACISAlgo_HelixCurveAdaptor::Evaluator
{
public:
    ACISAlgo_HelixCurveAdaptor_CylinderEvaluator (const ACISGeom_HelixData& theData);
    virtual void D0 (Standard_Real U, gp_Pnt& P) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D1 (Standard_Real U, gp_Pnt& P, gp_Vec& V) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D2 (Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual void D3 (Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2, gp_Vec& V3) const __CADEX_OVERRIDE_ATTRIBUTE;
    virtual gp_Vec DN (Standard_Real U, Standard_Integer N) const __CADEX_OVERRIDE_ATTRIBUTE;
};

ACISAlgo_HelixCurveAdaptor_CylinderEvaluator::ACISAlgo_HelixCurveAdaptor_CylinderEvaluator (
    const ACISGeom_HelixData& theData) :
    ACISAlgo_HelixCurveAdaptor::Evaluator (theData)
{
    myVCoef = theData.Pitch() * theData.ScaleFactor() / (2 * M_PI);
}


void ACISAlgo_HelixCurveAdaptor_CylinderEvaluator::D0 (Standard_Real U,
    gp_Pnt& P) const
{
    Standard_Real v    = VParameter (U);
    Standard_Real Rx   = myData.XRadius();
    Standard_Real Ry   = myData.YRadius();
    Standard_Real sinU = sin (U);
    Standard_Real cosU = cos (U);
    P = Rx * cosU * XDir() + Ry * sinU * YDir() + v * ZDir() + Loc();
}

void ACISAlgo_HelixCurveAdaptor_CylinderEvaluator::D1 (
    Standard_Real U,
    gp_Pnt& P,
    gp_Vec& V) const
{
    Standard_Real v    = VParameter (U);
    Standard_Real Rx   = myData.XRadius();
    Standard_Real Ry   = myData.YRadius();
    Standard_Real sinU = sin (U);
    Standard_Real cosU = cos (U);
    P = Rx * cosU * XDir() + Ry * sinU * YDir() + v * ZDir() + Loc();

    Standard_Real k    = myVCoef;
    V = -Rx * sinU * XDir() + Ry * cosU * YDir() + k * ZDir();
}

void ACISAlgo_HelixCurveAdaptor_CylinderEvaluator::D2 (
    Standard_Real U,
    gp_Pnt& P,
    gp_Vec& V1,
    gp_Vec& V2) const
{
    Standard_Real v    = VParameter (U);
    Standard_Real Rx   = myData.XRadius();
    Standard_Real Ry   = myData.YRadius();
    Standard_Real sinU = sin (U);
    Standard_Real cosU = cos (U);
    P = Rx * cosU * XDir() + Ry * sinU * YDir() + v * ZDir() + Loc();

    Standard_Real k    = myVCoef;
    V1 = -Rx * sinU * XDir() + Ry * cosU * YDir() + k * ZDir();
    V2 = -Rx * cosU * XDir() - Ry * sinU * YDir();
}
/*********************************************************************************************/

ACISAlgo_HelixCurveAdaptor::ACISAlgo_HelixCurveAdaptor (const ACISGeom_HelixData& theData) :
    myMin (theData.RangeMin()),
    myMax (theData.RangeMax())
{
    if (std::fabs (theData.Taper()) < Precision::Confusion()) { //cylinder
        myEvaluator.reset (new ACISAlgo_HelixCurveAdaptor_CylinderEvaluator (theData));

    } else { //cone
        myEvaluator.reset (new ACISAlgo_HelixCurveAdaptor_ConeEvaluator (theData));
    }
}

/*! Used when trimming*/
ACISAlgo_HelixCurveAdaptor::ACISAlgo_HelixCurveAdaptor (const std::shared_ptr& theEvaluator,
    Standard_Real theMin,
    Standard_Real theMax) :
    myEvaluator (theEvaluator),
    myMin (theMin),
    myMax (theMax)
{
    __CADEX_ASSERT_INVALID_VALUE(myEvaluator->Data().RangeMin() <= theMin);
    __CADEX_ASSERT_INVALID_VALUE(myEvaluator->Data().RangeMax() >= theMax);
}

Standard_Real ACISAlgo_HelixCurveAdaptor::FirstParameter() const
{
    return myMin;
}

Standard_Real ACISAlgo_HelixCurveAdaptor::LastParameter() const
{
    return myMax;
}

GeomAbs_Shape ACISAlgo_HelixCurveAdaptor::Continuity() const
{
    return GeomAbs_CN;
}

Standard_Integer ACISAlgo_HelixCurveAdaptor::NbIntervals (const GeomAbs_Shape /*S*/) __CADEX_ADAPTOR3D_CURVE_CONST
{
    return 1;
}

void ACISAlgo_HelixCurveAdaptor::Intervals (TColStd_Array1OfReal& T, const GeomAbs_Shape /*S*/) __CADEX_ADAPTOR3D_CURVE_CONST
{
    T (T.Lower()) = FirstParameter();
    T (T.Upper()) = LastParameter();
}

Handle(Adaptor3d_HCurve) ACISAlgo_HelixCurveAdaptor::Trim (const Standard_Real First,
    const Standard_Real Last,
    const Standard_Real /*Tol*/) const
{
    return new ACISAlgo_HHelixCurveAdaptor (myEvaluator, First, Last);
}

Standard_Boolean ACISAlgo_HelixCurveAdaptor::IsClosed() const
{
    return Standard_False;
}

Standard_Boolean ACISAlgo_HelixCurveAdaptor::IsPeriodic() const
{
    return Standard_False;
}

gp_Pnt ACISAlgo_HelixCurveAdaptor::Value (const Standard_Real U) const
{
    gp_Pnt aP;
    D0 (U, aP);
    return aP;
}

void ACISAlgo_HelixCurveAdaptor::D0 (const Standard_Real U, gp_Pnt& P) const
{
    myEvaluator->D0 (U, P);
}

void ACISAlgo_HelixCurveAdaptor::D1 (const Standard_Real U, gp_Pnt& P, gp_Vec& V) const
{
    myEvaluator->D1 (U, P, V);
}

void ACISAlgo_HelixCurveAdaptor::D2 (const Standard_Real U, gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const
{
    myEvaluator->D2 (U, P, V1, V2);
}


Standard_Real ACISAlgo_HelixCurveAdaptor::Resolution (const Standard_Real R3d) const
{
    //see GeomAdaptor_Curve::Resolution()
    const auto& aData = myEvaluator->Data();
    Standard_Real R = std::max (aData.XRadius(), aData.YRadius());
    if (R3d < 2 * R)
        return 2 * ASin (R3d / (2 * R));
    else
        return 2 * M_PI;
}

GeomAbs_CurveType ACISAlgo_HelixCurveAdaptor::GetType() const
{
    return GeomAbs_OtherCurve;
}


Below are two screenshot of approximated helices in DRAW – the first one has different Rx and Ry radii and is lying on a cylindrical surface, the second is of equal Rx and Ry radii lying on a conical surface.



Hope this post will give you some hints on how to approximate arbitrary curves and surfaces using B-Spline approximation techniques.

If you have any interesting examples to share that would certainly be good to know.

Thanks,
Roman

 
Share
Tweet
Pin
Share
No comments
Older Posts

Subscribe for the new posts

Blog Archive

  • October 2020 (1)
  • September 2015 (1)
  • 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