高级会员
注册日期: 06-11
帖子: 14579
精华: 1
现金: 224494 标准币
资产: 234494 标准币
|
【转帖】spline Approximation
spline approximation
spline approximation
i have to import in my system an oddbspline class and i'd like to approximate the spline with lines and/or arcs. is there any function in directdwg doing the job?
here is the arx code for doing this. once i have downloaded this from the arx knowledge support which now was thrown away by autodesk and you need to pay money to them to receive this (something typical to autodesk by the way!!!).
it works under autocad but you need to change it a little. also the number of approximation points depends on you.
i think i had made some changes on this code so feel free to ask anything on it.
header file:
[code]
//splineconv.h
#ifndef _splineconv_h
#define _splineconv_h
class cspannode {
//construction
public:
cspannode( const double dpar, acdbentity* pent );
// attributes
public:
double getpar() const { return m_dpar; }
acgevector3d gettan() const { return m_vectan; }
acgepoint3d getpt() const { return m_pt; }
cspannode* getprev() const { return m_pprev; }
cspannode* getnext() const { return m_pnext; }
void setprev(cspannode* pprev) { m_pprev = pprev; }
void setnext(cspannode* pnext ) {m_pnext = pnext; }
// implementation
public:
~cspannode() {;}
private:
double m_dpar;
acgevector3d m_vectan;
acgepoint3d m_pt;
cspannode* m_pprev;
cspannode* m_pnext;
}; //class
class csplineconvertor {
// construction
public:
csplineconvertor();
//attributes
double gettolgoal(void) const { return m_dtolgoal; }
double gettolachieved(void) const { return m_dtolachieved; }
int getnumsteps(void) const { return m_nsteps; }
//operations
public:
bool selectspline( acdbentity* pent, const double dtolgoal=0.01, const int nmaxsteps=1000 );
bool getpoints( acgepoint3darray &pts );
//implementation
public:
~csplineconvertor();
private:
acdbspline* m_pspline; // spline to convert
cspannode* m_pfirstnode; // list of the nodes
bool m_bisrefined;
double m_dtolgoal;
double m_dtolachieved;
int m_nsteps; // number of the steps processed
int m_nmaxsteps; // maximal number of steps
bool refine();
bool getsplinenodes( acgedoublearray& arknots, double& dknottol );
bool spanwithintol( const cspannode* pstartnode, const cspannode* pendnode, double &dmidpar, double &dtolachieved );
}; //class
#endif _splineconv_h
</pre><hr></blockquote>
and the c++ file:
[code]
// splineconv.cpp
#include "stdafx.h"
#include "stdarx.h"
#include "icbacadinterface.h"
#include "splineconv.h"
#include "entitycheck.h"
// --------------------------- cspannode members ---------------------------
cspannode::cspannode( const double dpar, acdbentity* pent ) {
rxassert( isspline(pent) );
acdbspline* pspline = acdbspline::cast(pent);
m_dpar = dpar;
pspline->getpointatparam( dpar, m_pt );
pspline->getfirstderiv( dpar, m_vectan );
m_pprev = null;
m_pnext = null;
} //cspannode
// --------------------------- end cspannode members -----------------------
// --------------------------- csplineconvertor members ---------------------------
csplineconvertor::csplineconvertor() {
m_pspline = null;
m_pfirstnode = null;
m_bisrefined = false;
m_dtolgoal = 0.0;
m_dtolachieved = 0.0;
m_nsteps = 0;
m_nmaxsteps = 0;
} //csplineconvertor
csplineconvertor::~csplineconvertor() {
// deleting the list of nodes
cspannode* pnode = m_pfirstnode;
cspannode* pnextnode = null;
while( pnode != null ) {
pnextnode = pnode->getnext();
delete pnode;
pnode = pnextnode;
} //while
} //~csplineconvertor
bool csplineconvertor::selectspline( acdbentity* pent, const double dtolgoal/*=0.01*/, const int nmaxsteps/*=1000*/ ) {
// gets the spline pointer
rxassert( isspline(pent) );
m_pspline = acdbspline::cast(pent);
rxassert( m_pspline );
m_dtolgoal = dtolgoal;
m_nmaxsteps = nmaxsteps;
m_nsteps = 0;
//_icb gets the knots info
acgedoublearray arknots;
double dknottol = 0.0;
if ( getsplinenodes( arknots, dknottol ) == false ) {
acutprintf("problems extracting nurbs data\n");
return false;
} //if
cspannode* pnode = null;
cspannode* phinode = null;
int nind = arknots.length()-1;
double dhipar = arknots[nind]; // saving the highest param
double dpar = 0.0; // current param
while ( nind > 0 ) {
nind--;
dpar = arknots[nind];
// there are two situations where we allow ourselves another node. the first
// place is where this is our first node, ie phinode is null. the second is
// that there is a significant gap between the adjacent parameters.
if( phinode == null || fabs( dpar - dhipar ) > dknottol ) {
// must add another node
pnode = new cspannode( dpar, m_pspline );
m_nsteps++;
pnode->setnext( phinode );
if( phinode != null )
phinode->setprev( pnode );
phinode = pnode;
nind--;
dhipar = dpar;
} //if
} //while
m_pfirstnode = pnode;
return true;
} //setdata
// extracts the nurbs data of the spline and gets the nodes info
// dknottol is the knot value tolerance of spline
bool csplineconvertor::getsplinenodes( acgedoublearray& arknots, double& dknottol ) {
acad::errorstatus nerr;
int degree;
adesk::boolean rational;
adesk::boolean closed;
adesk::boolean periodic;
acgepoint3darray controlpoints;
acgedoublearray weights;
double controlpttol;
rxassert( isspline(m_pspline) );
nerr = m_pspline->getnurbsdata(
degree, rational, closed,
periodic, controlpoints,
arknots, weights, controlpttol,
dknottol );
return ( nerr == acad::eok );
} //getsplinenodes
bool csplineconvertor::spanwithintol( const cspannode* pstartnode, const cspannode* pendnode, double &dmidpar, double &dtolachieved ) {
acgevector3d norm = pstartnode->gettan().crossproduct( pendnode->gettan() ).normal();
acgeline3d l1 = acgeline3d( pstartnode->getpt(), pstartnode->gettan() );
acgeline3d l2 = acgeline3d( pendnode->getpt(), pendnode->gettan() );
acgeline3d l3 = acgeline3d( pstartnode->getpt(), pendnode->getpt() );
acgepoint3d p2;
acgepoint3d p1 = l1.closestpointto( l2, p2 );
double dist1 = l3.distanceto( p1 );
double dist2 = l3.distanceto( p2 );
dtolachieved = (dist1 > dist2 ) ? dist1 : dist2;
if( dtolachieved > gettolgoal() ) {
dmidpar = (pendnode->getpar() + pstartnode->getpar())* 0.5;
return false;
} else {
return true;
} //else
} //spanwithintol
// refines the knots and copy the points from the knots
bool csplineconvertor::getpoints( acgepoint3darray &arpoints ) {
bool bresult = true;
if ( !m_bisrefined ) {
bresult = refine();
} //if
if ( bresult == false ) return false;
arpoints.setlogicallength( m_nsteps );
cspannode* pnode = m_pfirstnode;
int i=0;
// getting all the node points
while( pnode != null ) {
arpoints.setat( i, pnode->getpt() );
pnode = pnode->getnext();
i++;
} //while
return true;
} //getpoints
// refine the points in the spline to meet the tolerance
bool csplineconvertor::refine() {
// our approach is to step along each span, asking the spanwithintol() func
// to check to span; if its ok, then we leave it, otherwise we split the span, using the
// nominated parameter, and test these spans.
rxassert( m_pfirstnode != null );
cspannode* plonode = m_pfirstnode;
cspannode* phinode = plonode->getnext();
cspannode* pmidnode;
bool bspandone;
double dtolthisspan;
double dmidpar;
// iterating all the list of nodes
while( phinode != null ) {
bspandone = spanwithintol( plonode, phinode, dmidpar, dtolthisspan );
if ( !bspandone ) {
// we have to add in the new node, and keep going.
pmidnode = new cspannode( dmidpar, m_pspline );
// adding the mid node next to the plonode
plonode->setnext( pmidnode );
pmidnode->setnext( phinode );
pmidnode->setprev( plonode );
phinode->setprev( pmidnode );
phinode = pmidnode;
// one node more
m_nsteps++;
} else {
if( dtolthisspan > m_dtolachieved )
m_dtolachieved = dtolthisspan;
// step to next span
plonode = phinode;
phinode = plonode->getnext();
} //else
} //while
// just to stop if things get really ugly, we allow ourselves a maximum number
// of steps. of course if this fails, the user might be willing to up the maximum number.
//
// if( m_nsteps > m_nmaxsteps ) {
// // it would seem useful to give some guesstimate on how much of the curve
// // we have created already. what we do is calculate the percentage of
// // the curve which is below this span completely. given the way the refinement
// // is performed, this is a pretty good guess. note that is just an estimate,
// // since it assumes that segments of the curve with equal parametrisation
// // require equal number of steps.
// //
// cspannode* pnode = m_pfirstnode;
// cspannode* pnextnode = pnode->getnext();
// double dbottompar = pnode->getpar();
// double dtoppar = 0.0;
//
// // first get the last node
// do {
// pnode = pnextnode;
// pnextnode = pnode->getnext();
// } while( pnextnode != null );
//
// // get param at the top
// dtoppar = pnode->getpar();
// double dcompleted = (plonode->getpar() - dbottompar) / (dtoppar - dbottompar);
//
// // offer our humble apologies
// acutprintf("requires too many steps\n");
// // offer the mitigating circumstances
// acutprintf("%d steps used so far to cover less than %2.0f%% of the curve\n",
// m_nmaxsteps, dcompleted * 100.0 );
//
// return false;
// } //if
// we're here, so we worked
m_bisrefined = true;
return true;
} //refine
// --------------------------- end csplineconvertor members ---------------------------
</pre><hr></blockquote>
hope this helps.
regards
chudomir delchev
best regards
chudomir
yeah, i've forgot a code for using it:
[code]
csplineconvertor convertor;
acgepoint3darray arpoints;
convertor.selectspline( acdbspline::cast(pcurve) );
convertor.getpoints(arpoints);
acdb3dpolyline* p3dpline = new acdb3dpolyline(acdb::k3dsimplepoly, arpoints);
// now use eighter the polyline or the array of points
</pre><hr></blockquote>
regards
chudomir delchev
best regards
chudomir
thanks! it's great!
marco
may i some question?
maybe better way is to use oddbspline::worlddraw() with your own odgiworlddraw inheritant passed?
then, when you receive nurbs geometry primitive, call odgenurbcurve3d::getsamplepoints().
or you can inherit your geometry object from odgibasedrawobject - then you'll receive polyline primitive.
sincerely yours,
george udov
|