]> Shamusworld >> Repos - ttedit/blob - src/glyphpoints.cpp
Added rectangle point selection, canvas zooming.
[ttedit] / src / glyphpoints.cpp
1 //
2 // GLYPHPOINTS.CPP
3 //
4 // Class implementation. Nothing too inexplicable going on here. Fairly
5 // straightforward stuff.
6 //
7 // by James L. Hammons
8 // (C) 2004 Underground Software
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  ??/??/200?  Created this file
15 // JLH  05/18/2004  Added pure point adding, inserting, better polygon handling
16 //
17
18 // Uncomment this for debugging...
19 #define DEBUG
20
21 #include "glyphpoints.h"
22 #ifdef DEBUG
23 #include "debug.h"
24 #endif
25 #include <math.h>
26
27
28 /*GlyphPoints::GlyphPoints(void)
29 {
30         GlyphPoints(0, 0, NULL, NULL, NULL, NULL);
31 }*/
32
33 GlyphPoints::GlyphPoints(int nPts/*=0*/, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,
34         bool * oca/*=null*/, uint16_t * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
35 //GlyphPoints::GlyphPoints(int nPts, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,
36 //      bool * oca/*=null*/, uint16_t * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
37 {
38         AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);
39
40         if (nPlys == 0)
41         {
42                 numPolys = 1;
43                 polyEnd = new uint16_t[numPolys];
44                 polyEnd[0] = numPoints - 1;
45         }
46 #ifdef DEBUG
47 WriteLogMsg("GlyphPoints: Default constructor. %u points, %u polys.\n", numPoints, numPolys);
48 #endif
49 }
50
51
52 GlyphPoints::GlyphPoints(int xx, int yy, bool oc)
53 {
54 //Hmm. What to do with this...?
55         AllocateAndCopy(1, 0, &xx, &yy, &oc, NULL);
56 #ifdef DEBUG
57 WriteLogMsg("GlyphPoints: Single point constructor. %u points, %u polys.\n", numPoints, numPolys);
58 #endif
59 }
60
61
62 // Copy constructor (needed for deep copying)
63
64 //GlyphPoints::GlyphPoints(GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
65 GlyphPoints::GlyphPoints(const GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
66 {
67         *this = c;                                                                      // Use overloaded operator=
68 #ifdef DEBUG
69 WriteLogMsg("GlyphPoints: Copy constructor. %u points, %u polys.\n", numPoints, numPolys);
70 #endif
71 }
72
73
74 GlyphPoints::~GlyphPoints()
75 {
76         FreeAllocatedMemory();
77 #if 0
78         if (x)
79                 delete[] x;
80
81         if (y)
82                 delete[] y;
83
84         if (onCurve)
85                 delete[] onCurve;
86
87         if (polyEnd)
88                 delete[] polyEnd;
89 #endif
90 }
91
92
93 void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16_t * pa)
94 {
95         numPoints = nPts, numPolys = nPlys;
96
97         if (nPts)
98         {
99                 x = new int[numPoints];
100                 y = new int[numPoints];
101                 onCurve = new bool[numPoints];
102
103                 if (xa)                                                                 // Copy points in if they're passed in...
104                         for(int i=0; i<nPts; i++)
105                                 x[i] = xa[i];
106
107                 if (ya)
108                         for(int i=0; i<nPts; i++)
109                                 y[i] = ya[i];
110
111                 if (oca)
112                         for(int i=0; i<nPts; i++)
113                                 onCurve[i] = oca[i];
114         }
115
116         if (numPolys)
117         {
118                 polyEnd = new uint16_t[numPolys];
119
120                 if (pa)                                                                 // Copy poly ends in if they're passed in...
121                         for(int i=0; i<nPlys; i++)
122                                 polyEnd[i] = pa[i];
123         }
124 }
125
126
127 void GlyphPoints::FreeAllocatedMemory(void)
128 {
129         if (x)
130                 delete[] x;
131
132         if (y)
133                 delete[] y;
134
135         if (onCurve)
136                 delete[] onCurve;
137
138         if (polyEnd)
139                 delete[] polyEnd;
140 }
141
142
143 GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)
144 {
145         if (this == &c)
146                 return *this;                                                   // Take care of self-assignment
147
148         FreeAllocatedMemory();
149         AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);
150
151         return *this;
152 }
153
154
155 // Add another GlyphPoints' points to this one...
156
157 GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)
158 {
159         int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;
160
161         int * totX = new int[totPoints];
162         int * totY = new int[totPoints];
163         bool * totOnCurve = new bool[totPoints];
164         uint16_t * totPolyEnd = new uint16_t[totPolys];
165
166         for(int i=0; i<numPoints; i++)
167         {
168                 totX[i] = x[i];
169                 totY[i] = y[i];
170                 totOnCurve[i] = onCurve[i];
171         }
172
173         for(int i=0; i<numPolys; i++)
174                 totPolyEnd[i] = polyEnd[i];
175
176         for(int i=0; i<c.numPoints; i++)
177         {
178                 totX[numPoints+i] = c.x[i];
179                 totY[numPoints+i] = c.y[i];
180                 totOnCurve[numPoints+i] = c.onCurve[i];
181         }
182
183         for(int i=0; i<c.numPolys; i++)
184                 totPolyEnd[numPolys+i] = numPoints + c.polyEnd[i];  // Need to adjust the "added in"
185                                                         // poly's end points...
186
187         GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);
188         delete[] totX;
189         delete[] totY;
190         delete[] totOnCurve;
191         delete[] totPolyEnd;
192
193         return retVal;
194 }
195
196
197 // Add a point to this GlyphPoints...
198
199 GlyphPoints GlyphPoints::operator+(const IPoint &c)
200 {
201 //This is kinda silly. We can do better than this! !!! FIX !!!
202         int * totX = new int[numPoints + 1];
203         int * totY = new int[numPoints + 1];
204         bool * totOnCurve = new bool[numPoints + 1];
205         uint16_t * totPolyEnd = new uint16_t[numPolys];
206
207         for(int i=0; i<numPoints; i++)
208                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
209
210         totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;
211
212         for(int i=0; i<numPolys; i++)
213                 totPolyEnd[i] = polyEnd[i];
214
215         totPolyEnd[numPolys - 1]++;                                     // Bump polygon's end point
216         GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);
217
218         delete[] totX;
219         delete[] totY;
220         delete[] totOnCurve;
221
222         return retVal;
223 }
224
225
226 GlyphPoints& GlyphPoints::operator+=(const IPoint &p)
227 {
228         InsertPoint(numPoints, p.x, p.y, p.onCurve);
229
230         return *this;
231 }
232
233
234 void GlyphPoints::Clear(void)
235 {
236         FreeAllocatedMemory();
237         x = y = NULL;
238         onCurve = NULL;
239         polyEnd = NULL;
240         numPoints = numPolys = pointsAllocated = polysAllocated = 0;
241
242         numPolys = 1;
243         polyEnd = new uint16_t[numPolys];
244         polyEnd[0] = numPoints - 1;
245 }
246
247
248 void GlyphPoints::InsertPoint(uint16_t pt, int xx, int yy, bool oc)
249 {
250 //wouldn't it be better to treat this case as inserting at the end?
251         if (pt > numPoints)                                                     // > because we can insert at end...!
252                 throw GP_OUT_OF_RANGE;
253
254 //This is kinda silly. We can do better than this! !!! FIX !!!
255         int * totX = new int[numPoints + 1];
256         int * totY = new int[numPoints + 1];
257         bool * totOnCurve = new bool[numPoints + 1];
258
259         for(int i=0; i<pt; i++)
260                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
261
262         for(int i=pt; i<numPoints; i++)
263                 totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];
264
265         totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;
266
267 //A way to fix the kludge in GetPoly() would be to put a check here to see if
268 //we're adding to the end of the structure: [DONE, below]
269         int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt));
270         for(int i=polyInsert; i<numPolys; i++)
271                 polyEnd[i]++;                                                   // Bump polygons' end point
272
273         numPoints++;
274
275         delete[] x;
276         delete[] y;
277         delete[] onCurve;
278
279         x = totX, y = totY, onCurve = totOnCurve;
280 }
281
282
283 void GlyphPoints::InsertPoint(uint16_t pt, const IPoint &p)
284 {
285         InsertPoint(pt, p.x, p.y, p.onCurve);
286 }
287
288
289 //
290 // Delete a point from the glyph
291 // Note that we don't bother to reallocate anything here, just bump the
292 // size counters down as needed. In the future, we'll keep track so we
293 // don't have to reallocate *every* damn time a point is added...
294 //
295 void GlyphPoints::DeletePoint(uint16_t pt)
296 {
297         // Adjust polygon ends appropriately
298         uint16_t poly = GetPoly(pt);
299
300         for(int i=poly; i<numPolys; i++)
301                 polyEnd[i]--;
302
303 //Need to check here if we're deleting the last point in the glyph or not.
304 //!!! FIX !!! [DONE]
305         if (GetNumPoints(poly) == 0 && numPoints > 0)
306         {
307                 numPolys--;
308
309                 for(int i=poly; i<numPolys; i++)
310                         polyEnd[i] = polyEnd[i + 1];
311         }
312
313 //This causes a crash becuz GetPoly() uses numPoints... !!! FIX !!! [DONE by switching poly delete & point delete]
314         // Close up the gap left by the current point
315         numPoints--;
316
317         for(int i=pt; i<numPoints; i++)
318                 x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];
319 }
320
321
322 uint16_t GlyphPoints::GetNumPoints(void)
323 {
324         return numPoints;
325 }
326
327
328 uint16_t GlyphPoints::GetNumPoints(uint16_t poly)
329 {
330         if (poly >= numPolys)
331 #ifdef DEBUG
332 {
333 WriteLogMsg("Exception: GetNumPoints(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
334 #endif
335                 throw GP_OUT_OF_RANGE;
336 #ifdef DEBUG
337 }
338 #endif
339
340         return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);
341 }
342
343
344 uint16_t GlyphPoints::GetNumPolys(void)
345 {
346         return numPolys;
347 }
348
349
350 int GlyphPoints::GetX(uint16_t pt)
351 {
352         if (pt >= numPoints)
353 #ifdef DEBUG
354 {
355 WriteLogMsg("Exception: GetX(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
356 #endif
357                 throw GP_OUT_OF_RANGE;
358 #ifdef DEBUG
359 }
360 #endif
361
362         return x[pt];
363 }
364
365
366 int GlyphPoints::GetY(uint16_t pt)
367 {
368         if (pt >= numPoints)
369 #ifdef DEBUG
370 {
371 WriteLogMsg("Exception: GetY(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
372 #endif
373                 throw GP_OUT_OF_RANGE;
374 #ifdef DEBUG
375 }
376 #endif
377
378         return y[pt];
379 }
380
381
382 Vector GlyphPoints::GetXY(uint16_t pt)
383 {
384         if (pt >= numPoints)
385 #ifdef DEBUG
386 {
387 WriteLogMsg("Exception: GetXY(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
388 #endif
389                 throw GP_OUT_OF_RANGE;
390 #ifdef DEBUG
391 }
392 #endif
393
394         return Vector(x[pt], y[pt]);
395 }
396
397
398 bool GlyphPoints::GetOnCurve(uint16_t pt)
399 {
400         if (pt >= numPoints)
401 #ifdef DEBUG
402 {
403 WriteLogMsg("Exception: GetOnCurve(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
404 #endif
405                 throw GP_OUT_OF_RANGE;
406 #ifdef DEBUG
407 }
408 #endif
409
410         return onCurve[pt];
411 }
412
413
414 int GlyphPoints::GetX(uint16_t poly, uint16_t pt)
415 {
416         if (pt >= GetNumPoints(poly))
417 #ifdef DEBUG
418 {
419 WriteLogMsg("Exception: GetX(uint16_t, uint16_t). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
420 #endif
421                 throw GP_OUT_OF_RANGE;
422 #ifdef DEBUG
423 }
424 #endif
425
426         return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
427 }
428
429
430 int GlyphPoints::GetNextX(uint16_t poly, uint16_t pt)
431 {
432         return GetX(poly, GetNext(poly, pt));
433 }
434
435
436 int GlyphPoints::GetY(uint16_t poly, uint16_t pt)
437 {
438         if (pt >= GetNumPoints(poly))
439 #ifdef DEBUG
440 {
441 WriteLogMsg("Exception: GetY(uint16_t, uint16_t). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
442 #endif
443                 throw GP_OUT_OF_RANGE;
444 #ifdef DEBUG
445 }
446 #endif
447
448         return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
449 }
450
451
452 int GlyphPoints::GetNextY(uint16_t poly, uint16_t pt)
453 {
454         return GetY(poly, GetNext(poly, pt));
455 }
456
457
458 IPoint GlyphPoints::GetPoint(uint16_t poly, uint16_t pt)
459 {
460         return IPoint(GetX(poly, pt), GetY(poly, pt), GetOnCurve(poly, pt));
461 }
462
463
464 IPoint GlyphPoints::GetPoint(uint16_t pointNumber)
465 {
466         if (pointNumber > numPoints)
467                 throw GP_OUT_OF_RANGE;
468
469         return IPoint(x[pointNumber], y[pointNumber], onCurve[pointNumber]);
470 }
471
472
473 bool GlyphPoints::GetOnCurve(uint16_t poly, uint16_t pt)
474 {
475         if (pt >= GetNumPoints(poly))
476 #ifdef DEBUG
477 {
478 WriteLogMsg("Exception: GetOnCurve(uint16_t, uint16_t). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
479 #endif
480                 throw GP_OUT_OF_RANGE;
481 #ifdef DEBUG
482 }
483 #endif
484
485         return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
486 }
487
488
489 bool GlyphPoints::GetPrevOnCurve(uint16_t poly, uint16_t pt)
490 {
491         return GetOnCurve(poly, GetPrev(poly, pt));
492 }
493
494
495 bool GlyphPoints::GetNextOnCurve(uint16_t poly, uint16_t pt)
496 {
497         return GetOnCurve(poly, GetNext(poly, pt));
498 }
499
500
501 uint16_t GlyphPoints::GetPolyStart(uint16_t poly)
502 {
503         if (poly >= numPolys)
504 #ifdef DEBUG
505 {
506 WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
507 #endif
508                 throw GP_OUT_OF_RANGE;
509 #ifdef DEBUG
510 }
511 #endif
512
513         // If it's poly 0, return 0. Otherwise, get the previous poly's end & add one to it
514         return (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
515 }
516
517
518 uint16_t GlyphPoints::GetPolyEnd(uint16_t poly)
519 {
520         if (poly >= numPolys)
521 #ifdef DEBUG
522 {
523 WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
524 #endif
525                 throw GP_OUT_OF_RANGE;
526 #ifdef DEBUG
527 }
528 #endif
529
530         return polyEnd[poly];
531 }
532
533
534 void GlyphPoints::OffsetPoints(int xOff, int yOff)
535 {
536         for(int i=0; i<numPoints; i++)
537                 x[i] += xOff, y[i] += yOff;
538 }
539
540
541 //
542 // Offset only a specific polygon in the glyph
543 //
544 void GlyphPoints::OffsetPoly(uint16_t poly, int32_t xOff, int32_t yOff)
545 {
546         if (poly >= numPolys)
547 #ifdef DEBUG
548 {
549 WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
550 #endif
551                 throw GP_OUT_OF_RANGE;
552 #ifdef DEBUG
553 }
554 #endif
555
556         uint16_t polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
557
558         for(int i=0; i<GetNumPoints(poly); i++)
559                 x[polyStart + i] += xOff, y[polyStart + i] += yOff;
560 }
561
562
563 void GlyphPoints::ScalePoints(float sc)
564 {
565         for(int i=0; i<numPoints; i++)
566                 x[i] = (int)(((float)x[i] * sc) + 0.5f),
567                 y[i] = (int)(((float)y[i] * sc) + 0.5f);
568 }
569
570
571 void GlyphPoints::SetXY(uint16_t pt, int xx, int yy)
572 {
573         if (pt >= numPoints)
574 #ifdef DEBUG
575 {
576 WriteLogMsg("Exception: SetXY(uint16_t, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
577 #endif
578                 throw GP_OUT_OF_RANGE;
579 #ifdef DEBUG
580 }
581 #endif
582
583         x[pt] = xx, y[pt] = yy;
584 }
585
586
587 void GlyphPoints::SetOnCurve(uint16_t pt, bool oc)
588 {
589         if (pt >= numPoints)
590 #ifdef DEBUG
591 {
592 WriteLogMsg("Exception: SetOnCurve(uint16_t, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
593 #endif
594                 throw GP_OUT_OF_RANGE;
595 #ifdef DEBUG
596 }
597 #endif
598
599         onCurve[pt] = oc;
600 }
601
602
603 void GlyphPoints::SetPoint(const uint16_t pointNum, const IPoint point)
604 {
605         if (pointNum >= numPoints)
606 #ifdef DEBUG
607 {
608 WriteLogMsg("Exception: SetPoint(uint16_t, IPoint). pt=%u, numPoints=%u\xD\xA", pointNum, numPoints);
609 #endif
610                 throw GP_OUT_OF_RANGE;
611 #ifdef DEBUG
612 }
613 #endif
614
615         x[pointNum] = point.x, y[pointNum] = point.y, onCurve[pointNum] = point.onCurve;
616 }
617
618
619 uint16_t GlyphPoints::GetPrev(uint16_t pt)
620 {
621 // pt = 7, polyEnd = 4, 9, 15
622         uint16_t min = 0, max = numPoints - 1;
623
624         for(int i=0; i<numPolys; i++)
625         {
626                 if (pt <= polyEnd[i])
627                 {
628                         if (i > 0)
629                                 min = polyEnd[i - 1] + 1;
630
631                         max = polyEnd[i];
632                         break;
633                 }
634         }
635
636         uint16_t retVal = pt - 1;
637
638         if (pt == min)
639                 retVal = max;
640
641         return retVal;
642 }
643
644
645 uint16_t GlyphPoints::GetNext(uint16_t pt)
646 {
647         uint16_t min = 0, max = numPoints - 1;
648
649         for(int i=0; i<numPolys; i++)
650         {
651                 if (pt <= polyEnd[i])
652                 {
653                         if (i > 0)
654                                 min = polyEnd[i - 1] + 1;
655
656                         max = polyEnd[i];
657                         break;
658                 }
659         }
660
661         uint16_t retVal = pt + 1;
662
663         if (pt == max)
664                 retVal = min;
665
666         return retVal;
667 }
668
669
670 //
671 // Get previous point for this polygon using wraparound.
672 // Note that pt is a zero-based index!
673 //
674 uint16_t GlyphPoints::GetPrev(uint16_t poly, uint16_t pt)
675 {
676         return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);
677 }
678
679
680 //
681 // Get next point for this polygon using wraparound.
682 // Note that pt is a zero-based index!
683 //
684 uint16_t GlyphPoints::GetNext(uint16_t poly, uint16_t pt)
685 {
686         return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);
687 }
688
689
690 #warning "!!! This function returns incorrect results !!!"
691 uint16_t GlyphPoints::GetPoly(uint16_t pt)
692 {
693         if (pt >= numPoints)
694 #ifdef DEBUG
695 {
696 WriteLogMsg("Exception: GetPoly(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
697 #endif
698                 throw GP_OUT_OF_RANGE;
699 #ifdef DEBUG
700 }
701 #endif
702
703         for(int i=0; i<numPolys; i++)
704                 if (pt <= polyEnd[i])
705                         return i;
706
707         return (uint16_t)-1;
708 }
709
710
711 void GlyphPoints::AddNewPolyAtEnd(void)
712 {
713         if (numPoints == 0)                                                     // By default, we already *have* a poly
714                 return;
715
716         uint16_t * newPolyEnd = new uint16_t[numPolys + 1];
717
718         for(uint16_t i=0; i<numPolys; i++)
719                 newPolyEnd[i] = polyEnd[i];
720
721         newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];
722         numPolys++;
723         delete[] polyEnd;
724         polyEnd = newPolyEnd;
725 }
726
727
728 IPoint GlyphPoints::GetMidpointToPrev(uint16_t poly, uint16_t pt)
729 {
730         uint16_t prev = GetPrev(poly, pt);
731
732         int32_t x1 = GetX(poly, pt), y1 = GetY(poly, pt);
733         int32_t x2 = GetX(poly, prev), y2 = GetY(poly, prev);
734
735         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
736 }
737
738
739 IPoint GlyphPoints::GetMidpointToNext(uint16_t poly, uint16_t pt)
740 {
741         uint16_t next = GetNext(poly, pt);
742
743         int32_t x1 = GetX(poly, pt), y1 = GetY(poly, pt);
744         int32_t x2 = GetX(poly, next), y2 = GetY(poly, next);
745
746         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
747 }
748
749
750 IPoint GlyphPoints::GetPrevPoint(uint16_t poly, uint16_t pt)
751 {
752         uint16_t prevPt = GetPrev(poly, pt);
753
754         return IPoint(GetX(poly, prevPt), GetY(poly, prevPt));
755 }
756
757
758 IPoint GlyphPoints::GetNextPoint(uint16_t poly, uint16_t pt)
759 {
760         uint16_t nextPt = GetNext(poly, pt);
761
762         return IPoint(GetX(poly, nextPt), GetY(poly, nextPt));
763 }
764
765
766 uint16_t GlyphPoints::GetPolyForPoint(IPoint point)
767 {
768         uint16_t poly = 0;
769
770         for(uint16_t i=0; i<numPoints; i++)
771         {
772                 if (i > polyEnd[poly])
773                         poly++;
774
775                 if (IPoint(x[i], y[i]) == point)
776                         return poly;
777         }
778
779         return 0xFFFF;
780 }
781
782
783 uint16_t GlyphPoints::GetPolyForPointNumber(uint16_t pointNumber)
784 {
785         // If there's only one poly, we know where the point is...
786         if (numPolys <= 1)
787                 return 0;
788
789         // Otherwise, do a linear search through the polys to find the right one
790         for(uint16_t i=0; i<numPolys; i++)
791         {
792                 if (pointNumber >= GetPolyStart(i) && pointNumber <= polyEnd[i])
793                         return i;
794         }
795
796         return 0xFFFF;
797 }
798
799
800 //
801 // Rotate a point by "angle" around point "center"
802 //
803 IPoint GlyphPoints::RotatePoint(const double angle, const IPoint point, const IPoint center)
804 {
805         // Translate the point to the origin
806         double xt = (double)(point.x - center.x);
807         double yt = (double)(point.y - center.y);
808
809         // Rotate the point by angle
810         double xr = (xt * cos(angle)) - (yt * sin(angle));
811         double yr = (xt * sin(angle)) + (yt * cos(angle));
812
813         // Translate it back...
814         IPoint rotated;
815         rotated.x = (int)(xr + 0.5) + center.x;
816         rotated.y = (int)(yr + 0.5) + center.y;
817         return rotated;
818 }
819
820
821 //
822 // Rotate all points in the glyph by "angle" around point "pt"
823 //
824 void GlyphPoints::RotatePoints(const double angle, const IPoint pt)
825 {
826         for(int i=0; i<numPoints; i++)
827         {
828                 // Translate the point to the origin
829                 double xt = (double)(x[i] - pt.x);
830                 double yt = (double)(y[i] - pt.y);
831
832                 // Rotate the point by angle
833                 double xr = (xt * cos(angle)) - (yt * sin(angle));
834                 double yr = (xt * sin(angle)) + (yt * cos(angle));
835
836                 // Put it back...
837                 x[i] = (int)(xr + 0.5) + pt.x;
838                 y[i] = (int)(yr + 0.5) + pt.y;
839         }
840 }
841
842
843 IPoint GlyphPoints::GetPolyCentroid(const int16_t poly)
844 {
845         // We should throw an exception here, but meh
846         // (this actually short circuits the exception handling in all the GetPolyXXX() functions)
847         // [now we do!]
848         if (poly >= numPolys)
849                 throw GP_OUT_OF_RANGE;
850 //              return IPoint(0, 0);
851
852 //      if (poly >= numPolys)
853 //#ifdef DEBUG
854 //{
855 //WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
856 //#endif
857 //              throw GP_OUT_OF_RANGE;
858 //#ifdef DEBUG
859 //}
860 //#endif
861
862         IPoint centroid;                                                                // Initializes to (0, 0)
863         uint16_t numPointsInPoly = GetNumPoints(poly);
864
865         for(uint16_t i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
866         {
867                 centroid.x += x[i];
868                 centroid.y += y[i];
869         }
870
871         centroid.x /= numPointsInPoly;
872         centroid.y /= numPointsInPoly;
873
874         return centroid;
875 }
876
877
878 void GlyphPoints::RotatePolyAroundCentroid(const int16_t poly, const double angle)
879 {
880         if (poly >= numPolys)
881                 return;
882
883         IPoint centroid = GetPolyCentroid(poly);
884
885         for(uint16_t i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
886         {
887                 IPoint rotated = RotatePoint(angle, IPoint(x[i], y[i]), centroid);
888                 x[i] = rotated.x;
889                 y[i] = rotated.y;
890         }
891 }
892
893
894 void GlyphPoints::InvertPolyDrawSequence(const uint16_t poly)
895 {
896         if (poly >= numPolys)
897                 throw GP_OUT_OF_RANGE;
898
899         uint16_t pointNum1 = GetPolyStart(poly);
900         uint16_t pointNum2 = GetPolyEnd(poly);
901
902         // Algorithm: Step through points in the polygon, swapping 1st and last, then
903         // 2nd and (last - 1), 3rd and (last - 2), etc. We only do this for half the
904         // points, as doing it for all would undo the swapping we did in the 1st half.
905         for(uint16_t i=0; i<GetNumPoints(poly)/2; i++)
906         {
907                 IPoint point1 = GetPoint(pointNum1 + i);
908                 IPoint point2 = GetPoint(pointNum2 - i);
909                 SetPoint(pointNum2 - i, point1);
910                 SetPoint(pointNum1 + i, point2);
911         }
912 }
913
914
915 // really need to do checking on the results from fscanf...
916 bool GlyphPoints::LoadGlyphFromFile(FILE * file)
917 {
918         char line[512];
919         float version;
920
921         FreeAllocatedMemory();
922
923         fscanf(file, "%s V%f", line, &version);
924         fscanf(file, "%s %u", line, &numPoints);
925         x = new int[numPoints];
926         y = new int[numPoints];
927         onCurve = new bool[numPoints];
928
929         for(int i=0; i<numPoints; i++)
930         {
931                 fscanf(file, "%d %d %s", &x[i], &y[i], (char *)&line);
932                 onCurve[i] = (line[0] == 'T' ? true : false);
933         }
934
935         fscanf(file, "%s %u", line, &numPolys);
936         polyEnd = new uint16_t[numPolys];
937
938         for(int i=0; i<numPolys; i++)
939         {
940                 fscanf(file, "%u", &polyEnd[i]);
941         }
942
943         return true;
944 }
945
946
947 bool GlyphPoints::SaveGlyphToFile(FILE * file)
948 {
949 //      GlyphPoints glyph = editWnd->pts;
950         fprintf(file, "TTEGLYPH V1.0\n");
951         fprintf(file, "POINTS %u\n", numPoints);
952
953         for(int i=0; i<numPoints; i++)
954         {
955                 fprintf(file, "%d %d %s\n", x[i], y[i], (onCurve[i] ? "T" : "F")); 
956         }
957
958         fprintf(file, "POLYS %u\n", numPolys);
959
960         for(int i=0; i<numPolys; i++)
961         {
962                 fprintf(file, "%u\n", polyEnd[i]); 
963         }
964
965         return true;
966 }
967