]> Shamusworld >> Repos - ttedit/blob - src/glyphpoints.cpp
d7ce0d5b19d082d629c28aa9f8458142830402e2
[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
26 /*GlyphPoints::GlyphPoints(void)
27 {
28         GlyphPoints(0, 0, NULL, NULL, NULL, NULL);
29 }*/
30
31 GlyphPoints::GlyphPoints(int nPts/*=0*/, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,
32         bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
33 //GlyphPoints::GlyphPoints(int nPts, 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 {
36         AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);
37
38         if (nPlys == 0)
39         {
40                 numPolys = 1;
41                 polyEnd = new uint16[numPolys];
42                 polyEnd[0] = numPoints - 1;
43         }
44 #ifdef DEBUG
45 WriteLogMsg("GlyphPoints: Default constructor. %u points, %u polys.\n", numPoints, numPolys);
46 #endif
47 }
48
49 GlyphPoints::GlyphPoints(int xx, int yy, bool oc)
50 {
51 //Hmm. What to do with this...?
52         AllocateAndCopy(1, 0, &xx, &yy, &oc, NULL);
53 #ifdef DEBUG
54 WriteLogMsg("GlyphPoints: Single point constructor. %u points, %u polys.\n", numPoints, numPolys);
55 #endif
56 }
57
58 // Copy constructor (needed for deep copying)
59
60 //GlyphPoints::GlyphPoints(GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
61 GlyphPoints::GlyphPoints(const GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
62 {
63         *this = c;                                                                      // Use overloaded operator=
64 #ifdef DEBUG
65 WriteLogMsg("GlyphPoints: Copy constructor. %u points, %u polys.\n", numPoints, numPolys);
66 #endif
67 }
68
69 GlyphPoints::~GlyphPoints()
70 {
71         if (x)
72                 delete[] x;
73
74         if (y)
75                 delete[] y;
76
77         if (onCurve)
78                 delete[] onCurve;
79
80         if (polyEnd)
81                 delete[] polyEnd;
82 }
83
84 void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16 * pa)
85 {
86         numPoints = nPts, numPolys = nPlys;
87
88         if (nPts)
89         {
90                 x = new int[numPoints];
91                 y = new int[numPoints];
92                 onCurve = new bool[numPoints];
93
94                 if (xa)                                                                 // Copy points in if they're passed in...
95                         for(int i=0; i<nPts; i++)
96                                 x[i] = xa[i];
97
98                 if (ya)
99                         for(int i=0; i<nPts; i++)
100                                 y[i] = ya[i];
101
102                 if (oca)
103                         for(int i=0; i<nPts; i++)
104                                 onCurve[i] = oca[i];
105         }
106
107         if (numPolys)
108         {
109                 polyEnd = new uint16[numPolys];
110
111                 if (pa)                                                                 // Copy poly ends in if they're passed in...
112                         for(int i=0; i<nPlys; i++)
113                                 polyEnd[i] = pa[i];
114         }
115 }
116
117 GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)
118 {
119         if (this == &c)
120                 return *this;                                                   // Take care of self-assignment
121
122         if (x)
123                 delete[] x;
124
125         if (y)
126                 delete[] y;
127
128         if (onCurve)
129                 delete[] onCurve;
130
131         if (polyEnd)
132                 delete[] polyEnd;
133
134         AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);
135
136         return *this;
137 }
138
139 // Add another GlyphPoints' points to this one...
140
141 GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)
142 {
143         int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;
144
145         int * totX = new int[totPoints];
146         int * totY = new int[totPoints];
147         bool * totOnCurve = new bool[totPoints];
148         uint16 * totPolyEnd = new uint16[totPolys];
149
150         for(int i=0; i<numPoints; i++)
151         {
152                 totX[i] = x[i];
153                 totY[i] = y[i];
154                 totOnCurve[i] = onCurve[i];
155         }
156
157         for(int i=0; i<numPolys; i++)
158                 totPolyEnd[i] = polyEnd[i];
159
160         for(int i=0; i<c.numPoints; i++)
161         {
162                 totX[numPoints+i] = c.x[i];
163                 totY[numPoints+i] = c.y[i];
164                 totOnCurve[numPoints+i] = c.onCurve[i];
165         }
166
167         for(int i=0; i<c.numPolys; i++)
168                 totPolyEnd[numPolys+i] = numPoints + c.polyEnd[i];  // Need to adjust the "added in"
169                                                         // poly's end points...
170
171         GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);
172         delete[] totX;
173         delete[] totY;
174         delete[] totOnCurve;
175         delete[] totPolyEnd;
176
177         return retVal;
178 }
179
180 // Add a point to this GlyphPoints...
181
182 GlyphPoints GlyphPoints::operator+(const IPoint &c)
183 {
184 //This is kinda silly. We can do better than this! !!! FIX !!!
185         int * totX = new int[numPoints + 1];
186         int * totY = new int[numPoints + 1];
187         bool * totOnCurve = new bool[numPoints + 1];
188         uint16 * totPolyEnd = new uint16[numPolys];
189
190         for(int i=0; i<numPoints; i++)
191                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
192
193         totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;
194
195         for(int i=0; i<numPolys; i++)
196                 totPolyEnd[i] = polyEnd[i];
197
198         totPolyEnd[numPolys - 1]++;                                     // Bump polygon's end point
199         GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);
200
201         delete[] totX;
202         delete[] totY;
203         delete[] totOnCurve;
204
205         return retVal;
206 }
207
208 GlyphPoints& GlyphPoints::operator+=(const IPoint &p)
209 {
210         InsertPoint(numPoints, p.x, p.y, p.onCurve);
211
212         return *this;
213 }
214
215 void GlyphPoints::InsertPoint(uint16 pt, int xx, int yy, bool oc)
216 {
217         if (pt > numPoints)                                                     // > because we can insert at end...!
218                 throw GP_OUT_OF_RANGE;
219
220 //This is kinda silly. We can do better than this! !!! FIX !!!
221         int * totX = new int[numPoints + 1];
222         int * totY = new int[numPoints + 1];
223         bool * totOnCurve = new bool[numPoints + 1];
224
225         for(int i=0; i<pt; i++)
226                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
227
228         for(int i=pt; i<numPoints; i++)
229                 totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];
230
231         totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;
232
233 //A way to fix the kludge in GetPoly() would be to put a check here to see if
234 //we're adding to the end of the structure: [DONE, below]
235         int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt));
236         for(int i=polyInsert; i<numPolys; i++)
237 //      for(int i=GetPoly(pt); i<numPolys; i++)
238                 polyEnd[i]++;                                                   // Bump polygons' end point
239
240         numPoints++;
241
242         delete[] x;
243         delete[] y;
244         delete[] onCurve;
245
246         x = totX, y = totY, onCurve = totOnCurve;
247 }
248
249 void GlyphPoints::InsertPoint(uint16 pt, const IPoint &p)
250 {
251         InsertPoint(pt, p.x, p.y, p.onCurve);
252 }
253
254 //
255 // Delete a point from the glyph
256 // Note that we don't bother to reallocate anything here, just bump the
257 // size counters down as needed. In the future, we'll keep track so we
258 // don't have to reallocate *every* damn time a point is added...
259 //
260 void GlyphPoints::DeletePoint(uint16 pt)
261 {
262         // Adjust polygon ends appropriately
263         uint16 poly = GetPoly(pt);
264
265         for(int i=poly; i<numPolys; i++)
266                 polyEnd[i]--;
267
268 //Need to check here if we're deleting the last point in the glyph or not.
269 //!!! FIX !!! [DONE]
270         if (GetNumPoints(poly) == 0 && numPoints > 0)
271         {
272                 numPolys--;
273
274                 for(int i=poly; i<numPolys; i++)
275                         polyEnd[i] = polyEnd[i + 1];
276         }
277
278 //This causes a crash becuz GetPoly() uses numPoints... !!! FIX !!! [DONE by switching poly delete & point delete]
279         // Close up the gap left by the current point
280         numPoints--;
281
282         for(int i=pt; i<numPoints; i++)
283                 x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];
284 }
285
286 uint16 GlyphPoints::GetNumPoints(void)
287 {
288         return numPoints;
289 }
290
291 uint16 GlyphPoints::GetNumPoints(uint16 poly)
292 {
293         if (poly >= numPolys)
294 #ifdef DEBUG
295 {
296 WriteLogMsg("Exception: GetNumPoints(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
297 #endif
298                 throw GP_OUT_OF_RANGE;
299 #ifdef DEBUG
300 }
301 #endif
302
303         return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);
304 }
305
306 uint16 GlyphPoints::GetNumPolys(void)
307 {
308         return numPolys;
309 }
310
311 int GlyphPoints::GetX(uint16 pt)
312 {
313         if (pt >= numPoints)
314 #ifdef DEBUG
315 {
316 WriteLogMsg("Exception: GetX(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
317 #endif
318                 throw GP_OUT_OF_RANGE;
319 #ifdef DEBUG
320 }
321 #endif
322
323         return x[pt];
324 }
325
326 int GlyphPoints::GetY(uint16 pt)
327 {
328         if (pt >= numPoints)
329 #ifdef DEBUG
330 {
331 WriteLogMsg("Exception: GetY(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
332 #endif
333                 throw GP_OUT_OF_RANGE;
334 #ifdef DEBUG
335 }
336 #endif
337
338         return y[pt];
339 }
340
341 bool GlyphPoints::GetOnCurve(uint16 pt)
342 {
343         if (pt >= numPoints)
344 #ifdef DEBUG
345 {
346 WriteLogMsg("Exception: GetOnCurve(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
347 #endif
348                 throw GP_OUT_OF_RANGE;
349 #ifdef DEBUG
350 }
351 #endif
352
353         return onCurve[pt];
354 }
355
356 int GlyphPoints::GetX(uint16 poly, uint16 pt)
357 {
358         if (pt >= GetNumPoints(poly))
359 #ifdef DEBUG
360 {
361 WriteLogMsg("Exception: GetX(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
362 #endif
363                 throw GP_OUT_OF_RANGE;
364 #ifdef DEBUG
365 }
366 #endif
367
368         return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
369 }
370
371 int GlyphPoints::GetY(uint16 poly, uint16 pt)
372 {
373         if (pt >= GetNumPoints(poly))
374 #ifdef DEBUG
375 {
376 WriteLogMsg("Exception: GetY(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
377 #endif
378                 throw GP_OUT_OF_RANGE;
379 #ifdef DEBUG
380 }
381 #endif
382
383         return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
384 }
385
386 bool GlyphPoints::GetOnCurve(uint16 poly, uint16 pt)
387 {
388         if (pt >= GetNumPoints(poly))
389 #ifdef DEBUG
390 {
391 WriteLogMsg("Exception: GetOnCurve(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
392 #endif
393                 throw GP_OUT_OF_RANGE;
394 #ifdef DEBUG
395 }
396 #endif
397
398         return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
399 }
400
401 uint16 GlyphPoints::GetPolyEnd(uint16 poly)
402 {
403         if (poly >= numPolys)
404 #ifdef DEBUG
405 {
406 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
407 #endif
408                 throw GP_OUT_OF_RANGE;
409 #ifdef DEBUG
410 }
411 #endif
412
413         return polyEnd[poly];
414 }
415
416 void GlyphPoints::OffsetPoints(int xOff, int yOff)
417 {
418         for(int i=0; i<numPoints; i++)
419                 x[i] += xOff, y[i] += yOff;
420 }
421
422 //
423 // Offset only a specific polygon in the glyph
424 //
425 void GlyphPoints::OffsetPoly(uint16 poly, int32 xOff, int32 yOff)
426 {
427         if (poly >= numPolys)
428 #ifdef DEBUG
429 {
430 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
431 #endif
432                 throw GP_OUT_OF_RANGE;
433 #ifdef DEBUG
434 }
435 #endif
436
437         uint16 polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
438
439         for(int i=0; i<GetNumPoints(poly); i++)
440                 x[polyStart + i] += xOff, y[polyStart + i] += yOff;
441 }
442
443 void GlyphPoints::ScalePoints(float sc)
444 {
445         for(int i=0; i<numPoints; i++)
446                 x[i] = (int)(((float)x[i] * sc) + 0.5f),
447                 y[i] = (int)(((float)y[i] * sc) + 0.5f);
448 }
449
450 void GlyphPoints::SetXY(uint16 pt, int xx, int yy)
451 {
452         if (pt >= numPoints)
453 #ifdef DEBUG
454 {
455 WriteLogMsg("Exception: SetXY(uint16, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
456 #endif
457                 throw GP_OUT_OF_RANGE;
458 #ifdef DEBUG
459 }
460 #endif
461
462         x[pt] = xx, y[pt] = yy;
463 }
464
465 void GlyphPoints::SetOnCurve(uint16 pt, bool oc)
466 {
467         if (pt >= numPoints)
468 #ifdef DEBUG
469 {
470 WriteLogMsg("Exception: SetOnCurve(uint16, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
471 #endif
472                 throw GP_OUT_OF_RANGE;
473 #ifdef DEBUG
474 }
475 #endif
476
477         onCurve[pt] = oc;
478 }
479
480 uint16 GlyphPoints::GetPrev(uint16 pt)
481 {
482 // pt = 7, polyEnd = 4, 9, 15
483         uint16 min = 0, max = numPoints - 1;
484
485         for(int i=0; i<numPolys; i++)
486         {
487                 if (pt <= polyEnd[i])
488                 {
489                         if (i > 0)
490                                 min = polyEnd[i - 1] + 1;
491
492                         max = polyEnd[i];
493                         break;
494                 }
495         }
496
497         uint16 retVal = pt - 1;
498
499         if (pt == min)
500                 retVal = max;
501
502         return retVal;
503 }
504
505 uint16 GlyphPoints::GetNext(uint16 pt)
506 {
507         uint16 min = 0, max = numPoints - 1;
508
509         for(int i=0; i<numPolys; i++)
510         {
511                 if (pt <= polyEnd[i])
512                 {
513                         if (i > 0)
514                                 min = polyEnd[i - 1] + 1;
515
516                         max = polyEnd[i];
517                         break;
518                 }
519         }
520
521         uint16 retVal = pt + 1;
522
523         if (pt == max)
524                 retVal = min;
525
526         return retVal;
527 }
528
529 //
530 // Get previous point for this polygon using wraparound.
531 // Note that pt is a zero-based index!
532 //
533 uint16 GlyphPoints::GetPrev(uint16 poly, uint16 pt)
534 {
535         return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);
536 }
537
538 //
539 // Get next point for this polygon using wraparound.
540 // Note that pt is a zero-based index!
541 //
542 uint16 GlyphPoints::GetNext(uint16 poly, uint16 pt)
543 {
544         return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);
545 }
546
547 uint16 GlyphPoints::GetPoly(uint16 pt)
548 {
549         if (pt >= numPoints)
550 #ifdef DEBUG
551 {
552 WriteLogMsg("Exception: GetPoly(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
553 #endif
554                 throw GP_OUT_OF_RANGE;
555 #ifdef DEBUG
556 }
557 #endif
558
559         for(int i=0; i<numPolys; i++)
560                 if (pt <= polyEnd[i])
561                         return i;
562
563         return (uint16)-1;
564 }
565
566 void GlyphPoints::AddNewPolyAtEnd(void)
567 {
568         if (numPoints == 0)                                                     // By default, we already *have* a poly
569                 return;
570
571         uint16 * newPolyEnd = new uint16[numPolys + 1];
572
573         for(uint16 i=0; i<numPolys; i++)
574                 newPolyEnd[i] = polyEnd[i];
575
576         newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];
577         numPolys++;
578         delete[] polyEnd;
579         polyEnd = newPolyEnd;
580 }
581
582 IPoint GlyphPoints::GetMidpointToPrev(uint16 poly, uint16 pt)
583 {
584         uint16 prev = GetPrev(poly, pt);
585
586         int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
587         int32 x2 = GetX(poly, prev), y2 = GetY(poly, prev);
588
589         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
590 }
591
592 IPoint GlyphPoints::GetMidpointToNext(uint16 poly, uint16 pt)
593 {
594         uint16 next = GetNext(poly, pt);
595
596         int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
597         int32 x2 = GetX(poly, next), y2 = GetY(poly, next);
598
599         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
600 }
601
602 IPoint GlyphPoints::GetPrevPoint(uint16 poly, uint16 pt)
603 {
604         uint16 prevPt = GetPrev(poly, pt);
605
606         return IPoint(GetX(poly, prevPt), GetY(poly, prevPt));
607 }
608
609 IPoint GlyphPoints::GetNextPoint(uint16 poly, uint16 pt)
610 {
611         uint16 nextPt = GetNext(poly, pt);
612
613         return IPoint(GetX(poly, nextPt), GetY(poly, nextPt));
614 }