]> Shamusworld >> Repos - ttedit/blob - src/glyphpoints.cpp
Added rotation tool, save/load capability.
[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 * 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 * 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[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 * 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[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 #if 0
149         if (x)
150                 delete[] x;
151
152         if (y)
153                 delete[] y;
154
155         if (onCurve)
156                 delete[] onCurve;
157
158         if (polyEnd)
159                 delete[] polyEnd;
160 #endif
161         FreeAllocatedMemory();
162         AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);
163
164         return *this;
165 }
166
167
168 // Add another GlyphPoints' points to this one...
169
170 GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)
171 {
172         int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;
173
174         int * totX = new int[totPoints];
175         int * totY = new int[totPoints];
176         bool * totOnCurve = new bool[totPoints];
177         uint16 * totPolyEnd = new uint16[totPolys];
178
179         for(int i=0; i<numPoints; i++)
180         {
181                 totX[i] = x[i];
182                 totY[i] = y[i];
183                 totOnCurve[i] = onCurve[i];
184         }
185
186         for(int i=0; i<numPolys; i++)
187                 totPolyEnd[i] = polyEnd[i];
188
189         for(int i=0; i<c.numPoints; i++)
190         {
191                 totX[numPoints+i] = c.x[i];
192                 totY[numPoints+i] = c.y[i];
193                 totOnCurve[numPoints+i] = c.onCurve[i];
194         }
195
196         for(int i=0; i<c.numPolys; i++)
197                 totPolyEnd[numPolys+i] = numPoints + c.polyEnd[i];  // Need to adjust the "added in"
198                                                         // poly's end points...
199
200         GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);
201         delete[] totX;
202         delete[] totY;
203         delete[] totOnCurve;
204         delete[] totPolyEnd;
205
206         return retVal;
207 }
208
209
210 // Add a point to this GlyphPoints...
211
212 GlyphPoints GlyphPoints::operator+(const IPoint &c)
213 {
214 //This is kinda silly. We can do better than this! !!! FIX !!!
215         int * totX = new int[numPoints + 1];
216         int * totY = new int[numPoints + 1];
217         bool * totOnCurve = new bool[numPoints + 1];
218         uint16 * totPolyEnd = new uint16[numPolys];
219
220         for(int i=0; i<numPoints; i++)
221                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
222
223         totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;
224
225         for(int i=0; i<numPolys; i++)
226                 totPolyEnd[i] = polyEnd[i];
227
228         totPolyEnd[numPolys - 1]++;                                     // Bump polygon's end point
229         GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);
230
231         delete[] totX;
232         delete[] totY;
233         delete[] totOnCurve;
234
235         return retVal;
236 }
237
238
239 GlyphPoints& GlyphPoints::operator+=(const IPoint &p)
240 {
241         InsertPoint(numPoints, p.x, p.y, p.onCurve);
242
243         return *this;
244 }
245
246
247 void GlyphPoints::Clear(void)
248 {
249         FreeAllocatedMemory();
250         x = y = NULL;
251         onCurve = NULL;
252         polyEnd = NULL;
253         numPoints = numPolys = pointsAllocated = polysAllocated = 0;
254 }
255
256
257 void GlyphPoints::InsertPoint(uint16 pt, int xx, int yy, bool oc)
258 {
259         if (pt > numPoints)                                                     // > because we can insert at end...!
260                 throw GP_OUT_OF_RANGE;
261
262 //This is kinda silly. We can do better than this! !!! FIX !!!
263         int * totX = new int[numPoints + 1];
264         int * totY = new int[numPoints + 1];
265         bool * totOnCurve = new bool[numPoints + 1];
266
267         for(int i=0; i<pt; i++)
268                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
269
270         for(int i=pt; i<numPoints; i++)
271                 totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];
272
273         totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;
274
275 //A way to fix the kludge in GetPoly() would be to put a check here to see if
276 //we're adding to the end of the structure: [DONE, below]
277         int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt));
278         for(int i=polyInsert; i<numPolys; i++)
279 //      for(int i=GetPoly(pt); i<numPolys; i++)
280                 polyEnd[i]++;                                                   // Bump polygons' end point
281
282         numPoints++;
283
284         delete[] x;
285         delete[] y;
286         delete[] onCurve;
287
288         x = totX, y = totY, onCurve = totOnCurve;
289 }
290
291
292 void GlyphPoints::InsertPoint(uint16 pt, const IPoint &p)
293 {
294         InsertPoint(pt, p.x, p.y, p.onCurve);
295 }
296
297
298 //
299 // Delete a point from the glyph
300 // Note that we don't bother to reallocate anything here, just bump the
301 // size counters down as needed. In the future, we'll keep track so we
302 // don't have to reallocate *every* damn time a point is added...
303 //
304 void GlyphPoints::DeletePoint(uint16 pt)
305 {
306         // Adjust polygon ends appropriately
307         uint16 poly = GetPoly(pt);
308
309         for(int i=poly; i<numPolys; i++)
310                 polyEnd[i]--;
311
312 //Need to check here if we're deleting the last point in the glyph or not.
313 //!!! FIX !!! [DONE]
314         if (GetNumPoints(poly) == 0 && numPoints > 0)
315         {
316                 numPolys--;
317
318                 for(int i=poly; i<numPolys; i++)
319                         polyEnd[i] = polyEnd[i + 1];
320         }
321
322 //This causes a crash becuz GetPoly() uses numPoints... !!! FIX !!! [DONE by switching poly delete & point delete]
323         // Close up the gap left by the current point
324         numPoints--;
325
326         for(int i=pt; i<numPoints; i++)
327                 x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];
328 }
329
330
331 uint16 GlyphPoints::GetNumPoints(void)
332 {
333         return numPoints;
334 }
335
336
337 uint16 GlyphPoints::GetNumPoints(uint16 poly)
338 {
339         if (poly >= numPolys)
340 #ifdef DEBUG
341 {
342 WriteLogMsg("Exception: GetNumPoints(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
343 #endif
344                 throw GP_OUT_OF_RANGE;
345 #ifdef DEBUG
346 }
347 #endif
348
349         return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);
350 }
351
352
353 uint16 GlyphPoints::GetNumPolys(void)
354 {
355         return numPolys;
356 }
357
358
359 int GlyphPoints::GetX(uint16 pt)
360 {
361         if (pt >= numPoints)
362 #ifdef DEBUG
363 {
364 WriteLogMsg("Exception: GetX(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
365 #endif
366                 throw GP_OUT_OF_RANGE;
367 #ifdef DEBUG
368 }
369 #endif
370
371         return x[pt];
372 }
373
374
375 int GlyphPoints::GetY(uint16 pt)
376 {
377         if (pt >= numPoints)
378 #ifdef DEBUG
379 {
380 WriteLogMsg("Exception: GetY(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
381 #endif
382                 throw GP_OUT_OF_RANGE;
383 #ifdef DEBUG
384 }
385 #endif
386
387         return y[pt];
388 }
389
390
391 bool GlyphPoints::GetOnCurve(uint16 pt)
392 {
393         if (pt >= numPoints)
394 #ifdef DEBUG
395 {
396 WriteLogMsg("Exception: GetOnCurve(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
397 #endif
398                 throw GP_OUT_OF_RANGE;
399 #ifdef DEBUG
400 }
401 #endif
402
403         return onCurve[pt];
404 }
405
406
407 int GlyphPoints::GetX(uint16 poly, uint16 pt)
408 {
409         if (pt >= GetNumPoints(poly))
410 #ifdef DEBUG
411 {
412 WriteLogMsg("Exception: GetX(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
413 #endif
414                 throw GP_OUT_OF_RANGE;
415 #ifdef DEBUG
416 }
417 #endif
418
419         return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
420 }
421
422
423 int GlyphPoints::GetNextX(uint16 poly, uint16 pt)
424 {
425         return GetX(poly, GetNext(poly, pt));
426 }
427
428
429 int GlyphPoints::GetY(uint16 poly, uint16 pt)
430 {
431         if (pt >= GetNumPoints(poly))
432 #ifdef DEBUG
433 {
434 WriteLogMsg("Exception: GetY(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
435 #endif
436                 throw GP_OUT_OF_RANGE;
437 #ifdef DEBUG
438 }
439 #endif
440
441         return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
442 }
443
444
445 int GlyphPoints::GetNextY(uint16 poly, uint16 pt)
446 {
447         return GetY(poly, GetNext(poly, pt));
448 }
449
450
451 IPoint GlyphPoints::GetPoint(uint16 poly, uint16 pt)
452 {
453         return IPoint(GetX(poly, pt), GetY(poly, pt));
454 }
455
456
457 bool GlyphPoints::GetOnCurve(uint16 poly, uint16 pt)
458 {
459         if (pt >= GetNumPoints(poly))
460 #ifdef DEBUG
461 {
462 WriteLogMsg("Exception: GetOnCurve(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
463 #endif
464                 throw GP_OUT_OF_RANGE;
465 #ifdef DEBUG
466 }
467 #endif
468
469         return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
470 }
471
472
473 bool GlyphPoints::GetPrevOnCurve(uint16 poly, uint16 pt)
474 {
475         return GetOnCurve(poly, GetPrev(poly, pt));
476 }
477
478
479 bool GlyphPoints::GetNextOnCurve(uint16 poly, uint16 pt)
480 {
481         return GetOnCurve(poly, GetNext(poly, pt));
482 }
483
484
485 uint16 GlyphPoints::GetPolyStart(uint16 poly)
486 {
487         if (poly >= numPolys)
488 #ifdef DEBUG
489 {
490 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
491 #endif
492                 throw GP_OUT_OF_RANGE;
493 #ifdef DEBUG
494 }
495 #endif
496
497         // If it's poly 0, return 0. Otherwise, get the previous poly's end & add one to it
498         return (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
499 }
500
501
502 uint16 GlyphPoints::GetPolyEnd(uint16 poly)
503 {
504         if (poly >= numPolys)
505 #ifdef DEBUG
506 {
507 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
508 #endif
509                 throw GP_OUT_OF_RANGE;
510 #ifdef DEBUG
511 }
512 #endif
513
514         return polyEnd[poly];
515 }
516
517
518 void GlyphPoints::OffsetPoints(int xOff, int yOff)
519 {
520         for(int i=0; i<numPoints; i++)
521                 x[i] += xOff, y[i] += yOff;
522 }
523
524
525 //
526 // Offset only a specific polygon in the glyph
527 //
528 void GlyphPoints::OffsetPoly(uint16 poly, int32 xOff, int32 yOff)
529 {
530         if (poly >= numPolys)
531 #ifdef DEBUG
532 {
533 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
534 #endif
535                 throw GP_OUT_OF_RANGE;
536 #ifdef DEBUG
537 }
538 #endif
539
540         uint16 polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
541
542         for(int i=0; i<GetNumPoints(poly); i++)
543                 x[polyStart + i] += xOff, y[polyStart + i] += yOff;
544 }
545
546
547 void GlyphPoints::ScalePoints(float sc)
548 {
549         for(int i=0; i<numPoints; i++)
550                 x[i] = (int)(((float)x[i] * sc) + 0.5f),
551                 y[i] = (int)(((float)y[i] * sc) + 0.5f);
552 }
553
554
555 void GlyphPoints::SetXY(uint16 pt, int xx, int yy)
556 {
557         if (pt >= numPoints)
558 #ifdef DEBUG
559 {
560 WriteLogMsg("Exception: SetXY(uint16, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
561 #endif
562                 throw GP_OUT_OF_RANGE;
563 #ifdef DEBUG
564 }
565 #endif
566
567         x[pt] = xx, y[pt] = yy;
568 }
569
570
571 void GlyphPoints::SetOnCurve(uint16 pt, bool oc)
572 {
573         if (pt >= numPoints)
574 #ifdef DEBUG
575 {
576 WriteLogMsg("Exception: SetOnCurve(uint16, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
577 #endif
578                 throw GP_OUT_OF_RANGE;
579 #ifdef DEBUG
580 }
581 #endif
582
583         onCurve[pt] = oc;
584 }
585
586
587 uint16 GlyphPoints::GetPrev(uint16 pt)
588 {
589 // pt = 7, polyEnd = 4, 9, 15
590         uint16 min = 0, max = numPoints - 1;
591
592         for(int i=0; i<numPolys; i++)
593         {
594                 if (pt <= polyEnd[i])
595                 {
596                         if (i > 0)
597                                 min = polyEnd[i - 1] + 1;
598
599                         max = polyEnd[i];
600                         break;
601                 }
602         }
603
604         uint16 retVal = pt - 1;
605
606         if (pt == min)
607                 retVal = max;
608
609         return retVal;
610 }
611
612
613 uint16 GlyphPoints::GetNext(uint16 pt)
614 {
615         uint16 min = 0, max = numPoints - 1;
616
617         for(int i=0; i<numPolys; i++)
618         {
619                 if (pt <= polyEnd[i])
620                 {
621                         if (i > 0)
622                                 min = polyEnd[i - 1] + 1;
623
624                         max = polyEnd[i];
625                         break;
626                 }
627         }
628
629         uint16 retVal = pt + 1;
630
631         if (pt == max)
632                 retVal = min;
633
634         return retVal;
635 }
636
637
638 //
639 // Get previous point for this polygon using wraparound.
640 // Note that pt is a zero-based index!
641 //
642 uint16 GlyphPoints::GetPrev(uint16 poly, uint16 pt)
643 {
644         return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);
645 }
646
647
648 //
649 // Get next point for this polygon using wraparound.
650 // Note that pt is a zero-based index!
651 //
652 uint16 GlyphPoints::GetNext(uint16 poly, uint16 pt)
653 {
654         return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);
655 }
656
657
658 uint16 GlyphPoints::GetPoly(uint16 pt)
659 {
660         if (pt >= numPoints)
661 #ifdef DEBUG
662 {
663 WriteLogMsg("Exception: GetPoly(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
664 #endif
665                 throw GP_OUT_OF_RANGE;
666 #ifdef DEBUG
667 }
668 #endif
669
670         for(int i=0; i<numPolys; i++)
671                 if (pt <= polyEnd[i])
672                         return i;
673
674         return (uint16)-1;
675 }
676
677
678 void GlyphPoints::AddNewPolyAtEnd(void)
679 {
680         if (numPoints == 0)                                                     // By default, we already *have* a poly
681                 return;
682
683         uint16 * newPolyEnd = new uint16[numPolys + 1];
684
685         for(uint16 i=0; i<numPolys; i++)
686                 newPolyEnd[i] = polyEnd[i];
687
688         newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];
689         numPolys++;
690         delete[] polyEnd;
691         polyEnd = newPolyEnd;
692 }
693
694
695 IPoint GlyphPoints::GetMidpointToPrev(uint16 poly, uint16 pt)
696 {
697         uint16 prev = GetPrev(poly, pt);
698
699         int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
700         int32 x2 = GetX(poly, prev), y2 = GetY(poly, prev);
701
702         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
703 }
704
705
706 IPoint GlyphPoints::GetMidpointToNext(uint16 poly, uint16 pt)
707 {
708         uint16 next = GetNext(poly, pt);
709
710         int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
711         int32 x2 = GetX(poly, next), y2 = GetY(poly, next);
712
713         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
714 }
715
716
717 IPoint GlyphPoints::GetPrevPoint(uint16 poly, uint16 pt)
718 {
719         uint16 prevPt = GetPrev(poly, pt);
720
721         return IPoint(GetX(poly, prevPt), GetY(poly, prevPt));
722 }
723
724
725 IPoint GlyphPoints::GetNextPoint(uint16 poly, uint16 pt)
726 {
727         uint16 nextPt = GetNext(poly, pt);
728
729         return IPoint(GetX(poly, nextPt), GetY(poly, nextPt));
730 }
731
732
733 //
734 // Rotate a point by "angle" around point "center"
735 //
736 IPoint GlyphPoints::RotatePoint(const double angle, const IPoint point, const IPoint center)
737 {
738         // Translate the point to the origin
739         double xt = (double)(point.x - center.x);
740         double yt = (double)(point.y - center.y);
741
742         // Rotate the point by angle
743         double xr = (xt * cos(angle)) - (yt * sin(angle));
744         double yr = (xt * sin(angle)) + (yt * cos(angle));
745
746         // Translate it back...
747         IPoint rotated;
748         rotated.x = (int)(xr + 0.5) + center.x;
749         rotated.y = (int)(yr + 0.5) + center.y;
750         return rotated;
751 }
752
753
754 //
755 // Rotate all points in the glyph by "angle" around point "pt"
756 //
757 void GlyphPoints::RotatePoints(const double angle, const IPoint pt)
758 {
759         for(int i=0; i<numPoints; i++)
760         {
761                 // Translate the point to the origin
762                 double xt = (double)(x[i] - pt.x);
763                 double yt = (double)(y[i] - pt.y);
764
765                 // Rotate the point by angle
766                 double xr = (xt * cos(angle)) - (yt * sin(angle));
767                 double yr = (xt * sin(angle)) + (yt * cos(angle));
768
769                 // Put it back...
770                 x[i] = (int)(xr + 0.5) + pt.x;
771                 y[i] = (int)(yr + 0.5) + pt.y;
772         }
773 }
774
775
776 IPoint GlyphPoints::GetPolyCentroid(const int16 poly)
777 {
778         // We should throw an exception here, but meh
779         // (this actually short circuits the exception handling in all the GetPolyXXX() functions)
780         if (poly >= numPolys)
781                 return IPoint(0, 0);
782
783 //      if (poly >= numPolys)
784 //#ifdef DEBUG
785 //{
786 //WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
787 //#endif
788 //              throw GP_OUT_OF_RANGE;
789 //#ifdef DEBUG
790 //}
791 //#endif
792
793         IPoint centroid;                                                                // Initializes to (0, 0)
794         uint16 numPointsInPoly = GetNumPoints(poly);
795
796         for(uint16 i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
797         {
798                 centroid.x += x[i];
799                 centroid.y += y[i];
800         }
801
802         centroid.x /= numPointsInPoly;
803         centroid.y /= numPointsInPoly;
804
805         return centroid;
806 }
807
808
809 void GlyphPoints::RotatePolyAroundCentroid(const int16 poly, const double angle)
810 {
811         if (poly >= numPolys)
812                 return;
813
814         IPoint centroid = GetPolyCentroid(poly);
815
816         for(uint16 i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
817         {
818                 IPoint rotated = RotatePoint(angle, IPoint(x[i], y[i]), centroid);
819                 x[i] = rotated.x;
820                 y[i] = rotated.y;
821         }
822 }
823
824
825 // really need to do checking on the results from fscanf...
826 bool GlyphPoints::LoadGlyphFromFile(FILE * file)
827 {
828         char line[512];
829         float version;
830
831         FreeAllocatedMemory();
832
833         fscanf(file, "%s V%f", line, &version);
834         fscanf(file, "%s %u", line, &numPoints);
835         x = new int[numPoints];
836         y = new int[numPoints];
837         onCurve = new bool[numPoints];
838
839         for(int i=0; i<numPoints; i++)
840         {
841                 fscanf(file, "%d %d %s", &x[i], &y[i], &line);
842                 onCurve[i] = (line[0] == 'T' ? true : false);
843         }
844
845         fscanf(file, "%s %u", line, &numPolys);
846         polyEnd = new uint16[numPolys];
847
848         for(int i=0; i<numPolys; i++)
849         {
850                 fscanf(file, "%u", &polyEnd[i]);
851         }
852
853         return true;
854 }
855
856
857 bool GlyphPoints::SaveGlyphToFile(FILE * file)
858 {
859 //      GlyphPoints glyph = editWnd->pts;
860         fprintf(file, "TTEGLYPH V1.0\n");
861         fprintf(file, "POINTS %u\n", numPoints);
862
863         for(int i=0; i<numPoints; i++)
864         {
865                 fprintf(file, "%d %d %s\n", x[i], y[i], (onCurve[i] ? "T" : "F")); 
866         }
867
868         fprintf(file, "POLYS %u\n", numPolys);
869
870         for(int i=0; i<numPolys; i++)
871         {
872                 fprintf(file, "%u\n", polyEnd[i]); 
873         }
874
875         return true;
876 }
877