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