skia2/include/core/SkPoint.h
Cary Clark ba2526bc66 replace some points with vectors to clarify documentation
Some SkIPoint and SkPoint methods become clearer if their
parameters or return value is typed as a vector.

Since SkPoint is identical to SkVector (and SkIPoint is
identical to newly added SkIVector) this has no impact
on compiled code.

Some routines arguably have multiple possible point and
vector combinations which will be included in eventual
documentation; the interface should have the most common
and/or logical choice.

Some of my choices could be argued with as well. Does
SkPoint::Normalize take a SkPoint? Afternative points
of view encouraged.

R=reed@google.com,bsalomon@google.com
Bug: skia:6898
Change-Id: I2429b9d43b20351188d7c6433620a2e221f75bd8
Reviewed-on: https://skia-review.googlesource.com/69680
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Cary Clark <caryclark@skia.org>
2017-11-09 21:37:27 +00:00

335 lines
8.9 KiB
C

/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPoint_DEFINED
#define SkPoint_DEFINED
#include "SkMath.h"
#include "SkScalar.h"
/** \struct SkIPoint16
SkIPoint holds two 16 bit integer coordinates
*/
struct SkIPoint16 {
int16_t fX;
int16_t fY;
static constexpr SkIPoint16 Make(int x, int y) {
return {SkToS16(x), SkToS16(y)};
}
int16_t x() const { return fX; }
int16_t y() const { return fY; }
void set(int x, int y) {
fX = SkToS16(x);
fY = SkToS16(y);
}
};
struct SkIPoint;
typedef SkIPoint SkIVector;
/** \struct SkIPoint
SkIPoint holds two 32 bit integer coordinates
*/
struct SkIPoint {
int32_t fX;
int32_t fY;
static constexpr SkIPoint Make(int32_t x, int32_t y) {
return {x, y};
}
int32_t x() const { return fX; }
int32_t y() const { return fY; }
/**
* Returns true iff fX and fY are both zero.
*/
bool isZero() const { return (fX | fY) == 0; }
/** Set the x and y values of the point. */
void set(int32_t x, int32_t y) {
fX = x;
fY = y;
}
/** Return a new point whose X and Y coordinates are the negative of the
original point's
*/
SkIPoint operator-() const {
return {-fX, -fY};
}
/** Add v's coordinates to this point's */
void operator+=(const SkIVector& v) {
fX += v.fX;
fY += v.fY;
}
/** Subtract v's coordinates from this point's */
void operator-=(const SkIVector& v) {
fX -= v.fX;
fY -= v.fY;
}
/** Returns true if the point's coordinates equal (x,y) */
bool equals(int32_t x, int32_t y) const {
return fX == x && fY == y;
}
friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
return a.fX == b.fX && a.fY == b.fY;
}
friend bool operator!=(const SkIPoint& a, const SkIPoint& b) {
return a.fX != b.fX || a.fY != b.fY;
}
/** Returns a new point whose coordinates are the difference between
a and b (i.e. a - b)
*/
friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) {
return {a.fX - b.fX, a.fY - b.fY};
}
/** Returns a new point whose coordinates are the sum of a and b (a + b)
*/
friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) {
return {a.fX + b.fX, a.fY + b.fY};
}
};
struct SkPoint;
typedef SkPoint SkVector;
struct SK_API SkPoint {
SkScalar fX;
SkScalar fY;
static constexpr SkPoint Make(SkScalar x, SkScalar y) {
return {x, y};
}
SkScalar x() const { return fX; }
SkScalar y() const { return fY; }
/**
* Returns true iff fX and fY are both zero.
*/
bool isZero() const { return (0 == fX) & (0 == fY); }
/** Set the point's X and Y coordinates */
void set(SkScalar x, SkScalar y) {
fX = x;
fY = y;
}
/** Set the point's X and Y coordinates by automatically promoting (x,y) to
SkScalar values.
*/
void iset(int32_t x, int32_t y) {
fX = SkIntToScalar(x);
fY = SkIntToScalar(y);
}
/** Set the point's X and Y coordinates by automatically promoting p's
coordinates to SkScalar values.
*/
void iset(const SkIPoint& p) {
fX = SkIntToScalar(p.fX);
fY = SkIntToScalar(p.fY);
}
void setAbs(const SkPoint& pt) {
fX = SkScalarAbs(pt.fX);
fY = SkScalarAbs(pt.fY);
}
static void Offset(SkPoint points[], int count, const SkVector& offset) {
Offset(points, count, offset.fX, offset.fY);
}
static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) {
for (int i = 0; i < count; ++i) {
points[i].offset(dx, dy);
}
}
void offset(SkScalar dx, SkScalar dy) {
fX += dx;
fY += dy;
}
/** Return the euclidian distance from (0,0) to the point
*/
SkScalar length() const { return SkPoint::Length(fX, fY); }
SkScalar distanceToOrigin() const { return this->length(); }
/** Set the point (vector) to be unit-length in the same direction as it
already points. If the point has a degenerate length (i.e. nearly 0)
then set it to (0,0) and return false; otherwise return true.
*/
bool normalize();
/** Set the point (vector) to be unit-length in the same direction as the
x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0)
then set it to (0,0) and return false, otherwise return true.
*/
bool setNormalize(SkScalar x, SkScalar y);
/** Scale the point (vector) to have the specified length, and return that
length. If the original length is degenerately small (nearly zero),
set it to (0,0) and return false, otherwise return true.
*/
bool setLength(SkScalar length);
/** Set the point (vector) to have the specified length in the same
direction as (x,y). If the vector (x,y) has a degenerate length
(i.e. nearly 0) then set it to (0,0) and return false, otherwise return true.
*/
bool setLength(SkScalar x, SkScalar y, SkScalar length);
/** Scale the point's coordinates by scale, writing the answer into dst.
It is legal for dst == this.
*/
void scale(SkScalar scale, SkPoint* dst) const;
/** Scale the point's coordinates by scale, writing the answer back into
the point.
*/
void scale(SkScalar value) { this->scale(value, this); }
/** Negate the point's coordinates
*/
void negate() {
fX = -fX;
fY = -fY;
}
/** Returns a new point whose coordinates are the negative of the point's
*/
SkPoint operator-() const {
return {-fX, -fY};
}
/** Add v's coordinates to the point's
*/
void operator+=(const SkVector& v) {
fX += v.fX;
fY += v.fY;
}
/** Subtract v's coordinates from the point's
*/
void operator-=(const SkVector& v) {
fX -= v.fX;
fY -= v.fY;
}
SkPoint operator*(SkScalar scale) const {
return {fX * scale, fY * scale};
}
SkPoint& operator*=(SkScalar scale) {
fX *= scale;
fY *= scale;
return *this;
}
/**
* Returns true if both X and Y are finite (not infinity or NaN)
*/
bool isFinite() const {
SkScalar accum = 0;
accum *= fX;
accum *= fY;
// accum is either NaN or it is finite (zero).
SkASSERT(0 == accum || SkScalarIsNaN(accum));
// value==value will be true iff value is not NaN
// TODO: is it faster to say !accum or accum==accum?
return !SkScalarIsNaN(accum);
}
/**
* Returns true if the point's coordinates equal (x,y)
*/
bool equals(SkScalar x, SkScalar y) const {
return fX == x && fY == y;
}
friend bool operator==(const SkPoint& a, const SkPoint& b) {
return a.fX == b.fX && a.fY == b.fY;
}
friend bool operator!=(const SkPoint& a, const SkPoint& b) {
return a.fX != b.fX || a.fY != b.fY;
}
/** Returns a new point whose coordinates are the difference between
a's and b's (a - b)
*/
friend SkVector operator-(const SkPoint& a, const SkPoint& b) {
return {a.fX - b.fX, a.fY - b.fY};
}
/** Returns a new point whose coordinates are the sum of a's and b's (a + b)
*/
friend SkPoint operator+(const SkPoint& a, const SkVector& b) {
return {a.fX + b.fX, a.fY + b.fY};
}
/** Returns the euclidian distance from (0,0) to (x,y)
*/
static SkScalar Length(SkScalar x, SkScalar y);
/** Normalize pt, returning its previous length. If the prev length is too
small (degenerate), set pt to (0,0) and return 0. This uses the same
tolerance as CanNormalize.
Note that this method may be significantly more expensive than
the non-static normalize(), because it has to return the previous length
of the point. If you don't need the previous length, call the
non-static normalize() method instead.
*/
static SkScalar Normalize(SkVector* vec);
/** Returns the euclidian distance between a and b
*/
static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
return Length(a.fX - b.fX, a.fY - b.fY);
}
/** Returns the dot product of a and b, treating them as 2D vectors
*/
static SkScalar DotProduct(const SkVector& a, const SkVector& b) {
return a.fX * b.fX + a.fY * b.fY;
}
/** Returns the cross product of a and b, treating them as 2D vectors
*/
static SkScalar CrossProduct(const SkVector& a, const SkVector& b) {
return a.fX * b.fY - a.fY * b.fX;
}
SkScalar cross(const SkVector& vec) const {
return CrossProduct(*this, vec);
}
SkScalar dot(const SkVector& vec) const {
return DotProduct(*this, vec);
}
};
#endif