bezier.cpp
上传用户:whjcdz88
上传日期:2011-09-07
资源大小:121k
文件大小:6k
源码类别:

图形图象

开发平台:

WINDOWS

  1. #include "stdafx.h"
  2. #include "bezier.h"
  3. #include <math.h>
  4. // Copyright Llew S. Goodstadt 1998
  5. // http://www.lg.ndirect.co.uk    mailto:lg@ndirect.co.uk
  6. // you are hereby granted the right tofair use and distribution
  7. // including in both commercial and non-commercial applications.
  8. // anonymous namespace for static linking
  9. namespace
  10. {
  11.     void DoBezierPts(const LBezier& V, double error, double& len, double& t, double& result);
  12. }
  13. void LBezier::GetCPoint(CPoint* out)
  14. {
  15.     for (int i = 0; i <= 3; ++i)
  16.         out[i] = p[i].GetCPoint();
  17. }
  18. // split into two halves
  19. void LBezier::Split(LBezier& Left, LBezier& Right) const
  20. {
  21.     // Triangle Matrix
  22.     LBezier   Vtemp[4];
  23.     // Copy control LDPoints
  24.     Vtemp[0] = *this;
  25.     // Triangle computation
  26.     for (int i = 1; i <= 3; i++) 
  27.     {
  28.         for (int j =0 ; j <= 3 - i; j++) 
  29.         {
  30.             Vtemp[i].p[j].x =   0.5 * Vtemp[i-1].p[j].x + 0.5 * Vtemp[i-1].p[j+1].x;
  31.             Vtemp[i].p[j].y =   0.5 * Vtemp[i-1].p[j].y + 0.5 * Vtemp[i-1].p[j+1].y;
  32.         }
  33.     }
  34.     for (int j = 0; j <= 3; j++)
  35.     {
  36.         Left.p[j]  = Vtemp[j].p[0];      
  37.         Right.p[j] = Vtemp[3-j].p[j];    
  38.     }   
  39. }   
  40. //Get length of bezier to within error
  41. double LBezier::Length(double error) const
  42. {
  43.     // control polygon length
  44.     double controlPolygonLen = 0.0;
  45.     for (int i = 0; i <= 2; i++)
  46.         controlPolygonLen += p[i].DistFrom(p[i+1]);
  47.     // chord length
  48.     double chordLen = p[0].DistFrom(p[3]);
  49.     // split into two until each can be approximated by its chord
  50.     if(controlPolygonLen - chordLen > error)  
  51.     {
  52.         // split in two recursively and add lengths of each
  53.         LBezier left, right;
  54.         Split(left, right);
  55.         return left.Length(error) + right.Length(error);
  56.     }
  57.     return controlPolygonLen;
  58. }
  59. void LBezier::TSplit(LBezier& Output, double t)
  60. {
  61.     double s    = 1.0 - t;
  62.     double ss   = s * s;
  63.     double tt   = t * t;
  64.     Output.p[0]     = p[0];
  65.     Output.p[1]     = p[1] * t + p[0] * s;
  66.     Output.p[2]     = p[0] * ss + p[1] * s * t * 2.0 + p[2] * tt;
  67.     Output.p[3]     = p[0] * s * ss + p[1] * ss * t * 3.0 + 
  68.                       p[2] * s * tt * 3.0 + p[3] * t * tt;
  69.     p[0]        = Output.p[3];
  70.     p[1]        = p[1] * ss + p[2] * s * t * 2.0 + p[3] * tt;
  71.     p[2]        = p[2] * s + p[3] * t;
  72. }
  73. double LBezier::TAtLength(unsigned int& length) const
  74. {
  75.     double t = 0.0;
  76.     double result = 0.0;
  77.     double adjust = 0.0;
  78.     double tempLength = length;
  79.     if (length < 3)
  80.     {
  81.         LDPoint rnd(p[0].GetCPoint());
  82.         adjust = p[0].DistFrom(p[3]) - rnd.DistFrom(p[3]); 
  83.         tempLength += adjust;
  84.     }
  85.     DoBezierPts(*this, 0.5, tempLength, t, result);
  86.     length -= static_cast<int>(result - adjust + 0.5);
  87.     return t;
  88. }
  89. double LBezier::TAtLength(double& length, double error) const
  90. {
  91.     double t = 0.0;
  92.     double result = 0.0;
  93.     double adjust = 0.0;
  94.     double tempLength = length;
  95.     if (length < 3.0)
  96.     {
  97.         LDPoint rnd(p[0].GetCPoint());
  98.         adjust = p[0].DistFrom(p[3]) - rnd.DistFrom(p[3]); 
  99.         tempLength += adjust;
  100.     }
  101.     DoBezierPts(*this, 0.5, tempLength, t, result);
  102.     length -= static_cast<int>(result - adjust + 0.5);
  103.     return t;
  104. }
  105. // Create points to simulate ellipse using beziers
  106. void EllipseToBezier(CRect& r, CPoint* cCtlPt)
  107. {
  108.     const double EToBConst = 0.2761423749154; 
  109.     //  2/3*(sqrt(2)-1) 
  110.     // error = +0.027%  - 0.0%
  111.     CSize offset((int)(r.Width() * EToBConst), (int)(r.Height() * EToBConst));
  112.     CPoint centre((r.left + r.right) / 2, (r.top + r.bottom) / 2);
  113.     cCtlPt[0].x  =                                      //------------------------/
  114.     cCtlPt[1].x  =                                      //                        /
  115.     cCtlPt[11].x =                                      //        2___3___4       /
  116.     cCtlPt[12].x = r.left;                              //     1             5    /
  117.     cCtlPt[5].x  =                                      //     |             |    /
  118.     cCtlPt[6].x  =                                      //     |             |    /
  119.     cCtlPt[7].x  = r.right;                             //     0,12          6    /
  120.     cCtlPt[2].x  =                                      //     |             |    /
  121.     cCtlPt[10].x = centre.x - offset.cx;                //     |             |    /
  122.     cCtlPt[4].x  =                                      //    11             7    /
  123.     cCtlPt[8].x  = centre.x + offset.cx;                //       10___9___8       /
  124.     cCtlPt[3].x  =                                      //                        /
  125.     cCtlPt[9].x  = centre.x;                            //------------------------*
  126.     cCtlPt[2].y  =
  127.     cCtlPt[3].y  =
  128.     cCtlPt[4].y  = r.top;
  129.     cCtlPt[8].y  =
  130.     cCtlPt[9].y  =
  131.     cCtlPt[10].y = r.bottom;
  132.     cCtlPt[7].y  =
  133.     cCtlPt[11].y = centre.y + offset.cy;
  134.     cCtlPt[1].y  =
  135.     cCtlPt[5].y  = centre.y - offset.cy;
  136.     cCtlPt[0].y  =
  137.     cCtlPt[12].y =
  138.     cCtlPt[6].y  = centre.y;
  139. }
  140. namespace
  141. {
  142. static int recurse = 0;
  143. void DoBezierPts(const LBezier& V, double error, double& len, double& t, double& result)
  144. {
  145. //  TRACE0("BezierPtsrn");
  146.     if (len == 0.0)
  147.     {   
  148.         TRACE0("!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!");
  149.         return;
  150.     }
  151.     // control polygon length
  152.     double controlPolygonLen = 0.0;
  153.     for (int i = 0; i <= 2; i++)
  154.         controlPolygonLen += V.p[i].DistFrom(V.p[i+1]);
  155.     // chord length
  156.     double chordLen = V.p[0].DistFrom(V.p[3]);
  157.     // call self recursively until accurate enough
  158.     if(controlPolygonLen - chordLen > error || 
  159.         controlPolygonLen + result > len + error)
  160.     {
  161.         // split in two
  162.         LBezier left, right;
  163.         V.Split(left, right);
  164.         // add left and right sides
  165.         ++recurse;
  166.         DoBezierPts(left, error, len, t, result);
  167.         if (len == 0.0l)
  168.         {
  169.             --recurse;
  170.             return;
  171.         }
  172.         DoBezierPts(right, error, len, t, result);
  173.         --recurse;
  174.         return;
  175.     }
  176.     result  += controlPolygonLen;
  177.     t       += 1.0 / (1 << recurse);
  178. //  TRACE3("recurse=%4.d, length =%.5g, result = %.5grn", recurse, controlPolygonLen, result);
  179.     if (fabs(result - len)<=error)
  180.     {
  181. //      TRACE0("tfinished!!rn");
  182.         len = 0.0l;
  183.         return;
  184.     }
  185. }
  186. };