4aaaaeace7
git-svn-id: http://skia.googlecode.com/svn/trunk@7898 2bbb7eff-a529-9590-31e7-b0007b416f81
343 lines
12 KiB
C++
343 lines
12 KiB
C++
/*
|
|
* Copyright 2012 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "Simplify.h"
|
|
|
|
namespace SimplifyAngleTest {
|
|
|
|
#include "Simplify.cpp"
|
|
|
|
} // end of SimplifyAngleTest namespace
|
|
|
|
#include "Intersection_Tests.h"
|
|
|
|
static const SkPoint lines[][2] = {
|
|
{ { 10, 10}, { 10, 20} },
|
|
{ { 10, 10}, { 20, 10} },
|
|
{ { 10, 10}, {-20, 10} },
|
|
{ { 10, 10}, { 10, -20} },
|
|
{ { 10, 10}, { 20, 20} },
|
|
{ { 10, 10}, {-20, -20} },
|
|
{ { 10, 10}, {-20, 40} },
|
|
{ { 10, 10}, { 40, -20} }
|
|
};
|
|
|
|
static const size_t lineCount = sizeof(lines) / sizeof(lines[0]);
|
|
|
|
static const SkPoint quads[][3] = {
|
|
{{ 1, 1}, { 2, 2}, { 1, 3}}, // 0
|
|
{{ 1, 1}, { 3, 3}, { 1, 5}}, // 1
|
|
{{ 1, 1}, { 4, 4}, { 1, 7}}, // 2
|
|
{{ 1, 1}, { 5, 5}, { 9, 9}}, // 3
|
|
{{ 1, 1}, { 4, 4}, { 7, 1}}, // 4
|
|
{{ 1, 1}, { 3, 3}, { 5, 1}}, // 5
|
|
{{ 1, 1}, { 2, 2}, { 3, 1}}, // 6
|
|
};
|
|
|
|
static const size_t quadCount = sizeof(quads) / sizeof(quads[0]);
|
|
|
|
static const SkPoint cubics[][4] = {
|
|
{{ 1, 1}, { 2, 2}, { 2, 3}, { 1, 4}},
|
|
{{ 1, 1}, { 3, 3}, { 3, 5}, { 1, 7}},
|
|
{{ 1, 1}, { 4, 4}, { 4, 7}, { 1, 10}},
|
|
{{ 1, 1}, { 5, 5}, { 8, 8}, { 9, 9}},
|
|
{{ 1, 1}, { 4, 4}, { 7, 4}, { 10, 1}},
|
|
{{ 1, 1}, { 3, 3}, { 5, 3}, { 7, 1}},
|
|
{{ 1, 1}, { 2, 2}, { 3, 2}, { 4, 1}},
|
|
};
|
|
|
|
static const size_t cubicCount = sizeof(cubics) / sizeof(cubics[0]);
|
|
|
|
struct segment {
|
|
SkPath::Verb verb;
|
|
SkPoint pts[4];
|
|
};
|
|
|
|
static const segment segmentTest1[] = {
|
|
{SkPath::kLine_Verb, {{2, 1}, {1, 0} }},
|
|
{SkPath::kQuad_Verb, {{2, 1}, {1, 0}, {0, 0}}},
|
|
{SkPath::kQuad_Verb, {{2, 1}, {3, 2}, {2, 3}}},
|
|
{SkPath::kLine_Verb, {{2, 1}, {3, 2} }},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segment segmentTest2[] = {
|
|
{SkPath::kLine_Verb, {{1, 0}, {0, 0} }},
|
|
{SkPath::kQuad_Verb, {{1, 0}, {1.89897954f, 0.898979485f}, {2.39387703f, 1.59591794f}}},
|
|
{SkPath::kLine_Verb, {{1, 0}, {3, 2} }},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segment segmentTest3[] = {
|
|
{SkPath::kQuad_Verb, {{0, 0}, {2, 0}, {0, 1}}},
|
|
{SkPath::kQuad_Verb, {{0, 0}, {1, 0}, {0, 1}}},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segment* segmentTests[] = {
|
|
segmentTest3,
|
|
segmentTest2,
|
|
segmentTest1,
|
|
};
|
|
|
|
static const size_t segmentTestCount = sizeof(segmentTests) / sizeof(segmentTests[0]);
|
|
|
|
static void testSegments(bool testFlat) {
|
|
for (size_t testIndex = 0; testIndex < segmentTestCount; ++testIndex) {
|
|
const segment* segPtr = segmentTests[testIndex];
|
|
SimplifyAngleTest::Angle lesser, greater;
|
|
int index = 0;
|
|
do {
|
|
int next = index + 1;
|
|
SkTDArray<SimplifyAngleTest::Span> dummy;
|
|
lesser.set(segPtr[index].pts, segPtr[index].verb, NULL, index, next, dummy);
|
|
if (segPtr[next].verb == SkPath::kMove_Verb) {
|
|
break;
|
|
}
|
|
greater.set(segPtr[next].pts, segPtr[next].verb, NULL, index, next, dummy);
|
|
bool result = lesser < greater;
|
|
SkASSERT(result);
|
|
index = next;
|
|
} while (true);
|
|
}
|
|
}
|
|
|
|
static void testLines(bool testFlat) {
|
|
// create angles in a circle
|
|
SkTDArray<SimplifyAngleTest::Angle> angles;
|
|
SkTDArray<SimplifyAngleTest::Angle* > angleList;
|
|
SkTDArray<double> arcTans;
|
|
size_t x;
|
|
for (x = 0; x < lineCount; ++x) {
|
|
SimplifyAngleTest::Angle* angle = angles.append();
|
|
SkTDArray<SimplifyAngleTest::Span> dummy;
|
|
angle->set(lines[x], SkPath::kLine_Verb, 0, x, x + 1, dummy);
|
|
double arcTan = atan2(lines[x][0].fX - lines[x][1].fX,
|
|
lines[x][0].fY - lines[x][1].fY);
|
|
arcTans.push(arcTan);
|
|
}
|
|
for (x = 0; x < lineCount; ++x) {
|
|
angleList.push(&angles[x]);
|
|
}
|
|
QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
|
|
bool first = true;
|
|
bool wrap = false;
|
|
double base, last;
|
|
for (size_t x = 0; x < lineCount; ++x) {
|
|
const SimplifyAngleTest::Angle* angle = angleList[x];
|
|
int span = angle->start();
|
|
// SkDebugf("%s [%d] %1.9g (%1.9g,%1.9g %1.9g,%1.9g)\n", __FUNCTION__,
|
|
// span, arcTans[span], lines[span][0].fX, lines[span][0].fY,
|
|
// lines[span][1].fX, lines[span][1].fY);
|
|
if (first) {
|
|
base = last = arcTans[span];
|
|
first = false;
|
|
continue;
|
|
}
|
|
if (last < arcTans[span]) {
|
|
last = arcTans[span];
|
|
continue;
|
|
}
|
|
if (!wrap) {
|
|
if (base < arcTans[span]) {
|
|
SkDebugf("%s !wrap [%d] %g\n", __FUNCTION__, span, arcTans[span]);
|
|
SkASSERT(0);
|
|
}
|
|
last = arcTans[span];
|
|
wrap = true;
|
|
continue;
|
|
}
|
|
SkDebugf("%s wrap [%d] %g\n", __FUNCTION__, span, arcTans[span]);
|
|
SkASSERT(0);
|
|
}
|
|
}
|
|
|
|
static void testQuads(bool testFlat) {
|
|
SkTDArray<SimplifyAngleTest::Angle> angles;
|
|
SkTDArray<SimplifyAngleTest::Angle* > angleList;
|
|
size_t x;
|
|
for (x = 0; x < quadCount; ++x) {
|
|
SimplifyAngleTest::Angle* angle = angles.append();
|
|
SkTDArray<SimplifyAngleTest::Span> dummy;
|
|
angle->set(quads[x], SkPath::kQuad_Verb, 0, x, x + 1, dummy);
|
|
}
|
|
for (x = 0; x < quadCount; ++x) {
|
|
angleList.push(&angles[x]);
|
|
}
|
|
QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
|
|
for (size_t x = 0; x < quadCount; ++x) {
|
|
*angleList[x] < *angleList[x + 1];
|
|
SkASSERT(x == quadCount - 1 || *angleList[x] < *angleList[x + 1]);
|
|
const SimplifyAngleTest::Angle* angle = angleList[x];
|
|
if ((int) x != angle->start()) {
|
|
SkDebugf("%s [%d] [%d]\n", __FUNCTION__, x, angle->start());
|
|
SkASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void testCubics(bool testFlat) {
|
|
SkTDArray<SimplifyAngleTest::Angle> angles;
|
|
SkTDArray<SimplifyAngleTest::Angle* > angleList;
|
|
for (size_t x = 0; x < cubicCount; ++x) {
|
|
SimplifyAngleTest::Angle* angle = angles.append();
|
|
SkTDArray<SimplifyAngleTest::Span> dummy;
|
|
angle->set(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1, dummy);
|
|
angleList.push(angle);
|
|
}
|
|
QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
|
|
for (size_t x = 0; x < cubicCount; ++x) {
|
|
const SimplifyAngleTest::Angle* angle = angleList[x];
|
|
if ((int) x != angle->start()) {
|
|
SkDebugf("%s [%d] [%d]\n", __FUNCTION__, x, angle->start());
|
|
SkASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct segmentWithT {
|
|
SkPath::Verb verb;
|
|
SkPoint pts[4];
|
|
double ts[2];
|
|
};
|
|
|
|
|
|
static const segmentWithT oneOffTest1[] = {
|
|
{SkPath::kQuad_Verb, {{391.653534f, 183.286819f}, {391.653534f, 157.724487f}, {405.469604f, 141.372879f}},
|
|
{0.62346946335026932, 0.62344389027237135}},
|
|
{SkPath::kQuad_Verb, {{399.365234f, 171.695801f}, {399.365234f, 140.337967f}, {375.976227f, 140.337967f}},
|
|
{0.31638302676995866, 0.31637992418411398}},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segmentWithT oneOffTest2[] = {
|
|
{SkPath::kQuad_Verb, {{399.070374f, 151.722f}, {391.101532f, 163.002533f}, {391.101532f, 182.665863f}},
|
|
{0.13793711854916513, 0.13790171160614006}},
|
|
{SkPath::kQuad_Verb, {{391.653534f, 183.286819f}, {391.653534f, 157.724487f}, {405.469604f, 141.372879f}},
|
|
{0.62344389027237135, 0.62346946335026932}},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segmentWithT oneOffTest3[] = {
|
|
{SkPath::kQuad_Verb, {{399.365234f, 171.695801f}, {399.365234f, 140.337967f}, {375.976227f, 140.337967f}},
|
|
{0.31637992418411398, 0.31638302676995866, }},
|
|
{SkPath::kQuad_Verb, {{399.070374f, 151.722f}, {391.101532f, 163.002533f}, {391.101532f, 182.665863f}},
|
|
{0.13790171160614006, 0.13793711854916513}},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segmentWithT oneOffTest4[] = {
|
|
{SkPath::kCubic_Verb, {{1,2}, {1,3}, {1,0}, {5,3}}, {0.134792, 0}},
|
|
{SkPath::kCubic_Verb, {{0,1}, {3,5}, {2,1}, {3,1}}, {0.134792094, 0}},
|
|
{SkPath::kCubic_Verb, {{0,1}, {3,5}, {2,1}, {3,1}}, {0.134792094, 0.551812363}},
|
|
{SkPath::kCubic_Verb, {{1,2}, {1,3}, {1,0}, {5,3}}, {0.134792, 0.333333333}},
|
|
{SkPath::kMove_Verb }
|
|
};
|
|
|
|
static const segmentWithT* oneOffTests[] = {
|
|
oneOffTest1,
|
|
oneOffTest2,
|
|
oneOffTest3,
|
|
oneOffTest4,
|
|
};
|
|
|
|
static const size_t oneOffTestCount = sizeof(oneOffTests) / sizeof(oneOffTests[0]);
|
|
|
|
static void oneOffTest(bool testFlat) {
|
|
for (size_t testIndex = 0; testIndex < oneOffTestCount; ++testIndex) {
|
|
const segmentWithT* segPtr = oneOffTests[testIndex];
|
|
SimplifyAngleTest::Angle lesser, greater;
|
|
int index = 0;
|
|
do {
|
|
int next = index + 1;
|
|
SkTDArray<SimplifyAngleTest::Span> dummy; // FIXME
|
|
lesser.set(segPtr[index].pts, segPtr[index].verb, 0, index, next, dummy); // FIXME: segPtr[index].ts[0], segPtr[index].ts[1]);
|
|
if (segPtr[next].verb == SkPath::kMove_Verb) {
|
|
break;
|
|
}
|
|
greater.set(segPtr[next].pts, segPtr[next].verb, 0, index, next, dummy); // FIXME: segPtr[next].ts[0], segPtr[next].ts[1]);
|
|
bool result = lesser < greater;
|
|
SkASSERT(result);
|
|
index = next;
|
|
} while (true);
|
|
}
|
|
SkDebugf("%s finished\n", __FUNCTION__);
|
|
}
|
|
|
|
#if 0 // seems too complicated for this to be useful (didn't finish writing/debugging this)
|
|
// this (trys to) take a pair of curves, construct segments/spans, and verify that they sort correctly
|
|
static void oneOffTestNew() {
|
|
const segmentWithT* segPtr = oneOffTest4;
|
|
SimplifyAngleTest::Segment segOne, segTwo;
|
|
segOne.init(segPtr[0].pts, segPtr[0].verb, false, false);
|
|
segTwo.init(segPtr[1].pts, segPtr[1].verb, false, false);
|
|
int index = 0;
|
|
do {
|
|
int next = index + 1;
|
|
if (segPtr[index].verb == SkPath::kMove_Verb) {
|
|
break;
|
|
}
|
|
SkPoint sub[4];
|
|
(*SegmentSubDivide[segPtr[index].verb])(segPtr[index].pts, segPtr[index].ts[0],
|
|
segPtr[index].ts[1], sub);
|
|
if (memcmp(segPtr[index].pts, segPtr[0].pts, sizeof(SkPoint) * (segPtr[index].verb + 1) == 0) {
|
|
segOne.addT(&segTwo, sub[0], segPtr[index].ts[0]);
|
|
segOne.addT(&segTwo, sub[segPtr[index].verb], segPtr[index].ts[1]);
|
|
} else {
|
|
segTwo.addT(&segOne, sub[0], segPtr[index].ts[0]);
|
|
segTwo.addT(&v, sub[segPtr[index].verb], segPtr[index].ts[1]);
|
|
}
|
|
} while (true);
|
|
SimplifyAngleTest::Angle lesser, greater;
|
|
do {
|
|
int next = index + 1;
|
|
if (segPtr[next].verb == SkPath::kMove_Verb) {
|
|
break;
|
|
}
|
|
SkPoint one[4], two[4];
|
|
bool use1 = memcmp(segPtr[index].pts, segPtr[0].pts, sizeof(SkPoint) * (segPtr[index].verb + 1) == 0;
|
|
lesser.set(segPtr[index].pts, segPtr[index].verb, use1 ? &segOne : &segTwo, index, next, dummy);
|
|
use1 = memcmp(segPtr[next].pts, segPtr[0].pts, sizeof(SkPoint) * (segPtr[next].verb + 1) == 0;
|
|
greater.set(segPtr[next].pts, segPtr[next].verb, use1 ? &segOne : &segTwo, index, next, dummy);
|
|
bool result = lesser < greater;
|
|
SkASSERT(result);
|
|
index = next;
|
|
} while (true);
|
|
SkDebugf("%s finished\n", __FUNCTION__);
|
|
}
|
|
#endif
|
|
|
|
static void (*tests[])(bool) = {
|
|
oneOffTest,
|
|
testSegments,
|
|
testLines,
|
|
testQuads,
|
|
testCubics
|
|
};
|
|
|
|
static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
|
|
|
|
static void (*firstTest)(bool) = 0;
|
|
static bool skipAll = false;
|
|
|
|
void SimplifyAngle_Test() {
|
|
if (skipAll) {
|
|
return;
|
|
}
|
|
size_t index = 0;
|
|
if (firstTest) {
|
|
while (index < testCount && tests[index] != firstTest) {
|
|
++index;
|
|
}
|
|
}
|
|
bool firstTestComplete = false;
|
|
for ( ; index < testCount; ++index) {
|
|
(*tests[index])(false); // set to true to exercise setFlat
|
|
firstTestComplete = true;
|
|
}
|
|
}
|