home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / src / ogl / misc.cpp < prev    next >
C/C++ Source or Header  |  2002-03-16  |  22KB  |  868 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        misc.cpp
  3. // Purpose:     Miscellaneous OGL support functions
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: misc.cpp,v 1.5 2002/03/15 20:50:40 RD Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "misc.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include <wx/wx.h>
  25. #endif
  26.  
  27. #include <wx/wxexpr.h>
  28.  
  29. #include <wx/types.h>
  30.  
  31. #ifdef new
  32. #undef new
  33. #endif
  34.  
  35. #if wxUSE_IOSTREAMH
  36. #include <iostream.h>
  37. #else
  38. #include <iostream>
  39. #endif
  40. #include <ctype.h>
  41. #include <math.h>
  42. #include <stdlib.h>
  43.  
  44. #include <wx/ogl/basic.h>
  45. #include <wx/ogl/basicp.h>
  46. #include <wx/ogl/misc.h>
  47. #include <wx/ogl/constrnt.h>
  48. #include <wx/ogl/composit.h>
  49.  
  50. wxFont*         g_oglNormalFont;
  51. wxPen*          g_oglBlackPen;
  52. wxPen*          g_oglTransparentPen;
  53. wxPen*          g_oglBlackForegroundPen;
  54. wxPen*          g_oglWhiteBackgroundPen;
  55. wxBrush*        g_oglWhiteBackgroundBrush;
  56.  
  57. char*           oglBuffer = NULL;
  58.  
  59. wxList          oglObjectCopyMapping(wxKEY_INTEGER);
  60.  
  61.  
  62.  
  63. void wxOGLInitialize()
  64. {
  65.   g_oglNormalFont = wxTheFontList->FindOrCreateFont(10, wxSWISS, wxNORMAL, wxNORMAL);
  66.   g_oglBlackPen = wxThePenList->FindOrCreatePen(wxT("BLACK"), 1, wxSOLID);
  67.   g_oglTransparentPen = wxThePenList->FindOrCreatePen(wxT("WHITE"), 1, wxTRANSPARENT);
  68.   g_oglBlackForegroundPen = wxThePenList->FindOrCreatePen(wxT("BLACK"), 1, wxSOLID);
  69.   g_oglWhiteBackgroundPen = wxThePenList->FindOrCreatePen(wxT("WHITE"), 1, wxSOLID);
  70.   g_oglWhiteBackgroundBrush = wxTheBrushList->FindOrCreateBrush(wxT("WHITE"), wxSOLID);
  71.  
  72.   OGLInitializeConstraintTypes();
  73.  
  74.   // Initialize big buffer used when writing images
  75.   oglBuffer = new char[3000];
  76.  
  77. }
  78.  
  79. void wxOGLCleanUp()
  80. {
  81.     if (oglBuffer)
  82.     {
  83.         delete[] oglBuffer;
  84.         oglBuffer = NULL;
  85.     }
  86.     oglBuffer = NULL;
  87.  
  88.     g_oglNormalFont = NULL;             // These will be cleaned up by their GDI list
  89.     g_oglBlackPen = NULL;
  90.     g_oglTransparentPen = NULL;
  91.     g_oglBlackForegroundPen = NULL;
  92.     g_oglWhiteBackgroundPen = NULL;
  93.     g_oglWhiteBackgroundBrush = NULL;
  94.  
  95.     OGLCleanUpConstraintTypes();
  96. }
  97.  
  98. wxFont *oglMatchFont(int point_size)
  99. {
  100.   wxFont *font = wxTheFontList->FindOrCreateFont(point_size, wxSWISS, wxNORMAL, wxNORMAL);
  101. #if 0
  102.   switch (point_size)
  103.   {
  104.     case 4:
  105.       font = swiss_font_4;
  106.       break;
  107.     case 6:
  108.       font = swiss_font_6;
  109.       break;
  110.     case 8:
  111.       font = swiss_font_8;
  112.       break;
  113.     case 12:
  114.       font = swiss_font_12;
  115.       break;
  116.     case 14:
  117.       font = swiss_font_14;
  118.       break;
  119.     case 18:
  120.       font = swiss_font_18;
  121.       break;
  122.     case 24:
  123.       font = swiss_font_24;
  124.       break;
  125.     default:
  126.     case 10:
  127.       font = swiss_font_10;
  128.       break;
  129.   }
  130. #endif
  131.   return font;
  132. }
  133.  
  134. int FontSizeDialog(wxFrame *parent, int old_size)
  135. {
  136.   if (old_size <= 0)
  137.     old_size = 10;
  138.   wxString buf;
  139.   buf << old_size;
  140.   wxString ans = wxGetTextFromUser(wxT("Enter point size"), wxT("Font size"), buf, parent);
  141.   if (ans.Length() == 0)
  142.     return 0;
  143.  
  144.   long new_size = 0;
  145.   ans.ToLong(&new_size);
  146.   if ((new_size <= 0) || (new_size > 40))
  147.   {
  148.     wxMessageBox(wxT("Invalid point size!"), wxT("Error"), wxOK);
  149.     return 0;
  150.   }
  151.   return new_size;
  152. /*
  153.   char *strings[8];
  154.   strings[0] = "4";
  155.   strings[1] = "6";
  156.   strings[2] = "8";
  157.   strings[3] = "10";
  158.   strings[4] = "12";
  159.   strings[5] = "14";
  160.   strings[6] = "18";
  161.   strings[7] = "24";
  162.   char *ans = wxGetSingleChoice("Choose", "Choose a font size", 8, strings, parent);
  163.   if (ans)
  164.   {
  165.     int size;
  166.     sscanf(ans, "%d", &size);
  167.     return oglMatchFont(size);
  168.   }
  169.   else return NULL;
  170. */
  171. }
  172.  
  173. // Centre a list of strings in the given box. xOffset and yOffset are the
  174. // the positions that these lines should be relative to, and this might be
  175. // the same as m_xpos, m_ypos, but might be zero if formatting from left-justifying.
  176. void oglCentreText(wxDC& dc, wxList *text_list,
  177.                 double m_xpos, double m_ypos, double width, double height,
  178.                 int formatMode)
  179. {
  180.   int n = text_list->Number();
  181.  
  182.   if (!text_list || (n == 0))
  183.     return;
  184.  
  185.   // First, get maximum dimensions of box enclosing text
  186.  
  187.   long char_height = 0;
  188.   long max_width = 0;
  189.   long current_width = 0;
  190.  
  191.   // Store text extents for speed
  192.   double *widths = new double[n];
  193.  
  194.   wxNode *current = text_list->First();
  195.   int i = 0;
  196.   while (current)
  197.   {
  198.     wxShapeTextLine *line = (wxShapeTextLine *)current->Data();
  199.     dc.GetTextExtent(line->GetText(), ¤t_width, &char_height);
  200.     widths[i] = current_width;
  201.  
  202.     if (current_width > max_width)
  203.       max_width = current_width;
  204.     current = current->Next();
  205.     i ++;
  206.   }
  207.  
  208.   double max_height = n*char_height;
  209.  
  210.   double xoffset, yoffset, xOffset, yOffset;
  211.  
  212.   if (formatMode & FORMAT_CENTRE_VERT)
  213.   {
  214.     if (max_height < height)
  215.       yoffset = (double)(m_ypos - (height/2.0) + (height - max_height)/2.0);
  216.     else
  217.       yoffset = (double)(m_ypos - (height/2.0));
  218.     yOffset = m_ypos;
  219.   }
  220.   else
  221.   {
  222.     yoffset = 0.0;
  223.     yOffset = 0.0;
  224.   }
  225.  
  226.   if (formatMode & FORMAT_CENTRE_HORIZ)
  227.   {
  228.     xoffset = (double)(m_xpos - width/2.0);
  229.     xOffset = m_xpos;
  230.   }
  231.   else
  232.   {
  233.     xoffset = 0.0;
  234.     xOffset = 0.0;
  235.   }
  236.  
  237.   current = text_list->First();
  238.   i = 0;
  239.  
  240.   while (current)
  241.   {
  242.     wxShapeTextLine *line = (wxShapeTextLine *)current->Data();
  243.  
  244.     double x;
  245.     if ((formatMode & FORMAT_CENTRE_HORIZ) && (widths[i] < width))
  246.       x = (double)((width - widths[i])/2.0 + xoffset);
  247.     else
  248.       x = xoffset;
  249.     double y = (double)(i*char_height + yoffset);
  250.  
  251.     line->SetX( x - xOffset ); line->SetY( y - yOffset );
  252.     current = current->Next();
  253.     i ++;
  254.   }
  255.  
  256.   delete widths;
  257. }
  258.  
  259. // Centre a list of strings in the given box
  260. void oglCentreTextNoClipping(wxDC& dc, wxList *text_list,
  261.                               double m_xpos, double m_ypos, double width, double height)
  262. {
  263.   int n = text_list->Number();
  264.  
  265.   if (!text_list || (n == 0))
  266.     return;
  267.  
  268.   // First, get maximum dimensions of box enclosing text
  269.  
  270.   long char_height = 0;
  271.   long max_width = 0;
  272.   long current_width = 0;
  273.  
  274.   // Store text extents for speed
  275.   double *widths = new double[n];
  276.  
  277.   wxNode *current = text_list->First();
  278.   int i = 0;
  279.   while (current)
  280.   {
  281.     wxShapeTextLine *line = (wxShapeTextLine *)current->Data();
  282.     dc.GetTextExtent(line->GetText(), ¤t_width, &char_height);
  283.     widths[i] = current_width;
  284.  
  285.     if (current_width > max_width)
  286.       max_width = current_width;
  287.     current = current->Next();
  288.     i ++;
  289.   }
  290.  
  291.   double max_height = n*char_height;
  292.  
  293.   double yoffset = (double)(m_ypos - (height/2.0) + (height - max_height)/2.0);
  294.  
  295.   double xoffset = (double)(m_xpos - width/2.0);
  296.  
  297.   current = text_list->First();
  298.   i = 0;
  299.  
  300.   while (current)
  301.   {
  302.     wxShapeTextLine *line = (wxShapeTextLine *)current->Data();
  303.  
  304.     double x = (double)((width - widths[i])/2.0 + xoffset);
  305.     double y = (double)(i*char_height + yoffset);
  306.  
  307.     line->SetX( x - m_xpos ); line->SetY( y - m_ypos );
  308.     current = current->Next();
  309.     i ++;
  310.   }
  311.   delete widths;
  312. }
  313.  
  314. void oglGetCentredTextExtent(wxDC& dc, wxList *text_list,
  315.                               double m_xpos, double m_ypos, double width, double height,
  316.                               double *actual_width, double *actual_height)
  317. {
  318.   int n = text_list->Number();
  319.  
  320.   if (!text_list || (n == 0))
  321.   {
  322.     *actual_width = 0;
  323.     *actual_height = 0;
  324.     return;
  325.   }
  326.  
  327.   // First, get maximum dimensions of box enclosing text
  328.  
  329.   long char_height = 0;
  330.   long max_width = 0;
  331.   long current_width = 0;
  332.  
  333.   wxNode *current = text_list->First();
  334.   int i = 0;
  335.   while (current)
  336.   {
  337.     wxShapeTextLine *line = (wxShapeTextLine *)current->Data();
  338.     dc.GetTextExtent(line->GetText(), ¤t_width, &char_height);
  339.  
  340.     if (current_width > max_width)
  341.       max_width = current_width;
  342.     current = current->Next();
  343.     i ++;
  344.   }
  345.  
  346.   *actual_height = n*char_height;
  347.   *actual_width = max_width;
  348. }
  349.  
  350. // Format a string to a list of strings that fit in the given box.
  351. // Interpret %n and 10 or 13 as a new line.
  352. wxStringList *oglFormatText(wxDC& dc, const wxString& text, double width, double height, int formatMode)
  353. {
  354.   // First, parse the string into a list of words
  355.   wxStringList word_list;
  356.  
  357.   // Make new lines into NULL strings at this point
  358.   int i = 0; int j = 0; int len = text.Length();
  359.   wxChar word[200]; word[0] = 0;
  360.   bool end_word = FALSE; bool new_line = FALSE;
  361.   while (i < len)
  362.   {
  363.     switch (text[i])
  364.     {
  365.       case wxT('%'):
  366.       {
  367.         i ++;
  368.         if (i == len)
  369.         { word[j] = wxT('%'); j ++; }
  370.         else
  371.         {
  372.           if (text[i] == wxT('n'))
  373.           { new_line = TRUE; end_word = TRUE; i++; }
  374.           else
  375.           { word[j] = wxT('%'); j ++; word[j] = text[i]; j ++; i ++; }
  376.         }
  377.         break;
  378.       }
  379.       case 10:
  380.       {
  381.         new_line = TRUE; end_word = TRUE; i++;
  382.         break;
  383.       }
  384.       case 13:
  385.       {
  386.         new_line = TRUE; end_word = TRUE; i++;
  387.       }
  388.       case wxT(' '):
  389.       {
  390.         end_word = TRUE;
  391.         i ++;
  392.         break;
  393.       }
  394.       default:
  395.       {
  396.         word[j] = text[i];
  397.         j ++; i ++;
  398.         break;
  399.       }
  400.     }
  401.     if (i == len) end_word = TRUE;
  402.     if (end_word)
  403.     {
  404.       word[j] = 0;
  405.       j = 0;
  406.       word_list.Add(word);
  407.       end_word = FALSE;
  408.     }
  409.     if (new_line)
  410.     {
  411.       word_list.Append(NULL);
  412.       new_line = FALSE;
  413.     }
  414.   }
  415.   // Now, make a list of strings which can fit in the box
  416.   wxStringList *string_list = new wxStringList;
  417.  
  418.   wxString buffer;
  419.   wxNode *node = word_list.First();
  420.   long x, y;
  421.  
  422.   while (node)
  423.   {
  424.     wxString oldBuffer(buffer);
  425.  
  426.     char *s = (char *)node->Data();
  427.     if (!s)
  428.     {
  429.       // FORCE NEW LINE
  430.       if (buffer.Length() > 0)
  431.         string_list->Add(buffer);
  432.  
  433.       buffer.Empty();
  434.     }
  435.     else
  436.     {
  437.       if (buffer.Length() != 0)
  438.         buffer += " ";
  439.  
  440.       buffer += s;
  441.       dc.GetTextExtent(buffer, &x, &y);
  442.  
  443.       // Don't fit within the bounding box if we're fitting shape to contents
  444.       if ((x > width) && !(formatMode & FORMAT_SIZE_TO_CONTENTS))
  445.       {
  446.         // Deal with first word being wider than box
  447.         if (oldBuffer.Length() > 0)
  448.           string_list->Add(oldBuffer);
  449.  
  450.         buffer.Empty();
  451.         buffer += s;
  452.       }
  453.     }
  454.  
  455.     node = node->Next();
  456.   }
  457.   if (buffer.Length() != 0)
  458.     string_list->Add(buffer);
  459.  
  460.   return string_list;
  461. }
  462.  
  463. void oglDrawFormattedText(wxDC& dc, wxList *text_list,
  464.                        double m_xpos, double m_ypos, double width, double height,
  465.                        int formatMode)
  466. {
  467.   double xoffset, yoffset;
  468.   if (formatMode & FORMAT_CENTRE_HORIZ)
  469.     xoffset = m_xpos;
  470.   else
  471.     xoffset = (double)(m_xpos - (width / 2.0));
  472.  
  473.   if (formatMode & FORMAT_CENTRE_VERT)
  474.     yoffset = m_ypos;
  475.   else
  476.     yoffset = (double)(m_ypos - (height / 2.0));
  477.  
  478.   dc.SetClippingRegion(
  479.                     (long)(m_xpos - width/2.0), (long)(m_ypos - height/2.0),
  480.                     (long)width, (long)height);
  481.  
  482.   wxNode *current = text_list->First();
  483.   while (current)
  484.   {
  485.     wxShapeTextLine *line = (wxShapeTextLine *)current->Data();
  486.  
  487.     dc.DrawText(line->GetText(), WXROUND(xoffset + line->GetX()), WXROUND(yoffset + line->GetY()));
  488.     current = current->Next();
  489.   }
  490.  
  491.   dc.DestroyClippingRegion();
  492. }
  493.  
  494. /*
  495.  * Find centroid given list of points comprising polyline
  496.  *
  497.  */
  498.  
  499. void oglFindPolylineCentroid(wxList *points, double *x, double *y)
  500. {
  501.   double xcount = 0;
  502.   double ycount = 0;
  503.  
  504.   wxNode *node = points->First();
  505.   while (node)
  506.   {
  507.     wxRealPoint *point = (wxRealPoint *)node->Data();
  508.     xcount += point->x;
  509.     ycount += point->y;
  510.     node = node->Next();
  511.   }
  512.  
  513.   *x = (xcount/points->Number());
  514.   *y = (ycount/points->Number());
  515. }
  516.  
  517. /*
  518.  * Check that (x1, y1) -> (x2, y2) hits (x3, y3) -> (x4, y4).
  519.  * If so, ratio1 gives the proportion along the first line
  520.  * that the intersection occurs (or something like that).
  521.  * Used by functions below.
  522.  *
  523.  */
  524. void oglCheckLineIntersection(double x1, double y1, double x2, double y2,
  525.                              double x3, double y3, double x4, double y4,
  526.                              double *ratio1, double *ratio2)
  527. {
  528.   double denominator_term = (y4 - y3)*(x2 - x1) - (y2 - y1)*(x4 - x3);
  529.   double numerator_term = (x3 - x1)*(y4 - y3) + (x4 - x3)*(y1 - y3);
  530.  
  531.   double line_constant;
  532.   double length_ratio = 1.0;
  533.   double k_line = 1.0;
  534.  
  535.   // Check for parallel lines
  536.   if ((denominator_term < 0.005) && (denominator_term > -0.005))
  537.     line_constant = -1.0;
  538.   else
  539.     line_constant = numerator_term/denominator_term;
  540.  
  541.   // Check for intersection
  542.   if ((line_constant < 1.0) && (line_constant > 0.0))
  543.   {
  544.     // Now must check that other line hits
  545.     if (((y4 - y3) < 0.005) && ((y4 - y3) > -0.005))
  546.       k_line = ((x1 - x3) + line_constant*(x2 - x1))/(x4 - x3);
  547.     else
  548.       k_line = ((y1 - y3) + line_constant*(y2 - y1))/(y4 - y3);
  549.  
  550.     if ((k_line >= 0.0) && (k_line < 1.0))
  551.       length_ratio = line_constant;
  552.     else
  553.       k_line = 1.0;
  554.   }
  555.   *ratio1 = length_ratio;
  556.   *ratio2 = k_line;
  557. }
  558.  
  559. /*
  560.  * Find where (x1, y1) -> (x2, y2) hits one of the lines in xvec, yvec.
  561.  * (*x3, *y3) is the point where it hits.
  562.  *
  563.  */
  564. void oglFindEndForPolyline(double n, double xvec[], double yvec[],
  565.                            double x1, double y1, double x2, double y2, double *x3, double *y3)
  566. {
  567.   int i;
  568.   double lastx = xvec[0];
  569.   double lasty = yvec[0];
  570.  
  571.   double min_ratio = 1.0;
  572.   double line_ratio;
  573.   double other_ratio;
  574.  
  575.   for (i = 1; i < n; i++)
  576.   {
  577.     oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i],
  578.                             &line_ratio, &other_ratio);
  579.     lastx = xvec[i];
  580.     lasty = yvec[i];
  581.  
  582.     if (line_ratio < min_ratio)
  583.       min_ratio = line_ratio;
  584.   }
  585.  
  586.   // Do last (implicit) line if last and first doubles are not identical
  587.   if (!(xvec[0] == lastx && yvec[0] == lasty))
  588.   {
  589.     oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0],
  590.                             &line_ratio, &other_ratio);
  591.  
  592.     if (line_ratio < min_ratio)
  593.       min_ratio = line_ratio;
  594.   }
  595.  
  596.   *x3 = (x1 + (x2 - x1)*min_ratio);
  597.   *y3 = (y1 + (y2 - y1)*min_ratio);
  598.  
  599. }
  600.  
  601. /*
  602.  * Find where the line hits the box.
  603.  *
  604.  */
  605.  
  606. void oglFindEndForBox(double width, double height,
  607.                       double x1, double y1,         // Centre of box (possibly)
  608.                       double x2, double y2,         // other end of line
  609.                       double *x3, double *y3)       // End on box edge
  610. {
  611.   double xvec[5];
  612.   double yvec[5];
  613.  
  614.   xvec[0] = (double)(x1 - width/2.0);
  615.   yvec[0] = (double)(y1 - height/2.0);
  616.   xvec[1] = (double)(x1 - width/2.0);
  617.   yvec[1] = (double)(y1 + height/2.0);
  618.   xvec[2] = (double)(x1 + width/2.0);
  619.   yvec[2] = (double)(y1 + height/2.0);
  620.   xvec[3] = (double)(x1 + width/2.0);
  621.   yvec[3] = (double)(y1 - height/2.0);
  622.   xvec[4] = (double)(x1 - width/2.0);
  623.   yvec[4] = (double)(y1 - height/2.0);
  624.  
  625.   oglFindEndForPolyline(5, xvec, yvec, x2, y2, x1, y1, x3, y3);
  626. }
  627.  
  628. /*
  629.  * Find where the line hits the circle.
  630.  *
  631.  */
  632.  
  633. void oglFindEndForCircle(double radius,
  634.                          double x1, double y1,  // Centre of circle
  635.                          double x2, double y2,  // Other end of line
  636.                          double *x3, double *y3)
  637. {
  638.   double H = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
  639.  
  640.   if (H == 0.0)
  641.   {
  642.     *x3 = x1;
  643.     *y3 = y1;
  644.   }
  645.   else
  646.   {
  647.    *y3 = radius * (y2 - y1)/H + y1;
  648.    *x3 = radius * (x2 - x1)/H + x1;
  649.   }
  650. }
  651.  
  652. /*
  653.  * Given the line (x1, y1) -> (x2, y2), and an arrow size of given length and width,
  654.  * return the position of the tip of the arrow and the left and right vertices of the arrow.
  655.  *
  656.  */
  657.  
  658. void oglGetArrowPoints(double x1, double y1, double x2, double y2,
  659.                       double length, double width,
  660.                       double *tip_x, double *tip_y,
  661.                       double *side1_x, double *side1_y,
  662.                       double *side2_x, double *side2_y)
  663. {
  664.   double l = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
  665.  
  666.   if (l < 0.01)
  667.     l = (double) 0.01;
  668.  
  669.   double i_bar = (x2 - x1)/l;
  670.   double j_bar = (y2 - y1)/l;
  671.  
  672.   double x3 = (- length*i_bar) + x2;
  673.   double y3 = (- length*j_bar) + y2;
  674.  
  675.   *side1_x = width*(-j_bar) + x3;
  676.   *side1_y = width*i_bar + y3;
  677.  
  678.   *side2_x = -width*(-j_bar) + x3;
  679.   *side2_y = -width*i_bar + y3;
  680.  
  681.   *tip_x = x2; *tip_y = y2;
  682. }
  683.  
  684. /*
  685.  * Given an ellipse and endpoints of a line, returns the point at which
  686.  * the line touches the ellipse in values x4, y4.
  687.  * This function assumes that the centre of the ellipse is at x1, y1, and the
  688.  * ellipse has a width of width1 and a height of height1. It also assumes you are
  689.  * wanting to draw an arc FROM point x2, y2 TOWARDS point x3, y3.
  690.  * This function calculates the x,y coordinates of the intersection point of
  691.  * the arc with the ellipse.
  692.  * Author: Ian Harrison
  693.  */
  694.  
  695. void oglDrawArcToEllipse(double x1, double y1, double width1, double height1, double x2, double y2, double x3, double y3,
  696.   double *x4, double *y4)
  697. {
  698.   double a1 = (double)(width1/2.0);
  699.   double b1 = (double)(height1/2.0);
  700.  
  701.   // These are required to give top left x and y coordinates for DrawEllipse
  702. //  double top_left_x1 = (double)(x1 - a1);
  703. //  double top_left_y1 = (double)(y1 - b1);
  704. /*
  705.   // Check for vertical line
  706.   if (fabs(x2 - x3) < 0.05)
  707.   {
  708.     *x4 = x3;
  709.     if (y2 < y3)
  710.       *y4 = (double)(y1 - b1);
  711.     else
  712.       *y4 = (double)(y1 + b1);
  713.     return;
  714.   }
  715. */
  716.   // Check that x2 != x3
  717.   if (fabs(x2 - x3) < 0.05)
  718.   {
  719.     *x4 = x2;
  720.     if (y3 > y2)
  721.       *y4 = (double)(y1 - sqrt((b1*b1 - (((x2-x1)*(x2-x1))*(b1*b1)/(a1*a1)))));
  722.     else
  723.       *y4 = (double)(y1 + sqrt((b1*b1 - (((x2-x1)*(x2-x1))*(b1*b1)/(a1*a1)))));
  724.     return;
  725.   }
  726.  
  727.   // Calculate the x and y coordinates of the point where arc intersects ellipse
  728.  
  729.   double A, B, C, D, E, F, G, H, K;
  730.   double ellipse1_x, ellipse1_y;
  731.  
  732.   A = (double)(1/(a1 * a1));
  733.   B = (double)((y3 - y2) * (y3 - y2)) / ((x3 - x2) * (x3 - x2) * b1 * b1);
  734.   C = (double)(2 * (y3 - y2) * (y2 - y1)) / ((x3 - x2) * b1 * b1);
  735.   D = (double)((y2 - y1) * (y2 - y1)) / (b1 * b1);
  736.   E = (double)(A + B);
  737.   F = (double)(C - (2 * A * x1) - (2 * B * x2));
  738.   G = (double)((A * x1 * x1) + (B * x2 * x2) - (C * x2) + D - 1);
  739.   H = (double)((y3 - y2) / (x3 - x2));
  740.   K = (double)((F * F) - (4 * E * G));
  741.  
  742.   if (K >= 0)
  743.   // In this case the line intersects the ellipse, so calculate intersection
  744.   {
  745.     if(x2 >= x1)
  746.     {
  747.       ellipse1_x = (double)(((F * -1) + sqrt(K)) / (2 * E));
  748.       ellipse1_y = (double)((H * (ellipse1_x - x2)) + y2);
  749.     }
  750.     else
  751.     {
  752.       ellipse1_x = (double)(((F * -1) -  sqrt(K)) / (2 * E));
  753.       ellipse1_y = (double)((H * (ellipse1_x - x2)) + y2);
  754.     }
  755.   }
  756.   else
  757.   // in this case, arc does not intersect ellipse, so just draw arc
  758.   {
  759.     ellipse1_x = x3;
  760.     ellipse1_y = y3;
  761.   }
  762.   *x4 = ellipse1_x;
  763.   *y4 = ellipse1_y;
  764.  
  765. /*
  766.   // Draw a little circle (radius = 2) at the end of the arc where it hits
  767.   // the ellipse .
  768.  
  769.   double circle_x = ellipse1_x - 2.0;
  770.   double circle_y = ellipse1_y - 2.0;
  771.   m_canvas->DrawEllipse(circle_x, circle_y, 4.0, 4.0);
  772. */
  773. }
  774.  
  775. // Update a list item from a list of strings
  776. void UpdateListBox(wxListBox *item, wxList *list)
  777. {
  778.   item->Clear();
  779.   if (!list)
  780.     return;
  781.  
  782.   wxNode *node = list->First();
  783.   while (node)
  784.   {
  785.     char *s = (char *)node->Data();
  786.     item->Append(s);
  787.     node = node->Next();
  788.   }
  789. }
  790.  
  791. bool oglRoughlyEqual(double val1, double val2, double tol)
  792. {
  793.     return ( (val1 < (val2 + tol)) && (val1 > (val2 - tol)) &&
  794.              (val2 < (val1 + tol)) && (val2 > (val1 - tol)));
  795. }
  796.  
  797. /*
  798.  * Hex<->Dec conversion
  799.  */
  800.  
  801. // Array used in DecToHex conversion routine.
  802. static wxChar sg_HexArray[] = { wxT('0'), wxT('1'), wxT('2'), wxT('3'),
  803.                                 wxT('4'), wxT('5'), wxT('6'), wxT('7'),
  804.                                 wxT('8'), wxT('9'), wxT('A'), wxT('B'),
  805.                                 wxT('C'), wxT('D'), wxT('E'), wxT('F')
  806. };
  807.  
  808. // Convert 2-digit hex number to decimal
  809. unsigned int oglHexToDec(wxChar* buf)
  810. {
  811.   int firstDigit, secondDigit;
  812.  
  813.   if (buf[0] >= wxT('A'))
  814.     firstDigit = buf[0] - wxT('A') + 10;
  815.   else
  816.     firstDigit = buf[0] - wxT('0');
  817.  
  818.   if (buf[1] >= wxT('A'))
  819.     secondDigit = buf[1] - wxT('A') + 10;
  820.   else
  821.     secondDigit = buf[1] - wxT('0');
  822.  
  823.   return firstDigit * 16 + secondDigit;
  824. }
  825.  
  826. // Convert decimal integer to 2-character hex string
  827. void oglDecToHex(unsigned int dec, wxChar *buf)
  828. {
  829.     int firstDigit = (int)(dec/16.0);
  830.     int secondDigit = (int)(dec - (firstDigit*16.0));
  831.     buf[0] = sg_HexArray[firstDigit];
  832.     buf[1] = sg_HexArray[secondDigit];
  833.     buf[2] = 0;
  834. }
  835.  
  836. // 3-digit hex to wxColour
  837. wxColour oglHexToColour(const wxString& hex)
  838. {
  839.     if (hex.Length() == 6)
  840.     {
  841.         long r, g, b;
  842.         r = g = b = 0;
  843.         hex.Mid(0,2).ToLong(&r, 16);
  844.         hex.Mid(2,2).ToLong(&g, 16);
  845.         hex.Mid(4,2).ToLong(&b, 16);
  846.         return wxColour(r, g, b);
  847.     }
  848.     else
  849.         return wxColour(0,0,0);
  850. }
  851.  
  852. // RGB to 3-digit hex
  853. wxString oglColourToHex(const wxColour& colour)
  854. {
  855.     wxChar buf[7];
  856.     unsigned int red = colour.Red();
  857.     unsigned int green = colour.Green();
  858.     unsigned int blue = colour.Blue();
  859.  
  860.     oglDecToHex(red, buf);
  861.     oglDecToHex(green, buf+2);
  862.     oglDecToHex(blue, buf+4);
  863.  
  864.     return wxString(buf);
  865. }
  866.  
  867.  
  868.