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