![]() |
【转帖】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 |
所有的时间均为北京时间。 现在的时间是 08:29 PM. |