| /* |
| Copyright 2010 Google Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| |
| #ifndef GrPoint_DEFINED |
| #define GrPoint_DEFINED |
| |
| #include "GrTypes.h" |
| #include "GrScalar.h" |
| |
| /** |
| * 2D Point struct |
| */ |
| struct GrPoint { |
| public: |
| GrScalar fX, fY; |
| |
| GrPoint() {} |
| GrPoint(GrScalar x, GrScalar y) { fX = x; fY = y; } |
| |
| GrScalar x() const { return fX; } |
| GrScalar y() const { return fY; } |
| |
| void set(GrScalar x, GrScalar y) { |
| fX = x; |
| fY = y; |
| } |
| |
| void setAsMidPoint(const GrPoint& a, const GrPoint& b) { |
| fX = GrScalarAve(a.fX, b.fX); |
| fY = GrScalarAve(a.fY, b.fY); |
| } |
| |
| void offset(GrScalar dx, GrScalar dy) { |
| fX += dx; |
| fY += dy; |
| } |
| |
| GrScalar distanceToSqd(const GrPoint& p) const { |
| GrScalar dx = (p.fX - fX); |
| GrScalar dy = (p.fY - fY); |
| return GrMul(dx, dx) + GrMul(dy, dy); |
| } |
| |
| GrScalar distanceTo(const GrPoint& p) const { |
| // TODO: fixed point sqrt |
| return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToSqd(p)))); |
| } |
| |
| GrScalar distanceToOriginSqd() const { |
| return GrMul(fX, fX) + GrMul(fY, fY); |
| } |
| |
| GrScalar distanceToOrigin() const { |
| return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToOriginSqd()))); |
| } |
| |
| inline GrScalar distanceToLineBetweenSqd(const GrPoint& a, |
| const GrPoint& b) const; |
| |
| inline GrScalar distanceToLineBetween(const GrPoint& a, |
| const GrPoint& b) const; |
| |
| inline GrScalar distanceToLineSegmentBetweenSqd(const GrPoint& a, |
| const GrPoint& b) const; |
| |
| inline GrScalar distanceToLineSegmentBetween(const GrPoint& a, |
| const GrPoint& b) const; |
| |
| // counter-clockwise fan |
| void setRectFan(GrScalar l, GrScalar t, GrScalar r, GrScalar b) { |
| GrPoint* v = this; |
| v[0].set(l, t); |
| v[1].set(l, b); |
| v[2].set(r, b); |
| v[3].set(r, t); |
| } |
| |
| void setRectFan(GrScalar l, GrScalar t, GrScalar r, GrScalar b, size_t stride) { |
| GrAssert(stride >= sizeof(GrPoint)); |
| ((GrPoint*)((intptr_t)this + 0 * stride))->set(l, t); |
| ((GrPoint*)((intptr_t)this + 1 * stride))->set(l, b); |
| ((GrPoint*)((intptr_t)this + 2 * stride))->set(r, b); |
| ((GrPoint*)((intptr_t)this + 3 * stride))->set(r, t); |
| } |
| |
| // counter-clockwise fan |
| void setIRectFan(int l, int t, int r, int b) { |
| GrPoint* v = this; |
| v[0].set(GrIntToScalar(l), GrIntToScalar(t)); |
| v[1].set(GrIntToScalar(l), GrIntToScalar(b)); |
| v[2].set(GrIntToScalar(r), GrIntToScalar(b)); |
| v[3].set(GrIntToScalar(r), GrIntToScalar(t)); |
| } |
| |
| void setIRectFan(int l, int t, int r, int b, size_t stride) { |
| GrAssert(stride >= sizeof(GrPoint)); |
| ((GrPoint*)((intptr_t)this + 0 * stride))->set(GrIntToScalar(l), |
| GrIntToScalar(t)); |
| ((GrPoint*)((intptr_t)this + 1 * stride))->set(GrIntToScalar(l), |
| GrIntToScalar(b)); |
| ((GrPoint*)((intptr_t)this + 2 * stride))->set(GrIntToScalar(r), |
| GrIntToScalar(b)); |
| ((GrPoint*)((intptr_t)this + 3 * stride))->set(GrIntToScalar(r), |
| GrIntToScalar(t)); |
| } |
| |
| bool operator ==(const GrPoint& p) const { |
| return fX == p.fX && fY == p.fY; |
| } |
| |
| bool operator !=(const GrPoint& p) const { |
| return fX != p.fX || fY != p.fY; |
| } |
| }; |
| |
| struct GrIPoint16 { |
| int16_t fX, fY; |
| |
| void set(intptr_t x, intptr_t y) { |
| fX = GrToS16(x); |
| fY = GrToS16(y); |
| } |
| }; |
| |
| struct GrVec { |
| public: |
| GrScalar fX, fY; |
| |
| GrVec() {} |
| GrVec(GrScalar x, GrScalar y) { fX = x; fY = y; } |
| |
| GrScalar x() const { return fX; } |
| GrScalar y() const { return fY; } |
| |
| /** |
| * set x and y length of the vector. |
| */ |
| void set(GrScalar x, GrScalar y) { |
| fX = x; |
| fY = y; |
| } |
| |
| /** |
| * set vector to point from a to b. |
| */ |
| void setBetween(const GrPoint& a, const GrPoint& b) { |
| fX = b.fX - a.fX; |
| fY = b.fY - a.fY; |
| } |
| |
| /** |
| * length of the vector squared. |
| */ |
| GrScalar lengthSqd() const { |
| return GrMul(fX, fX) + GrMul(fY, fY); |
| } |
| |
| /** |
| * length of the vector. |
| */ |
| GrScalar length() const { |
| // TODO: fixed point sqrt |
| return GrFloatToScalar(sqrtf(GrScalarToFloat(lengthSqd()))); |
| } |
| |
| /** |
| * normalizes the vector if it's length is not 0. |
| * @return true if normalized, otherwise false. |
| */ |
| bool normalize() { |
| GrScalar l = lengthSqd(); |
| if (l) { |
| // TODO: fixed point sqrt and invert |
| l = 1 / sqrtf(l); |
| fX *= l; |
| fY *= l; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Dot product of this with vec. |
| */ |
| GrScalar dot(const GrVec& vec) const { |
| return GrMul(vec.fX, fX) + GrMul(vec.fY, fY); |
| } |
| |
| /** |
| * z-value of this cross vec. |
| */ |
| GrScalar cross(const GrVec& vec) const { |
| return GrMul(fX, vec.fY) - GrMul(fY, vec.fX); |
| } |
| |
| bool operator ==(const GrPoint& p) const { |
| return fX == p.fX && fY == p.fY; |
| } |
| |
| bool operator !=(const GrPoint& p) const { |
| return fX != p.fX || fY != p.fY; |
| } |
| }; |
| |
| GrScalar GrPoint::distanceToLineBetweenSqd(const GrPoint& a, |
| const GrPoint& b) const { |
| // Let d be the distance between c (this) and line ab. |
| // The area of the triangle defined by a, b, and c is |
| // A = |b-a|*d/2. Let u = b-a and v = c-a. The cross product of |
| // u and v is aligned with the z axis and its magnitude is 2A. |
| // So d = |u x v| / |u|. |
| GrVec u, v; |
| u.setBetween(a,b); |
| v.setBetween(a,*this); |
| |
| GrScalar det = u.cross(v); |
| return (GrMul(det, det)) / u.lengthSqd(); |
| } |
| |
| GrScalar GrPoint::distanceToLineBetween(const GrPoint& a, |
| const GrPoint& b) const { |
| GrVec u, v; |
| u.setBetween(a,b); |
| v.setBetween(a,*this); |
| |
| GrScalar det = u.cross(v); |
| return (GrScalarAbs(det)) / u.length(); |
| } |
| |
| GrScalar GrPoint::distanceToLineSegmentBetweenSqd(const GrPoint& a, |
| const GrPoint& b) const { |
| // See comments to distanceToLineBetweenSqd. If the projection of c onto |
| // u is between a and b then this returns the same result as that |
| // function. Otherwise, it returns the distance to the closer of a and |
| // b. Let the projection of v onto u be v'. There are three cases: |
| // 1. v' points opposite to u. c is not between a and b and is closer |
| // to a than b. |
| // 2. v' points along u and has magnitude less than y. c is between |
| // a and b and the distance to the segment is the same as distance |
| // to the line ab. |
| // 3. v' points along u and has greater magnitude than u. c is not |
| // not between a and b and is closer to b than a. |
| // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're |
| // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise |
| // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to |
| // avoid a sqrt to compute |u|. |
| |
| GrVec u, v; |
| u.setBetween(a,b); |
| v.setBetween(a,*this); |
| |
| GrScalar uLengthSqd = u.lengthSqd(); |
| GrScalar uDotV = u.dot(v); |
| |
| if (uDotV <= 0) { |
| return v.lengthSqd(); |
| } else if (uDotV > uLengthSqd) { |
| return b.distanceToSqd(*this); |
| } else { |
| GrScalar det = u.cross(v); |
| return (GrMul(det, det)) / uLengthSqd; |
| } |
| } |
| |
| GrScalar GrPoint::distanceToLineSegmentBetween(const GrPoint& a, |
| const GrPoint& b) const { |
| // TODO: fixed point sqrt |
| return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToLineSegmentBetweenSqd(a,b)))); |
| } |
| |
| |
| #endif |
| |