/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file.
*/ #include"src/core/SkStrokerPriv.h"
static AngleType Dot2AngleType(SkScalar dot) { // need more precise fixed normalization // SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero);
if (dot >= 0) { // shallow or line return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType;
} else { // sharp or 180 return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType;
}
}
staticvoid HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after) { #if 1 /* In the degenerate case that the stroke radius is larger than our segments just connecting the two inner segments may "show through" as a funny diagonal. To pseudo-fix this, we go through the pivot point. This adds an extra point/edge, but I can't see a cheap way to know when this is not needed :(
*/
inner->lineTo(pivot.fX, pivot.fY); #endif
SkVector before = beforeUnitNormal;
SkVector after = afterUnitNormal;
SkRotationDirection dir = kCW_SkRotationDirection;
if (!is_clockwise(before, after)) { using std::swap;
swap(outer, inner);
before.negate();
after.negate();
dir = kCCW_SkRotationDirection;
}
SkMatrix matrix;
matrix.setScale(radius, radius);
matrix.postTranslate(pivot.fX, pivot.fY);
SkConic conics[SkConic::kMaxConicsForArc]; int count = SkConic::BuildUnitArc(before, after, dir, &matrix, conics); if (count > 0) { for (int i = 0; i < count; ++i) {
outer->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
}
after.scale(radius);
HandleInnerJoin(inner, pivot, after);
}
}
#define kOneOverSqrt2 (0.707106781f)
staticvoid MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal, const SkPoint& pivot, const SkVector& afterUnitNormal,
SkScalar radius, SkScalar invMiterLimit, bool prevIsLine, bool currIsLine) { // negate the dot since we're using normals instead of tangents
SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
AngleType angleType = Dot2AngleType(dotProd);
SkVector before = beforeUnitNormal;
SkVector after = afterUnitNormal;
SkVector mid;
SkScalar sinHalfAngle; bool ccw;
if (angleType == kNearlyLine_AngleType) { return;
} if (angleType == kNearly180_AngleType) {
currIsLine = false; goto DO_BLUNT;
}
ccw = !is_clockwise(before, after); if (ccw) { using std::swap;
swap(outer, inner);
before.negate();
after.negate();
}
/* Before we enter the world of square-roots and divides, check if we're trying to join an upright right angle (common case for stroking rectangles). If so, special case that (for speed an accuracy). Note: we only need to check one normal if dot==0
*/ if (0 == dotProd && invMiterLimit <= kOneOverSqrt2) {
mid = (before + after) * radius; goto DO_MITER;
}
/* midLength = radius / sinHalfAngle if (midLength > miterLimit * radius) abort if (radius / sinHalf > miterLimit * radius) abort if (1 / sinHalf > miterLimit) abort if (1 / miterLimit > sinHalf) abort My dotProd is opposite sign, since it is built from normals and not tangents hence 1 + dot instead of 1 - dot in the formula
*/
sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd)); if (sinHalfAngle < invMiterLimit) {
currIsLine = false; goto DO_BLUNT;
}
// choose the most accurate way to form the initial mid-vector if (angleType == kSharp_AngleType) {
mid.set(after.fY - before.fY, before.fX - after.fX); if (ccw) {
mid.negate();
}
} else {
mid.set(before.fX + after.fX, before.fY + after.fY);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.