00001
00002
00003 #include "Iguana/Inventor/interface/IgSoSplineTrack.h"
00004 #include <Inventor/nodes/SoCoordinate4.h>
00005 #include <Inventor/nodes/SoNurbsCurve.h>
00006 #include <cmath>
00007 #include <iostream>
00008
00009
00010
00011 namespace {
00012 #ifdef TGS_VERSION
00013 static const float maxNurbAngle = M_PI / 2.;
00014 #else
00015 static const float maxNurbAngle = M_PI / 6.;
00016 #endif
00017 }
00018
00019 namespace {
00020
00021
00022
00023
00024
00025 class RootFunction : public std::unary_function<float,float>
00026 {
00027 public:
00028 RootFunction(float paramA, float paramC, float paramF) :
00029 a(paramA), c(paramC), f(paramF)
00030 {};
00031 float operator()(const float x) const
00032 {
00033 double denom = -2* (1-cos (x))* (1-a) +x*x* (cos (x)-a);
00034 double numerator = c * (cos (x)-a);
00035 double radical = numerator / denom;
00036 if (radical > 0) {
00037 radical = sqrt (radical);}
00038 else {
00039 radical = 0;
00040 }
00041
00042 return static_cast<float> (f + radical * (1-a)* (-2+2*cos (x)+x*sin (x))/ (cos (x)-1));
00043 }
00044 private:
00045 const double a, c, f;
00046 };
00047 }
00048
00049
00050
00051
00052
00053 const float M_SQRT3_2 = 0.8660254037844F;
00054 const int IgSoSplineTrack::NORDER = 3;
00055
00056 SO_KIT_SOURCE (IgSoSplineTrack);
00057
00058
00059
00060
00061
00062 void
00063 IgSoSplineTrack::initClass (void)
00064 { SO_KIT_INIT_CLASS (IgSoSplineTrack, IgSoShapeKit, "IgSoShapeKit"); }
00065
00066 IgSoSplineTrack::IgSoSplineTrack (void)
00067 {
00068 SO_KIT_CONSTRUCTOR (IgSoSplineTrack);
00069
00070 SO_KIT_ADD_FIELD (points, (SbVec3f (0, 0, 0)));
00071 SO_KIT_ADD_FIELD (tangents, (SbVec3f (0, 0, 0)));
00072
00073 SO_KIT_ADD_CATALOG_ENTRY (coordinates, SoCoordinate4, FALSE, separator, \x0, TRUE);
00074 SO_KIT_ADD_CATALOG_ENTRY (curve, SoNurbsCurve, FALSE, separator,\x0, TRUE);
00075
00076 SO_KIT_INIT_INSTANCE ();
00077
00078
00079
00080
00081 SbVec3f defPoints[2] = {SbVec3f (0.F,0.F,0.F),
00082 SbVec3f (0.F,1.F,0.F)};
00083 SbVec3f defTangents[2] = {SbVec3f (1.F,0.F,0.F),
00084 SbVec3f (1.F,0.F,0.F)};
00085 points.setValues (0, 2, defPoints);
00086 tangents.setValues (0, 2, defTangents);
00087
00088 setUpConnections (true, true);
00089 }
00090
00091 void
00092 IgSoSplineTrack::refresh (void)
00093 {
00094 int npts = points.getNum ();
00095 if (npts <= 1)
00096 {
00097 setPart ("coordinates", NULL);
00098 setPart ("curve", NULL);
00099 return;
00100 }
00101
00102 SoCoordinate4 *coords = new SoCoordinate4;
00103 SoNurbsCurve *ncurve = new SoNurbsCurve;
00104
00105
00106 std::vector <SbVec4f> controlPoints (2 * npts - 1);
00107 std::vector <float> knotVals (2 * npts - 1 + NORDER);
00108
00109 int ik = 0;
00110 int ipi = 0;
00111 int ik_count = 0;
00112 int ipo = 0;
00113
00114 knotVals[ik++] = static_cast<float>(ik_count);
00115
00116 while (ipi < (npts - 1))
00117 {
00118 knotVals[ik++] = static_cast<float>(ik_count);
00119 controlPoints[ipo++] = SbVec4f ( points[ipi][0], points[ipi][1], points[ipi][2], 1.F);
00120
00121 midpoint (points[ipi], points[ipi+1], tangents[ipi], tangents[ipi+1], ik, ik_count, ipo, controlPoints, knotVals);
00122 ipi++;
00123 }
00124
00125 controlPoints[ipo++] = SbVec4f ( points[ipi][0], points[ipi][1], points[ipi][2],1.F);
00126 knotVals[ik++] = static_cast<float>(ik_count);
00127 knotVals[ik++] = static_cast<float>(ik_count);
00128 knotVals[ik++] = static_cast<float>(ik_count);
00129
00130
00131 coords->point.setValues (0,ipo,&(controlPoints[0]));
00132 ncurve->knotVector.setValues (0,ik, &(knotVals[0]));
00133 ncurve->numControlPoints.setValue (ipo);
00134
00135 setPart ("coordinates", coords);
00136 setPart ("curve", ncurve);
00137 }
00138
00139 void
00140 IgSoSplineTrack::midpoint (const SbVec3f pa, const SbVec3f pb, const SbVec3f ta, const SbVec3f tb,
00141 int &ik, int &ik_count, int &ipo, std::vector<SbVec4f> &controlPoints, std::vector<float> &knotVals)
00142 {
00143
00144
00145
00146
00147 const float eps = 0.000001F;
00148
00149
00150
00151 float paramA = tb.dot (ta);
00152 float paramC = (pb-pa).dot (pb-pa);
00153 float paramD = tb.dot (ta.cross (pb-pa));
00154
00155
00156 SbVec3f midpt3s ((pa+pb)/2.F);
00157 SbVec4f midpt4s (midpt3s[0],midpt3s[1],midpt3s[2],1.F);
00158
00159
00160 if (std::abs (paramC)<eps || (std::abs (paramA-1) < eps && std::abs (paramD)/paramC < eps)) {
00161 controlPoints[ipo++] = midpt4s;
00162 knotVals[ik++] = static_cast<float>(ik_count++);
00163 return;
00164 }
00165
00166
00167 SbVec3f perp = ta.cross (tb);
00168 if (std::abs (perp.dot (perp)) < eps)
00169 {
00170 controlPoints[ipo++] = midpt4s;
00171 knotVals[ik++] = static_cast<float>(ik_count++);
00172 return;
00173 }
00174
00175 float zeta = 0.F;
00176 float delta = 0.F;
00177 float rho = 0.F;
00178
00179
00180 if (std::abs (paramD)<eps)
00181 {
00182
00183
00184 zeta = 0.F;
00185 delta = std::acos(paramA);
00186 rho = std::sqrt(paramC/2.F/(1.F-paramA));
00187 paramD = -1.5F*eps;
00188 }
00189 else
00190 {
00191
00192 bool err = true;
00193 int paramSign = 1;
00194
00195 delta = findRoot (RootFunction(paramA, paramC, -paramD), 0.01F, static_cast< float > (M_PI), eps, err);
00196 if (err) {
00197 paramSign = -1;
00198 delta = findRoot (RootFunction(paramA, paramC, paramD), 0.01F, static_cast< float > (M_PI), eps, err);
00199 if (err)
00200 {
00201 #if 0 //DEBUG
00202 std::cout << "Problem in SoSplineTrack. Can't find root. " << std::endl;
00203 float x,y,z;
00204 pa.getValue (x,y,z);
00205 std::cout << "pa: " << x << ", " << y << ", " << z << std::endl;
00206 pb.getValue (x,y,z);
00207 std::cout << "pb: " << x << ", " << y << ", " << z << std::endl;
00208 ta.getValue (x,y,z);
00209 std::cout << "ta: " << x << ", " << y << ", " << z << std::endl;
00210 tb.getValue (x,y,z);
00211 std::cout << "tb: " << x << ", " << y << ", " << z << std::endl;
00212 #endif //DEBUG
00213 controlPoints[ipo++] = midpt4s;
00214 return;
00215 }
00216 }
00217 zeta = paramSign * sqrt (std::abs ((paramA-cos (delta))/ (1.0F-paramA)));
00218 rho = sqrt (paramC/ (2+delta*delta*zeta*zeta-2*cos (delta)));
00219 }
00220
00221 SbVec3f taMP = SbVec3f ( 0.f, rho, rho*zeta);
00222 taMP.normalize();
00223 SbVec3f paMP = SbVec3f ( rho, 0.0f, 0.f );
00224 SbVec3f tbMP = SbVec3f( -rho * sin(delta), rho * cos(delta), rho * zeta );
00225 tbMP.normalize();
00226 SbVec3f tc = ta.cross(tb);
00227 tc.normalize();
00228 SbVec3f tcMP = taMP.cross(tbMP);
00229 tcMP.normalize();
00230
00231
00232
00233 SbMatrix mMP(taMP[0], tbMP[0], tcMP[0], 0.f,
00234 taMP[1], tbMP[1], tcMP[1], 0.f,
00235 taMP[2], tbMP[2], tcMP[2], 0.f,
00236 0.f, 0.f, 0.f, 1.f);
00237
00238 SbMatrix m(ta[0], tb[0], tc[0], 0.f,
00239 ta[1], tb[1], tc[1], 0.f,
00240 ta[2], tb[2], tc[2], 0.f,
00241 0.f, 0.f, 0.f, 1.f);
00242
00243 SbMatrix mm = m.multRight(mMP.inverse()).transpose();
00244
00245
00246
00247
00248 SbMatrix xform;
00249 xform.setTranslate(-paMP);
00250 xform = xform.multRight(mm);
00251 SbMatrix transBack;
00252 transBack.setTranslate(pa);
00253 xform = xform.multRight(transBack);
00254
00255
00256 const int ndiv = 1 + static_cast<int>(std::floor(std::abs(delta)/maxNurbAngle));
00257
00258 float deltan = delta/ndiv;
00259 float wt = std::abs (cos (deltan/2) );
00260 #if 0 //DEBUG
00261 if (wt < eps)
00262 {
00263 std::cout << "Problem in SoSplineTrack. Wt = " << wt << std::endl;
00264 std::cout << " params: " << paramA <<","<< paramC << "," << paramD << std::endl;
00265 }
00266 #endif //DEBUG
00267
00268
00269 if (ndiv > 1)
00270 {
00271 controlPoints.resize( controlPoints.size()+2*(ndiv-1) );
00272 knotVals.resize( knotVals.size()+2*(ndiv-1) );
00273 }
00274
00275 float angle=0.F;
00276 for ( int i=0; i < ndiv; i++, angle += deltan )
00277 {
00278 if (i!=0)
00279 {
00280 SbVec3f endpt ( rho * std::cos(angle), rho * std::sin(angle), rho * zeta * (angle) );
00281 xform.multVecMatrix ( endpt, endpt );
00282 SbVec4f endpt4 ( endpt[0], endpt[1], endpt[2], 1.F );
00283 knotVals[ik++] = static_cast<float>(ik_count);
00284 controlPoints[ipo++] = endpt4;
00285 }
00286 SbVec3f midpt3_0 ( rho * std::cos (angle+deltan/2.0F), rho * std::sin (angle+deltan/2.0F), rho * zeta*(angle+deltan/2.0F));
00287 SbVec3f midpt3 (midpt3_0[0]/wt, midpt3_0[1]/wt, midpt3_0[2]);
00288
00289 xform.multVecMatrix (midpt3,midpt3);
00290 SbVec4f midpt (midpt3[0],midpt3[1],midpt3[2],1.F);
00291 midpt *= wt;
00292 controlPoints[ipo++] = midpt;
00293 knotVals[ik++] = static_cast<float>(ik_count++);
00294 }
00295
00296 }
00297
00298 float
00299 IgSoSplineTrack::findRoot (const RootFunction func, float x1, float x2, float xacc, bool &err)
00300 {
00301
00302 err = false;
00303 const int JMAX = 40;
00304
00305 func(x1);
00306 float f= func(x1);
00307 float fmid= func(x2);
00308
00309
00310 if (f*fmid >=0.0) {
00311 err = true;
00312 #if 0 //DEBUG
00313 std::cout << "SoSplineTrack f*fmid >= 0" << std::endl;
00314 std::cout << " f="<< f << " fmid=" << fmid << std::endl;
00315 #endif //DEBUG
00316 return 0.0;}
00317 else {
00318 float dx, xmid;
00319 float rtb = f < 0.0 ? (dx=x2-x1,x1) : (dx=x1-x2,x2);
00320 for (int j=1; j<JMAX; j++) {
00321 fmid= func(xmid=rtb + (dx *= 0.5));
00322 if (fmid <= 0.0) rtb=xmid;
00323 if (std::abs (dx) < xacc || fmid == 0.0) return rtb;
00324 }
00325 err = true;
00326 #if 0 //DEBUG
00327 std::cout << "SoSplineTrack: findRoot failed to converge" << std::endl;
00328 std::cout << " f="<< f << " fmid=" << fmid << " rtb=" << rtb << std::endl;
00329 #endif //DEBUG
00330 return 0.0;
00331 }
00332 }