1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
29 //==============================================================================
30 /**
31     A pair of (x, y) coordinates.
32 
33     The ValueType template should be a primitive type such as int, float, double,
34     rather than a class.
35 
36     @see Line, Path, AffineTransform
37 
38     @tags{Graphics}
39 */
40 template <typename ValueType>
41 class Point
42 {
43 public:
44     /** Creates a point at the origin */
45     constexpr Point() = default;
46 
47     /** Creates a copy of another point. */
48     constexpr Point (const Point&) = default;
49 
50     /** Creates a point from an (x, y) position. */
Point(ValueType initialX,ValueType initialY)51     constexpr Point (ValueType initialX, ValueType initialY) noexcept : x (initialX), y (initialY) {}
52 
53     //==============================================================================
54     /** Copies this point from another one. */
55     Point& operator= (const Point&) = default;
56 
57     constexpr inline bool operator== (Point other) const noexcept      { return x == other.x && y == other.y; }
58     constexpr inline bool operator!= (Point other) const noexcept      { return x != other.x || y != other.y; }
59 
60     /** Returns true if the point is (0, 0). */
isOrigin()61     constexpr bool isOrigin() const noexcept                           { return x == ValueType() && y == ValueType(); }
62 
63     /** Returns true if the coordinates are finite values. */
isFinite()64     constexpr inline bool isFinite() const noexcept                    { return juce_isfinite(x) && juce_isfinite(y); }
65 
66     /** Returns the point's x coordinate. */
getX()67     constexpr inline ValueType getX() const noexcept                   { return x; }
68 
69     /** Returns the point's y coordinate. */
getY()70     constexpr inline ValueType getY() const noexcept                   { return y; }
71 
72     /** Sets the point's x coordinate. */
setX(ValueType newX)73     inline void setX (ValueType newX) noexcept                         { x = newX; }
74 
75     /** Sets the point's y coordinate. */
setY(ValueType newY)76     inline void setY (ValueType newY) noexcept                         { y = newY; }
77 
78     /** Returns a point which has the same Y position as this one, but a new X. */
withX(ValueType newX)79     constexpr Point withX (ValueType newX) const noexcept              { return Point (newX, y); }
80 
81     /** Returns a point which has the same X position as this one, but a new Y. */
withY(ValueType newY)82     constexpr Point withY (ValueType newY) const noexcept              { return Point (x, newY); }
83 
84     /** Changes the point's x and y coordinates. */
setXY(ValueType newX,ValueType newY)85     void setXY (ValueType newX, ValueType newY) noexcept               { x = newX; y = newY; }
86 
87     /** Adds a pair of coordinates to this value. */
addXY(ValueType xToAdd,ValueType yToAdd)88     void addXY (ValueType xToAdd, ValueType yToAdd) noexcept           { x += xToAdd; y += yToAdd; }
89 
90     //==============================================================================
91     /** Returns a point with a given offset from this one. */
translated(ValueType deltaX,ValueType deltaY)92     constexpr Point translated (ValueType deltaX, ValueType deltaY) const noexcept    { return Point (x + deltaX, y + deltaY); }
93 
94     /** Adds two points together */
95     constexpr Point operator+ (Point other) const noexcept             { return Point (x + other.x, y + other.y); }
96 
97     /** Adds another point's coordinates to this one */
98     Point& operator+= (Point other) noexcept                           { x += other.x; y += other.y; return *this; }
99 
100     /** Subtracts one points from another */
101     constexpr Point operator- (Point other) const noexcept             { return Point (x - other.x, y - other.y); }
102 
103     /** Subtracts another point's coordinates to this one */
104     Point& operator-= (Point other) noexcept                           { x -= other.x; y -= other.y; return *this; }
105 
106     /** Multiplies two points together */
107     template <typename OtherType>
108     constexpr Point operator* (Point<OtherType> other) const noexcept  { return Point ((ValueType) (x * other.x), (ValueType) (y * other.y)); }
109 
110     /** Multiplies another point's coordinates to this one */
111     template <typename OtherType>
112     Point& operator*= (Point<OtherType> other) noexcept                { *this = *this * other; return *this; }
113 
114     /** Divides one point by another */
115     template <typename OtherType>
116     constexpr Point operator/ (Point<OtherType> other) const noexcept  { return Point ((ValueType) (x / other.x), (ValueType) (y / other.y)); }
117 
118     /** Divides this point's coordinates by another */
119     template <typename OtherType>
120     Point& operator/= (Point<OtherType> other) noexcept                { *this = *this / other; return *this; }
121 
122     /** Returns a point whose coordinates are multiplied by a given scalar value. */
123     template <typename OtherType>
124     constexpr Point operator* (OtherType multiplier) const noexcept
125     {
126         using CommonType = typename std::common_type<ValueType, OtherType>::type;
127         return Point ((ValueType) ((CommonType) x * (CommonType) multiplier),
128                       (ValueType) ((CommonType) y * (CommonType) multiplier));
129     }
130 
131     /** Returns a point whose coordinates are divided by a given scalar value. */
132     template <typename OtherType>
133     constexpr Point operator/ (OtherType divisor) const noexcept
134     {
135         using CommonType = typename std::common_type<ValueType, OtherType>::type;
136         return Point ((ValueType) ((CommonType) x / (CommonType) divisor),
137                       (ValueType) ((CommonType) y / (CommonType) divisor));
138     }
139 
140     /** Multiplies the point's coordinates by a scalar value. */
141     template <typename FloatType>
142     Point& operator*= (FloatType multiplier) noexcept                  { x = (ValueType) (x * multiplier); y = (ValueType) (y * multiplier); return *this; }
143 
144     /** Divides the point's coordinates by a scalar value. */
145     template <typename FloatType>
146     Point& operator/= (FloatType divisor) noexcept                     { x = (ValueType) (x / divisor); y = (ValueType) (y / divisor); return *this; }
147 
148     /** Returns the inverse of this point. */
149     constexpr Point operator-() const noexcept                         { return Point (-x, -y); }
150 
151     //==============================================================================
152     /** This type will be double if the Point's type is double, otherwise it will be float. */
153     using FloatType = typename TypeHelpers::SmallestFloatType<ValueType>::type;
154 
155     //==============================================================================
156     /** Returns the straight-line distance between this point and the origin. */
getDistanceFromOrigin()157     ValueType getDistanceFromOrigin() const noexcept                          { return juce_hypot (x, y); }
158 
159     /** Returns the straight-line distance between this point and another one. */
getDistanceFrom(Point other)160     ValueType getDistanceFrom (Point other) const noexcept                    { return juce_hypot (x - other.x, y - other.y); }
161 
162     /** Returns the square of the straight-line distance between this point and the origin. */
getDistanceSquaredFromOrigin()163     constexpr ValueType getDistanceSquaredFromOrigin() const noexcept         { return x * x + y * y; }
164 
165     /** Returns the square of the straight-line distance between this point and another one. */
getDistanceSquaredFrom(Point other)166     constexpr ValueType getDistanceSquaredFrom (Point other) const noexcept   { return (*this - other).getDistanceSquaredFromOrigin(); }
167 
168     /** Returns the angle from this point to another one.
169 
170         Taking this point to be the centre of a circle, and the other point being a position on
171         the circumference, the return value is the number of radians clockwise from the 12 o'clock
172         direction.
173         So 12 o'clock = 0, 3 o'clock = Pi/2, 6 o'clock = Pi, 9 o'clock = -Pi/2
174     */
getAngleToPoint(Point other)175     FloatType getAngleToPoint (Point other) const noexcept
176     {
177         return static_cast<FloatType> (std::atan2 (static_cast<FloatType> (other.x - x),
178                                                    static_cast<FloatType> (y - other.y)));
179     }
180 
181     /** Returns the point that would be reached by rotating this point clockwise
182         about the origin by the specified angle.
183     */
rotatedAboutOrigin(ValueType angleRadians)184     Point rotatedAboutOrigin (ValueType angleRadians) const noexcept
185     {
186         return Point (x * std::cos (angleRadians) - y * std::sin (angleRadians),
187                       x * std::sin (angleRadians) + y * std::cos (angleRadians));
188     }
189 
190     /** Taking this point to be the centre of a circle, this returns a point on its circumference.
191         @param radius   the radius of the circle.
192         @param angle    the angle of the point, in radians clockwise from the 12 o'clock position.
193     */
getPointOnCircumference(float radius,float angle)194     Point<FloatType> getPointOnCircumference (float radius, float angle) const noexcept
195     {
196         return Point<FloatType> (static_cast<FloatType> (x + radius * std::sin (angle)),
197                                  static_cast<FloatType> (y - radius * std::cos (angle)));
198     }
199 
200     /** Taking this point to be the centre of an ellipse, this returns a point on its circumference.
201         @param radiusX  the horizontal radius of the circle.
202         @param radiusY  the vertical radius of the circle.
203         @param angle    the angle of the point, in radians clockwise from the 12 o'clock position.
204     */
getPointOnCircumference(float radiusX,float radiusY,float angle)205     Point<FloatType> getPointOnCircumference (float radiusX, float radiusY, float angle) const noexcept
206     {
207         return Point<FloatType> (static_cast<FloatType> (x + radiusX * std::sin (angle)),
208                                  static_cast<FloatType> (y - radiusY * std::cos (angle)));
209     }
210 
211     /** Returns the dot-product of two points (x1 * x2 + y1 * y2). */
getDotProduct(Point other)212     constexpr FloatType getDotProduct (Point other) const noexcept     { return x * other.x + y * other.y; }
213 
214     //==============================================================================
215     /** Uses a transform to change the point's coordinates.
216         This will only compile if ValueType = float!
217 
218         @see AffineTransform::transformPoint
219     */
applyTransform(const AffineTransform & transform)220     void applyTransform (const AffineTransform& transform) noexcept     { transform.transformPoint (x, y); }
221 
222     /** Returns the position of this point, if it is transformed by a given AffineTransform. */
transformedBy(const AffineTransform & transform)223     Point transformedBy (const AffineTransform& transform) const noexcept
224     {
225         return Point (static_cast<ValueType> (transform.mat00 * (float) x + transform.mat01 * (float) y + transform.mat02),
226                       static_cast<ValueType> (transform.mat10 * (float) x + transform.mat11 * (float) y + transform.mat12));
227     }
228 
229     //==============================================================================
230     /** Casts this point to a Point<int> object. */
toInt()231     constexpr Point<int> toInt() const noexcept              { return Point<int> (static_cast<int> (x), static_cast<int> (y)); }
232 
233     /** Casts this point to a Point<float> object. */
toFloat()234     constexpr Point<float> toFloat() const noexcept          { return Point<float> (static_cast<float> (x), static_cast<float> (y)); }
235 
236     /** Casts this point to a Point<double> object. */
toDouble()237     constexpr Point<double> toDouble() const noexcept        { return Point<double> (static_cast<double> (x), static_cast<double> (y)); }
238 
239     /** Casts this point to a Point<int> object using roundToInt() to convert the values. */
roundToInt()240     constexpr Point<int> roundToInt() const noexcept         { return Point<int> (juce::roundToInt (x), juce::roundToInt (y)); }
241 
242     /** Returns the point as a string in the form "x, y". */
toString()243     String toString() const                                       { return String (x) + ", " + String (y); }
244 
245     //==============================================================================
246     ValueType x{}; /**< The point's X coordinate. */
247     ValueType y{}; /**< The point's Y coordinate. */
248 };
249 
250 /** Multiplies the point's coordinates by a scalar value. */
251 template <typename ValueType>
252 Point<ValueType> operator* (ValueType value, Point<ValueType> p) noexcept       { return p * value; }
253 
254 } // namespace juce
255