blob: bb24959c34d8c549a386837b14c796abe4111241 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#ifndef GrPoint_DEFINED
19#define GrPoint_DEFINED
20
21#include "GrTypes.h"
22#include "GrScalar.h"
23
24/**
25 * 2D Point struct
26 */
27struct GrPoint {
28public:
29 GrScalar fX, fY;
30
31 GrPoint() {}
32 GrPoint(GrScalar x, GrScalar y) { fX = x; fY = y; }
33
34 GrScalar x() const { return fX; }
35 GrScalar y() const { return fY; }
36
37 void set(GrScalar x, GrScalar y) {
38 fX = x;
39 fY = y;
40 }
41
42 void setAsMidPoint(const GrPoint& a, const GrPoint& b) {
43 fX = GrScalarAve(a.fX, b.fX);
44 fY = GrScalarAve(a.fY, b.fY);
45 }
46
47 void offset(GrScalar dx, GrScalar dy) {
48 fX += dx;
49 fY += dy;
50 }
51
52 GrScalar distanceToSqd(const GrPoint& p) const {
53 GrScalar dx = (p.fX - fX);
54 GrScalar dy = (p.fY - fY);
55 return GrMul(dx, dx) + GrMul(dy, dy);
56 }
57
58 GrScalar distanceTo(const GrPoint& p) const {
59 // TODO: fixed point sqrt
60 return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToSqd(p))));
61 }
62
63 GrScalar distanceToOriginSqd() const {
64 return GrMul(fX, fX) + GrMul(fY, fY);
65 }
66
67 GrScalar distanceToOrigin() const {
68 return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToOriginSqd())));
69 }
70
71 inline GrScalar distanceToLineBetweenSqd(const GrPoint& a,
72 const GrPoint& b) const;
73
74 inline GrScalar distanceToLineBetween(const GrPoint& a,
75 const GrPoint& b) const;
76
77 inline GrScalar distanceToLineSegmentBetweenSqd(const GrPoint& a,
78 const GrPoint& b) const;
79
80 inline GrScalar distanceToLineSegmentBetween(const GrPoint& a,
81 const GrPoint& b) const;
82
83 // counter-clockwise fan
84 void setRectFan(GrScalar l, GrScalar t, GrScalar r, GrScalar b) {
85 GrPoint* v = this;
86 v[0].set(l, t);
87 v[1].set(l, b);
88 v[2].set(r, b);
89 v[3].set(r, t);
90 }
91
92 void setRectFan(GrScalar l, GrScalar t, GrScalar r, GrScalar b, size_t stride) {
93 GrAssert(stride >= sizeof(GrPoint));
94 ((GrPoint*)((intptr_t)this + 0 * stride))->set(l, t);
95 ((GrPoint*)((intptr_t)this + 1 * stride))->set(l, b);
96 ((GrPoint*)((intptr_t)this + 2 * stride))->set(r, b);
97 ((GrPoint*)((intptr_t)this + 3 * stride))->set(r, t);
98 }
99
100 // counter-clockwise fan
101 void setIRectFan(int l, int t, int r, int b) {
102 GrPoint* v = this;
103 v[0].set(GrIntToScalar(l), GrIntToScalar(t));
104 v[1].set(GrIntToScalar(l), GrIntToScalar(b));
105 v[2].set(GrIntToScalar(r), GrIntToScalar(b));
106 v[3].set(GrIntToScalar(r), GrIntToScalar(t));
107 }
108
109 void setIRectFan(int l, int t, int r, int b, size_t stride) {
110 GrAssert(stride >= sizeof(GrPoint));
111 ((GrPoint*)((intptr_t)this + 0 * stride))->set(GrIntToScalar(l),
112 GrIntToScalar(t));
113 ((GrPoint*)((intptr_t)this + 1 * stride))->set(GrIntToScalar(l),
114 GrIntToScalar(b));
115 ((GrPoint*)((intptr_t)this + 2 * stride))->set(GrIntToScalar(r),
116 GrIntToScalar(b));
117 ((GrPoint*)((intptr_t)this + 3 * stride))->set(GrIntToScalar(r),
118 GrIntToScalar(t));
119 }
120
121 bool operator ==(const GrPoint& p) const {
122 return fX == p.fX && fY == p.fY;
123 }
124
125 bool operator !=(const GrPoint& p) const {
126 return fX != p.fX || fY != p.fY;
127 }
128};
129
130struct GrIPoint16 {
131 int16_t fX, fY;
132
133 void set(intptr_t x, intptr_t y) {
134 fX = GrToS16(x);
135 fY = GrToS16(y);
136 }
137};
138
139struct GrVec {
140public:
141 GrScalar fX, fY;
142
143 GrVec() {}
144 GrVec(GrScalar x, GrScalar y) { fX = x; fY = y; }
145
146 GrScalar x() const { return fX; }
147 GrScalar y() const { return fY; }
148
149 /**
150 * set x and y length of the vector.
151 */
152 void set(GrScalar x, GrScalar y) {
153 fX = x;
154 fY = y;
155 }
156
157 /**
158 * set vector to point from a to b.
159 */
160 void setBetween(const GrPoint& a, const GrPoint& b) {
161 fX = b.fX - a.fX;
162 fY = b.fY - a.fY;
163 }
164
165 /**
166 * length of the vector squared.
167 */
168 GrScalar lengthSqd() const {
169 return GrMul(fX, fX) + GrMul(fY, fY);
170 }
171
172 /**
173 * length of the vector.
174 */
175 GrScalar length() const {
176 // TODO: fixed point sqrt
177 return GrFloatToScalar(sqrtf(GrScalarToFloat(lengthSqd())));
178 }
179
180 /**
181 * normalizes the vector if it's length is not 0.
182 * @return true if normalized, otherwise false.
183 */
184 bool normalize() {
185 GrScalar l = lengthSqd();
186 if (l) {
187 // TODO: fixed point sqrt and invert
188 l = 1 / sqrtf(l);
189 fX *= l;
190 fY *= l;
191 return true;
192 }
193 return false;
194 }
195
196 /**
197 * Dot product of this with vec.
198 */
199 GrScalar dot(const GrVec& vec) const {
200 return GrMul(vec.fX, fX) + GrMul(vec.fY, fY);
201 }
202
203 /**
204 * z-value of this cross vec.
205 */
206 GrScalar cross(const GrVec& vec) const {
207 return GrMul(fX, vec.fY) - GrMul(fY, vec.fX);
208 }
209
210 bool operator ==(const GrPoint& p) const {
211 return fX == p.fX && fY == p.fY;
212 }
213
214 bool operator !=(const GrPoint& p) const {
215 return fX != p.fX || fY != p.fY;
216 }
217};
218
219GrScalar GrPoint::distanceToLineBetweenSqd(const GrPoint& a,
220 const GrPoint& b) const {
221 // Let d be the distance between c (this) and line ab.
222 // The area of the triangle defined by a, b, and c is
223 // A = |b-a|*d/2. Let u = b-a and v = c-a. The cross product of
224 // u and v is aligned with the z axis and its magnitude is 2A.
225 // So d = |u x v| / |u|.
226 GrVec u, v;
227 u.setBetween(a,b);
228 v.setBetween(a,*this);
229
230 GrScalar det = u.cross(v);
231 return (GrMul(det, det)) / u.lengthSqd();
232}
233
234GrScalar GrPoint::distanceToLineBetween(const GrPoint& a,
235 const GrPoint& b) const {
236 GrVec u, v;
237 u.setBetween(a,b);
238 v.setBetween(a,*this);
239
240 GrScalar det = u.cross(v);
241 return (GrScalarAbs(det)) / u.length();
242}
243
244GrScalar GrPoint::distanceToLineSegmentBetweenSqd(const GrPoint& a,
245 const GrPoint& b) const {
246 // See comments to distanceToLineBetweenSqd. If the projection of c onto
247 // u is between a and b then this returns the same result as that
248 // function. Otherwise, it returns the distance to the closer of a and
249 // b. Let the projection of v onto u be v'. There are three cases:
250 // 1. v' points opposite to u. c is not between a and b and is closer
251 // to a than b.
252 // 2. v' points along u and has magnitude less than y. c is between
253 // a and b and the distance to the segment is the same as distance
254 // to the line ab.
255 // 3. v' points along u and has greater magnitude than u. c is not
256 // not between a and b and is closer to b than a.
257 // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
258 // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
259 // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
260 // avoid a sqrt to compute |u|.
261
262 GrVec u, v;
263 u.setBetween(a,b);
264 v.setBetween(a,*this);
265
266 GrScalar uLengthSqd = u.lengthSqd();
267 GrScalar uDotV = u.dot(v);
268
269 if (uDotV <= 0) {
270 return v.lengthSqd();
271 } else if (uDotV > uLengthSqd) {
272 return b.distanceToSqd(*this);
273 } else {
274 GrScalar det = u.cross(v);
275 return (GrMul(det, det)) / uLengthSqd;
276 }
277}
278
279GrScalar GrPoint::distanceToLineSegmentBetween(const GrPoint& a,
280 const GrPoint& b) const {
281 // TODO: fixed point sqrt
282 return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToLineSegmentBetweenSqd(a,b))));
283}
284
285
286#endif
287