static FskErr DashNextSegment(DashBuddy *db, const FskFixedPoint2D *pt) { FskErr err; FskFixedPoint2D q; FskFixedVector2D v; FskFixed segPhase, endPhase, deltaPhase; FskFract t; UInt32 i; q = db->lastPt; /* Point of last state change */ v.x = pt->x - db->lastPt.x; v.y = pt->y - db->lastPt.y; /* Vector along the line segment */ segPhase = FskFixedHypot(FskFixedDotProduct2D(&v, db->dashBasis+0), FskFixedDotProduct2D(&v, db->dashBasis+1)); /* Phase delta for this segment (Riemannian metric) */ endPhase = db->dashPhase + segPhase; /* Phase at end of this line segment */ while (db->thisPhaseSegment[1] <= endPhase) { /* We know that we're going to cross a dash segment */ deltaPhase = db->thisPhaseSegment[1] - db->dashPhase; /* Phase change since the last state change */ t = FskFracDiv(deltaPhase, segPhase); q.x += FskFracMul(t, v.x); q.y += FskFracMul(t, v.y); /* Compute location of next transition */ if ((i = FskGrowableArrayGetItemCount(db->ptArray)) > 0) DrawDashSegment(db, &q); /* ON transitioning to OFF: end and draw this dash segment */ else (void)FskGrowableArrayAppendItem(db->ptArray, &q); /* OFF transition to ON: add the start point */ if (++(db->thisPhaseSegment) >= db->resetSegmentPhase) { /* Advance phase segment... */ db->thisPhaseSegment = db->dashSegmentPhases; /* ... and reset if at the end of the phase period */ endPhase -= db->dashPeriod; /* The end is getting closer */ } db->dashPhase = db->thisPhaseSegment[0]; /* Set the phase */ } /* The end is still within the same dash segment */ if ((i = FskGrowableArrayGetItemCount(db->ptArray)) > 0) err = FskGrowableArrayAppendItem(db->ptArray, pt); /* In the ON state: add a kink point */ else err = kFskErrNone; /* In the OFF state */ db->dashPhase = endPhase; /* Update the phase */ db->lastPt = *pt; return err; }
static FskErr BeveledJoin(const LineSeg *seg0, const LineSeg *seg1, FskGrowableFixedPoint2DArray fwdPoly, FskGrowableFixedPoint2DArray revPoly) { FskErr err = kFskErrNone; FskFract sinAng, cosAng, snmHaf, sinHaf, cosHaf; FskFixed bevHafWidth, mitLength, maxElbow; FskFractVector2D u; FskFixedVector2D b, c, e; FskFixedPoint2D p[3]; sinAng = FskFractCrossProduct2D(&seg0->par, &seg1->par); /* Sine of change in trajectory */ if (sinAng == 0) /* Collinear */ goto bail; /* All done */ cosAng = FskFractDotProduct(&seg0->par.x, &seg1->par.x, 2); /* Cosine of change in trajectory */ if (cosAng > FRACT_ONE) cosAng = FRACT_ONE; else if (cosAng < -FRACT_ONE) cosAng = -FRACT_ONE; cosHaf = FskFracSqrt(FRACT_HALF - (cosAng >> 1)); /* Cosine of half the subtended angle */ snmHaf = FskFracSqrt(FRACT_HALF + (cosAng >> 1)); /* Sine of half the subtended angle */ if (snmHaf != 0) { sinHaf = snmHaf; if (sinAng < 0) sinHaf = -sinHaf; u.x = FskFixedNLinear2D(seg0->par.x, cosHaf, seg0->par.y, sinHaf, 30); /* Unit vector to elbow, inside or outside */ u.y = FskFixedNLinear2D(seg0->par.y, cosHaf, -seg0->par.x, sinHaf, 30); bevHafWidth = (FskFixed)(((FskInt64)(seg0->strokeWidth) * cosHaf / (FRACT_ONE + snmHaf) + 1) >> 1); c.x = FskFixedNMul(seg0->strokeWidth, u.x, 31); /* Midpoint of bevel */ c.y = FskFixedNMul(seg0->strokeWidth, u.y, 31); b.x = FskFracMul(bevHafWidth, -u.y); /* Half-vector of bevel */ b.y = FskFracMul(bevHafWidth, u.x); mitLength = FskFixedNDiv(seg0->strokeWidth, snmHaf, 29); if ((maxElbow = (seg0->strokeWidth)) < seg0->length) /* Limit the extent of the inside bevel joint */ maxElbow = seg0->length; if (maxElbow < seg1->length) maxElbow = seg1->length; if (mitLength > maxElbow) mitLength = maxElbow; e.x = FskFracMul(mitLength, u.x); /* Scaled vector to elbow, inside */ e.y = FskFracMul(mitLength, u.y); if (sinAng > 0) { /* Positive rotation */ p[0].x = seg0->pt[1].x + c.x - b.x; /* First bevel point */ p[0].y = seg0->pt[1].y + c.y - b.y; p[1].x = seg0->pt[1].x + c.x + b.x; /* Second bevel point */ p[1].y = seg0->pt[1].y + c.y + b.y; p[2].x = seg0->pt[1].x - e.x; /* Inside elbow */ p[2].y = seg0->pt[1].y - e.y; BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItems(revPoly, &p[0], 2)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItem( fwdPoly, &p[2])); } else { /* Negative rotation */ p[0].x = seg0->pt[1].x + c.x + b.x; /* First bevel point */ p[0].y = seg0->pt[1].y + c.y + b.y; p[1].x = seg0->pt[1].x + c.x - b.x; /* Second bevel point */ p[1].y = seg0->pt[1].y + c.y - b.y; p[2].x = seg0->pt[1].x - e.x; /* Inside elbow */ p[2].y = seg0->pt[1].y - e.y; BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItems(fwdPoly, &p[0], 2)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItem( revPoly, &p[2])); } }
static FskErr RoundedJoin(const LineSeg *seg0, const LineSeg *seg1, FskGrowableFixedPoint2DArray fwdPoly, FskGrowableFixedPoint2DArray revPoly) { FskErr err = kFskErrNone; FskFract sinAng, cosAng, snmHaf, sinHaf, cosHaf; FskFixed mitLength, maxElbow; FskFractVector2D u; FskFixedVector2D v0, v1, e; FskFixedPoint2D p[4]; sinAng = FskFractCrossProduct2D(&seg0->par, &seg1->par); /* Sine of change in trajectory */ if (sinAng == 0) /* Collinear */ goto bail; /* All done */ cosAng = FskFractDotProduct(&seg0->par.x, &seg1->par.x, 2); /* Cosine of change in trajectory */ if (cosAng > FRACT_ONE) cosAng = FRACT_ONE; else if (cosAng < -FRACT_ONE) cosAng = -FRACT_ONE; cosHaf = FskFracSqrt(FRACT_HALF - (cosAng >> 1)); /* Cosine of half the subtended angle */ snmHaf = FskFracSqrt(FRACT_HALF + (cosAng >> 1)); /* Sine of half the subtended angle */ if (snmHaf != 0) { sinHaf = snmHaf; if (sinAng < 0) sinHaf = -sinHaf; v0.x = FskFixedNMul(seg0->perp.x, seg0->strokeWidth, 31); /* Perpendicular excursion from seg0 */ v0.y = FskFixedNMul(seg0->perp.y, seg0->strokeWidth, 31); v1.x = FskFixedNMul(seg1->perp.x, seg0->strokeWidth, 31); /* Perpendicular excursion from seg1 */ v1.y = FskFixedNMul(seg1->perp.y, seg0->strokeWidth, 31); u.x = FskFixedNLinear2D(seg0->par.x, cosHaf, seg0->par.y, sinHaf, 30); /* Unit vector to elbow, inside or outside */ u.y = FskFixedNLinear2D(seg0->par.y, cosHaf, -seg0->par.x, sinHaf, 30); mitLength = FskFixedNDiv(seg0->strokeWidth, snmHaf, 29); if ((maxElbow = (seg0->strokeWidth)) < seg0->length) /* Limit the extent of the inside bevel joint */ maxElbow = seg0->length; if (maxElbow < seg1->length) maxElbow = seg1->length; if (mitLength > maxElbow) mitLength = maxElbow; e.x = FskFracMul(mitLength, u.x); /* Scaled vector to elbow, inside */ e.y = FskFracMul(mitLength, u.y); if (sinAng > 0) { /* Positive rotation */ p[0].x = seg0->pt[1].x - v0.x; /* Start of arc */ p[0].y = seg0->pt[1].y - v0.y; p[2].x = seg0->pt[1].x - v1.x; /* End of arc */ p[2].y = seg0->pt[1].y - v1.y; p[1].x = seg0->pt[1].x + e.x; /* Outside elbow point */ p[1].y = seg0->pt[1].y + e.y; p[3].x = seg0->pt[1].x - e.x; /* Inside elbow point */ p[3].y = seg0->pt[1].y - e.y; BAIL_IF_ERR(err = FskTessellateRationalBezier2DRegularly(&p[0], &p[1], &snmHaf, 3, NULL, revPoly)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItem(fwdPoly, &p[3])); } else { /* Negative rotation */ p[0].x = seg0->pt[1].x + v0.x; /* Start of arc */ p[0].y = seg0->pt[1].y + v0.y; p[2].x = seg0->pt[1].x + v1.x; /* End of arc */ p[2].y = seg0->pt[1].y + v1.y; p[1].x = seg0->pt[1].x + e.x; /* Outside elbow point */ p[1].y = seg0->pt[1].y + e.y; p[3].x = seg0->pt[1].x - e.x; /* Inside elbow point */ p[3].y = seg0->pt[1].y - e.y; BAIL_IF_ERR(err = FskTessellateRationalBezier2DRegularly(&p[0], &p[1], &snmHaf, 3, NULL, fwdPoly)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItem(revPoly, &p[3])); } } /* else 0 degrees subtended (180 degree about face): what to do? */ bail: return err; }