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