4 // Class implementation. Nothing too inexplicable going on here. Fairly
5 // straightforward stuff.
8 // (C) 2004 Underground Software
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- ------------------------------------------------------------
14 // JLH ??/??/200? Created this file
15 // JLH 05/18/2004 Added pure point adding, inserting, better polygon handling
18 // Uncomment this for debugging...
21 #include "glyphpoints.h"
28 /*GlyphPoints::GlyphPoints(void)
30 GlyphPoints(0, 0, NULL, NULL, NULL, NULL);
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)
38 AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);
43 polyEnd = new uint16[numPolys];
44 polyEnd[0] = numPoints - 1;
47 WriteLogMsg("GlyphPoints: Default constructor. %u points, %u polys.\n", numPoints, numPolys);
52 GlyphPoints::GlyphPoints(int xx, int yy, bool oc)
54 //Hmm. What to do with this...?
55 AllocateAndCopy(1, 0, &xx, &yy, &oc, NULL);
57 WriteLogMsg("GlyphPoints: Single point constructor. %u points, %u polys.\n", numPoints, numPolys);
62 // Copy constructor (needed for deep copying)
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)
67 *this = c; // Use overloaded operator=
69 WriteLogMsg("GlyphPoints: Copy constructor. %u points, %u polys.\n", numPoints, numPolys);
74 GlyphPoints::~GlyphPoints()
76 FreeAllocatedMemory();
93 void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16 * pa)
95 numPoints = nPts, numPolys = nPlys;
99 x = new int[numPoints];
100 y = new int[numPoints];
101 onCurve = new bool[numPoints];
103 if (xa) // Copy points in if they're passed in...
104 for(int i=0; i<nPts; i++)
108 for(int i=0; i<nPts; i++)
112 for(int i=0; i<nPts; i++)
118 polyEnd = new uint16[numPolys];
120 if (pa) // Copy poly ends in if they're passed in...
121 for(int i=0; i<nPlys; i++)
127 void GlyphPoints::FreeAllocatedMemory(void)
143 GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)
146 return *this; // Take care of self-assignment
161 FreeAllocatedMemory();
162 AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);
168 // Add another GlyphPoints' points to this one...
170 GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)
172 int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;
174 int * totX = new int[totPoints];
175 int * totY = new int[totPoints];
176 bool * totOnCurve = new bool[totPoints];
177 uint16 * totPolyEnd = new uint16[totPolys];
179 for(int i=0; i<numPoints; i++)
183 totOnCurve[i] = onCurve[i];
186 for(int i=0; i<numPolys; i++)
187 totPolyEnd[i] = polyEnd[i];
189 for(int i=0; i<c.numPoints; i++)
191 totX[numPoints+i] = c.x[i];
192 totY[numPoints+i] = c.y[i];
193 totOnCurve[numPoints+i] = c.onCurve[i];
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...
200 GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);
210 // Add a point to this GlyphPoints...
212 GlyphPoints GlyphPoints::operator+(const IPoint &c)
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];
220 for(int i=0; i<numPoints; i++)
221 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
223 totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;
225 for(int i=0; i<numPolys; i++)
226 totPolyEnd[i] = polyEnd[i];
228 totPolyEnd[numPolys - 1]++; // Bump polygon's end point
229 GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);
239 GlyphPoints& GlyphPoints::operator+=(const IPoint &p)
241 InsertPoint(numPoints, p.x, p.y, p.onCurve);
247 void GlyphPoints::Clear(void)
249 FreeAllocatedMemory();
253 numPoints = numPolys = pointsAllocated = polysAllocated = 0;
257 void GlyphPoints::InsertPoint(uint16 pt, int xx, int yy, bool oc)
259 if (pt > numPoints) // > because we can insert at end...!
260 throw GP_OUT_OF_RANGE;
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];
267 for(int i=0; i<pt; i++)
268 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
270 for(int i=pt; i<numPoints; i++)
271 totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];
273 totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;
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
288 x = totX, y = totY, onCurve = totOnCurve;
292 void GlyphPoints::InsertPoint(uint16 pt, const IPoint &p)
294 InsertPoint(pt, p.x, p.y, p.onCurve);
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...
304 void GlyphPoints::DeletePoint(uint16 pt)
306 // Adjust polygon ends appropriately
307 uint16 poly = GetPoly(pt);
309 for(int i=poly; i<numPolys; i++)
312 //Need to check here if we're deleting the last point in the glyph or not.
314 if (GetNumPoints(poly) == 0 && numPoints > 0)
318 for(int i=poly; i<numPolys; i++)
319 polyEnd[i] = polyEnd[i + 1];
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
326 for(int i=pt; i<numPoints; i++)
327 x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];
331 uint16 GlyphPoints::GetNumPoints(void)
337 uint16 GlyphPoints::GetNumPoints(uint16 poly)
339 if (poly >= numPolys)
342 WriteLogMsg("Exception: GetNumPoints(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
344 throw GP_OUT_OF_RANGE;
349 return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);
353 uint16 GlyphPoints::GetNumPolys(void)
359 int GlyphPoints::GetX(uint16 pt)
364 WriteLogMsg("Exception: GetX(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
366 throw GP_OUT_OF_RANGE;
375 int GlyphPoints::GetY(uint16 pt)
380 WriteLogMsg("Exception: GetY(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
382 throw GP_OUT_OF_RANGE;
391 bool GlyphPoints::GetOnCurve(uint16 pt)
396 WriteLogMsg("Exception: GetOnCurve(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
398 throw GP_OUT_OF_RANGE;
407 int GlyphPoints::GetX(uint16 poly, uint16 pt)
409 if (pt >= GetNumPoints(poly))
412 WriteLogMsg("Exception: GetX(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
414 throw GP_OUT_OF_RANGE;
419 return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
423 int GlyphPoints::GetNextX(uint16 poly, uint16 pt)
425 return GetX(poly, GetNext(poly, pt));
429 int GlyphPoints::GetY(uint16 poly, uint16 pt)
431 if (pt >= GetNumPoints(poly))
434 WriteLogMsg("Exception: GetY(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
436 throw GP_OUT_OF_RANGE;
441 return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
445 int GlyphPoints::GetNextY(uint16 poly, uint16 pt)
447 return GetY(poly, GetNext(poly, pt));
451 IPoint GlyphPoints::GetPoint(uint16 poly, uint16 pt)
453 return IPoint(GetX(poly, pt), GetY(poly, pt));
457 bool GlyphPoints::GetOnCurve(uint16 poly, uint16 pt)
459 if (pt >= GetNumPoints(poly))
462 WriteLogMsg("Exception: GetOnCurve(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
464 throw GP_OUT_OF_RANGE;
469 return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
473 bool GlyphPoints::GetPrevOnCurve(uint16 poly, uint16 pt)
475 return GetOnCurve(poly, GetPrev(poly, pt));
479 bool GlyphPoints::GetNextOnCurve(uint16 poly, uint16 pt)
481 return GetOnCurve(poly, GetNext(poly, pt));
485 uint16 GlyphPoints::GetPolyStart(uint16 poly)
487 if (poly >= numPolys)
490 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
492 throw GP_OUT_OF_RANGE;
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);
502 uint16 GlyphPoints::GetPolyEnd(uint16 poly)
504 if (poly >= numPolys)
507 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
509 throw GP_OUT_OF_RANGE;
514 return polyEnd[poly];
518 void GlyphPoints::OffsetPoints(int xOff, int yOff)
520 for(int i=0; i<numPoints; i++)
521 x[i] += xOff, y[i] += yOff;
526 // Offset only a specific polygon in the glyph
528 void GlyphPoints::OffsetPoly(uint16 poly, int32 xOff, int32 yOff)
530 if (poly >= numPolys)
533 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
535 throw GP_OUT_OF_RANGE;
540 uint16 polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
542 for(int i=0; i<GetNumPoints(poly); i++)
543 x[polyStart + i] += xOff, y[polyStart + i] += yOff;
547 void GlyphPoints::ScalePoints(float sc)
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);
555 void GlyphPoints::SetXY(uint16 pt, int xx, int yy)
560 WriteLogMsg("Exception: SetXY(uint16, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
562 throw GP_OUT_OF_RANGE;
567 x[pt] = xx, y[pt] = yy;
571 void GlyphPoints::SetOnCurve(uint16 pt, bool oc)
576 WriteLogMsg("Exception: SetOnCurve(uint16, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
578 throw GP_OUT_OF_RANGE;
587 uint16 GlyphPoints::GetPrev(uint16 pt)
589 // pt = 7, polyEnd = 4, 9, 15
590 uint16 min = 0, max = numPoints - 1;
592 for(int i=0; i<numPolys; i++)
594 if (pt <= polyEnd[i])
597 min = polyEnd[i - 1] + 1;
604 uint16 retVal = pt - 1;
613 uint16 GlyphPoints::GetNext(uint16 pt)
615 uint16 min = 0, max = numPoints - 1;
617 for(int i=0; i<numPolys; i++)
619 if (pt <= polyEnd[i])
622 min = polyEnd[i - 1] + 1;
629 uint16 retVal = pt + 1;
639 // Get previous point for this polygon using wraparound.
640 // Note that pt is a zero-based index!
642 uint16 GlyphPoints::GetPrev(uint16 poly, uint16 pt)
644 return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);
649 // Get next point for this polygon using wraparound.
650 // Note that pt is a zero-based index!
652 uint16 GlyphPoints::GetNext(uint16 poly, uint16 pt)
654 return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);
658 uint16 GlyphPoints::GetPoly(uint16 pt)
663 WriteLogMsg("Exception: GetPoly(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
665 throw GP_OUT_OF_RANGE;
670 for(int i=0; i<numPolys; i++)
671 if (pt <= polyEnd[i])
678 void GlyphPoints::AddNewPolyAtEnd(void)
680 if (numPoints == 0) // By default, we already *have* a poly
683 uint16 * newPolyEnd = new uint16[numPolys + 1];
685 for(uint16 i=0; i<numPolys; i++)
686 newPolyEnd[i] = polyEnd[i];
688 newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];
691 polyEnd = newPolyEnd;
695 IPoint GlyphPoints::GetMidpointToPrev(uint16 poly, uint16 pt)
697 uint16 prev = GetPrev(poly, pt);
699 int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
700 int32 x2 = GetX(poly, prev), y2 = GetY(poly, prev);
702 return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
706 IPoint GlyphPoints::GetMidpointToNext(uint16 poly, uint16 pt)
708 uint16 next = GetNext(poly, pt);
710 int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
711 int32 x2 = GetX(poly, next), y2 = GetY(poly, next);
713 return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
717 IPoint GlyphPoints::GetPrevPoint(uint16 poly, uint16 pt)
719 uint16 prevPt = GetPrev(poly, pt);
721 return IPoint(GetX(poly, prevPt), GetY(poly, prevPt));
725 IPoint GlyphPoints::GetNextPoint(uint16 poly, uint16 pt)
727 uint16 nextPt = GetNext(poly, pt);
729 return IPoint(GetX(poly, nextPt), GetY(poly, nextPt));
734 // Rotate a point by "angle" around point "center"
736 IPoint GlyphPoints::RotatePoint(const double angle, const IPoint point, const IPoint center)
738 // Translate the point to the origin
739 double xt = (double)(point.x - center.x);
740 double yt = (double)(point.y - center.y);
742 // Rotate the point by angle
743 double xr = (xt * cos(angle)) - (yt * sin(angle));
744 double yr = (xt * sin(angle)) + (yt * cos(angle));
746 // Translate it back...
748 rotated.x = (int)(xr + 0.5) + center.x;
749 rotated.y = (int)(yr + 0.5) + center.y;
755 // Rotate all points in the glyph by "angle" around point "pt"
757 void GlyphPoints::RotatePoints(const double angle, const IPoint pt)
759 for(int i=0; i<numPoints; i++)
761 // Translate the point to the origin
762 double xt = (double)(x[i] - pt.x);
763 double yt = (double)(y[i] - pt.y);
765 // Rotate the point by angle
766 double xr = (xt * cos(angle)) - (yt * sin(angle));
767 double yr = (xt * sin(angle)) + (yt * cos(angle));
770 x[i] = (int)(xr + 0.5) + pt.x;
771 y[i] = (int)(yr + 0.5) + pt.y;
776 IPoint GlyphPoints::GetPolyCentroid(const int16 poly)
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)
783 // if (poly >= numPolys)
786 //WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
788 // throw GP_OUT_OF_RANGE;
793 IPoint centroid; // Initializes to (0, 0)
794 uint16 numPointsInPoly = GetNumPoints(poly);
796 for(uint16 i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
802 centroid.x /= numPointsInPoly;
803 centroid.y /= numPointsInPoly;
809 void GlyphPoints::RotatePolyAroundCentroid(const int16 poly, const double angle)
811 if (poly >= numPolys)
814 IPoint centroid = GetPolyCentroid(poly);
816 for(uint16 i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
818 IPoint rotated = RotatePoint(angle, IPoint(x[i], y[i]), centroid);
825 // really need to do checking on the results from fscanf...
826 bool GlyphPoints::LoadGlyphFromFile(FILE * file)
831 FreeAllocatedMemory();
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];
839 for(int i=0; i<numPoints; i++)
841 fscanf(file, "%d %d %s", &x[i], &y[i], &line);
842 onCurve[i] = (line[0] == 'T' ? true : false);
845 fscanf(file, "%s %u", line, &numPolys);
846 polyEnd = new uint16[numPolys];
848 for(int i=0; i<numPolys; i++)
850 fscanf(file, "%u", &polyEnd[i]);
857 bool GlyphPoints::SaveGlyphToFile(FILE * file)
859 // GlyphPoints glyph = editWnd->pts;
860 fprintf(file, "TTEGLYPH V1.0\n");
861 fprintf(file, "POINTS %u\n", numPoints);
863 for(int i=0; i<numPoints; i++)
865 fprintf(file, "%d %d %s\n", x[i], y[i], (onCurve[i] ? "T" : "F"));
868 fprintf(file, "POLYS %u\n", numPolys);
870 for(int i=0; i<numPolys; i++)
872 fprintf(file, "%u\n", polyEnd[i]);