home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / DASHED.ZIP / bezier.cpp next >
Encoding:
C/C++ Source or Header  |  1998-11-29  |  6.4 KB  |  213 lines

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