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