/* * 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 "include/core/SkPath.h" #include "include/core/SkPoint.h" #include "include/core/SkTypes.h" #include "include/private/base/SkDebug.h" #include "src/pathops/SkIntersections.h" #include "src/pathops/SkPathOpsCubic.h" #include "src/pathops/SkPathOpsCurve.h" #include "src/pathops/SkPathOpsDebug.h" #include "src/pathops/SkPathOpsLine.h" #include "src/pathops/SkPathOpsPoint.h" #include "src/pathops/SkPathOpsTypes.h" #include <cmath> /* Find the intersection of a line and cubic by solving for valid t values. Analogous to line-quadratic intersection, solve line-cubic intersection by representing the cubic as: x = a(1-t)^3 + 2b(1-t)^2t + c(1-t)t^2 + dt^3 y = e(1-t)^3 + 2f(1-t)^2t + g(1-t)t^2 + ht^3 and the line as: y = i*x + j (if the line is more horizontal) or: x = i*y + j (if the line is more vertical) Then using Mathematica, solve for the values of t where the cubic intersects the line: (in) Resultant[ a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - x, e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - i*x - j, x] (out) -e + j + 3 e t - 3 f t - 3 e t^2 + 6 f t^2 - 3 g t^2 + e t^3 - 3 f t^3 + 3 g t^3 - h t^3 + i ( a - 3 a t + 3 b t + 3 a t^2 - 6 b t^2 + 3 c t^2 - a t^3 + 3 b t^3 - 3 c t^3 + d t^3 ) if i goes to infinity, we can rewrite the line in terms of x. Mathematica: (in) Resultant[ a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - i*y - j, e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y] (out) a - j - 3 a t + 3 b t + 3 a t^2 - 6 b t^2 + 3 c t^2 - a t^3 + 3 b t^3 - 3 c t^3 + d t^3 - i ( e - 3 e t + 3 f t + 3 e t^2 - 6 f t^2 + 3 g t^2 - e t^3 + 3 f t^3 - 3 g t^3 + h t^3 ) Solving this with Mathematica produces an expression with hundreds of terms; instead, use Numeric Solutions recipe to solve the cubic. The near-horizontal case, in terms of: Ax^3 + Bx^2 + Cx + D == 0 A = (-(-e + 3*f - 3*g + h) + i*(-a + 3*b - 3*c + d) ) B = 3*(-( e - 2*f + g ) + i*( a - 2*b + c ) ) C = 3*(-(-e + f ) + i*(-a + b ) ) D = (-( e ) + i*( a ) + j ) The near-vertical case, in terms of: Ax^3 + Bx^2 + Cx + D == 0 A = ( (-a + 3*b - 3*c + d) - i*(-e + 3*f - 3*g + h) ) B = 3*( ( a - 2*b + c ) - i*( e - 2*f + g ) ) C = 3*( (-a + b ) - i*(-e + f ) ) D = ( ( a ) - i*( e ) - j ) For horizontal lines: (in) Resultant[ a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - j, e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y] (out) e - j - 3 e t + 3 f t + 3 e t^2 - 6 f t^2 + 3 g t^2 - e t^3 + 3 f t^3 - 3 g t^3 + h t^3 */ class LineCubicIntersections { … }; int SkIntersections::horizontal(const SkDCubic& cubic, double left, double right, double y, bool flipped) { … } int SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom, double x, bool flipped) { … } int SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) { … } int SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { … } // SkDCubic accessors to Intersection utilities int SkDCubic::horizontalIntersect(double yIntercept, double roots[3]) const { … } int SkDCubic::verticalIntersect(double xIntercept, double roots[3]) const { … }