VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_graphics / geometry / juce_Line.h
blob940b095599ded5190deb750375f8c302f671a775
1 /*
2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
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.
23 ==============================================================================
26 namespace juce
29 //==============================================================================
30 /**
31 Represents a line.
33 This class contains a bunch of useful methods for various geometric
34 tasks.
36 The ValueType template parameter should be a primitive type - float or double
37 are what it's designed for. Integer types will work in a basic way, but some methods
38 that perform mathematical operations may not compile, or they may not produce
39 sensible results.
41 @see Point, Rectangle, Path, Graphics::drawLine
43 @tags{Graphics}
45 template <typename ValueType>
46 class Line
48 public:
49 //==============================================================================
50 /** Creates a line, using (0, 0) as its start and end points. */
51 Line() = default;
53 /** Creates a copy of another line. */
54 Line (const Line&) = default;
56 /** Creates a line based on the coordinates of its start and end points. */
57 Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) noexcept
58 : start (startX, startY), end (endX, endY)
62 /** Creates a line from its start and end points. */
63 Line (Point<ValueType> startPoint, Point<ValueType> endPoint) noexcept
64 : start (startPoint), end (endPoint)
68 /** Copies a line from another one. */
69 Line& operator= (const Line&) = default;
71 /** Destructor. */
72 ~Line() = default;
74 //==============================================================================
75 /** Returns the x coordinate of the line's start point. */
76 inline ValueType getStartX() const noexcept { return start.x; }
78 /** Returns the y coordinate of the line's start point. */
79 inline ValueType getStartY() const noexcept { return start.y; }
81 /** Returns the x coordinate of the line's end point. */
82 inline ValueType getEndX() const noexcept { return end.x; }
84 /** Returns the y coordinate of the line's end point. */
85 inline ValueType getEndY() const noexcept { return end.y; }
87 /** Returns the line's start point. */
88 inline Point<ValueType> getStart() const noexcept { return start; }
90 /** Returns the line's end point. */
91 inline Point<ValueType> getEnd() const noexcept { return end; }
93 /** Changes this line's start point */
94 void setStart (ValueType newStartX, ValueType newStartY) noexcept { start.setXY (newStartX, newStartY); }
96 /** Changes this line's end point */
97 void setEnd (ValueType newEndX, ValueType newEndY) noexcept { end.setXY (newEndX, newEndY); }
99 /** Changes this line's start point */
100 void setStart (const Point<ValueType> newStart) noexcept { start = newStart; }
102 /** Changes this line's end point */
103 void setEnd (const Point<ValueType> newEnd) noexcept { end = newEnd; }
105 /** Returns a line that is the same as this one, but with the start and end reversed, */
106 Line reversed() const noexcept { return { end, start }; }
108 /** Applies an affine transform to the line's start and end points. */
109 void applyTransform (const AffineTransform& transform) noexcept
111 start.applyTransform (transform);
112 end.applyTransform (transform);
115 //==============================================================================
116 /** Returns the length of the line. */
117 ValueType getLength() const noexcept { return start.getDistanceFrom (end); }
119 /** Returns the length of the line. */
120 ValueType getLengthSquared() const noexcept { return start.getDistanceSquaredFrom (end); }
122 /** Returns true if the line's start and end x coordinates are the same. */
123 bool isVertical() const noexcept { return start.x == end.x; }
125 /** Returns true if the line's start and end y coordinates are the same. */
126 bool isHorizontal() const noexcept { return start.y == end.y; }
128 /** Returns the line's angle.
130 This value is the number of radians clockwise from the 12 o'clock direction,
131 where the line's start point is considered to be at the centre.
133 typename Point<ValueType>::FloatType getAngle() const noexcept { return start.getAngleToPoint (end); }
135 /** Creates a line from a start point, length and angle.
137 This angle is the number of radians clockwise from the 12 o'clock direction,
138 where the line's start point is considered to be at the centre.
140 static Line fromStartAndAngle (Point<ValueType> startPoint, ValueType length, ValueType angle) noexcept
142 return { startPoint, startPoint.getPointOnCircumference (length, angle) };
145 //==============================================================================
146 /** Casts this line to float coordinates. */
147 Line<float> toFloat() const noexcept { return { start.toFloat(), end.toFloat() }; }
149 /** Casts this line to double coordinates. */
150 Line<double> toDouble() const noexcept { return { start.toDouble(), end.toDouble() }; }
152 //==============================================================================
153 /** Compares two lines. */
154 bool operator== (Line other) const noexcept { return start == other.start && end == other.end; }
156 /** Compares two lines. */
157 bool operator!= (Line other) const noexcept { return start != other.start || end != other.end; }
159 //==============================================================================
160 /** Finds the intersection between two lines.
162 @param line the line to intersect with
163 @returns the point at which the lines intersect, even if this lies beyond the end of the lines
165 Point<ValueType> getIntersection (Line line) const noexcept
167 Point<ValueType> p;
168 findIntersection (start, end, line.start, line.end, p);
169 return p;
172 /** Finds the intersection between two lines.
174 @param line the other line
175 @param intersection the position of the point where the lines meet (or
176 where they would meet if they were infinitely long)
177 the intersection (if the lines intersect). If the lines
178 are parallel, this will just be set to the position
179 of one of the line's endpoints.
180 @returns true if the line segments intersect; false if they don't. Even if they
181 don't intersect, the intersection coordinates returned will still
182 be valid
184 bool intersects (Line line, Point<ValueType>& intersection) const noexcept
186 return findIntersection (start, end, line.start, line.end, intersection);
189 /** Returns true if this line intersects another. */
190 bool intersects (Line other) const noexcept
192 Point<ValueType> ignored;
193 return findIntersection (start, end, other.start, other.end, ignored);
196 //==============================================================================
197 /** Returns the location of the point which is a given distance along this line.
199 @param distanceFromStart the distance to move along the line from its
200 start point. This value can be negative or longer
201 than the line itself
202 @see getPointAlongLineProportionally
204 Point<ValueType> getPointAlongLine (ValueType distanceFromStart) const noexcept
206 const auto length = getLength();
207 return length == 0 ? start : start + (end - start) * (distanceFromStart / length);
210 /** Returns a point which is a certain distance along and to the side of this line.
212 This effectively moves a given distance along the line, then another distance
213 perpendicularly to this, and returns the resulting position.
215 @param distanceFromStart the distance to move along the line from its
216 start point. This value can be negative or longer
217 than the line itself
218 @param perpendicularDistance how far to move sideways from the line. If you're
219 looking along the line from its start towards its
220 end, then a positive value here will move to the
221 right, negative value move to the left.
223 Point<ValueType> getPointAlongLine (ValueType distanceFromStart,
224 ValueType perpendicularDistance) const noexcept
226 auto delta = end - start;
227 auto length = juce_hypot ((double) delta.x,
228 (double) delta.y);
229 if (length <= 0)
230 return start;
232 return { start.x + static_cast<ValueType> ((delta.x * distanceFromStart - delta.y * perpendicularDistance) / length),
233 start.y + static_cast<ValueType> ((delta.y * distanceFromStart + delta.x * perpendicularDistance) / length) };
236 /** Returns the location of the point which is a given distance along this line
237 proportional to the line's length.
239 @param proportionOfLength the distance to move along the line from its
240 start point, in multiples of the line's length.
241 So a value of 0.0 will return the line's start point
242 and a value of 1.0 will return its end point. (This value
243 can be negative or greater than 1.0).
244 @see getPointAlongLine
246 Point<ValueType> getPointAlongLineProportionally (typename Point<ValueType>::FloatType proportionOfLength) const noexcept
248 return start + (end - start) * proportionOfLength;
251 /** Returns the smallest distance between this line segment and a given point.
253 So if the point is close to the line, this will return the perpendicular
254 distance from the line; if the point is a long way beyond one of the line's
255 end-point's, it'll return the straight-line distance to the nearest end-point.
257 pointOnLine receives the position of the point that is found.
259 @returns the point's distance from the line
260 @see getPositionAlongLineOfNearestPoint
262 ValueType getDistanceFromPoint (Point<ValueType> targetPoint,
263 Point<ValueType>& pointOnLine) const noexcept
265 auto delta = end - start;
266 auto length = delta.x * delta.x + delta.y * delta.y;
268 if (length > 0)
270 auto prop = ((targetPoint.x - start.x) * delta.x
271 + (targetPoint.y - start.y) * delta.y) / (double) length;
273 if (prop >= 0 && prop <= 1.0)
275 pointOnLine = start + delta * prop;
276 return targetPoint.getDistanceFrom (pointOnLine);
280 auto fromStart = targetPoint.getDistanceFrom (start);
281 auto fromEnd = targetPoint.getDistanceFrom (end);
283 if (fromStart < fromEnd)
285 pointOnLine = start;
286 return fromStart;
289 pointOnLine = end;
290 return fromEnd;
293 /** Finds the point on this line which is nearest to a given point, and
294 returns its position as a proportional position along the line.
296 @returns a value 0 to 1.0 which is the distance along this line from the
297 line's start to the point which is nearest to the point passed-in. To
298 turn this number into a position, use getPointAlongLineProportionally().
299 @see getDistanceFromPoint, getPointAlongLineProportionally
301 ValueType findNearestProportionalPositionTo (Point<ValueType> point) const noexcept
303 auto delta = end - start;
304 auto length = delta.x * delta.x + delta.y * delta.y;
306 return length <= 0 ? 0
307 : jlimit (ValueType(), static_cast<ValueType> (1),
308 static_cast<ValueType> ((((point.x - start.x) * delta.x
309 + (point.y - start.y) * delta.y) / length)));
312 /** Finds the point on this line which is nearest to a given point.
313 @see getDistanceFromPoint, findNearestProportionalPositionTo
315 Point<ValueType> findNearestPointTo (Point<ValueType> point) const noexcept
317 return getPointAlongLineProportionally (findNearestProportionalPositionTo (point));
320 /** Returns true if the given point lies above this line.
322 The return value is true if the point's y coordinate is less than the y
323 coordinate of this line at the given x (assuming the line extends infinitely
324 in both directions).
326 bool isPointAbove (Point<ValueType> point) const noexcept
328 return start.x != end.x
329 && point.y < ((end.y - start.y) * (point.x - start.x)) / (end.x - start.x) + start.y;
332 /** Returns a lengthened copy of this line.
334 This will extend the line by a certain amount by moving the start away from the end
335 (leaving the end-point the same), and return the new line.
337 Line withLengthenedStart (ValueType distanceToLengthenBy) const noexcept
339 return withShortenedStart (-distanceToLengthenBy);
342 //==============================================================================
343 /** Returns a shortened copy of this line.
345 This will chop off part of the start of this line by a certain amount, (leaving the
346 end-point the same), and return the new line.
348 Line withShortenedStart (ValueType distanceToShortenBy) const noexcept
350 return { getPointAlongLine (jmin (distanceToShortenBy, getLength())), end };
353 /** Returns a lengthened copy of this line.
355 This will extend the line by a certain amount by moving the end away from the start
356 (leaving the start-point the same), and return the new line.
358 Line withLengthenedEnd (ValueType distanceToLengthenBy) const noexcept
360 return withShortenedEnd (-distanceToLengthenBy);
363 /** Returns a shortened copy of this line.
365 This will chop off part of the end of this line by a certain amount, (leaving the
366 start-point the same), and return the new line.
368 Line withShortenedEnd (ValueType distanceToShortenBy) const noexcept
370 auto length = getLength();
371 return { start, getPointAlongLine (length - jmin (distanceToShortenBy, length)) };
374 private:
375 //==============================================================================
376 Point<ValueType> start, end;
378 static bool isZeroToOne (ValueType v) noexcept { return v >= 0 && v <= static_cast<ValueType> (1); }
380 static bool findIntersection (const Point<ValueType> p1, const Point<ValueType> p2,
381 const Point<ValueType> p3, const Point<ValueType> p4,
382 Point<ValueType>& intersection) noexcept
384 if (p2 == p3)
386 intersection = p2;
387 return true;
390 auto d1 = p2 - p1;
391 auto d2 = p4 - p3;
392 auto divisor = d1.x * d2.y - d2.x * d1.y;
394 if (divisor == 0)
396 if (! (d1.isOrigin() || d2.isOrigin()))
398 if (d1.y == 0 && d2.y != 0)
400 auto along = (p1.y - p3.y) / d2.y;
401 intersection = p1.withX (p3.x + along * d2.x);
402 return isZeroToOne (along);
405 if (d2.y == 0 && d1.y != 0)
407 auto along = (p3.y - p1.y) / d1.y;
408 intersection = p3.withX (p1.x + along * d1.x);
409 return isZeroToOne (along);
412 if (d1.x == 0 && d2.x != 0)
414 auto along = (p1.x - p3.x) / d2.x;
415 intersection = p1.withY (p3.y + along * d2.y);
416 return isZeroToOne (along);
419 if (d2.x == 0 && d1.x != 0)
421 auto along = (p3.x - p1.x) / d1.x;
422 intersection = p3.withY (p1.y + along * d1.y);
423 return isZeroToOne (along);
427 intersection = (p2 + p3) / static_cast<ValueType> (2);
428 return false;
431 auto along1 = ((p1.y - p3.y) * d2.x - (p1.x - p3.x) * d2.y) / divisor;
432 intersection = p1 + d1 * along1;
434 if (! isZeroToOne (along1))
435 return false;
437 auto along2 = ((p1.y - p3.y) * d1.x - (p1.x - p3.x) * d1.y) / divisor;
438 return isZeroToOne (along2);
442 } // namespace juce