1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2012 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkLineParameters_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkLineParameters_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsCubic.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsLine.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsQuad.h" 14*c8dee2aaSAndroid Build Coastguard Worker 15*c8dee2aaSAndroid Build Coastguard Worker // Sources 16*c8dee2aaSAndroid Build Coastguard Worker // computer-aided design - volume 22 number 9 november 1990 pp 538 - 549 17*c8dee2aaSAndroid Build Coastguard Worker // online at http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker // This turns a line segment into a parameterized line, of the form 20*c8dee2aaSAndroid Build Coastguard Worker // ax + by + c = 0 21*c8dee2aaSAndroid Build Coastguard Worker // When a^2 + b^2 == 1, the line is normalized. 22*c8dee2aaSAndroid Build Coastguard Worker // The distance to the line for (x, y) is d(x,y) = ax + by + c 23*c8dee2aaSAndroid Build Coastguard Worker // 24*c8dee2aaSAndroid Build Coastguard Worker // Note that the distances below are not necessarily normalized. To get the true 25*c8dee2aaSAndroid Build Coastguard Worker // distance, it's necessary to either call normalize() after xxxEndPoints(), or 26*c8dee2aaSAndroid Build Coastguard Worker // divide the result of xxxDistance() by sqrt(normalSquared()) 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker class SkLineParameters { 29*c8dee2aaSAndroid Build Coastguard Worker public: 30*c8dee2aaSAndroid Build Coastguard Worker cubicEndPoints(const SkDCubic & pts)31*c8dee2aaSAndroid Build Coastguard Worker bool cubicEndPoints(const SkDCubic& pts) { 32*c8dee2aaSAndroid Build Coastguard Worker int endIndex = 1; 33*c8dee2aaSAndroid Build Coastguard Worker cubicEndPoints(pts, 0, endIndex); 34*c8dee2aaSAndroid Build Coastguard Worker if (dy() != 0) { 35*c8dee2aaSAndroid Build Coastguard Worker return true; 36*c8dee2aaSAndroid Build Coastguard Worker } 37*c8dee2aaSAndroid Build Coastguard Worker if (dx() == 0) { 38*c8dee2aaSAndroid Build Coastguard Worker cubicEndPoints(pts, 0, ++endIndex); 39*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(endIndex == 2); 40*c8dee2aaSAndroid Build Coastguard Worker if (dy() != 0) { 41*c8dee2aaSAndroid Build Coastguard Worker return true; 42*c8dee2aaSAndroid Build Coastguard Worker } 43*c8dee2aaSAndroid Build Coastguard Worker if (dx() == 0) { 44*c8dee2aaSAndroid Build Coastguard Worker cubicEndPoints(pts, 0, ++endIndex); // line 45*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(endIndex == 3); 46*c8dee2aaSAndroid Build Coastguard Worker return false; 47*c8dee2aaSAndroid Build Coastguard Worker } 48*c8dee2aaSAndroid Build Coastguard Worker } 49*c8dee2aaSAndroid Build Coastguard Worker // FIXME: after switching to round sort, remove bumping fA 50*c8dee2aaSAndroid Build Coastguard Worker if (dx() < 0) { // only worry about y bias when breaking cw/ccw tie 51*c8dee2aaSAndroid Build Coastguard Worker return true; 52*c8dee2aaSAndroid Build Coastguard Worker } 53*c8dee2aaSAndroid Build Coastguard Worker // if cubic tangent is on x axis, look at next control point to break tie 54*c8dee2aaSAndroid Build Coastguard Worker // control point may be approximate, so it must move significantly to account for error 55*c8dee2aaSAndroid Build Coastguard Worker if (NotAlmostEqualUlps(pts[0].fY, pts[++endIndex].fY)) { 56*c8dee2aaSAndroid Build Coastguard Worker if (pts[0].fY > pts[endIndex].fY) { 57*c8dee2aaSAndroid Build Coastguard Worker fA = DBL_EPSILON; // push it from 0 to slightly negative (y() returns -a) 58*c8dee2aaSAndroid Build Coastguard Worker } 59*c8dee2aaSAndroid Build Coastguard Worker return true; 60*c8dee2aaSAndroid Build Coastguard Worker } 61*c8dee2aaSAndroid Build Coastguard Worker if (endIndex == 3) { 62*c8dee2aaSAndroid Build Coastguard Worker return true; 63*c8dee2aaSAndroid Build Coastguard Worker } 64*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(endIndex == 2); 65*c8dee2aaSAndroid Build Coastguard Worker if (pts[0].fY > pts[3].fY) { 66*c8dee2aaSAndroid Build Coastguard Worker fA = DBL_EPSILON; // push it from 0 to slightly negative (y() returns -a) 67*c8dee2aaSAndroid Build Coastguard Worker } 68*c8dee2aaSAndroid Build Coastguard Worker return true; 69*c8dee2aaSAndroid Build Coastguard Worker } 70*c8dee2aaSAndroid Build Coastguard Worker cubicEndPoints(const SkDCubic & pts,int s,int e)71*c8dee2aaSAndroid Build Coastguard Worker void cubicEndPoints(const SkDCubic& pts, int s, int e) { 72*c8dee2aaSAndroid Build Coastguard Worker fA = pts[s].fY - pts[e].fY; 73*c8dee2aaSAndroid Build Coastguard Worker fB = pts[e].fX - pts[s].fX; 74*c8dee2aaSAndroid Build Coastguard Worker fC = pts[s].fX * pts[e].fY - pts[e].fX * pts[s].fY; 75*c8dee2aaSAndroid Build Coastguard Worker } 76*c8dee2aaSAndroid Build Coastguard Worker cubicPart(const SkDCubic & part)77*c8dee2aaSAndroid Build Coastguard Worker double cubicPart(const SkDCubic& part) { 78*c8dee2aaSAndroid Build Coastguard Worker cubicEndPoints(part); 79*c8dee2aaSAndroid Build Coastguard Worker if (part[0] == part[1] || ((const SkDLine& ) part[0]).nearRay(part[2])) { 80*c8dee2aaSAndroid Build Coastguard Worker return pointDistance(part[3]); 81*c8dee2aaSAndroid Build Coastguard Worker } 82*c8dee2aaSAndroid Build Coastguard Worker return pointDistance(part[2]); 83*c8dee2aaSAndroid Build Coastguard Worker } 84*c8dee2aaSAndroid Build Coastguard Worker lineEndPoints(const SkDLine & pts)85*c8dee2aaSAndroid Build Coastguard Worker void lineEndPoints(const SkDLine& pts) { 86*c8dee2aaSAndroid Build Coastguard Worker fA = pts[0].fY - pts[1].fY; 87*c8dee2aaSAndroid Build Coastguard Worker fB = pts[1].fX - pts[0].fX; 88*c8dee2aaSAndroid Build Coastguard Worker fC = pts[0].fX * pts[1].fY - pts[1].fX * pts[0].fY; 89*c8dee2aaSAndroid Build Coastguard Worker } 90*c8dee2aaSAndroid Build Coastguard Worker quadEndPoints(const SkDQuad & pts)91*c8dee2aaSAndroid Build Coastguard Worker bool quadEndPoints(const SkDQuad& pts) { 92*c8dee2aaSAndroid Build Coastguard Worker quadEndPoints(pts, 0, 1); 93*c8dee2aaSAndroid Build Coastguard Worker if (dy() != 0) { 94*c8dee2aaSAndroid Build Coastguard Worker return true; 95*c8dee2aaSAndroid Build Coastguard Worker } 96*c8dee2aaSAndroid Build Coastguard Worker if (dx() == 0) { 97*c8dee2aaSAndroid Build Coastguard Worker quadEndPoints(pts, 0, 2); 98*c8dee2aaSAndroid Build Coastguard Worker return false; 99*c8dee2aaSAndroid Build Coastguard Worker } 100*c8dee2aaSAndroid Build Coastguard Worker if (dx() < 0) { // only worry about y bias when breaking cw/ccw tie 101*c8dee2aaSAndroid Build Coastguard Worker return true; 102*c8dee2aaSAndroid Build Coastguard Worker } 103*c8dee2aaSAndroid Build Coastguard Worker // FIXME: after switching to round sort, remove this 104*c8dee2aaSAndroid Build Coastguard Worker if (pts[0].fY > pts[2].fY) { 105*c8dee2aaSAndroid Build Coastguard Worker fA = DBL_EPSILON; 106*c8dee2aaSAndroid Build Coastguard Worker } 107*c8dee2aaSAndroid Build Coastguard Worker return true; 108*c8dee2aaSAndroid Build Coastguard Worker } 109*c8dee2aaSAndroid Build Coastguard Worker quadEndPoints(const SkDQuad & pts,int s,int e)110*c8dee2aaSAndroid Build Coastguard Worker void quadEndPoints(const SkDQuad& pts, int s, int e) { 111*c8dee2aaSAndroid Build Coastguard Worker fA = pts[s].fY - pts[e].fY; 112*c8dee2aaSAndroid Build Coastguard Worker fB = pts[e].fX - pts[s].fX; 113*c8dee2aaSAndroid Build Coastguard Worker fC = pts[s].fX * pts[e].fY - pts[e].fX * pts[s].fY; 114*c8dee2aaSAndroid Build Coastguard Worker } 115*c8dee2aaSAndroid Build Coastguard Worker quadPart(const SkDQuad & part)116*c8dee2aaSAndroid Build Coastguard Worker double quadPart(const SkDQuad& part) { 117*c8dee2aaSAndroid Build Coastguard Worker quadEndPoints(part); 118*c8dee2aaSAndroid Build Coastguard Worker return pointDistance(part[2]); 119*c8dee2aaSAndroid Build Coastguard Worker } 120*c8dee2aaSAndroid Build Coastguard Worker normalSquared()121*c8dee2aaSAndroid Build Coastguard Worker double normalSquared() const { 122*c8dee2aaSAndroid Build Coastguard Worker return fA * fA + fB * fB; 123*c8dee2aaSAndroid Build Coastguard Worker } 124*c8dee2aaSAndroid Build Coastguard Worker normalize()125*c8dee2aaSAndroid Build Coastguard Worker bool normalize() { 126*c8dee2aaSAndroid Build Coastguard Worker double normal = sqrt(normalSquared()); 127*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero(normal)) { 128*c8dee2aaSAndroid Build Coastguard Worker fA = fB = fC = 0; 129*c8dee2aaSAndroid Build Coastguard Worker return false; 130*c8dee2aaSAndroid Build Coastguard Worker } 131*c8dee2aaSAndroid Build Coastguard Worker double reciprocal = 1 / normal; 132*c8dee2aaSAndroid Build Coastguard Worker fA *= reciprocal; 133*c8dee2aaSAndroid Build Coastguard Worker fB *= reciprocal; 134*c8dee2aaSAndroid Build Coastguard Worker fC *= reciprocal; 135*c8dee2aaSAndroid Build Coastguard Worker return true; 136*c8dee2aaSAndroid Build Coastguard Worker } 137*c8dee2aaSAndroid Build Coastguard Worker cubicDistanceY(const SkDCubic & pts,SkDCubic & distance)138*c8dee2aaSAndroid Build Coastguard Worker void cubicDistanceY(const SkDCubic& pts, SkDCubic& distance) const { 139*c8dee2aaSAndroid Build Coastguard Worker double oneThird = 1 / 3.0; 140*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < 4; ++index) { 141*c8dee2aaSAndroid Build Coastguard Worker distance[index].fX = index * oneThird; 142*c8dee2aaSAndroid Build Coastguard Worker distance[index].fY = fA * pts[index].fX + fB * pts[index].fY + fC; 143*c8dee2aaSAndroid Build Coastguard Worker } 144*c8dee2aaSAndroid Build Coastguard Worker } 145*c8dee2aaSAndroid Build Coastguard Worker quadDistanceY(const SkDQuad & pts,SkDQuad & distance)146*c8dee2aaSAndroid Build Coastguard Worker void quadDistanceY(const SkDQuad& pts, SkDQuad& distance) const { 147*c8dee2aaSAndroid Build Coastguard Worker double oneHalf = 1 / 2.0; 148*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < 3; ++index) { 149*c8dee2aaSAndroid Build Coastguard Worker distance[index].fX = index * oneHalf; 150*c8dee2aaSAndroid Build Coastguard Worker distance[index].fY = fA * pts[index].fX + fB * pts[index].fY + fC; 151*c8dee2aaSAndroid Build Coastguard Worker } 152*c8dee2aaSAndroid Build Coastguard Worker } 153*c8dee2aaSAndroid Build Coastguard Worker controlPtDistance(const SkDCubic & pts,int index)154*c8dee2aaSAndroid Build Coastguard Worker double controlPtDistance(const SkDCubic& pts, int index) const { 155*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(index == 1 || index == 2); 156*c8dee2aaSAndroid Build Coastguard Worker return fA * pts[index].fX + fB * pts[index].fY + fC; 157*c8dee2aaSAndroid Build Coastguard Worker } 158*c8dee2aaSAndroid Build Coastguard Worker controlPtDistance(const SkDQuad & pts)159*c8dee2aaSAndroid Build Coastguard Worker double controlPtDistance(const SkDQuad& pts) const { 160*c8dee2aaSAndroid Build Coastguard Worker return fA * pts[1].fX + fB * pts[1].fY + fC; 161*c8dee2aaSAndroid Build Coastguard Worker } 162*c8dee2aaSAndroid Build Coastguard Worker pointDistance(const SkDPoint & pt)163*c8dee2aaSAndroid Build Coastguard Worker double pointDistance(const SkDPoint& pt) const { 164*c8dee2aaSAndroid Build Coastguard Worker return fA * pt.fX + fB * pt.fY + fC; 165*c8dee2aaSAndroid Build Coastguard Worker } 166*c8dee2aaSAndroid Build Coastguard Worker dx()167*c8dee2aaSAndroid Build Coastguard Worker double dx() const { 168*c8dee2aaSAndroid Build Coastguard Worker return fB; 169*c8dee2aaSAndroid Build Coastguard Worker } 170*c8dee2aaSAndroid Build Coastguard Worker dy()171*c8dee2aaSAndroid Build Coastguard Worker double dy() const { 172*c8dee2aaSAndroid Build Coastguard Worker return -fA; 173*c8dee2aaSAndroid Build Coastguard Worker } 174*c8dee2aaSAndroid Build Coastguard Worker 175*c8dee2aaSAndroid Build Coastguard Worker private: 176*c8dee2aaSAndroid Build Coastguard Worker double fA; 177*c8dee2aaSAndroid Build Coastguard Worker double fB; 178*c8dee2aaSAndroid Build Coastguard Worker double fC; 179*c8dee2aaSAndroid Build Coastguard Worker }; 180*c8dee2aaSAndroid Build Coastguard Worker 181*c8dee2aaSAndroid Build Coastguard Worker #endif 182