| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "impeller/geometry/wangs_formula.h" |
| |
| namespace impeller { |
| |
| namespace { |
| |
| // Don't allow linearized segments to be off by more than 1/4th of a pixel from |
| // the true curve. This value should be scaled by the max basis of the |
| // X and Y directions. |
| constexpr static Scalar kPrecision = 4; |
| |
| } // namespace |
| |
| Scalar ComputeCubicSubdivisions(Scalar scale_factor, |
| Point p0, |
| Point p1, |
| Point p2, |
| Point p3) { |
| const Scalar k = scale_factor * .75f * kPrecision; |
| const Vector2 a = p0 - p1 * 2 + p2; |
| const Vector2 b = p1 - p2 * 2 + p3; |
| const Scalar max_len_sq = |
| std::max(a.GetLengthSquared(), b.GetLengthSquared()); |
| return std::sqrt(k * std::sqrt(max_len_sq)); |
| } |
| |
| Scalar ComputeQuadradicSubdivisions(Scalar scale_factor, |
| Point p0, |
| Point p1, |
| Point p2) { |
| const Scalar k = scale_factor * .25f * kPrecision; |
| return std::sqrt(k * (p0 - p1 * 2 + p2).GetLength()); |
| } |
| |
| // Returns Wang's formula specialized for a conic curve. |
| // |
| // This is not actually due to Wang, but is an analogue from: |
| // (Theorem 3, corollary 1): |
| // J. Zheng, T. Sederberg. "Estimating Tessellation Parameter Intervals for |
| // Rational Curves and Surfaces." ACM Transactions on Graphics 19(1). 2000. |
| Scalar ComputeConicSubdivisions(Scalar scale_factor, |
| Point p0, |
| Point p1, |
| Point p2, |
| Scalar w) { |
| // Compute center of bounding box in projected space |
| const Point C = 0.5f * (p0.Min(p1).Min(p2) + p0.Max(p1).Max(p2)); |
| |
| // Translate by -C. This improves translation-invariance of the formula, |
| // see Sec. 3.3 of cited paper |
| p0 -= C; |
| p1 -= C; |
| p2 -= C; |
| |
| // Compute max length |
| const Scalar max_len = |
| std::sqrt(std::max(p0.Dot(p0), std::max(p1.Dot(p1), p2.Dot(p2)))); |
| |
| // Compute forward differences |
| const Point dp = -2 * w * p1 + p0 + p2; |
| const Scalar dw = std::abs(-2 * w + 2); |
| |
| // Compute numerator and denominator for parametric step size of |
| // linearization. Here, the epsilon referenced from the cited paper |
| // is 1/precision. |
| Scalar k = scale_factor * kPrecision; |
| const Scalar rp_minus_1 = std::max(0.0f, max_len * k - 1); |
| const Scalar numer = std::sqrt(dp.Dot(dp)) * k + rp_minus_1 * dw; |
| const Scalar denom = 4 * std::min(w, 1.0f); |
| |
| // Number of segments = sqrt(numer / denom). |
| // This assumes parametric interval of curve being linearized is |
| // [t0,t1] = [0, 1]. |
| // If not, the number of segments is (tmax - tmin) / sqrt(denom / numer). |
| return std::sqrt(numer / denom); |
| } |
| |
| } // namespace impeller |