|
|
@@ -1,13 +1,11 @@
|
|
|
# Глава 2. Рисование линий
|
|
|
|
|
|
-A line is a series of adjacent points. We will limit ourselves to two types of
|
|
|
-lines:
|
|
|
+Прямая — это ряд смежных точек. Мы ограничимся рассмотрением двух типов прямых:
|
|
|
|
|
|
-Horizontal and vertical lines
|
|
|
+- горизонтальные линии
|
|
|
+- вертикальные линии
|
|
|
|
|
|
-- When drawing these lines point by point, just one coordinate changes, while the other stays constant.
|
|
|
-- A point is an object consisting of x and y coordinates, and we define it and
|
|
|
-use it like this:
|
|
|
+При построении этих линий точка за точкой меняется только одна координата, а другая остается неизменной. Точка — это объект, состоящий из координат x и y. Мы определяем и используем ее следующим образом:
|
|
|
|
|
|
```nim
|
|
|
import pixels
|
|
|
@@ -25,26 +23,24 @@ use it like this:
|
|
|
- 4 We can access fields of an object with a dot. In this case, we access the x
|
|
|
and y coordinates of the point p with p.x and p.y.
|
|
|
|
|
|
-## 2.1. Drawing horizontal and vertical lines
|
|
|
+- 1 Определение точки как объекта
|
|
|
+- 2 Координаты `x` и `y` — целые числа
|
|
|
+- 3 Переменная `p` является экземпляром класса `Point` с координатами (5, 7).
|
|
|
+- 4 Мы можем обращаться к полям объекта через точку. В данном случае мы обращаемся к координатам `x` и `y` точки `p` через `p.x` и `p.y`.
|
|
|
|
|
|
-A line can be defined by a starting and an ending point, or by a starting point
|
|
|
-and its length and a direction. We’ll show both approaches.
|
|
|
+## 2.1. Проведение горизонтальных и вертикальных линий
|
|
|
|
|
|
-## 2.1.1. Drawing a line using one point, length, direction
|
|
|
+Линия может быть задана начальной и конечной точками или начальной точкой, длиной и направлением. Мы рассмотрим оба подхода.
|
|
|
|
|
|
-We can define a line by its starting point, its length, and its direction. Having
|
|
|
-these two information, we can then draw a line pixel by pixel.
|
|
|
+### 2.1.1. Проведение линии с использованием одной точки, длины и направления
|
|
|
|
|
|
-A line length is a positive integer (a zero would be just a point, not a line; a
|
|
|
-negative value for the length is physically impossible). A direction can be
|
|
|
-either horizontal or vertical.
|
|
|
+Мы можем задать линию по её начальной точке, длине и направлению. Имея эту информацию, мы можем рисовать линию попиксельно.
|
|
|
|
|
|
-This means that we will limit ourselves to always create lines from left to
|
|
|
-right (we specify the leftmost point of a line and then increase the x
|
|
|
-coordinate) or top to bottom (we increase the y coordinate).
|
|
|
+Длина линии — это положительное целое число (нуль — это просто точка, а не линия; отрицательное значение длины физически невозможно). Направление может быть горизонтальным или вертикальным.
|
|
|
|
|
|
-We can start by creating two similar procs: one for drawing horizontal lines,
|
|
|
-and one for drawing vertical lines.
|
|
|
+Это значит, что мы будем ограничиваться построением линий слева направо (указываем самую левую точку линии, а затем увеличиваем координату `x`) или сверху вниз (увеличиваем координату `y`).
|
|
|
+
|
|
|
+Для начала можно создать два похожих процесса: один для рисования горизонтальных линий, другой — для рисования вертикальных.
|
|
|
|
|
|
```nim
|
|
|
import pixels
|
|
|
@@ -63,27 +59,18 @@ and one for drawing vertical lines.
|
|
|
drawVerticalLine(a, 30) # 6
|
|
|
```
|
|
|
|
|
|
-- 1 The length is defined as Nim’s built-in Positive type, which is a subtype of
|
|
|
- int, containing just positive numbers.
|
|
|
-- 2 The p..q is an (inline) iterator, which iterates from p to q (both ends are
|
|
|
- inclusive) in the ascending order, i.e. p must be smaller than q for the
|
|
|
- iteration to happen. In this case we’re iterating from zero to length.
|
|
|
-- 3 For a horizontal line, the y coordinate remains constant, and in each
|
|
|
- iteration step we draw a pixel one pixel to the right from the previous
|
|
|
- step.
|
|
|
-- 4 Similarly, for a vertical line, the x coordinate stays constant, and we
|
|
|
- increase the y coordinate to draw a new pixel.
|
|
|
-- 5 This will draw a horizontal line from (60, 40) to (110, 40).
|
|
|
-- 6 This will draw a vertical line from (60, 40) to (60, 70).
|
|
|
+- 1 Длина определяется как встроенный в **Nim** тип `Positive`, который является подтипом `int` и содержит только положительные числа.
|
|
|
+- 2 `p..q` — это (встроенный) итератор, который выполняет итерацию от `p` до `q` (оба конца включительно) в порядке возрастания, то есть для выполнения итерации `p` должно быть меньше `q`. В данном случае мы выполняем итерацию от нуля до `length`.
|
|
|
+- 3 Для горизонтальной линии координата `y` остается постоянной, и на каждом шаге итерации мы рисуем пиксель на один пиксель правее, чем на предыдущем шаге.
|
|
|
+- 4 Аналогичным образом для вертикальной линии координата `x` остается неизменной, а координата `y` увеличивается, чтобы нарисовать новый пиксель.
|
|
|
+- 5 Этот вызов позволит провести горизонтальную линию от (60, 40) до (110, 40).
|
|
|
+- 6 Этот вызов позволит провести вертикальную линию от (60, 40) до (60, 70).
|
|
|
|
|
|
-We can have one proc, drawLine, which will draw both horizontal and vertical
|
|
|
-lines, depending on the provided user’s parameter.
|
|
|
+У нас может быть одна процедура `drawLine`, которая будет рисовать как горизонтальные, так и вертикальные линии в зависимости от заданного пользователем параметра.
|
|
|
|
|
|
-To model a set of a limited amount of values, we use the enum type. The
|
|
|
-benefits of this choice will be visible later, when we will see one of the
|
|
|
-features of Nim: exhaustiveness checking.
|
|
|
+Для моделирования набора из ограниченного количества значений мы используем тип `enum`. Преимущества этого выбора станут очевидны позже, когда мы рассмотрим одну из особенностей языка **Nim** — проверку полноты перечисления.
|
|
|
|
|
|
-We can now extend the previous example with these lines:
|
|
|
+Теперь мы можем дополнить предыдущий пример следующими строками:
|
|
|
|
|
|
```nim
|
|
|
type
|
|
|
@@ -100,27 +87,20 @@ We can now extend the previous example with these lines:
|
|
|
drawLine(a, 30, Vertical)
|
|
|
```
|
|
|
|
|
|
-- 1 A Direction is an enumeration (enum) with two possible values.
|
|
|
-- 2 The values of a Direction are: Horizontal and Vertical.
|
|
|
-- 3 We now have an extra parameter of the Direction type.
|
|
|
-- 4 This is a case statement. It is similar to if statement, but more powerful.
|
|
|
- Not only we get separate branches for each case, we also have
|
|
|
- exhaustiveness checking: we cannot by accident leave out some cases.
|
|
|
- Concretely, we must account for all the enum values.
|
|
|
-- 5 We delegate the task of drawing lines to the previously defined procs.
|
|
|
-- 6 This will draw the same lines as in the example before.
|
|
|
+- 1 Направление — это перечисление (`enum`) с двумя возможными значениями.
|
|
|
+- 2 Значения направления: горизонтальное и вертикальное.
|
|
|
+- 3 Теперь у нас есть дополнительный параметр типа `Direction`.
|
|
|
+- 4 Это оператор `switch`. Он похож на оператор `if`, но более функционален. Мы не только получаем отдельные ветви для каждого варианта, но и проверяем полноту: мы не можем случайно пропустить какой-либо вариант. В частности, мы должны учесть все значения перечисления.
|
|
|
+- 5 Мы делегируем задачу по построению линий ранее определенным процессам.
|
|
|
+- 6 Будут нарисованы те же линии, что и в предыдущем примере.
|
|
|
|
|
|
-## 2.1.2. Drawing a line by specifying start and end
|
|
|
+### 2.1.2. Рисование линии с указанием начальной и конечной точек
|
|
|
|
|
|
-If we use two points to define a line, we don’t have to know (or calculate) the
|
|
|
-line length, and the direction can be inferred from the relation of these two
|
|
|
-points: if they have the same y coordinate, we are drawing a horizontal line,
|
|
|
-and a vertical line between two points with the same x coordinate.
|
|
|
+Если мы используем две точки для определения прямой, нам не нужно знать (или вычислять) длину прямой, а направление можно определить по расположению этих двух точек: если у них одинаковые координаты по оси `Y`, мы рисуем горизонтальную прямую, а если одинаковые координаты по оси `X` — вертикальную.
|
|
|
|
|
|
-We will always iterate from a point with a smaller value of the changing
|
|
|
-coordinate, but we will allow our users to specify the points in any order.
|
|
|
+Мы всегда будем начинать с точки с меньшим значением изменяемой координаты, но позволим пользователям указывать точки в любом порядке.
|
|
|
|
|
|
-We can achieve this with recursion.
|
|
|
+Этого можно добиться с помощью рекурсии.
|
|
|
|
|
|
```nim
|
|
|
proc drawHorizontalLine(a, b: Point) = # 1
|
|
|
@@ -143,11 +123,8 @@ We can achieve this with recursion.
|
|
|
drawVerticalLine(p, r) # 5
|
|
|
```
|
|
|
|
|
|
-- 1 Even though we already have a proc of the same name, there is no
|
|
|
- overriding: they are different procs because they have different
|
|
|
- parameters.
|
|
|
-- 2 Notice the reversed order of the arguments.
|
|
|
-- 3 The x is a changing variable, while the y remains constant.
|
|
|
-- 4 Draws a horizontal line between (20, 20) and (50, 20).
|
|
|
-- 5 Since r.y is smaller than p.y, this will in turn call drawVerticalLine(r, p)
|
|
|
- and draw a vertical line between (20, -10) and (20, 20).
|
|
|
+- 1 Несмотря на то, что у нас уже есть процедура с таким же названием, переопределения не происходит: это разные процедуры, потому что у них разные параметры.
|
|
|
+- 2 Обратите внимание на обратный порядок аргументов.
|
|
|
+- 3 `x` — изменяющаяся переменная, а `y` остается постоянной.
|
|
|
+- 4 Проведите горизонтальную линию между точками (20, 20) и (50, 20).
|
|
|
+- 5 Поскольку `r.y` меньше, чем `p.y`, это, в свою очередь, приведёт к вызову функции `drawVerticalLine(r, p)` и нарисует вертикальную линию между точками (20, -10) и (20, 20)
|