float SubtractDirectionCW(float fDst, float fSrc) { fSrc = NormalizeDirection(fSrc); fDst = NormalizeDirection(fDst); float fDelta = fDst - fSrc; if (fDelta > 0.0f) fDelta -= D3DX_PI * 2.0f; return fDelta; }
// Desc: // if abs(fSrc - fDst) < fClamp, return fSrc, else return fDst - fClamp float ClampDirectionCW(float fDst, float fSrc, float fClamp) { float fResult = fSrc; float fDelta = SubtractDirectionCW(fDst, fSrc); if (fDelta < -fClamp) fResult = fDst + fClamp; fResult = NormalizeDirection(fResult); return fResult; }
// Gathers outline points and their directions from start_index into dirs by // stepping along the outline and normalizing the coordinates until the // required feature_length has been collected or end_index is reached. // On input pos must point to the position corresponding to start_index and on // return pos is updated to the current raw position, and pos_normed is set to // the normed version of pos. // Since directions wrap-around, they need special treatment to get the mean. // Provided the cluster of directions doesn't straddle the wrap-around point, // the simple mean works. If they do, then, unless the directions are wildly // varying, the cluster rotated by 180 degrees will not straddle the wrap- // around point, so mean(dir + 180 degrees) - 180 degrees will work. Since // LLSQ conveniently stores the mean of 2 variables, we use it to store // dir and dir+128 (128 is 180 degrees) and then use the resulting mean // with the least variance. static int GatherPoints(const C_OUTLINE* outline, double feature_length, const DENORM& denorm, const DENORM* root_denorm, int start_index, int end_index, ICOORD* pos, FCOORD* pos_normed, LLSQ* points, LLSQ* dirs) { int step_length = outline->pathlength(); ICOORD step = outline->step(start_index % step_length); // Prev_normed is the start point of this collection and will be set on the // first iteration, and on later iterations used to determine the length // that has been collected. FCOORD prev_normed; points->clear(); dirs->clear(); int num_points = 0; int index; for (index = start_index; index <= end_index; ++index, *pos += step) { step = outline->step(index % step_length); int edge_weight = outline->edge_strength_at_index(index % step_length); if (edge_weight == 0) { // This point has conflicting gradient and step direction, so ignore it. continue; } // Get the sub-pixel precise location and normalize. FCOORD f_pos = outline->sub_pixel_pos_at_index(*pos, index % step_length); denorm.NormTransform(root_denorm, f_pos, pos_normed); if (num_points == 0) { // The start of this segment. prev_normed = *pos_normed; } else { FCOORD offset = *pos_normed - prev_normed; float length = offset.length(); if (length > feature_length) { // We have gone far enough from the start. We will use this point in // the next set so return what we have so far. return index; } } points->add(pos_normed->x(), pos_normed->y(), edge_weight); int direction = outline->direction_at_index(index % step_length); if (direction >= 0) { direction = NormalizeDirection(direction, f_pos, denorm, root_denorm); // Use both the direction and direction +128 so we are not trying to // take the mean of something straddling the wrap-around point. dirs->add(direction, Modulo(direction + 128, 256)); } ++num_points; } return index; }
float CloseToDirectionCW(float fDst, float fSrc, float fStep) { float fResult = fDst; float fDelta = SubtractDirectionCW(fDst, fSrc); if (abs(fDelta) > FLT_EPSILON) { if (fDelta < -fStep) fResult = fSrc - fStep; fResult = NormalizeDirection(fResult); } return fResult; }
float InterpolateDirectionCW(float fDst, float fSrc, float fRatio) { float fDelta = SubtractDirectionCW(fDst, fSrc); float fResult = NormalizeDirection(fDelta * fRatio + fSrc); return fResult; }