Skip to content

Commit

Permalink
add support of Hermite curves
Browse files Browse the repository at this point in the history
  • Loading branch information
wwmayer committed Oct 26, 2016
1 parent 761d684 commit 18a5ff8
Show file tree
Hide file tree
Showing 6 changed files with 392 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/Mod/Part/App/AppPart.cpp
Expand Up @@ -75,6 +75,7 @@
#include "ArcOfHyperbolaPy.h"
#include "BezierCurvePy.h"
#include "BSplineCurvePy.h"
#include "HermiteCurvePy.h"
#include "HyperbolaPy.h"
#include "OffsetCurvePy.h"
#include "ParabolaPy.h"
Expand Down Expand Up @@ -200,6 +201,7 @@ PyMODINIT_FUNC initPart()
Base::Interpreter().addType(&Part::ArcOfHyperbolaPy ::Type,partModule,"ArcOfHyperbola");
Base::Interpreter().addType(&Part::BezierCurvePy ::Type,partModule,"BezierCurve");
Base::Interpreter().addType(&Part::BSplineCurvePy ::Type,partModule,"BSplineCurve");
Base::Interpreter().addType(&Part::HermiteCurvePy ::Type,partModule,"HermiteCurve");
Base::Interpreter().addType(&Part::OffsetCurvePy ::Type,partModule,"OffsetCurve");

Base::Interpreter().addType(&Part::PlanePy ::Type,partModule,"Plane");
Expand Down Expand Up @@ -320,6 +322,7 @@ PyMODINIT_FUNC initPart()
Part::GeomCurve ::init();
Part::GeomBezierCurve ::init();
Part::GeomBSplineCurve ::init();
Part::GeomHermiteCurve ::init();
Part::GeomCircle ::init();
Part::GeomArcOfCircle ::init();
Part::GeomArcOfEllipse ::init();
Expand Down
3 changes: 3 additions & 0 deletions src/Mod/Part/App/CMakeLists.txt
Expand Up @@ -56,6 +56,7 @@ generate_from_xml(LinePy)
generate_from_xml(PointPy)
generate_from_xml(BezierCurvePy)
generate_from_xml(BSplineCurvePy)
generate_from_xml(HermiteCurvePy)
generate_from_xml(PlanePy)
generate_from_xml(ConePy)
generate_from_xml(CylinderPy)
Expand Down Expand Up @@ -194,6 +195,8 @@ SET(Python_SRCS
BezierCurvePyImp.cpp
BSplineCurvePy.xml
BSplineCurvePyImp.cpp
HermiteCurvePy.xml
HermiteCurvePyImp.cpp
PlanePy.xml
PlanePyImp.cpp
ConePy.xml
Expand Down
147 changes: 147 additions & 0 deletions src/Mod/Part/App/Geometry.cpp
Expand Up @@ -50,6 +50,7 @@
# include <Geom_RectangularTrimmedSurface.hxx>
# include <Geom_SurfaceOfRevolution.hxx>
# include <Geom_SurfaceOfLinearExtrusion.hxx>
# include <GeomAPI_Interpolate.hxx>
# include <GeomConvert.hxx>
# include <GeomConvert_CompCurveToBSplineCurve.hxx>
# include <GeomLProp_CLProps.hxx>
Expand All @@ -70,8 +71,11 @@
# include <gp_Torus.hxx>
# include <Standard_Real.hxx>
# include <Standard_Version.hxx>
# include <Standard_ConstructionError.hxx>
# include <TColgp_Array1OfPnt.hxx>
# include <TColgp_Array2OfPnt.hxx>
# include <TColgp_HArray1OfPnt.hxx>
# include <TColStd_HArray1OfBoolean.hxx>
# include <TColStd_Array1OfReal.hxx>
# include <TColStd_Array1OfInteger.hxx>
# include <gp.hxx>
Expand Down Expand Up @@ -103,6 +107,7 @@
#include "ArcOfParabolaPy.h"
#include "BezierCurvePy.h"
#include "BSplineCurvePy.h"
#include "HermiteCurvePy.h"
#include "HyperbolaPy.h"
#include "ArcOfHyperbolaPy.h"
#include "OffsetCurvePy.h"
Expand Down Expand Up @@ -467,6 +472,148 @@ PyObject *GeomBezierCurve::getPyObject(void)

// -------------------------------------------------

TYPESYSTEM_SOURCE(Part::GeomHermiteCurve,Part::GeomCurve);

GeomHermiteCurve::GeomHermiteCurve()
{
std::vector<gp_Pnt> p;
p.push_back(gp_Pnt(0.0,0.0,0.0));
p.push_back(gp_Pnt(1.0,0.0,0.0));

std::vector<gp_Vec> t;
t.push_back(gp_Vec(1,0,0));
t.push_back(gp_Vec(1,0,0));

compute(p, t);
}

GeomHermiteCurve::GeomHermiteCurve(const std::vector<gp_Pnt>& p,
const std::vector<gp_Vec>& t)
{
compute(p, t);
}

GeomHermiteCurve::~GeomHermiteCurve()
{
}

void GeomHermiteCurve::interpolate(const std::vector<gp_Pnt>& p,
const std::vector<gp_Vec>& t)
{
if (p.size() < 2)
Standard_ConstructionError::Raise();
if (p.size() != t.size())
Standard_ConstructionError::Raise();

compute(p, t);
}

void GeomHermiteCurve::getCardinalSplineTangents(const std::vector<gp_Pnt>& p,
const std::vector<double>& c,
std::vector<gp_Vec>& t) const
{
// https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline#Cardinal_Spline
if (p.size() < 2)
Standard_ConstructionError::Raise();
if (p.size() != c.size())
Standard_ConstructionError::Raise();

t.resize(p.size());
if (p.size() == 2) {
t[0] = gp_Vec(p[0], p[1]);
t[1] = gp_Vec(p[0], p[1]);
}
else {
std::size_t e = p.size() - 1;

for (std::size_t i = 1; i < e; i++) {
gp_Vec v = gp_Vec(p[i-1], p[i+1]);
double f = 0.5 * (1-c[i]);
v.Scale(f);
t[i] = v;
}

t[0] = t[1];
t[t.size()-1] = t[t.size()-2];
}
}

void GeomHermiteCurve::getCardinalSplineTangents(const std::vector<gp_Pnt>& p, double c,
std::vector<gp_Vec>& t) const
{
// https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline#Cardinal_Spline
if (p.size() < 2)
Standard_ConstructionError::Raise();

t.resize(p.size());
if (p.size() == 2) {
t[0] = gp_Vec(p[0], p[1]);
t[1] = gp_Vec(p[0], p[1]);
}
else {
std::size_t e = p.size() - 1;
double f = 0.5 * (1-c);

for (std::size_t i = 1; i < e; i++) {
gp_Vec v = gp_Vec(p[i-1], p[i+1]);
v.Scale(f);
t[i] = v;
}

t[0] = t[1];
t[t.size()-1] = t[t.size()-2];
}
}

const Handle_Geom_Geometry& GeomHermiteCurve::handle() const
{
return myCurve;
}

void GeomHermiteCurve::compute(const std::vector<gp_Pnt>& p,
const std::vector<gp_Vec>& t)
{
double tol3d = Precision::Approximation();
Handle_TColgp_HArray1OfPnt pts = new TColgp_HArray1OfPnt(1, p.size());
for (std::size_t i=0; i<p.size(); i++) {
pts->SetValue(i+1, p[i]);
}

TColgp_Array1OfVec tgs(1, t.size());
Handle_TColStd_HArray1OfBoolean fgs = new TColStd_HArray1OfBoolean(1, t.size());
for (std::size_t i=0; i<p.size(); i++) {
tgs.SetValue(i+1, t[i]);
fgs->SetValue(i+1, Standard_True);
}

GeomAPI_Interpolate interpolate(pts, Standard_False, tol3d);
interpolate.Load(tgs, fgs);
interpolate.Perform();
this->myCurve = interpolate.Curve();

this->poles = p;
this->tangents = t;
}

Geometry *GeomHermiteCurve::clone(void) const
{
GeomHermiteCurve *newCurve = new GeomHermiteCurve(poles, tangents);
newCurve->Construction = this->Construction;
return newCurve;
}

// Persistence implementer
unsigned int GeomHermiteCurve::getMemSize (void) const {assert(0); return 0;/* not implemented yet */}
void GeomHermiteCurve::Save (Base::Writer &/*writer*/) const {assert(0); /* not implemented yet */}
void GeomHermiteCurve::Restore (Base::XMLReader &/*reader*/) {assert(0); /* not implemented yet */}

PyObject *GeomHermiteCurve::getPyObject(void)
{
return new HermiteCurvePy(static_cast<GeomHermiteCurve*>(this->clone()));
}

// -------------------------------------------------

TYPESYSTEM_SOURCE(Part::GeomBSplineCurve,Part::GeomCurve);

GeomBSplineCurve::GeomBSplineCurve()
Expand Down
54 changes: 54 additions & 0 deletions src/Mod/Part/App/Geometry.h
Expand Up @@ -52,7 +52,10 @@
#include <TopoDS_Shape.hxx>
#include <gp_Ax1.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <list>
#include <vector>
#include <Base/Persistence.h>
#include <Base/Vector3D.h>

Expand Down Expand Up @@ -150,6 +153,57 @@ class PartExport GeomBezierCurve : public GeomCurve
Handle_Geom_BezierCurve myCurve;
};

/*!
* \brief The GeomHermiteCurve class
* The GeomHermiteCurve describes a cubic Hermite spline.
* @note Since OpenCascade doesn't directly support Hermite splines
* the returned curve will be a B-Spline curve.
*/
class PartExport GeomHermiteCurve : public GeomCurve
{
TYPESYSTEM_HEADER();
public:
GeomHermiteCurve();
GeomHermiteCurve(const std::vector<gp_Pnt>&, const std::vector<gp_Vec>&);
virtual ~GeomHermiteCurve();
virtual Geometry *clone(void) const;
/*!
* Set the poles and tangents for the cubic Hermite spline
*/
void interpolate(const std::vector<gp_Pnt>&, const std::vector<gp_Vec>&);
/*!
* Compute the tangents for a Cardinal spline using the
* the cubic Hermite spline. It uses the method for Cardinal splines.
*/
void getCardinalSplineTangents(const std::vector<gp_Pnt>&,
const std::vector<double>&,
std::vector<gp_Vec>&) const;
/*!
* Compute the tangents for a Cardinal spline using the
* the cubic Hermite spline. It uses the method for Cardinal splines.
* It uses the same parameter for each tangent.
*/
void getCardinalSplineTangents(const std::vector<gp_Pnt>&, double,
std::vector<gp_Vec>&) const;

// Persistence implementer ---------------------
virtual unsigned int getMemSize (void) const;
virtual void Save (Base::Writer &/*writer*/) const;
virtual void Restore(Base::XMLReader &/*reader*/);
// Base implementer ----------------------------
virtual PyObject *getPyObject(void);

const Handle_Geom_Geometry& handle() const;

private:
void compute(const std::vector<gp_Pnt>&, const std::vector<gp_Vec>&);

private:
Handle_Geom_BSplineCurve myCurve;
std::vector<gp_Pnt> poles;
std::vector<gp_Vec> tangents;
};

class PartExport GeomBSplineCurve : public GeomCurve
{
TYPESYSTEM_HEADER();
Expand Down
30 changes: 30 additions & 0 deletions src/Mod/Part/App/HermiteCurvePy.xml
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="GeometryCurvePy"
Name="HermiteCurvePy"
Twin="GeomHermiteCurve"
TwinPointer="GeomHermiteCurve"
Include="Mod/Part/App/Geometry.h"
Namespace="Part"
FatherInclude="Mod/Part/App/GeometryCurvePy.h"
FatherNamespace="Part"
Constructor="true">
<Documentation>
<Author Licence="LGPL" Name="Werner Mayer" EMail="wmayer@users.sourceforge.net" />
<UserDocu>
Describes a Hermite curve
</UserDocu>
</Documentation>
<Methode Name="interpolate" Keyword="true">
<Documentation>
<UserDocu>Set the poles and tangents to compute the Hermite curve.</UserDocu>
</Documentation>
</Methode>
<Methode Name="getCardinalSplineTangents" Keyword="true">
<Documentation>
<UserDocu>Compute the tangents for a Cardinal spline</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

0 comments on commit 18a5ff8

Please sign in to comment.