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