1 /*
2 * Copyright 2017 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
8 #include "src/core/SkGaussFilter.h"
9 #include "tests/Test.h"
10
11 #include <cmath>
12 #include <cstdlib>
13 #include <initializer_list>
14 #include <tuple>
15 #include <vector>
16
17 // one part in a million
18 static constexpr double kEpsilon = 0.000001;
19
careful_add(int n,double * gauss)20 static double careful_add(int n, double* gauss) {
21 // Sum smallest to largest to retain precision.
22 double sum = 0;
23 for (int i = n - 1; i >= 1; i--) {
24 sum += 2.0 * gauss[i];
25 }
26 sum += gauss[0];
27 return sum;
28 }
29
DEF_TEST(SkGaussFilterCommon,r)30 DEF_TEST(SkGaussFilterCommon, r) {
31 using Test = std::tuple<double, std::vector<double>>;
32
33 auto golden_check = [&](const Test& test) {
34 double sigma; std::vector<double> golden;
35 std::tie(sigma, golden) = test;
36 SkGaussFilter filter{sigma};
37 double result[SkGaussFilter::kGaussArrayMax];
38 int n = 0;
39 for (auto d : filter) {
40 result[n++] = d;
41 }
42 REPORTER_ASSERT(r, static_cast<size_t>(n) == golden.size());
43 double sum = careful_add(n, result);
44 REPORTER_ASSERT(r, sum == 1.0);
45 for (size_t i = 0; i < golden.size(); i++) {
46 REPORTER_ASSERT(r, std::abs(golden[i] - result[i]) < kEpsilon);
47 }
48 };
49
50 // The following two sigmas account for about 85% of all sigmas used for masks.
51 // Golden values generated using Mathematica.
52 auto tests = {
53 // GaussianMatrix[{{Automatic}, {.788675}}]
54 Test{0.788675, {0.593605, 0.176225, 0.0269721}},
55
56 // GaussianMatrix[{{4}, {1.07735}}, Method -> "Bessel"]
57 Test{1.07735, {0.429537, 0.214955, 0.059143, 0.0111337}},
58 };
59
60 for (auto& test : tests) {
61 golden_check(test);
62 }
63 }
64
DEF_TEST(SkGaussFilterSweep,r)65 DEF_TEST(SkGaussFilterSweep, r) {
66 // The double just before 2.0.
67 const double maxSigma = nextafter(2.0, 0.0);
68 auto check = [&](double sigma) {
69 SkGaussFilter filter{sigma};
70 double result[SkGaussFilter::kGaussArrayMax];
71 int n = 0;
72 for (auto d : filter) {
73 result[n++] = d;
74 }
75 REPORTER_ASSERT(r, n <= SkGaussFilter::kGaussArrayMax);
76 double sum = careful_add(n, result);
77 REPORTER_ASSERT(r, sum == 1.0);
78 };
79
80 for (double sigma = 0.0; sigma < 2.0; sigma += 0.1) {
81 check(sigma);
82 }
83 check(maxSigma);
84 }
85