メインコンテンツまでスキップ

チュートリアル点、線、矩形クラス

Use the ポイント, ライン, and 長方形 classes to simplify your geometry calculations.

レベル:初級

プラットフォーム:Windows, macOS, Linux, iOS, Android

クラス: ポイント, ライン, 長方形, パス, ランダム, レンジ

はじめる

Download the demo project for this tutorial here: ピップ | ジップ. Unzip the project and open the first header file in the Projucer.

If you need help with this step, see チュートリアルProjucerパート1:Projucerを始める.

The demo project

このデモ・プロジェクトは、いくつかの簡単な描画操作を行います。デフォルトの状態では、左上に小さなオレンジ色の四角がある灰色の背景を描画します:

Simple drawing of a square
Simple drawing of a square

We are going to look at different ways of drawing lines and rectangles, and how the ポイント, ライン, and 長方形 classes can simplify the way you think about drawing operations (and component positions) in JUCE.

Rectangle basics

A great deal of graphics drawing and component layout code needs to deal with rectangles. This tutorial starts with the simple drawing of a filled square. We are now going to explore how the ポイント, ライン, and 長方形 classes can help us with drawing operations. We can also apply these techniques to the positioning of child components (in your Component::resized() function). Our starter code in the ペイント function is this:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);

g.fillRect (10, 10, 40, 40);
}

Here we specify the bounds of the rectangle directly to the Graphics::fillRect() function as separate integers:

g.fillRect (10, // x
10, // y
40, // 幅
40); // 高さ

While this is straightforward, if we specify the bounds as a 長方形 object, it becomes much easier to perform manipulations of the rectangle.

Using the Rectangle and Point classes

It is easy to replace these separate coordinates, width, and height values with a 長方形 object, like so [1]:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);

juce::Rectangle領域 (10, 10, 40, 40); // [1].

g.setColour (juce::Colours::orange);
g.fillRect (area);
}

There are other ways to create rectangles. For example, rather than specifying width and height, we might have two points that we want to use as corners of the rectangle. We can use the ポイント class and a different 長方形 constructor:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);
juce::Rectangle area (juce::Point (10, 10),
juce::Point(50, 50));

g.fillRect (area);
}

このテクニックの素晴らしい点のひとつは、任意の2点を指定できることだ。これらの点は矩形の左上と右下の角を表す必要はない。従って、これに相当するものは次のようになる:

juce::Rectangle area (juce::Point (10, 50),
juce::Point(50, 10));

Using the Point and Path classes

In fact, using a パス object we can specify a rectangle with four points defining each corner:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);

juce::Path path;
path.startNewSubPath (juce::Point (10, 10));
path.lineTo (juce::Point (50, 10));
path.lineTo (juce::Point (50, 50));
path.lineTo (juce::Point(10, 50));
path.closeSubPath();

g.fillPath (path);
}
注記

パスのポイントを変えて、他の四角形形状を作ってみてください。

パスに直接矩形を追加することもできる:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);

juce::Path path;
juce::Rectangle領域 (10, 10, 40, 40);
path.addRectangle (area);

g.fillPath (path);
}
注記

Testing points within rectangles

Another useful feature of a 長方形 object is that it can test whether it contains a specified point. To test this out, we are going to get our component to repaint itself each time we click the mouse. To do this, add the following function:

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

Now let's write our ペイント function such that it randomly generates a rectangle and a point. Then it will draw the rectangle and then a smaller rectangle located around the point. This smaller rectangle will be drawn in a different colour depending upon whether the randomly-generated point is within the larger rectangle or not. Our ペイント function should start as before, but we're going to generate some random values so let's cache a reference of the system ランダム object too.

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);

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

次に、ランダムな長方形を作成します。以下のコードを追加する:

        juce::Range rectRange (20, getWidth() / 2);
juce::RectanglerectArea (random.nextInt (rectRange)、
random.nextInt (rectRange)、
random.nextInt (rectRange)、
random.nextInt (rectRange));

g.drawRect (rectArea, 2);

We limit the range of random values for each of the rectangle elements using a レンジ object. We also draw (rather than fill) the rectangle with a thickness of 2 points. To draw the smaller rectangle we are going to need another 長方形 object. If we use only two arguments to the 長方形 constructor, it creates a 長方形 object with the specified width and height (in that order) at a position of zero (0, 0). Add this line:

Now let's randomly-generate a point and position the centre of the 点面積 rectangle at that point. Add the following code:

        juce::Point point (random.nextInt (juce::Range (0, getWidth())),
random.nextInt (juce::Range(0, getHeight()));
pointArea.setCentre (point);

This demonstrates another useful feature of the 長方形 class as we can position its centre if we wish. This is sometimes preferable to considering a rectangle's position to be its top-left corner. Now we can use the 矩形::contains() function to determine whether the ポイント object is within the bounds of the 矩形領域 object. Add this code:

g.setColour (rectArea.contains (point) ? juce::Colours::limegreen
: juce::Colours::cornflowerblue);

g.fillRect (pointArea);

アプリケーションを実行すると、以下のスクリーンショットのようになるはずです。コンポーネントを再描画するには、コンポーネントをクリックすることを忘れないでください:

Testing points within rectangles
Testing points within rectangles
注記

The code for this example can be found in the PointLineRectangleTutorial_02.h file of the demo project.

Dealing with lines

線の描画と処理も同様に簡単だ。次のコードは対角線を描画する:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);

juce::Line line (juce::Point (10, 10),
juce::Point(50, 50));

g.drawLine (line, 2.0f);
}

Line intersections

The ライン class can also perform line intersection tests. To test this out we are going to generate several randomly-generated lines, then we are going to draw a circle at the points where any of these lines intersect with any of the other lines. First let's set up our ペイント function with a background and get ready for generating some random numbers:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);
g.setColour (juce::Colours::orange);

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

では、ランダムな線を生成し、描画するだけでなく、配列に格納してみよう。次のコードを追加する:

        juce::Range lineRange (0, getWidth());
juce::Array> lines;
auto numLines = 10;

for (auto i = 0; i < numLines; ++i)
{
juce::Lineline ((float) random.nextInt (lineRange)、
(float) random.nextInt (lineRange)、
(float) random.nextInt (lineRange)、
(float) random.nextInt (lineRange));

lines.add (line);
g.drawLine (line, 2.0f);
}

次に色を変え、円を描く境界となる正方形を用意する。これを加える:

        g.setColour (juce::Colours::palegreen);
juce::RectanglepointArea (8, 8);

Finally, we'll iterate over the array of lines checking for intersections with any of the other lines using the Line::intersects() function. We then move the centre of the 点面積 rectangle to this point and paint a circle. To do this, add the following code:

        for (auto lineI : lines)
{
for (auto lineJ : lines)
{
if (lines.indexOf (lineI) != lines.indexOf (lineJ))
{
juce::Point交差点だ;

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

The piece of code that checks for the intersection [2], calls the Line::intersects() function. This not only returns 真の if the lines actually intersect, but also returns the point at which they intersect in the 交差点 argument.

今すぐアプリケーションを実行してください。マウスのクリックに反応して再描画するコードを残しておけば、コンポーネントをクリックすることで新しい線のセットを生成することができます。

Line intersections
Line intersections
注記

The code for this example can be found in the PointLineRectangleチュートリアル_03.h file of the demo project.

If we didn't check the ブール returned by the Line::intersects() function, or we used the Line::getIntersection() instead, then points would be drawn in places where the lines だろう intersect should they be extended in each direction to an infinite length. For example, look at the following code:

//..
if (lines.indexOf (lineI) != lines.indexOf (lineJ))
{
juce::Point交差点;
pointArea.setCentre (lineI.getIntersection (lineJ));
g.fillEllipse (pointArea);
}
//..

そうすると、以下のスクリーンショットのようなものが生成される:

Line intersections beyond the endpoints
Line intersections beyond the endpoints

The final for() loop in the code for this example is simple, but not ideal. The problem is that it checks each line against every other line . Rewrite this code such that it only checks each pair of lines once. You should be able to remove the if (lines.indexOf (lineI) != lines.indexOf (lineJ)) statement as part of this rewrite.

Manipulating rectangles

Now let's look at some more manipulations of rectangles that we can perform. Before we start, let's add a simple function to generate a random colour (see チュートリアルランダム・クラス) as we're going to be doing this quite a number of times in the following examples:

静的 juce::Colour getRandomColour()
{
auto& random = juce::Random::getSystemRandom();

return juce::Colour ((juce::uint8) random.nextInt (256)、
(juce::uint8) random.nextInt (256)、
(juce::uint8) random.nextInt (256));
}

Now, let's extend the code for drawing the rectangle by using the 長方形 class, by drawing ten squares in a diagonal pattern, and using a randomly-generated colour:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);

juce::Rectangleエリア(10, 10, 40, 40);

auto numSquares = 10;

for (auto i = 0; i < numSquares; ++i)
{
g.setColour (getRandomColour());
g.fillRect (area);

area.translate (30, 30); // [3].
}
}

The 矩形::translate() function [3] moves the given rectangle by the horizontal and vertical offsets provided. The result should look something like the following screenshot:

Diagonal pattern of squares
Diagonal pattern of squares

ここではそのコードを拡張して、次の描画操作の前に矩形のサイズを変更する。これに加えて、平行移動は矩形の幅と高さに等しくなるように行われる。

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);

juce::Rectangle area (10, 10, 40, 40);

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

for (auto i = 0; i < numSquares; ++i)
{
g.setColour (getRandomColour());
g.fillRect (area);

area.translate (area.getWidth(), area.getHeight()); // [4]
area.setSize (random.nextInt (juce::Range (20, 40)), // width
random.nextInt (juce::Range(20, 40)); // 高さ
}
}

これにより、以下のスクリーンショットに示すように、矩形はその角で「結合」される:

Rectangles joined at the corners
Rectangles joined at the corners

As an alternative to using the 矩形::translate() function, we could instead use addition to "add" points to rectangle in order to translate them. This means we could replace [4] above with the following line:

area += juce::Point(area.getWidth(),area.getHeight());

Rectangle intersections

If we have rectangles that overlap, we can determine the intersecting area using the 矩形::getIntersection() function. In the following example we calculate the intersecting rectangle between the current and next rectangles in the series. To make this clear, we draw outlines for each rectangle in the series and highlight the intersecting areas by drawing them as filled rectangles.

    void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::darkgrey);

juce::Rectangle area (10, 10, 40, 40);

auto& random = juce::Random::getSystemRandom();
juce::Range rectRandomRange (20, 40);
auto numSquares = 10;

for (auto i = 0; i < numSquares; ++i)
{
auto nextArea = area + juce::Point(random.nextInt (rectRandomRange), // [5].
random.nextInt (rectRandomRange));

g.setColour (getRandomColour());
g.fillRect (area.getIntersection (nextArea)); // [6].

g.setColour (getRandomColour());
g.drawRect (area, 2); // [7].

area = nextArea;
}
}

Notice that we use the + operator to offset the rectangle [5]. We also fill the intersecting areas first [6] before drawing the rectangle outlines [7]. This causes the last intersecting area to be drawn without its final corresponding rectangle.

Rectangle intersections
Rectangle intersections
注記

The code for this final example can be found in the PointLineRectangleチュートリアル_04.h file of the demo project.

概要

In this tutorial we have introduced the template classes ポイント, ライン, and 長方形. In particular, we have covered the following techniques:

  • Creating and manipulating 長方形 objects and using them in drawing code.
  • Creating 長方形 objects from corner points or by intersections of two rectangles.
  • Creating パス objects containing rectangles.
  • Creating ライン objects, drawing lines, and finding points where lines intersect.

関連項目