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_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)
38 AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);
43 polyEnd = new uint16_t[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();
80 void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16_t * pa)
82 numPoints = nPts, numPolys = nPlys;
86 x = new int[numPoints];
87 y = new int[numPoints];
88 onCurve = new bool[numPoints];
90 if (xa) // Copy points in if they're passed in...
91 for(int i=0; i<nPts; i++)
95 for(int i=0; i<nPts; i++)
99 for(int i=0; i<nPts; i++)
105 polyEnd = new uint16_t[numPolys];
107 if (pa) // Copy poly ends in if they're passed in...
108 for(int i=0; i<nPlys; i++)
114 void GlyphPoints::FreeAllocatedMemory(void)
130 GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)
133 return *this; // Take care of self-assignment
135 FreeAllocatedMemory();
136 AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);
142 // Add another GlyphPoints' points to this one...
144 GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)
146 int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;
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];
153 for(int i=0; i<numPoints; i++)
157 totOnCurve[i] = onCurve[i];
160 for(int i=0; i<numPolys; i++)
161 totPolyEnd[i] = polyEnd[i];
163 for(int i=0; i<c.numPoints; i++)
165 totX[numPoints+i] = c.x[i];
166 totY[numPoints+i] = c.y[i];
167 totOnCurve[numPoints+i] = c.onCurve[i];
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...
174 GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);
184 // Add a point to this GlyphPoints...
186 GlyphPoints GlyphPoints::operator+(const IPoint &c)
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];
194 for(int i=0; i<numPoints; i++)
195 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
197 totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;
199 for(int i=0; i<numPolys; i++)
200 totPolyEnd[i] = polyEnd[i];
202 totPolyEnd[numPolys - 1]++; // Bump polygon's end point
203 GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);
213 GlyphPoints& GlyphPoints::operator+=(const IPoint &p)
215 InsertPoint(numPoints, p.x, p.y, p.onCurve);
221 void GlyphPoints::Clear(void)
223 FreeAllocatedMemory();
227 numPoints = numPolys = pointsAllocated = polysAllocated = 0;
230 polyEnd = new uint16_t[numPolys];
231 polyEnd[0] = numPoints - 1;
235 void GlyphPoints::InsertPoint(uint16_t pt, int xx, int yy, bool oc)
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;
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];
246 for(int i=0; i<pt; i++)
247 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
249 for(int i=pt; i<numPoints; i++)
250 totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];
252 totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;
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
266 x = totX, y = totY, onCurve = totOnCurve;
270 void GlyphPoints::InsertPoint(uint16_t pt, const IPoint &p)
272 InsertPoint(pt, p.x, p.y, p.onCurve);
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...
282 void GlyphPoints::DeletePoint(uint16_t pt)
284 // Adjust polygon ends appropriately
285 uint16_t poly = GetPoly(pt);
287 for(int i=poly; i<numPolys; i++)
290 //Need to check here if we're deleting the last point in the glyph or not.
292 if (GetNumPoints(poly) == 0 && numPoints > 0)
296 for(int i=poly; i<numPolys; i++)
297 polyEnd[i] = polyEnd[i + 1];
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
304 for(int i=pt; i<numPoints; i++)
305 x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];
309 uint16_t GlyphPoints::GetNumPoints(void)
315 uint16_t GlyphPoints::GetNumPoints(uint16_t poly)
317 if (poly >= numPolys)
320 WriteLogMsg("Exception: GetNumPoints(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
322 throw GP_OUT_OF_RANGE;
327 return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);
331 uint16_t GlyphPoints::GetNumPolys(void)
337 int GlyphPoints::GetX(uint16_t pt)
342 WriteLogMsg("Exception: GetX(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
344 throw GP_OUT_OF_RANGE;
353 int GlyphPoints::GetY(uint16_t pt)
358 WriteLogMsg("Exception: GetY(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
360 throw GP_OUT_OF_RANGE;
369 Vector GlyphPoints::GetXY(uint16_t pt)
374 WriteLogMsg("Exception: GetXY(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
376 throw GP_OUT_OF_RANGE;
381 return Vector(x[pt], y[pt]);
385 bool GlyphPoints::GetOnCurve(uint16_t pt)
390 WriteLogMsg("Exception: GetOnCurve(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
392 throw GP_OUT_OF_RANGE;
401 int GlyphPoints::GetX(uint16_t poly, uint16_t pt)
403 if (pt >= GetNumPoints(poly))
406 WriteLogMsg("Exception: GetX(uint16_t, uint16_t). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
408 throw GP_OUT_OF_RANGE;
413 return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
417 int GlyphPoints::GetNextX(uint16_t poly, uint16_t pt)
419 return GetX(poly, GetNext(poly, pt));
423 int GlyphPoints::GetY(uint16_t poly, uint16_t pt)
425 if (pt >= GetNumPoints(poly))
428 WriteLogMsg("Exception: GetY(uint16_t, uint16_t). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
430 throw GP_OUT_OF_RANGE;
435 return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
439 int GlyphPoints::GetNextY(uint16_t poly, uint16_t pt)
441 return GetY(poly, GetNext(poly, pt));
445 IPoint GlyphPoints::GetPoint(uint16_t poly, uint16_t pt)
447 return IPoint(GetX(poly, pt), GetY(poly, pt), GetOnCurve(poly, pt));
451 IPoint GlyphPoints::GetPoint(uint16_t pointNumber)
453 if (pointNumber > numPoints)
454 throw GP_OUT_OF_RANGE;
456 return IPoint(x[pointNumber], y[pointNumber], onCurve[pointNumber]);
460 bool GlyphPoints::GetOnCurve(uint16_t poly, uint16_t pt)
462 if (pt >= GetNumPoints(poly))
465 WriteLogMsg("Exception: GetOnCurve(uint16_t, uint16_t). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
467 throw GP_OUT_OF_RANGE;
472 return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
476 bool GlyphPoints::GetPrevOnCurve(uint16_t poly, uint16_t pt)
478 return GetOnCurve(poly, GetPrev(poly, pt));
482 bool GlyphPoints::GetNextOnCurve(uint16_t poly, uint16_t pt)
484 return GetOnCurve(poly, GetNext(poly, pt));
488 uint16_t GlyphPoints::GetPolyStart(uint16_t poly)
490 if (poly >= numPolys)
493 WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
495 throw GP_OUT_OF_RANGE;
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);
505 uint16_t GlyphPoints::GetPolyEnd(uint16_t poly)
507 if (poly >= numPolys)
510 WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
512 throw GP_OUT_OF_RANGE;
517 return polyEnd[poly];
521 void GlyphPoints::OffsetPoints(int xOff, int yOff)
523 for(int i=0; i<numPoints; i++)
524 x[i] += xOff, y[i] += yOff;
529 // Offset only a specific polygon in the glyph
531 void GlyphPoints::OffsetPoly(uint16_t poly, int32_t xOff, int32_t yOff)
533 if (poly >= numPolys)
536 WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
538 throw GP_OUT_OF_RANGE;
543 uint16_t polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
545 for(int i=0; i<GetNumPoints(poly); i++)
546 x[polyStart + i] += xOff, y[polyStart + i] += yOff;
550 void GlyphPoints::ScalePoints(float sc)
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);
558 void GlyphPoints::SetXY(uint16_t pt, int xx, int yy)
563 WriteLogMsg("Exception: SetXY(uint16_t, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
565 throw GP_OUT_OF_RANGE;
570 x[pt] = xx, y[pt] = yy;
574 void GlyphPoints::SetOnCurve(uint16_t pt, bool oc)
579 WriteLogMsg("Exception: SetOnCurve(uint16_t, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
581 throw GP_OUT_OF_RANGE;
590 void GlyphPoints::SetPoint(const uint16_t pointNum, const IPoint point)
592 if (pointNum >= numPoints)
595 WriteLogMsg("Exception: SetPoint(uint16_t, IPoint). pt=%u, numPoints=%u\xD\xA", pointNum, numPoints);
597 throw GP_OUT_OF_RANGE;
602 x[pointNum] = point.x, y[pointNum] = point.y, onCurve[pointNum] = point.onCurve;
606 uint16_t GlyphPoints::GetPrev(uint16_t pt)
608 // pt = 7, polyEnd = 4, 9, 15
609 uint16_t min = 0, max = numPoints - 1;
611 for(int i=0; i<numPolys; i++)
613 if (pt <= polyEnd[i])
616 min = polyEnd[i - 1] + 1;
623 uint16_t retVal = pt - 1;
632 uint16_t GlyphPoints::GetNext(uint16_t pt)
634 uint16_t min = 0, max = numPoints - 1;
636 for(int i=0; i<numPolys; i++)
638 if (pt <= polyEnd[i])
641 min = polyEnd[i - 1] + 1;
648 uint16_t retVal = pt + 1;
658 // Get previous point for this polygon using wraparound.
659 // Note that pt is a zero-based index!
661 uint16_t GlyphPoints::GetPrev(uint16_t poly, uint16_t pt)
663 return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);
668 // Get next point for this polygon using wraparound.
669 // Note that pt is a zero-based index!
671 uint16_t GlyphPoints::GetNext(uint16_t poly, uint16_t pt)
673 return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);
677 #warning "!!! This function returns incorrect results !!!"
678 uint16_t GlyphPoints::GetPoly(uint16_t pt)
683 WriteLogMsg("Exception: GetPoly(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
685 throw GP_OUT_OF_RANGE;
690 for(int i=0; i<numPolys; i++)
691 if (pt <= polyEnd[i])
698 void GlyphPoints::AddNewPolyAtEnd(void)
700 if (numPoints == 0) // By default, we already *have* a poly
703 uint16_t * newPolyEnd = new uint16_t[numPolys + 1];
705 for(uint16_t i=0; i<numPolys; i++)
706 newPolyEnd[i] = polyEnd[i];
708 newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];
711 polyEnd = newPolyEnd;
715 IPoint GlyphPoints::GetMidpointToPrev(uint16_t poly, uint16_t pt)
717 uint16_t prev = GetPrev(poly, pt);
719 int32_t x1 = GetX(poly, pt), y1 = GetY(poly, pt);
720 int32_t x2 = GetX(poly, prev), y2 = GetY(poly, prev);
722 return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
726 IPoint GlyphPoints::GetMidpointToNext(uint16_t poly, uint16_t pt)
728 uint16_t next = GetNext(poly, pt);
730 int32_t x1 = GetX(poly, pt), y1 = GetY(poly, pt);
731 int32_t x2 = GetX(poly, next), y2 = GetY(poly, next);
733 return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
737 IPoint GlyphPoints::GetPrevPoint(uint16_t poly, uint16_t pt)
739 uint16_t prevPt = GetPrev(poly, pt);
741 return IPoint(GetX(poly, prevPt), GetY(poly, prevPt), GetOnCurve(poly, prevPt));
745 IPoint GlyphPoints::GetNextPoint(uint16_t poly, uint16_t pt)
747 uint16_t nextPt = GetNext(poly, pt);
749 return IPoint(GetX(poly, nextPt), GetY(poly, nextPt), GetOnCurve(poly, nextPt));
753 uint16_t GlyphPoints::GetPolyForPoint(IPoint point)
757 for(uint16_t i=0; i<numPoints; i++)
759 if (i > polyEnd[poly])
762 if (IPoint(x[i], y[i]) == point)
770 uint16_t GlyphPoints::GetPolyForPointNumber(uint16_t pointNumber)
772 // If there's only one poly, we know where the point is...
776 // Otherwise, do a linear search through the polys to find the right one
777 for(uint16_t i=0; i<numPolys; i++)
779 if (pointNumber >= GetPolyStart(i) && pointNumber <= polyEnd[i])
788 // Rotate a point by "angle" around point "center"
790 IPoint GlyphPoints::RotatePoint(const double angle, const IPoint point, const IPoint center)
792 // Translate the point to the origin
793 double xt = (double)(point.x - center.x);
794 double yt = (double)(point.y - center.y);
796 // Rotate the point by angle
797 double xr = (xt * cos(angle)) - (yt * sin(angle));
798 double yr = (xt * sin(angle)) + (yt * cos(angle));
800 // Translate it back...
802 rotated.x = (int)(xr + 0.5) + center.x;
803 rotated.y = (int)(yr + 0.5) + center.y;
809 // Rotate all points in the glyph by "angle" around point "pt"
811 void GlyphPoints::RotatePoints(const double angle, const IPoint pt)
813 for(int i=0; i<numPoints; i++)
815 // Translate the point to the origin
816 double xt = (double)(x[i] - pt.x);
817 double yt = (double)(y[i] - pt.y);
819 // Rotate the point by angle
820 double xr = (xt * cos(angle)) - (yt * sin(angle));
821 double yr = (xt * sin(angle)) + (yt * cos(angle));
824 x[i] = (int)(xr + 0.5) + pt.x;
825 y[i] = (int)(yr + 0.5) + pt.y;
830 IPoint GlyphPoints::GetPolyCentroid(const int16_t poly)
832 // We should throw an exception here, but meh
833 // (this actually short circuits the exception handling in all the GetPolyXXX() functions)
835 if (poly >= numPolys)
836 throw GP_OUT_OF_RANGE;
837 // return IPoint(0, 0);
839 // if (poly >= numPolys)
842 //WriteLogMsg("Exception: GetPolyEnd(uint16_t). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
844 // throw GP_OUT_OF_RANGE;
849 IPoint centroid; // Initializes to (0, 0)
850 uint16_t numPointsInPoly = GetNumPoints(poly);
852 for(uint16_t i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
858 centroid.x /= numPointsInPoly;
859 centroid.y /= numPointsInPoly;
865 void GlyphPoints::RotatePolyAroundCentroid(const int16_t poly, const double angle)
867 if (poly >= numPolys)
870 IPoint centroid = GetPolyCentroid(poly);
872 for(uint16_t i=GetPolyStart(poly); i<=GetPolyEnd(poly); i++)
874 IPoint rotated = RotatePoint(angle, IPoint(x[i], y[i]), centroid);
881 void GlyphPoints::InvertPolyDrawSequence(const uint16_t poly)
883 if (poly >= numPolys)
884 throw GP_OUT_OF_RANGE;
886 uint16_t pointNum1 = GetPolyStart(poly);
887 uint16_t pointNum2 = GetPolyEnd(poly);
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++)
894 IPoint point1 = GetPoint(pointNum1 + i);
895 IPoint point2 = GetPoint(pointNum2 - i);
896 SetPoint(pointNum2 - i, point1);
897 SetPoint(pointNum1 + i, point2);
902 // really need to do checking on the results from fscanf...
903 bool GlyphPoints::LoadGlyphFromFile(FILE * file)
908 FreeAllocatedMemory();
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];
916 for(int i=0; i<numPoints; i++)
918 fscanf(file, "%d %d %s", &x[i], &y[i], (char *)&line);
919 onCurve[i] = (line[0] == 'T' ? true : false);
922 fscanf(file, "%s %u", line, &numPolys);
923 polyEnd = new uint16_t[numPolys];
925 for(int i=0; i<numPolys; i++)
927 fscanf(file, "%u", &polyEnd[i]);
934 bool GlyphPoints::SaveGlyphToFile(FILE * file)
936 // GlyphPoints glyph = editWnd->pts;
937 fprintf(file, "TTEGLYPH V1.0\n");
938 fprintf(file, "POINTS %u\n", numPoints);
940 for(int i=0; i<numPoints; i++)
942 fprintf(file, "%d %d %s\n", x[i], y[i], (onCurve[i] ? "T" : "F"));
945 fprintf(file, "POLYS %u\n", numPolys);
947 for(int i=0; i<numPolys; i++)
949 fprintf(file, "%u\n", polyEnd[i]);