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