зеркало из https://github.com/mozilla/moz-skia.git
work in progress
nearly coincident mostly work support files for creating projects from gyp git-svn-id: http://skia.googlecode.com/svn/trunk@3500 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
6e08bfeca9
Коммит
d88e0894d0
|
@ -0,0 +1,67 @@
|
|||
#include "CurveIntersection.h"
|
||||
#include "LineIntersection.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "TSearch.h"
|
||||
|
||||
namespace UnitTest {
|
||||
|
||||
#include "EdgeWalker.cpp"
|
||||
|
||||
} // end of UnitTest namespace
|
||||
|
||||
#include "Intersection_Tests.h"
|
||||
|
||||
SkPoint leftRight[][4] = {
|
||||
// equal length
|
||||
{{10, 10}, {10, 50}, {20, 10}, {20, 50}},
|
||||
{{10, 10}, {10, 50}, {10, 10}, {20, 50}},
|
||||
{{10, 10}, {10, 50}, {20, 10}, {10, 50}},
|
||||
// left top higher
|
||||
{{10, 0}, {10, 50}, {20, 10}, {20, 50}},
|
||||
{{10, 0}, {10, 50}, {10, 10}, {20, 50}},
|
||||
{{10, 0}, {10, 50}, {20, 10}, {10, 50}},
|
||||
{{10, 0}, {10, 50}, {20, 10}, {10 + 0.000001, 40}},
|
||||
// left top lower
|
||||
{{10, 20}, {10, 50}, {20, 10}, {20, 50}},
|
||||
{{10, 20}, {10, 50}, {10, 10}, {20, 50}},
|
||||
{{10, 20}, {10, 50}, {20, 10}, {10, 50}},
|
||||
{{10, 20}, {10, 50}, {20, 10}, {10 + 0.000001, 40}},
|
||||
{{10, 20}, {10, 50}, { 0, 0}, {50, 50}},
|
||||
// left bottom higher
|
||||
{{10, 10}, {10, 40}, {20, 10}, {20, 50}},
|
||||
{{10, 10}, {10, 40}, {10, 10}, {20, 50}},
|
||||
{{10, 10}, {10, 40}, {20, 10}, {10, 50}},
|
||||
{{10, 10}, {10, 40}, {20, 10}, { 0 + 0.000001, 70}},
|
||||
// left bottom lower
|
||||
{{10, 10}, {10, 60}, {20, 10}, {20, 50}},
|
||||
{{10, 10}, {10, 60}, {10, 10}, {20, 50}},
|
||||
{{10, 10}, {10, 60}, {20, 10}, {10 + 0.000001, 50}},
|
||||
{{10, 10}, {10, 60}, {20, 10}, {10 + 0.000001, 40}},
|
||||
{{10, 10}, {10, 60}, { 0, 0}, {20 + 0.000001, 20}},
|
||||
};
|
||||
|
||||
size_t leftRightCount = sizeof(leftRight) / sizeof(leftRight[0]);
|
||||
|
||||
void ActiveEdge_Test() {
|
||||
UnitTest::InEdge leftIn, rightIn;
|
||||
UnitTest::ActiveEdge left, right;
|
||||
left.fWorkEdge.fEdge = &leftIn;
|
||||
right.fWorkEdge.fEdge = &rightIn;
|
||||
for (size_t x = 0; x < leftRightCount; ++x) {
|
||||
left.fAbove = leftRight[x][0];
|
||||
left.fBelow = leftRight[x][1];
|
||||
right.fAbove = leftRight[x][2];
|
||||
right.fBelow = leftRight[x][3];
|
||||
SkASSERT(left < right);
|
||||
SkASSERT(left.operator_less_than(right));
|
||||
SkASSERT(!(right < left));
|
||||
SkASSERT(!right.operator_less_than(left));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#include "CubicIntersection.h"
|
||||
#include "LineParameters.h"
|
||||
#include <algorithm> // used for std::swap
|
||||
|
||||
// return false if unable to clip (e.g., unable to create implicit line)
|
||||
// caller should subdivide, or create degenerate if the values are too small
|
||||
bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double& maxT) {
|
||||
minT = 1;
|
||||
maxT = 0;
|
||||
// determine normalized implicit line equation for pt[0] to pt[3]
|
||||
// of the form ax + by + c = 0, where a*a + b*b == 1
|
||||
|
||||
// find the implicit line equation parameters
|
||||
LineParameters endLine;
|
||||
endLine.cubicEndPoints(cubic1);
|
||||
if (!endLine.normalize()) {
|
||||
printf("line cannot be normalized: need more code here\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
double distance[2];
|
||||
endLine.controlPtDistance(cubic1, distance);
|
||||
|
||||
// find fat line
|
||||
double top = distance[0];
|
||||
double bottom = distance[1];
|
||||
if (top > bottom) {
|
||||
std::swap(top, bottom);
|
||||
}
|
||||
if (top * bottom >= 0) {
|
||||
const double scale = 3/4.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (13)
|
||||
if (top < 0) {
|
||||
top *= scale;
|
||||
bottom = 0;
|
||||
} else {
|
||||
top = 0;
|
||||
bottom *= scale;
|
||||
}
|
||||
} else {
|
||||
const double scale = 4/9.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (15)
|
||||
top *= scale;
|
||||
bottom *= scale;
|
||||
}
|
||||
|
||||
// compute intersecting candidate distance
|
||||
Cubic distance2y; // points with X of (0, 1/3, 2/3, 1)
|
||||
endLine.cubicDistanceY(cubic2, distance2y);
|
||||
|
||||
int flags = 0;
|
||||
if (approximately_lesser(distance2y[0].y, top)) {
|
||||
flags |= kFindTopMin;
|
||||
} else if (approximately_greater(distance2y[0].y, bottom)) {
|
||||
flags |= kFindBottomMin;
|
||||
} else {
|
||||
minT = 0;
|
||||
}
|
||||
|
||||
if (approximately_lesser(distance2y[3].y, top)) {
|
||||
flags |= kFindTopMax;
|
||||
} else if (approximately_greater(distance2y[3].y, bottom)) {
|
||||
flags |= kFindBottomMax;
|
||||
} else {
|
||||
maxT = 1;
|
||||
}
|
||||
// Find the intersection of distance convex hull and fat line.
|
||||
char to_0[2];
|
||||
char to_3[2];
|
||||
bool do_1_2_edge = convex_x_hull(distance2y, to_0, to_3);
|
||||
x_at(distance2y[0], distance2y[to_0[0]], top, bottom, flags, minT, maxT);
|
||||
if (to_0[0] != to_0[1]) {
|
||||
x_at(distance2y[0], distance2y[to_0[1]], top, bottom, flags, minT, maxT);
|
||||
}
|
||||
x_at(distance2y[to_3[0]], distance2y[3], top, bottom, flags, minT, maxT);
|
||||
if (to_3[0] != to_3[1]) {
|
||||
x_at(distance2y[to_3[1]], distance2y[3], top, bottom, flags, minT, maxT);
|
||||
}
|
||||
if (do_1_2_edge) {
|
||||
x_at(distance2y[1], distance2y[2], top, bottom, flags, minT, maxT);
|
||||
}
|
||||
|
||||
return minT < maxT; // returns false if distance shows no intersection
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#include "CubicIntersection.h"
|
||||
#include "CubicIntersection_TestData.h"
|
||||
#include "CubicIntersection_Tests.h"
|
||||
|
||||
void BezierClip_Test() {
|
||||
for (size_t index = 0; index < tests_count; ++index) {
|
||||
const Cubic& cubic1 = tests[index][0];
|
||||
const Cubic& cubic2 = tests[index][1];
|
||||
Cubic reduce1, reduce2;
|
||||
int order1 = reduceOrder(cubic1, reduce1, kReduceOrder_NoQuadraticsAllowed);
|
||||
int order2 = reduceOrder(cubic2, reduce2, kReduceOrder_NoQuadraticsAllowed);
|
||||
if (order1 < 4) {
|
||||
printf("%s [%d] cubic1 order=%d\n", __FUNCTION__, (int) index, order1);
|
||||
}
|
||||
if (order2 < 4) {
|
||||
printf("%s [%d] cubic2 order=%d\n", __FUNCTION__, (int) index, order2);
|
||||
}
|
||||
if (order1 == 4 && order2 == 4) {
|
||||
double minT = 0;
|
||||
double maxT = 1;
|
||||
bezier_clip(reduce1, reduce2, minT, maxT);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef CubicIntersection_DEFINE
|
||||
#define CubicIntersection_DEFINE
|
||||
|
||||
#include "DataTypes.h"
|
||||
|
||||
class Intersections;
|
||||
|
@ -33,3 +36,5 @@ bool intersectStartT(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
|
|||
bool intersectStart(const Cubic& cubic, const _Line& line, Intersections& );
|
||||
bool intersectStart(const Quadratic& q1, const Quadratic& q2, Intersections& );
|
||||
bool intersectStart(const Quadratic& quad, const _Line& line, Intersections& );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
#include "CubicIntersection.h"
|
||||
#include "Intersections.h"
|
||||
#include "IntersectionUtilities.h"
|
||||
#include "LineIntersection.h"
|
||||
|
||||
class CubicIntersections : public Intersections {
|
||||
public:
|
||||
|
||||
CubicIntersections(const Cubic& c1, const Cubic& c2, Intersections& i)
|
||||
: cubic1(c1)
|
||||
, cubic2(c2)
|
||||
, intersections(i)
|
||||
, depth(0)
|
||||
, splits(0) {
|
||||
}
|
||||
|
||||
bool intersect() {
|
||||
double minT1, minT2, maxT1, maxT2;
|
||||
if (!bezier_clip(cubic2, cubic1, minT1, maxT1)) {
|
||||
return false;
|
||||
}
|
||||
if (!bezier_clip(cubic1, cubic2, minT2, maxT2)) {
|
||||
return false;
|
||||
}
|
||||
int split;
|
||||
if (maxT1 - minT1 < maxT2 - minT2) {
|
||||
intersections.swap();
|
||||
minT2 = 0;
|
||||
maxT2 = 1;
|
||||
split = maxT1 - minT1 > tClipLimit;
|
||||
} else {
|
||||
minT1 = 0;
|
||||
maxT1 = 1;
|
||||
split = (maxT2 - minT2 > tClipLimit) << 1;
|
||||
}
|
||||
return chop(minT1, maxT1, minT2, maxT2, split);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
|
||||
Cubic smaller, larger;
|
||||
// FIXME: carry last subdivide and reduceOrder result with cubic
|
||||
sub_divide(cubic1, minT1, maxT1, intersections.swapped() ? larger : smaller);
|
||||
sub_divide(cubic2, minT2, maxT2, intersections.swapped() ? smaller : larger);
|
||||
Cubic smallResult;
|
||||
if (reduceOrder(smaller, smallResult,
|
||||
kReduceOrder_NoQuadraticsAllowed) <= 2) {
|
||||
Cubic largeResult;
|
||||
if (reduceOrder(larger, largeResult,
|
||||
kReduceOrder_NoQuadraticsAllowed) <= 2) {
|
||||
_Point pt;
|
||||
const _Line& smallLine = (const _Line&) smallResult;
|
||||
const _Line& largeLine = (const _Line&) largeResult;
|
||||
if (!lineIntersect(smallLine, largeLine, &pt)) {
|
||||
return false;
|
||||
}
|
||||
double smallT = t_at(smallLine, pt);
|
||||
double largeT = t_at(largeLine, pt);
|
||||
if (intersections.swapped()) {
|
||||
smallT = interp(minT2, maxT2, smallT);
|
||||
largeT = interp(minT1, maxT1, largeT);
|
||||
} else {
|
||||
smallT = interp(minT1, maxT1, smallT);
|
||||
largeT = interp(minT2, maxT2, largeT);
|
||||
}
|
||||
intersections.add(smallT, largeT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
double minT, maxT;
|
||||
if (!bezier_clip(smaller, larger, minT, maxT)) {
|
||||
if (minT == maxT) {
|
||||
if (intersections.swapped()) {
|
||||
minT1 = (minT1 + maxT1) / 2;
|
||||
minT2 = interp(minT2, maxT2, minT);
|
||||
} else {
|
||||
minT1 = interp(minT1, maxT1, minT);
|
||||
minT2 = (minT2 + maxT2) / 2;
|
||||
}
|
||||
intersections.add(minT1, minT2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int split;
|
||||
if (intersections.swapped()) {
|
||||
double newMinT1 = interp(minT1, maxT1, minT);
|
||||
double newMaxT1 = interp(minT1, maxT1, maxT);
|
||||
split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
|
||||
#define VERBOSE 0
|
||||
#if VERBOSE
|
||||
printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n",
|
||||
__FUNCTION__, depth, splits, newMinT1, newMaxT1, minT1, maxT1,
|
||||
split);
|
||||
#endif
|
||||
minT1 = newMinT1;
|
||||
maxT1 = newMaxT1;
|
||||
} else {
|
||||
double newMinT2 = interp(minT2, maxT2, minT);
|
||||
double newMaxT2 = interp(minT2, maxT2, maxT);
|
||||
split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
|
||||
#if VERBOSE
|
||||
printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n",
|
||||
__FUNCTION__, depth, splits, newMinT2, newMaxT2, minT2, maxT2,
|
||||
split);
|
||||
#endif
|
||||
minT2 = newMinT2;
|
||||
maxT2 = newMaxT2;
|
||||
}
|
||||
return chop(minT1, maxT1, minT2, maxT2, split);
|
||||
}
|
||||
|
||||
bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
|
||||
++depth;
|
||||
intersections.swap();
|
||||
if (split) {
|
||||
++splits;
|
||||
if (split & 2) {
|
||||
double middle1 = (maxT1 + minT1) / 2;
|
||||
intersect(minT1, middle1, minT2, maxT2);
|
||||
intersect(middle1, maxT1, minT2, maxT2);
|
||||
} else {
|
||||
double middle2 = (maxT2 + minT2) / 2;
|
||||
intersect(minT1, maxT1, minT2, middle2);
|
||||
intersect(minT1, maxT1, middle2, maxT2);
|
||||
}
|
||||
--splits;
|
||||
intersections.swap();
|
||||
--depth;
|
||||
return intersections.intersected();
|
||||
}
|
||||
bool result = intersect(minT1, maxT1, minT2, maxT2);
|
||||
intersections.swap();
|
||||
--depth;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
|
||||
const Cubic& cubic1;
|
||||
const Cubic& cubic2;
|
||||
Intersections& intersections;
|
||||
int depth;
|
||||
int splits;
|
||||
};
|
||||
|
||||
bool intersectStartT(const Cubic& c1, const Cubic& c2, Intersections& i) {
|
||||
CubicIntersections c(c1, c2, i);
|
||||
return c.intersect();
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
// included by CubicParameterization.cpp
|
||||
// accesses internal functions to validate parameterized coefficients
|
||||
|
||||
#include "Parameterization_Test.h"
|
||||
|
||||
static void parameter_coeffs(const Cubic& cubic, double coeffs[coeff_count]) {
|
||||
#if USE_SYVESTER
|
||||
double ax, bx, cx, dx;
|
||||
if (try_alt)
|
||||
alt_set_abcd(&cubic[0].x, ax, bx, cx, dx);
|
||||
else
|
||||
set_abcd(&cubic[0].x, ax, bx, cx, dx);
|
||||
double ay, by, cy, dy;
|
||||
if (try_alt)
|
||||
alt_set_abcd(&cubic[0].y, ay, by, cy, dy);
|
||||
else
|
||||
set_abcd(&cubic[0].y, ay, by, cy, dy);
|
||||
calc_ABCD(ax, ay, coeffs);
|
||||
if (!try_alt) calc_bc(dx, bx, cx);
|
||||
if (!try_alt) calc_bc(dy, by, cy);
|
||||
#else
|
||||
double ax = cubic[0].x;
|
||||
double bx = cubic[1].x;
|
||||
double cx = cubic[2].x;
|
||||
double dx = cubic[3].x;
|
||||
double ay = cubic[0].y;
|
||||
double by = cubic[1].y;
|
||||
double cy = cubic[2].y;
|
||||
double dy = cubic[3].y;
|
||||
calc_ABCD(ax, bx, cx, dx, ay, by, cy, dy, coeffs);
|
||||
#endif
|
||||
for (int index = xx_coeff; index < coeff_count; ++index) {
|
||||
int procIndex = index - xx_coeff;
|
||||
coeffs[index] = (*calc_proc[procIndex])(ax, bx, cx, dx, ay, by, cy, dy);
|
||||
}
|
||||
}
|
||||
|
||||
bool point_on_parameterized_curve(const Cubic& cubic, const _Point& point) {
|
||||
double coeffs[coeff_count];
|
||||
parameter_coeffs(cubic, coeffs);
|
||||
double xxx = coeffs[xxx_coeff] * point.x * point.x * point.x;
|
||||
double xxy = coeffs[xxy_coeff] * point.x * point.x * point.y;
|
||||
double xyy = coeffs[xyy_coeff] * point.x * point.y * point.y;
|
||||
double yyy = coeffs[yyy_coeff] * point.y * point.y * point.y;
|
||||
double xx = coeffs[ xx_coeff] * point.x * point.x;
|
||||
double xy = coeffs[ xy_coeff] * point.x * point.y;
|
||||
double yy = coeffs[ yy_coeff] * point.y * point.y;
|
||||
double x = coeffs[ x_coeff] * point.x;
|
||||
double y = coeffs[ y_coeff] * point.y;
|
||||
double c = coeffs[ c_coeff];
|
||||
double sum = xxx + xxy + xyy + yyy + xx + xy + yy + x + y + c;
|
||||
return approximately_zero(sum);
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
#include "CubicUtilities.h"
|
||||
#include "DataTypes.h"
|
||||
#include "QuadraticUtilities.h"
|
||||
|
||||
const double PI = 4 * atan(1);
|
||||
|
||||
static bool is_unit_interval(double x) {
|
||||
return x > 0 && x < 1;
|
||||
}
|
||||
|
||||
// from SkGeometry.cpp (and Numeric Solutions, 5.6)
|
||||
int cubicRoots(double A, double B, double C, double D, double t[3]) {
|
||||
if (approximately_zero(A)) { // we're just a quadratic
|
||||
return quadraticRoots(B, C, D, t);
|
||||
}
|
||||
double a, b, c;
|
||||
{
|
||||
double invA = 1 / A;
|
||||
a = B * invA;
|
||||
b = C * invA;
|
||||
c = D * invA;
|
||||
}
|
||||
double a2 = a * a;
|
||||
double Q = (a2 - b * 3) / 9;
|
||||
double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
|
||||
double Q3 = Q * Q * Q;
|
||||
double R2MinusQ3 = R * R - Q3;
|
||||
double adiv3 = a / 3;
|
||||
double* roots = t;
|
||||
double r;
|
||||
|
||||
if (R2MinusQ3 < 0) // we have 3 real roots
|
||||
{
|
||||
double theta = acos(R / sqrt(Q3));
|
||||
double neg2RootQ = -2 * sqrt(Q);
|
||||
|
||||
r = neg2RootQ * cos(theta / 3) - adiv3;
|
||||
if (is_unit_interval(r))
|
||||
*roots++ = r;
|
||||
|
||||
r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
|
||||
if (is_unit_interval(r))
|
||||
*roots++ = r;
|
||||
|
||||
r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
|
||||
if (is_unit_interval(r))
|
||||
*roots++ = r;
|
||||
}
|
||||
else // we have 1 real root
|
||||
{
|
||||
double A = fabs(R) + sqrt(R2MinusQ3);
|
||||
A = cube_root(A);
|
||||
if (R > 0) {
|
||||
A = -A;
|
||||
}
|
||||
if (A != 0) {
|
||||
A += Q / A;
|
||||
}
|
||||
r = A - adiv3;
|
||||
if (is_unit_interval(r))
|
||||
*roots++ = r;
|
||||
}
|
||||
return (int)(roots - t);
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef CurveIntersection_DEFINE
|
||||
#define CurveIntersection_DEFINE
|
||||
|
||||
#include "DataTypes.h"
|
||||
|
||||
class Intersections;
|
||||
|
@ -32,3 +35,5 @@ bool intersect(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
|
|||
int intersect(const Cubic& cubic, const _Line& line, double cRange[3], double lRange[3]);
|
||||
bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& );
|
||||
bool intersect(const Quadratic& quad, const _Line& line, Intersections& );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#ifndef __DataTypes_h__
|
||||
#define __DataTypes_h__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern double fabs( double );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
extern const double PointEpsilon;
|
||||
extern const double SquaredEpsilon;
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* EdgeApp.cpp
|
||||
* edge
|
||||
*
|
||||
* Created by Cary Clark on 7/6/11.
|
||||
* Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkImageEncoder.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTime.h"
|
||||
#include "SkWindow.h"
|
||||
|
||||
#include "SkTouchGesture.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
#include "Intersection_Tests.h"
|
||||
|
||||
extern void CreateSweep(SkBitmap* , float width);
|
||||
extern void CreateHorz(SkBitmap* );
|
||||
extern void CreateVert(SkBitmap* );
|
||||
extern void CreateAngle(SkBitmap* sweep, float angle);
|
||||
extern void SkAntiEdge_Test();
|
||||
|
||||
|
||||
static const char gCharEvtName[] = "Char_Event";
|
||||
static const char gKeyEvtName[] = "Key_Event";
|
||||
|
||||
class SkEdgeView : public SkView {
|
||||
public:
|
||||
SkEdgeView() {
|
||||
CreateSweep(&fSweep_1_0, 1);
|
||||
CreateSweep(&fSweep_1_2, 1.2f);
|
||||
CreateSweep(&fSweep_1_4, 1.4f);
|
||||
CreateSweep(&fSweep_1_6, 1.6f);
|
||||
CreateHorz(&fBitmapH);
|
||||
CreateVert(&fBitmapV);
|
||||
CreateAngle(&fAngle_12, 12);
|
||||
CreateAngle(&fAngle_45, 45);
|
||||
}
|
||||
virtual ~SkEdgeView() {}
|
||||
|
||||
protected:
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
canvas->drawBitmap(fSweep_1_0, 0, 10);
|
||||
canvas->drawBitmap(fBitmapH, 110, 10);
|
||||
canvas->drawBitmap(fBitmapV, 220, 10);
|
||||
canvas->drawBitmap(fSweep_1_2, 0, 110);
|
||||
canvas->drawBitmap(fSweep_1_4, 100, 110);
|
||||
canvas->drawBitmap(fSweep_1_6, 200, 110);
|
||||
canvas->drawBitmap(fAngle_12, 0, 200);
|
||||
canvas->drawBitmap(fAngle_45, 124, 220);
|
||||
}
|
||||
|
||||
private:
|
||||
SkBitmap fSweep_1_0;
|
||||
SkBitmap fSweep_1_2;
|
||||
SkBitmap fSweep_1_4;
|
||||
SkBitmap fSweep_1_6;
|
||||
SkBitmap fBitmapH;
|
||||
SkBitmap fBitmapV;
|
||||
SkBitmap fAngle_12;
|
||||
SkBitmap fAngle_45;
|
||||
typedef SkView INHERITED;
|
||||
};
|
||||
|
||||
class EdgeWindow : public SkOSWindow {
|
||||
public:
|
||||
EdgeWindow(void* hwnd) : INHERITED(hwnd) {
|
||||
this->setConfig(SkBitmap::kARGB_8888_Config);
|
||||
this->setVisibleP(true);
|
||||
fView.setVisibleP(true);
|
||||
fView.setClipToBounds(false);
|
||||
this->attachChildToFront(&fView)->unref();
|
||||
}
|
||||
virtual ~EdgeWindow() {}
|
||||
|
||||
virtual void draw(SkCanvas* canvas){
|
||||
this->INHERITED::draw(canvas);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
SkEdgeView fView;
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
}
|
||||
|
||||
virtual bool onHandleKey(SkKey key) {
|
||||
SkEvent evt(gKeyEvtName);
|
||||
evt.setFast32(key);
|
||||
if (fView.doQuery(&evt)) {
|
||||
return true;
|
||||
}
|
||||
return this->INHERITED::onHandleKey(key);
|
||||
}
|
||||
|
||||
virtual bool onHandleChar(SkUnichar uni) {
|
||||
SkEvent evt(gCharEvtName);
|
||||
evt.setFast32(uni);
|
||||
if (fView.doQuery(&evt)) {
|
||||
return true;
|
||||
}
|
||||
return this->INHERITED::onHandleChar(uni);
|
||||
}
|
||||
|
||||
virtual void onSizeChange() {
|
||||
fView.setSize(this->width(), this->height());
|
||||
this->INHERITED::onSizeChange();
|
||||
}
|
||||
|
||||
virtual SkCanvas* beforeChildren(SkCanvas* canvas) {
|
||||
return this->INHERITED::beforeChildren(canvas);
|
||||
}
|
||||
|
||||
virtual void afterChildren(SkCanvas*) {}
|
||||
virtual void beforeChild(SkView* child, SkCanvas* canvas) {}
|
||||
virtual void afterChild(SkView* child, SkCanvas* canvas) {}
|
||||
|
||||
virtual bool onEvent(const SkEvent& evt) {
|
||||
return this->INHERITED::onEvent(evt);
|
||||
}
|
||||
|
||||
virtual bool onQuery(SkEvent* evt) {
|
||||
return this->INHERITED::onQuery(evt);
|
||||
}
|
||||
|
||||
virtual bool onDispatchClick(int x, int y, Click::State state, void* owner) {
|
||||
int w = SkScalarRound(this->width());
|
||||
int h = SkScalarRound(this->height());
|
||||
// check for the resize-box
|
||||
if (w - x < 16 && h - y < 16) {
|
||||
return false; // let the OS handle the click
|
||||
} else {
|
||||
return this->INHERITED::onDispatchClick(x, y, state, owner);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool onClick(Click* click) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Click* onFindClickHandler(SkScalar x, SkScalar y) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef SkOSWindow INHERITED;
|
||||
};
|
||||
|
||||
|
||||
#include "SkApplication.h"
|
||||
|
||||
SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
|
||||
return new EdgeWindow(hwnd);
|
||||
}
|
||||
|
||||
void application_init() {
|
||||
SkGraphics::Init();
|
||||
SkEvent::Init();
|
||||
|
||||
Intersection_Tests();
|
||||
SkAntiEdge_Test();
|
||||
}
|
||||
|
||||
void application_term() {
|
||||
SkEvent::Term();
|
||||
SkGraphics::Term();
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.googlecode.skia.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>EdgeDemoApp</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,116 @@
|
|||
#include "EdgeWalker_Test.h"
|
||||
#include "ShapeOps.h"
|
||||
#import "SkCanvas.h"
|
||||
#import "SkPaint.h"
|
||||
#import "SkWindow.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkCGUtils.h"
|
||||
|
||||
class SkSampleView : public SkView {
|
||||
public:
|
||||
SkSampleView() {
|
||||
this->setVisibleP(true);
|
||||
this->setClipToBounds(false);
|
||||
};
|
||||
protected:
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
// Three circles bounce inside a rectangle. The circles describe three, four
|
||||
// or five points which in turn describe a polygon. The polygon points
|
||||
// bounce inside the circles. The circles rotate and scale over time. The
|
||||
// polygons are combined into a single path, simplified, and stroked.
|
||||
static int step = 0;
|
||||
const int circles = 3;
|
||||
int scales[circles];
|
||||
int angles[circles];
|
||||
int locs[circles * 2];
|
||||
int pts[circles * 2 * 4];
|
||||
int c, p;
|
||||
for (c = 0; c < circles; ++c) {
|
||||
scales[c] = abs(10 - (step + c * 4) % 21);
|
||||
angles[c] = (step + c * 6) % 600;
|
||||
locs[c * 2] = abs(130 - (step + c * 9) % 261);
|
||||
locs[c * 2 + 1] = abs(170 - (step + c * 11) % 341);
|
||||
for (p = 0; p < 4; ++p) {
|
||||
pts[c * 8 + p * 2] = abs(90 - ((step + c * 121 + p * 13) % 190));
|
||||
pts[c * 8 + p * 2 + 1] = abs(110 - ((step + c * 223 + p * 17) % 230));
|
||||
}
|
||||
}
|
||||
SkPath path, out;
|
||||
for (c = 0; c < circles; ++c) {
|
||||
for (p = 0; p < 4; ++p) {
|
||||
SkScalar x = pts[c * 8 + p * 2];
|
||||
SkScalar y = pts[c * 8 + p * 2 + 1];
|
||||
x *= 3 + scales[c] / 10.0f;
|
||||
y *= 3 + scales[c] / 10.0f;
|
||||
SkScalar angle = angles[c] * 3.1415f * 2 / 600;
|
||||
SkScalar temp = x * cos(angle) - y * sin(angle);
|
||||
y = x * sin(angle) + y * cos(angle);
|
||||
x = temp;
|
||||
x += locs[c * 2] * 200 / 130.0f;
|
||||
y += locs[c * 2 + 1] * 200 / 170.0f;
|
||||
x += 50;
|
||||
// y += 200;
|
||||
if (p == 0) {
|
||||
path.moveTo(x, y);
|
||||
} else {
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
path.close();
|
||||
}
|
||||
showPath(path, "original:");
|
||||
simplify(path, true, out);
|
||||
showPath(out, "simplified:");
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(3);
|
||||
paint.setColor(0x3F007fbF);
|
||||
canvas->drawPath(path, paint);
|
||||
paint.setColor(0xFF60FF00);
|
||||
paint.setStrokeWidth(1);
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
canvas->drawPath(out, paint);
|
||||
++step;
|
||||
inval(NULL);
|
||||
}
|
||||
private:
|
||||
typedef SkView INHERITED;
|
||||
};
|
||||
|
||||
void application_init() {
|
||||
SkGraphics::Init();
|
||||
SkEvent::Init();
|
||||
}
|
||||
|
||||
void application_term() {
|
||||
SkGraphics::Term();
|
||||
SkEvent::Term();
|
||||
}
|
||||
|
||||
class FillLayout : public SkView::Layout {
|
||||
protected:
|
||||
virtual void onLayoutChildren(SkView* parent) {
|
||||
SkView* view = SkView::F2BIter(parent).next();
|
||||
view->setSize(parent->width(), parent->height());
|
||||
}
|
||||
};
|
||||
|
||||
#import "SimpleApp.h"
|
||||
@implementation SimpleNSView
|
||||
|
||||
- (id)initWithDefaults {
|
||||
if (self = [super initWithDefaults]) {
|
||||
fWind = new SkOSWindow(self);
|
||||
fWind->setLayout(new FillLayout, false);
|
||||
fWind->attachChildToFront(new SkSampleView)->unref();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
|
||||
SkCGDrawBitmap(ctx, fWind->getBitmap(), 0, 0);
|
||||
}
|
||||
|
||||
@end
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* EdgeMain.cpp
|
||||
* shapeops_edge
|
||||
*
|
||||
* Created by Cary Clark on 3/26/12.
|
||||
* Copyright 2012 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EdgeMain.h"
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#include "Intersection_Tests.h"
|
||||
|
||||
int main(int argc, char* argv) {
|
||||
Intersection_Tests();
|
||||
return 0;
|
||||
}
|
|
@ -12,10 +12,11 @@
|
|||
#include "SkRect.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "ShapeOps.h"
|
||||
#include "TSearch.h"
|
||||
|
||||
#if 0 // set to 1 for no debugging whatsoever
|
||||
static bool gShowDebugf = false; // FIXME: remove once debugging is complete
|
||||
const bool gShowDebugf = false; // FIXME: remove once debugging is complete
|
||||
|
||||
#define DEBUG_DUMP 0
|
||||
#define DEBUG_ADD 0
|
||||
|
@ -31,13 +32,13 @@ static bool gShowDebugf = false; // FIXME: remove once debugging is complete
|
|||
#define DEBUG_BOTTOM 0
|
||||
|
||||
#else
|
||||
static bool gShowDebugf = true; // FIXME: remove once debugging is complete
|
||||
const bool gShowDebugf = true; // FIXME: remove once debugging is complete
|
||||
|
||||
#define DEBUG_DUMP 01
|
||||
#define DEBUG_ADD 01
|
||||
#define DEBUG_ADD_INTERSECTING_TS 0
|
||||
#define DEBUG_ADD_BOTTOM_TS 0
|
||||
#define COMPARE_DOUBLE 01
|
||||
#define COMPARE_DOUBLE 0
|
||||
#define DEBUG_ABOVE_BELOW 01
|
||||
#define DEBUG_ACTIVE_LESS_THAN 01
|
||||
#define DEBUG_SORT_HORIZONTAL 01
|
||||
|
@ -48,9 +49,7 @@ static bool gShowDebugf = true; // FIXME: remove once debugging is complete
|
|||
|
||||
#endif
|
||||
|
||||
// FIXME: not wild about this -- min delta should be based on size of curve, not t
|
||||
// #define MIN_T_DELTA 0.000001
|
||||
// not wild about this either -- for SkScalars backed by floats, would like to
|
||||
// FIXME: not wild about this -- for SkScalars backed by floats, would like to
|
||||
// represent deltas in terms of number of significant matching bits
|
||||
#define MIN_PT_DELTA 0.000001
|
||||
|
||||
|
@ -117,9 +116,6 @@ static void LineSubDivide(const SkPoint a[2], double startT, double endT,
|
|||
}
|
||||
#endif
|
||||
|
||||
// functions
|
||||
void contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray);
|
||||
void simplify(const SkPath& path, bool asFill, SkPath& simple);
|
||||
/*
|
||||
list of edges
|
||||
bounds for edge
|
||||
|
@ -290,7 +286,9 @@ public:
|
|||
}
|
||||
gap = lastLine[1] != *start;
|
||||
if (gap) {
|
||||
SkASSERT(fFill && lastLine[1].fY == start->fY);
|
||||
// FIXME: see comment in bridge -- this probably
|
||||
// conceals errors
|
||||
SkASSERT(fFill && UlpsDiff(lastLine[1].fY, start->fY) <= 10);
|
||||
simple.lineTo(lastLine[1].fX, lastLine[1].fY);
|
||||
if (gShowDebugf) {
|
||||
SkDebugf("%s lineTo x (%g,%g)\n", __FUNCTION__,
|
||||
|
@ -298,8 +296,10 @@ public:
|
|||
}
|
||||
}
|
||||
if (gap || !extendLine(lastLine, *end)) {
|
||||
// FIXME: see comment in bridge -- this probably
|
||||
// conceals errors
|
||||
SkASSERT(lastLine[1] == *start ||
|
||||
(fFill && lastLine[1].fY == start->fY));
|
||||
(fFill && UlpsDiff(lastLine[1].fY, start->fY) <= 10));
|
||||
simple.lineTo(start->fX, start->fY);
|
||||
if (gShowDebugf) {
|
||||
SkDebugf("%s lineTo (%g,%g)\n", __FUNCTION__,
|
||||
|
@ -447,8 +447,10 @@ public:
|
|||
pairUp = leftMatch == rightMatch;
|
||||
} else {
|
||||
#if DEBUG_OUT
|
||||
if (left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY
|
||||
!= right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) {
|
||||
// FIXME : not happy that error in low bit is allowed
|
||||
// this probably conceals error elsewhere
|
||||
if (UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
|
||||
right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) > 1) {
|
||||
*fMismatches.append() = leftIndex;
|
||||
if (rightPtr == lastPtr) {
|
||||
*fMismatches.append() = rightIndex;
|
||||
|
@ -456,8 +458,8 @@ public:
|
|||
pairUp = false;
|
||||
}
|
||||
#else
|
||||
SkASSERT(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY
|
||||
== right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY);
|
||||
SkASSERT(UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
|
||||
right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) <= 10);
|
||||
#endif
|
||||
}
|
||||
if (pairUp) {
|
||||
|
@ -895,8 +897,29 @@ struct WorkEdge {
|
|||
// as active edges are introduced, only local sorting should be required
|
||||
class ActiveEdge {
|
||||
public:
|
||||
// OPTIMIZATION: fold return statements into one
|
||||
bool operator<(const ActiveEdge& rh) const {
|
||||
double topD = fAbove.fX - rh.fAbove.fX;
|
||||
if (rh.fAbove.fY < fAbove.fY) {
|
||||
topD = (rh.fBelow.fY - rh.fAbove.fY) * topD
|
||||
- (fAbove.fY - rh.fAbove.fY) * (rh.fBelow.fX - rh.fAbove.fX);
|
||||
} else if (rh.fAbove.fY > fAbove.fY) {
|
||||
topD = (fBelow.fY - fAbove.fY) * topD
|
||||
+ (rh.fAbove.fY - fAbove.fY) * (fBelow.fX - fAbove.fX);
|
||||
}
|
||||
double botD = fBelow.fX - rh.fBelow.fX;
|
||||
if (rh.fBelow.fY > fBelow.fY) {
|
||||
botD = (rh.fBelow.fY - rh.fAbove.fY) * botD
|
||||
- (fBelow.fY - rh.fBelow.fY) * (rh.fBelow.fX - rh.fAbove.fX);
|
||||
} else if (rh.fBelow.fY < fBelow.fY) {
|
||||
botD = (fBelow.fY - fAbove.fY) * botD
|
||||
+ (rh.fBelow.fY - fBelow.fY) * (fBelow.fX - fAbove.fX);
|
||||
}
|
||||
// return sign of greater absolute value
|
||||
return (fabs(topD) > fabs(botD) ? topD : botD) < 0;
|
||||
}
|
||||
|
||||
// OPTIMIZATION: fold return statements into one
|
||||
bool operator_less_than(const ActiveEdge& rh) const {
|
||||
if (rh.fAbove.fY - fAbove.fY > fBelow.fY - rh.fAbove.fY
|
||||
&& fBelow.fY < rh.fBelow.fY
|
||||
|| fAbove.fY - rh.fAbove.fY < rh.fBelow.fY - fAbove.fY
|
||||
|
@ -1114,10 +1137,16 @@ public:
|
|||
// edges.
|
||||
bool isCoincidentWith(const ActiveEdge* edge, SkScalar y) const {
|
||||
|
||||
#if 0
|
||||
if (!fAbove.equalsWithinTolerance(edge->fAbove, MIN_PT_DELTA)
|
||||
|| !fBelow.equalsWithinTolerance(edge->fBelow, MIN_PT_DELTA)) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (fAbove != edge->fAbove || fBelow != edge->fBelow) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
uint8_t verb = fDone ? fWorkEdge.lastVerb() : fWorkEdge.verb();
|
||||
uint8_t edgeVerb = edge->fDone ? edge->fWorkEdge.lastVerb()
|
||||
: edge->fWorkEdge.verb();
|
||||
|
@ -1138,6 +1167,11 @@ public:
|
|||
// The shortest close call edge should be moved into a position where
|
||||
// it contributes if the winding is transitioning to or from zero.
|
||||
bool swapClose(const ActiveEdge* next, int prev, int wind, int mask) const {
|
||||
#if DEBUG_ADJUST_COINCIDENT
|
||||
SkDebugf("%s edge=%d (%g) next=%d (%g) prev=%d wind=%d nextWind=%d\n",
|
||||
__FUNCTION__, ID(), fBelow.fY, next->ID(), next->fBelow.fY,
|
||||
prev, wind, wind + next->fWorkEdge.winding());
|
||||
#endif
|
||||
if ((prev & mask) == 0 || (wind & mask) == 0) {
|
||||
return next->fBelow.fY < fBelow.fY;
|
||||
}
|
||||
|
@ -1170,6 +1204,11 @@ public:
|
|||
|
||||
bool tooCloseToCall(const ActiveEdge* edge) const {
|
||||
int ulps;
|
||||
// FIXME: the first variation works better (or at least causes fewer tests
|
||||
// to fail than the second, although the second's logic better matches the
|
||||
// current sort criteria. Need to track down the cause of the crash, and
|
||||
// see if the second case isn't somehow buggy.
|
||||
#if 01
|
||||
// FIXME: don't compare points for equality
|
||||
// OPTIMIZATION: refactor to make one call to UlpsDiff
|
||||
if (edge->fAbove.fY - fAbove.fY > fBelow.fY - edge->fAbove.fY
|
||||
|
@ -1189,6 +1228,38 @@ public:
|
|||
(check.fY - edge->fAbove.fY)
|
||||
* (edge->fBelow.fX - edge->fAbove.fX));
|
||||
}
|
||||
#else
|
||||
double t1, t2, b1, b2;
|
||||
if (edge->fAbove.fY < fAbove.fY) {
|
||||
t1 = (edge->fBelow.fY - edge->fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
|
||||
t2 = (fAbove.fY - edge->fAbove.fY) * (edge->fBelow.fX - edge->fAbove.fX);
|
||||
} else if (edge->fAbove.fY > fAbove.fY) {
|
||||
t1 = (fBelow.fY - fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
|
||||
t2 = (fAbove.fY - edge->fAbove.fY) * (fBelow.fX - fAbove.fX);
|
||||
} else {
|
||||
t1 = fAbove.fX;
|
||||
t2 = edge->fAbove.fX;
|
||||
}
|
||||
if (edge->fBelow.fY > fBelow.fY) {
|
||||
b1 = (edge->fBelow.fY - edge->fAbove.fY) * (fBelow.fX - edge->fBelow.fX);
|
||||
b2 = (fBelow.fY - edge->fBelow.fY) * (edge->fBelow.fX - edge->fAbove.fX);
|
||||
} else if (edge->fBelow.fY < fBelow.fY) {
|
||||
b1 = (fBelow.fY - fAbove.fY) * (fBelow.fX - edge->fBelow.fX);
|
||||
b2 = (fBelow.fY - edge->fBelow.fY) * (fBelow.fX - fAbove.fX);
|
||||
} else {
|
||||
b1 = fBelow.fX;
|
||||
b2 = edge->fBelow.fX;
|
||||
}
|
||||
if (fabs(t1 - t2) > fabs(b1 - b2)) {
|
||||
ulps = UlpsDiff(t1, t2);
|
||||
} else {
|
||||
ulps = UlpsDiff(b1, b2);
|
||||
}
|
||||
#if DEBUG_ADJUST_COINCIDENT
|
||||
SkDebugf("%s this=%d edge=%d ulps=%d\n", __FUNCTION__, ID(), edge->ID(),
|
||||
ulps);
|
||||
#endif
|
||||
#endif
|
||||
return ulps >= 0 && ulps <= 32;
|
||||
}
|
||||
|
||||
|
@ -1522,12 +1593,12 @@ static void skipCoincidence(int lastWinding, int winding, int windingMask,
|
|||
|
||||
static void sortHorizontal(SkTDArray<ActiveEdge>& activeEdges,
|
||||
SkTDArray<ActiveEdge*>& edgeList, SkScalar y) {
|
||||
const int tab = 3; // FIXME: debugging only
|
||||
size_t edgeCount = activeEdges.count();
|
||||
if (edgeCount == 0) {
|
||||
return;
|
||||
}
|
||||
#if DEBUG_SORT_HORIZONTAL
|
||||
const int tab = 3; // FIXME: debugging only
|
||||
SkDebugf("%s y=%1.9g\n", __FUNCTION__, y);
|
||||
#endif
|
||||
size_t index;
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
#include "EdgeWalker_Test.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
struct State {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
pthread_t threadID;
|
||||
bool abcIsATriangle;
|
||||
};
|
||||
|
||||
void createThread(State* statePtr, void* (*test)(void* )) {
|
||||
int threadError = pthread_create(&statePtr->threadID, NULL, test,
|
||||
(void*) statePtr);
|
||||
SkASSERT(!threadError);
|
||||
}
|
||||
|
||||
void waitForCompletion(State threadState[], int& threadIndex) {
|
||||
for (int index = 0; index < threadIndex; ++index) {
|
||||
pthread_join(threadState[index].threadID, NULL);
|
||||
}
|
||||
SkDebugf(".");
|
||||
threadIndex = 0;
|
||||
}
|
||||
|
||||
static void* testSimplify4x4QuadralateralsMain(void* data)
|
||||
{
|
||||
char pathStr[1024];
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
SkASSERT(data);
|
||||
State& state = *(State*) data;
|
||||
int ax = state.a & 0x03;
|
||||
int ay = state.a >> 2;
|
||||
int bx = state.b & 0x03;
|
||||
int by = state.b >> 2;
|
||||
int cx = state.c & 0x03;
|
||||
int cy = state.c >> 2;
|
||||
int dx = state.d & 0x03;
|
||||
int dy = state.d >> 2;
|
||||
for (int e = 0 ; e < 16; ++e) {
|
||||
int ex = e & 0x03;
|
||||
int ey = e >> 2;
|
||||
for (int f = e ; f < 16; ++f) {
|
||||
int fx = f & 0x03;
|
||||
int fy = f >> 2;
|
||||
for (int g = f ; g < 16; ++g) {
|
||||
int gx = g & 0x03;
|
||||
int gy = g >> 2;
|
||||
for (int h = g ; h < 16; ++h) {
|
||||
int hx = h & 0x03;
|
||||
int hy = h >> 2;
|
||||
SkPath path, out;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(ax, ay);
|
||||
path.lineTo(bx, by);
|
||||
path.lineTo(cx, cy);
|
||||
path.lineTo(dx, dy);
|
||||
path.close();
|
||||
path.moveTo(ex, ey);
|
||||
path.lineTo(fx, fy);
|
||||
path.lineTo(gx, gy);
|
||||
path.lineTo(hx, hy);
|
||||
path.close();
|
||||
if (1) { // gdb: set print elements 400
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", dx, dy);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ex, ey);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", gx, gy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", hx, hy);
|
||||
str += sprintf(str, " path.close();");
|
||||
}
|
||||
if (!testSimplify(path, true, out)) {
|
||||
SkDebugf("*/\n{ SkPath::kWinding_FillType, %d, %d, %d, %d,"
|
||||
" %d, %d, %d, %d },\n/*\n", state.a, state.b, state.c, state.d,
|
||||
e, f, g, h);
|
||||
}
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
if (!testSimplify(path, true, out)) {
|
||||
SkDebugf("*/\n{ SkPath::kEvenOdd_FillType, %d, %d, %d, %d,"
|
||||
" %d, %d, %d, %d },\n/*\n", state.a, state.b, state.c, state.d,
|
||||
e, f, g, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int maxThreads = gShowDebugf ? 1 : 24;
|
||||
|
||||
void Simplify4x4QuadralateralsThreaded_Test()
|
||||
{
|
||||
State threadState[maxThreads];
|
||||
int threadIndex = 0;
|
||||
for (int a = 0; a < 16; ++a) {
|
||||
for (int b = a ; b < 16; ++b) {
|
||||
for (int c = b ; c < 16; ++c) {
|
||||
for (int d = c; d < 16; ++d) {
|
||||
State* statePtr = &threadState[threadIndex];
|
||||
statePtr->a = a;
|
||||
statePtr->b = b;
|
||||
statePtr->c = c;
|
||||
statePtr->d = d;
|
||||
if (maxThreads > 1) {
|
||||
createThread(statePtr, testSimplify4x4QuadralateralsMain);
|
||||
if (++threadIndex >= maxThreads) {
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
} else {
|
||||
testSimplify4x4QuadralateralsMain(statePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
|
||||
|
||||
static void* testSimplify4x4NondegeneratesMain(void* data) {
|
||||
char pathStr[1024];
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
SkASSERT(data);
|
||||
State& state = *(State*) data;
|
||||
int ax = state.a & 0x03;
|
||||
int ay = state.a >> 2;
|
||||
int bx = state.b & 0x03;
|
||||
int by = state.b >> 2;
|
||||
int cx = state.c & 0x03;
|
||||
int cy = state.c >> 2;
|
||||
for (int d = 0; d < 15; ++d) {
|
||||
int dx = d & 0x03;
|
||||
int dy = d >> 2;
|
||||
for (int e = d + 1; e < 16; ++e) {
|
||||
int ex = e & 0x03;
|
||||
int ey = e >> 2;
|
||||
for (int f = d + 1; f < 16; ++f) {
|
||||
if (e == f) {
|
||||
continue;
|
||||
}
|
||||
int fx = f & 0x03;
|
||||
int fy = f >> 2;
|
||||
if ((ex - dx) * (fy - dy) == (ey - dy) * (fx - dx)) {
|
||||
continue;
|
||||
}
|
||||
SkPath path, out;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(ax, ay);
|
||||
path.lineTo(bx, by);
|
||||
path.lineTo(cx, cy);
|
||||
path.close();
|
||||
path.moveTo(dx, dy);
|
||||
path.lineTo(ex, ey);
|
||||
path.lineTo(fx, fy);
|
||||
path.close();
|
||||
if (1) {
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", dx, dy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", ex, ey);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||
str += sprintf(str, " path.close();");
|
||||
}
|
||||
testSimplify(path, true, out);
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
testSimplify(path, true, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SimplifyNondegenerate4x4TrianglesThreaded_Test() {
|
||||
State threadState[maxThreads];
|
||||
int threadIndex = 0;
|
||||
for (int a = 0; a < 15; ++a) {
|
||||
int ax = a & 0x03;
|
||||
int ay = a >> 2;
|
||||
for (int b = a + 1; b < 16; ++b) {
|
||||
int bx = b & 0x03;
|
||||
int by = b >> 2;
|
||||
for (int c = a + 1; c < 16; ++c) {
|
||||
if (b == c) {
|
||||
continue;
|
||||
}
|
||||
int cx = c & 0x03;
|
||||
int cy = c >> 2;
|
||||
if ((bx - ax) * (cy - ay) == (by - ay) * (cx - ax)) {
|
||||
continue;
|
||||
}
|
||||
State* statePtr = &threadState[threadIndex];
|
||||
statePtr->a = a;
|
||||
statePtr->b = b;
|
||||
statePtr->c = c;
|
||||
if (maxThreads > 1) {
|
||||
createThread(statePtr, testSimplify4x4NondegeneratesMain);
|
||||
if (++threadIndex >= maxThreads) {
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
} else {
|
||||
testSimplify4x4NondegeneratesMain(statePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
|
||||
static void* testSimplify4x4DegeneratesMain(void* data) {
|
||||
char pathStr[1024];
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
SkASSERT(data);
|
||||
State& state = *(State*) data;
|
||||
int ax = state.a & 0x03;
|
||||
int ay = state.a >> 2;
|
||||
int bx = state.b & 0x03;
|
||||
int by = state.b >> 2;
|
||||
int cx = state.c & 0x03;
|
||||
int cy = state.c >> 2;
|
||||
for (int d = 0; d < 16; ++d) {
|
||||
int dx = d & 0x03;
|
||||
int dy = d >> 2;
|
||||
for (int e = d ; e < 16; ++e) {
|
||||
int ex = e & 0x03;
|
||||
int ey = e >> 2;
|
||||
for (int f = d ; f < 16; ++f) {
|
||||
int fx = f & 0x03;
|
||||
int fy = f >> 2;
|
||||
if (state.abcIsATriangle && (ex - dx) * (fy - dy)
|
||||
!= (ey - dy) * (fx - dx)) {
|
||||
continue;
|
||||
}
|
||||
SkPath path, out;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(ax, ay);
|
||||
path.lineTo(bx, by);
|
||||
path.lineTo(cx, cy);
|
||||
path.close();
|
||||
path.moveTo(dx, dy);
|
||||
path.lineTo(ex, ey);
|
||||
path.lineTo(fx, fy);
|
||||
path.close();
|
||||
if (1) {
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", dx, dy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", ex, ey);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||
str += sprintf(str, " path.close();");
|
||||
}
|
||||
testSimplify(path, true, out);
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
testSimplify(path, true, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SimplifyDegenerate4x4TrianglesThreaded_Test() {
|
||||
State threadState[maxThreads];
|
||||
int threadIndex = 0;
|
||||
for (int a = 0; a < 16; ++a) {
|
||||
int ax = a & 0x03;
|
||||
int ay = a >> 2;
|
||||
for (int b = a ; b < 16; ++b) {
|
||||
int bx = b & 0x03;
|
||||
int by = b >> 2;
|
||||
for (int c = a ; c < 16; ++c) {
|
||||
int cx = c & 0x03;
|
||||
int cy = c >> 2;
|
||||
State* statePtr = &threadState[threadIndex];
|
||||
statePtr->abcIsATriangle = (bx - ax) * (cy - ay)
|
||||
!= (by - ay) * (cx - ax);
|
||||
statePtr->a = a;
|
||||
statePtr->b = b;
|
||||
statePtr->c = c;
|
||||
if (maxThreads > 1) {
|
||||
createThread(statePtr, testSimplify4x4DegeneratesMain);
|
||||
if (++threadIndex >= maxThreads) {
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
} else {
|
||||
testSimplify4x4DegeneratesMain(statePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
|
|
@ -356,130 +356,6 @@ static void testSimplifyTriangle2() {
|
|||
testSimplify(path, true, out); // expect | |
|
||||
} // |_|
|
||||
|
||||
static void testSimplifyNondegenerate4x4Triangles() {
|
||||
char pathStr[1024];
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
for (int a = 0; a < 15; ++a) {
|
||||
int ax = a & 0x03;
|
||||
int ay = a >> 2;
|
||||
for (int b = a + 1; b < 16; ++b) {
|
||||
int bx = b & 0x03;
|
||||
int by = b >> 2;
|
||||
for (int c = a + 1; c < 16; ++c) {
|
||||
if (b == c) {
|
||||
continue;
|
||||
}
|
||||
int cx = c & 0x03;
|
||||
int cy = c >> 2;
|
||||
if ((bx - ax) * (cy - ay) == (by - ay) * (cx - ax)) {
|
||||
continue;
|
||||
}
|
||||
for (int d = 0; d < 15; ++d) {
|
||||
int dx = d & 0x03;
|
||||
int dy = d >> 2;
|
||||
for (int e = d + 1; e < 16; ++e) {
|
||||
int ex = e & 0x03;
|
||||
int ey = e >> 2;
|
||||
for (int f = d + 1; f < 16; ++f) {
|
||||
if (e == f) {
|
||||
continue;
|
||||
}
|
||||
int fx = f & 0x03;
|
||||
int fy = f >> 2;
|
||||
if ((ex - dx) * (fy - dy) == (ey - dy) * (fx - dx)) {
|
||||
continue;
|
||||
}
|
||||
SkPath path, out;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(ax, ay);
|
||||
path.lineTo(bx, by);
|
||||
path.lineTo(cx, cy);
|
||||
path.close();
|
||||
path.moveTo(dx, dy);
|
||||
path.lineTo(ex, ey);
|
||||
path.lineTo(fx, fy);
|
||||
path.close();
|
||||
if (1) {
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", dx, dy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", ex, ey);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||
str += sprintf(str, " path.close();");
|
||||
}
|
||||
testSimplify(path, true, out);
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
testSimplify(path, true, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testSimplifyDegenerate4x4Triangles() {
|
||||
char pathStr[1024];
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
for (int a = 0; a < 16; ++a) {
|
||||
int ax = a & 0x03;
|
||||
int ay = a >> 2;
|
||||
for (int b = a ; b < 16; ++b) {
|
||||
int bx = b & 0x03;
|
||||
int by = b >> 2;
|
||||
for (int c = a ; c < 16; ++c) {
|
||||
int cx = c & 0x03;
|
||||
int cy = c >> 2;
|
||||
bool abcIsATriangle = (bx - ax) * (cy - ay)
|
||||
!= (by - ay) * (cx - ax);
|
||||
for (int d = 0; d < 16; ++d) {
|
||||
int dx = d & 0x03;
|
||||
int dy = d >> 2;
|
||||
for (int e = d ; e < 16; ++e) {
|
||||
int ex = e & 0x03;
|
||||
int ey = e >> 2;
|
||||
for (int f = d ; f < 16; ++f) {
|
||||
int fx = f & 0x03;
|
||||
int fy = f >> 2;
|
||||
if (abcIsATriangle && (ex - dx) * (fy - dy)
|
||||
!= (ey - dy) * (fx - dx)) {
|
||||
continue;
|
||||
}
|
||||
SkPath path, out;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(ax, ay);
|
||||
path.lineTo(bx, by);
|
||||
path.lineTo(cx, cy);
|
||||
path.close();
|
||||
path.moveTo(dx, dy);
|
||||
path.lineTo(ex, ey);
|
||||
path.lineTo(fx, fy);
|
||||
path.close();
|
||||
if (1) {
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", dx, dy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", ex, ey);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||
str += sprintf(str, " path.close();");
|
||||
}
|
||||
testSimplify(path, true, out);
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
testSimplify(path, true, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testPathTriangleRendering() {
|
||||
SkPath one, two;
|
||||
one.moveTo(0, 0);
|
||||
|
@ -773,7 +649,79 @@ path.close();
|
|||
simplify(__FUNCTION__, path, true, out);
|
||||
}
|
||||
|
||||
static void testSimplifySkinnyTriangle11() {
|
||||
SkPath path, out;
|
||||
path.moveTo(-177.878387, 265.368988);
|
||||
path.lineTo(-254.415771, 303.709961);
|
||||
path.lineTo(-317.465363, 271.325562);
|
||||
path.lineTo(-374.520386, 207.507660);
|
||||
path.lineTo(-177.878387, 265.368988);
|
||||
path.close();
|
||||
path.moveTo(-63.582489, -3.679123);
|
||||
path.lineTo(-134.496841, 26.434566);
|
||||
path.lineTo(-205.411209, 56.548256);
|
||||
path.lineTo(-276.325562, 86.661942);
|
||||
path.lineTo(-63.582489, -3.679123);
|
||||
path.close();
|
||||
path.moveTo(-57.078423, 162.633453);
|
||||
path.lineTo(-95.963928, 106.261139);
|
||||
path.lineTo(-134.849457, 49.888824);
|
||||
path.lineTo(-173.734955, -6.483480);
|
||||
path.lineTo(-57.078423, 162.633453);
|
||||
path.close();
|
||||
simplify(__FUNCTION__, path, true, out);
|
||||
}
|
||||
|
||||
static void testSimplifySkinnyTriangle12() {
|
||||
SkPath path, out;
|
||||
path.moveTo(98.666489, -94.295059);
|
||||
path.lineTo(156.584320, -61.939133);
|
||||
path.lineTo(174.672974, -12.343765);
|
||||
path.lineTo(158.622345, 52.028267);
|
||||
path.lineTo(98.666489, -94.295059);
|
||||
path.close();
|
||||
path.moveTo(-133.225616, -48.622055);
|
||||
path.lineTo(-73.855499, -10.375397);
|
||||
path.lineTo(-14.485367, 27.871277);
|
||||
path.lineTo(44.884750, 66.117935);
|
||||
path.lineTo(-133.225616, -48.622055);
|
||||
path.close();
|
||||
path.moveTo( 9.030045, -163.413132);
|
||||
path.lineTo(-19.605331, -89.588760);
|
||||
path.lineTo(-48.240707, -15.764404);
|
||||
path.lineTo(-76.876053, 58.059944);
|
||||
path.lineTo( 9.030045, -163.413132);
|
||||
path.close();
|
||||
simplify(__FUNCTION__, path, true, out);
|
||||
}
|
||||
|
||||
static void testSimplifySkinnyTriangle13() {
|
||||
SkPath path, out;
|
||||
path.moveTo(340.41568, -170.97171);
|
||||
path.lineTo(418.846893, -142.428329);
|
||||
path.lineTo(497.278107, -113.884933);
|
||||
path.lineTo(449.18222, -45.6723022);
|
||||
path.lineTo(340.41568, -170.97171);
|
||||
path.close();
|
||||
path.moveTo(301.372925, -213.590073);
|
||||
path.lineTo(348.294434, -271.975586);
|
||||
path.lineTo(395.215973, -330.361145);
|
||||
path.lineTo(400.890381, -263.276855);
|
||||
path.lineTo(301.372925, -213.590073);
|
||||
path.close();
|
||||
path.moveTo(326.610535, 34.0393639);
|
||||
path.lineTo(371.334595, -14.9620667);
|
||||
path.lineTo(416.058624, -63.9634857);
|
||||
path.lineTo(460.782654, -112.96492);
|
||||
path.lineTo(326.610535, 34.0393639);
|
||||
path.close();
|
||||
simplify(__FUNCTION__, path, true, out);
|
||||
}
|
||||
|
||||
static void (*simplifyTests[])() = {
|
||||
testSimplifySkinnyTriangle13,
|
||||
testSimplifySkinnyTriangle12,
|
||||
testSimplifySkinnyTriangle11,
|
||||
testSimplifySkinnyTriangle10,
|
||||
testSimplifySkinnyTriangle9,
|
||||
testSimplifySkinnyTriangle8,
|
||||
|
@ -812,8 +760,6 @@ static void (*simplifyTests[])() = {
|
|||
testSimplifyTriangle2,
|
||||
testSimplifyWindingParallelogram,
|
||||
testSimplifyXorParallelogram,
|
||||
testSimplifyDegenerate4x4Triangles,
|
||||
testSimplifyNondegenerate4x4Triangles,
|
||||
testPathTriangleRendering,
|
||||
};
|
||||
|
||||
|
|
|
@ -91,79 +91,6 @@ static void testSimplifyQuad6() {
|
|||
testSimplify(path, true, out);
|
||||
}
|
||||
|
||||
static void testSimplify4x4Quadralaterals() {
|
||||
char pathStr[1024];
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
for (int a = 0; a < 16; ++a) {
|
||||
int ax = a & 0x03;
|
||||
int ay = a >> 2;
|
||||
for (int b = a ; b < 16; ++b) {
|
||||
int bx = b & 0x03;
|
||||
int by = b >> 2;
|
||||
for (int c = b ; c < 16; ++c) {
|
||||
int cx = c & 0x03;
|
||||
int cy = c >> 2;
|
||||
for (int d = c; d < 16; ++d) {
|
||||
int dx = d & 0x03;
|
||||
int dy = d >> 2;
|
||||
for (int e = 0 ; e < 16; ++e) {
|
||||
int ex = e & 0x03;
|
||||
int ey = e >> 2;
|
||||
for (int f = e ; f < 16; ++f) {
|
||||
int fx = f & 0x03;
|
||||
int fy = f >> 2;
|
||||
for (int g = f ; g < 16; ++g) {
|
||||
int gx = g & 0x03;
|
||||
int gy = g >> 2;
|
||||
for (int h = g ; h < 16; ++h) {
|
||||
int hx = h & 0x03;
|
||||
int hy = h >> 2;
|
||||
SkPath path, out;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(ax, ay);
|
||||
path.lineTo(bx, by);
|
||||
path.lineTo(cx, cy);
|
||||
path.lineTo(dx, dy);
|
||||
path.close();
|
||||
path.moveTo(ex, ey);
|
||||
path.lineTo(fx, fy);
|
||||
path.lineTo(gx, gy);
|
||||
path.lineTo(hx, hy);
|
||||
path.close();
|
||||
if (1) { // gdb: set print elements 400
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", dx, dy);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " path.moveTo(%d, %d);\n", ex, ey);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", gx, gy);
|
||||
str += sprintf(str, " path.lineTo(%d, %d);\n", hx, hy);
|
||||
str += sprintf(str, " path.close();");
|
||||
}
|
||||
if (!testSimplify(path, true, out)) {
|
||||
SkDebugf("*/\n{ SkPath::kWinding_FillType, %d, %d, %d, %d, %d, %d, %d, %d },\n/*\n",
|
||||
a, b, c, d, e, f, g, h);
|
||||
}
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
if (!testSimplify(path, true, out)) {
|
||||
SkDebugf("*/\n{ SkPath::kEvenOdd_FillType, %d, %d, %d, %d, %d, %d, %d, %d },\n/*\n",
|
||||
a, b, c, d, e, f, g, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void (*simplifyTests[])() = {
|
||||
testSimplifyQuad6,
|
||||
testSimplifyQuad5,
|
||||
|
@ -171,7 +98,6 @@ static void (*simplifyTests[])() = {
|
|||
testSimplifyQuad3,
|
||||
testSimplifyQuad2,
|
||||
testSimplifyQuad1,
|
||||
testSimplify4x4Quadralaterals,
|
||||
};
|
||||
|
||||
static size_t simplifyTestsCount = sizeof(simplifyTests) / sizeof(simplifyTests[0]);
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
|
||||
#include "SkPath.h"
|
||||
#include "ShapeOps.h"
|
||||
|
||||
extern void contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray);
|
||||
extern bool comparePaths(const SkPath& one, const SkPath& two);
|
||||
extern void comparePathsTiny(const SkPath& one, const SkPath& two);
|
||||
extern bool drawAsciiPaths(const SkPath& one, const SkPath& two,
|
||||
bool drawPaths);
|
||||
extern void simplify(const SkPath& path, bool asFill, SkPath& simple);
|
||||
extern void showPath(const SkPath& path, const char* str = NULL);
|
||||
extern bool testSimplify(const SkPath& path, bool fill, SkPath& out);
|
||||
|
|
|
@ -19,17 +19,17 @@ void showPath(const SkPath& path, const char* str) {
|
|||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
SkDebugf("path.moveTo(%3.6g, %3.6g);\n", pts[0].fX, pts[0].fY);
|
||||
SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
|
||||
continue;
|
||||
case SkPath::kLine_Verb:
|
||||
SkDebugf("path.lineTo(%3.6g, %3.6g);\n", pts[1].fX, pts[1].fY);
|
||||
SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
SkDebugf("path.quadTo(%3.6g, %3.6g, %3.6g, %3.6g);\n",
|
||||
SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
|
||||
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
SkDebugf("path.cubicTo(%3.6g, %3.6g, %3.6g, %3.6g);\n",
|
||||
SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
|
||||
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
|
||||
pts[3].fX, pts[3].fY);
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
#if 0
|
||||
// snippets that one day may be useful, unused for now...
|
||||
|
||||
// get sign, exponent, mantissa from double
|
||||
|
@ -37,4 +38,5 @@
|
|||
{ /* i.e., Mantissa is even */
|
||||
mantissa >>= 1;
|
||||
exponent++;
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -5,6 +5,8 @@ void cubecode_test(int test);
|
|||
void testSimplify();
|
||||
|
||||
void Intersection_Tests() {
|
||||
ActiveEdge_Test();
|
||||
|
||||
cubecode_test(1);
|
||||
convert_testx();
|
||||
// tests are in dependency / complexity order
|
||||
|
@ -21,6 +23,10 @@ void Intersection_Tests() {
|
|||
SimplifyRectangularPaths_Test();
|
||||
SimplifyQuadralateralPaths_Test();
|
||||
|
||||
SimplifyDegenerate4x4TrianglesThreaded_Test();
|
||||
SimplifyNondegenerate4x4TrianglesThreaded_Test();
|
||||
Simplify4x4QuadralateralsThreaded_Test();
|
||||
|
||||
QuadraticCoincidence_Test();
|
||||
QuadraticReduceOrder_Test();
|
||||
QuadraticBezierClip_Test();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
void ActiveEdge_Test();
|
||||
void ConvexHull_Test();
|
||||
void ConvexHull_X_Test();
|
||||
void CubicBezierClip_Test();
|
||||
|
@ -11,8 +12,11 @@ void LineCubicIntersection_Test();
|
|||
void LineIntersection_Test();
|
||||
void LineParameter_Test();
|
||||
void LineQuadraticIntersection_Test();
|
||||
void SimplifyDegenerate4x4TrianglesThreaded_Test();
|
||||
void SimplifyNondegenerate4x4TrianglesThreaded_Test();
|
||||
void SimplifyPolygonPaths_Test();
|
||||
void SimplifyQuadralateralPaths_Test();
|
||||
void Simplify4x4QuadralateralsThreaded_Test();
|
||||
void SimplifyRectangularPaths_Test();
|
||||
void QuadraticBezierClip_Test();
|
||||
void QuadraticCoincidence_Test();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef LineIntersection_DEFINE
|
||||
#define LineIntersection_DEFINE
|
||||
|
||||
#include "DataTypes.h"
|
||||
|
||||
|
@ -6,3 +8,5 @@ int horizontalLineIntersect(const _Line& line, double left, double right,
|
|||
double y, double tRange[2]);
|
||||
int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]);
|
||||
bool testIntersect(const _Line& a, const _Line& b);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// included by QuadraticParameterization.cpp
|
||||
// accesses internal functions to validate parameterized coefficients
|
||||
|
||||
#include "Parameterization_Test.h"
|
||||
|
||||
bool point_on_parameterized_curve(const Quadratic& quad, const _Point& point) {
|
||||
double coeffs[coeff_count];
|
||||
implicit_coefficients(quad, coeffs);
|
||||
double xx = coeffs[ xx_coeff] * point.x * point.x;
|
||||
double xy = coeffs[ xy_coeff] * point.x * point.y;
|
||||
double yy = coeffs[ yy_coeff] * point.y * point.y;
|
||||
double x = coeffs[ x_coeff] * point.x;
|
||||
double y = coeffs[ y_coeff] * point.y;
|
||||
double c = coeffs[ c_coeff];
|
||||
double sum = xx + xy + yy + x + y + c;
|
||||
return approximately_zero(sum);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "QuadraticUtilities.h"
|
||||
#include <math.h>
|
||||
|
||||
int quadraticRoots(double A, double B, double C, double t[2]) {
|
||||
B *= 2;
|
||||
|
|
|
@ -1,238 +0,0 @@
|
|||
#include "CubicIntersection.h"
|
||||
#include "Extrema.h"
|
||||
#include "IntersectionUtilities.h"
|
||||
#include "LineParameters.h"
|
||||
|
||||
#ifdef MAYBE_USEFUL_IN_THE_FUTURE
|
||||
static double interp_quad_coords(double a, double b, double c, double t)
|
||||
{
|
||||
double ab = interp(a, b, t);
|
||||
double bc = interp(b, c, t);
|
||||
return interp(ab, bc, t);
|
||||
}
|
||||
#endif
|
||||
|
||||
static double interp_cubic_coords(const double* src, double t)
|
||||
{
|
||||
double ab = interp(src[0], src[2], t);
|
||||
double bc = interp(src[2], src[4], t);
|
||||
double cd = interp(src[4], src[6], t);
|
||||
double abc = interp(ab, bc, t);
|
||||
double bcd = interp(bc, cd, t);
|
||||
return interp(abc, bcd, t);
|
||||
}
|
||||
|
||||
static int coincident_line(const Cubic& cubic, Cubic& reduction) {
|
||||
reduction[0] = reduction[1] = cubic[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vertical_line(const Cubic& cubic, Cubic& reduction) {
|
||||
double tValues[2];
|
||||
reduction[0] = cubic[0];
|
||||
reduction[1] = cubic[3];
|
||||
int smaller = reduction[1].y > reduction[0].y;
|
||||
int larger = smaller ^ 1;
|
||||
int roots = SkFindCubicExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
|
||||
for (int index = 0; index < roots; ++index) {
|
||||
double yExtrema = interp_cubic_coords(&cubic[0].y, tValues[index]);
|
||||
if (reduction[smaller].y > yExtrema) {
|
||||
reduction[smaller].y = yExtrema;
|
||||
continue;
|
||||
}
|
||||
if (reduction[larger].y < yExtrema) {
|
||||
reduction[larger].y = yExtrema;
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int horizontal_line(const Cubic& cubic, Cubic& reduction) {
|
||||
double tValues[2];
|
||||
reduction[0] = cubic[0];
|
||||
reduction[1] = cubic[3];
|
||||
int smaller = reduction[1].x > reduction[0].x;
|
||||
int larger = smaller ^ 1;
|
||||
int roots = SkFindCubicExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
|
||||
for (int index = 0; index < roots; ++index) {
|
||||
double xExtrema = interp_cubic_coords(&cubic[0].x, tValues[index]);
|
||||
if (reduction[smaller].x > xExtrema) {
|
||||
reduction[smaller].x = xExtrema;
|
||||
continue;
|
||||
}
|
||||
if (reduction[larger].x < xExtrema) {
|
||||
reduction[larger].x = xExtrema;
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
// check to see if it is a quadratic or a line
|
||||
static int check_quadratic(const Cubic& cubic, Cubic& reduction,
|
||||
int minX, int maxX, int minY, int maxY) {
|
||||
double dx10 = cubic[1].x - cubic[0].x;
|
||||
double dx23 = cubic[2].x - cubic[3].x;
|
||||
double midX = cubic[0].x + dx10 * 3 / 2;
|
||||
if (!approximately_equal(midX - cubic[3].x, dx23 * 3 / 2)) {
|
||||
return 0;
|
||||
}
|
||||
double dy10 = cubic[1].y - cubic[0].y;
|
||||
double dy23 = cubic[2].y - cubic[3].y;
|
||||
double midY = cubic[0].y + dy10 * 3 / 2;
|
||||
if (!approximately_equal(midY - cubic[3].y, dy23 * 3 / 2)) {
|
||||
return 0;
|
||||
}
|
||||
reduction[0] = cubic[0];
|
||||
reduction[1].x = midX;
|
||||
reduction[1].y = midY;
|
||||
reduction[2] = cubic[3];
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int check_linear(const Cubic& cubic, Cubic& reduction,
|
||||
int minX, int maxX, int minY, int maxY) {
|
||||
int startIndex = 0;
|
||||
int endIndex = 3;
|
||||
while (cubic[startIndex].approximatelyEqual(cubic[endIndex])) {
|
||||
--endIndex;
|
||||
if (endIndex == 0) {
|
||||
printf("%s shouldn't get here if all four points are about equal", __FUNCTION__);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
LineParameters lineParameters;
|
||||
lineParameters.cubicEndPoints(cubic, startIndex, endIndex);
|
||||
double normalSquared = lineParameters.normalSquared();
|
||||
double distance[2]; // distance is not normalized
|
||||
int mask = other_two(startIndex, endIndex);
|
||||
int inner1 = startIndex ^ mask;
|
||||
int inner2 = endIndex ^ mask;
|
||||
lineParameters.controlPtDistance(cubic, inner1, inner2, distance);
|
||||
double limit = normalSquared * SquaredEpsilon;
|
||||
int index;
|
||||
for (index = 0; index < 2; ++index) {
|
||||
double distSq = distance[index];
|
||||
distSq *= distSq;
|
||||
if (distSq > limit) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// four are colinear: return line formed by outside
|
||||
reduction[0] = cubic[0];
|
||||
reduction[1] = cubic[3];
|
||||
int sameSide1;
|
||||
int sameSide2;
|
||||
bool useX = cubic[maxX].x - cubic[minX].x >= cubic[maxY].y - cubic[minY].y;
|
||||
if (useX) {
|
||||
sameSide1 = sign(cubic[0].x - cubic[1].x) + sign(cubic[3].x - cubic[1].x);
|
||||
sameSide2 = sign(cubic[0].x - cubic[2].x) + sign(cubic[3].x - cubic[2].x);
|
||||
} else {
|
||||
sameSide1 = sign(cubic[0].y - cubic[1].y) + sign(cubic[3].y - cubic[1].y);
|
||||
sameSide2 = sign(cubic[0].y - cubic[2].y) + sign(cubic[3].y - cubic[2].y);
|
||||
}
|
||||
if (sameSide1 == sameSide2 && (sameSide1 & 3) != 2) {
|
||||
return 2;
|
||||
}
|
||||
double tValues[2];
|
||||
int roots;
|
||||
if (useX) {
|
||||
roots = SkFindCubicExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
|
||||
} else {
|
||||
roots = SkFindCubicExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
|
||||
}
|
||||
for (index = 0; index < roots; ++index) {
|
||||
_Point extrema;
|
||||
extrema.x = interp_cubic_coords(&cubic[0].x, tValues[index]);
|
||||
extrema.y = interp_cubic_coords(&cubic[0].y, tValues[index]);
|
||||
// sameSide > 0 means mid is smaller than either [0] or [3], so replace smaller
|
||||
int replace;
|
||||
if (useX) {
|
||||
if (extrema.x < cubic[0].x ^ extrema.x < cubic[3].x) {
|
||||
continue;
|
||||
}
|
||||
replace = (extrema.x < cubic[0].x | extrema.x < cubic[3].x)
|
||||
^ cubic[0].x < cubic[3].x;
|
||||
} else {
|
||||
if (extrema.y < cubic[0].y ^ extrema.y < cubic[3].y) {
|
||||
continue;
|
||||
}
|
||||
replace = (extrema.y < cubic[0].y | extrema.y < cubic[3].y)
|
||||
^ cubic[0].y < cubic[3].y;
|
||||
}
|
||||
reduction[replace] = extrema;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* food for thought:
|
||||
http://objectmix.com/graphics/132906-fast-precision-driven-cubic-quadratic-piecewise-degree-reduction-algos-2-a.html
|
||||
|
||||
Given points c1, c2, c3 and c4 of a cubic Bezier, the points of the
|
||||
corresponding quadratic Bezier are (given in convex combinations of
|
||||
points):
|
||||
|
||||
q1 = (11/13)c1 + (3/13)c2 -(3/13)c3 + (2/13)c4
|
||||
q2 = -c1 + (3/2)c2 + (3/2)c3 - c4
|
||||
q3 = (2/13)c1 - (3/13)c2 + (3/13)c3 + (11/13)c4
|
||||
|
||||
Of course, this curve does not interpolate the end-points, but it would
|
||||
be interesting to see the behaviour of such a curve in an applet.
|
||||
|
||||
--
|
||||
Kalle Rutanen
|
||||
http://kaba.hilvi.org
|
||||
|
||||
*/
|
||||
|
||||
// reduce to a quadratic or smaller
|
||||
// look for identical points
|
||||
// look for all four points in a line
|
||||
// note that three points in a line doesn't simplify a cubic
|
||||
// look for approximation with single quadratic
|
||||
// save approximation with multiple quadratics for later
|
||||
int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Flags allowQuadratics) {
|
||||
int index, minX, maxX, minY, maxY;
|
||||
int minXSet, minYSet;
|
||||
minX = maxX = minY = maxY = 0;
|
||||
minXSet = minYSet = 0;
|
||||
for (index = 1; index < 4; ++index) {
|
||||
if (cubic[minX].x > cubic[index].x) {
|
||||
minX = index;
|
||||
}
|
||||
if (cubic[minY].y > cubic[index].y) {
|
||||
minY = index;
|
||||
}
|
||||
if (cubic[maxX].x < cubic[index].x) {
|
||||
maxX = index;
|
||||
}
|
||||
if (cubic[maxY].y < cubic[index].y) {
|
||||
maxY = index;
|
||||
}
|
||||
}
|
||||
for (index = 0; index < 4; ++index) {
|
||||
if (approximately_equal(cubic[index].x, cubic[minX].x)) {
|
||||
minXSet |= 1 << index;
|
||||
}
|
||||
if (approximately_equal(cubic[index].y, cubic[minY].y)) {
|
||||
minYSet |= 1 << index;
|
||||
}
|
||||
}
|
||||
if (minXSet == 0xF) { // test for vertical line
|
||||
if (minYSet == 0xF) { // return 1 if all four are coincident
|
||||
return coincident_line(cubic, reduction);
|
||||
}
|
||||
return vertical_line(cubic, reduction);
|
||||
}
|
||||
if (minYSet == 0xF) { // test for horizontal line
|
||||
return horizontal_line(cubic, reduction);
|
||||
}
|
||||
int result = check_linear(cubic, reduction, minX, maxX, minY, maxY);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
if (allowQuadratics && (result = check_quadratic(cubic, reduction, minX, maxX, minY, maxY))) {
|
||||
return result;
|
||||
}
|
||||
memcpy(reduction, cubic, sizeof(Cubic));
|
||||
return 4;
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
#include "CubicIntersection.h"
|
||||
#include "CubicIntersection_TestData.h"
|
||||
#include "CubicIntersection_Tests.h"
|
||||
#include "QuadraticIntersection_TestData.h"
|
||||
#include "TestUtilities.h"
|
||||
|
||||
void ReduceOrder_Test() {
|
||||
size_t index;
|
||||
Cubic reduce;
|
||||
int order;
|
||||
enum {
|
||||
RunAll,
|
||||
RunPointDegenerates,
|
||||
RunNotPointDegenerates,
|
||||
RunLines,
|
||||
RunNotLines,
|
||||
RunModEpsilonLines,
|
||||
RunLessEpsilonLines,
|
||||
RunNegEpsilonLines,
|
||||
RunQuadraticLines,
|
||||
RunQuadraticModLines,
|
||||
RunComputedLines,
|
||||
RunNone
|
||||
} run = RunAll;
|
||||
int firstTestIndex = 0;
|
||||
#if 0
|
||||
run = RunComputedLines;
|
||||
firstTestIndex = 18;
|
||||
#endif
|
||||
int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates ? firstTestIndex : INT_MAX;
|
||||
int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates ? firstTestIndex : INT_MAX;
|
||||
int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : INT_MAX;
|
||||
int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : INT_MAX;
|
||||
int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines ? firstTestIndex : INT_MAX;
|
||||
int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines ? firstTestIndex : INT_MAX;
|
||||
int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines ? firstTestIndex : INT_MAX;
|
||||
int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines ? firstTestIndex : INT_MAX;
|
||||
int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines ? firstTestIndex : INT_MAX;
|
||||
int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines ? firstTestIndex : INT_MAX;
|
||||
|
||||
for (index = firstPointDegeneratesTest; index < pointDegenerates_count; ++index) {
|
||||
const Cubic& cubic = pointDegenerates[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order != 1) {
|
||||
printf("[%d] pointDegenerates order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstNotPointDegeneratesTest; index < notPointDegenerates_count; ++index) {
|
||||
const Cubic& cubic = notPointDegenerates[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order == 1) {
|
||||
printf("[%d] notPointDegenerates order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstLinesTest; index < lines_count; ++index) {
|
||||
const Cubic& cubic = lines[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order != 2) {
|
||||
printf("[%d] lines order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstNotLinesTest; index < notLines_count; ++index) {
|
||||
const Cubic& cubic = notLines[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order == 2) {
|
||||
printf("[%d] notLines order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstModEpsilonTest; index < modEpsilonLines_count; ++index) {
|
||||
const Cubic& cubic = modEpsilonLines[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order == 2) {
|
||||
printf("[%d] line mod by epsilon order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstLessEpsilonTest; index < lessEpsilonLines_count; ++index) {
|
||||
const Cubic& cubic = lessEpsilonLines[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order != 2) {
|
||||
printf("[%d] line less by epsilon/2 order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstNegEpsilonTest; index < negEpsilonLines_count; ++index) {
|
||||
const Cubic& cubic = negEpsilonLines[index];
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order != 2) {
|
||||
printf("[%d] line neg by epsilon/2 order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
|
||||
const Quadratic& quad = quadraticLines[index];
|
||||
Cubic cubic;
|
||||
quad_to_cubic(quad, cubic);
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order != 2) {
|
||||
printf("[%d] line quad order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
|
||||
const Quadratic& quad = quadraticModEpsilonLines[index];
|
||||
Cubic cubic;
|
||||
quad_to_cubic(quad, cubic);
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (order != 3) {
|
||||
printf("[%d] line mod quad order=%d\n", (int) index, order);
|
||||
}
|
||||
}
|
||||
|
||||
// test if computed line end points are valid
|
||||
for (index = firstComputedLinesTest; index < lines_count; ++index) {
|
||||
const Cubic& cubic = lines[index];
|
||||
bool controlsInside = controls_inside(cubic);
|
||||
order = reduceOrder(cubic, reduce, kReduceOrder_QuadraticsAllowed);
|
||||
if (reduce[0].x == reduce[1].x && reduce[0].y == reduce[1].y) {
|
||||
printf("[%d] line computed ends match order=%d\n", (int) index, order);
|
||||
}
|
||||
if (controlsInside) {
|
||||
if ( reduce[0].x != cubic[0].x && reduce[0].x != cubic[3].x
|
||||
|| reduce[0].y != cubic[0].y && reduce[0].y != cubic[3].y
|
||||
|| reduce[1].x != cubic[0].x && reduce[1].x != cubic[3].x
|
||||
|| reduce[1].y != cubic[0].y && reduce[1].y != cubic[3].y) {
|
||||
printf("[%d] line computed ends order=%d\n", (int) index, order);
|
||||
}
|
||||
} else {
|
||||
// binary search for extrema, compare against actual results
|
||||
// while a control point is outside of bounding box formed by end points, split
|
||||
_Rect bounds = {DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX};
|
||||
find_tight_bounds(cubic, bounds);
|
||||
if ( !approximately_equal(reduce[0].x, bounds.left) && !approximately_equal(reduce[0].x, bounds.right)
|
||||
|| !approximately_equal(reduce[0].y, bounds.top) && !approximately_equal(reduce[0].y, bounds.bottom)
|
||||
|| !approximately_equal(reduce[1].x, bounds.left) && !approximately_equal(reduce[1].x, bounds.right)
|
||||
|| !approximately_equal(reduce[1].y, bounds.top) && !approximately_equal(reduce[1].y, bounds.bottom)) {
|
||||
printf("[%d] line computed tight bounds order=%d\n", (int) index, order);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include "SkPath.h"
|
||||
|
||||
void contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray);
|
||||
void simplify(const SkPath& path, bool asFill, SkPath& simple);
|
||||
|
||||
extern const bool gShowDebugf; // FIXME: remove once debugging is complete
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.googlecode.skia.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>ShapeOpsDemo</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,110 @@
|
|||
#include "EdgeWalker_Test.h"
|
||||
#include "ShapeOps.h"
|
||||
#include "SkApplication.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkEvent.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkPaint.h"
|
||||
|
||||
SkCanvas* canvas = 0;
|
||||
SkBitmap* bitmap;
|
||||
|
||||
static bool test15(SkCanvas* canvas) {
|
||||
// Three circles bounce inside a rectangle. The circles describe three, four
|
||||
// or five points which in turn describe a polygon. The polygon points
|
||||
// bounce inside the circles. The circles rotate and scale over time. The
|
||||
// polygons are combined into a single path, simplified, and stroked.
|
||||
static int step = 0;
|
||||
const int circles = 3;
|
||||
int scales[circles];
|
||||
int angles[circles];
|
||||
int locs[circles * 2];
|
||||
int pts[circles * 2 * 4];
|
||||
int c, p;
|
||||
for (c = 0; c < circles; ++c) {
|
||||
scales[c] = abs(10 - (step + c * 4) % 21);
|
||||
angles[c] = (step + c * 6) % 600;
|
||||
locs[c * 2] = abs(130 - (step + c * 9) % 261);
|
||||
locs[c * 2 + 1] = abs(170 - (step + c * 11) % 341);
|
||||
for (p = 0; p < 4; ++p) {
|
||||
pts[c * 8 + p * 2] = abs(90 - ((step + c * 121 + p * 13) % 190));
|
||||
pts[c * 8 + p * 2 + 1] = abs(110 - ((step + c * 223 + p * 17) % 230));
|
||||
}
|
||||
}
|
||||
SkPath path, out;
|
||||
for (c = 0; c < circles; ++c) {
|
||||
for (p = 0; p < 4; ++p) {
|
||||
SkScalar x = pts[c * 8 + p * 2];
|
||||
SkScalar y = pts[c * 8 + p * 2 + 1];
|
||||
x *= 3 + scales[c] / 10.0f;
|
||||
y *= 3 + scales[c] / 10.0f;
|
||||
SkScalar angle = angles[c] * 3.1415f * 2 / 600;
|
||||
SkScalar temp = x * cos(angle) - y * sin(angle);
|
||||
y = x * sin(angle) + y * cos(angle);
|
||||
x = temp;
|
||||
x += locs[c * 2] * 200 / 130.0f;
|
||||
y += locs[c * 2 + 1] * 200 / 170.0f;
|
||||
x += 50;
|
||||
// y += 200;
|
||||
if (p == 0) {
|
||||
path.moveTo(x, y);
|
||||
} else {
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
path.close();
|
||||
}
|
||||
showPath(path, "original:");
|
||||
simplify(path, true, out);
|
||||
showPath(out, "simplified:");
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(3);
|
||||
paint.setColor(0x3F007fbF);
|
||||
canvas->drawPath(path, paint);
|
||||
paint.setColor(0xFF60FF00);
|
||||
paint.setStrokeWidth(1);
|
||||
canvas->drawPath(out, paint);
|
||||
++step;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool (*tests[])(SkCanvas* ) = {
|
||||
test15,
|
||||
};
|
||||
|
||||
static size_t testsCount = sizeof(tests) / sizeof(tests[0]);
|
||||
|
||||
static bool (*firstTest)(SkCanvas*) = test15;
|
||||
|
||||
extern "C" void* getPixels(bool* animate);
|
||||
extern "C" void unlockPixels();
|
||||
|
||||
extern "C" void* getPixels(bool* animate) {
|
||||
if (!canvas) {
|
||||
canvas = new SkCanvas();
|
||||
bitmap = new SkBitmap();
|
||||
SkBitmap::Config config = SkBitmap::kARGB_8888_Config;
|
||||
|
||||
bitmap->setConfig(config, 1100, 630);
|
||||
bitmap->allocPixels();
|
||||
bitmap->setIsOpaque(true);
|
||||
canvas->setBitmapDevice(*bitmap);
|
||||
}
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
size_t index = 0;
|
||||
if (index == 0 && firstTest) {
|
||||
while (index < testsCount && tests[index] != firstTest) {
|
||||
++index;
|
||||
}
|
||||
}
|
||||
*animate = (tests[index])(canvas);
|
||||
bitmap->lockPixels();
|
||||
return bitmap->getPixels();
|
||||
}
|
||||
|
||||
extern "C" void unlockPixels() {
|
||||
bitmap->unlockPixels();
|
||||
}
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef TSearch_DEFINED
|
||||
#define TSearch_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
// FIXME: Move this templated version into SKTSearch.h
|
||||
|
@ -61,3 +64,5 @@ void QSort(S& context, T* left, T* right,
|
|||
QSort(context, left, pivot - 1, lessThan);
|
||||
QSort(context, pivot + 1, right, lessThan);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
FE99AE40151B4ED10072AA0D /* tempskinny4.txt in Resources */ = {isa = PBXBuildFile; fileRef = FE99AE3F151B4ED10072AA0D /* tempskinny4.txt */; };
|
||||
FE99AE44151B4EE70072AA0D /* xtempskinny4.txt in Resources */ = {isa = PBXBuildFile; fileRef = FE99AE43151B4EE70072AA0D /* xtempskinny4.txt */; };
|
||||
FE99AEBE151B64ED0072AA0D /* op.htm in Resources */ = {isa = PBXBuildFile; fileRef = FE99AEBD151B64ED0072AA0D /* op.htm */; };
|
||||
FE99AF2B151CC0AA0072AA0D /* ActiveEdge_Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE99AF2A151CC0AA0072AA0D /* ActiveEdge_Test.cpp */; };
|
||||
FE99B13215209E300072AA0D /* EdgeWalkerPolygon4x4_Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE99B13115209E300072AA0D /* EdgeWalkerPolygon4x4_Test.cpp */; };
|
||||
FEA5F4E21498000C005052F9 /* libports.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FEA5F4E11497FFF6005052F9 /* libports.a */; };
|
||||
FEA61B0014EF589900B736CB /* libanimator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FEED7268144DD3EA0059E97B /* libanimator.a */; };
|
||||
FEA61B2C14F2AF6600B736CB /* EdgeWalkerRectangles_Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA61B2B14F2AF6600B736CB /* EdgeWalkerRectangles_Test.cpp */; };
|
||||
|
@ -264,6 +266,8 @@
|
|||
FE99AE3F151B4ED10072AA0D /* tempskinny4.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tempskinny4.txt; sourceTree = "<group>"; };
|
||||
FE99AE43151B4EE70072AA0D /* xtempskinny4.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = xtempskinny4.txt; sourceTree = "<group>"; };
|
||||
FE99AEBD151B64ED0072AA0D /* op.htm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = op.htm; sourceTree = "<group>"; };
|
||||
FE99AF2A151CC0AA0072AA0D /* ActiveEdge_Test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActiveEdge_Test.cpp; sourceTree = "<group>"; };
|
||||
FE99B13115209E300072AA0D /* EdgeWalkerPolygon4x4_Test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EdgeWalkerPolygon4x4_Test.cpp; sourceTree = "<group>"; };
|
||||
FEA5F4D91497FFF6005052F9 /* ports.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ports.xcodeproj; path = ../../out/gyp/ports.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
FEA61B2B14F2AF6600B736CB /* EdgeWalkerRectangles_Test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EdgeWalkerRectangles_Test.cpp; sourceTree = "<group>"; };
|
||||
FEA670F013C49E2200FE6FC1 /* SkAntiEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SkAntiEdge.cpp; sourceTree = "<group>"; };
|
||||
|
@ -525,6 +529,7 @@
|
|||
FEC123A5149001540086BF1F /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FE99AF2A151CC0AA0072AA0D /* ActiveEdge_Test.cpp */,
|
||||
FEED76C0144F3E7F0059E97B /* ConvexHull_Test.cpp */,
|
||||
FEC117CB14843B0A0086BF1F /* CubicBezierClip_Test.cpp */,
|
||||
FEED7689144F2E7D0059E97B /* CubicIntersection_Test.cpp */,
|
||||
|
@ -533,8 +538,12 @@
|
|||
FECA9A5914B3B09100B35E2C /* CubicParameterization_Test.cpp */,
|
||||
FECAAB7F14BDFAFD00B35E2C /* CubicParameterization_TestUtility.cpp */,
|
||||
FEED7625144F22E20059E97B /* CubicReduceOrder_Test.cpp */,
|
||||
FE7413DB14F6926D00056D7B /* EdgeWalker_Test.h */,
|
||||
FE7413D714F691C200056D7B /* EdgeWalker_TestUtility.cpp */,
|
||||
FE7413D314F6915A00056D7B /* EdgeWalkerPolygons_Test.cpp */,
|
||||
FE99B13115209E300072AA0D /* EdgeWalkerPolygon4x4_Test.cpp */,
|
||||
FED866D615066642006F4508 /* EdgeWalkerPolygons_Mismatches.cpp */,
|
||||
FED865F815056A79006F4508 /* EdgeWalkerQuadralaterals_Test.cpp */,
|
||||
FEA61B2B14F2AF6600B736CB /* EdgeWalkerRectangles_Test.cpp */,
|
||||
FED53C381483CB9400F6359E /* Inline_Tests.cpp */,
|
||||
FEED7680144F2E480059E97B /* Intersection_Tests.h */,
|
||||
|
@ -553,9 +562,6 @@
|
|||
FECAA6E014BDDF2D00B35E2C /* QuadraticReduceOrder_Test.cpp */,
|
||||
FEED7673144F2D770059E97B /* TestUtilities.h */,
|
||||
FEED764B144F29BD0059E97B /* TestUtilities.cpp */,
|
||||
FE7413DB14F6926D00056D7B /* EdgeWalker_Test.h */,
|
||||
FED865F815056A79006F4508 /* EdgeWalkerQuadralaterals_Test.cpp */,
|
||||
FED866D615066642006F4508 /* EdgeWalkerPolygons_Mismatches.cpp */,
|
||||
);
|
||||
name = Tests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -974,6 +980,8 @@
|
|||
FE7413D814F691C200056D7B /* EdgeWalker_TestUtility.cpp in Sources */,
|
||||
FED865F915056A79006F4508 /* EdgeWalkerQuadralaterals_Test.cpp in Sources */,
|
||||
FED866D715066642006F4508 /* EdgeWalkerPolygons_Mismatches.cpp in Sources */,
|
||||
FE99AF2B151CC0AA0072AA0D /* ActiveEdge_Test.cpp in Sources */,
|
||||
FE99B13215209E300072AA0D /* EdgeWalkerPolygon4x4_Test.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1025,92 +1033,77 @@
|
|||
C01FCF4B08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = edge_Prefix.pch;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "edge-Info.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PREBINDING = NO;
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks";
|
||||
PRODUCT_NAME = edge;
|
||||
SKIP_INSTALL = YES;
|
||||
WRAPPER_EXTENSION = app;
|
||||
ZERO_LINK = YES;
|
||||
SDKROOT = macosx10.6;
|
||||
SYMROOT = ../xcodebuild;
|
||||
WRAPPER_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C01FCF4C08A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = edge_Prefix.pch;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
INFOPLIST_FILE = "edge-Info.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks";
|
||||
PRODUCT_NAME = edge;
|
||||
SDKROOT = macosx10.6;
|
||||
SYMROOT = ../xcodebuild;
|
||||
WRAPPER_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
C01FCF4F08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_ENABLE_CPP_EXCEPTIONS = YES;
|
||||
GCC_ENABLE_CPP_RTTI = YES;
|
||||
GCC_ENABLE_SYMBOL_SEPARATION = YES;
|
||||
GCC_MODEL_TUNING = G4;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
SK_BUILD_FOR_MAC,
|
||||
SK_DEBUG,
|
||||
"\"SK_SCALAR_IS_FLOAT\"",
|
||||
"\"SK_CAN_USE_FLOAT\"",
|
||||
"\"SK_BUILD_FOR_MAC\"",
|
||||
"\"SK_USE_POSIX_THREADS\"",
|
||||
"\"GR_MAC_BUILD=1\"",
|
||||
"\"SK_SUPPORT_PDF\"",
|
||||
"\"SK_DEBUG\"",
|
||||
"\"GR_DEBUG=1\"",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_THREADSAFE_STATICS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = NO;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = YES;
|
||||
GCC_WARN_PROTOTYPE_CONVERSION = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_PREPROCESS = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = "";
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
OTHER_LDFLAGS = "";
|
||||
PREBINDING = YES;
|
||||
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES;
|
||||
SDKROOT = "";
|
||||
USER_HEADER_SEARCH_PATHS = "../../gpu/include ../../src/core ../../include/** ../../gm";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../gpu/include,
|
||||
../../src/core,
|
||||
"../../include/**",
|
||||
../../gm,
|
||||
);
|
||||
INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)";
|
||||
SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C01FCF5008A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.6;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"\"SK_SCALAR_IS_FLOAT\"",
|
||||
"\"SK_CAN_USE_FLOAT\"",
|
||||
"\"SK_BUILD_FOR_MAC\"",
|
||||
"\"SK_USE_POSIX_THREADS\"",
|
||||
"\"GR_MAC_BUILD=1\"",
|
||||
"\"SK_SUPPORT_PDF\"",
|
||||
"\"SK_RELEASE\"",
|
||||
"\"GR_RELEASE=1\"",
|
||||
"\"NDEBUG\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../gpu/include,
|
||||
../../src/core,
|
||||
"../../include/**",
|
||||
../../gm,
|
||||
);
|
||||
INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)";
|
||||
SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
@ -15,11 +15,65 @@ path.lineTo(280.861267, 299.881470);
|
|||
path.lineTo(43.485352, 308.984497);
|
||||
path.close();
|
||||
</div>
|
||||
<div id="test_2div">
|
||||
path.moveTo(-177.878387, 265.368988);
|
||||
path.lineTo(-254.415771, 303.709961);
|
||||
path.lineTo(-317.465363, 271.325562);
|
||||
path.lineTo(-374.520386, 207.507660);
|
||||
path.lineTo(-177.878387, 265.368988);
|
||||
path.close();
|
||||
path.moveTo(-63.582489, -3.679123);
|
||||
path.lineTo(-134.496841, 26.434566);
|
||||
path.lineTo(-205.411209, 56.548256);
|
||||
path.lineTo(-276.325562, 86.661942);
|
||||
path.lineTo(-63.582489, -3.679123);
|
||||
path.close();
|
||||
path.moveTo(-57.078423, 162.633453);
|
||||
path.lineTo(-95.963928, 106.261139);
|
||||
path.lineTo(-134.849457, 49.888824);
|
||||
path.lineTo(-173.734955, -6.483480);
|
||||
path.lineTo(-57.078423, 162.633453);
|
||||
path.close();
|
||||
</div>
|
||||
<div id="test_3div">
|
||||
path.moveTo(98.666489, -94.295059);
|
||||
path.lineTo(156.584320, -61.939133);
|
||||
path.lineTo(174.672974, -12.343765);
|
||||
path.lineTo(158.622345, 52.028267);
|
||||
path.lineTo(98.666489, -94.295059);
|
||||
path.close();
|
||||
path.moveTo(-133.225616, -48.622055);
|
||||
path.lineTo(-73.855499, -10.375397);
|
||||
path.lineTo(-14.485367, 27.871277);
|
||||
path.lineTo(44.884750, 66.117935);
|
||||
path.lineTo(-133.225616, -48.622055);
|
||||
path.close();
|
||||
path.moveTo( 9.030045, -163.413132);
|
||||
path.lineTo(-19.605331, -89.588760);
|
||||
path.lineTo(-48.240707, -15.764404);
|
||||
path.lineTo(-76.876053, 58.059944);
|
||||
path.lineTo( 9.030045, -163.413132);
|
||||
path.close();
|
||||
</div>
|
||||
<div id="test_4div">
|
||||
path.moveTo( -5503.40843,1749.49658);
|
||||
path.lineTo(-5503.40843,1749.49718);
|
||||
path.close();
|
||||
path.moveTo( -5503.40843,1749.49658);
|
||||
path.lineTo(-5503.40729,1749.50314);
|
||||
path.close();
|
||||
path.moveTo( -5503.40729,1749.50314);
|
||||
path.lineTo(-5503.40729,1749.50361);
|
||||
path.close();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
test_4div,
|
||||
test_3div,
|
||||
test_2div,
|
||||
test_1div,
|
||||
];
|
||||
|
||||
|
@ -37,7 +91,7 @@ var ctx;
|
|||
function parse(test) {
|
||||
var contours = [];
|
||||
var contourStrs = test.split("path.close();");
|
||||
var pattern = /\d+\.*\d*/g;
|
||||
var pattern = /-?\d+\.*\d*/g;
|
||||
for (var c in contourStrs) {
|
||||
var points = contourStrs[c].match(pattern);
|
||||
var pts = [];
|
||||
|
@ -82,7 +136,7 @@ function init(test) {
|
|||
}
|
||||
|
||||
function drawPoint(px, py, xoffset, yoffset, unit) {
|
||||
var label = px + "=" + px.toFixed(3) + ", " + py + "=" + py.toFixed(3);
|
||||
var label = px.toFixed(3) + ", " + py.toFixed(3);
|
||||
var _px = px * unit + xoffset;
|
||||
var _py = py * unit + yoffset;
|
||||
ctx.beginPath();
|
||||
|
|
Загрузка…
Ссылка в новой задаче