int LineArcIntof(const Span& line, const Span& arc, Point& p0, Point& p1, double t[4]) { // inters of line arc // solving x = x0 + dx * t x = y0 + dy * t // x = xc + R * cos(a) y = yc + R * sin(a) for t // gives :- t² (dx² + dy²) + 2t(dx*dx0 + dy*dy0) + (x0-xc)² + (y0-yc)² - R² = 0 int nRoots; Vector2d v0(arc.pc, line.p0); Vector2d v1(line.p0, line.p1); double s = v1.magnitudesqd(); p0.ok = p1.ok = false; if((nRoots = quadratic(s, 2 * (v0 * v1), v0.magnitudesqd() - arc.radius * arc.radius, t[0], t[1])) != 0) { double toler = geoff_geometry::TOLERANCE / sqrt(s); // calc a parametric tolerance if(t[0] > -toler && t[0] < 1 + toler) { p0 = v1 * t[0] + line.p0; p0.ok = arc.OnSpan(p0, &t[2]); } if(nRoots == 2) { if(t[1] > -toler && t[1] < 1 + toler) { p1 = v1 * t[1] + line.p0; p1.ok = arc.OnSpan(p1, &t[3]); } } if(!p0.ok && p1.ok) { p0 = p1; p1.ok = false; } nRoots = (int)p0.ok + (int)p1.ok; } return nRoots; }
int ArcArcIntof(const Span& arc0, const Span& arc1, Point& pLeft, Point& pRight) { // Intof 2 arcs int numInts = Intof(Circle(arc0.pc, arc0.radius), Circle(arc1.pc, arc1.radius), pLeft, pRight); if(numInts == 0) { pLeft = arc0.p1; pLeft.ok = false; return 0; } int nLeft = arc0.OnSpan(pLeft) && arc1.OnSpan(pLeft); int nRight = (numInts == 2)?arc0.OnSpan(pRight) && arc1.OnSpan(pRight) : 0; if(nLeft == 0 && nRight) pLeft = pRight; return nLeft + nRight; }
double Dist(const Span& sp, const Point& p , Point& pnear ) { // returns distance of p from span, pnear is the nearpoint on the span (or endpoint) if(!sp.dir) { double d, t; Point3d unused_pnear; d = Dist(Line(sp), Point3d(p), unused_pnear, t); if(t < -geoff_geometry::TOLERANCE) { pnear = sp.p0; // nearpoint d = pnear.Dist(p); } else if(t > sp.length + geoff_geometry::TOLERANCE) { pnear = sp.p1; d = pnear.Dist(p); } return d; } else { // put pnear on the circle double radiusp; Vector2d v(sp.pc, p); if((radiusp = v.magnitude()) < geoff_geometry::TOLERANCE) { // point specified on circle centre - use first point as near point pnear = sp.p0; // nearpoint return sp.radius; } else { pnear = v * (sp.radius / radiusp) + sp.pc; // check if projected point is on the arc if(sp.OnSpan(pnear)) return fabs(radiusp - sp.radius); // double h1 = pnear.x - sp.p0.x ; // double v1 = pnear.y - sp.p0.y ; // double h2 = sp.p1.x - pnear.x ; // double v2 = sp.p1.y - pnear.y ; // if ( sp.dir * ( h1 * v2 - h2 * v1 ) >= 0 )return fabs(radiusp - sp.radius); // point not on arc so calc nearest end-point double ndist = p.Dist(sp.p0); double dist = p.Dist(sp.p1); if(ndist >= dist) { // sp.p1 is near point pnear = sp.p1; return dist; } // sp.p0 is near point pnear = sp.p0; // nearpoint return ndist ; } } }
bool OnSpan(const Span& sp, const Point& p, bool nearPoints, Point& pNear, Point& pOnSpan) { // function returns true if pNear == pOnSpan // returns pNear & pOnSpan if nearPoints true // pNear (nearest on unbound span) // pOnSpan (nearest on finite span) if(sp.dir) { // arc if(fabs(p.Dist(sp.pc) - sp.radius) > geoff_geometry::TOLERANCE) { if(!nearPoints) return false; } pNear = On(Circle(sp.pc, sp.radius), p); if(sp.OnSpan(pNear)) { if(nearPoints) pOnSpan = pNear; return true; // near point is on arc - already calculated } // point not on arc return the nearest end-point if(nearPoints) pOnSpan = (p.Dist(sp.p0) >= p.Dist(sp.p1)) ?sp.p1 : sp.p0; return false; } else { // straight if(fabs(CLine(sp.p0, sp.vs).Dist(p)) > geoff_geometry::TOLERANCE) { if(!nearPoints) return false; } Vector2d v(sp.p0, p); double t = v * sp.vs; if(nearPoints) pNear = sp.vs * t + sp.p0; bool onSpan = (t > - geoff_geometry::TOLERANCE && t < sp.length + geoff_geometry::TOLERANCE); if(! onSpan) { if(nearPoints) pOnSpan = (p.Dist(sp.p0) >= p.Dist(sp.p1))?sp.p1 : sp.p0; } else { if(nearPoints) pOnSpan = pNear; } return onSpan; } }