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