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