migrating to the latest JUCE version
This commit is contained in:
		@@ -1,280 +1,280 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AffineTransform::AffineTransform (float m00, float m01, float m02,
 | 
			
		||||
                                  float m10, float m11, float m12) noexcept
 | 
			
		||||
 :  mat00 (m00), mat01 (m01), mat02 (m02),
 | 
			
		||||
    mat10 (m10), mat11 (m11), mat12 (m12)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::operator== (const AffineTransform& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return mat00 == other.mat00
 | 
			
		||||
        && mat01 == other.mat01
 | 
			
		||||
        && mat02 == other.mat02
 | 
			
		||||
        && mat10 == other.mat10
 | 
			
		||||
        && mat11 == other.mat11
 | 
			
		||||
        && mat12 == other.mat12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::operator!= (const AffineTransform& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return ! operator== (other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool AffineTransform::isIdentity() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return mat01 == 0.0f
 | 
			
		||||
        && mat02 == 0.0f
 | 
			
		||||
        && mat10 == 0.0f
 | 
			
		||||
        && mat12 == 0.0f
 | 
			
		||||
        && mat00 == 1.0f
 | 
			
		||||
        && mat11 == 1.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const AffineTransform AffineTransform::identity (1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AffineTransform AffineTransform::followedBy (const AffineTransform& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { other.mat00 * mat00 + other.mat01 * mat10,
 | 
			
		||||
             other.mat00 * mat01 + other.mat01 * mat11,
 | 
			
		||||
             other.mat00 * mat02 + other.mat01 * mat12 + other.mat02,
 | 
			
		||||
             other.mat10 * mat00 + other.mat11 * mat10,
 | 
			
		||||
             other.mat10 * mat01 + other.mat11 * mat11,
 | 
			
		||||
             other.mat10 * mat02 + other.mat11 * mat12 + other.mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::translated (float dx, float dy) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { mat00, mat01, mat02 + dx,
 | 
			
		||||
             mat10, mat11, mat12 + dy };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::translation (float dx, float dy) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { 1.0f, 0.0f, dx,
 | 
			
		||||
             0.0f, 1.0f, dy };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::withAbsoluteTranslation (float tx, float ty) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { mat00, mat01, tx,
 | 
			
		||||
             mat10, mat11, ty };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotated (float rad) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    auto cosRad = std::cos (rad);
 | 
			
		||||
    auto sinRad = std::sin (rad);
 | 
			
		||||
 | 
			
		||||
    return { cosRad * mat00 - sinRad * mat10,
 | 
			
		||||
             cosRad * mat01 - sinRad * mat11,
 | 
			
		||||
             cosRad * mat02 - sinRad * mat12,
 | 
			
		||||
             sinRad * mat00 + cosRad * mat10,
 | 
			
		||||
             sinRad * mat01 + cosRad * mat11,
 | 
			
		||||
             sinRad * mat02 + cosRad * mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotation (float rad) noexcept
 | 
			
		||||
{
 | 
			
		||||
    auto cosRad = std::cos (rad);
 | 
			
		||||
    auto sinRad = std::sin (rad);
 | 
			
		||||
 | 
			
		||||
    return { cosRad, -sinRad, 0,
 | 
			
		||||
             sinRad,  cosRad, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotation (float rad, float pivotX, float pivotY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    auto cosRad = std::cos (rad);
 | 
			
		||||
    auto sinRad = std::sin (rad);
 | 
			
		||||
 | 
			
		||||
    return { cosRad, -sinRad, -cosRad * pivotX +  sinRad * pivotY + pivotX,
 | 
			
		||||
             sinRad,  cosRad, -sinRad * pivotX + -cosRad * pivotY + pivotY };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotated (float angle, float pivotX, float pivotY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return followedBy (rotation (angle, pivotX, pivotY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scaled (float factorX, float factorY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX * mat00, factorX * mat01, factorX * mat02,
 | 
			
		||||
             factorY * mat10, factorY * mat11, factorY * mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scaled (float factor) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factor * mat00, factor * mat01, factor * mat02,
 | 
			
		||||
             factor * mat10, factor * mat11, factor * mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scale (float factorX, float factorY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX, 0, 0, 0, factorY, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scale (float factor) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factor, 0, 0, 0, factor, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scaled (float factorX, float factorY,
 | 
			
		||||
                                         float pivotX, float pivotY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX * mat00, factorX * mat01, factorX * mat02 + pivotX * (1.0f - factorX),
 | 
			
		||||
             factorY * mat10, factorY * mat11, factorY * mat12 + pivotY * (1.0f - factorY) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scale (float factorX, float factorY,
 | 
			
		||||
                                        float pivotX, float pivotY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX, 0, pivotX * (1.0f - factorX),
 | 
			
		||||
             0, factorY, pivotY * (1.0f - factorY) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::shear (float shearX, float shearY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { 1.0f,   shearX, 0,
 | 
			
		||||
             shearY, 1.0f,   0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::sheared (float shearX, float shearY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { mat00 + shearX * mat10,
 | 
			
		||||
             mat01 + shearX * mat11,
 | 
			
		||||
             mat02 + shearX * mat12,
 | 
			
		||||
             mat10 + shearY * mat00,
 | 
			
		||||
             mat11 + shearY * mat01,
 | 
			
		||||
             mat12 + shearY * mat02 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::verticalFlip (float height) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { 1.0f,  0.0f, 0.0f,
 | 
			
		||||
             0.0f, -1.0f, height };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::inverted() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    double determinant = getDeterminant();
 | 
			
		||||
 | 
			
		||||
    if (! approximatelyEqual (determinant, 0.0))
 | 
			
		||||
    {
 | 
			
		||||
        determinant = 1.0 / determinant;
 | 
			
		||||
 | 
			
		||||
        auto dst00 = (float) ( mat11 * determinant);
 | 
			
		||||
        auto dst10 = (float) (-mat10 * determinant);
 | 
			
		||||
        auto dst01 = (float) (-mat01 * determinant);
 | 
			
		||||
        auto dst11 = (float) ( mat00 * determinant);
 | 
			
		||||
 | 
			
		||||
        return { dst00, dst01, -mat02 * dst00 - mat12 * dst01,
 | 
			
		||||
                 dst10, dst11, -mat02 * dst10 - mat12 * dst11 };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // singularity..
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::isSingularity() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (mat00 * mat11 - mat10 * mat01) == 0.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::fromTargetPoints (float x00, float y00,
 | 
			
		||||
                                                   float x10, float y10,
 | 
			
		||||
                                                   float x01, float y01) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { x10 - x00, x01 - x00, x00,
 | 
			
		||||
             y10 - y00, y01 - y00, y00 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::fromTargetPoints (float sx1, float sy1, float tx1, float ty1,
 | 
			
		||||
                                                   float sx2, float sy2, float tx2, float ty2,
 | 
			
		||||
                                                   float sx3, float sy3, float tx3, float ty3) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return fromTargetPoints (sx1, sy1, sx2, sy2, sx3, sy3)
 | 
			
		||||
            .inverted()
 | 
			
		||||
            .followedBy (fromTargetPoints (tx1, ty1, tx2, ty2, tx3, ty3));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::isOnlyTranslation() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return mat01 == 0.0f
 | 
			
		||||
        && mat10 == 0.0f
 | 
			
		||||
        && mat00 == 1.0f
 | 
			
		||||
        && mat11 == 1.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float AffineTransform::getDeterminant() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (mat00 * mat11) - (mat01 * mat10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float AffineTransform::getScaleFactor() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (std::abs (mat00) + std::abs (mat11)) / 2.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
class AffineTransformTests  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AffineTransformTests()
 | 
			
		||||
        : UnitTest ("AffineTransform", UnitTestCategories::maths)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("Determinant");
 | 
			
		||||
        {
 | 
			
		||||
            constexpr float scale1 = 1.5f, scale2 = 1.3f;
 | 
			
		||||
 | 
			
		||||
            auto transform = AffineTransform::scale (scale1)
 | 
			
		||||
                                             .followedBy (AffineTransform::rotation (degreesToRadians (72.0f)))
 | 
			
		||||
                                             .followedBy (AffineTransform::translation (100.0f, 20.0f))
 | 
			
		||||
                                             .followedBy (AffineTransform::scale (scale2));
 | 
			
		||||
 | 
			
		||||
            expect (approximatelyEqual (std::sqrt (std::abs (transform.getDeterminant())), scale1 * scale2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static AffineTransformTests timeTests;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AffineTransform::AffineTransform (float m00, float m01, float m02,
 | 
			
		||||
                                  float m10, float m11, float m12) noexcept
 | 
			
		||||
 :  mat00 (m00), mat01 (m01), mat02 (m02),
 | 
			
		||||
    mat10 (m10), mat11 (m11), mat12 (m12)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::operator== (const AffineTransform& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return mat00 == other.mat00
 | 
			
		||||
        && mat01 == other.mat01
 | 
			
		||||
        && mat02 == other.mat02
 | 
			
		||||
        && mat10 == other.mat10
 | 
			
		||||
        && mat11 == other.mat11
 | 
			
		||||
        && mat12 == other.mat12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::operator!= (const AffineTransform& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return ! operator== (other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool AffineTransform::isIdentity() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return mat01 == 0.0f
 | 
			
		||||
        && mat02 == 0.0f
 | 
			
		||||
        && mat10 == 0.0f
 | 
			
		||||
        && mat12 == 0.0f
 | 
			
		||||
        && mat00 == 1.0f
 | 
			
		||||
        && mat11 == 1.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const AffineTransform AffineTransform::identity (1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AffineTransform AffineTransform::followedBy (const AffineTransform& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { other.mat00 * mat00 + other.mat01 * mat10,
 | 
			
		||||
             other.mat00 * mat01 + other.mat01 * mat11,
 | 
			
		||||
             other.mat00 * mat02 + other.mat01 * mat12 + other.mat02,
 | 
			
		||||
             other.mat10 * mat00 + other.mat11 * mat10,
 | 
			
		||||
             other.mat10 * mat01 + other.mat11 * mat11,
 | 
			
		||||
             other.mat10 * mat02 + other.mat11 * mat12 + other.mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::translated (float dx, float dy) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { mat00, mat01, mat02 + dx,
 | 
			
		||||
             mat10, mat11, mat12 + dy };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::translation (float dx, float dy) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { 1.0f, 0.0f, dx,
 | 
			
		||||
             0.0f, 1.0f, dy };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::withAbsoluteTranslation (float tx, float ty) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { mat00, mat01, tx,
 | 
			
		||||
             mat10, mat11, ty };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotated (float rad) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    auto cosRad = std::cos (rad);
 | 
			
		||||
    auto sinRad = std::sin (rad);
 | 
			
		||||
 | 
			
		||||
    return { cosRad * mat00 - sinRad * mat10,
 | 
			
		||||
             cosRad * mat01 - sinRad * mat11,
 | 
			
		||||
             cosRad * mat02 - sinRad * mat12,
 | 
			
		||||
             sinRad * mat00 + cosRad * mat10,
 | 
			
		||||
             sinRad * mat01 + cosRad * mat11,
 | 
			
		||||
             sinRad * mat02 + cosRad * mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotation (float rad) noexcept
 | 
			
		||||
{
 | 
			
		||||
    auto cosRad = std::cos (rad);
 | 
			
		||||
    auto sinRad = std::sin (rad);
 | 
			
		||||
 | 
			
		||||
    return { cosRad, -sinRad, 0,
 | 
			
		||||
             sinRad,  cosRad, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotation (float rad, float pivotX, float pivotY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    auto cosRad = std::cos (rad);
 | 
			
		||||
    auto sinRad = std::sin (rad);
 | 
			
		||||
 | 
			
		||||
    return { cosRad, -sinRad, -cosRad * pivotX +  sinRad * pivotY + pivotX,
 | 
			
		||||
             sinRad,  cosRad, -sinRad * pivotX + -cosRad * pivotY + pivotY };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::rotated (float angle, float pivotX, float pivotY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return followedBy (rotation (angle, pivotX, pivotY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scaled (float factorX, float factorY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX * mat00, factorX * mat01, factorX * mat02,
 | 
			
		||||
             factorY * mat10, factorY * mat11, factorY * mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scaled (float factor) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factor * mat00, factor * mat01, factor * mat02,
 | 
			
		||||
             factor * mat10, factor * mat11, factor * mat12 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scale (float factorX, float factorY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX, 0, 0, 0, factorY, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scale (float factor) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factor, 0, 0, 0, factor, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scaled (float factorX, float factorY,
 | 
			
		||||
                                         float pivotX, float pivotY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX * mat00, factorX * mat01, factorX * mat02 + pivotX * (1.0f - factorX),
 | 
			
		||||
             factorY * mat10, factorY * mat11, factorY * mat12 + pivotY * (1.0f - factorY) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::scale (float factorX, float factorY,
 | 
			
		||||
                                        float pivotX, float pivotY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { factorX, 0, pivotX * (1.0f - factorX),
 | 
			
		||||
             0, factorY, pivotY * (1.0f - factorY) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::shear (float shearX, float shearY) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { 1.0f,   shearX, 0,
 | 
			
		||||
             shearY, 1.0f,   0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::sheared (float shearX, float shearY) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { mat00 + shearX * mat10,
 | 
			
		||||
             mat01 + shearX * mat11,
 | 
			
		||||
             mat02 + shearX * mat12,
 | 
			
		||||
             mat10 + shearY * mat00,
 | 
			
		||||
             mat11 + shearY * mat01,
 | 
			
		||||
             mat12 + shearY * mat02 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::verticalFlip (float height) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { 1.0f,  0.0f, 0.0f,
 | 
			
		||||
             0.0f, -1.0f, height };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::inverted() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    double determinant = getDeterminant();
 | 
			
		||||
 | 
			
		||||
    if (! approximatelyEqual (determinant, 0.0))
 | 
			
		||||
    {
 | 
			
		||||
        determinant = 1.0 / determinant;
 | 
			
		||||
 | 
			
		||||
        auto dst00 = (float) ( mat11 * determinant);
 | 
			
		||||
        auto dst10 = (float) (-mat10 * determinant);
 | 
			
		||||
        auto dst01 = (float) (-mat01 * determinant);
 | 
			
		||||
        auto dst11 = (float) ( mat00 * determinant);
 | 
			
		||||
 | 
			
		||||
        return { dst00, dst01, -mat02 * dst00 - mat12 * dst01,
 | 
			
		||||
                 dst10, dst11, -mat02 * dst10 - mat12 * dst11 };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // singularity..
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::isSingularity() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (mat00 * mat11 - mat10 * mat01) == 0.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::fromTargetPoints (float x00, float y00,
 | 
			
		||||
                                                   float x10, float y10,
 | 
			
		||||
                                                   float x01, float y01) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return { x10 - x00, x01 - x00, x00,
 | 
			
		||||
             y10 - y00, y01 - y00, y00 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AffineTransform AffineTransform::fromTargetPoints (float sx1, float sy1, float tx1, float ty1,
 | 
			
		||||
                                                   float sx2, float sy2, float tx2, float ty2,
 | 
			
		||||
                                                   float sx3, float sy3, float tx3, float ty3) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return fromTargetPoints (sx1, sy1, sx2, sy2, sx3, sy3)
 | 
			
		||||
            .inverted()
 | 
			
		||||
            .followedBy (fromTargetPoints (tx1, ty1, tx2, ty2, tx3, ty3));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AffineTransform::isOnlyTranslation() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return mat01 == 0.0f
 | 
			
		||||
        && mat10 == 0.0f
 | 
			
		||||
        && mat00 == 1.0f
 | 
			
		||||
        && mat11 == 1.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float AffineTransform::getDeterminant() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (mat00 * mat11) - (mat01 * mat10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float AffineTransform::getScaleFactor() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (std::abs (mat00) + std::abs (mat11)) / 2.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
class AffineTransformTests  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AffineTransformTests()
 | 
			
		||||
        : UnitTest ("AffineTransform", UnitTestCategories::maths)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("Determinant");
 | 
			
		||||
        {
 | 
			
		||||
            constexpr float scale1 = 1.5f, scale2 = 1.3f;
 | 
			
		||||
 | 
			
		||||
            auto transform = AffineTransform::scale (scale1)
 | 
			
		||||
                                             .followedBy (AffineTransform::rotation (degreesToRadians (72.0f)))
 | 
			
		||||
                                             .followedBy (AffineTransform::translation (100.0f, 20.0f))
 | 
			
		||||
                                             .followedBy (AffineTransform::scale (scale2));
 | 
			
		||||
 | 
			
		||||
            expect (approximatelyEqual (std::sqrt (std::abs (transform.getDeterminant())), scale1 * scale2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static AffineTransformTests timeTests;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,303 +1,303 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Represents a 2D affine-transformation matrix.
 | 
			
		||||
 | 
			
		||||
    An affine transformation is a transformation such as a rotation, scale, shear,
 | 
			
		||||
    resize or translation.
 | 
			
		||||
 | 
			
		||||
    These are used for various 2D transformation tasks, e.g. with Path objects.
 | 
			
		||||
 | 
			
		||||
    @see Path, Point, Line
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AffineTransform  final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an identity transform. */
 | 
			
		||||
    AffineTransform() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another transform. */
 | 
			
		||||
    AffineTransform (const AffineTransform&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a transform from a set of raw matrix values.
 | 
			
		||||
 | 
			
		||||
        The resulting matrix is:
 | 
			
		||||
 | 
			
		||||
            (mat00 mat01 mat02)
 | 
			
		||||
            (mat10 mat11 mat12)
 | 
			
		||||
            (  0     0     1  )
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform (float mat00, float mat01, float mat02,
 | 
			
		||||
                     float mat10, float mat11, float mat12) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Copies from another AffineTransform object */
 | 
			
		||||
    AffineTransform& operator= (const AffineTransform&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Compares two transforms. */
 | 
			
		||||
    bool operator== (const AffineTransform& other) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Compares two transforms. */
 | 
			
		||||
    bool operator!= (const AffineTransform& other) const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Transforms a 2D coordinate using this matrix. */
 | 
			
		||||
    template <typename ValueType>
 | 
			
		||||
    void transformPoint (ValueType& x, ValueType& y) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto oldX = x;
 | 
			
		||||
        x = static_cast<ValueType> (mat00 * oldX + mat01 * y + mat02);
 | 
			
		||||
        y = static_cast<ValueType> (mat10 * oldX + mat11 * y + mat12);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Transforms two 2D coordinates using this matrix.
 | 
			
		||||
        This is just a shortcut for calling transformPoint() on each of these pairs of
 | 
			
		||||
        coordinates in turn. (And putting all the calculations into one function hopefully
 | 
			
		||||
        also gives the compiler a bit more scope for pipelining it).
 | 
			
		||||
    */
 | 
			
		||||
    template <typename ValueType>
 | 
			
		||||
    void transformPoints (ValueType& x1, ValueType& y1,
 | 
			
		||||
                          ValueType& x2, ValueType& y2) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto oldX1 = x1, oldX2 = x2;
 | 
			
		||||
        x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
 | 
			
		||||
        y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
 | 
			
		||||
        x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
 | 
			
		||||
        y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Transforms three 2D coordinates using this matrix.
 | 
			
		||||
        This is just a shortcut for calling transformPoint() on each of these pairs of
 | 
			
		||||
        coordinates in turn. (And putting all the calculations into one function hopefully
 | 
			
		||||
        also gives the compiler a bit more scope for pipelining it).
 | 
			
		||||
    */
 | 
			
		||||
    template <typename ValueType>
 | 
			
		||||
    void transformPoints (ValueType& x1, ValueType& y1,
 | 
			
		||||
                          ValueType& x2, ValueType& y2,
 | 
			
		||||
                          ValueType& x3, ValueType& y3) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto oldX1 = x1, oldX2 = x2, oldX3 = x3;
 | 
			
		||||
        x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
 | 
			
		||||
        y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
 | 
			
		||||
        x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
 | 
			
		||||
        y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
 | 
			
		||||
        x3 = static_cast<ValueType> (mat00 * oldX3 + mat01 * y3 + mat02);
 | 
			
		||||
        y3 = static_cast<ValueType> (mat10 * oldX3 + mat11 * y3 + mat12);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a new transform which is the same as this one followed by a translation. */
 | 
			
		||||
    AffineTransform translated (float deltaX,
 | 
			
		||||
                                float deltaY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is the same as this one followed by a translation. */
 | 
			
		||||
    template <typename PointType>
 | 
			
		||||
    AffineTransform translated (PointType delta) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return translated ((float) delta.x, (float) delta.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a translation. */
 | 
			
		||||
    static AffineTransform translation (float deltaX,
 | 
			
		||||
                                        float deltaY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a translation. */
 | 
			
		||||
    template <typename PointType>
 | 
			
		||||
    static AffineTransform translation (PointType delta) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return translation ((float) delta.x, (float) delta.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a copy of this transform with the specified translation matrix values. */
 | 
			
		||||
    AffineTransform withAbsoluteTranslation (float translationX,
 | 
			
		||||
                                             float translationY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a rotation.
 | 
			
		||||
 | 
			
		||||
        The rotation is specified by a number of radians to rotate clockwise, centred around
 | 
			
		||||
        the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform rotated (float angleInRadians) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a rotation about a given point.
 | 
			
		||||
 | 
			
		||||
        The rotation is specified by a number of radians to rotate clockwise, centred around
 | 
			
		||||
        the coordinates passed in.
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform rotated (float angleInRadians,
 | 
			
		||||
                             float pivotX,
 | 
			
		||||
                             float pivotY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a rotation about (0, 0). */
 | 
			
		||||
    static AffineTransform rotation (float angleInRadians) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a rotation about a given point. */
 | 
			
		||||
    static AffineTransform rotation (float angleInRadians,
 | 
			
		||||
                                     float pivotX,
 | 
			
		||||
                                     float pivotY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a re-scaling.
 | 
			
		||||
        The scaling is centred around the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform scaled (float factorX,
 | 
			
		||||
                            float factorY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a re-scaling.
 | 
			
		||||
        The scaling is centred around the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform scaled (float factor) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a re-scaling.
 | 
			
		||||
        The scaling is centred around the origin provided.
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform scaled (float factorX, float factorY,
 | 
			
		||||
                            float pivotX, float pivotY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a re-scale about the origin. */
 | 
			
		||||
    static AffineTransform scale (float factorX,
 | 
			
		||||
                                  float factorY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a re-scale about the origin. */
 | 
			
		||||
    static AffineTransform scale (float factor) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a re-scale centred around the point provided. */
 | 
			
		||||
    static AffineTransform scale (float factorX, float factorY,
 | 
			
		||||
                                  float pivotX, float pivotY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a shear.
 | 
			
		||||
        The shear is centred around the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform sheared (float shearX, float shearY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a shear transform, centred around the origin (0, 0). */
 | 
			
		||||
    static AffineTransform shear (float shearX, float shearY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform that will flip coordinates vertically within a window of the given height.
 | 
			
		||||
        This is handy for converting between upside-down coordinate systems such as OpenGL or CoreGraphics.
 | 
			
		||||
    */
 | 
			
		||||
    static AffineTransform verticalFlip (float height) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a matrix which is the inverse operation of this one.
 | 
			
		||||
 | 
			
		||||
        Some matrices don't have an inverse - in this case, the method will just return
 | 
			
		||||
        an identity transform.
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform inverted() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the transform that will map three known points onto three coordinates
 | 
			
		||||
        that are supplied.
 | 
			
		||||
 | 
			
		||||
        This returns the transform that will transform (0, 0) into (x00, y00),
 | 
			
		||||
        (1, 0) to (x10, y10), and (0, 1) to (x01, y01).
 | 
			
		||||
    */
 | 
			
		||||
    static AffineTransform fromTargetPoints (float x00, float y00,
 | 
			
		||||
                                             float x10, float y10,
 | 
			
		||||
                                             float x01, float y01) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the transform that will map three specified points onto three target points. */
 | 
			
		||||
    static AffineTransform fromTargetPoints (float sourceX1, float sourceY1, float targetX1, float targetY1,
 | 
			
		||||
                                             float sourceX2, float sourceY2, float targetX2, float targetY2,
 | 
			
		||||
                                             float sourceX3, float sourceY3, float targetX3, float targetY3) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the transform that will map three specified points onto three target points. */
 | 
			
		||||
    template <typename PointType>
 | 
			
		||||
    static AffineTransform fromTargetPoints (PointType source1, PointType target1,
 | 
			
		||||
                                             PointType source2, PointType target2,
 | 
			
		||||
                                             PointType source3, PointType target3) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return fromTargetPoints (source1.x, source1.y, target1.x, target1.y,
 | 
			
		||||
                                 source2.x, source2.y, target2.x, target2.y,
 | 
			
		||||
                                 source3.x, source3.y, target3.x, target3.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the result of concatenating another transformation after this one. */
 | 
			
		||||
    AffineTransform followedBy (const AffineTransform& other) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this transform has no effect on points. */
 | 
			
		||||
    bool isIdentity() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */
 | 
			
		||||
    bool isSingularity() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the transform only translates, and doesn't scale or rotate the
 | 
			
		||||
        points. */
 | 
			
		||||
    bool isOnlyTranslation() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** If this transform is only a translation, this returns the X offset.
 | 
			
		||||
        @see isOnlyTranslation
 | 
			
		||||
    */
 | 
			
		||||
    float getTranslationX() const noexcept                  { return mat02; }
 | 
			
		||||
 | 
			
		||||
    /** If this transform is only a translation, this returns the X offset.
 | 
			
		||||
        @see isOnlyTranslation
 | 
			
		||||
    */
 | 
			
		||||
    float getTranslationY() const noexcept                  { return mat12; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the determinant of the transform. */
 | 
			
		||||
    float getDeterminant() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #ifndef DOXYGEN
 | 
			
		||||
    /** This method has been deprecated.
 | 
			
		||||
 | 
			
		||||
        You can calculate the scale factor using:
 | 
			
		||||
        @code
 | 
			
		||||
        std::sqrt (std::abs (AffineTransform::getDeterminant()))
 | 
			
		||||
        @endcode
 | 
			
		||||
 | 
			
		||||
        This method produces incorrect values for transforms containing rotations.
 | 
			
		||||
 | 
			
		||||
        Returns the approximate scale factor by which lengths will be transformed.
 | 
			
		||||
        Obviously a length may be scaled by entirely different amounts depending on its
 | 
			
		||||
        direction, so this is only appropriate as a rough guide.
 | 
			
		||||
    */
 | 
			
		||||
    [[deprecated ("This method produces incorrect values for transforms containing rotations. "
 | 
			
		||||
                 "See the method docs for a code example on how to calculate the correct scale factor.")]]
 | 
			
		||||
    float getScaleFactor() const noexcept;
 | 
			
		||||
 | 
			
		||||
    [[deprecated ("If you need an identity transform, just use AffineTransform() or {}.")]]
 | 
			
		||||
    static const AffineTransform identity;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /* The transform matrix is:
 | 
			
		||||
 | 
			
		||||
        (mat00 mat01 mat02)
 | 
			
		||||
        (mat10 mat11 mat12)
 | 
			
		||||
        (  0     0     1  )
 | 
			
		||||
    */
 | 
			
		||||
    float mat00 { 1.0f }, mat01 { 0.0f }, mat02 { 0.0f };
 | 
			
		||||
    float mat10 { 0.0f }, mat11 { 1.0f }, mat12 { 0.0f };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Represents a 2D affine-transformation matrix.
 | 
			
		||||
 | 
			
		||||
    An affine transformation is a transformation such as a rotation, scale, shear,
 | 
			
		||||
    resize or translation.
 | 
			
		||||
 | 
			
		||||
    These are used for various 2D transformation tasks, e.g. with Path objects.
 | 
			
		||||
 | 
			
		||||
    @see Path, Point, Line
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AffineTransform  final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an identity transform. */
 | 
			
		||||
    AffineTransform() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another transform. */
 | 
			
		||||
    AffineTransform (const AffineTransform&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a transform from a set of raw matrix values.
 | 
			
		||||
 | 
			
		||||
        The resulting matrix is:
 | 
			
		||||
 | 
			
		||||
            (mat00 mat01 mat02)
 | 
			
		||||
            (mat10 mat11 mat12)
 | 
			
		||||
            (  0     0     1  )
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform (float mat00, float mat01, float mat02,
 | 
			
		||||
                     float mat10, float mat11, float mat12) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Copies from another AffineTransform object */
 | 
			
		||||
    AffineTransform& operator= (const AffineTransform&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Compares two transforms. */
 | 
			
		||||
    bool operator== (const AffineTransform& other) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Compares two transforms. */
 | 
			
		||||
    bool operator!= (const AffineTransform& other) const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Transforms a 2D coordinate using this matrix. */
 | 
			
		||||
    template <typename ValueType>
 | 
			
		||||
    void transformPoint (ValueType& x, ValueType& y) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto oldX = x;
 | 
			
		||||
        x = static_cast<ValueType> (mat00 * oldX + mat01 * y + mat02);
 | 
			
		||||
        y = static_cast<ValueType> (mat10 * oldX + mat11 * y + mat12);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Transforms two 2D coordinates using this matrix.
 | 
			
		||||
        This is just a shortcut for calling transformPoint() on each of these pairs of
 | 
			
		||||
        coordinates in turn. (And putting all the calculations into one function hopefully
 | 
			
		||||
        also gives the compiler a bit more scope for pipelining it).
 | 
			
		||||
    */
 | 
			
		||||
    template <typename ValueType>
 | 
			
		||||
    void transformPoints (ValueType& x1, ValueType& y1,
 | 
			
		||||
                          ValueType& x2, ValueType& y2) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto oldX1 = x1, oldX2 = x2;
 | 
			
		||||
        x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
 | 
			
		||||
        y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
 | 
			
		||||
        x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
 | 
			
		||||
        y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Transforms three 2D coordinates using this matrix.
 | 
			
		||||
        This is just a shortcut for calling transformPoint() on each of these pairs of
 | 
			
		||||
        coordinates in turn. (And putting all the calculations into one function hopefully
 | 
			
		||||
        also gives the compiler a bit more scope for pipelining it).
 | 
			
		||||
    */
 | 
			
		||||
    template <typename ValueType>
 | 
			
		||||
    void transformPoints (ValueType& x1, ValueType& y1,
 | 
			
		||||
                          ValueType& x2, ValueType& y2,
 | 
			
		||||
                          ValueType& x3, ValueType& y3) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto oldX1 = x1, oldX2 = x2, oldX3 = x3;
 | 
			
		||||
        x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
 | 
			
		||||
        y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
 | 
			
		||||
        x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
 | 
			
		||||
        y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
 | 
			
		||||
        x3 = static_cast<ValueType> (mat00 * oldX3 + mat01 * y3 + mat02);
 | 
			
		||||
        y3 = static_cast<ValueType> (mat10 * oldX3 + mat11 * y3 + mat12);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a new transform which is the same as this one followed by a translation. */
 | 
			
		||||
    AffineTransform translated (float deltaX,
 | 
			
		||||
                                float deltaY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is the same as this one followed by a translation. */
 | 
			
		||||
    template <typename PointType>
 | 
			
		||||
    AffineTransform translated (PointType delta) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return translated ((float) delta.x, (float) delta.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a translation. */
 | 
			
		||||
    static AffineTransform translation (float deltaX,
 | 
			
		||||
                                        float deltaY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a translation. */
 | 
			
		||||
    template <typename PointType>
 | 
			
		||||
    static AffineTransform translation (PointType delta) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return translation ((float) delta.x, (float) delta.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a copy of this transform with the specified translation matrix values. */
 | 
			
		||||
    AffineTransform withAbsoluteTranslation (float translationX,
 | 
			
		||||
                                             float translationY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a rotation.
 | 
			
		||||
 | 
			
		||||
        The rotation is specified by a number of radians to rotate clockwise, centred around
 | 
			
		||||
        the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform rotated (float angleInRadians) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a rotation about a given point.
 | 
			
		||||
 | 
			
		||||
        The rotation is specified by a number of radians to rotate clockwise, centred around
 | 
			
		||||
        the coordinates passed in.
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform rotated (float angleInRadians,
 | 
			
		||||
                             float pivotX,
 | 
			
		||||
                             float pivotY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a rotation about (0, 0). */
 | 
			
		||||
    static AffineTransform rotation (float angleInRadians) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a rotation about a given point. */
 | 
			
		||||
    static AffineTransform rotation (float angleInRadians,
 | 
			
		||||
                                     float pivotX,
 | 
			
		||||
                                     float pivotY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a re-scaling.
 | 
			
		||||
        The scaling is centred around the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform scaled (float factorX,
 | 
			
		||||
                            float factorY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a re-scaling.
 | 
			
		||||
        The scaling is centred around the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform scaled (float factor) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a re-scaling.
 | 
			
		||||
        The scaling is centred around the origin provided.
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform scaled (float factorX, float factorY,
 | 
			
		||||
                            float pivotX, float pivotY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a re-scale about the origin. */
 | 
			
		||||
    static AffineTransform scale (float factorX,
 | 
			
		||||
                                  float factorY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a re-scale about the origin. */
 | 
			
		||||
    static AffineTransform scale (float factor) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a new transform which is a re-scale centred around the point provided. */
 | 
			
		||||
    static AffineTransform scale (float factorX, float factorY,
 | 
			
		||||
                                  float pivotX, float pivotY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform which is the same as this one followed by a shear.
 | 
			
		||||
        The shear is centred around the origin (0, 0).
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform sheared (float shearX, float shearY) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a shear transform, centred around the origin (0, 0). */
 | 
			
		||||
    static AffineTransform shear (float shearX, float shearY) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a transform that will flip coordinates vertically within a window of the given height.
 | 
			
		||||
        This is handy for converting between upside-down coordinate systems such as OpenGL or CoreGraphics.
 | 
			
		||||
    */
 | 
			
		||||
    static AffineTransform verticalFlip (float height) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a matrix which is the inverse operation of this one.
 | 
			
		||||
 | 
			
		||||
        Some matrices don't have an inverse - in this case, the method will just return
 | 
			
		||||
        an identity transform.
 | 
			
		||||
    */
 | 
			
		||||
    AffineTransform inverted() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the transform that will map three known points onto three coordinates
 | 
			
		||||
        that are supplied.
 | 
			
		||||
 | 
			
		||||
        This returns the transform that will transform (0, 0) into (x00, y00),
 | 
			
		||||
        (1, 0) to (x10, y10), and (0, 1) to (x01, y01).
 | 
			
		||||
    */
 | 
			
		||||
    static AffineTransform fromTargetPoints (float x00, float y00,
 | 
			
		||||
                                             float x10, float y10,
 | 
			
		||||
                                             float x01, float y01) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the transform that will map three specified points onto three target points. */
 | 
			
		||||
    static AffineTransform fromTargetPoints (float sourceX1, float sourceY1, float targetX1, float targetY1,
 | 
			
		||||
                                             float sourceX2, float sourceY2, float targetX2, float targetY2,
 | 
			
		||||
                                             float sourceX3, float sourceY3, float targetX3, float targetY3) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the transform that will map three specified points onto three target points. */
 | 
			
		||||
    template <typename PointType>
 | 
			
		||||
    static AffineTransform fromTargetPoints (PointType source1, PointType target1,
 | 
			
		||||
                                             PointType source2, PointType target2,
 | 
			
		||||
                                             PointType source3, PointType target3) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return fromTargetPoints (source1.x, source1.y, target1.x, target1.y,
 | 
			
		||||
                                 source2.x, source2.y, target2.x, target2.y,
 | 
			
		||||
                                 source3.x, source3.y, target3.x, target3.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the result of concatenating another transformation after this one. */
 | 
			
		||||
    AffineTransform followedBy (const AffineTransform& other) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this transform has no effect on points. */
 | 
			
		||||
    bool isIdentity() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */
 | 
			
		||||
    bool isSingularity() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the transform only translates, and doesn't scale or rotate the
 | 
			
		||||
        points. */
 | 
			
		||||
    bool isOnlyTranslation() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** If this transform is only a translation, this returns the X offset.
 | 
			
		||||
        @see isOnlyTranslation
 | 
			
		||||
    */
 | 
			
		||||
    float getTranslationX() const noexcept                  { return mat02; }
 | 
			
		||||
 | 
			
		||||
    /** If this transform is only a translation, this returns the X offset.
 | 
			
		||||
        @see isOnlyTranslation
 | 
			
		||||
    */
 | 
			
		||||
    float getTranslationY() const noexcept                  { return mat12; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the determinant of the transform. */
 | 
			
		||||
    float getDeterminant() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #ifndef DOXYGEN
 | 
			
		||||
    /** This method has been deprecated.
 | 
			
		||||
 | 
			
		||||
        You can calculate the scale factor using:
 | 
			
		||||
        @code
 | 
			
		||||
        std::sqrt (std::abs (AffineTransform::getDeterminant()))
 | 
			
		||||
        @endcode
 | 
			
		||||
 | 
			
		||||
        This method produces incorrect values for transforms containing rotations.
 | 
			
		||||
 | 
			
		||||
        Returns the approximate scale factor by which lengths will be transformed.
 | 
			
		||||
        Obviously a length may be scaled by entirely different amounts depending on its
 | 
			
		||||
        direction, so this is only appropriate as a rough guide.
 | 
			
		||||
    */
 | 
			
		||||
    [[deprecated ("This method produces incorrect values for transforms containing rotations. "
 | 
			
		||||
                 "See the method docs for a code example on how to calculate the correct scale factor.")]]
 | 
			
		||||
    float getScaleFactor() const noexcept;
 | 
			
		||||
 | 
			
		||||
    [[deprecated ("If you need an identity transform, just use AffineTransform() or {}.")]]
 | 
			
		||||
    static const AffineTransform identity;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /* The transform matrix is:
 | 
			
		||||
 | 
			
		||||
        (mat00 mat01 mat02)
 | 
			
		||||
        (mat10 mat11 mat12)
 | 
			
		||||
        (  0     0     1  )
 | 
			
		||||
    */
 | 
			
		||||
    float mat00 { 1.0f }, mat01 { 0.0f }, mat02 { 0.0f };
 | 
			
		||||
    float mat10 { 0.0f }, mat11 { 1.0f }, mat12 { 0.0f };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,148 +1,167 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Specifies a set of gaps to be left around the sides of a rectangle.
 | 
			
		||||
 | 
			
		||||
    This is basically the size of the spaces at the top, bottom, left and right of
 | 
			
		||||
    a rectangle. It's used by various component classes to specify borders.
 | 
			
		||||
 | 
			
		||||
    @see Rectangle
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class BorderSize
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a null border.
 | 
			
		||||
        All sizes are left as 0.
 | 
			
		||||
    */
 | 
			
		||||
    BorderSize() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another border. */
 | 
			
		||||
    BorderSize (const BorderSize&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a border with the given gaps. */
 | 
			
		||||
    BorderSize (ValueType topGap, ValueType leftGap, ValueType bottomGap, ValueType rightGap) noexcept
 | 
			
		||||
        : top (topGap), left (leftGap), bottom (bottomGap), right (rightGap)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Creates a border with the given gap on all sides. */
 | 
			
		||||
    explicit BorderSize (ValueType allGaps) noexcept
 | 
			
		||||
        : top (allGaps), left (allGaps), bottom (allGaps), right (allGaps)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the gap that should be left at the top of the region. */
 | 
			
		||||
    ValueType getTop() const noexcept                   { return top; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the gap that should be left at the left of the region. */
 | 
			
		||||
    ValueType getLeft() const noexcept                  { return left; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the gap that should be left at the bottom of the region. */
 | 
			
		||||
    ValueType getBottom() const noexcept                { return bottom; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the gap that should be left at the right of the region. */
 | 
			
		||||
    ValueType getRight() const noexcept                 { return right; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the sum of the top and bottom gaps. */
 | 
			
		||||
    ValueType getTopAndBottom() const noexcept          { return top + bottom; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the sum of the left and right gaps. */
 | 
			
		||||
    ValueType getLeftAndRight() const noexcept          { return left + right; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this border has no thickness along any edge. */
 | 
			
		||||
    bool isEmpty() const noexcept                       { return left + right + top + bottom == ValueType(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the top gap. */
 | 
			
		||||
    void setTop (ValueType newTopGap) noexcept          { top = newTopGap; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the left gap. */
 | 
			
		||||
    void setLeft (ValueType newLeftGap) noexcept        { left = newLeftGap; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the bottom gap. */
 | 
			
		||||
    void setBottom (ValueType newBottomGap) noexcept    { bottom = newBottomGap; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the right gap. */
 | 
			
		||||
    void setRight (ValueType newRightGap) noexcept      { right = newRightGap; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a rectangle with these borders removed from it. */
 | 
			
		||||
    Rectangle<ValueType> subtractedFrom (const Rectangle<ValueType>& original) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Rectangle<ValueType> (original.getX() + left,
 | 
			
		||||
                                     original.getY() + top,
 | 
			
		||||
                                     original.getWidth() - (left + right),
 | 
			
		||||
                                     original.getHeight() - (top + bottom));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Removes this border from a given rectangle. */
 | 
			
		||||
    void subtractFrom (Rectangle<ValueType>& rectangle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        rectangle = subtractedFrom (rectangle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a rectangle with these borders added around it. */
 | 
			
		||||
    Rectangle<ValueType> addedTo (const Rectangle<ValueType>& original) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Rectangle<ValueType> (original.getX() - left,
 | 
			
		||||
                                     original.getY() - top,
 | 
			
		||||
                                     original.getWidth() + (left + right),
 | 
			
		||||
                                     original.getHeight() + (top + bottom));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Adds this border around a given rectangle. */
 | 
			
		||||
    void addTo (Rectangle<ValueType>& rectangle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        rectangle = addedTo (rectangle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool operator== (const BorderSize& other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return top == other.top && left == other.left && bottom == other.bottom && right == other.right;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator!= (const BorderSize& other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return ! operator== (other);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ValueType top{}, left{}, bottom{}, right{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Specifies a set of gaps to be left around the sides of a rectangle.
 | 
			
		||||
 | 
			
		||||
    This is basically the size of the spaces at the top, bottom, left and right of
 | 
			
		||||
    a rectangle. It's used by various component classes to specify borders.
 | 
			
		||||
 | 
			
		||||
    @see Rectangle
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class BorderSize
 | 
			
		||||
{
 | 
			
		||||
    auto tie() const { return std::tie (top, left, bottom, right); }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a null border.
 | 
			
		||||
        All sizes are left as 0.
 | 
			
		||||
    */
 | 
			
		||||
    BorderSize() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a border with the given gaps. */
 | 
			
		||||
    BorderSize (ValueType topGap, ValueType leftGap, ValueType bottomGap, ValueType rightGap) noexcept
 | 
			
		||||
        : top (topGap), left (leftGap), bottom (bottomGap), right (rightGap)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Creates a border with the given gap on all sides. */
 | 
			
		||||
    explicit BorderSize (ValueType allGaps) noexcept
 | 
			
		||||
        : top (allGaps), left (allGaps), bottom (allGaps), right (allGaps)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the gap that should be left at the top of the region. */
 | 
			
		||||
    ValueType getTop() const noexcept                   { return top; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the gap that should be left at the left of the region. */
 | 
			
		||||
    ValueType getLeft() const noexcept                  { return left; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the gap that should be left at the bottom of the region. */
 | 
			
		||||
    ValueType getBottom() const noexcept                { return bottom; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the gap that should be left at the right of the region. */
 | 
			
		||||
    ValueType getRight() const noexcept                 { return right; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the sum of the top and bottom gaps. */
 | 
			
		||||
    ValueType getTopAndBottom() const noexcept          { return top + bottom; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the sum of the left and right gaps. */
 | 
			
		||||
    ValueType getLeftAndRight() const noexcept          { return left + right; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this border has no thickness along any edge. */
 | 
			
		||||
    bool isEmpty() const noexcept                       { return left + right + top + bottom == ValueType(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the top gap. */
 | 
			
		||||
    void setTop (ValueType newTopGap) noexcept          { top = newTopGap; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the left gap. */
 | 
			
		||||
    void setLeft (ValueType newLeftGap) noexcept        { left = newLeftGap; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the bottom gap. */
 | 
			
		||||
    void setBottom (ValueType newBottomGap) noexcept    { bottom = newBottomGap; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the right gap. */
 | 
			
		||||
    void setRight (ValueType newRightGap) noexcept      { right = newRightGap; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a rectangle with these borders removed from it. */
 | 
			
		||||
    Rectangle<ValueType> subtractedFrom (const Rectangle<ValueType>& original) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { original.getX() + left,
 | 
			
		||||
                 original.getY() + top,
 | 
			
		||||
                 original.getWidth() - (left + right),
 | 
			
		||||
                 original.getHeight() - (top + bottom) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Removes this border from a given rectangle. */
 | 
			
		||||
    void subtractFrom (Rectangle<ValueType>& rectangle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        rectangle = subtractedFrom (rectangle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a rectangle with these borders added around it. */
 | 
			
		||||
    Rectangle<ValueType> addedTo (const Rectangle<ValueType>& original) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { original.getX() - left,
 | 
			
		||||
                 original.getY() - top,
 | 
			
		||||
                 original.getWidth() + (left + right),
 | 
			
		||||
                 original.getHeight() + (top + bottom) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Adds this border around a given rectangle. */
 | 
			
		||||
    void addTo (Rectangle<ValueType>& rectangle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        rectangle = addedTo (rectangle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Removes this border from another border. */
 | 
			
		||||
    BorderSize<ValueType> subtractedFrom (const BorderSize<ValueType>& other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { other.top    - top,
 | 
			
		||||
                 other.left   - left,
 | 
			
		||||
                 other.bottom - bottom,
 | 
			
		||||
                 other.right  - right };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Adds this border to another border. */
 | 
			
		||||
    BorderSize<ValueType> addedTo (const BorderSize<ValueType>& other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { other.top    + top,
 | 
			
		||||
                 other.left   + left,
 | 
			
		||||
                 other.bottom + bottom,
 | 
			
		||||
                 other.right  + right };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies each member of the border by a scalar. */
 | 
			
		||||
    template <typename ScalarType>
 | 
			
		||||
    BorderSize<ValueType> multipliedBy (ScalarType scalar) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { static_cast<ValueType> (scalar * top),
 | 
			
		||||
                 static_cast<ValueType> (scalar * left),
 | 
			
		||||
                 static_cast<ValueType> (scalar * bottom),
 | 
			
		||||
                 static_cast<ValueType> (scalar * right) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool operator== (const BorderSize& other) const noexcept { return tie() == other.tie(); }
 | 
			
		||||
    bool operator!= (const BorderSize& other) const noexcept { return tie() != other.tie(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ValueType top{}, left{}, bottom{}, right{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,226 +1,226 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A table of horizontal scan-line segments - used for rasterising Paths.
 | 
			
		||||
 | 
			
		||||
    @see Path, Graphics
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  EdgeTable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an edge table containing a path.
 | 
			
		||||
 | 
			
		||||
        A table is created with a fixed vertical range, and only sections of the path
 | 
			
		||||
        which lie within this range will be added to the table.
 | 
			
		||||
 | 
			
		||||
        @param clipLimits               only the region of the path that lies within this area will be added
 | 
			
		||||
        @param pathToAdd                the path to add to the table
 | 
			
		||||
        @param transform                a transform to apply to the path being added
 | 
			
		||||
    */
 | 
			
		||||
    EdgeTable (Rectangle<int> clipLimits,
 | 
			
		||||
               const Path& pathToAdd,
 | 
			
		||||
               const AffineTransform& transform);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle. */
 | 
			
		||||
    explicit EdgeTable (Rectangle<int> rectangleToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle. */
 | 
			
		||||
    explicit EdgeTable (Rectangle<float> rectangleToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle list. */
 | 
			
		||||
    explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle list. */
 | 
			
		||||
    explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another edge table. */
 | 
			
		||||
    EdgeTable (const EdgeTable&);
 | 
			
		||||
 | 
			
		||||
    /** Copies from another edge table. */
 | 
			
		||||
    EdgeTable& operator= (const EdgeTable&);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~EdgeTable();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void clipToRectangle (Rectangle<int> r);
 | 
			
		||||
    void excludeRectangle (Rectangle<int> r);
 | 
			
		||||
    void clipToEdgeTable (const EdgeTable&);
 | 
			
		||||
    void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
 | 
			
		||||
    bool isEmpty() noexcept;
 | 
			
		||||
    const Rectangle<int>& getMaximumBounds() const noexcept      { return bounds; }
 | 
			
		||||
    void translate (float dx, int dy) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Scales all the alpha-levels in the table by the given multiplier. */
 | 
			
		||||
    void multiplyLevels (float factor);
 | 
			
		||||
 | 
			
		||||
    /** Reduces the amount of space the table has allocated.
 | 
			
		||||
 | 
			
		||||
        This will shrink the table down to use as little memory as possible - useful for
 | 
			
		||||
        read-only tables that get stored and re-used for rendering.
 | 
			
		||||
    */
 | 
			
		||||
    void optimiseTable();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Iterates the lines in the table, for rendering.
 | 
			
		||||
 | 
			
		||||
        This function will iterate each line in the table, and call a user-defined class
 | 
			
		||||
        to render each pixel or continuous line of pixels that the table contains.
 | 
			
		||||
 | 
			
		||||
        @param iterationCallback    this templated class must contain the following methods:
 | 
			
		||||
                                        @code
 | 
			
		||||
                                        inline void setEdgeTableYPos (int y);
 | 
			
		||||
                                        inline void handleEdgeTablePixel (int x, int alphaLevel) const;
 | 
			
		||||
                                        inline void handleEdgeTablePixelFull (int x) const;
 | 
			
		||||
                                        inline void handleEdgeTableLine (int x, int width, int alphaLevel) const;
 | 
			
		||||
                                        inline void handleEdgeTableLineFull (int x, int width) const;
 | 
			
		||||
                                        @endcode
 | 
			
		||||
                                        (these don't necessarily have to be 'const', but it might help it go faster)
 | 
			
		||||
    */
 | 
			
		||||
    template <class EdgeTableIterationCallback>
 | 
			
		||||
    void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        const int* lineStart = table;
 | 
			
		||||
 | 
			
		||||
        for (int y = 0; y < bounds.getHeight(); ++y)
 | 
			
		||||
        {
 | 
			
		||||
            const int* line = lineStart;
 | 
			
		||||
            lineStart += lineStrideElements;
 | 
			
		||||
            int numPoints = line[0];
 | 
			
		||||
 | 
			
		||||
            if (--numPoints > 0)
 | 
			
		||||
            {
 | 
			
		||||
                int x = *++line;
 | 
			
		||||
                jassert ((x / scale) >= bounds.getX() && (x / scale) < bounds.getRight());
 | 
			
		||||
                int levelAccumulator = 0;
 | 
			
		||||
 | 
			
		||||
                iterationCallback.setEdgeTableYPos (bounds.getY() + y);
 | 
			
		||||
 | 
			
		||||
                while (--numPoints >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                    const int level = *++line;
 | 
			
		||||
                    jassert (isPositiveAndBelow (level, scale));
 | 
			
		||||
                    const int endX = *++line;
 | 
			
		||||
                    jassert (endX >= x);
 | 
			
		||||
                    const int endOfRun = (endX / scale);
 | 
			
		||||
 | 
			
		||||
                    if (endOfRun == (x / scale))
 | 
			
		||||
                    {
 | 
			
		||||
                        // small segment within the same pixel, so just save it for the next
 | 
			
		||||
                        // time round..
 | 
			
		||||
                        levelAccumulator += (endX - x) * level;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // plot the fist pixel of this segment, including any accumulated
 | 
			
		||||
                        // levels from smaller segments that haven't been drawn yet
 | 
			
		||||
                        levelAccumulator += (0x100 - (x & 0xff)) * level;
 | 
			
		||||
                        levelAccumulator /= scale;
 | 
			
		||||
                        x /= scale;
 | 
			
		||||
 | 
			
		||||
                        if (levelAccumulator > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (levelAccumulator >= 255)
 | 
			
		||||
                                iterationCallback.handleEdgeTablePixelFull (x);
 | 
			
		||||
                            else
 | 
			
		||||
                                iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // if there's a run of similar pixels, do it all in one go..
 | 
			
		||||
                        if (level > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            jassert (endOfRun <= bounds.getRight());
 | 
			
		||||
                            const int numPix = endOfRun - ++x;
 | 
			
		||||
 | 
			
		||||
                            if (numPix > 0)
 | 
			
		||||
                                iterationCallback.handleEdgeTableLine (x, numPix, level);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // save the bit at the end to be drawn next time round the loop.
 | 
			
		||||
                        levelAccumulator = (endX & 0xff) * level;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    x = endX;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                levelAccumulator /= scale;
 | 
			
		||||
 | 
			
		||||
                if (levelAccumulator > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    x /= scale;
 | 
			
		||||
                    jassert (x >= bounds.getX() && x < bounds.getRight());
 | 
			
		||||
 | 
			
		||||
                    if (levelAccumulator >= 255)
 | 
			
		||||
                        iterationCallback.handleEdgeTablePixelFull (x);
 | 
			
		||||
                    else
 | 
			
		||||
                        iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    static constexpr auto defaultEdgesPerLine = 32;
 | 
			
		||||
    static constexpr auto scale = 256;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
 | 
			
		||||
    struct LineItem
 | 
			
		||||
    {
 | 
			
		||||
        int x, level;
 | 
			
		||||
 | 
			
		||||
        bool operator< (const LineItem& other) const noexcept   { return x < other.x; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    HeapBlock<int> table;
 | 
			
		||||
    Rectangle<int> bounds;
 | 
			
		||||
    int maxEdgesPerLine, lineStrideElements;
 | 
			
		||||
    bool needToCheckEmptiness = true;
 | 
			
		||||
 | 
			
		||||
    void allocate();
 | 
			
		||||
    void clearLineSizes() noexcept;
 | 
			
		||||
    void addEdgePoint (int x, int y, int winding);
 | 
			
		||||
    void addEdgePointPair (int x1, int x2, int y, int winding);
 | 
			
		||||
    void remapTableForNumEdges (int newNumEdgesPerLine);
 | 
			
		||||
    void remapWithExtraSpace (int numPointsNeeded);
 | 
			
		||||
    void intersectWithEdgeTableLine (int y, const int* otherLine);
 | 
			
		||||
    void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
 | 
			
		||||
    void sanitiseLevels (bool useNonZeroWinding) noexcept;
 | 
			
		||||
    static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (EdgeTable)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A table of horizontal scan-line segments - used for rasterising Paths.
 | 
			
		||||
 | 
			
		||||
    @see Path, Graphics
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  EdgeTable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an edge table containing a path.
 | 
			
		||||
 | 
			
		||||
        A table is created with a fixed vertical range, and only sections of the path
 | 
			
		||||
        which lie within this range will be added to the table.
 | 
			
		||||
 | 
			
		||||
        @param clipLimits               only the region of the path that lies within this area will be added
 | 
			
		||||
        @param pathToAdd                the path to add to the table
 | 
			
		||||
        @param transform                a transform to apply to the path being added
 | 
			
		||||
    */
 | 
			
		||||
    EdgeTable (Rectangle<int> clipLimits,
 | 
			
		||||
               const Path& pathToAdd,
 | 
			
		||||
               const AffineTransform& transform);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle. */
 | 
			
		||||
    explicit EdgeTable (Rectangle<int> rectangleToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle. */
 | 
			
		||||
    explicit EdgeTable (Rectangle<float> rectangleToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle list. */
 | 
			
		||||
    explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates an edge table containing a rectangle list. */
 | 
			
		||||
    explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another edge table. */
 | 
			
		||||
    EdgeTable (const EdgeTable&);
 | 
			
		||||
 | 
			
		||||
    /** Copies from another edge table. */
 | 
			
		||||
    EdgeTable& operator= (const EdgeTable&);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~EdgeTable();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void clipToRectangle (Rectangle<int> r);
 | 
			
		||||
    void excludeRectangle (Rectangle<int> r);
 | 
			
		||||
    void clipToEdgeTable (const EdgeTable&);
 | 
			
		||||
    void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
 | 
			
		||||
    bool isEmpty() noexcept;
 | 
			
		||||
    const Rectangle<int>& getMaximumBounds() const noexcept      { return bounds; }
 | 
			
		||||
    void translate (float dx, int dy) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Scales all the alpha-levels in the table by the given multiplier. */
 | 
			
		||||
    void multiplyLevels (float factor);
 | 
			
		||||
 | 
			
		||||
    /** Reduces the amount of space the table has allocated.
 | 
			
		||||
 | 
			
		||||
        This will shrink the table down to use as little memory as possible - useful for
 | 
			
		||||
        read-only tables that get stored and re-used for rendering.
 | 
			
		||||
    */
 | 
			
		||||
    void optimiseTable();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Iterates the lines in the table, for rendering.
 | 
			
		||||
 | 
			
		||||
        This function will iterate each line in the table, and call a user-defined class
 | 
			
		||||
        to render each pixel or continuous line of pixels that the table contains.
 | 
			
		||||
 | 
			
		||||
        @param iterationCallback    this templated class must contain the following methods:
 | 
			
		||||
                                        @code
 | 
			
		||||
                                        inline void setEdgeTableYPos (int y);
 | 
			
		||||
                                        inline void handleEdgeTablePixel (int x, int alphaLevel) const;
 | 
			
		||||
                                        inline void handleEdgeTablePixelFull (int x) const;
 | 
			
		||||
                                        inline void handleEdgeTableLine (int x, int width, int alphaLevel) const;
 | 
			
		||||
                                        inline void handleEdgeTableLineFull (int x, int width) const;
 | 
			
		||||
                                        @endcode
 | 
			
		||||
                                        (these don't necessarily have to be 'const', but it might help it go faster)
 | 
			
		||||
    */
 | 
			
		||||
    template <class EdgeTableIterationCallback>
 | 
			
		||||
    void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        const int* lineStart = table;
 | 
			
		||||
 | 
			
		||||
        for (int y = 0; y < bounds.getHeight(); ++y)
 | 
			
		||||
        {
 | 
			
		||||
            const int* line = lineStart;
 | 
			
		||||
            lineStart += lineStrideElements;
 | 
			
		||||
            int numPoints = line[0];
 | 
			
		||||
 | 
			
		||||
            if (--numPoints > 0)
 | 
			
		||||
            {
 | 
			
		||||
                int x = *++line;
 | 
			
		||||
                jassert ((x / scale) >= bounds.getX() && (x / scale) < bounds.getRight());
 | 
			
		||||
                int levelAccumulator = 0;
 | 
			
		||||
 | 
			
		||||
                iterationCallback.setEdgeTableYPos (bounds.getY() + y);
 | 
			
		||||
 | 
			
		||||
                while (--numPoints >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                    const int level = *++line;
 | 
			
		||||
                    jassert (isPositiveAndBelow (level, scale));
 | 
			
		||||
                    const int endX = *++line;
 | 
			
		||||
                    jassert (endX >= x);
 | 
			
		||||
                    const int endOfRun = (endX / scale);
 | 
			
		||||
 | 
			
		||||
                    if (endOfRun == (x / scale))
 | 
			
		||||
                    {
 | 
			
		||||
                        // small segment within the same pixel, so just save it for the next
 | 
			
		||||
                        // time round..
 | 
			
		||||
                        levelAccumulator += (endX - x) * level;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // plot the fist pixel of this segment, including any accumulated
 | 
			
		||||
                        // levels from smaller segments that haven't been drawn yet
 | 
			
		||||
                        levelAccumulator += (0x100 - (x & 0xff)) * level;
 | 
			
		||||
                        levelAccumulator /= scale;
 | 
			
		||||
                        x /= scale;
 | 
			
		||||
 | 
			
		||||
                        if (levelAccumulator > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (levelAccumulator >= 255)
 | 
			
		||||
                                iterationCallback.handleEdgeTablePixelFull (x);
 | 
			
		||||
                            else
 | 
			
		||||
                                iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // if there's a run of similar pixels, do it all in one go..
 | 
			
		||||
                        if (level > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            jassert (endOfRun <= bounds.getRight());
 | 
			
		||||
                            const int numPix = endOfRun - ++x;
 | 
			
		||||
 | 
			
		||||
                            if (numPix > 0)
 | 
			
		||||
                                iterationCallback.handleEdgeTableLine (x, numPix, level);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // save the bit at the end to be drawn next time round the loop.
 | 
			
		||||
                        levelAccumulator = (endX & 0xff) * level;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    x = endX;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                levelAccumulator /= scale;
 | 
			
		||||
 | 
			
		||||
                if (levelAccumulator > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    x /= scale;
 | 
			
		||||
                    jassert (x >= bounds.getX() && x < bounds.getRight());
 | 
			
		||||
 | 
			
		||||
                    if (levelAccumulator >= 255)
 | 
			
		||||
                        iterationCallback.handleEdgeTablePixelFull (x);
 | 
			
		||||
                    else
 | 
			
		||||
                        iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    static constexpr auto defaultEdgesPerLine = 32;
 | 
			
		||||
    static constexpr auto scale = 256;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
 | 
			
		||||
    struct LineItem
 | 
			
		||||
    {
 | 
			
		||||
        int x, level;
 | 
			
		||||
 | 
			
		||||
        bool operator< (const LineItem& other) const noexcept   { return x < other.x; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    HeapBlock<int> table;
 | 
			
		||||
    Rectangle<int> bounds;
 | 
			
		||||
    int maxEdgesPerLine, lineStrideElements;
 | 
			
		||||
    bool needToCheckEmptiness = true;
 | 
			
		||||
 | 
			
		||||
    void allocate();
 | 
			
		||||
    void clearLineSizes() noexcept;
 | 
			
		||||
    void addEdgePoint (int x, int y, int winding);
 | 
			
		||||
    void addEdgePointPair (int x1, int x2, int y, int winding);
 | 
			
		||||
    void remapTableForNumEdges (int newNumEdgesPerLine);
 | 
			
		||||
    void remapWithExtraSpace (int numPointsNeeded);
 | 
			
		||||
    void intersectWithEdgeTableLine (int y, const int* otherLine);
 | 
			
		||||
    void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
 | 
			
		||||
    void sanitiseLevels (bool useNonZeroWinding) noexcept;
 | 
			
		||||
    static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (EdgeTable)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										863
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Line.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										863
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Line.h
									
									
									
									
										vendored
									
									
								
							@@ -1,421 +1,442 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Represents a line.
 | 
			
		||||
 | 
			
		||||
    This class contains a bunch of useful methods for various geometric
 | 
			
		||||
    tasks.
 | 
			
		||||
 | 
			
		||||
    The ValueType template parameter should be a primitive type - float or double
 | 
			
		||||
    are what it's designed for. Integer types will work in a basic way, but some methods
 | 
			
		||||
    that perform mathematical operations may not compile, or they may not produce
 | 
			
		||||
    sensible results.
 | 
			
		||||
 | 
			
		||||
    @see Point, Rectangle, Path, Graphics::drawLine
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class Line
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a line, using (0, 0) as its start and end points. */
 | 
			
		||||
    Line() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another line. */
 | 
			
		||||
    Line (const Line&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a line based on the coordinates of its start and end points. */
 | 
			
		||||
    Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) noexcept
 | 
			
		||||
        : start (startX, startY), end (endX, endY)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Creates a line from its start and end points. */
 | 
			
		||||
    Line (Point<ValueType> startPoint, Point<ValueType> endPoint) noexcept
 | 
			
		||||
        : start (startPoint), end (endPoint)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Copies a line from another one. */
 | 
			
		||||
    Line& operator= (const Line&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~Line() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the x coordinate of the line's start point. */
 | 
			
		||||
    inline ValueType getStartX() const noexcept                             { return start.x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the y coordinate of the line's start point. */
 | 
			
		||||
    inline ValueType getStartY() const noexcept                             { return start.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the x coordinate of the line's end point. */
 | 
			
		||||
    inline ValueType getEndX() const noexcept                               { return end.x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the y coordinate of the line's end point. */
 | 
			
		||||
    inline ValueType getEndY() const noexcept                               { return end.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the line's start point. */
 | 
			
		||||
    inline Point<ValueType> getStart() const noexcept                       { return start; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the line's end point. */
 | 
			
		||||
    inline Point<ValueType> getEnd() const noexcept                         { return end; }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's start point */
 | 
			
		||||
    void setStart (ValueType newStartX, ValueType newStartY) noexcept       { start.setXY (newStartX, newStartY); }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's end point */
 | 
			
		||||
    void setEnd (ValueType newEndX, ValueType newEndY) noexcept             { end.setXY (newEndX, newEndY); }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's start point */
 | 
			
		||||
    void setStart (const Point<ValueType> newStart) noexcept                { start = newStart; }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's end point */
 | 
			
		||||
    void setEnd (const Point<ValueType> newEnd) noexcept                    { end = newEnd; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a line that is the same as this one, but with the start and end reversed, */
 | 
			
		||||
    Line reversed() const noexcept                                          { return { end, start }; }
 | 
			
		||||
 | 
			
		||||
    /** Applies an affine transform to the line's start and end points. */
 | 
			
		||||
    void applyTransform (const AffineTransform& transform) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        start.applyTransform (transform);
 | 
			
		||||
        end.applyTransform (transform);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the length of the line. */
 | 
			
		||||
    ValueType getLength() const noexcept                                    { return start.getDistanceFrom (end); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the length of the line. */
 | 
			
		||||
    ValueType getLengthSquared() const noexcept                             { return start.getDistanceSquaredFrom (end); }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the line's start and end x coordinates are the same. */
 | 
			
		||||
    bool isVertical() const noexcept                                        { return start.x == end.x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the line's start and end y coordinates are the same. */
 | 
			
		||||
    bool isHorizontal() const noexcept                                      { return start.y == end.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the line's angle.
 | 
			
		||||
 | 
			
		||||
        This value is the number of radians clockwise from the 12 o'clock direction,
 | 
			
		||||
        where the line's start point is considered to be at the centre.
 | 
			
		||||
    */
 | 
			
		||||
    typename Point<ValueType>::FloatType getAngle() const noexcept          { return start.getAngleToPoint (end); }
 | 
			
		||||
 | 
			
		||||
    /** Creates a line from a start point, length and angle.
 | 
			
		||||
 | 
			
		||||
        This angle is the number of radians clockwise from the 12 o'clock direction,
 | 
			
		||||
        where the line's start point is considered to be at the centre.
 | 
			
		||||
    */
 | 
			
		||||
    static Line fromStartAndAngle (Point<ValueType> startPoint, ValueType length, ValueType angle) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { startPoint, startPoint.getPointOnCircumference (length, angle) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Casts this line to float coordinates. */
 | 
			
		||||
    Line<float> toFloat() const noexcept                                    { return { start.toFloat(), end.toFloat() }; }
 | 
			
		||||
 | 
			
		||||
    /** Casts this line to double coordinates. */
 | 
			
		||||
    Line<double> toDouble() const noexcept                                  { return { start.toDouble(), end.toDouble() }; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Compares two lines. */
 | 
			
		||||
    bool operator== (Line other) const noexcept                             { return start == other.start && end == other.end; }
 | 
			
		||||
 | 
			
		||||
    /** Compares two lines. */
 | 
			
		||||
    bool operator!= (Line other) const noexcept                             { return start != other.start || end != other.end; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Finds the intersection between two lines.
 | 
			
		||||
 | 
			
		||||
        @param line     the line to intersect with
 | 
			
		||||
        @returns        the point at which the lines intersect, even if this lies beyond the end of the lines
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getIntersection (Line line) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        Point<ValueType> p;
 | 
			
		||||
        findIntersection (start, end, line.start, line.end, p);
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Finds the intersection between two lines.
 | 
			
		||||
 | 
			
		||||
        @param line             the other line
 | 
			
		||||
        @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.
 | 
			
		||||
        @returns    true if the line segments intersect; false if they don't. Even if they
 | 
			
		||||
                    don't intersect, the intersection coordinates returned will still
 | 
			
		||||
                    be valid
 | 
			
		||||
    */
 | 
			
		||||
    bool intersects (Line line, Point<ValueType>& intersection) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return findIntersection (start, end, line.start, line.end, intersection);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this line intersects another. */
 | 
			
		||||
    bool intersects (Line other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        Point<ValueType> ignored;
 | 
			
		||||
        return findIntersection (start, end, other.start, other.end, ignored);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the location of the point which is a given distance along this line.
 | 
			
		||||
 | 
			
		||||
        @param distanceFromStart    the distance to move along the line from its
 | 
			
		||||
                                    start point. This value can be negative or longer
 | 
			
		||||
                                    than the line itself
 | 
			
		||||
        @see getPointAlongLineProportionally
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getPointAlongLine (ValueType distanceFromStart) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return start + (end - start) * (distanceFromStart / getLength());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point which is a certain distance along and to the side of this line.
 | 
			
		||||
 | 
			
		||||
        This effectively moves a given distance along the line, then another distance
 | 
			
		||||
        perpendicularly to this, and returns the resulting position.
 | 
			
		||||
 | 
			
		||||
        @param distanceFromStart    the distance to move along the line from its
 | 
			
		||||
                                    start point. This value can be negative or longer
 | 
			
		||||
                                    than the line itself
 | 
			
		||||
        @param perpendicularDistance    how far to move sideways from the line. If you're
 | 
			
		||||
                                    looking along the line from its start towards its
 | 
			
		||||
                                    end, then a positive value here will move to the
 | 
			
		||||
                                    right, negative value move to the left.
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getPointAlongLine (ValueType distanceFromStart,
 | 
			
		||||
                                        ValueType perpendicularDistance) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto delta = end - start;
 | 
			
		||||
        auto length = juce_hypot ((double) delta.x,
 | 
			
		||||
                                  (double) delta.y);
 | 
			
		||||
        if (length <= 0)
 | 
			
		||||
            return start;
 | 
			
		||||
 | 
			
		||||
        return { start.x + static_cast<ValueType> ((delta.x * distanceFromStart - delta.y * perpendicularDistance) / length),
 | 
			
		||||
                 start.y + static_cast<ValueType> ((delta.y * distanceFromStart + delta.x * perpendicularDistance) / length) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the location of the point which is a given distance along this line
 | 
			
		||||
        proportional to the line's length.
 | 
			
		||||
 | 
			
		||||
        @param proportionOfLength   the distance to move along the line from its
 | 
			
		||||
                                    start point, in multiples of the line's length.
 | 
			
		||||
                                    So a value of 0.0 will return the line's start point
 | 
			
		||||
                                    and a value of 1.0 will return its end point. (This value
 | 
			
		||||
                                    can be negative or greater than 1.0).
 | 
			
		||||
        @see getPointAlongLine
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getPointAlongLineProportionally (typename Point<ValueType>::FloatType proportionOfLength) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return start + (end - start) * proportionOfLength;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the smallest distance between this line segment and a given point.
 | 
			
		||||
 | 
			
		||||
        So if the point is close to the line, this will return the perpendicular
 | 
			
		||||
        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.
 | 
			
		||||
 | 
			
		||||
        pointOnLine receives the position of the point that is found.
 | 
			
		||||
 | 
			
		||||
        @returns the point's distance from the line
 | 
			
		||||
        @see getPositionAlongLineOfNearestPoint
 | 
			
		||||
    */
 | 
			
		||||
    ValueType getDistanceFromPoint (Point<ValueType> targetPoint,
 | 
			
		||||
                                    Point<ValueType>& pointOnLine) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto delta = end - start;
 | 
			
		||||
        auto length = delta.x * delta.x + delta.y * delta.y;
 | 
			
		||||
 | 
			
		||||
        if (length > 0)
 | 
			
		||||
        {
 | 
			
		||||
            auto prop = ((targetPoint.x - start.x) * delta.x
 | 
			
		||||
                       + (targetPoint.y - start.y) * delta.y) / (double) length;
 | 
			
		||||
 | 
			
		||||
            if (prop >= 0 && prop <= 1.0)
 | 
			
		||||
            {
 | 
			
		||||
                pointOnLine = start + delta * prop;
 | 
			
		||||
                return targetPoint.getDistanceFrom (pointOnLine);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto fromStart = targetPoint.getDistanceFrom (start);
 | 
			
		||||
        auto fromEnd   = targetPoint.getDistanceFrom (end);
 | 
			
		||||
 | 
			
		||||
        if (fromStart < fromEnd)
 | 
			
		||||
        {
 | 
			
		||||
            pointOnLine = start;
 | 
			
		||||
            return fromStart;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pointOnLine = end;
 | 
			
		||||
        return fromEnd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Finds the point on this line which is nearest to a given point, and
 | 
			
		||||
        returns its position as a proportional position along the line.
 | 
			
		||||
 | 
			
		||||
        @returns    a value 0 to 1.0 which is the distance along this line from the
 | 
			
		||||
                    line's start to the point which is nearest to the point passed-in. To
 | 
			
		||||
                    turn this number into a position, use getPointAlongLineProportionally().
 | 
			
		||||
        @see getDistanceFromPoint, getPointAlongLineProportionally
 | 
			
		||||
    */
 | 
			
		||||
    ValueType findNearestProportionalPositionTo (Point<ValueType> point) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto delta = end - start;
 | 
			
		||||
        auto length = delta.x * delta.x + delta.y * delta.y;
 | 
			
		||||
 | 
			
		||||
        return length <= 0 ? 0
 | 
			
		||||
                           : jlimit (ValueType(), static_cast<ValueType> (1),
 | 
			
		||||
                                     static_cast<ValueType> ((((point.x - start.x) * delta.x
 | 
			
		||||
                                                             + (point.y - start.y) * delta.y) / length)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Finds the point on this line which is nearest to a given point.
 | 
			
		||||
        @see getDistanceFromPoint, findNearestProportionalPositionTo
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> findNearestPointTo (Point<ValueType> point) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return getPointAlongLineProportionally (findNearestProportionalPositionTo (point));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the given point lies above this line.
 | 
			
		||||
 | 
			
		||||
        The return value is true if the point's y coordinate is less than the y
 | 
			
		||||
        coordinate of this line at the given x (assuming the line extends infinitely
 | 
			
		||||
        in both directions).
 | 
			
		||||
    */
 | 
			
		||||
    bool isPointAbove (Point<ValueType> point) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return start.x != end.x
 | 
			
		||||
                && point.y < ((end.y - start.y) * (point.x - start.x)) / (end.x - start.x) + start.y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a shortened copy of this line.
 | 
			
		||||
 | 
			
		||||
        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.
 | 
			
		||||
    */
 | 
			
		||||
    Line withShortenedStart (ValueType distanceToShortenBy) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { 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.
 | 
			
		||||
    */
 | 
			
		||||
    Line withShortenedEnd (ValueType distanceToShortenBy) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto length = getLength();
 | 
			
		||||
        return { start, getPointAlongLine (length - jmin (distanceToShortenBy, length)) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Point<ValueType> start, end;
 | 
			
		||||
 | 
			
		||||
    static bool isZeroToOne (ValueType v) noexcept      { return v >= 0 && v <= static_cast<ValueType> (1); }
 | 
			
		||||
 | 
			
		||||
    static bool findIntersection (const Point<ValueType> p1, const Point<ValueType> p2,
 | 
			
		||||
                                  const Point<ValueType> p3, const Point<ValueType> p4,
 | 
			
		||||
                                  Point<ValueType>& intersection) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (p2 == p3)
 | 
			
		||||
        {
 | 
			
		||||
            intersection = p2;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto d1 = p2 - p1;
 | 
			
		||||
        auto d2 = p4 - p3;
 | 
			
		||||
        auto divisor = d1.x * d2.y - d2.x * d1.y;
 | 
			
		||||
 | 
			
		||||
        if (divisor == 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (! (d1.isOrigin() || d2.isOrigin()))
 | 
			
		||||
            {
 | 
			
		||||
                if (d1.y == 0 && d2.y != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p1.y - p3.y) / d2.y;
 | 
			
		||||
                    intersection = p1.withX (p3.x + along * d2.x);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (d2.y == 0 && d1.y != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p3.y - p1.y) / d1.y;
 | 
			
		||||
                    intersection = p3.withX (p1.x + along * d1.x);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (d1.x == 0 && d2.x != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p1.x - p3.x) / d2.x;
 | 
			
		||||
                    intersection = p1.withY (p3.y + along * d2.y);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (d2.x == 0 && d1.x != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p3.x - p1.x) / d1.x;
 | 
			
		||||
                    intersection = p3.withY (p1.y + along * d1.y);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            intersection = (p2 + p3) / static_cast<ValueType> (2);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto along1 = ((p1.y - p3.y) * d2.x - (p1.x - p3.x) * d2.y) / divisor;
 | 
			
		||||
        intersection = p1 + d1 * along1;
 | 
			
		||||
 | 
			
		||||
        if (! isZeroToOne (along1))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        auto along2 = ((p1.y - p3.y) * d1.x - (p1.x - p3.x) * d1.y) / divisor;
 | 
			
		||||
        return isZeroToOne (along2);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Represents a line.
 | 
			
		||||
 | 
			
		||||
    This class contains a bunch of useful methods for various geometric
 | 
			
		||||
    tasks.
 | 
			
		||||
 | 
			
		||||
    The ValueType template parameter should be a primitive type - float or double
 | 
			
		||||
    are what it's designed for. Integer types will work in a basic way, but some methods
 | 
			
		||||
    that perform mathematical operations may not compile, or they may not produce
 | 
			
		||||
    sensible results.
 | 
			
		||||
 | 
			
		||||
    @see Point, Rectangle, Path, Graphics::drawLine
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class Line
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a line, using (0, 0) as its start and end points. */
 | 
			
		||||
    Line() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another line. */
 | 
			
		||||
    Line (const Line&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a line based on the coordinates of its start and end points. */
 | 
			
		||||
    Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) noexcept
 | 
			
		||||
        : start (startX, startY), end (endX, endY)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Creates a line from its start and end points. */
 | 
			
		||||
    Line (Point<ValueType> startPoint, Point<ValueType> endPoint) noexcept
 | 
			
		||||
        : start (startPoint), end (endPoint)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Copies a line from another one. */
 | 
			
		||||
    Line& operator= (const Line&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~Line() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the x coordinate of the line's start point. */
 | 
			
		||||
    inline ValueType getStartX() const noexcept                             { return start.x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the y coordinate of the line's start point. */
 | 
			
		||||
    inline ValueType getStartY() const noexcept                             { return start.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the x coordinate of the line's end point. */
 | 
			
		||||
    inline ValueType getEndX() const noexcept                               { return end.x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the y coordinate of the line's end point. */
 | 
			
		||||
    inline ValueType getEndY() const noexcept                               { return end.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the line's start point. */
 | 
			
		||||
    inline Point<ValueType> getStart() const noexcept                       { return start; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the line's end point. */
 | 
			
		||||
    inline Point<ValueType> getEnd() const noexcept                         { return end; }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's start point */
 | 
			
		||||
    void setStart (ValueType newStartX, ValueType newStartY) noexcept       { start.setXY (newStartX, newStartY); }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's end point */
 | 
			
		||||
    void setEnd (ValueType newEndX, ValueType newEndY) noexcept             { end.setXY (newEndX, newEndY); }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's start point */
 | 
			
		||||
    void setStart (const Point<ValueType> newStart) noexcept                { start = newStart; }
 | 
			
		||||
 | 
			
		||||
    /** Changes this line's end point */
 | 
			
		||||
    void setEnd (const Point<ValueType> newEnd) noexcept                    { end = newEnd; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a line that is the same as this one, but with the start and end reversed, */
 | 
			
		||||
    Line reversed() const noexcept                                          { return { end, start }; }
 | 
			
		||||
 | 
			
		||||
    /** Applies an affine transform to the line's start and end points. */
 | 
			
		||||
    void applyTransform (const AffineTransform& transform) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        start.applyTransform (transform);
 | 
			
		||||
        end.applyTransform (transform);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the length of the line. */
 | 
			
		||||
    ValueType getLength() const noexcept                                    { return start.getDistanceFrom (end); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the length of the line. */
 | 
			
		||||
    ValueType getLengthSquared() const noexcept                             { return start.getDistanceSquaredFrom (end); }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the line's start and end x coordinates are the same. */
 | 
			
		||||
    bool isVertical() const noexcept                                        { return start.x == end.x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the line's start and end y coordinates are the same. */
 | 
			
		||||
    bool isHorizontal() const noexcept                                      { return start.y == end.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the line's angle.
 | 
			
		||||
 | 
			
		||||
        This value is the number of radians clockwise from the 12 o'clock direction,
 | 
			
		||||
        where the line's start point is considered to be at the centre.
 | 
			
		||||
    */
 | 
			
		||||
    typename Point<ValueType>::FloatType getAngle() const noexcept          { return start.getAngleToPoint (end); }
 | 
			
		||||
 | 
			
		||||
    /** Creates a line from a start point, length and angle.
 | 
			
		||||
 | 
			
		||||
        This angle is the number of radians clockwise from the 12 o'clock direction,
 | 
			
		||||
        where the line's start point is considered to be at the centre.
 | 
			
		||||
    */
 | 
			
		||||
    static Line fromStartAndAngle (Point<ValueType> startPoint, ValueType length, ValueType angle) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { startPoint, startPoint.getPointOnCircumference (length, angle) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Casts this line to float coordinates. */
 | 
			
		||||
    Line<float> toFloat() const noexcept                                    { return { start.toFloat(), end.toFloat() }; }
 | 
			
		||||
 | 
			
		||||
    /** Casts this line to double coordinates. */
 | 
			
		||||
    Line<double> toDouble() const noexcept                                  { return { start.toDouble(), end.toDouble() }; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Compares two lines. */
 | 
			
		||||
    bool operator== (Line other) const noexcept                             { return start == other.start && end == other.end; }
 | 
			
		||||
 | 
			
		||||
    /** Compares two lines. */
 | 
			
		||||
    bool operator!= (Line other) const noexcept                             { return start != other.start || end != other.end; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Finds the intersection between two lines.
 | 
			
		||||
 | 
			
		||||
        @param line     the line to intersect with
 | 
			
		||||
        @returns        the point at which the lines intersect, even if this lies beyond the end of the lines
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getIntersection (Line line) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        Point<ValueType> p;
 | 
			
		||||
        findIntersection (start, end, line.start, line.end, p);
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Finds the intersection between two lines.
 | 
			
		||||
 | 
			
		||||
        @param line             the other line
 | 
			
		||||
        @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.
 | 
			
		||||
        @returns    true if the line segments intersect; false if they don't. Even if they
 | 
			
		||||
                    don't intersect, the intersection coordinates returned will still
 | 
			
		||||
                    be valid
 | 
			
		||||
    */
 | 
			
		||||
    bool intersects (Line line, Point<ValueType>& intersection) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return findIntersection (start, end, line.start, line.end, intersection);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this line intersects another. */
 | 
			
		||||
    bool intersects (Line other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        Point<ValueType> ignored;
 | 
			
		||||
        return findIntersection (start, end, other.start, other.end, ignored);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the location of the point which is a given distance along this line.
 | 
			
		||||
 | 
			
		||||
        @param distanceFromStart    the distance to move along the line from its
 | 
			
		||||
                                    start point. This value can be negative or longer
 | 
			
		||||
                                    than the line itself
 | 
			
		||||
        @see getPointAlongLineProportionally
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getPointAlongLine (ValueType distanceFromStart) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        const auto length = getLength();
 | 
			
		||||
        return length == 0 ? start : start + (end - start) * (distanceFromStart / length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point which is a certain distance along and to the side of this line.
 | 
			
		||||
 | 
			
		||||
        This effectively moves a given distance along the line, then another distance
 | 
			
		||||
        perpendicularly to this, and returns the resulting position.
 | 
			
		||||
 | 
			
		||||
        @param distanceFromStart    the distance to move along the line from its
 | 
			
		||||
                                    start point. This value can be negative or longer
 | 
			
		||||
                                    than the line itself
 | 
			
		||||
        @param perpendicularDistance    how far to move sideways from the line. If you're
 | 
			
		||||
                                    looking along the line from its start towards its
 | 
			
		||||
                                    end, then a positive value here will move to the
 | 
			
		||||
                                    right, negative value move to the left.
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getPointAlongLine (ValueType distanceFromStart,
 | 
			
		||||
                                        ValueType perpendicularDistance) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto delta = end - start;
 | 
			
		||||
        auto length = juce_hypot ((double) delta.x,
 | 
			
		||||
                                  (double) delta.y);
 | 
			
		||||
        if (length <= 0)
 | 
			
		||||
            return start;
 | 
			
		||||
 | 
			
		||||
        return { start.x + static_cast<ValueType> ((delta.x * distanceFromStart - delta.y * perpendicularDistance) / length),
 | 
			
		||||
                 start.y + static_cast<ValueType> ((delta.y * distanceFromStart + delta.x * perpendicularDistance) / length) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the location of the point which is a given distance along this line
 | 
			
		||||
        proportional to the line's length.
 | 
			
		||||
 | 
			
		||||
        @param proportionOfLength   the distance to move along the line from its
 | 
			
		||||
                                    start point, in multiples of the line's length.
 | 
			
		||||
                                    So a value of 0.0 will return the line's start point
 | 
			
		||||
                                    and a value of 1.0 will return its end point. (This value
 | 
			
		||||
                                    can be negative or greater than 1.0).
 | 
			
		||||
        @see getPointAlongLine
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getPointAlongLineProportionally (typename Point<ValueType>::FloatType proportionOfLength) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return start + (end - start) * proportionOfLength;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the smallest distance between this line segment and a given point.
 | 
			
		||||
 | 
			
		||||
        So if the point is close to the line, this will return the perpendicular
 | 
			
		||||
        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.
 | 
			
		||||
 | 
			
		||||
        pointOnLine receives the position of the point that is found.
 | 
			
		||||
 | 
			
		||||
        @returns the point's distance from the line
 | 
			
		||||
        @see getPositionAlongLineOfNearestPoint
 | 
			
		||||
    */
 | 
			
		||||
    ValueType getDistanceFromPoint (Point<ValueType> targetPoint,
 | 
			
		||||
                                    Point<ValueType>& pointOnLine) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto delta = end - start;
 | 
			
		||||
        auto length = delta.x * delta.x + delta.y * delta.y;
 | 
			
		||||
 | 
			
		||||
        if (length > 0)
 | 
			
		||||
        {
 | 
			
		||||
            auto prop = ((targetPoint.x - start.x) * delta.x
 | 
			
		||||
                       + (targetPoint.y - start.y) * delta.y) / (double) length;
 | 
			
		||||
 | 
			
		||||
            if (prop >= 0 && prop <= 1.0)
 | 
			
		||||
            {
 | 
			
		||||
                pointOnLine = start + delta * prop;
 | 
			
		||||
                return targetPoint.getDistanceFrom (pointOnLine);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto fromStart = targetPoint.getDistanceFrom (start);
 | 
			
		||||
        auto fromEnd   = targetPoint.getDistanceFrom (end);
 | 
			
		||||
 | 
			
		||||
        if (fromStart < fromEnd)
 | 
			
		||||
        {
 | 
			
		||||
            pointOnLine = start;
 | 
			
		||||
            return fromStart;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pointOnLine = end;
 | 
			
		||||
        return fromEnd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Finds the point on this line which is nearest to a given point, and
 | 
			
		||||
        returns its position as a proportional position along the line.
 | 
			
		||||
 | 
			
		||||
        @returns    a value 0 to 1.0 which is the distance along this line from the
 | 
			
		||||
                    line's start to the point which is nearest to the point passed-in. To
 | 
			
		||||
                    turn this number into a position, use getPointAlongLineProportionally().
 | 
			
		||||
        @see getDistanceFromPoint, getPointAlongLineProportionally
 | 
			
		||||
    */
 | 
			
		||||
    ValueType findNearestProportionalPositionTo (Point<ValueType> point) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto delta = end - start;
 | 
			
		||||
        auto length = delta.x * delta.x + delta.y * delta.y;
 | 
			
		||||
 | 
			
		||||
        return length <= 0 ? 0
 | 
			
		||||
                           : jlimit (ValueType(), static_cast<ValueType> (1),
 | 
			
		||||
                                     static_cast<ValueType> ((((point.x - start.x) * delta.x
 | 
			
		||||
                                                             + (point.y - start.y) * delta.y) / length)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Finds the point on this line which is nearest to a given point.
 | 
			
		||||
        @see getDistanceFromPoint, findNearestProportionalPositionTo
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> findNearestPointTo (Point<ValueType> point) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return getPointAlongLineProportionally (findNearestProportionalPositionTo (point));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the given point lies above this line.
 | 
			
		||||
 | 
			
		||||
        The return value is true if the point's y coordinate is less than the y
 | 
			
		||||
        coordinate of this line at the given x (assuming the line extends infinitely
 | 
			
		||||
        in both directions).
 | 
			
		||||
    */
 | 
			
		||||
    bool isPointAbove (Point<ValueType> point) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return start.x != end.x
 | 
			
		||||
                && point.y < ((end.y - start.y) * (point.x - start.x)) / (end.x - start.x) + start.y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a lengthened copy of this line.
 | 
			
		||||
 | 
			
		||||
        This will extend the line by a certain amount by moving the start away from the end
 | 
			
		||||
        (leaving the end-point the same), and return the new line.
 | 
			
		||||
    */
 | 
			
		||||
    Line withLengthenedStart (ValueType distanceToLengthenBy) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return withShortenedStart (-distanceToLengthenBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a shortened copy of this line.
 | 
			
		||||
 | 
			
		||||
        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.
 | 
			
		||||
    */
 | 
			
		||||
    Line withShortenedStart (ValueType distanceToShortenBy) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return { getPointAlongLine (jmin (distanceToShortenBy, getLength())), end };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a lengthened copy of this line.
 | 
			
		||||
 | 
			
		||||
        This will extend the line by a certain amount by moving the end away from the start
 | 
			
		||||
        (leaving the start-point the same), and return the new line.
 | 
			
		||||
    */
 | 
			
		||||
    Line withLengthenedEnd (ValueType distanceToLengthenBy) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return withShortenedEnd (-distanceToLengthenBy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** 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.
 | 
			
		||||
    */
 | 
			
		||||
    Line withShortenedEnd (ValueType distanceToShortenBy) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto length = getLength();
 | 
			
		||||
        return { start, getPointAlongLine (length - jmin (distanceToShortenBy, length)) };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Point<ValueType> start, end;
 | 
			
		||||
 | 
			
		||||
    static bool isZeroToOne (ValueType v) noexcept      { return v >= 0 && v <= static_cast<ValueType> (1); }
 | 
			
		||||
 | 
			
		||||
    static bool findIntersection (const Point<ValueType> p1, const Point<ValueType> p2,
 | 
			
		||||
                                  const Point<ValueType> p3, const Point<ValueType> p4,
 | 
			
		||||
                                  Point<ValueType>& intersection) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (p2 == p3)
 | 
			
		||||
        {
 | 
			
		||||
            intersection = p2;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto d1 = p2 - p1;
 | 
			
		||||
        auto d2 = p4 - p3;
 | 
			
		||||
        auto divisor = d1.x * d2.y - d2.x * d1.y;
 | 
			
		||||
 | 
			
		||||
        if (divisor == 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (! (d1.isOrigin() || d2.isOrigin()))
 | 
			
		||||
            {
 | 
			
		||||
                if (d1.y == 0 && d2.y != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p1.y - p3.y) / d2.y;
 | 
			
		||||
                    intersection = p1.withX (p3.x + along * d2.x);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (d2.y == 0 && d1.y != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p3.y - p1.y) / d1.y;
 | 
			
		||||
                    intersection = p3.withX (p1.x + along * d1.x);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (d1.x == 0 && d2.x != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p1.x - p3.x) / d2.x;
 | 
			
		||||
                    intersection = p1.withY (p3.y + along * d2.y);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (d2.x == 0 && d1.x != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    auto along = (p3.x - p1.x) / d1.x;
 | 
			
		||||
                    intersection = p3.withY (p1.y + along * d1.y);
 | 
			
		||||
                    return isZeroToOne (along);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            intersection = (p2 + p3) / static_cast<ValueType> (2);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto along1 = ((p1.y - p3.y) * d2.x - (p1.x - p3.x) * d2.y) / divisor;
 | 
			
		||||
        intersection = p1 + d1 * along1;
 | 
			
		||||
 | 
			
		||||
        if (! isZeroToOne (along1))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        auto along2 = ((p1.y - p3.y) * d1.x - (p1.x - p3.x) * d1.y) / divisor;
 | 
			
		||||
        return isZeroToOne (along2);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,185 +1,185 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Represents a parallelogram that is defined by 3 points.
 | 
			
		||||
    @see Rectangle, Point, Line
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class Parallelogram
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a parallelogram with zero size at the origin.
 | 
			
		||||
    */
 | 
			
		||||
    Parallelogram() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another parallelogram. */
 | 
			
		||||
    Parallelogram (const Parallelogram&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a parallelogram based on 3 points. */
 | 
			
		||||
    Parallelogram (Point<ValueType> topLeftPosition,
 | 
			
		||||
                   Point<ValueType> topRightPosition,
 | 
			
		||||
                   Point<ValueType> bottomLeftPosition) noexcept
 | 
			
		||||
       : topLeft (topLeftPosition), topRight (topRightPosition), bottomLeft (bottomLeftPosition)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Creates a parallelogram from a rectangle. */
 | 
			
		||||
    Parallelogram (Rectangle<ValueType> rectangle) noexcept
 | 
			
		||||
       : topLeft (rectangle.getTopLeft()),
 | 
			
		||||
         topRight (rectangle.getTopRight()),
 | 
			
		||||
         bottomLeft (rectangle.getBottomLeft())
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Parallelogram& operator= (const Parallelogram&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~Parallelogram() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the parallelogram has a width or height of more than zero. */
 | 
			
		||||
    bool isEmpty() const noexcept                                   { return topLeft != topRight || topLeft != bottomLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the parallelogram's coordinates are all finite numbers, i.e. not NaN or infinity. */
 | 
			
		||||
    inline bool isFinite() const noexcept                           { return topLeft.isFinite() && topRight.isFinite() && bottomLeft.isFinite(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the width of the parallelogram (i.e. the straight-line distance between the top-left and top-right. */
 | 
			
		||||
    inline ValueType getWidth() const noexcept                      { return Line<ValueType> (topLeft, topRight).getLength(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the height of the parallelogram (i.e. the straight-line distance between the top-left and bottom-left. */
 | 
			
		||||
    inline ValueType getHeight() const noexcept                     { return Line<ValueType> (topLeft, bottomLeft).getLength(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the parallelogram's top-left position as a Point. */
 | 
			
		||||
    Point<ValueType> getTopLeft() const noexcept                    { return topLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parallelogram's top-right position as a Point. */
 | 
			
		||||
    Point<ValueType> getTopRight() const noexcept                   { return topRight; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parallelogram's bottom-left position as a Point. */
 | 
			
		||||
    Point<ValueType> getBottomLeft() const noexcept                 { return bottomLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parallelogram's bottom-right position as a Point. */
 | 
			
		||||
    Point<ValueType> getBottomRight() const noexcept                { return topRight + (bottomLeft - topLeft); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the two parallelograms are identical. */
 | 
			
		||||
    bool operator== (const Parallelogram& other) const noexcept     { return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the two parallelograms are not identical. */
 | 
			
		||||
    bool operator!= (const Parallelogram& other) const noexcept     { return ! operator== (other); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a parallelogram which is the same as this one moved by a given amount. */
 | 
			
		||||
    Parallelogram operator+ (Point<ValueType> deltaPosition) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto p = *this;
 | 
			
		||||
        p += deltaPosition;
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Moves this parallelogram by a given amount. */
 | 
			
		||||
    Parallelogram& operator+= (Point<ValueType> deltaPosition) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        topLeft += deltaPosition;
 | 
			
		||||
        topRight += deltaPosition;
 | 
			
		||||
        bottomLeft += deltaPosition;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a parallelogram which is the same as this one moved by a given amount. */
 | 
			
		||||
    Parallelogram operator- (Point<ValueType> deltaPosition) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return operator+ (-deltaPosition);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Moves this parallelogram by a given amount. */
 | 
			
		||||
    Parallelogram& operator-= (Point<ValueType> deltaPosition) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return operator-= (-deltaPosition);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a parallelogram that has been scaled by the given amount, centred around the origin. */
 | 
			
		||||
    template <typename PointOrScalarType>
 | 
			
		||||
    Parallelogram operator* (PointOrScalarType scaleFactor) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto p = *this;
 | 
			
		||||
        p *= scaleFactor;
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Scales this parallelogram by the given amount, centred around the origin. */
 | 
			
		||||
    template <typename PointOrScalarType>
 | 
			
		||||
    Parallelogram operator*= (PointOrScalarType scaleFactor) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        topLeft *= scaleFactor;
 | 
			
		||||
        topRight *= scaleFactor;
 | 
			
		||||
        bottomLeft *= scaleFactor;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a point within this parallelogram, specified as proportional coordinates.
 | 
			
		||||
        The relative X and Y values should be between 0 and 1, where 0 is the left or
 | 
			
		||||
        top of this parallelogram, and 1 is the right or bottom. (Out-of-bounds values
 | 
			
		||||
        will return a point outside the parallelogram).
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getRelativePoint (Point<ValueType> relativePosition) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return topLeft
 | 
			
		||||
                + (topRight - topLeft) * relativePosition.x
 | 
			
		||||
                + (bottomLeft - topLeft) * relativePosition.y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a transformed version of the parallelogram. */
 | 
			
		||||
    Parallelogram transformedBy (const AffineTransform& transform) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto p = *this;
 | 
			
		||||
        transform.transformPoints (p.topLeft.x, p.topLeft.y,
 | 
			
		||||
                                   p.topRight.x, p.topRight.y,
 | 
			
		||||
                                   p.bottomLeft.x, p.bottomLeft.y);
 | 
			
		||||
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the smallest rectangle that encloses this parallelogram. */
 | 
			
		||||
    Rectangle<ValueType> getBoundingBox() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        const Point<ValueType> points[] = { topLeft, topRight, bottomLeft, getBottomRight() };
 | 
			
		||||
        return Rectangle<ValueType>::findAreaContainingPoints (points, 4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Point<ValueType> topLeft, topRight, bottomLeft;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Represents a parallelogram that is defined by 3 points.
 | 
			
		||||
    @see Rectangle, Point, Line
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class Parallelogram
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a parallelogram with zero size at the origin.
 | 
			
		||||
    */
 | 
			
		||||
    Parallelogram() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another parallelogram. */
 | 
			
		||||
    Parallelogram (const Parallelogram&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a parallelogram based on 3 points. */
 | 
			
		||||
    Parallelogram (Point<ValueType> topLeftPosition,
 | 
			
		||||
                   Point<ValueType> topRightPosition,
 | 
			
		||||
                   Point<ValueType> bottomLeftPosition) noexcept
 | 
			
		||||
       : topLeft (topLeftPosition), topRight (topRightPosition), bottomLeft (bottomLeftPosition)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Creates a parallelogram from a rectangle. */
 | 
			
		||||
    Parallelogram (Rectangle<ValueType> rectangle) noexcept
 | 
			
		||||
       : topLeft (rectangle.getTopLeft()),
 | 
			
		||||
         topRight (rectangle.getTopRight()),
 | 
			
		||||
         bottomLeft (rectangle.getBottomLeft())
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Parallelogram& operator= (const Parallelogram&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~Parallelogram() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the parallelogram has a width or height of more than zero. */
 | 
			
		||||
    bool isEmpty() const noexcept                                   { return topLeft != topRight || topLeft != bottomLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the parallelogram's coordinates are all finite numbers, i.e. not NaN or infinity. */
 | 
			
		||||
    inline bool isFinite() const noexcept                           { return topLeft.isFinite() && topRight.isFinite() && bottomLeft.isFinite(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the width of the parallelogram (i.e. the straight-line distance between the top-left and top-right. */
 | 
			
		||||
    inline ValueType getWidth() const noexcept                      { return Line<ValueType> (topLeft, topRight).getLength(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the height of the parallelogram (i.e. the straight-line distance between the top-left and bottom-left. */
 | 
			
		||||
    inline ValueType getHeight() const noexcept                     { return Line<ValueType> (topLeft, bottomLeft).getLength(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the parallelogram's top-left position as a Point. */
 | 
			
		||||
    Point<ValueType> getTopLeft() const noexcept                    { return topLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parallelogram's top-right position as a Point. */
 | 
			
		||||
    Point<ValueType> getTopRight() const noexcept                   { return topRight; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parallelogram's bottom-left position as a Point. */
 | 
			
		||||
    Point<ValueType> getBottomLeft() const noexcept                 { return bottomLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parallelogram's bottom-right position as a Point. */
 | 
			
		||||
    Point<ValueType> getBottomRight() const noexcept                { return topRight + (bottomLeft - topLeft); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the two parallelograms are identical. */
 | 
			
		||||
    bool operator== (const Parallelogram& other) const noexcept     { return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the two parallelograms are not identical. */
 | 
			
		||||
    bool operator!= (const Parallelogram& other) const noexcept     { return ! operator== (other); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a parallelogram which is the same as this one moved by a given amount. */
 | 
			
		||||
    Parallelogram operator+ (Point<ValueType> deltaPosition) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto p = *this;
 | 
			
		||||
        p += deltaPosition;
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Moves this parallelogram by a given amount. */
 | 
			
		||||
    Parallelogram& operator+= (Point<ValueType> deltaPosition) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        topLeft += deltaPosition;
 | 
			
		||||
        topRight += deltaPosition;
 | 
			
		||||
        bottomLeft += deltaPosition;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a parallelogram which is the same as this one moved by a given amount. */
 | 
			
		||||
    Parallelogram operator- (Point<ValueType> deltaPosition) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return operator+ (-deltaPosition);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Moves this parallelogram by a given amount. */
 | 
			
		||||
    Parallelogram& operator-= (Point<ValueType> deltaPosition) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return operator-= (-deltaPosition);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a parallelogram that has been scaled by the given amount, centred around the origin. */
 | 
			
		||||
    template <typename PointOrScalarType>
 | 
			
		||||
    Parallelogram operator* (PointOrScalarType scaleFactor) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto p = *this;
 | 
			
		||||
        p *= scaleFactor;
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Scales this parallelogram by the given amount, centred around the origin. */
 | 
			
		||||
    template <typename PointOrScalarType>
 | 
			
		||||
    Parallelogram operator*= (PointOrScalarType scaleFactor) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        topLeft *= scaleFactor;
 | 
			
		||||
        topRight *= scaleFactor;
 | 
			
		||||
        bottomLeft *= scaleFactor;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a point within this parallelogram, specified as proportional coordinates.
 | 
			
		||||
        The relative X and Y values should be between 0 and 1, where 0 is the left or
 | 
			
		||||
        top of this parallelogram, and 1 is the right or bottom. (Out-of-bounds values
 | 
			
		||||
        will return a point outside the parallelogram).
 | 
			
		||||
    */
 | 
			
		||||
    Point<ValueType> getRelativePoint (Point<ValueType> relativePosition) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return topLeft
 | 
			
		||||
                + (topRight - topLeft) * relativePosition.x
 | 
			
		||||
                + (bottomLeft - topLeft) * relativePosition.y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a transformed version of the parallelogram. */
 | 
			
		||||
    Parallelogram transformedBy (const AffineTransform& transform) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        auto p = *this;
 | 
			
		||||
        transform.transformPoints (p.topLeft.x, p.topLeft.y,
 | 
			
		||||
                                   p.topRight.x, p.topRight.y,
 | 
			
		||||
                                   p.bottomLeft.x, p.bottomLeft.y);
 | 
			
		||||
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the smallest rectangle that encloses this parallelogram. */
 | 
			
		||||
    Rectangle<ValueType> getBoundingBox() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        const Point<ValueType> points[] = { topLeft, topRight, bottomLeft, getBottomRight() };
 | 
			
		||||
        return Rectangle<ValueType>::findAreaContainingPoints (points, 4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Point<ValueType> topLeft, topRight, bottomLeft;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3078
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Path.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3078
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Path.cpp
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1678
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Path.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1678
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Path.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,295 +1,295 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_MSVC && JUCE_DEBUG
 | 
			
		||||
 #pragma optimize ("t", on)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
PathFlatteningIterator::PathFlatteningIterator (const Path& pathToUse,
 | 
			
		||||
                                                const AffineTransform& t,
 | 
			
		||||
                                                float tolerance)
 | 
			
		||||
    : x2 (0),
 | 
			
		||||
      y2 (0),
 | 
			
		||||
      closesSubPath (false),
 | 
			
		||||
      subPathIndex (-1),
 | 
			
		||||
      path (pathToUse),
 | 
			
		||||
      transform (t),
 | 
			
		||||
      source (path.data.begin()),
 | 
			
		||||
      toleranceSquared (tolerance * tolerance),
 | 
			
		||||
      isIdentityTransform (t.isIdentity())
 | 
			
		||||
{
 | 
			
		||||
    stackPos = stackBase;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PathFlatteningIterator::~PathFlatteningIterator()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PathFlatteningIterator::isLastInSubpath() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return stackPos == stackBase.get()
 | 
			
		||||
             && (source == path.data.end() || isMarker (*source, Path::moveMarker));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PathFlatteningIterator::next()
 | 
			
		||||
{
 | 
			
		||||
    x1 = x2;
 | 
			
		||||
    y1 = y2;
 | 
			
		||||
 | 
			
		||||
    float x3 = 0;
 | 
			
		||||
    float y3 = 0;
 | 
			
		||||
    float x4 = 0;
 | 
			
		||||
    float y4 = 0;
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        float type;
 | 
			
		||||
 | 
			
		||||
        if (stackPos == stackBase.get())
 | 
			
		||||
        {
 | 
			
		||||
            if (source == path.data.end())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            type = *source++;
 | 
			
		||||
 | 
			
		||||
            if (! isMarker (type, Path::closeSubPathMarker))
 | 
			
		||||
            {
 | 
			
		||||
                x2 = *source++;
 | 
			
		||||
                y2 = *source++;
 | 
			
		||||
 | 
			
		||||
                if (isMarker (type, Path::quadMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *source++;
 | 
			
		||||
                    y3 = *source++;
 | 
			
		||||
 | 
			
		||||
                    if (! isIdentityTransform)
 | 
			
		||||
                        transform.transformPoints (x2, y2, x3, y3);
 | 
			
		||||
                }
 | 
			
		||||
                else if (isMarker (type, Path::cubicMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *source++;
 | 
			
		||||
                    y3 = *source++;
 | 
			
		||||
                    x4 = *source++;
 | 
			
		||||
                    y4 = *source++;
 | 
			
		||||
 | 
			
		||||
                    if (! isIdentityTransform)
 | 
			
		||||
                        transform.transformPoints (x2, y2, x3, y3, x4, y4);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (! isIdentityTransform)
 | 
			
		||||
                        transform.transformPoint (x2, y2);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            type = *--stackPos;
 | 
			
		||||
 | 
			
		||||
            if (! isMarker (type, Path::closeSubPathMarker))
 | 
			
		||||
            {
 | 
			
		||||
                x2 = *--stackPos;
 | 
			
		||||
                y2 = *--stackPos;
 | 
			
		||||
 | 
			
		||||
                if (isMarker (type, Path::quadMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *--stackPos;
 | 
			
		||||
                    y3 = *--stackPos;
 | 
			
		||||
                }
 | 
			
		||||
                else if (isMarker (type, Path::cubicMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *--stackPos;
 | 
			
		||||
                    y3 = *--stackPos;
 | 
			
		||||
                    x4 = *--stackPos;
 | 
			
		||||
                    y4 = *--stackPos;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isMarker (type, Path::lineMarker))
 | 
			
		||||
        {
 | 
			
		||||
            ++subPathIndex;
 | 
			
		||||
 | 
			
		||||
            closesSubPath = stackPos == stackBase.get()
 | 
			
		||||
                             && source != path.data.end()
 | 
			
		||||
                             && *source == Path::closeSubPathMarker
 | 
			
		||||
                             && x2 == subPathCloseX
 | 
			
		||||
                             && y2 == subPathCloseY;
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isMarker (type, Path::quadMarker))
 | 
			
		||||
        {
 | 
			
		||||
            const size_t offset = (size_t) (stackPos - stackBase);
 | 
			
		||||
 | 
			
		||||
            if (offset >= stackSize - 10)
 | 
			
		||||
            {
 | 
			
		||||
                stackSize <<= 1;
 | 
			
		||||
                stackBase.realloc (stackSize);
 | 
			
		||||
                stackPos = stackBase + offset;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto m1x = (x1 + x2) * 0.5f;
 | 
			
		||||
            auto m1y = (y1 + y2) * 0.5f;
 | 
			
		||||
            auto m2x = (x2 + x3) * 0.5f;
 | 
			
		||||
            auto m2y = (y2 + y3) * 0.5f;
 | 
			
		||||
            auto m3x = (m1x + m2x) * 0.5f;
 | 
			
		||||
            auto m3y = (m1y + m2y) * 0.5f;
 | 
			
		||||
 | 
			
		||||
            auto errorX = m3x - x2;
 | 
			
		||||
            auto errorY = m3y - y2;
 | 
			
		||||
 | 
			
		||||
            auto outsideTolerance = errorX * errorX + errorY * errorY > toleranceSquared;
 | 
			
		||||
            auto canBeSubdivided = (m3x != m1x && m3x != m2x)
 | 
			
		||||
                                || (m3y != m1y && m3y != m2y);
 | 
			
		||||
 | 
			
		||||
            if (outsideTolerance && canBeSubdivided)
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y3;
 | 
			
		||||
                *stackPos++ = x3;
 | 
			
		||||
                *stackPos++ = m2y;
 | 
			
		||||
                *stackPos++ = m2x;
 | 
			
		||||
                *stackPos++ = Path::quadMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m3y;
 | 
			
		||||
                *stackPos++ = m3x;
 | 
			
		||||
                *stackPos++ = m1y;
 | 
			
		||||
                *stackPos++ = m1x;
 | 
			
		||||
                *stackPos++ = Path::quadMarker;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y3;
 | 
			
		||||
                *stackPos++ = x3;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m3y;
 | 
			
		||||
                *stackPos++ = m3x;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            jassert (stackPos < stackBase + stackSize);
 | 
			
		||||
        }
 | 
			
		||||
        else if (isMarker (type, Path::cubicMarker))
 | 
			
		||||
        {
 | 
			
		||||
            const size_t offset = (size_t) (stackPos - stackBase);
 | 
			
		||||
 | 
			
		||||
            if (offset >= stackSize - 16)
 | 
			
		||||
            {
 | 
			
		||||
                stackSize <<= 1;
 | 
			
		||||
                stackBase.realloc (stackSize);
 | 
			
		||||
                stackPos = stackBase + offset;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto m1x = (x1 + x2) * 0.5f;
 | 
			
		||||
            auto m1y = (y1 + y2) * 0.5f;
 | 
			
		||||
            auto m2x = (x3 + x2) * 0.5f;
 | 
			
		||||
            auto m2y = (y3 + y2) * 0.5f;
 | 
			
		||||
            auto m3x = (x3 + x4) * 0.5f;
 | 
			
		||||
            auto m3y = (y3 + y4) * 0.5f;
 | 
			
		||||
            auto m4x = (m1x + m2x) * 0.5f;
 | 
			
		||||
            auto m4y = (m1y + m2y) * 0.5f;
 | 
			
		||||
            auto m5x = (m3x + m2x) * 0.5f;
 | 
			
		||||
            auto m5y = (m3y + m2y) * 0.5f;
 | 
			
		||||
 | 
			
		||||
            auto error1X = m4x - x2;
 | 
			
		||||
            auto error1Y = m4y - y2;
 | 
			
		||||
            auto error2X = m5x - x3;
 | 
			
		||||
            auto error2Y = m5y - y3;
 | 
			
		||||
 | 
			
		||||
            auto outsideTolerance = error1X * error1X + error1Y * error1Y > toleranceSquared
 | 
			
		||||
                                 || error2X * error2X + error2Y * error2Y > toleranceSquared;
 | 
			
		||||
            auto canBeSubdivided = (m4x != m1x && m4x != m2x)
 | 
			
		||||
                                || (m4y != m1y && m4y != m2y)
 | 
			
		||||
                                || (m5x != m3x && m5x != m2x)
 | 
			
		||||
                                || (m5y != m3y && m5y != m2y);
 | 
			
		||||
 | 
			
		||||
            if (outsideTolerance && canBeSubdivided)
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y4;
 | 
			
		||||
                *stackPos++ = x4;
 | 
			
		||||
                *stackPos++ = m3y;
 | 
			
		||||
                *stackPos++ = m3x;
 | 
			
		||||
                *stackPos++ = m5y;
 | 
			
		||||
                *stackPos++ = m5x;
 | 
			
		||||
                *stackPos++ = Path::cubicMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = (m4y + m5y) * 0.5f;
 | 
			
		||||
                *stackPos++ = (m4x + m5x) * 0.5f;
 | 
			
		||||
                *stackPos++ = m4y;
 | 
			
		||||
                *stackPos++ = m4x;
 | 
			
		||||
                *stackPos++ = m1y;
 | 
			
		||||
                *stackPos++ = m1x;
 | 
			
		||||
                *stackPos++ = Path::cubicMarker;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y4;
 | 
			
		||||
                *stackPos++ = x4;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m5y;
 | 
			
		||||
                *stackPos++ = m5x;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m4y;
 | 
			
		||||
                *stackPos++ = m4x;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (isMarker (type, Path::closeSubPathMarker))
 | 
			
		||||
        {
 | 
			
		||||
            if (x2 != subPathCloseX || y2 != subPathCloseY)
 | 
			
		||||
            {
 | 
			
		||||
                x1 = x2;
 | 
			
		||||
                y1 = y2;
 | 
			
		||||
                x2 = subPathCloseX;
 | 
			
		||||
                y2 = subPathCloseY;
 | 
			
		||||
                closesSubPath = true;
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            jassert (isMarker (type, Path::moveMarker));
 | 
			
		||||
 | 
			
		||||
            subPathIndex = -1;
 | 
			
		||||
            subPathCloseX = x1 = x2;
 | 
			
		||||
            subPathCloseY = y1 = y2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MSVC && JUCE_DEBUG
 | 
			
		||||
  #pragma optimize ("", on)  // resets optimisations to the project defaults
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_MSVC && JUCE_DEBUG
 | 
			
		||||
 #pragma optimize ("t", on)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
PathFlatteningIterator::PathFlatteningIterator (const Path& pathToUse,
 | 
			
		||||
                                                const AffineTransform& t,
 | 
			
		||||
                                                float tolerance)
 | 
			
		||||
    : x2 (0),
 | 
			
		||||
      y2 (0),
 | 
			
		||||
      closesSubPath (false),
 | 
			
		||||
      subPathIndex (-1),
 | 
			
		||||
      path (pathToUse),
 | 
			
		||||
      transform (t),
 | 
			
		||||
      source (path.data.begin()),
 | 
			
		||||
      toleranceSquared (tolerance * tolerance),
 | 
			
		||||
      isIdentityTransform (t.isIdentity())
 | 
			
		||||
{
 | 
			
		||||
    stackPos = stackBase;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PathFlatteningIterator::~PathFlatteningIterator()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PathFlatteningIterator::isLastInSubpath() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return stackPos == stackBase.get()
 | 
			
		||||
             && (source == path.data.end() || isMarker (*source, Path::moveMarker));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PathFlatteningIterator::next()
 | 
			
		||||
{
 | 
			
		||||
    x1 = x2;
 | 
			
		||||
    y1 = y2;
 | 
			
		||||
 | 
			
		||||
    float x3 = 0;
 | 
			
		||||
    float y3 = 0;
 | 
			
		||||
    float x4 = 0;
 | 
			
		||||
    float y4 = 0;
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        float type;
 | 
			
		||||
 | 
			
		||||
        if (stackPos == stackBase.get())
 | 
			
		||||
        {
 | 
			
		||||
            if (source == path.data.end())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            type = *source++;
 | 
			
		||||
 | 
			
		||||
            if (! isMarker (type, Path::closeSubPathMarker))
 | 
			
		||||
            {
 | 
			
		||||
                x2 = *source++;
 | 
			
		||||
                y2 = *source++;
 | 
			
		||||
 | 
			
		||||
                if (isMarker (type, Path::quadMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *source++;
 | 
			
		||||
                    y3 = *source++;
 | 
			
		||||
 | 
			
		||||
                    if (! isIdentityTransform)
 | 
			
		||||
                        transform.transformPoints (x2, y2, x3, y3);
 | 
			
		||||
                }
 | 
			
		||||
                else if (isMarker (type, Path::cubicMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *source++;
 | 
			
		||||
                    y3 = *source++;
 | 
			
		||||
                    x4 = *source++;
 | 
			
		||||
                    y4 = *source++;
 | 
			
		||||
 | 
			
		||||
                    if (! isIdentityTransform)
 | 
			
		||||
                        transform.transformPoints (x2, y2, x3, y3, x4, y4);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (! isIdentityTransform)
 | 
			
		||||
                        transform.transformPoint (x2, y2);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            type = *--stackPos;
 | 
			
		||||
 | 
			
		||||
            if (! isMarker (type, Path::closeSubPathMarker))
 | 
			
		||||
            {
 | 
			
		||||
                x2 = *--stackPos;
 | 
			
		||||
                y2 = *--stackPos;
 | 
			
		||||
 | 
			
		||||
                if (isMarker (type, Path::quadMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *--stackPos;
 | 
			
		||||
                    y3 = *--stackPos;
 | 
			
		||||
                }
 | 
			
		||||
                else if (isMarker (type, Path::cubicMarker))
 | 
			
		||||
                {
 | 
			
		||||
                    x3 = *--stackPos;
 | 
			
		||||
                    y3 = *--stackPos;
 | 
			
		||||
                    x4 = *--stackPos;
 | 
			
		||||
                    y4 = *--stackPos;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isMarker (type, Path::lineMarker))
 | 
			
		||||
        {
 | 
			
		||||
            ++subPathIndex;
 | 
			
		||||
 | 
			
		||||
            closesSubPath = stackPos == stackBase.get()
 | 
			
		||||
                             && source != path.data.end()
 | 
			
		||||
                             && *source == Path::closeSubPathMarker
 | 
			
		||||
                             && x2 == subPathCloseX
 | 
			
		||||
                             && y2 == subPathCloseY;
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isMarker (type, Path::quadMarker))
 | 
			
		||||
        {
 | 
			
		||||
            const size_t offset = (size_t) (stackPos - stackBase);
 | 
			
		||||
 | 
			
		||||
            if (offset >= stackSize - 10)
 | 
			
		||||
            {
 | 
			
		||||
                stackSize <<= 1;
 | 
			
		||||
                stackBase.realloc (stackSize);
 | 
			
		||||
                stackPos = stackBase + offset;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto m1x = (x1 + x2) * 0.5f;
 | 
			
		||||
            auto m1y = (y1 + y2) * 0.5f;
 | 
			
		||||
            auto m2x = (x2 + x3) * 0.5f;
 | 
			
		||||
            auto m2y = (y2 + y3) * 0.5f;
 | 
			
		||||
            auto m3x = (m1x + m2x) * 0.5f;
 | 
			
		||||
            auto m3y = (m1y + m2y) * 0.5f;
 | 
			
		||||
 | 
			
		||||
            auto errorX = m3x - x2;
 | 
			
		||||
            auto errorY = m3y - y2;
 | 
			
		||||
 | 
			
		||||
            auto outsideTolerance = errorX * errorX + errorY * errorY > toleranceSquared;
 | 
			
		||||
            auto canBeSubdivided = (m3x != m1x && m3x != m2x)
 | 
			
		||||
                                || (m3y != m1y && m3y != m2y);
 | 
			
		||||
 | 
			
		||||
            if (outsideTolerance && canBeSubdivided)
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y3;
 | 
			
		||||
                *stackPos++ = x3;
 | 
			
		||||
                *stackPos++ = m2y;
 | 
			
		||||
                *stackPos++ = m2x;
 | 
			
		||||
                *stackPos++ = Path::quadMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m3y;
 | 
			
		||||
                *stackPos++ = m3x;
 | 
			
		||||
                *stackPos++ = m1y;
 | 
			
		||||
                *stackPos++ = m1x;
 | 
			
		||||
                *stackPos++ = Path::quadMarker;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y3;
 | 
			
		||||
                *stackPos++ = x3;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m3y;
 | 
			
		||||
                *stackPos++ = m3x;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            jassert (stackPos < stackBase + stackSize);
 | 
			
		||||
        }
 | 
			
		||||
        else if (isMarker (type, Path::cubicMarker))
 | 
			
		||||
        {
 | 
			
		||||
            const size_t offset = (size_t) (stackPos - stackBase);
 | 
			
		||||
 | 
			
		||||
            if (offset >= stackSize - 16)
 | 
			
		||||
            {
 | 
			
		||||
                stackSize <<= 1;
 | 
			
		||||
                stackBase.realloc (stackSize);
 | 
			
		||||
                stackPos = stackBase + offset;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto m1x = (x1 + x2) * 0.5f;
 | 
			
		||||
            auto m1y = (y1 + y2) * 0.5f;
 | 
			
		||||
            auto m2x = (x3 + x2) * 0.5f;
 | 
			
		||||
            auto m2y = (y3 + y2) * 0.5f;
 | 
			
		||||
            auto m3x = (x3 + x4) * 0.5f;
 | 
			
		||||
            auto m3y = (y3 + y4) * 0.5f;
 | 
			
		||||
            auto m4x = (m1x + m2x) * 0.5f;
 | 
			
		||||
            auto m4y = (m1y + m2y) * 0.5f;
 | 
			
		||||
            auto m5x = (m3x + m2x) * 0.5f;
 | 
			
		||||
            auto m5y = (m3y + m2y) * 0.5f;
 | 
			
		||||
 | 
			
		||||
            auto error1X = m4x - x2;
 | 
			
		||||
            auto error1Y = m4y - y2;
 | 
			
		||||
            auto error2X = m5x - x3;
 | 
			
		||||
            auto error2Y = m5y - y3;
 | 
			
		||||
 | 
			
		||||
            auto outsideTolerance = error1X * error1X + error1Y * error1Y > toleranceSquared
 | 
			
		||||
                                 || error2X * error2X + error2Y * error2Y > toleranceSquared;
 | 
			
		||||
            auto canBeSubdivided = (m4x != m1x && m4x != m2x)
 | 
			
		||||
                                || (m4y != m1y && m4y != m2y)
 | 
			
		||||
                                || (m5x != m3x && m5x != m2x)
 | 
			
		||||
                                || (m5y != m3y && m5y != m2y);
 | 
			
		||||
 | 
			
		||||
            if (outsideTolerance && canBeSubdivided)
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y4;
 | 
			
		||||
                *stackPos++ = x4;
 | 
			
		||||
                *stackPos++ = m3y;
 | 
			
		||||
                *stackPos++ = m3x;
 | 
			
		||||
                *stackPos++ = m5y;
 | 
			
		||||
                *stackPos++ = m5x;
 | 
			
		||||
                *stackPos++ = Path::cubicMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = (m4y + m5y) * 0.5f;
 | 
			
		||||
                *stackPos++ = (m4x + m5x) * 0.5f;
 | 
			
		||||
                *stackPos++ = m4y;
 | 
			
		||||
                *stackPos++ = m4x;
 | 
			
		||||
                *stackPos++ = m1y;
 | 
			
		||||
                *stackPos++ = m1x;
 | 
			
		||||
                *stackPos++ = Path::cubicMarker;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                *stackPos++ = y4;
 | 
			
		||||
                *stackPos++ = x4;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m5y;
 | 
			
		||||
                *stackPos++ = m5x;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
 | 
			
		||||
                *stackPos++ = m4y;
 | 
			
		||||
                *stackPos++ = m4x;
 | 
			
		||||
                *stackPos++ = Path::lineMarker;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (isMarker (type, Path::closeSubPathMarker))
 | 
			
		||||
        {
 | 
			
		||||
            if (x2 != subPathCloseX || y2 != subPathCloseY)
 | 
			
		||||
            {
 | 
			
		||||
                x1 = x2;
 | 
			
		||||
                y1 = y2;
 | 
			
		||||
                x2 = subPathCloseX;
 | 
			
		||||
                y2 = subPathCloseY;
 | 
			
		||||
                closesSubPath = true;
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            jassert (isMarker (type, Path::moveMarker));
 | 
			
		||||
 | 
			
		||||
            subPathIndex = -1;
 | 
			
		||||
            subPathCloseX = x1 = x2;
 | 
			
		||||
            subPathCloseY = y1 = y2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MSVC && JUCE_DEBUG
 | 
			
		||||
  #pragma optimize ("", on)  // resets optimisations to the project defaults
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,111 +1,111 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Flattens a Path object into a series of straight-line sections.
 | 
			
		||||
 | 
			
		||||
    Use one of these to iterate through a Path object, and it will convert
 | 
			
		||||
    all the curves into line sections so it's easy to render or perform
 | 
			
		||||
    geometric operations on.
 | 
			
		||||
 | 
			
		||||
    @see Path
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  PathFlatteningIterator  final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a PathFlatteningIterator.
 | 
			
		||||
 | 
			
		||||
        After creation, use the next() method to initialise the fields in the
 | 
			
		||||
        object with the first line's position.
 | 
			
		||||
 | 
			
		||||
        @param path         the path to iterate along
 | 
			
		||||
        @param transform    a transform to apply to each point in the path being iterated
 | 
			
		||||
        @param tolerance    the amount by which the curves are allowed to deviate from the lines
 | 
			
		||||
                            into which they are being broken down - a higher tolerance contains
 | 
			
		||||
                            less lines, so can be generated faster, but will be less smooth.
 | 
			
		||||
    */
 | 
			
		||||
    PathFlatteningIterator (const Path& path,
 | 
			
		||||
                            const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                            float tolerance = Path::defaultToleranceForMeasurement);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~PathFlatteningIterator();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Fetches the next line segment from the path.
 | 
			
		||||
 | 
			
		||||
        This will update the member variables x1, y1, x2, y2, subPathIndex and closesSubPath
 | 
			
		||||
        so that they describe the new line segment.
 | 
			
		||||
 | 
			
		||||
        @returns false when there are no more lines to fetch.
 | 
			
		||||
    */
 | 
			
		||||
    bool next();
 | 
			
		||||
 | 
			
		||||
    float x1;  /**< The x position of the start of the current line segment. */
 | 
			
		||||
    float y1;  /**< The y position of the start of the current line segment. */
 | 
			
		||||
    float x2;  /**< The x position of the end of the current line segment. */
 | 
			
		||||
    float y2;  /**< The y position of the end of the current line segment. */
 | 
			
		||||
 | 
			
		||||
    /** Indicates whether the current line segment is closing a sub-path.
 | 
			
		||||
 | 
			
		||||
        If the current line is the one that connects the end of a sub-path
 | 
			
		||||
        back to the start again, this will be true.
 | 
			
		||||
    */
 | 
			
		||||
    bool closesSubPath;
 | 
			
		||||
 | 
			
		||||
    /** The index of the current line within the current sub-path.
 | 
			
		||||
 | 
			
		||||
        E.g. you can use this to see whether the line is the first one in the
 | 
			
		||||
        subpath by seeing if it's 0.
 | 
			
		||||
    */
 | 
			
		||||
    int subPathIndex;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the current segment is the last in the current sub-path. */
 | 
			
		||||
    bool isLastInSubpath() const noexcept;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    const Path& path;
 | 
			
		||||
    const AffineTransform transform;
 | 
			
		||||
    const float* source;
 | 
			
		||||
    const float toleranceSquared;
 | 
			
		||||
    float subPathCloseX = 0, subPathCloseY = 0;
 | 
			
		||||
    const bool isIdentityTransform;
 | 
			
		||||
 | 
			
		||||
    HeapBlock<float> stackBase { 32 };
 | 
			
		||||
    float* stackPos;
 | 
			
		||||
    size_t stackSize = 32;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathFlatteningIterator)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Flattens a Path object into a series of straight-line sections.
 | 
			
		||||
 | 
			
		||||
    Use one of these to iterate through a Path object, and it will convert
 | 
			
		||||
    all the curves into line sections so it's easy to render or perform
 | 
			
		||||
    geometric operations on.
 | 
			
		||||
 | 
			
		||||
    @see Path
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  PathFlatteningIterator  final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a PathFlatteningIterator.
 | 
			
		||||
 | 
			
		||||
        After creation, use the next() method to initialise the fields in the
 | 
			
		||||
        object with the first line's position.
 | 
			
		||||
 | 
			
		||||
        @param path         the path to iterate along
 | 
			
		||||
        @param transform    a transform to apply to each point in the path being iterated
 | 
			
		||||
        @param tolerance    the amount by which the curves are allowed to deviate from the lines
 | 
			
		||||
                            into which they are being broken down - a higher tolerance contains
 | 
			
		||||
                            less lines, so can be generated faster, but will be less smooth.
 | 
			
		||||
    */
 | 
			
		||||
    PathFlatteningIterator (const Path& path,
 | 
			
		||||
                            const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                            float tolerance = Path::defaultToleranceForMeasurement);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~PathFlatteningIterator();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Fetches the next line segment from the path.
 | 
			
		||||
 | 
			
		||||
        This will update the member variables x1, y1, x2, y2, subPathIndex and closesSubPath
 | 
			
		||||
        so that they describe the new line segment.
 | 
			
		||||
 | 
			
		||||
        @returns false when there are no more lines to fetch.
 | 
			
		||||
    */
 | 
			
		||||
    bool next();
 | 
			
		||||
 | 
			
		||||
    float x1;  /**< The x position of the start of the current line segment. */
 | 
			
		||||
    float y1;  /**< The y position of the start of the current line segment. */
 | 
			
		||||
    float x2;  /**< The x position of the end of the current line segment. */
 | 
			
		||||
    float y2;  /**< The y position of the end of the current line segment. */
 | 
			
		||||
 | 
			
		||||
    /** Indicates whether the current line segment is closing a sub-path.
 | 
			
		||||
 | 
			
		||||
        If the current line is the one that connects the end of a sub-path
 | 
			
		||||
        back to the start again, this will be true.
 | 
			
		||||
    */
 | 
			
		||||
    bool closesSubPath;
 | 
			
		||||
 | 
			
		||||
    /** The index of the current line within the current sub-path.
 | 
			
		||||
 | 
			
		||||
        E.g. you can use this to see whether the line is the first one in the
 | 
			
		||||
        subpath by seeing if it's 0.
 | 
			
		||||
    */
 | 
			
		||||
    int subPathIndex;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the current segment is the last in the current sub-path. */
 | 
			
		||||
    bool isLastInSubpath() const noexcept;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    const Path& path;
 | 
			
		||||
    const AffineTransform transform;
 | 
			
		||||
    const float* source;
 | 
			
		||||
    const float toleranceSquared;
 | 
			
		||||
    float subPathCloseX = 0, subPathCloseY = 0;
 | 
			
		||||
    const bool isIdentityTransform;
 | 
			
		||||
 | 
			
		||||
    HeapBlock<float> stackBase { 32 };
 | 
			
		||||
    float* stackPos;
 | 
			
		||||
    size_t stackSize = 32;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathFlatteningIterator)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,206 +1,206 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Describes a type of stroke used to render a solid outline along a path.
 | 
			
		||||
 | 
			
		||||
    A PathStrokeType object can be used directly to create the shape of an outline
 | 
			
		||||
    around a path, and is used by Graphics::strokePath to specify the type of
 | 
			
		||||
    stroke to draw.
 | 
			
		||||
 | 
			
		||||
    @see Path, Graphics::strokePath
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  PathStrokeType
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The type of shape to use for the corners between two adjacent line segments. */
 | 
			
		||||
    enum JointStyle
 | 
			
		||||
    {
 | 
			
		||||
        mitered,    /**< Indicates that corners should be drawn with sharp joints.
 | 
			
		||||
                         Note that for angles that curve back on themselves, drawing a
 | 
			
		||||
                         mitre could require extending the point too far away from the
 | 
			
		||||
                         path, so a mitre limit is imposed and any corners that exceed it
 | 
			
		||||
                         are drawn as bevelled instead. */
 | 
			
		||||
        curved,     /**< Indicates that corners should be drawn as rounded-off. */
 | 
			
		||||
        beveled     /**< Indicates that corners should be drawn with a line flattening their
 | 
			
		||||
                         outside edge. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** The type shape to use for the ends of lines. */
 | 
			
		||||
    enum EndCapStyle
 | 
			
		||||
    {
 | 
			
		||||
        butt,       /**< Ends of lines are flat and don't extend beyond the end point. */
 | 
			
		||||
        square,     /**< Ends of lines are flat, but stick out beyond the end point for half
 | 
			
		||||
                         the thickness of the stroke. */
 | 
			
		||||
        rounded     /**< Ends of lines are rounded-off with a circular shape. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a stroke type with a given line-width, and default joint/end styles. */
 | 
			
		||||
    explicit PathStrokeType (float strokeThickness) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates a stroke type.
 | 
			
		||||
 | 
			
		||||
        @param strokeThickness      the width of the line to use
 | 
			
		||||
        @param jointStyle           the type of joints to use for corners
 | 
			
		||||
        @param endStyle             the type of end-caps to use for the ends of open paths.
 | 
			
		||||
    */
 | 
			
		||||
    PathStrokeType (float strokeThickness,
 | 
			
		||||
                    JointStyle jointStyle,
 | 
			
		||||
                    EndCapStyle endStyle = butt) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another stroke type. */
 | 
			
		||||
    PathStrokeType (const PathStrokeType&) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Copies another stroke onto this one. */
 | 
			
		||||
    PathStrokeType& operator= (const PathStrokeType&) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~PathStrokeType() noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies this stroke type to a path and returns the resultant stroke as another Path.
 | 
			
		||||
 | 
			
		||||
        @param destPath         the resultant stroked outline shape will be copied into this path.
 | 
			
		||||
                                Note that it's ok for the source and destination Paths to be
 | 
			
		||||
                                the same object, so you can easily turn a path into a stroked version
 | 
			
		||||
                                of itself.
 | 
			
		||||
        @param sourcePath       the path to use as the source
 | 
			
		||||
        @param transform        an optional transform to apply to the points from the source path
 | 
			
		||||
                                as they are being used
 | 
			
		||||
        @param extraAccuracy    if this is greater than 1.0, it will subdivide the path to
 | 
			
		||||
                                a higher resolution, which improves the quality if you'll later want
 | 
			
		||||
                                to enlarge the stroked path. So for example, if you're planning on drawing
 | 
			
		||||
                                the stroke at 3x the size that you're creating it, you should set this to 3.
 | 
			
		||||
 | 
			
		||||
        @see createDashedStroke
 | 
			
		||||
    */
 | 
			
		||||
    void createStrokedPath (Path& destPath,
 | 
			
		||||
                            const Path& sourcePath,
 | 
			
		||||
                            const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                            float extraAccuracy = 1.0f) const;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies this stroke type to a path, creating a dashed line.
 | 
			
		||||
 | 
			
		||||
        This is similar to createStrokedPath, but uses the array passed in to
 | 
			
		||||
        break the stroke up into a series of dashes.
 | 
			
		||||
 | 
			
		||||
        @param destPath         the resultant stroked outline shape will be copied into this path.
 | 
			
		||||
                                Note that it's ok for the source and destination Paths to be
 | 
			
		||||
                                the same object, so you can easily turn a path into a stroked version
 | 
			
		||||
                                of itself.
 | 
			
		||||
        @param sourcePath       the path to use as the source
 | 
			
		||||
        @param dashLengths      An array of alternating on/off lengths. E.g. { 2, 3, 4, 5 } will create
 | 
			
		||||
                                a line of length 2, then skip a length of 3, then add a line of length 4,
 | 
			
		||||
                                skip 5, and keep repeating this pattern.
 | 
			
		||||
        @param numDashLengths   The number of lengths in the dashLengths array. This should really be
 | 
			
		||||
                                an even number, otherwise the pattern will get out of step as it
 | 
			
		||||
                                repeats.
 | 
			
		||||
        @param transform        an optional transform to apply to the points from the source path
 | 
			
		||||
                                as they are being used
 | 
			
		||||
        @param extraAccuracy    if this is greater than 1.0, it will subdivide the path to
 | 
			
		||||
                                a higher resolution, which improves the quality if you'll later want
 | 
			
		||||
                                to enlarge the stroked path. So for example, if you're planning on drawing
 | 
			
		||||
                                the stroke at 3x the size that you're creating it, you should set this to 3.
 | 
			
		||||
    */
 | 
			
		||||
    void createDashedStroke (Path& destPath,
 | 
			
		||||
                             const Path& sourcePath,
 | 
			
		||||
                             const float* dashLengths,
 | 
			
		||||
                             int numDashLengths,
 | 
			
		||||
                             const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                             float extraAccuracy = 1.0f) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies this stroke type to a path and returns the resultant stroke as another Path.
 | 
			
		||||
 | 
			
		||||
        @param destPath             the resultant stroked outline shape will be copied into this path.
 | 
			
		||||
                                    Note that it's ok for the source and destination Paths to be
 | 
			
		||||
                                    the same object, so you can easily turn a path into a stroked version
 | 
			
		||||
                                    of itself.
 | 
			
		||||
        @param sourcePath           the path to use as the source
 | 
			
		||||
        @param arrowheadStartWidth  the width of the arrowhead at the start of the path
 | 
			
		||||
        @param arrowheadStartLength the length of the arrowhead at the start of the path
 | 
			
		||||
        @param arrowheadEndWidth    the width of the arrowhead at the end of the path
 | 
			
		||||
        @param arrowheadEndLength   the length of the arrowhead at the end of the path
 | 
			
		||||
        @param transform            an optional transform to apply to the points from the source path
 | 
			
		||||
                                    as they are being used
 | 
			
		||||
        @param extraAccuracy        if this is greater than 1.0, it will subdivide the path to
 | 
			
		||||
                                    a higher resolution, which improves the quality if you'll later want
 | 
			
		||||
                                    to enlarge the stroked path. So for example, if you're planning on drawing
 | 
			
		||||
                                    the stroke at 3x the size that you're creating it, you should set this to 3.
 | 
			
		||||
        @see createDashedStroke
 | 
			
		||||
    */
 | 
			
		||||
    void createStrokeWithArrowheads (Path& destPath,
 | 
			
		||||
                                     const Path& sourcePath,
 | 
			
		||||
                                     float arrowheadStartWidth, float arrowheadStartLength,
 | 
			
		||||
                                     float arrowheadEndWidth, float arrowheadEndLength,
 | 
			
		||||
                                     const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                                     float extraAccuracy = 1.0f) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the stroke thickness. */
 | 
			
		||||
    float getStrokeThickness() const noexcept                   { return thickness; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the stroke thickness. */
 | 
			
		||||
    void setStrokeThickness (float newThickness) noexcept       { thickness = newThickness; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the joint style. */
 | 
			
		||||
    JointStyle getJointStyle() const noexcept                   { return jointStyle; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the joint style. */
 | 
			
		||||
    void setJointStyle (JointStyle newStyle) noexcept           { jointStyle = newStyle; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the end-cap style. */
 | 
			
		||||
    EndCapStyle getEndStyle() const noexcept                    { return endStyle; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the end-cap style. */
 | 
			
		||||
    void setEndStyle (EndCapStyle newStyle) noexcept            { endStyle = newStyle; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Compares the stroke thickness, joint and end styles of two stroke types. */
 | 
			
		||||
    bool operator== (const PathStrokeType&) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Compares the stroke thickness, joint and end styles of two stroke types. */
 | 
			
		||||
    bool operator!= (const PathStrokeType&) const noexcept;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    float thickness;
 | 
			
		||||
    JointStyle jointStyle;
 | 
			
		||||
    EndCapStyle endStyle;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (PathStrokeType)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Describes a type of stroke used to render a solid outline along a path.
 | 
			
		||||
 | 
			
		||||
    A PathStrokeType object can be used directly to create the shape of an outline
 | 
			
		||||
    around a path, and is used by Graphics::strokePath to specify the type of
 | 
			
		||||
    stroke to draw.
 | 
			
		||||
 | 
			
		||||
    @see Path, Graphics::strokePath
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  PathStrokeType
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The type of shape to use for the corners between two adjacent line segments. */
 | 
			
		||||
    enum JointStyle
 | 
			
		||||
    {
 | 
			
		||||
        mitered,    /**< Indicates that corners should be drawn with sharp joints.
 | 
			
		||||
                         Note that for angles that curve back on themselves, drawing a
 | 
			
		||||
                         mitre could require extending the point too far away from the
 | 
			
		||||
                         path, so a mitre limit is imposed and any corners that exceed it
 | 
			
		||||
                         are drawn as bevelled instead. */
 | 
			
		||||
        curved,     /**< Indicates that corners should be drawn as rounded-off. */
 | 
			
		||||
        beveled     /**< Indicates that corners should be drawn with a line flattening their
 | 
			
		||||
                         outside edge. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** The type shape to use for the ends of lines. */
 | 
			
		||||
    enum EndCapStyle
 | 
			
		||||
    {
 | 
			
		||||
        butt,       /**< Ends of lines are flat and don't extend beyond the end point. */
 | 
			
		||||
        square,     /**< Ends of lines are flat, but stick out beyond the end point for half
 | 
			
		||||
                         the thickness of the stroke. */
 | 
			
		||||
        rounded     /**< Ends of lines are rounded-off with a circular shape. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a stroke type with a given line-width, and default joint/end styles. */
 | 
			
		||||
    explicit PathStrokeType (float strokeThickness) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates a stroke type.
 | 
			
		||||
 | 
			
		||||
        @param strokeThickness      the width of the line to use
 | 
			
		||||
        @param jointStyle           the type of joints to use for corners
 | 
			
		||||
        @param endStyle             the type of end-caps to use for the ends of open paths.
 | 
			
		||||
    */
 | 
			
		||||
    PathStrokeType (float strokeThickness,
 | 
			
		||||
                    JointStyle jointStyle,
 | 
			
		||||
                    EndCapStyle endStyle = butt) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another stroke type. */
 | 
			
		||||
    PathStrokeType (const PathStrokeType&) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Copies another stroke onto this one. */
 | 
			
		||||
    PathStrokeType& operator= (const PathStrokeType&) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~PathStrokeType() noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies this stroke type to a path and returns the resultant stroke as another Path.
 | 
			
		||||
 | 
			
		||||
        @param destPath         the resultant stroked outline shape will be copied into this path.
 | 
			
		||||
                                Note that it's ok for the source and destination Paths to be
 | 
			
		||||
                                the same object, so you can easily turn a path into a stroked version
 | 
			
		||||
                                of itself.
 | 
			
		||||
        @param sourcePath       the path to use as the source
 | 
			
		||||
        @param transform        an optional transform to apply to the points from the source path
 | 
			
		||||
                                as they are being used
 | 
			
		||||
        @param extraAccuracy    if this is greater than 1.0, it will subdivide the path to
 | 
			
		||||
                                a higher resolution, which improves the quality if you'll later want
 | 
			
		||||
                                to enlarge the stroked path. So for example, if you're planning on drawing
 | 
			
		||||
                                the stroke at 3x the size that you're creating it, you should set this to 3.
 | 
			
		||||
 | 
			
		||||
        @see createDashedStroke
 | 
			
		||||
    */
 | 
			
		||||
    void createStrokedPath (Path& destPath,
 | 
			
		||||
                            const Path& sourcePath,
 | 
			
		||||
                            const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                            float extraAccuracy = 1.0f) const;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies this stroke type to a path, creating a dashed line.
 | 
			
		||||
 | 
			
		||||
        This is similar to createStrokedPath, but uses the array passed in to
 | 
			
		||||
        break the stroke up into a series of dashes.
 | 
			
		||||
 | 
			
		||||
        @param destPath         the resultant stroked outline shape will be copied into this path.
 | 
			
		||||
                                Note that it's ok for the source and destination Paths to be
 | 
			
		||||
                                the same object, so you can easily turn a path into a stroked version
 | 
			
		||||
                                of itself.
 | 
			
		||||
        @param sourcePath       the path to use as the source
 | 
			
		||||
        @param dashLengths      An array of alternating on/off lengths. E.g. { 2, 3, 4, 5 } will create
 | 
			
		||||
                                a line of length 2, then skip a length of 3, then add a line of length 4,
 | 
			
		||||
                                skip 5, and keep repeating this pattern.
 | 
			
		||||
        @param numDashLengths   The number of lengths in the dashLengths array. This should really be
 | 
			
		||||
                                an even number, otherwise the pattern will get out of step as it
 | 
			
		||||
                                repeats.
 | 
			
		||||
        @param transform        an optional transform to apply to the points from the source path
 | 
			
		||||
                                as they are being used
 | 
			
		||||
        @param extraAccuracy    if this is greater than 1.0, it will subdivide the path to
 | 
			
		||||
                                a higher resolution, which improves the quality if you'll later want
 | 
			
		||||
                                to enlarge the stroked path. So for example, if you're planning on drawing
 | 
			
		||||
                                the stroke at 3x the size that you're creating it, you should set this to 3.
 | 
			
		||||
    */
 | 
			
		||||
    void createDashedStroke (Path& destPath,
 | 
			
		||||
                             const Path& sourcePath,
 | 
			
		||||
                             const float* dashLengths,
 | 
			
		||||
                             int numDashLengths,
 | 
			
		||||
                             const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                             float extraAccuracy = 1.0f) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies this stroke type to a path and returns the resultant stroke as another Path.
 | 
			
		||||
 | 
			
		||||
        @param destPath             the resultant stroked outline shape will be copied into this path.
 | 
			
		||||
                                    Note that it's ok for the source and destination Paths to be
 | 
			
		||||
                                    the same object, so you can easily turn a path into a stroked version
 | 
			
		||||
                                    of itself.
 | 
			
		||||
        @param sourcePath           the path to use as the source
 | 
			
		||||
        @param arrowheadStartWidth  the width of the arrowhead at the start of the path
 | 
			
		||||
        @param arrowheadStartLength the length of the arrowhead at the start of the path
 | 
			
		||||
        @param arrowheadEndWidth    the width of the arrowhead at the end of the path
 | 
			
		||||
        @param arrowheadEndLength   the length of the arrowhead at the end of the path
 | 
			
		||||
        @param transform            an optional transform to apply to the points from the source path
 | 
			
		||||
                                    as they are being used
 | 
			
		||||
        @param extraAccuracy        if this is greater than 1.0, it will subdivide the path to
 | 
			
		||||
                                    a higher resolution, which improves the quality if you'll later want
 | 
			
		||||
                                    to enlarge the stroked path. So for example, if you're planning on drawing
 | 
			
		||||
                                    the stroke at 3x the size that you're creating it, you should set this to 3.
 | 
			
		||||
        @see createDashedStroke
 | 
			
		||||
    */
 | 
			
		||||
    void createStrokeWithArrowheads (Path& destPath,
 | 
			
		||||
                                     const Path& sourcePath,
 | 
			
		||||
                                     float arrowheadStartWidth, float arrowheadStartLength,
 | 
			
		||||
                                     float arrowheadEndWidth, float arrowheadEndLength,
 | 
			
		||||
                                     const AffineTransform& transform = AffineTransform(),
 | 
			
		||||
                                     float extraAccuracy = 1.0f) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the stroke thickness. */
 | 
			
		||||
    float getStrokeThickness() const noexcept                   { return thickness; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the stroke thickness. */
 | 
			
		||||
    void setStrokeThickness (float newThickness) noexcept       { thickness = newThickness; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the joint style. */
 | 
			
		||||
    JointStyle getJointStyle() const noexcept                   { return jointStyle; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the joint style. */
 | 
			
		||||
    void setJointStyle (JointStyle newStyle) noexcept           { jointStyle = newStyle; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the end-cap style. */
 | 
			
		||||
    EndCapStyle getEndStyle() const noexcept                    { return endStyle; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the end-cap style. */
 | 
			
		||||
    void setEndStyle (EndCapStyle newStyle) noexcept            { endStyle = newStyle; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Compares the stroke thickness, joint and end styles of two stroke types. */
 | 
			
		||||
    bool operator== (const PathStrokeType&) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Compares the stroke thickness, joint and end styles of two stroke types. */
 | 
			
		||||
    bool operator!= (const PathStrokeType&) const noexcept;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    float thickness;
 | 
			
		||||
    JointStyle jointStyle;
 | 
			
		||||
    EndCapStyle endStyle;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (PathStrokeType)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,254 +1,254 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A pair of (x, y) coordinates.
 | 
			
		||||
 | 
			
		||||
    The ValueType template should be a primitive type such as int, float, double,
 | 
			
		||||
    rather than a class.
 | 
			
		||||
 | 
			
		||||
    @see Line, Path, AffineTransform
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class Point
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Creates a point at the origin */
 | 
			
		||||
    constexpr Point() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another point. */
 | 
			
		||||
    constexpr Point (const Point&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a point from an (x, y) position. */
 | 
			
		||||
    constexpr Point (ValueType initialX, ValueType initialY) noexcept : x (initialX), y (initialY) {}
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Copies this point from another one. */
 | 
			
		||||
    Point& operator= (const Point&) = default;
 | 
			
		||||
 | 
			
		||||
    constexpr inline bool operator== (Point other) const noexcept      { return x == other.x && y == other.y; }
 | 
			
		||||
    constexpr inline bool operator!= (Point other) const noexcept      { return x != other.x || y != other.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the point is (0, 0). */
 | 
			
		||||
    constexpr bool isOrigin() const noexcept                           { return x == ValueType() && y == ValueType(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the coordinates are finite values. */
 | 
			
		||||
    constexpr inline bool isFinite() const noexcept                    { return juce_isfinite(x) && juce_isfinite(y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point's x coordinate. */
 | 
			
		||||
    constexpr inline ValueType getX() const noexcept                   { return x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point's y coordinate. */
 | 
			
		||||
    constexpr inline ValueType getY() const noexcept                   { return y; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the point's x coordinate. */
 | 
			
		||||
    inline void setX (ValueType newX) noexcept                         { x = newX; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the point's y coordinate. */
 | 
			
		||||
    inline void setY (ValueType newY) noexcept                         { y = newY; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point which has the same Y position as this one, but a new X. */
 | 
			
		||||
    constexpr Point withX (ValueType newX) const noexcept              { return Point (newX, y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point which has the same X position as this one, but a new Y. */
 | 
			
		||||
    constexpr Point withY (ValueType newY) const noexcept              { return Point (x, newY); }
 | 
			
		||||
 | 
			
		||||
    /** Changes the point's x and y coordinates. */
 | 
			
		||||
    void setXY (ValueType newX, ValueType newY) noexcept               { x = newX; y = newY; }
 | 
			
		||||
 | 
			
		||||
    /** Adds a pair of coordinates to this value. */
 | 
			
		||||
    void addXY (ValueType xToAdd, ValueType yToAdd) noexcept           { x += xToAdd; y += yToAdd; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a point with a given offset from this one. */
 | 
			
		||||
    constexpr Point translated (ValueType deltaX, ValueType deltaY) const noexcept    { return Point (x + deltaX, y + deltaY); }
 | 
			
		||||
 | 
			
		||||
    /** Adds two points together */
 | 
			
		||||
    constexpr Point operator+ (Point other) const noexcept             { return Point (x + other.x, y + other.y); }
 | 
			
		||||
 | 
			
		||||
    /** Adds another point's coordinates to this one */
 | 
			
		||||
    Point& operator+= (Point other) noexcept                           { x += other.x; y += other.y; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Subtracts one points from another */
 | 
			
		||||
    constexpr Point operator- (Point other) const noexcept             { return Point (x - other.x, y - other.y); }
 | 
			
		||||
 | 
			
		||||
    /** Subtracts another point's coordinates to this one */
 | 
			
		||||
    Point& operator-= (Point other) noexcept                           { x -= other.x; y -= other.y; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies two points together */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator* (Point<OtherType> other) const noexcept  { return Point ((ValueType) (x * other.x), (ValueType) (y * other.y)); }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies another point's coordinates to this one */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    Point& operator*= (Point<OtherType> other) noexcept                { *this = *this * other; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Divides one point by another */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator/ (Point<OtherType> other) const noexcept  { return Point ((ValueType) (x / other.x), (ValueType) (y / other.y)); }
 | 
			
		||||
 | 
			
		||||
    /** Divides this point's coordinates by another */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    Point& operator/= (Point<OtherType> other) noexcept                { *this = *this / other; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point whose coordinates are multiplied by a given scalar value. */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator* (OtherType multiplier) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        using CommonType = typename std::common_type<ValueType, OtherType>::type;
 | 
			
		||||
        return Point ((ValueType) ((CommonType) x * (CommonType) multiplier),
 | 
			
		||||
                      (ValueType) ((CommonType) y * (CommonType) multiplier));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point whose coordinates are divided by a given scalar value. */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator/ (OtherType divisor) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        using CommonType = typename std::common_type<ValueType, OtherType>::type;
 | 
			
		||||
        return Point ((ValueType) ((CommonType) x / (CommonType) divisor),
 | 
			
		||||
                      (ValueType) ((CommonType) y / (CommonType) divisor));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies the point's coordinates by a scalar value. */
 | 
			
		||||
    template <typename FloatType>
 | 
			
		||||
    Point& operator*= (FloatType multiplier) noexcept                  { x = (ValueType) (x * multiplier); y = (ValueType) (y * multiplier); return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Divides the point's coordinates by a scalar value. */
 | 
			
		||||
    template <typename FloatType>
 | 
			
		||||
    Point& operator/= (FloatType divisor) noexcept                     { x = (ValueType) (x / divisor); y = (ValueType) (y / divisor); return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the inverse of this point. */
 | 
			
		||||
    constexpr Point operator-() const noexcept                         { return Point (-x, -y); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This type will be double if the Point's type is double, otherwise it will be float. */
 | 
			
		||||
    using FloatType = typename TypeHelpers::SmallestFloatType<ValueType>::type;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the straight-line distance between this point and the origin. */
 | 
			
		||||
    ValueType getDistanceFromOrigin() const noexcept                          { return juce_hypot (x, y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the straight-line distance between this point and another one. */
 | 
			
		||||
    ValueType getDistanceFrom (Point other) const noexcept                    { return juce_hypot (x - other.x, y - other.y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the square of the straight-line distance between this point and the origin. */
 | 
			
		||||
    constexpr ValueType getDistanceSquaredFromOrigin() const noexcept         { return x * x + y * y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the square of the straight-line distance between this point and another one. */
 | 
			
		||||
    constexpr ValueType getDistanceSquaredFrom (Point other) const noexcept   { return (*this - other).getDistanceSquaredFromOrigin(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the angle from this point to another one.
 | 
			
		||||
 | 
			
		||||
        Taking this point to be the centre of a circle, and the other point being a position on
 | 
			
		||||
        the circumference, the return value is the number of radians clockwise from the 12 o'clock
 | 
			
		||||
        direction.
 | 
			
		||||
        So 12 o'clock = 0, 3 o'clock = Pi/2, 6 o'clock = Pi, 9 o'clock = -Pi/2
 | 
			
		||||
    */
 | 
			
		||||
    FloatType getAngleToPoint (Point other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<FloatType> (std::atan2 (static_cast<FloatType> (other.x - x),
 | 
			
		||||
                                                   static_cast<FloatType> (y - other.y)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point that would be reached by rotating this point clockwise
 | 
			
		||||
        about the origin by the specified angle.
 | 
			
		||||
    */
 | 
			
		||||
    Point rotatedAboutOrigin (ValueType angleRadians) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point (x * std::cos (angleRadians) - y * std::sin (angleRadians),
 | 
			
		||||
                      x * std::sin (angleRadians) + y * std::cos (angleRadians));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Taking this point to be the centre of a circle, this returns a point on its circumference.
 | 
			
		||||
        @param radius   the radius of the circle.
 | 
			
		||||
        @param angle    the angle of the point, in radians clockwise from the 12 o'clock position.
 | 
			
		||||
    */
 | 
			
		||||
    Point<FloatType> getPointOnCircumference (float radius, float angle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point<FloatType> (static_cast<FloatType> (x + radius * std::sin (angle)),
 | 
			
		||||
                                 static_cast<FloatType> (y - radius * std::cos (angle)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Taking this point to be the centre of an ellipse, this returns a point on its circumference.
 | 
			
		||||
        @param radiusX  the horizontal radius of the circle.
 | 
			
		||||
        @param radiusY  the vertical radius of the circle.
 | 
			
		||||
        @param angle    the angle of the point, in radians clockwise from the 12 o'clock position.
 | 
			
		||||
    */
 | 
			
		||||
    Point<FloatType> getPointOnCircumference (float radiusX, float radiusY, float angle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point<FloatType> (static_cast<FloatType> (x + radiusX * std::sin (angle)),
 | 
			
		||||
                                 static_cast<FloatType> (y - radiusY * std::cos (angle)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the dot-product of two points (x1 * x2 + y1 * y2). */
 | 
			
		||||
    constexpr FloatType getDotProduct (Point other) const noexcept     { return x * other.x + y * other.y; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Uses a transform to change the point's coordinates.
 | 
			
		||||
        This will only compile if ValueType = float!
 | 
			
		||||
 | 
			
		||||
        @see AffineTransform::transformPoint
 | 
			
		||||
    */
 | 
			
		||||
    void applyTransform (const AffineTransform& transform) noexcept     { transform.transformPoint (x, y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the position of this point, if it is transformed by a given AffineTransform. */
 | 
			
		||||
    Point transformedBy (const AffineTransform& transform) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point (static_cast<ValueType> (transform.mat00 * (float) x + transform.mat01 * (float) y + transform.mat02),
 | 
			
		||||
                      static_cast<ValueType> (transform.mat10 * (float) x + transform.mat11 * (float) y + transform.mat12));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Casts this point to a Point<int> object. */
 | 
			
		||||
    constexpr Point<int> toInt() const noexcept              { return Point<int> (static_cast<int> (x), static_cast<int> (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Casts this point to a Point<float> object. */
 | 
			
		||||
    constexpr Point<float> toFloat() const noexcept          { return Point<float> (static_cast<float> (x), static_cast<float> (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Casts this point to a Point<double> object. */
 | 
			
		||||
    constexpr Point<double> toDouble() const noexcept        { return Point<double> (static_cast<double> (x), static_cast<double> (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Casts this point to a Point<int> object using roundToInt() to convert the values. */
 | 
			
		||||
    constexpr Point<int> roundToInt() const noexcept         { return Point<int> (juce::roundToInt (x), juce::roundToInt (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point as a string in the form "x, y". */
 | 
			
		||||
    String toString() const                                       { return String (x) + ", " + String (y); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ValueType x{}; /**< The point's X coordinate. */
 | 
			
		||||
    ValueType y{}; /**< The point's Y coordinate. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Multiplies the point's coordinates by a scalar value. */
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
Point<ValueType> operator* (ValueType value, Point<ValueType> p) noexcept       { return p * value; }
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A pair of (x, y) coordinates.
 | 
			
		||||
 | 
			
		||||
    The ValueType template should be a primitive type such as int, float, double,
 | 
			
		||||
    rather than a class.
 | 
			
		||||
 | 
			
		||||
    @see Line, Path, AffineTransform
 | 
			
		||||
 | 
			
		||||
    @tags{Graphics}
 | 
			
		||||
*/
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
class Point
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Creates a point at the origin */
 | 
			
		||||
    constexpr Point() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a copy of another point. */
 | 
			
		||||
    constexpr Point (const Point&) = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a point from an (x, y) position. */
 | 
			
		||||
    constexpr Point (ValueType initialX, ValueType initialY) noexcept : x (initialX), y (initialY) {}
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Copies this point from another one. */
 | 
			
		||||
    Point& operator= (const Point&) = default;
 | 
			
		||||
 | 
			
		||||
    constexpr inline bool operator== (Point other) const noexcept      { return x == other.x && y == other.y; }
 | 
			
		||||
    constexpr inline bool operator!= (Point other) const noexcept      { return x != other.x || y != other.y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the point is (0, 0). */
 | 
			
		||||
    constexpr bool isOrigin() const noexcept                           { return x == ValueType() && y == ValueType(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the coordinates are finite values. */
 | 
			
		||||
    constexpr inline bool isFinite() const noexcept                    { return juce_isfinite(x) && juce_isfinite(y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point's x coordinate. */
 | 
			
		||||
    constexpr inline ValueType getX() const noexcept                   { return x; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point's y coordinate. */
 | 
			
		||||
    constexpr inline ValueType getY() const noexcept                   { return y; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the point's x coordinate. */
 | 
			
		||||
    inline void setX (ValueType newX) noexcept                         { x = newX; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the point's y coordinate. */
 | 
			
		||||
    inline void setY (ValueType newY) noexcept                         { y = newY; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point which has the same Y position as this one, but a new X. */
 | 
			
		||||
    constexpr Point withX (ValueType newX) const noexcept              { return Point (newX, y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point which has the same X position as this one, but a new Y. */
 | 
			
		||||
    constexpr Point withY (ValueType newY) const noexcept              { return Point (x, newY); }
 | 
			
		||||
 | 
			
		||||
    /** Changes the point's x and y coordinates. */
 | 
			
		||||
    void setXY (ValueType newX, ValueType newY) noexcept               { x = newX; y = newY; }
 | 
			
		||||
 | 
			
		||||
    /** Adds a pair of coordinates to this value. */
 | 
			
		||||
    void addXY (ValueType xToAdd, ValueType yToAdd) noexcept           { x += xToAdd; y += yToAdd; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a point with a given offset from this one. */
 | 
			
		||||
    constexpr Point translated (ValueType deltaX, ValueType deltaY) const noexcept    { return Point (x + deltaX, y + deltaY); }
 | 
			
		||||
 | 
			
		||||
    /** Adds two points together */
 | 
			
		||||
    constexpr Point operator+ (Point other) const noexcept             { return Point (x + other.x, y + other.y); }
 | 
			
		||||
 | 
			
		||||
    /** Adds another point's coordinates to this one */
 | 
			
		||||
    Point& operator+= (Point other) noexcept                           { x += other.x; y += other.y; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Subtracts one points from another */
 | 
			
		||||
    constexpr Point operator- (Point other) const noexcept             { return Point (x - other.x, y - other.y); }
 | 
			
		||||
 | 
			
		||||
    /** Subtracts another point's coordinates to this one */
 | 
			
		||||
    Point& operator-= (Point other) noexcept                           { x -= other.x; y -= other.y; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies two points together */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator* (Point<OtherType> other) const noexcept  { return Point ((ValueType) (x * other.x), (ValueType) (y * other.y)); }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies another point's coordinates to this one */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    Point& operator*= (Point<OtherType> other) noexcept                { *this = *this * other; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Divides one point by another */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator/ (Point<OtherType> other) const noexcept  { return Point ((ValueType) (x / other.x), (ValueType) (y / other.y)); }
 | 
			
		||||
 | 
			
		||||
    /** Divides this point's coordinates by another */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    Point& operator/= (Point<OtherType> other) noexcept                { *this = *this / other; return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point whose coordinates are multiplied by a given scalar value. */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator* (OtherType multiplier) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        using CommonType = typename std::common_type<ValueType, OtherType>::type;
 | 
			
		||||
        return Point ((ValueType) ((CommonType) x * (CommonType) multiplier),
 | 
			
		||||
                      (ValueType) ((CommonType) y * (CommonType) multiplier));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns a point whose coordinates are divided by a given scalar value. */
 | 
			
		||||
    template <typename OtherType>
 | 
			
		||||
    constexpr Point operator/ (OtherType divisor) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        using CommonType = typename std::common_type<ValueType, OtherType>::type;
 | 
			
		||||
        return Point ((ValueType) ((CommonType) x / (CommonType) divisor),
 | 
			
		||||
                      (ValueType) ((CommonType) y / (CommonType) divisor));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Multiplies the point's coordinates by a scalar value. */
 | 
			
		||||
    template <typename FloatType>
 | 
			
		||||
    Point& operator*= (FloatType multiplier) noexcept                  { x = (ValueType) (x * multiplier); y = (ValueType) (y * multiplier); return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Divides the point's coordinates by a scalar value. */
 | 
			
		||||
    template <typename FloatType>
 | 
			
		||||
    Point& operator/= (FloatType divisor) noexcept                     { x = (ValueType) (x / divisor); y = (ValueType) (y / divisor); return *this; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the inverse of this point. */
 | 
			
		||||
    constexpr Point operator-() const noexcept                         { return Point (-x, -y); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This type will be double if the Point's type is double, otherwise it will be float. */
 | 
			
		||||
    using FloatType = typename TypeHelpers::SmallestFloatType<ValueType>::type;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the straight-line distance between this point and the origin. */
 | 
			
		||||
    ValueType getDistanceFromOrigin() const noexcept                          { return juce_hypot (x, y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the straight-line distance between this point and another one. */
 | 
			
		||||
    ValueType getDistanceFrom (Point other) const noexcept                    { return juce_hypot (x - other.x, y - other.y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the square of the straight-line distance between this point and the origin. */
 | 
			
		||||
    constexpr ValueType getDistanceSquaredFromOrigin() const noexcept         { return x * x + y * y; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the square of the straight-line distance between this point and another one. */
 | 
			
		||||
    constexpr ValueType getDistanceSquaredFrom (Point other) const noexcept   { return (*this - other).getDistanceSquaredFromOrigin(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the angle from this point to another one.
 | 
			
		||||
 | 
			
		||||
        Taking this point to be the centre of a circle, and the other point being a position on
 | 
			
		||||
        the circumference, the return value is the number of radians clockwise from the 12 o'clock
 | 
			
		||||
        direction.
 | 
			
		||||
        So 12 o'clock = 0, 3 o'clock = Pi/2, 6 o'clock = Pi, 9 o'clock = -Pi/2
 | 
			
		||||
    */
 | 
			
		||||
    FloatType getAngleToPoint (Point other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<FloatType> (std::atan2 (static_cast<FloatType> (other.x - x),
 | 
			
		||||
                                                   static_cast<FloatType> (y - other.y)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point that would be reached by rotating this point clockwise
 | 
			
		||||
        about the origin by the specified angle.
 | 
			
		||||
    */
 | 
			
		||||
    Point rotatedAboutOrigin (ValueType angleRadians) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point (x * std::cos (angleRadians) - y * std::sin (angleRadians),
 | 
			
		||||
                      x * std::sin (angleRadians) + y * std::cos (angleRadians));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Taking this point to be the centre of a circle, this returns a point on its circumference.
 | 
			
		||||
        @param radius   the radius of the circle.
 | 
			
		||||
        @param angle    the angle of the point, in radians clockwise from the 12 o'clock position.
 | 
			
		||||
    */
 | 
			
		||||
    Point<FloatType> getPointOnCircumference (float radius, float angle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point<FloatType> (static_cast<FloatType> (x + radius * std::sin (angle)),
 | 
			
		||||
                                 static_cast<FloatType> (y - radius * std::cos (angle)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Taking this point to be the centre of an ellipse, this returns a point on its circumference.
 | 
			
		||||
        @param radiusX  the horizontal radius of the circle.
 | 
			
		||||
        @param radiusY  the vertical radius of the circle.
 | 
			
		||||
        @param angle    the angle of the point, in radians clockwise from the 12 o'clock position.
 | 
			
		||||
    */
 | 
			
		||||
    Point<FloatType> getPointOnCircumference (float radiusX, float radiusY, float angle) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point<FloatType> (static_cast<FloatType> (x + radiusX * std::sin (angle)),
 | 
			
		||||
                                 static_cast<FloatType> (y - radiusY * std::cos (angle)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the dot-product of two points (x1 * x2 + y1 * y2). */
 | 
			
		||||
    constexpr FloatType getDotProduct (Point other) const noexcept     { return x * other.x + y * other.y; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Uses a transform to change the point's coordinates.
 | 
			
		||||
        This will only compile if ValueType = float!
 | 
			
		||||
 | 
			
		||||
        @see AffineTransform::transformPoint
 | 
			
		||||
    */
 | 
			
		||||
    void applyTransform (const AffineTransform& transform) noexcept     { transform.transformPoint (x, y); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the position of this point, if it is transformed by a given AffineTransform. */
 | 
			
		||||
    Point transformedBy (const AffineTransform& transform) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Point (static_cast<ValueType> (transform.mat00 * (float) x + transform.mat01 * (float) y + transform.mat02),
 | 
			
		||||
                      static_cast<ValueType> (transform.mat10 * (float) x + transform.mat11 * (float) y + transform.mat12));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Casts this point to a Point<int> object. */
 | 
			
		||||
    constexpr Point<int> toInt() const noexcept              { return Point<int> (static_cast<int> (x), static_cast<int> (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Casts this point to a Point<float> object. */
 | 
			
		||||
    constexpr Point<float> toFloat() const noexcept          { return Point<float> (static_cast<float> (x), static_cast<float> (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Casts this point to a Point<double> object. */
 | 
			
		||||
    constexpr Point<double> toDouble() const noexcept        { return Point<double> (static_cast<double> (x), static_cast<double> (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Casts this point to a Point<int> object using roundToInt() to convert the values. */
 | 
			
		||||
    constexpr Point<int> roundToInt() const noexcept         { return Point<int> (juce::roundToInt (x), juce::roundToInt (y)); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the point as a string in the form "x, y". */
 | 
			
		||||
    String toString() const                                       { return String (x) + ", " + String (y); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ValueType x{}; /**< The point's X coordinate. */
 | 
			
		||||
    ValueType y{}; /**< The point's Y coordinate. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Multiplies the point's coordinates by a scalar value. */
 | 
			
		||||
template <typename ValueType>
 | 
			
		||||
Point<ValueType> operator* (ValueType value, Point<ValueType> p) noexcept       { return p * value; }
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										51
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Rectangle_test.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								deps/juce/modules/juce_graphics/geometry/juce_Rectangle_test.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
struct RectangleUnitTest  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
    RectangleUnitTest() : UnitTest ("Rectangle", UnitTestCategories::graphics) {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("Rectangle/string conversions can be round-tripped");
 | 
			
		||||
        {
 | 
			
		||||
            const Rectangle<float> a (0.1f, 0.2f, 0.3f, 0.4f);
 | 
			
		||||
            expect (Rectangle<float>::fromString (a.toString()) == a);
 | 
			
		||||
 | 
			
		||||
            const Rectangle<double> b (0.1, 0.2, 0.3, 0.4);
 | 
			
		||||
            expect (Rectangle<double>::fromString (b.toString()) == b);
 | 
			
		||||
 | 
			
		||||
            const Rectangle<int> c (1, 2, 3, 4);
 | 
			
		||||
            expect (Rectangle<int>::fromString (c.toString()) == c);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static RectangleUnitTest rectangleUnitTest;
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
		Reference in New Issue
	
	Block a user