add SkPoint::CanNormalize to unify decisions about when a vector is degenerate
git-svn-id: http://skia.googlecode.com/svn/trunk@2236 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
11f6380510
commit
55b5f4bd6a
@ -199,6 +199,16 @@ struct SK_API SkPoint {
|
||||
SkScalar length() const { return SkPoint::Length(fX, fY); }
|
||||
SkScalar distanceToOrigin() const { return this->length(); }
|
||||
|
||||
/**
|
||||
* Return true if the computed length of the vector is >= the internal
|
||||
* tolerance (used to avoid dividing by tiny values).
|
||||
*/
|
||||
static bool CanNormalize(SkScalar dx, SkScalar dy);
|
||||
|
||||
bool canNormalize() const {
|
||||
return CanNormalize(fX, fY);
|
||||
}
|
||||
|
||||
/** Set the point (vector) to be unit-length in the same direction as it
|
||||
already points. If the point has a degenerate length (i.e. nearly 0)
|
||||
then return false and do nothing; otherwise return true.
|
||||
@ -317,7 +327,8 @@ struct SK_API SkPoint {
|
||||
static SkScalar Length(SkScalar x, SkScalar y);
|
||||
|
||||
/** Normalize pt, returning its previous length. If the prev length is too
|
||||
small (degenerate), return 0 and leave pt unchanged.
|
||||
small (degenerate), return 0 and leave pt unchanged. This uses the same
|
||||
tolerance as CanNormalize.
|
||||
|
||||
Note that this method may be significantly more expensive than
|
||||
the non-static normalize(), because it has to return the previous length
|
||||
|
@ -100,16 +100,21 @@ SkScalar SkPoint::Normalize(SkPoint* pt) {
|
||||
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
|
||||
bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
|
||||
float mag2 = dx * dx + dy * dy;
|
||||
return mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero;
|
||||
}
|
||||
|
||||
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
|
||||
return sk_float_sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
bool SkPoint::setLength(float x, float y, float length) {
|
||||
float mag = sk_float_sqrt(x * x + y * y);
|
||||
if (mag > SK_ScalarNearlyZero) {
|
||||
length /= mag;
|
||||
fX = x * length;
|
||||
fY = y * length;
|
||||
float mag2 = x * x + y * y;
|
||||
if (mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero) {
|
||||
float scale = length / sk_float_sqrt(mag2);
|
||||
fX = x * scale;
|
||||
fY = y * scale;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -119,6 +124,23 @@ bool SkPoint::setLength(float x, float y, float length) {
|
||||
|
||||
#include "Sk64.h"
|
||||
|
||||
bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
|
||||
Sk64 tmp1, tmp2, tolSqr;
|
||||
|
||||
tmp1.setMul(dx, dx);
|
||||
tmp2.setMul(dy, dy);
|
||||
tmp1.add(tmp2);
|
||||
|
||||
// we want nearlyzero^2, but to compute it fast we want to just do a
|
||||
// 32bit multiply, so we require that it not exceed 31bits. That is true
|
||||
// if nearlyzero is <= 0xB504, which should be trivial, since usually
|
||||
// nearlyzero is a very small fixed-point value.
|
||||
SkASSERT(SK_ScalarNearlyZero <= 0xB504);
|
||||
|
||||
tolSqr.set(0, SK_ScalarNearlyZero * SK_ScalarNearlyZero);
|
||||
return tmp1 > tolSqr;
|
||||
}
|
||||
|
||||
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
|
||||
Sk64 tmp1, tmp2;
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#define kMaxCubicSubdivide 4
|
||||
|
||||
static inline bool degenerate_vector(const SkVector& v) {
|
||||
return SkScalarNearlyZero(v.fX) && SkScalarNearlyZero(v.fY);
|
||||
return !SkPoint::CanNormalize(v.fX, v.fY);
|
||||
}
|
||||
|
||||
static inline bool degenerate_line(const SkPoint& a, const SkPoint& b,
|
||||
|
@ -6,10 +6,47 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "Test.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkParse.h"
|
||||
#include "SkSize.h"
|
||||
|
||||
static void stroke_cubic(const SkPoint pts[4]) {
|
||||
SkPath path;
|
||||
path.moveTo(pts[0]);
|
||||
path.cubicTo(pts[1], pts[2], pts[3]);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(SK_Scalar1 * 2);
|
||||
|
||||
SkPath fill;
|
||||
paint.getFillPath(path, &fill);
|
||||
}
|
||||
|
||||
// just ensure this can run w/o any SkASSERTS firing in the debug build
|
||||
// we used to assert due to differences in how we determine a degenerate vector
|
||||
// but that was fixed with the introduction of SkPoint::CanNormalize
|
||||
static void stroke_tiny_cubic() {
|
||||
SkPoint p0[] = {
|
||||
{ 372.0f, 92.0f },
|
||||
{ 372.0f, 92.0f },
|
||||
{ 372.0f, 92.0f },
|
||||
{ 372.0f, 92.0f },
|
||||
};
|
||||
|
||||
stroke_cubic(p0);
|
||||
|
||||
SkPoint p1[] = {
|
||||
{ 372.0f, 92.0f },
|
||||
{ 372.0007f, 92.000755f },
|
||||
{ 371.99927f, 92.003922f },
|
||||
{ 371.99826f, 92.003899f },
|
||||
};
|
||||
|
||||
stroke_cubic(p1);
|
||||
}
|
||||
|
||||
static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
SkPath::Iter iter(path, (bool)i);
|
||||
@ -102,6 +139,8 @@ static void test_close(skiatest::Reporter* reporter) {
|
||||
moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
|
||||
moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
|
||||
check_close(reporter, moves);
|
||||
|
||||
stroke_tiny_cubic();
|
||||
}
|
||||
|
||||
static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
|
||||
|
Loading…
Reference in New Issue
Block a user