home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / DASHED.ZIP / LINE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1998-11-29  |  5.7 KB  |  284 lines

  1. // Line.cpp : Defines the class behaviors for CDashLine
  2. //
  3. //    The Bresenham function in this file is derived from code from 
  4. //            Jean-Claude Lanz mailto:Jclanz@bluewin.ch
  5. //        and he presumably shares copyright to it
  6. //    Otherwise the copyright belongs to Llew S. Goodstadt 
  7. //        http://www.lg.ndirect.co.uk    mailto:lg@ndirect.co.uk
  8. //        who hereby grants you fair use and distribution rights of the code 
  9. //        in both commercial and non-commercial applications.
  10.  
  11. #include "stdafx.h"
  12. #include "Line.h"
  13. #include "bezier.h"
  14.  
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20.  
  21.  
  22.  
  23.  
  24. // define _TIMING to null out the GDI calls.
  25. //    i.e. you can find out what is the cost of the calculations
  26. //#define _TIMING 1
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // helper
  30.  
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CDashLine
  33.  
  34. CDashLine::CDashLine(CDC& dc, unsigned* pattern, unsigned count)
  35.     :m_DC(dc), m_Pattern(0)
  36. {
  37.     SetPattern(pattern, count);
  38. }
  39.  
  40. CDashLine::~CDashLine()
  41. {
  42.     // destroy GDI objects
  43.     delete[] m_Pattern;
  44. }
  45.  
  46. void CDashLine::SetPattern(unsigned* pattern, unsigned count)
  47. {
  48.     // Must be an even number of dash and gaps
  49.     ASSERT(m_Count >=0);
  50.     ASSERT(!(m_Count % 2));
  51.  
  52.     m_Count = count;
  53.     delete[] m_Pattern;
  54.     if (m_Count)
  55.     {
  56.         m_Pattern = new UINT[count];
  57.         memcpy(m_Pattern, pattern, count * sizeof(UINT));
  58.     }    
  59.     else
  60.         m_Pattern = 0;
  61.     Reset();
  62. }
  63.  
  64. void CDashLine::Reset()
  65. {
  66.     m_CurPat = 0;
  67.     if (m_Count)
  68.         m_CurStretch = m_Pattern[0];
  69. }
  70.  
  71. // use linear interpolation to compute next position
  72. void CDashLine::Bresenham(LONG x, LONG y)
  73. {
  74.  
  75.     // Setup Bresenham
  76.     LONG dx = x - m_CurPos.x;
  77.     LONG dy = y - m_CurPos.y;
  78.  
  79.     LONG *p1, *p2, *pd1, *pd2;
  80.     if (abs(dx) >= abs(dy))
  81.     {
  82.         p1 = &m_CurPos.x; 
  83.         p2 = &m_CurPos.y; 
  84.         pd1 = &dx; 
  85.         pd2 = &dy; 
  86.     }
  87.     else
  88.     {
  89.         p1 = &m_CurPos.y; 
  90.         p2 = &m_CurPos.x; 
  91.         pd1 = &dy; 
  92.         pd2 = &dx;
  93.     }
  94.  
  95.     int max = abs(*pd1);
  96.     int dec = abs(*pd2);
  97.     int s1 = (*pd1 >= 0) ? 1: -1;
  98.     int s2 = (*pd2 >= 0) ? 1: -1;
  99.     int val = max;
  100.  
  101.     // count past correct number of pixels in current segment
  102.     //         or until end of this line
  103.     for (int i = 0; i < max; i++)
  104.     {
  105.         val -= dec;
  106.         if (val <= 0) 
  107.         {    
  108.             *p2 += s2; 
  109.             val += max; 
  110.         }
  111.         *p1 += s1;
  112.  
  113.         --m_CurStretch;
  114.         if (!m_CurStretch)
  115.         {
  116.             // use next pattern for next segment
  117.             m_CurPat = (m_CurPat + 1) % m_Count;
  118.             m_CurStretch = m_Pattern[m_CurPat];
  119.  
  120.             // draw segment or skip gap
  121. #ifndef _TIMING
  122.             if (m_CurPat % 2)
  123.                 m_DC.LineTo(m_CurPos);
  124.             else
  125.                 m_DC.MoveTo(m_CurPos);
  126. #endif _TIMING
  127.  
  128.         
  129.             // if last point, return
  130.             if (i == max - 1) 
  131.                 return;
  132.         }
  133.     }
  134.  
  135.     // draw to last point if necessary
  136. #ifndef _TIMING
  137.     if (!(m_CurPat % 2))
  138.         m_DC.LineTo(m_CurPos);
  139. #endif _TIMING
  140. }
  141.  
  142. void CDashLine::MoveTo(int x, int y)
  143. {
  144.     // with MoveTo, reset parameters
  145.     Reset();
  146.  
  147.     // save current position
  148.     m_CurPos.x = x; 
  149.     m_CurPos.y = y;
  150.  
  151.     // move to position
  152.     m_DC.MoveTo(m_CurPos);
  153. }
  154.  
  155.  
  156. void CDashLine::LineTo(int x, int y)
  157. {
  158.     // line type and color
  159.     if (!m_Count)
  160.     {
  161.         m_DC.LineTo(x, y);
  162.         m_CurPos.x = x; m_CurPos.y = y;
  163.         return;
  164.     }
  165. #ifdef _TIMING
  166.     m_DC.LineTo(x, y);
  167. #endif _TIMING
  168.  
  169.     // calculate and draw next points
  170.     Bresenham(x, y);
  171. }
  172.  
  173.  
  174. // use linear interpolation to compute next position
  175. void CDashLine::BezierTo(POINT* dest)
  176. {
  177. #ifdef _TIMING
  178.     m_DC.PolyBezierTo(dest, 3);
  179. #endif _TIMING
  180.     if (!m_Count)
  181.     {
  182.         m_DC.PolyBezierTo(dest, 3);
  183.         m_CurPos = dest[2];
  184.         return;
  185.     }    
  186.  
  187.  
  188.     // Setup Bezier representing curve
  189.     LBezier currentBez;
  190.     currentBez.p[0] = m_CurPos;
  191.     for (int i = 0; i < 3; ++i)
  192.         currentBez.p[i+1] = dest[i];
  193.  
  194.     LBezier drawBezier;
  195.     CPoint Output[4];
  196.  
  197.     //for (int ii = 0; ii < 100; ++ii)
  198.     while(1)
  199.     {
  200.         // split off segment corresponding to current stretch, ie drawBezier
  201.         currentBez.TSplit(drawBezier, currentBez.TAtLength(m_CurStretch));
  202.         drawBezier.GetCPoint(Output);
  203.  
  204.         m_CurPos = Output[3];
  205.  
  206. #ifndef _TIMING
  207.         if (m_CurPat % 2)
  208.             m_DC.MoveTo(m_CurPos);
  209.         else
  210.             m_DC.PolyBezierTo(Output+1, 3);
  211. #endif _TIMING
  212.  
  213.         // break if some part of segment did not fit on bezier
  214.         if (!m_CurStretch)
  215.         {
  216.             // use next pattern for next segment
  217.             m_CurPat = (m_CurPat + 1) % m_Count;
  218.             m_CurStretch = m_Pattern[m_CurPat];
  219.         }    
  220.         else
  221.             break;        
  222.     }        
  223. }
  224.  
  225.  
  226. // Returns count of elements (dash/dot and gaps)
  227. // You must be careful to pass in enough memory for pattern
  228. // It is probably safest to always have an array of [8]
  229. unsigned CDashLine::GetPattern(unsigned* pattern, bool round, unsigned penSize, unsigned style)
  230. {
  231.     ASSERT(style <= DL_DASHDOTDOTDOT_GAP);
  232.     int gapLen    = round    ?    penSize * 2 : penSize;
  233.     int dotLen    = round    ?    1            : penSize;
  234.     int dashLen    = round    ?    penSize * 2 : penSize * 3;
  235.     if (style >= DL_DASH_GAP)
  236.         gapLen *= 2;
  237.     if (style == DL_SOLID)
  238.         return(0);
  239.     
  240.     switch (style)
  241.     {
  242.         case DL_DASH:
  243.         case DL_DASH_GAP:
  244.                 pattern[0] = dashLen;
  245.                 pattern[1] = gapLen;
  246.                 return 2;
  247.         case DL_DOT:
  248.         case DL_DOT_GAP:
  249.                 pattern[0] = dotLen;
  250.                 pattern[1] = gapLen;
  251.                 return 2;
  252.         case DL_DASHDOT:
  253.         case DL_DASHDOT_GAP:
  254.                 pattern[0] = dashLen;
  255.                 pattern[2] = dotLen;
  256.                 pattern[1] = 
  257.                 pattern[3] = gapLen;
  258.                 return 4;
  259.         case DL_DASHDOTDOT:
  260.         case DL_DASHDOTDOT_GAP:
  261.                 pattern[0] = dashLen;
  262.                 pattern[2] =
  263.                 pattern[4] = dotLen;
  264.                 pattern[1] =
  265.                 pattern[3] =
  266.                 pattern[5] = gapLen;
  267.                 return 6;
  268.         case DL_DASHDOTDOTDOT:
  269.         case DL_DASHDOTDOTDOT_GAP:
  270.         default:
  271.                 pattern[0] = dashLen;
  272.                 pattern[2] =
  273.                 pattern[4] = 
  274.                 pattern[6] = dotLen;
  275.                 pattern[1] =
  276.                 pattern[3] =
  277.                 pattern[5] = 
  278.                 pattern[7] = gapLen;
  279.                 return 8;
  280.         
  281.     }    
  282.         
  283. }    
  284.