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