blob: 8c540f0b990c862d4b38d01b0f975a144cae1379 [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 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000156
157 /**
158 * set this to (abs(v.x), abs(v.y))
159 */
160 void setAbs(const GrVec& v) {
161 fX = GrScalarAbs(v.fX);
162 fY = GrScalarAbs(v.fY);
163 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000164
165 /**
166 * set vector to point from a to b.
167 */
168 void setBetween(const GrPoint& a, const GrPoint& b) {
169 fX = b.fX - a.fX;
170 fY = b.fY - a.fY;
171 }
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000172
173 /**
174 * Make this vector be orthogonal to vec. Looking down vec the
175 * new vector will point left.
176 */
177 void setOrthogLeft(const GrVec& vec) {
178 // vec could be this
179 GrVec v = vec;
180 fX = -v.fY;
181 fY = v.fX;
182 }
183
184 /**
185 * Make this vector be orthogonal to vec. Looking down vec the
186 * new vector will point right.
187 */
188 void setOrthogRight(const GrVec& vec) {
189 // vec could be this
190 GrVec v = vec;
191 fX = v.fY;
192 fY = -v.fX;
193 }
194
195 /**
196 * set orthogonal to vec from a to b. Will be facing left relative to a,b
197 * vec
198 */
199 void setOrthogLeftToVecBetween(const GrPoint& a, const GrPoint& b) {
200 fX = a.fY - b.fY;
201 fY = b.fX - a.fX;
202 }
203
204 /**
205 * set orthogonal to vec from a to b. Will be facing right relative to a,b
206 * vec.
207 */
208 void setOrthogRightToVecBetween(const GrPoint& a, const GrPoint& b) {
209 fX = b.fY - a.fY;
210 fY = a.fX - b.fX;
211 }
212
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 /**
214 * length of the vector squared.
215 */
216 GrScalar lengthSqd() const {
217 return GrMul(fX, fX) + GrMul(fY, fY);
218 }
219
220 /**
221 * length of the vector.
222 */
223 GrScalar length() const {
224 // TODO: fixed point sqrt
225 return GrFloatToScalar(sqrtf(GrScalarToFloat(lengthSqd())));
226 }
227
228 /**
229 * normalizes the vector if it's length is not 0.
230 * @return true if normalized, otherwise false.
231 */
232 bool normalize() {
233 GrScalar l = lengthSqd();
234 if (l) {
235 // TODO: fixed point sqrt and invert
236 l = 1 / sqrtf(l);
237 fX *= l;
238 fY *= l;
239 return true;
240 }
241 return false;
242 }
243
244 /**
245 * Dot product of this with vec.
246 */
247 GrScalar dot(const GrVec& vec) const {
248 return GrMul(vec.fX, fX) + GrMul(vec.fY, fY);
249 }
250
251 /**
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000252 * Dot product of this vec with vector from (0,0) to a pt.
253 */
254 GrScalar dotWithVecToPt(const GrPoint& pt) const {
255 return GrMul(pt.fX, fX) + GrMul(pt.fY, fY);
256 }
257
258 /**
reed@google.comac10a2d2010-12-22 21:39:39 +0000259 * z-value of this cross vec.
260 */
261 GrScalar cross(const GrVec& vec) const {
262 return GrMul(fX, vec.fY) - GrMul(fY, vec.fX);
263 }
264
265 bool operator ==(const GrPoint& p) const {
266 return fX == p.fX && fY == p.fY;
267 }
268
269 bool operator !=(const GrPoint& p) const {
270 return fX != p.fX || fY != p.fY;
271 }
272};
273
274GrScalar GrPoint::distanceToLineBetweenSqd(const GrPoint& a,
275 const GrPoint& b) const {
276 // Let d be the distance between c (this) and line ab.
277 // The area of the triangle defined by a, b, and c is
278 // A = |b-a|*d/2. Let u = b-a and v = c-a. The cross product of
279 // u and v is aligned with the z axis and its magnitude is 2A.
280 // So d = |u x v| / |u|.
281 GrVec u, v;
282 u.setBetween(a,b);
283 v.setBetween(a,*this);
284
285 GrScalar det = u.cross(v);
286 return (GrMul(det, det)) / u.lengthSqd();
287}
288
289GrScalar GrPoint::distanceToLineBetween(const GrPoint& a,
290 const GrPoint& b) const {
291 GrVec u, v;
292 u.setBetween(a,b);
293 v.setBetween(a,*this);
294
295 GrScalar det = u.cross(v);
296 return (GrScalarAbs(det)) / u.length();
297}
298
299GrScalar GrPoint::distanceToLineSegmentBetweenSqd(const GrPoint& a,
300 const GrPoint& b) const {
301 // See comments to distanceToLineBetweenSqd. If the projection of c onto
302 // u is between a and b then this returns the same result as that
303 // function. Otherwise, it returns the distance to the closer of a and
304 // b. Let the projection of v onto u be v'. There are three cases:
305 // 1. v' points opposite to u. c is not between a and b and is closer
306 // to a than b.
307 // 2. v' points along u and has magnitude less than y. c is between
308 // a and b and the distance to the segment is the same as distance
309 // to the line ab.
310 // 3. v' points along u and has greater magnitude than u. c is not
311 // not between a and b and is closer to b than a.
312 // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
313 // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
314 // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
315 // avoid a sqrt to compute |u|.
316
317 GrVec u, v;
318 u.setBetween(a,b);
319 v.setBetween(a,*this);
320
321 GrScalar uLengthSqd = u.lengthSqd();
322 GrScalar uDotV = u.dot(v);
323
324 if (uDotV <= 0) {
325 return v.lengthSqd();
326 } else if (uDotV > uLengthSqd) {
327 return b.distanceToSqd(*this);
328 } else {
329 GrScalar det = u.cross(v);
330 return (GrMul(det, det)) / uLengthSqd;
331 }
332}
333
334GrScalar GrPoint::distanceToLineSegmentBetween(const GrPoint& a,
335 const GrPoint& b) const {
336 // TODO: fixed point sqrt
337 return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToLineSegmentBetweenSqd(a,b))));
338}
339
340
341#endif
342