Path: blob/devel/ElmerGUI/netgen/libsrc/csg/spline3d.cpp
3206 views
#include <mystdlib.h>12#include <myadt.hpp>34#include <linalg.hpp>5#include <csg.hpp>678namespace netgen9{10splinesegment3d :: splinesegment3d (const Point<3> & ap1, const Point<3> & ap2,11const Point<3> & ap3)12{13p1 = ap1;14p2 = ap2;15p3 = ap3;16}171819/*20todo21Tip von Joerg Stiller:22setzt Du in23void splinesegment3d :: Evaluate24Zeilen 54 und 5625b2 = 2 * t * (1-t);26b2 /= sqrt(2);27Das heisst, Du wichtest das zweite Bersteinpolynom mit28w2 = 1 / sqrt(2);29Das ist aber nur fuer 45-Grad-Segmente korrekt. Fuer den30allgemeinen Fall funktioniert31w2 = ( e(p3 - p1), e(p2 - p1) ); // also cos(winkel(p3-p1, p2-p1))32bzw. schoen symmetrisch33w2 = ( e(p3 - p1), e(p2 - p1) )/2 + ( e(p1 - p3), e(p2 - p3) )/2;34Das ist natuerlich kein C++ Code sondern symbolisch, wobei35e(p3 - p1) ist der von p1 zu p3 zeigende Einheitsvektor und36(a, b) steht fuer das Skalarprodukt zweier Vektoren etc.3738Eine vergleichbare Information steht auch irgendwo im Hoscheck & Lasser.39Ich habe das Buch aber eben nicht zur Hand.40*/4142void splinesegment3d :: Evaluate (double t, Point<3> & p) const43{44double x, y, z, w;45double b1, b2, b3;4647b1 = (1-t)*(1-t);48b2 = 2 * t * (1-t);49b3 = t * t;5051b2 /= sqrt(double(2));5253x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;54y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;55z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;56w = b1 + b2 + b3;5758p(0) = x / w;59p(1) = y / w;60p(2) = z / w;61}6263void splinesegment3d :: EvaluateTangent (double t, Vec<3> & tang) const64{65double x, y, z, w, xprime, yprime, zprime, wprime;66double b1, b2, b3, b1prime, b2prime, b3prime;6768b1 = (1-t)*(1-t);69b2 = 2 * t * (1-t);70b3 = t * t;71b2 /= sqrt(double(2));7273b1prime = 2 * t - 2;74b2prime = - 4 * t + 2;75b3prime = 2 * t;76b2prime /= sqrt(double(2));777879x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;80y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;81z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;82w = b1 + b2 + b3;8384xprime = p1(0) * b1prime + p2(0) * b2prime + p3(0) * b3prime;85yprime = p1(1) * b1prime + p2(1) * b2prime + p3(1) * b3prime;86zprime = p1(2) * b1prime + p2(2) * b2prime + p3(2) * b3prime;87wprime = b1prime + b2prime + b3prime;8889tang(0) = (w * xprime - x * wprime) / (w * w);90tang(1) = (w * yprime - y * wprime) / (w * w);91tang(2) = (w * zprime - z * wprime) / (w * w);92}939495void spline3d :: AddSegment (const Point<3> & ap1, const Point<3> & ap2,96const Point<3> & ap3)97{98segments.Append (new splinesegment3d (ap1, ap2, ap3));99}100101void spline3d :: Evaluate (double t, Point<3> & p) const102{103int nr;104double loct;105static int cnt = 0;106107cnt++;108if (cnt % 10000 == 0) (*mycout) << "Evaluate calls: " << cnt << endl;109110while (t < 0) t += GetNumSegments();111while (t >= GetNumSegments()) t -= GetNumSegments();112nr = 1 + int (t);113loct = t - nr + 1;114segments.Get(nr)->Evaluate (loct, p);115}116117void spline3d :: EvaluateTangent (double t, Vec<3> & tang) const118{119int nr;120double loct;121122while (t < 0) t += GetNumSegments();123while (t >= GetNumSegments()) t -= GetNumSegments();124nr = 1 + int (t);125loct = t - nr + 1;126segments.Get(nr)->EvaluateTangent (loct, tang);127}128129130double spline3d :: ProjectToSpline (Point<3> & p) const131{132double t, tl, tu, dt, dist, mindist, optt(0);133Point<3> hp;134Vec<3> tanx, px;135136dt = 0.01;137mindist = 0;138for (t = 0; t <= GetNumSegments() + dt/2; t += dt)139{140Evaluate (t, hp);141dist = Dist (hp, p);142if (t == 0 || dist < mindist)143{144optt = t;145mindist = dist;146}147}148149150tu = optt + dt;151tl = optt - dt;152while (tu - tl > 1e-2)153{154optt = 0.5 * (tu + tl);155Evaluate (optt, hp);156EvaluateTangent (optt, tanx);157if (tanx * (hp - p) > 0)158tu = optt;159else160tl = optt;161}162163optt = 0.5 * (tu + tl);164165optt = ProjectToSpline (p, optt);166return optt;167}168169170double spline3d :: ProjectToSpline (Point<3> & p, double optt) const171{172double tl, tu, dt, val, dval, valu, vall;173Point<3> hp;174Vec<3> tanx, px;175int its = 0;176int cnt = 1000;177do178{179dt = 1e-8;180tl = optt - dt;181tu = optt + dt;182183EvaluateTangent (optt, tanx);184Evaluate (optt, hp);185px = hp - p;186val = px * tanx;187188EvaluateTangent (tl, tanx);189Evaluate (tl, hp);190px = hp - p;191vall = px * tanx;192193EvaluateTangent (tu, tanx);194Evaluate (tu, hp);195px = hp - p;196valu = px * tanx;197198dval = (valu - vall) / (2 * dt);199200if (its % 100 == 99)201(*testout) << "optt = " << optt202<< " val = " << val203<< " dval = " << dval << endl;204optt -= val / dval;205its++;206if (fabs(val) < 1e-8 && cnt > 5) cnt = 5;207cnt--;208}209while (cnt > 0);210211Evaluate (optt, p);212return optt;213}214215216splinetube :: splinetube (const spline3d & amiddlecurve, double ar)217: Surface(), middlecurve (amiddlecurve), r(ar)218{219(*mycout) << "Splinetube Allocated, r = " << r << endl;220221}222223void splinetube :: DefineTangentialPlane (const Point<3> & ap1,224const Point<3> & ap2)225{226double t;227double phi, z;228229p1 = ap1;230p2 = ap2;231cp = p1;232t = middlecurve.ProjectToSpline (cp);233ex = p1 - cp;234middlecurve.EvaluateTangent (t, ez);235ex.Normalize();236ez.Normalize();237ey = Cross (ez, ex);238239phi = r * atan2 (ey * (p2-cp), ex * (p2-cp));240z = ez * (p2 - cp);241e2x(0) = phi;242e2x(1) = z;243e2x.Normalize();244e2y(1) = e2x(0);245e2y(0) = -e2x(1);246247// (*testout) << "Defineplane: " << endl248// << "p1 = " << p1 << " p2 = " << p2 << endl249// << "pc = " << cp << endl250// << "ex = " << ex << " ey = " << ey << " ez = " << ez << endl251// << "phi = " << phi << " z = " << z << endl252// << "e2x = " << e2x << " e2y = " << e2y << endl;253}254255void splinetube :: ToPlane (const Point<3> & p3d, Point<2> & pplain, double h,256int & zone) const257{258Vec<2> v;259v(0) = r * atan2 (ey * (p3d-cp), ex * (p3d-cp));260v(1) = ez * (p3d - cp);261zone = 0;262if (v(0) > r * 2) zone = 1;263if (v(0) < r * 2) zone = 2;264265pplain(0) = (v * e2x) / h;266pplain(1) = (v * e2y) / h;267}268269void splinetube :: FromPlane (const Point<2> & pplain, Point<3> & p3d, double h) const270{271Vec<2> v;272273v(0) = pplain(0) * h * e2x(0) + pplain(1) * h * e2y(0);274v(1) = pplain(0) * h * e2x(1) + pplain(1) * h * e2y(1);275276p3d = p1 + v(0) * ey + v(1) * ez;277278Project (p3d);279}280281void splinetube :: Project (Point<3> & p3d) const282{283Point<3> hp;284285hp = p3d;286middlecurve.ProjectToSpline (hp);287288p3d = hp + (r / Dist(p3d, hp)) * (p3d - hp);289}290291292293double splinetube :: CalcFunctionValue (const Point<3> & point) const294{295Point<3> hcp;296double rad;297298hcp = point;299middlecurve.ProjectToSpline (hcp);300rad = Dist (hcp, point);301return 0.5 * (rad * rad / r - r);302}303304void splinetube :: CalcGradient (const Point<3> & point, Vec<3> & grad) const305{306Point<3> hcp;307308hcp = point;309middlecurve.ProjectToSpline (hcp);310311grad = point - hcp;312grad /= r;313}314315316317318Point<3> splinetube :: GetSurfacePoint () const319{320Point<3> p;321Vec<3> t, n;322323middlecurve.Evaluate (0, p);324middlecurve.EvaluateTangent (0, t);325n = t.GetNormal ();326n *= r;327(*mycout) << "p = " << p << " t = " << t << " n = " << n << endl;328return p + n;329}330331void splinetube :: Print (ostream & str) const332{333int i;334str << "SplineTube, "335<< middlecurve.GetNumSegments () << " segments, r = " << r << endl;336for (i = 1; i <= middlecurve.GetNumSegments(); i++)337str << middlecurve.P1(i) << " - "338<< middlecurve.P2(i) << " - "339<< middlecurve.P3(i) << endl;340}341342343int splinetube :: BoxInSolid (const BoxSphere<3> & box) const344// 0 .. no, 1 .. yes, 2 .. maybe345{346Point<3> pc = box.Center();347middlecurve.ProjectToSpline (pc);348double d = Dist (pc, box.Center());349350if (d < r - box.Diam()/2) return 1;351if (d > r + box.Diam()/2) return 0;352return 2;353}354}355356357