1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-06 04:00:08 +00:00

Refactored the Line class to be templated (to update old code, just replace "Line" with "Line<float>"). Corrected a mac ppc build problem.

This commit is contained in:
Julian Storer 2010-04-26 15:47:21 +01:00
parent 0d611ec065
commit 082dff25dd
11 changed files with 601 additions and 984 deletions

View file

@ -85,8 +85,6 @@
#if defined (__ppc__) || defined (__ppc64__)
#define JUCE_PPC 1
#undef MAC_OS_X_VERSION_MAX_ALLOWED
#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_4
#else
#define JUCE_INTEL 1
#endif
@ -80044,12 +80042,12 @@ void Graphics::drawLine (const float startX, const float startY,
fillPath (p);
}
void Graphics::drawLine (const Line& line) const
void Graphics::drawLine (const Line<float>& line) const
{
drawLine (line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY());
}
void Graphics::drawLine (const Line& line, const float lineThickness) const
void Graphics::drawLine (const Line<float>& line, const float lineThickness) const
{
drawLine (line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), lineThickness);
}
@ -80893,48 +80891,40 @@ public:
: lookupTable (lookupTable_), numEntries (numEntries_)
{
jassert (numEntries_ >= 0);
float x1 = gradient.x1;
float y1 = gradient.y1;
float x2 = gradient.x2;
float y2 = gradient.y2;
Point<float> p1 (gradient.x1, gradient.y1);
Point<float> p2 (gradient.x2, gradient.y2);
if (! transform.isIdentity())
{
const Line l (x2, y2, x1, y1);
const Point<float> p3 = l.getPointAlongLine (0.0f, 100.0f);
float x3 = p3.getX();
float y3 = p3.getY();
const Line<float> l (p2, p1);
Point<float> p3 = l.getPointAlongLine (0.0f, 100.0f);
transform.transformPoint (x1, y1);
transform.transformPoint (x2, y2);
transform.transformPoint (x3, y3);
p1.applyTransform (transform);
p2.applyTransform (transform);
p3.applyTransform (transform);
const Line l2 (x2, y2, x3, y3);
const float prop = l2.findNearestPointTo (x1, y1);
const Point<float> newP2 (l2.getPointAlongLineProportionally (prop));
x2 = newP2.getX();
y2 = newP2.getY();
const Line<float> l2 (p2, p3);
p2 = l2.getPointAlongLineProportionally (l2.findNearestPointTo (p1));
}
vertical = fabs (x1 - x2) < 0.001f;
horizontal = fabs (y1 - y2) < 0.001f;
vertical = fabs (p1.getX() - p2.getX()) < 0.001f;
horizontal = fabs (p1.getY() - p2.getY()) < 0.001f;
if (vertical)
{
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (y2 - y1));
start = roundToInt (y1 * scale);
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.getY() - p1.getY()));
start = roundToInt (p1.getY() * scale);
}
else if (horizontal)
{
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (x2 - x1));
start = roundToInt (x1 * scale);
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.getX() - p1.getX()));
start = roundToInt (p1.getX() * scale);
}
else
{
grad = (y2 - y1) / (double) (x1 - x2);
yTerm = y1 - x1 / grad;
scale = roundToInt ((numEntries << (int) numScaleBits) / (yTerm * grad - (y2 * grad - x2)));
grad = (p2.getY() - p1.getY()) / (double) (p1.getX() - p2.getX());
yTerm = p1.getY() - p1.getX() / grad;
scale = roundToInt ((numEntries << (int) numScaleBits) / (yTerm * grad - (p2.getY() * grad - p2.getX())));
grad *= scale;
}
}
@ -86885,364 +86875,6 @@ END_JUCE_NAMESPACE
/*** Start of inlined file: juce_Line.cpp ***/
BEGIN_JUCE_NAMESPACE
static bool juce_lineIntersection (const float x1, const float y1,
const float x2, const float y2,
const float x3, const float y3,
const float x4, const float y4,
float& intersectionX,
float& intersectionY) throw()
{
if (x2 != x3 || y2 != y3)
{
const float dx1 = x2 - x1;
const float dy1 = y2 - y1;
const float dx2 = x4 - x3;
const float dy2 = y4 - y3;
const float divisor = dx1 * dy2 - dx2 * dy1;
if (divisor == 0)
{
if (! ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)))
{
if (dy1 == 0 && dy2 != 0)
{
const float along = (y1 - y3) / dy2;
intersectionX = x3 + along * dx2;
intersectionY = y1;
return along >= 0 && along <= 1.0f;
}
else if (dy2 == 0 && dy1 != 0)
{
const float along = (y3 - y1) / dy1;
intersectionX = x1 + along * dx1;
intersectionY = y3;
return along >= 0 && along <= 1.0f;
}
else if (dx1 == 0 && dx2 != 0)
{
const float along = (x1 - x3) / dx2;
intersectionX = x1;
intersectionY = y3 + along * dy2;
return along >= 0 && along <= 1.0f;
}
else if (dx2 == 0 && dx1 != 0)
{
const float along = (x3 - x1) / dx1;
intersectionX = x3;
intersectionY = y1 + along * dy1;
return along >= 0 && along <= 1.0f;
}
}
intersectionX = 0.5f * (x2 + x3);
intersectionY = 0.5f * (y2 + y3);
return false;
}
const float along1 = ((y1 - y3) * dx2 - (x1 - x3) * dy2) / divisor;
intersectionX = x1 + along1 * dx1;
intersectionY = y1 + along1 * dy1;
if (along1 < 0 || along1 > 1.0f)
return false;
const float along2 = ((y1 - y3) * dx1 - (x1 - x3) * dy1) / divisor;
return along2 >= 0 && along2 <= 1.0f;
}
intersectionX = x2;
intersectionY = y2;
return true;
}
Line::Line() throw()
: startX (0.0f),
startY (0.0f),
endX (0.0f),
endY (0.0f)
{
}
Line::Line (const Line& other) throw()
: startX (other.startX),
startY (other.startY),
endX (other.endX),
endY (other.endY)
{
}
Line::Line (const float startX_, const float startY_,
const float endX_, const float endY_) throw()
: startX (startX_),
startY (startY_),
endX (endX_),
endY (endY_)
{
}
Line::Line (const Point<float>& start,
const Point<float>& end) throw()
: startX (start.getX()),
startY (start.getY()),
endX (end.getX()),
endY (end.getY())
{
}
Line& Line::operator= (const Line& other) throw()
{
startX = other.startX;
startY = other.startY;
endX = other.endX;
endY = other.endY;
return *this;
}
Line::~Line() throw()
{
}
const Point<float> Line::getStart() const throw()
{
return Point<float> (startX, startY);
}
const Point<float> Line::getEnd() const throw()
{
return Point<float> (endX, endY);
}
void Line::setStart (const float newStartX,
const float newStartY) throw()
{
startX = newStartX;
startY = newStartY;
}
void Line::setStart (const Point<float>& newStart) throw()
{
startX = newStart.getX();
startY = newStart.getY();
}
void Line::setEnd (const float newEndX,
const float newEndY) throw()
{
endX = newEndX;
endY = newEndY;
}
void Line::setEnd (const Point<float>& newEnd) throw()
{
endX = newEnd.getX();
endY = newEnd.getY();
}
bool Line::operator== (const Line& other) const throw()
{
return startX == other.startX
&& startY == other.startY
&& endX == other.endX
&& endY == other.endY;
}
bool Line::operator!= (const Line& other) const throw()
{
return startX != other.startX
|| startY != other.startY
|| endX != other.endX
|| endY != other.endY;
}
void Line::applyTransform (const AffineTransform& transform) throw()
{
transform.transformPoint (startX, startY);
transform.transformPoint (endX, endY);
}
float Line::getLength() const throw()
{
return (float) juce_hypot (startX - endX,
startY - endY);
}
float Line::getAngle() const throw()
{
return atan2f (endX - startX,
endY - startY);
}
const Point<float> Line::getPointAlongLine (const float distanceFromStart) const throw()
{
const float alpha = distanceFromStart / getLength();
return Point<float> (startX + (endX - startX) * alpha,
startY + (endY - startY) * alpha);
}
const Point<float> Line::getPointAlongLine (const float offsetX,
const float offsetY) const throw()
{
const float dx = endX - startX;
const float dy = endY - startY;
const double length = juce_hypot (dx, dy);
if (length == 0)
return Point<float> (startX, startY);
else
return Point<float> (startX + (float) (((dx * offsetX) - (dy * offsetY)) / length),
startY + (float) (((dy * offsetX) + (dx * offsetY)) / length));
}
const Point<float> Line::getPointAlongLineProportionally (const float alpha) const throw()
{
return Point<float> (startX + (endX - startX) * alpha,
startY + (endY - startY) * alpha);
}
float Line::getDistanceFromLine (const float x,
const float y) const throw()
{
const double dx = endX - startX;
const double dy = endY - startY;
const double length = dx * dx + dy * dy;
if (length > 0)
{
const double prop = ((x - startX) * dx + (y - startY) * dy) / length;
if (prop >= 0.0f && prop < 1.0f)
{
return (float) juce_hypot (x - (startX + prop * dx),
y - (startY + prop * dy));
}
}
return (float) jmin (juce_hypot (x - startX, y - startY),
juce_hypot (x - endX, y - endY));
}
float Line::findNearestPointTo (const float x,
const float y) const throw()
{
const double dx = endX - startX;
const double dy = endY - startY;
const double length = dx * dx + dy * dy;
if (length <= 0.0)
return 0.0f;
return jlimit (0.0f, 1.0f,
(float) (((x - startX) * dx + (y - startY) * dy) / length));
}
const Line Line::withShortenedStart (const float distanceToShortenBy) const throw()
{
const float length = getLength();
return Line (getPointAlongLine (jmin (distanceToShortenBy, length)),
getEnd());
}
const Line Line::withShortenedEnd (const float distanceToShortenBy) const throw()
{
const float length = getLength();
return Line (getStart(),
getPointAlongLine (length - jmin (distanceToShortenBy, length)));
}
bool Line::clipToPath (const Path& path,
const bool keepSectionOutsidePath) throw()
{
const bool startInside = path.contains (startX, startY);
const bool endInside = path.contains (endX, endY);
if (startInside == endInside)
{
if (keepSectionOutsidePath != startInside)
{
// entirely outside the path
return false;
}
else
{
// entirely inside the path
startX = 0.0f;
startY = 0.0f;
endX = 0.0f;
endY = 0.0f;
return true;
}
}
else
{
bool changed = false;
PathFlatteningIterator iter (path, AffineTransform::identity);
while (iter.next())
{
float ix, iy;
if (intersects (Line (iter.x1, iter.y1,
iter.x2, iter.y2),
ix, iy))
{
if ((startInside && keepSectionOutsidePath)
|| (endInside && ! keepSectionOutsidePath))
{
setStart (ix, iy);
}
else
{
setEnd (ix, iy);
}
changed = true;
}
}
return changed;
}
}
bool Line::intersects (const Line& line,
float& intersectionX,
float& intersectionY) const throw()
{
return juce_lineIntersection (startX, startY,
endX, endY,
line.startX, line.startY,
line.endX, line.endY,
intersectionX,
intersectionY);
}
bool Line::isVertical() const throw()
{
return startX == endX;
}
bool Line::isHorizontal() const throw()
{
return startY == endY;
}
bool Line::isPointAbove (const float x, const float y) const throw()
{
return startX != endX
&& y < ((endY - startY) * (x - startX)) / (endX - startX) + startY;
}
END_JUCE_NAMESPACE
/*** End of inlined file: juce_Line.cpp ***/
@ -88243,8 +87875,7 @@ bool Path::contains (const float x, const float y, const float tolerence) const
while (i.next())
{
if ((i.y1 <= y && i.y2 > y)
|| (i.y2 <= y && i.y1 > y))
if ((i.y1 <= y && i.y2 > y) || (i.y2 <= y && i.y1 > y))
{
const float intersectX = i.x1 + (i.x2 - i.x1) * (y - i.y1) / (i.y2 - i.y1);
@ -88258,30 +87889,58 @@ bool Path::contains (const float x, const float y, const float tolerence) const
}
}
return (useNonZeroWinding) ? (negativeCrossings != positiveCrossings)
: ((negativeCrossings + positiveCrossings) & 1) != 0;
return useNonZeroWinding ? (negativeCrossings != positiveCrossings)
: ((negativeCrossings + positiveCrossings) & 1) != 0;
}
bool Path::intersectsLine (const float x1, const float y1,
const float x2, const float y2,
const float tolerence)
bool Path::contains (const Point<float>& point, const float tolerence) const
{
return contains (point.getX(), point.getY(), tolerence);
}
bool Path::intersectsLine (const Line<float>& line, const float tolerence)
{
PathFlatteningIterator i (*this, AffineTransform::identity, tolerence);
const Line line1 (x1, y1, x2, y2);
Point<float> intersection;
while (i.next())
{
const Line line2 (i.x1, i.y1, i.x2, i.y2);
float ix, iy;
if (line1.intersects (line2, ix, iy))
if (line.intersects (Line<float> (i.x1, i.y1, i.x2, i.y2), intersection))
return true;
}
return false;
}
const Line<float> Path::getClippedLine (const Line<float>& line, const bool keepSectionOutsidePath) const
{
Line<float> result (line);
const bool startInside = contains (line.getStart());
const bool endInside = contains (line.getEnd());
if (startInside == endInside)
{
if (keepSectionOutsidePath == startInside)
result = Line<float>();
}
else
{
PathFlatteningIterator i (*this, AffineTransform::identity);
Point<float> intersection;
while (i.next())
{
if (line.intersects (Line<float> (i.x1, i.y1, i.x2, i.y2), intersection))
{
if ((startInside && keepSectionOutsidePath) || (endInside && ! keepSectionOutsidePath))
result.setStart (intersection);
else
result.setEnd (intersection);
}
}
}
return result;
}
const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
{
if (cornerRadius <= 0.01f)

View file

@ -105,8 +105,6 @@
#if defined (__ppc__) || defined (__ppc64__)
#define JUCE_PPC 1
#undef MAC_OS_X_VERSION_MAX_ALLOWED
#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_4
#else
#define JUCE_INTEL 1
#endif
@ -9641,6 +9639,10 @@ public:
bool isOrigin() const throw() { return x == ValueType() && y == ValueType(); }
const Point withX (const ValueType newX) const throw() { return Point (newX, y); }
const Point withY (const ValueType newY) const throw() { return Point (x, newY); }
void setXY (const ValueType newX, const ValueType newY) throw() { x = newX; y = newY; }
void addXY (const ValueType xToAdd, const ValueType yToAdd) throw() { x += xToAdd; y += yToAdd; }
@ -9653,10 +9655,22 @@ public:
Point& operator-= (const Point& other) throw() { x -= other.x; y -= other.y; return *this; }
const Point operator* (const ValueType multiplier) const throw() { return Point (x * multiplier, y * multiplier); }
Point& operator*= (const ValueType multiplier) throw() { x *= multiplier; y *= multiplier; return *this; }
const Point operator/ (const ValueType divisor) const throw() { return Point (x / divisor, y / divisor); }
Point& operator/= (const ValueType divisor) throw() { x /= divisor; y /= divisor; return *this; }
const Point operator-() const throw() { return Point (-x, -y); }
ValueType getDistanceFromOrigin() const throw() { return (ValueType) juce_hypot (x, y); }
ValueType getDistanceFrom (const Point& other) const throw() { return (ValueType) juce_hypot (x - other.x, y - other.y); }
ValueType getAngleToPoint (const Point& other) const throw() { return (ValueType) atan2 (other.x - x, other.y - y); }
void applyTransform (const AffineTransform& transform) throw() { transform.transformPoint (x, y); }
const String toString() const { return String (x) + ", " + String (y); }
@ -9981,6 +9995,225 @@ public:
#define __JUCE_PATH_JUCEHEADER__
/*** Start of inlined file: juce_Line.h ***/
#ifndef __JUCE_LINE_JUCEHEADER__
#define __JUCE_LINE_JUCEHEADER__
template <typename ValueType>
class Line
{
public:
Line() throw() {}
Line (const Line& other) throw()
: start (other.start),
end (other.end)
{
}
Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) throw()
: start (startX, startY),
end (endX, endY)
{
}
Line (const Point<ValueType>& startPoint,
const Point<ValueType>& endPoint) throw()
: start (startPoint),
end (endPoint)
{
}
Line& operator= (const Line& other) throw()
{
start = other.start;
end = other.end;
return *this;
}
~Line() throw() {}
inline ValueType getStartX() const throw() { return start.getX(); }
inline ValueType getStartY() const throw() { return start.getY(); }
inline ValueType getEndX() const throw() { return end.getX(); }
inline ValueType getEndY() const throw() { return end.getY(); }
inline const Point<ValueType>& getStart() const throw() { return start; }
inline const Point<ValueType>& getEnd() const throw() { return end; }
void setStart (ValueType newStartX, ValueType newStartY) throw() { start.setXY (newStartX, newStartY); }
void setEnd (ValueType newEndX, ValueType newEndY) throw() { end.setXY (newEndX, newEndY); }
void setStart (const Point<ValueType>& newStart) throw() { start = newStart; }
void setEnd (const Point<ValueType>& newEnd) throw() { end = newEnd; }
void applyTransform (const AffineTransform& transform) throw()
{
start.applyTransform (transform);
end.applyTransform (transform);
}
ValueType getLength() const throw() { return start.getDistanceFrom (end); }
bool isVertical() const throw() { return start.getX() == end.getX(); }
bool isHorizontal() const throw() { return start.getY() == end.getY(); }
ValueType getAngle() const throw() { return start.getAngleToPoint (end); }
bool operator== (const Line& other) const throw() { return start == other.start && end == other.end; }
bool operator!= (const Line& other) const throw() { return start != other.start || end != other.end; }
bool intersects (const Line& line, Point<ValueType>& intersection) const throw()
{
return findIntersection (start, end, line.start, line.end, intersection);
}
const Point<ValueType> getPointAlongLine (ValueType distanceFromStart) const throw()
{
return start + (end - start) * (distanceFromStart / getLength());
}
const Point<ValueType> getPointAlongLine (ValueType distanceFromStart,
ValueType perpendicularDistance) const throw()
{
const Point<ValueType> delta (end - start);
const double length = juce_hypot (delta.getX(), delta.getY());
if (length == 0)
return start;
return Point<ValueType> (start.getX() + (ValueType) ((delta.getX() * distanceFromStart - delta.getY() * perpendicularDistance) / length),
start.getY() + (ValueType) ((delta.getY() * distanceFromStart + delta.getX() * perpendicularDistance) / length));
}
const Point<ValueType> getPointAlongLineProportionally (ValueType proportionOfLength) const throw()
{
return start + (end - start) * proportionOfLength;
}
ValueType getDistanceFromLine (const Point<ValueType>& point) const throw()
{
const Point<ValueType> delta (end - start);
const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY();
if (length > 0)
{
const double prop = ((point.getX() - start.getX()) * delta.getX()
+ (point.getY() - start.getY()) * delta.getY()) / length;
if (prop >= 0 && prop <= 1.0)
return point.getDistanceFrom (start + delta * (ValueType) prop);
}
return jmin (point.getDistanceFrom (start),
point.getDistanceFrom (end));
}
ValueType findNearestPointTo (const Point<ValueType>& point) const throw()
{
const Point<ValueType> delta (end - start);
const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY();
return length <= 0 ? 0
: jlimit ((ValueType) 0, (ValueType) 1,
(ValueType) (((point.getX() - start.getX()) * delta.getX()
+ (point.getY() - start.getY()) * delta.getY()) / length));
}
bool isPointAbove (const Point<ValueType>& point) const throw()
{
return start.getX() != end.getX()
&& point.getY() < ((end.getY() - start.getY())
* (point.getX() - start.getX())) / (end.getX() - start.getX()) + start.getY();
}
const Line withShortenedStart (ValueType distanceToShortenBy) const throw()
{
return Line (getPointAlongLine (jmin (distanceToShortenBy, getLength())), end);
}
const Line withShortenedEnd (ValueType distanceToShortenBy) const throw()
{
const ValueType length = getLength();
return Line (start, getPointAlongLine (length - jmin (distanceToShortenBy, length)));
}
juce_UseDebuggingNewOperator
private:
Point<ValueType> start, end;
static bool findIntersection (const Point<ValueType>& p1, const Point<ValueType>& p2,
const Point<ValueType>& p3, const Point<ValueType>& p4,
Point<ValueType>& intersection) throw()
{
if (p2 == p3)
{
intersection = p2;
return true;
}
const Point<ValueType> d1 (p2 - p1);
const Point<ValueType> d2 (p4 - p2);
const ValueType divisor = d1.getX() * d2.getY() - d2.getX() * d1.getY();
if (divisor == 0)
{
if (! (d1.isOrigin() || d2.isOrigin()))
{
if (d1.getY() == 0 && d2.getY() != 0)
{
const ValueType along = (p1.getY() - p3.getY()) / d2.getY();
intersection = p1.withX (p3.getX() + along * d2.getX());
return along >= 0 && along <= (ValueType) 1;
}
else if (d2.getY() == 0 && d1.getY() != 0)
{
const ValueType along = (p3.getY() - p1.getY()) / d1.getY();
intersection = p3.withX (p1.getX() + along * d1.getX());
return along >= 0 && along <= (ValueType) 1;
}
else if (d1.getX() == 0 && d2.getX() != 0)
{
const ValueType along = (p1.getX() - p3.getX()) / d2.getX();
intersection = p1.withY (p3.getY() + along * d2.getY());
return along >= 0 && along <= (ValueType) 1;
}
else if (d2.getX() == 0 && d1.getX() != 0)
{
const ValueType along = (p3.getX() - p1.getX()) / d1.getX();
intersection = p3.withY (p1.getY() + along * d1.getY());
return along >= 0 && along <= (ValueType) 1;
}
}
intersection = (p2 + p3) / (ValueType) 2;
return false;
}
const ValueType along1 = ((p1.getY() - p3.getY()) * d2.getX() - (p1.getX() - p3.getX()) * d2.getY()) / divisor;
intersection = p1 + d1 * along1;
if (along1 < 0 || along1 > (ValueType) 1)
return false;
const ValueType along2 = ((p1.getY() - p3.getY()) * d1.getX() - (p1.getX() - p3.getX()) * d1.getY()) / divisor;
return along2 >= 0 && along2 <= (ValueType) 1;
}
};
#endif // __JUCE_LINE_JUCEHEADER__
/*** End of inlined file: juce_Line.h ***/
/*** Start of inlined file: juce_Rectangle.h ***/
#ifndef __JUCE_RECTANGLE_JUCEHEADER__
#define __JUCE_RECTANGLE_JUCEHEADER__
@ -10602,10 +10835,14 @@ public:
bool contains (float x, float y,
float tolerence = 10.0f) const;
bool intersectsLine (float x1, float y1,
float x2, float y2,
bool contains (const Point<float>& point,
float tolerence = 10.0f) const;
bool intersectsLine (const Line<float>& line,
float tolerence = 10.0f);
const Line<float> getClippedLine (const Line<float>& line, bool keepSectionOutsidePath) const;
void clear() throw();
void startNewSubPath (float startX, float startY);
@ -11070,99 +11307,6 @@ private:
/*** End of inlined file: juce_PathStrokeType.h ***/
/*** Start of inlined file: juce_Line.h ***/
#ifndef __JUCE_LINE_JUCEHEADER__
#define __JUCE_LINE_JUCEHEADER__
class JUCE_API Line
{
public:
Line() throw();
Line (const Line& other) throw();
Line (float startX,
float startY,
float endX,
float endY) throw();
Line (const Point<float>& start,
const Point<float>& end) throw();
Line& operator= (const Line& other) throw();
~Line() throw();
inline float getStartX() const throw() { return startX; }
inline float getStartY() const throw() { return startY; }
inline float getEndX() const throw() { return endX; }
inline float getEndY() const throw() { return endY; }
const Point<float> getStart() const throw();
const Point<float> getEnd() const throw();
void setStart (float newStartX,
float newStartY) throw();
void setEnd (float newEndX,
float newEndY) throw();
void setStart (const Point<float>& newStart) throw();
void setEnd (const Point<float>& newEnd) throw();
void applyTransform (const AffineTransform& transform) throw();
float getLength() const throw();
bool isVertical() const throw();
bool isHorizontal() const throw();
float getAngle() const throw();
bool operator== (const Line& other) const throw();
bool operator!= (const Line& other) const throw();
bool intersects (const Line& line,
float& intersectionX,
float& intersectionY) const throw();
const Point<float> getPointAlongLine (float distanceFromStart) const throw();
const Point<float> getPointAlongLine (float distanceFromStart,
float perpendicularDistance) const throw();
const Point<float> getPointAlongLineProportionally (float proportionOfLength) const throw();
float getDistanceFromLine (float x, float y) const throw();
float findNearestPointTo (float x, float y) const throw();
bool isPointAbove (float x, float y) const throw();
const Line withShortenedStart (float distanceToShortenBy) const throw();
const Line withShortenedEnd (float distanceToShortenBy) const throw();
bool clipToPath (const Path& path, bool keepSectionOutsidePath) throw();
juce_UseDebuggingNewOperator
private:
float startX, startY, endX, endY;
};
#endif // __JUCE_LINE_JUCEHEADER__
/*** End of inlined file: juce_Line.h ***/
/*** Start of inlined file: juce_Colours.h ***/
#ifndef __JUCE_COLOURS_JUCEHEADER__
#define __JUCE_COLOURS_JUCEHEADER__
@ -12097,9 +12241,9 @@ public:
void drawLine (float startX, float startY, float endX, float endY,
float lineThickness) const;
void drawLine (const Line& line) const;
void drawLine (const Line<float>& line) const;
void drawLine (const Line& line, float lineThickness) const;
void drawLine (const Line<float>& line, float lineThickness) const;
void drawDashedLine (float startX, float startY,
float endX, float endY,

View file

@ -96,8 +96,6 @@
#if defined (__ppc__) || defined (__ppc64__)
#define JUCE_PPC 1
#undef MAC_OS_X_VERSION_MAX_ALLOWED
#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_4
#else
#define JUCE_INTEL 1
#endif

View file

@ -544,12 +544,12 @@ void Graphics::drawLine (const float startX, const float startY,
fillPath (p);
}
void Graphics::drawLine (const Line& line) const
void Graphics::drawLine (const Line<float>& line) const
{
drawLine (line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY());
}
void Graphics::drawLine (const Line& line, const float lineThickness) const
void Graphics::drawLine (const Line<float>& line, const float lineThickness) const
{
drawLine (line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), lineThickness);
}

View file

@ -359,13 +359,13 @@ public:
The line is 1 pixel wide and drawn with the current colour or brush.
*/
void drawLine (const Line& line) const;
void drawLine (const Line<float>& line) const;
/** Draws a line between two points with a given thickness.
@see Path::addLineSegment
*/
void drawLine (const Line& line, float lineThickness) const;
void drawLine (const Line<float>& line, float lineThickness) const;
/** Draws a dashed line using a custom set of dash-lengths.

View file

@ -177,48 +177,40 @@ public:
: lookupTable (lookupTable_), numEntries (numEntries_)
{
jassert (numEntries_ >= 0);
float x1 = gradient.x1;
float y1 = gradient.y1;
float x2 = gradient.x2;
float y2 = gradient.y2;
Point<float> p1 (gradient.x1, gradient.y1);
Point<float> p2 (gradient.x2, gradient.y2);
if (! transform.isIdentity())
{
const Line l (x2, y2, x1, y1);
const Point<float> p3 = l.getPointAlongLine (0.0f, 100.0f);
float x3 = p3.getX();
float y3 = p3.getY();
const Line<float> l (p2, p1);
Point<float> p3 = l.getPointAlongLine (0.0f, 100.0f);
transform.transformPoint (x1, y1);
transform.transformPoint (x2, y2);
transform.transformPoint (x3, y3);
p1.applyTransform (transform);
p2.applyTransform (transform);
p3.applyTransform (transform);
const Line l2 (x2, y2, x3, y3);
const float prop = l2.findNearestPointTo (x1, y1);
const Point<float> newP2 (l2.getPointAlongLineProportionally (prop));
x2 = newP2.getX();
y2 = newP2.getY();
const Line<float> l2 (p2, p3);
p2 = l2.getPointAlongLineProportionally (l2.findNearestPointTo (p1));
}
vertical = fabs (x1 - x2) < 0.001f;
horizontal = fabs (y1 - y2) < 0.001f;
vertical = fabs (p1.getX() - p2.getX()) < 0.001f;
horizontal = fabs (p1.getY() - p2.getY()) < 0.001f;
if (vertical)
{
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (y2 - y1));
start = roundToInt (y1 * scale);
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.getY() - p1.getY()));
start = roundToInt (p1.getY() * scale);
}
else if (horizontal)
{
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (x2 - x1));
start = roundToInt (x1 * scale);
scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.getX() - p1.getX()));
start = roundToInt (p1.getX() * scale);
}
else
{
grad = (y2 - y1) / (double) (x1 - x2);
yTerm = y1 - x1 / grad;
scale = roundToInt ((numEntries << (int) numScaleBits) / (yTerm * grad - (y2 * grad - x2)));
grad = (p2.getY() - p1.getY()) / (double) (p1.getX() - p2.getX());
yTerm = p1.getY() - p1.getX() / grad;
scale = roundToInt ((numEntries << (int) numScaleBits) / (yTerm * grad - (p2.getY() * grad - p2.getX())));
grad *= scale;
}
}

View file

@ -27,375 +27,7 @@
BEGIN_JUCE_NAMESPACE
#include "juce_Line.h"
#include "juce_PathIterator.h"
//==============================================================================
static bool juce_lineIntersection (const float x1, const float y1,
const float x2, const float y2,
const float x3, const float y3,
const float x4, const float y4,
float& intersectionX,
float& intersectionY) throw()
{
if (x2 != x3 || y2 != y3)
{
const float dx1 = x2 - x1;
const float dy1 = y2 - y1;
const float dx2 = x4 - x3;
const float dy2 = y4 - y3;
const float divisor = dx1 * dy2 - dx2 * dy1;
if (divisor == 0)
{
if (! ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)))
{
if (dy1 == 0 && dy2 != 0)
{
const float along = (y1 - y3) / dy2;
intersectionX = x3 + along * dx2;
intersectionY = y1;
return along >= 0 && along <= 1.0f;
}
else if (dy2 == 0 && dy1 != 0)
{
const float along = (y3 - y1) / dy1;
intersectionX = x1 + along * dx1;
intersectionY = y3;
return along >= 0 && along <= 1.0f;
}
else if (dx1 == 0 && dx2 != 0)
{
const float along = (x1 - x3) / dx2;
intersectionX = x1;
intersectionY = y3 + along * dy2;
return along >= 0 && along <= 1.0f;
}
else if (dx2 == 0 && dx1 != 0)
{
const float along = (x3 - x1) / dx1;
intersectionX = x3;
intersectionY = y1 + along * dy1;
return along >= 0 && along <= 1.0f;
}
}
intersectionX = 0.5f * (x2 + x3);
intersectionY = 0.5f * (y2 + y3);
return false;
}
const float along1 = ((y1 - y3) * dx2 - (x1 - x3) * dy2) / divisor;
intersectionX = x1 + along1 * dx1;
intersectionY = y1 + along1 * dy1;
if (along1 < 0 || along1 > 1.0f)
return false;
const float along2 = ((y1 - y3) * dx1 - (x1 - x3) * dy1) / divisor;
return along2 >= 0 && along2 <= 1.0f;
}
intersectionX = x2;
intersectionY = y2;
return true;
}
//==============================================================================
Line::Line() throw()
: startX (0.0f),
startY (0.0f),
endX (0.0f),
endY (0.0f)
{
}
Line::Line (const Line& other) throw()
: startX (other.startX),
startY (other.startY),
endX (other.endX),
endY (other.endY)
{
}
Line::Line (const float startX_, const float startY_,
const float endX_, const float endY_) throw()
: startX (startX_),
startY (startY_),
endX (endX_),
endY (endY_)
{
}
Line::Line (const Point<float>& start,
const Point<float>& end) throw()
: startX (start.getX()),
startY (start.getY()),
endX (end.getX()),
endY (end.getY())
{
}
Line& Line::operator= (const Line& other) throw()
{
startX = other.startX;
startY = other.startY;
endX = other.endX;
endY = other.endY;
return *this;
}
Line::~Line() throw()
{
}
//==============================================================================
const Point<float> Line::getStart() const throw()
{
return Point<float> (startX, startY);
}
const Point<float> Line::getEnd() const throw()
{
return Point<float> (endX, endY);
}
void Line::setStart (const float newStartX,
const float newStartY) throw()
{
startX = newStartX;
startY = newStartY;
}
void Line::setStart (const Point<float>& newStart) throw()
{
startX = newStart.getX();
startY = newStart.getY();
}
void Line::setEnd (const float newEndX,
const float newEndY) throw()
{
endX = newEndX;
endY = newEndY;
}
void Line::setEnd (const Point<float>& newEnd) throw()
{
endX = newEnd.getX();
endY = newEnd.getY();
}
bool Line::operator== (const Line& other) const throw()
{
return startX == other.startX
&& startY == other.startY
&& endX == other.endX
&& endY == other.endY;
}
bool Line::operator!= (const Line& other) const throw()
{
return startX != other.startX
|| startY != other.startY
|| endX != other.endX
|| endY != other.endY;
}
//==============================================================================
void Line::applyTransform (const AffineTransform& transform) throw()
{
transform.transformPoint (startX, startY);
transform.transformPoint (endX, endY);
}
//==============================================================================
float Line::getLength() const throw()
{
return (float) juce_hypot (startX - endX,
startY - endY);
}
float Line::getAngle() const throw()
{
return atan2f (endX - startX,
endY - startY);
}
const Point<float> Line::getPointAlongLine (const float distanceFromStart) const throw()
{
const float alpha = distanceFromStart / getLength();
return Point<float> (startX + (endX - startX) * alpha,
startY + (endY - startY) * alpha);
}
const Point<float> Line::getPointAlongLine (const float offsetX,
const float offsetY) const throw()
{
const float dx = endX - startX;
const float dy = endY - startY;
const double length = juce_hypot (dx, dy);
if (length == 0)
return Point<float> (startX, startY);
else
return Point<float> (startX + (float) (((dx * offsetX) - (dy * offsetY)) / length),
startY + (float) (((dy * offsetX) + (dx * offsetY)) / length));
}
const Point<float> Line::getPointAlongLineProportionally (const float alpha) const throw()
{
return Point<float> (startX + (endX - startX) * alpha,
startY + (endY - startY) * alpha);
}
float Line::getDistanceFromLine (const float x,
const float y) const throw()
{
const double dx = endX - startX;
const double dy = endY - startY;
const double length = dx * dx + dy * dy;
if (length > 0)
{
const double prop = ((x - startX) * dx + (y - startY) * dy) / length;
if (prop >= 0.0f && prop < 1.0f)
{
return (float) juce_hypot (x - (startX + prop * dx),
y - (startY + prop * dy));
}
}
return (float) jmin (juce_hypot (x - startX, y - startY),
juce_hypot (x - endX, y - endY));
}
float Line::findNearestPointTo (const float x,
const float y) const throw()
{
const double dx = endX - startX;
const double dy = endY - startY;
const double length = dx * dx + dy * dy;
if (length <= 0.0)
return 0.0f;
return jlimit (0.0f, 1.0f,
(float) (((x - startX) * dx + (y - startY) * dy) / length));
}
const Line Line::withShortenedStart (const float distanceToShortenBy) const throw()
{
const float length = getLength();
return Line (getPointAlongLine (jmin (distanceToShortenBy, length)),
getEnd());
}
const Line Line::withShortenedEnd (const float distanceToShortenBy) const throw()
{
const float length = getLength();
return Line (getStart(),
getPointAlongLine (length - jmin (distanceToShortenBy, length)));
}
//==============================================================================
bool Line::clipToPath (const Path& path,
const bool keepSectionOutsidePath) throw()
{
const bool startInside = path.contains (startX, startY);
const bool endInside = path.contains (endX, endY);
if (startInside == endInside)
{
if (keepSectionOutsidePath != startInside)
{
// entirely outside the path
return false;
}
else
{
// entirely inside the path
startX = 0.0f;
startY = 0.0f;
endX = 0.0f;
endY = 0.0f;
return true;
}
}
else
{
bool changed = false;
PathFlatteningIterator iter (path, AffineTransform::identity);
while (iter.next())
{
float ix, iy;
if (intersects (Line (iter.x1, iter.y1,
iter.x2, iter.y2),
ix, iy))
{
if ((startInside && keepSectionOutsidePath)
|| (endInside && ! keepSectionOutsidePath))
{
setStart (ix, iy);
}
else
{
setEnd (ix, iy);
}
changed = true;
}
}
return changed;
}
}
//==============================================================================
bool Line::intersects (const Line& line,
float& intersectionX,
float& intersectionY) const throw()
{
return juce_lineIntersection (startX, startY,
endX, endY,
line.startX, line.startY,
line.endX, line.endY,
intersectionX,
intersectionY);
}
bool Line::isVertical() const throw()
{
return startX == endX;
}
bool Line::isHorizontal() const throw()
{
return startY == endY;
}
bool Line::isPointAbove (const float x, const float y) const throw()
{
return startX != endX
&& y < ((endY - startY) * (x - startX)) / (endX - startX) + startY;
}
END_JUCE_NAMESPACE

View file

@ -26,122 +26,138 @@
#ifndef __JUCE_LINE_JUCEHEADER__
#define __JUCE_LINE_JUCEHEADER__
#include "juce_Path.h"
#include "juce_Point.h"
//==============================================================================
/**
Represents a line, using 32-bit float co-ordinates.
Represents a line.
This class contains a bunch of useful methods for various geometric
tasks.
@see Point, Rectangle, Path, Graphics::drawLine
*/
class JUCE_API Line
template <typename ValueType>
class Line
{
public:
//==============================================================================
/** Creates a line, using (0, 0) as its start and end points. */
Line() throw();
Line() throw() {}
/** Creates a copy of another line. */
Line (const Line& other) throw();
Line (const Line& other) throw()
: start (other.start),
end (other.end)
{
}
/** Creates a line based on the co-ordinates of its start and end points. */
Line (float startX,
float startY,
float endX,
float endY) throw();
Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) throw()
: start (startX, startY),
end (endX, endY)
{
}
/** Creates a line from its start and end points. */
Line (const Point<float>& start,
const Point<float>& end) throw();
Line (const Point<ValueType>& startPoint,
const Point<ValueType>& endPoint) throw()
: start (startPoint),
end (endPoint)
{
}
/** Copies a line from another one. */
Line& operator= (const Line& other) throw();
Line& operator= (const Line& other) throw()
{
start = other.start;
end = other.end;
return *this;
}
/** Destructor. */
~Line() throw();
~Line() throw() {}
//==============================================================================
/** Returns the x co-ordinate of the line's start point. */
inline float getStartX() const throw() { return startX; }
inline ValueType getStartX() const throw() { return start.getX(); }
/** Returns the y co-ordinate of the line's start point. */
inline float getStartY() const throw() { return startY; }
inline ValueType getStartY() const throw() { return start.getY(); }
/** Returns the x co-ordinate of the line's end point. */
inline float getEndX() const throw() { return endX; }
inline ValueType getEndX() const throw() { return end.getX(); }
/** Returns the y co-ordinate of the line's end point. */
inline float getEndY() const throw() { return endY; }
inline ValueType getEndY() const throw() { return end.getY(); }
/** Returns the line's start point. */
const Point<float> getStart() const throw();
inline const Point<ValueType>& getStart() const throw() { return start; }
/** Returns the line's end point. */
const Point<float> getEnd() const throw();
inline const Point<ValueType>& getEnd() const throw() { return end; }
/** Changes this line's start point */
void setStart (float newStartX,
float newStartY) throw();
void setStart (ValueType newStartX, ValueType newStartY) throw() { start.setXY (newStartX, newStartY); }
/** Changes this line's end point */
void setEnd (float newEndX,
float newEndY) throw();
void setEnd (ValueType newEndX, ValueType newEndY) throw() { end.setXY (newEndX, newEndY); }
/** Changes this line's start point */
void setStart (const Point<float>& newStart) throw();
void setStart (const Point<ValueType>& newStart) throw() { start = newStart; }
/** Changes this line's end point */
void setEnd (const Point<float>& newEnd) throw();
void setEnd (const Point<ValueType>& newEnd) throw() { end = newEnd; }
/** Applies an affine transform to the line's start and end points. */
void applyTransform (const AffineTransform& transform) throw();
void applyTransform (const AffineTransform& transform) throw()
{
start.applyTransform (transform);
end.applyTransform (transform);
}
//==============================================================================
/** Returns the length of the line. */
float getLength() const throw();
ValueType getLength() const throw() { return start.getDistanceFrom (end); }
/** Returns true if the line's start and end x co-ordinates are the same. */
bool isVertical() const throw();
bool isVertical() const throw() { return start.getX() == end.getX(); }
/** Returns true if the line's start and end y co-ordinates are the same. */
bool isHorizontal() const throw();
bool isHorizontal() const throw() { return start.getY() == end.getY(); }
/** Returns the line's angle.
This value is the number of radians clockwise from the 3 o'clock direction,
where the line's start point is considered to be at the centre.
*/
float getAngle() const throw();
ValueType getAngle() const throw() { return start.getAngleToPoint (end); }
//==============================================================================
/** Compares two lines. */
bool operator== (const Line& other) const throw();
bool operator== (const Line& other) const throw() { return start == other.start && end == other.end; }
/** Compares two lines. */
bool operator!= (const Line& other) const throw();
bool operator!= (const Line& other) const throw() { return start != other.start || end != other.end; }
//==============================================================================
/** Finds the intersection between two lines.
@param line the other line
@param intersectionX the x co-ordinate of the point where the lines meet (or
@param intersection the position of the point where the lines meet (or
where they would meet if they were infinitely long)
the intersection (if the lines intersect). If the lines
are parallel, this will just be set to the position
of one of the line's endpoints.
@param intersectionY the y co-ordinate of the point where the lines meet
@returns true if the line segments intersect; false if they dont. Even if they
don't intersect, the intersection co-ordinates returned will still
be valid
*/
bool intersects (const Line& line,
float& intersectionX,
float& intersectionY) const throw();
bool intersects (const Line& line, Point<ValueType>& intersection) const throw()
{
return findIntersection (start, end, line.start, line.end, intersection);
}
//==============================================================================
/** Returns the location of the point which is a given distance along this line.
@ -151,7 +167,10 @@ public:
than the line itself
@see getPointAlongLineProportionally
*/
const Point<float> getPointAlongLine (float distanceFromStart) const throw();
const Point<ValueType> getPointAlongLine (ValueType distanceFromStart) const throw()
{
return start + (end - start) * (distanceFromStart / getLength());
}
/** Returns a point which is a certain distance along and to the side of this line.
@ -166,8 +185,17 @@ public:
end, then a positive value here will move to the
right, negative value move to the left.
*/
const Point<float> getPointAlongLine (float distanceFromStart,
float perpendicularDistance) const throw();
const Point<ValueType> getPointAlongLine (ValueType distanceFromStart,
ValueType perpendicularDistance) const throw()
{
const Point<ValueType> delta (end - start);
const double length = juce_hypot (delta.getX(), delta.getY());
if (length == 0)
return start;
return Point<ValueType> (start.getX() + (ValueType) ((delta.getX() * distanceFromStart - delta.getY() * perpendicularDistance) / length),
start.getY() + (ValueType) ((delta.getY() * distanceFromStart + delta.getX() * perpendicularDistance) / length));
}
/** Returns the location of the point which is a given distance along this line
proportional to the line's length.
@ -179,7 +207,10 @@ public:
can be negative or greater than 1.0).
@see getPointAlongLine
*/
const Point<float> getPointAlongLineProportionally (float proportionOfLength) const throw();
const Point<ValueType> getPointAlongLineProportionally (ValueType proportionOfLength) const throw()
{
return start + (end - start) * proportionOfLength;
}
/** Returns the smallest distance between this line segment and a given point.
@ -187,12 +218,26 @@ public:
distance from the line; if the point is a long way beyond one of the line's
end-point's, it'll return the straight-line distance to the nearest end-point.
@param x x position of the point to test
@param y y position of the point to test
@returns the point's distance from the line
@see getPositionAlongLineOfNearestPoint
*/
float getDistanceFromLine (float x, float y) const throw();
ValueType getDistanceFromLine (const Point<ValueType>& point) const throw()
{
const Point<ValueType> delta (end - start);
const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY();
if (length > 0)
{
const double prop = ((point.getX() - start.getX()) * delta.getX()
+ (point.getY() - start.getY()) * delta.getY()) / length;
if (prop >= 0 && prop <= 1.0)
return point.getDistanceFrom (start + delta * (ValueType) prop);
}
return jmin (point.getDistanceFrom (start),
point.getDistanceFrom (end));
}
/** Finds the point on this line which is nearest to a given point, and
returns its position as a proportional position along the line.
@ -204,7 +249,16 @@ public:
turn this number into a position, use getPointAlongLineProportionally().
@see getDistanceFromLine, getPointAlongLineProportionally
*/
float findNearestPointTo (float x, float y) const throw();
ValueType findNearestPointTo (const Point<ValueType>& point) const throw()
{
const Point<ValueType> delta (end - start);
const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY();
return length <= 0 ? 0
: jlimit ((ValueType) 0, (ValueType) 1,
(ValueType) (((point.getX() - start.getX()) * delta.getX()
+ (point.getY() - start.getY()) * delta.getY()) / length));
}
/** Returns true if the given point lies above this line.
@ -212,7 +266,12 @@ public:
coordinate of this line at the given x (assuming the line extends infinitely
in both directions).
*/
bool isPointAbove (float x, float y) const throw();
bool isPointAbove (const Point<ValueType>& point) const throw()
{
return start.getX() != end.getX()
&& point.getY() < ((end.getY() - start.getY())
* (point.getX() - start.getX())) / (end.getX() - start.getX()) + start.getY();
}
//==============================================================================
/** Returns a shortened copy of this line.
@ -220,36 +279,86 @@ public:
This will chop off part of the start of this line by a certain amount, (leaving the
end-point the same), and return the new line.
*/
const Line withShortenedStart (float distanceToShortenBy) const throw();
const Line withShortenedStart (ValueType distanceToShortenBy) const throw()
{
return Line (getPointAlongLine (jmin (distanceToShortenBy, getLength())), end);
}
/** Returns a shortened copy of this line.
This will chop off part of the end of this line by a certain amount, (leaving the
start-point the same), and return the new line.
*/
const Line withShortenedEnd (float distanceToShortenBy) const throw();
/** Cuts off parts of this line to keep the parts that are either inside or
outside a path.
Note that this isn't smart enough to cope with situations where the
line would need to be cut into multiple pieces to correctly clip against
a re-entrant shape.
@param path the path to clip against
@param keepSectionOutsidePath if true, it's the section outside the path
that will be kept; if false its the section inside
the path
@returns true if the line was changed.
*/
bool clipToPath (const Path& path, bool keepSectionOutsidePath) throw();
const Line withShortenedEnd (ValueType distanceToShortenBy) const throw()
{
const ValueType length = getLength();
return Line (start, getPointAlongLine (length - jmin (distanceToShortenBy, length)));
}
//==============================================================================
juce_UseDebuggingNewOperator
private:
float startX, startY, endX, endY;
Point<ValueType> start, end;
static bool findIntersection (const Point<ValueType>& p1, const Point<ValueType>& p2,
const Point<ValueType>& p3, const Point<ValueType>& p4,
Point<ValueType>& intersection) throw()
{
if (p2 == p3)
{
intersection = p2;
return true;
}
const Point<ValueType> d1 (p2 - p1);
const Point<ValueType> d2 (p4 - p2);
const ValueType divisor = d1.getX() * d2.getY() - d2.getX() * d1.getY();
if (divisor == 0)
{
if (! (d1.isOrigin() || d2.isOrigin()))
{
if (d1.getY() == 0 && d2.getY() != 0)
{
const ValueType along = (p1.getY() - p3.getY()) / d2.getY();
intersection = p1.withX (p3.getX() + along * d2.getX());
return along >= 0 && along <= (ValueType) 1;
}
else if (d2.getY() == 0 && d1.getY() != 0)
{
const ValueType along = (p3.getY() - p1.getY()) / d1.getY();
intersection = p3.withX (p1.getX() + along * d1.getX());
return along >= 0 && along <= (ValueType) 1;
}
else if (d1.getX() == 0 && d2.getX() != 0)
{
const ValueType along = (p1.getX() - p3.getX()) / d2.getX();
intersection = p1.withY (p3.getY() + along * d2.getY());
return along >= 0 && along <= (ValueType) 1;
}
else if (d2.getX() == 0 && d1.getX() != 0)
{
const ValueType along = (p3.getX() - p1.getX()) / d1.getX();
intersection = p3.withY (p1.getY() + along * d1.getY());
return along >= 0 && along <= (ValueType) 1;
}
}
intersection = (p2 + p3) / (ValueType) 2;
return false;
}
const ValueType along1 = ((p1.getY() - p3.getY()) * d2.getX() - (p1.getX() - p3.getX()) * d2.getY()) / divisor;
intersection = p1 + d1 * along1;
if (along1 < 0 || along1 > (ValueType) 1)
return false;
const ValueType along2 = ((p1.getY() - p3.getY()) * d1.getX() - (p1.getX() - p3.getX()) * d1.getY()) / divisor;
return along2 >= 0 && along2 <= (ValueType) 1;
}
};

View file

@ -1040,8 +1040,7 @@ bool Path::contains (const float x, const float y, const float tolerence) const
while (i.next())
{
if ((i.y1 <= y && i.y2 > y)
|| (i.y2 <= y && i.y1 > y))
if ((i.y1 <= y && i.y2 > y) || (i.y2 <= y && i.y1 > y))
{
const float intersectX = i.x1 + (i.x2 - i.x1) * (y - i.y1) / (i.y2 - i.y1);
@ -1055,30 +1054,58 @@ bool Path::contains (const float x, const float y, const float tolerence) const
}
}
return (useNonZeroWinding) ? (negativeCrossings != positiveCrossings)
: ((negativeCrossings + positiveCrossings) & 1) != 0;
return useNonZeroWinding ? (negativeCrossings != positiveCrossings)
: ((negativeCrossings + positiveCrossings) & 1) != 0;
}
bool Path::intersectsLine (const float x1, const float y1,
const float x2, const float y2,
const float tolerence)
bool Path::contains (const Point<float>& point, const float tolerence) const
{
return contains (point.getX(), point.getY(), tolerence);
}
bool Path::intersectsLine (const Line<float>& line, const float tolerence)
{
PathFlatteningIterator i (*this, AffineTransform::identity, tolerence);
const Line line1 (x1, y1, x2, y2);
Point<float> intersection;
while (i.next())
{
const Line line2 (i.x1, i.y1, i.x2, i.y2);
float ix, iy;
if (line1.intersects (line2, ix, iy))
if (line.intersects (Line<float> (i.x1, i.y1, i.x2, i.y2), intersection))
return true;
}
return false;
}
const Line<float> Path::getClippedLine (const Line<float>& line, const bool keepSectionOutsidePath) const
{
Line<float> result (line);
const bool startInside = contains (line.getStart());
const bool endInside = contains (line.getEnd());
if (startInside == endInside)
{
if (keepSectionOutsidePath == startInside)
result = Line<float>();
}
else
{
PathFlatteningIterator i (*this, AffineTransform::identity);
Point<float> intersection;
while (i.next())
{
if (line.intersects (Line<float> (i.x1, i.y1, i.x2, i.y2), intersection))
{
if ((startInside && keepSectionOutsidePath) || (endInside && ! keepSectionOutsidePath))
result.setStart (intersection);
else
result.setEnd (intersection);
}
}
}
return result;
}
//==============================================================================
const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
{

View file

@ -27,7 +27,7 @@
#define __JUCE_PATH_JUCEHEADER__
#include "juce_AffineTransform.h"
#include "juce_Point.h"
#include "juce_Line.h"
#include "juce_Rectangle.h"
#include "../contexts/juce_Justification.h"
#include "../contexts/juce_EdgeTable.h"
@ -114,6 +114,22 @@ public:
bool contains (float x, float y,
float tolerence = 10.0f) const;
/** Checks whether a point lies within the path.
This is only relevent for closed paths (see closeSubPath()), and
may produce false results if used on a path which has open sub-paths.
The path's winding rule is taken into account by this method.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
@see closeSubPath, setUsingNonZeroWinding
*/
bool contains (const Point<float>& point,
float tolerence = 10.0f) const;
/** Checks whether a line crosses the path.
This will return positive if the line crosses any of the paths constituent
@ -124,10 +140,22 @@ public:
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
*/
bool intersectsLine (float x1, float y1,
float x2, float y2,
bool intersectsLine (const Line<float>& line,
float tolerence = 10.0f);
/** Cuts off parts of a line to keep the parts that are either inside or
outside this path.
Note that this isn't smart enough to cope with situations where the
line would need to be cut into multiple pieces to correctly clip against
a re-entrant shape.
@param keepSectionOutsidePath if true, it's the section outside the path
that will be kept; if false its the section inside
the path
*/
const Line<float> getClippedLine (const Line<float>& line, bool keepSectionOutsidePath) const;
//==============================================================================
/** Removes all lines and curves, resetting the path completely. */
void clear() throw();

View file

@ -71,6 +71,12 @@ public:
/** Returns true if the point is (0, 0). */
bool isOrigin() const throw() { return x == ValueType() && y == ValueType(); }
/** Returns a point which has the same Y position as this one, but a new X. */
const Point withX (const ValueType newX) const throw() { return Point (newX, y); }
/** Returns a point which has the same X position as this one, but a new Y. */
const Point withY (const ValueType newY) const throw() { return Point (x, newY); }
/** Changes the point's x and y co-ordinates. */
void setXY (const ValueType newX, const ValueType newY) throw() { x = newX; y = newY; }
@ -89,12 +95,34 @@ public:
/** Subtracts another point's co-ordinates to this one. */
Point& operator-= (const Point& other) throw() { x -= other.x; y -= other.y; return *this; }
/** Returns a point whose coordinates are multiplied by a given value. */
const Point operator* (const ValueType multiplier) const throw() { return Point (x * multiplier, y * multiplier); }
/** Multiplies the point's co-ordinates by a value. */
Point& operator*= (const ValueType multiplier) throw() { x *= multiplier; y *= multiplier; return *this; }
/** Returns a point whose coordinates are divided by a given value. */
const Point operator/ (const ValueType divisor) const throw() { return Point (x / divisor, y / divisor); }
/** Divides the point's co-ordinates by a value. */
Point& operator/= (const ValueType divisor) throw() { x /= divisor; y /= divisor; return *this; }
/** Returns the inverse of this point. */
const Point operator-() const throw() { return Point (-x, -y); }
/** Returns the straight-line distance between this point and another one. */
ValueType getDistanceFromOrigin() const throw() { return (ValueType) juce_hypot (x, y); }
/** Returns the straight-line distance between this point and another one. */
ValueType getDistanceFrom (const Point& other) const throw() { return (ValueType) juce_hypot (x - other.x, y - other.y); }
/** Returns the angle from this point to another one.
The return value is the number of radians clockwise from the 3 o'clock direction,
where this point is the centre and the other point is on the radius.
*/
ValueType getAngleToPoint (const Point& other) const throw() { return (ValueType) atan2 (other.x - x, other.y - y); }
/** Uses a transform to change the point's co-ordinates.
This will only compile if ValueType = float!
@see AffineTransform::transformPoint