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#ifndef SkPathOpsPoint_DEFINED
8#define SkPathOpsPoint_DEFINED
9
10#include "SkPathOpsTypes.h"
11#include "SkPoint.h"
12
13inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
14    return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY);
15}
16
17struct SkDVector {
18    double fX, fY;
19
20    friend SkDPoint operator+(const SkDPoint& a, const SkDVector& b);
21
22    void operator+=(const SkDVector& v) {
23        fX += v.fX;
24        fY += v.fY;
25    }
26
27    void operator-=(const SkDVector& v) {
28        fX -= v.fX;
29        fY -= v.fY;
30    }
31
32    void operator/=(const double s) {
33        fX /= s;
34        fY /= s;
35    }
36
37    void operator*=(const double s) {
38        fX *= s;
39        fY *= s;
40    }
41
42    SkVector asSkVector() const {
43        SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
44        return v;
45    }
46
47    double cross(const SkDVector& a) const {
48        return fX * a.fY - fY * a.fX;
49    }
50
51    double dot(const SkDVector& a) const {
52        return fX * a.fX + fY * a.fY;
53    }
54
55    double length() const {
56        return sqrt(lengthSquared());
57    }
58
59    double lengthSquared() const {
60        return fX * fX + fY * fY;
61    }
62};
63
64struct SkDPoint {
65    double fX;
66    double fY;
67
68    void set(const SkPoint& pt) {
69        fX = pt.fX;
70        fY = pt.fY;
71    }
72
73    friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b);
74
75    friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
76        return a.fX == b.fX && a.fY == b.fY;
77    }
78
79    friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
80        return a.fX != b.fX || a.fY != b.fY;
81    }
82
83    void operator=(const SkPoint& pt) {
84        fX = pt.fX;
85        fY = pt.fY;
86    }
87
88
89    void operator+=(const SkDVector& v) {
90        fX += v.fX;
91        fY += v.fY;
92    }
93
94    void operator-=(const SkDVector& v) {
95        fX -= v.fX;
96        fY -= v.fY;
97    }
98
99    // note: this can not be implemented with
100    // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
101    // because that will not take the magnitude of the values into account
102    bool approximatelyEqual(const SkDPoint& a) const {
103        if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
104            return true;
105        }
106        if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
107            return false;
108        }
109        double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
110        double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
111        double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
112        largest = SkTMax(largest, -tiniest);
113        return AlmostBequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
114    }
115
116    bool approximatelyEqual(const SkPoint& a) const {
117        SkDPoint dA;
118        dA.set(a);
119        return approximatelyEqual(dA);
120    }
121
122    static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
123        if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
124            return true;
125        }
126        if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
127            return false;
128        }
129        SkDPoint dA, dB;
130        dA.set(a);
131        dB.set(b);
132        double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
133        float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
134        float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
135        largest = SkTMax(largest, -tiniest);
136        return AlmostBequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
137    }
138
139    bool approximatelyPEqual(const SkDPoint& a) const {
140        if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
141            return true;
142        }
143        if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
144            return false;
145        }
146        double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
147        double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
148        double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
149        largest = SkTMax(largest, -tiniest);
150        return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
151    }
152
153    bool approximatelyZero() const {
154        return approximately_zero(fX) && approximately_zero(fY);
155    }
156
157    SkPoint asSkPoint() const {
158        SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
159        return pt;
160    }
161
162    double distance(const SkDPoint& a) const {
163        SkDVector temp = *this - a;
164        return temp.length();
165    }
166
167    double distanceSquared(const SkDPoint& a) const {
168        SkDVector temp = *this - a;
169        return temp.lengthSquared();
170    }
171
172    static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
173        SkDPoint result;
174        result.fX = (a.fX + b.fX) / 2;
175        result.fY = (a.fY + b.fY) / 2;
176        return result;
177    }
178
179    bool moreRoughlyEqual(const SkDPoint& a) const {
180        if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
181            return true;
182        }
183        double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
184        double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
185        double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
186        largest = SkTMax(largest, -tiniest);
187        return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
188    }
189
190    bool roughlyEqual(const SkDPoint& a) const {
191        return roughly_equal(a.fY, fY) && roughly_equal(a.fX, fX);
192    }
193
194    #ifdef SK_DEBUG
195    void dump() {
196        SkDebugf("{");
197        DebugDumpDouble(fX);
198        SkDebugf(", ");
199        DebugDumpDouble(fY);
200        SkDebugf("}");
201    }
202
203    static void dump(const SkPoint& pt) {
204        SkDebugf("{");
205        DebugDumpFloat(pt.fX);
206        SkDebugf(", ");
207        DebugDumpFloat(pt.fY);
208        SkDebugf("}");
209    }
210   #endif
211};
212
213#endif
214