//---------------------------------------------------------------------------- void Mgc::ApproximateEllipseByArcs (Real fA, Real fB, int iNumArcs, Vector2*& rakPoint, Vector2*& rakCenter, Real*& rafRadius) { // allocate arrays assert( iNumArcs >= 2 ); if ( iNumArcs < 2 ) { rakPoint = NULL; rakCenter = NULL; rafRadius = NULL; return; } rakPoint = new Vector2[iNumArcs+1]; rakCenter = new Vector2[iNumArcs]; rafRadius = new Real[iNumArcs]; // intermediate ellipse quantities Real fA2 = fA*fA, fB2 = fB*fB, fAB = fA*fB, fInvB2mA2 = 1.0f/(fB2-fA2); // End points of ellipse in first quadrant. Points are generated in // counterclockwise order. rakPoint[0] = Vector2(fA,0.0f); rakPoint[iNumArcs] = Vector2(0.0f,fB); // curvature at end points, store curvature for computing arcs Real fK0 = fA/fB2; Real fK1 = fB/fA2; // select ellipse points based on curvature properties Real fInvNumArcs = 1.0f/iNumArcs; int i; for (i = 1; i < iNumArcs; i++) { // curvature at new point is weighted average of curvature at ends Real fW1 = i*fInvNumArcs, fW0 = 1.0f - fW1; Real fK = fW0*fK0 + fW1*fK1; // compute point having this curvature Real fTmp = Math::Pow(fAB/fK,0.6666667f); rakPoint[i].x = fA*Math::Sqrt(Math::FAbs((fTmp-fA2)*fInvB2mA2)); rakPoint[i].y = fB*Math::Sqrt(Math::FAbs((fTmp-fB2)*fInvB2mA2)); } // compute arc at (a,0) Circle2 kCircle; Circumscribe(Vector2(rakPoint[1].x,-rakPoint[1].y),rakPoint[0], rakPoint[1],kCircle); rakCenter[0] = kCircle.Center(); rafRadius[0] = kCircle.Radius(); // compute arc at (0,b) int iLast = iNumArcs-1; Circumscribe(Vector2(-rakPoint[iLast].x,rakPoint[iLast].y), rakPoint[iNumArcs],rakPoint[iLast],kCircle); rakCenter[iLast] = kCircle.Center(); rafRadius[iLast] = kCircle.Radius(); // compute arcs at intermediate points between (a,0) and (0,b) int iM, iP; for (iM = 0, i = 1, iP = 2; i < iLast; iM++, i++, iP++) { Circumscribe(rakPoint[iM],rakPoint[i],rakPoint[iP],kCircle); rakCenter[i] = kCircle.Center(); rafRadius[i] = kCircle.Radius(); } }
void ApproximateEllipseByArcs (Real a, Real b, int numArcs, Vector2<Real>*& points, Vector2<Real>*& centers, Real*& radii) { // Allocate arrays. assertion(numArcs >= 2, "Must specify at least two arcs\n"); if (numArcs < 2) { points = 0; centers = 0; radii = 0; return; } points = new1<Vector2<Real> >(numArcs + 1); centers = new1<Vector2<Real> >(numArcs); radii = new1<Real>(numArcs); // Intermediate ellipse quantities. Real a2 = a*a, b2 = b*b, ab = a*b; Real invB2mA2 = ((Real)1)/(b2 - a2); // End points of ellipse in first quadrant. Points are generated in // counterclockwise order. points[0] = Vector2<Real>(a, (Real)0); points[numArcs] = Vector2<Real>((Real)0, b); // Curvature at end points, store curvature for computing arcs. Real curv0 = a/b2; Real curv1 = b/a2; // Select ellipse points based on curvature properties. Real invNumArcs = ((Real)1)/numArcs; int i; for (i = 1; i < numArcs; ++i) { // Curvature at new point is weighted average of curvature at ends. Real weight1 = i*invNumArcs; Real weight0 = (Real)1 - weight1; Real curv = weight0*curv0 + weight1*curv1; // Compute point having this curvature. Real tmp = Math<Real>::Pow(ab/curv, (Real)2/(Real)3); points[i][0] = a*Math<Real>::Sqrt( Math<Real>::FAbs((tmp - a2)*invB2mA2)); points[i][1] = b*Math<Real>::Sqrt( Math<Real>::FAbs((tmp - b2)*invB2mA2)); } // Compute arc at (a,0). Circle2<Real> circle; Circumscribe<Real>(Vector2<Real>(points[1][0], -points[1][1]), points[0], points[1], circle); centers[0] = circle.Center; radii[0] = circle.Radius; // Compute arc at (0,b). int last = numArcs - 1; Circumscribe(Vector2<Real>(-points[last][0], points[last][1]), points[numArcs], points[last], circle); centers[last] = circle.Center; radii[last] = circle.Radius; // Compute arcs at intermediate points between (a,0) and (0,b). int iM, iP; for (iM = 0, i = 1, iP = 2; i < last; ++iM, ++i, ++iP) { Circumscribe<Real>(points[iM], points[i], points[iP], circle); centers[i] = circle.Center; radii[i] = circle.Radius; } }