JUCEプログラミング、The Point, Line, and Rectangle classes3、直線の交差判定など

直線の描画でも、交差点を取得したり、いろいろとできるみたいですね。

配列の使い方とか、細かい点も参考になるよね~

JUCEチュートリアル、「Interface Design」の「The Point, Line, and Rectangle classes」チュートリアルの「Dealing with lines」項目の内容のプログラム実装とその処理の考察になります。

公式のチュートリアルページはこちらになります。

目次

こんな人の役に立つかも

・JUCEプログラミングを勉強している人

・JUCEチュートリアル「The Point, Line, and Rectangle classes」をやっている人

・JUCEの直線描画に関する詳細を知りたい人

作成するデモアプリ

10本の直線をウィンドウ内にランダムに描画して、お互い交差しているポイントに点を描画するようなデモプログラムを作成します。

プロジェクトは、Projucerの「GUI」テンプレートを使用して作成していきました。プロジェクト名は任意です。

MainComponent.h

前回の矩形描画と同様に、MainComponentクラスにMouseDown関数を実装して、ウィンドウがクリックされたら再描画されるようにしていきます。

まずは、「GUI」テンプレートを開いたら、MainCoponent.hにMouseDown関数をオーバーライドしておきます。

class MainComponent  : public juce::Component
{
public:

//...略...

    void mouseDown(const juce::MouseEvent&) override;//この関数を追加しました。

private:

//...略...
};

次に、処理内容はcppに記載していきます。

MainComponent.cpp

mouseDown関数

cppファイルの一番下に以下の関数の処理を追記しました。reapintでウィンドウ内(MainComponentの描画領域)をマウスクリックしたら、再度paint関数に定義した処理で描画しなおす処理です。

void MainComponent::mouseDown(const juce::MouseEvent&)
{
    repaint();
}

paint関数

paint関数の処理内容を以下のように記載しました。

今回の要所なので、詳細に見ていきたいと思います。

void MainComponent::paint(juce::Graphics& g)
{

    //[1]諸々の初期準備です。
    g.fillAll(juce::Colours::darkgrey);
    g.setColour (juce::Colours::orange);

    auto& random = juce::Random::getSystemRandom();

    //[2]直線パラメータの準備です。
    juce::Range<int> lineRange(0, getWidth());
    juce::Array<juce::Line<float>> lines;
    auto numLines = 10;

    //[3]直線の描画処理です。
    for (auto i = 0; i < numLines; ++i)
    {
        //[3-1]
        juce::Line<float> line((float)random.nextInt(lineRange),
            (float)random.nextInt(lineRange),
            (float)random.nextInt(lineRange),
            (float)random.nextInt(lineRange));

        lines.add(line);
//[3-2]
        g.drawLine(line, 2.0f);//[3-3]
    }

    //[4]交差点の描画処理です。
    //[4-1]
    g.setColour(juce::Colours::palegreen);
    juce::Rectangle<float> pointArea(8, 8);

    //[4-2]
    for (auto lineI : lines)
    {
        for (auto lineJ : lines)
        {
            if (lines.indexOf(lineI) != lines.indexOf(lineJ))
            {
                juce::Point<float> intersection;

                if (lineI.intersects(lineJ, intersection)) //[4-3]
                {
                    pointArea.setCentre(intersection);
                    g.fillEllipse(pointArea);
                }
            }
        }
    }
}

[1]で、描画領域全体を「darkgray」に塗りつぶし、これからの描画色を「orange」に設定します。また、ランダムな数値を得るために、randomオブジェクトを生成しました。

[2]では、描画する直線のパラメータ準備を行います。lineRangeオブジェクトで、0~描画領域幅までの数値を取得できるようにしておきます。また、lineオブジェクトは交差点を求める際に必要となるので、juce::Arrayに追加して管理しておきます。juce::Array<juce::Line<float>>クラスの配列「lines」を定義しました。そして、今回は10本の線を引きたいので、nunLinesに10を格納しておきます。

[3]は、numLinesで定義した回数forループで直線を描画して、直線の描画処理などを行います。

[3-1]で、まず直線の生成を行います。lineオブジェクトのコンストラクタへ「開始座標X,Y」と「終了座標X,Y」の4つの引数を与える方法で生成していまきす。

[3-2]、生成した直線は、後程、交差しているかの確認で利用しますので、lines配列(juce::Array)に格納していきます。Arrayへの要素追加はadd関数で可能です。最後に[3-3]でdrawLine関数で直線を描画します。

[4]で、直線同士が交差しているかを確認して交差している点は描画します。

まず[4-1]では、点の色を「palegreen」に設定しておきます。そして、点の描画サイズを矩形領域で8×8と設定しました。

[4-2]では、2重のforループでそれぞれの直線の交差を確認します。1つの直線に対して、他のすべての直線に対して確認するので、総当たりの処理です。

外側のループで、lineIとして比較する片方を決めます。(0から順に)内側のループでもう一度lines配列をlineJに取得して「lineI」と「lineJ」をIntersects関数で交差確認を行います。Intersects関数では、第二引数のpointクラスのオブジェクトintersectionに交差座標が格納されます。

この時、自分自身と比較しないように、「lines.indexOf(lineI) != lines.indexOf(lineJ)」という条件判定をすることで、自分以外の直線との比較を行うことができます。

図のように10回目まで繰り返すことで、ある直線に対して他の直線との組み合わせすべてを比較することができます。

最後に、描画では、8×8の矩形pointAreaの中心座標をintersectionに設定して、fillEllipse関数で円を描画します。

総当たりなので、もっと効率的な描画方法がありますよね~。

よかったらシェアしてね!
目次
閉じる