bool SSurface::PointIntersectingLine(Vector p0, Vector p1, double *u, double *v) { int i; for(i = 0; i < 15; i++) { Vector pi, p, tu, tv; p = PointAt(*u, *v); TangentsAt(*u, *v, &tu, &tv); Vector n = (tu.Cross(tv)).WithMagnitude(1); double d = p.Dot(n); bool parallel; pi = Vector::AtIntersectionOfPlaneAndLine(n, d, p0, p1, ¶llel); if(parallel) break; // Check for convergence if(pi.Equals(p, RATPOLY_EPS)) return true; // Adjust our guess and iterate Vector dp = pi.Minus(p); double du = dp.Dot(tu), dv = dp.Dot(tv); *u += du / (tu.MagSquared()); *v += dv / (tv.MagSquared()); } // dbp("didn't converge (surface intersecting line)"); return false; }
bool SSurface::ClosestPointNewton(Vector p, double *u, double *v, bool converge) { // Initial guess is in u, v; refine by Newton iteration. Vector p0 = Vector::From(0, 0, 0); for(int i = 0; i < (converge ? 25 : 5); i++) { p0 = PointAt(*u, *v); if(converge) { if(p0.Equals(p, RATPOLY_EPS)) { return true; } } Vector tu, tv; TangentsAt(*u, *v, &tu, &tv); // Project the point into a plane through p0, with basis tu, tv; a // second-order thing would converge faster but needs second // derivatives. Vector dp = p.Minus(p0); double du = dp.Dot(tu), dv = dp.Dot(tv); *u += du / (tu.MagSquared()); *v += dv / (tv.MagSquared()); } if(converge) { dbp("didn't converge"); dbp("have %.3f %.3f %.3f", CO(p0)); dbp("want %.3f %.3f %.3f", CO(p)); dbp("distance = %g", (p.Minus(p0)).Magnitude()); } return false; }
void SSurface::EdgeNormalsWithinSurface(Point2d auv, Point2d buv, Vector *pt, Vector *enin, Vector *enout, Vector *surfn, uint32_t auxA, SShell *shell, SShell *sha, SShell *shb) { // the midpoint of the edge Point2d muv = (auv.Plus(buv)).ScaledBy(0.5); *pt = PointAt(muv); // If this edge just approximates a curve, then refine our midpoint so // so that it actually lies on that curve too. Otherwise stuff like // point-on-face tests will fail, since the point won't actually lie // on the other face. hSCurve hc = { auxA }; SCurve *sc = shell->curve.FindById(hc); if(sc->isExact && sc->exact.deg != 1) { double t; sc->exact.ClosestPointTo(*pt, &t, false); *pt = sc->exact.PointAt(t); ClosestPointTo(*pt, &muv); } else if(!sc->isExact) { SSurface *trimmedA = sc->GetSurfaceA(sha, shb), *trimmedB = sc->GetSurfaceB(sha, shb); *pt = trimmedA->ClosestPointOnThisAndSurface(trimmedB, *pt); ClosestPointTo(*pt, &muv); } *surfn = NormalAt(muv.x, muv.y); // Compute the edge's inner normal in xyz space. Vector ab = (PointAt(auv)).Minus(PointAt(buv)), enxyz = (ab.Cross(*surfn)).WithMagnitude(SS.ChordTolMm()); // And based on that, compute the edge's inner normal in uv space. This // vector is perpendicular to the edge in xyz, but not necessarily in uv. Vector tu, tv; TangentsAt(muv.x, muv.y, &tu, &tv); Point2d enuv; enuv.x = enxyz.Dot(tu) / tu.MagSquared(); enuv.y = enxyz.Dot(tv) / tv.MagSquared(); // Compute the inner and outer normals of this edge (within the srf), // in xyz space. These are not necessarily antiparallel, if the // surface is curved. Vector pin = PointAt(muv.Minus(enuv)), pout = PointAt(muv.Plus(enuv)); *enin = pin.Minus(*pt), *enout = pout.Minus(*pt); }
Vector SSurface::NormalAt(double u, double v) { Vector tu, tv; TangentsAt(u, v, &tu, &tv); return tu.Cross(tv); }