Home | History | Annotate | Download | only in Intersection
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #include "CurveIntersection.h"
      8 #include "CurveUtilities.h"
      9 #include "EdgeWalker_Test.h"
     10 #include "Intersection_Tests.h"
     11 #include "Intersections.h"
     12 #include "TestUtilities.h"
     13 
     14 struct lineQuad {
     15     Quadratic quad;
     16     _Line line;
     17     int result;
     18     _Point expected[2];
     19 } lineQuadTests[] = {
     20     //        quad                    line                  results
     21     {{{1, 1}, {2, 1}, {0, 2}},  {{0, 0}, {1, 1}},  1,  {{1, 1}        }},
     22     {{{0, 0}, {1, 1}, {3, 1}},  {{0, 0}, {3, 1}},  2,  {{0, 0}, {3, 1}}},
     23     {{{2, 0}, {1, 1}, {2, 2}},  {{0, 0}, {0, 2}},  0                   },
     24     {{{4, 0}, {0, 1}, {4, 2}},  {{3, 1}, {4, 1}},  0,                  },
     25     {{{0, 0}, {0, 1}, {1, 1}},  {{0, 1}, {1, 0}},  1,  {{.25, .75}    }},
     26 };
     27 
     28 size_t lineQuadTests_count = sizeof(lineQuadTests) / sizeof(lineQuadTests[0]);
     29 
     30 const int firstLineQuadIntersectionTest = 0;
     31 
     32 static int doIntersect(Intersections& intersections, const Quadratic& quad, const _Line& line, bool& flipped) {
     33     int result;
     34     flipped = false;
     35     if (line[0].x == line[1].x) {
     36         double top = line[0].y;
     37         double bottom = line[1].y;
     38         flipped = top > bottom;
     39         if (flipped) {
     40             SkTSwap<double>(top, bottom);
     41         }
     42         result = verticalIntersect(quad, top, bottom, line[0].x, flipped, intersections);
     43     } else if (line[0].y == line[1].y) {
     44         double left = line[0].x;
     45         double right = line[1].x;
     46         flipped = left > right;
     47         if (flipped) {
     48             SkTSwap<double>(left, right);
     49         }
     50         result = horizontalIntersect(quad, left, right, line[0].y, flipped, intersections);
     51     } else {
     52         intersect(quad, line, intersections);
     53         result = intersections.fUsed;
     54     }
     55     return result;
     56 }
     57 
     58 static struct oneLineQuad {
     59     Quadratic quad;
     60     _Line line;
     61 } oneOffs[] = {
     62     {{{369.848602,145.680267}, {382.360413,121.298294}, {406.207703,121.298294}},
     63         {{406.207703,121.298294}, {348.781738,123.864815}}}
     64     };
     65 
     66 static size_t oneOffs_count = sizeof(oneOffs) / sizeof(oneOffs[0]);
     67 
     68 
     69 static void testOneOffs() {
     70     Intersections intersections;
     71     bool flipped = false;
     72     for (size_t index = 0; index < oneOffs_count; ++index) {
     73         const Quadratic& quad = oneOffs[index].quad;
     74         const _Line& line = oneOffs[index].line;
     75         int result = doIntersect(intersections, quad, line, flipped);
     76         for (int inner = 0; inner < result; ++inner) {
     77             double quadT = intersections.fT[0][inner];
     78             double quadX, quadY;
     79             xy_at_t(quad, quadT, quadX, quadY);
     80             double lineT = intersections.fT[1][inner];
     81             double lineX, lineY;
     82             xy_at_t(line, lineT, lineX, lineY);
     83             SkASSERT(AlmostEqualUlps(quadX, lineX)
     84                     && AlmostEqualUlps(quadY, lineY));
     85         }
     86     }
     87 }
     88 
     89 void LineQuadraticIntersection_Test() {
     90     if (1) {
     91         testOneOffs();
     92     }
     93     for (size_t index = firstLineQuadIntersectionTest; index < lineQuadTests_count; ++index) {
     94         const Quadratic& quad = lineQuadTests[index].quad;
     95         const _Line& line = lineQuadTests[index].line;
     96         Quadratic reduce1;
     97         _Line reduce2;
     98         int order1 = reduceOrder(quad, reduce1, kReduceOrder_TreatAsFill);
     99         int order2 = reduceOrder(line, reduce2);
    100         if (order1 < 3) {
    101             SkDebugf("%s [%d] quad order=%d\n", __FUNCTION__, (int) index, order1);
    102             SkASSERT(0);
    103         }
    104         if (order2 < 2) {
    105             SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, (int) index, order2);
    106             SkASSERT(0);
    107         }
    108         Intersections intersections;
    109         bool flipped = false;
    110         int result = doIntersect(intersections, quad, line, flipped);
    111         SkASSERT(result == lineQuadTests[index].result);
    112         if (!intersections.intersected()) {
    113             continue;
    114         }
    115         for (int pt = 0; pt < result; ++pt) {
    116             double tt1 = intersections.fT[0][pt];
    117             SkASSERT(tt1 >= 0 && tt1 <= 1);
    118             _Point t1, t2;
    119             xy_at_t(quad, tt1, t1.x, t1.y);
    120             double tt2 = intersections.fT[1][pt];
    121             SkASSERT(tt2 >= 0 && tt2 <= 1);
    122             xy_at_t(line, tt2, t2.x, t2.y);
    123             if (!AlmostEqualUlps(t1.x, t2.x)) {
    124                 SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
    125                     __FUNCTION__, (int)index, pt, tt1, t1.x, t1.y, tt2, t2.x, t2.y);
    126                 SkASSERT(0);
    127             }
    128             if (!AlmostEqualUlps(t1.y, t2.y)) {
    129                 SkDebugf("%s [%d,%d] y!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
    130                     __FUNCTION__, (int)index, pt, tt1, t1.x, t1.y, tt2, t2.x, t2.y);
    131                 SkASSERT(0);
    132             }
    133             if (!t1.approximatelyEqual(lineQuadTests[index].expected[0])
    134                     && (lineQuadTests[index].result == 1
    135                     || !t1.approximatelyEqual(lineQuadTests[index].expected[1]))) {
    136                 SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.x, t1.y);
    137                 SkASSERT(0);
    138             }
    139         }
    140     }
    141 }
    142 
    143 static void testLineIntersect(State4& state, const Quadratic& quad, const _Line& line,
    144         const double x, const double y) {
    145     char pathStr[1024];
    146     bzero(pathStr, sizeof(pathStr));
    147     char* str = pathStr;
    148     str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", quad[0].x, quad[0].y);
    149     str += sprintf(str, "    path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", quad[1].x, quad[1].y, quad[2].x, quad[2].y);
    150     str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", line[0].x, line[0].y);
    151     str += sprintf(str, "    path.lineTo(%1.9g, %1.9g);\n", line[1].x, line[1].y);
    152 
    153     Intersections intersections;
    154     bool flipped = false;
    155     int result = doIntersect(intersections, quad, line, flipped);
    156     bool found = false;
    157     for (int index = 0; index < result; ++index) {
    158         double quadT = intersections.fT[0][index];
    159         double quadX, quadY;
    160         xy_at_t(quad, quadT, quadX, quadY);
    161         double lineT = intersections.fT[1][index];
    162         double lineX, lineY;
    163         xy_at_t(line, lineT, lineX, lineY);
    164         if (fabs(quadX - lineX) < FLT_EPSILON && fabs(quadY - lineY) < FLT_EPSILON
    165                 && fabs(x - lineX) < FLT_EPSILON && fabs(y - lineY) < FLT_EPSILON) {
    166             found = true;
    167         }
    168     }
    169     SkASSERT(found);
    170     state.testsRun++;
    171 }
    172 
    173 
    174 // find a point on a quad by choosing a t from 0 to 1
    175 // create a vertical span above and below the point
    176 // verify that intersecting the vertical span and the quad returns t
    177 // verify that a vertical span starting at quad[0] intersects at t=0
    178 // verify that a vertical span starting at quad[2] intersects at t=1
    179 static void* testQuadLineIntersectMain(void* data)
    180 {
    181     SkASSERT(data);
    182     State4& state = *(State4*) data;
    183     do {
    184         int ax = state.a & 0x03;
    185         int ay = state.a >> 2;
    186         int bx = state.b & 0x03;
    187         int by = state.b >> 2;
    188         int cx = state.c & 0x03;
    189         int cy = state.c >> 2;
    190         Quadratic quad = {{ax, ay}, {bx, by}, {cx, cy}};
    191         Quadratic reduced;
    192         int order = reduceOrder(quad, reduced, kReduceOrder_TreatAsFill);
    193         if (order < 3) {
    194             continue; // skip degenerates
    195         }
    196         for (int tIndex = 0; tIndex <= 4; ++tIndex) {
    197             double x, y;
    198             xy_at_t(quad, tIndex / 4.0, x, y);
    199             for (int h = -2; h <= 2; ++h) {
    200                 for (int v = -2; v <= 2; ++v) {
    201                     if (h == v && abs(h) != 1) {
    202                         continue;
    203                     }
    204                     _Line line = {{x - h, y - v}, {x, y}};
    205                     testLineIntersect(state, quad, line, x, y);
    206                     _Line line2 = {{x, y}, {x + h, y + v}};
    207                     testLineIntersect(state, quad, line2, x, y);
    208                     _Line line3 = {{x - h, y - v}, {x + h, y + v}};
    209                     testLineIntersect(state, quad, line3, x, y);
    210                 }
    211             }
    212         }
    213     } while (runNextTestSet(state));
    214     return NULL;
    215 }
    216 
    217 void QuadLineIntersectThreaded_Test(int& testsRun)
    218 {
    219     SkDebugf("%s\n", __FUNCTION__);
    220     const char testStr[] = "testQuadLineIntersect";
    221     initializeTests(testStr, sizeof(testStr));
    222     int testsStart = testsRun;
    223     for (int a = 0; a < 16; ++a) {
    224         for (int b = 0 ; b < 16; ++b) {
    225             for (int c = 0 ; c < 16; ++c) {
    226                 testsRun += dispatchTest4(testQuadLineIntersectMain,
    227                         a, b, c, 0);
    228             }
    229             if (!gRunTestsInOneThread) SkDebugf(".");
    230         }
    231         if (!gRunTestsInOneThread) SkDebugf("%d", a);
    232     }
    233     testsRun += waitForCompletion();
    234     SkDebugf("\n%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
    235 }
    236