Skip to main content

09. Прототип

В этой главе мы создадим прототип графического приложения для решения поставленной геометрической задачи.

w

Пример готового проекта лежит здесь. Для выполнения текущего задания Fork от него делать запрещается.

В ходе работы вам будет нужно сделать несколько коммитов с промежуточными состояниями проекта, поэтому в прямом копировании нет смысла. Готовый проект даётся для того, чтобы было проще разобраться, как выполнить поставленное задание.

Если у вас не выполнено предыдущее задание или выполнено не полностью, то сделайте Fork готового проекта из предыдущей главы.

Панели

В нашем приложении будет четыре панели:

  • Рисование задачи
  • Лог
  • Управление
  • Помощь

Лог - это структура, которая умеет накапливать сообщения и потом выводить их в той или иной форме. Чаще всего лог выводят в файл, но для наглядности мы будем выводить его на экран.

В блоке помощи мы потом укажем управляющие сочетания клавиш.

Создадим 4 панели-прототипа в пакете panels: PanelControl, PanelHelp, PanelLog и PanelRendering

w

Все панели пока что одинаковые: на них добавлено по одному заголовку, который занимает всю панель. Отличаются только их тексты. Вам нужно самостоятельно написать по аналогии классы PanelLog, PanelHelp и PanelRendering

Ниже приведён код панели управления `PanelControl:

package panels;

import controls.Label;
import io.github.humbleui.jwm.*;
import io.github.humbleui.skija.Canvas;
import misc.CoordinateSystem2i;

import static app.Application.PANEL_PADDING;
import static app.Colors.PANEL_BACKGROUND_COLOR;

/**
* Панель управления
*/
public class PanelControl extends GridPanel {
/**
* Заголовок
*/
private final Label label;

/**
* Панель управления
*
* @param window окно
* @param drawBG флаг, нужно ли рисовать подложку
* @param color цвет подложки
* @param padding отступы
* @param gridWidth кол-во ячеек сетки по ширине
* @param gridHeight кол-во ячеек сетки по высоте
* @param gridX координата в сетке x
* @param gridY координата в сетке y
* @param colspan кол-во колонок, занимаемых панелью
* @param rowspan кол-во строк, занимаемых панелью
*/
public PanelControl(
Window window, boolean drawBG, int color, int padding, int gridWidth, int gridHeight,
int gridX, int gridY, int colspan, int rowspan
) {
super(window, drawBG, color, padding, gridWidth, gridHeight, gridX, gridY, colspan, rowspan);

// создаём первый заголовок
label = new Label(window, false, PANEL_BACKGROUND_COLOR, PANEL_PADDING,
1, 1, 0, 0, 1, 1, "Панель управления", true, true);


}

/**
* Обработчик событий
*
* @param e событие
*/
@Override
public void accept(Event e) {

}

/**
* Метод под рисование в конкретной реализации
*
* @param canvas область рисования
* @param windowCS СК окна
*/
@Override
public void paintImpl(Canvas canvas, CoordinateSystem2i windowCS) {
label.paint(canvas, windowCS);
}
}

Теперь добавим соответствующие поля в классе Application:

    /**
* панель легенды
*/
private final PanelHelp panelHelp;
/**
* панель курсора мыши
*/
private final PanelControl panelControl;
/**
* панель рисования
*/
private final PanelRendering panelRendering;
/**
* панель событий
*/
private final PanelLog panelLog;

Инициализируем их в конструкторе:

        ...
// создаём панель рисования
panelRendering = new PanelRendering(
window, true, PANEL_BACKGROUND_COLOR, PANEL_PADDING, 5, 3, 0, 0,
3, 2
);
// создаём панель управления
panelControl = new PanelControl(
window, true, PANEL_BACKGROUND_COLOR, PANEL_PADDING, 5, 3, 3, 0,
2, 2
);
// создаём панель лога
panelLog = new PanelLog(
window, true, PANEL_BACKGROUND_COLOR, PANEL_PADDING, 5, 3, 0, 2,
3, 1
);
// создаём панель помощи
panelHelp = new PanelHelp(
window, true, PANEL_BACKGROUND_COLOR, PANEL_PADDING, 5, 3, 3, 2,
2, 1
);
...

Перед изменением рисования вам нужно удалить все три заголовка (Label) из прошлого задания и связанные с ними команды

Теперь останется только добавить команды рисования в методе paint()

    /**
* Рисование
*
* @param canvas низкоуровневый инструмент рисования примитивов от Skija
* @param windowCS СК окна
*/
public void paint(Canvas canvas, CoordinateSystem2i windowCS) {
// запоминаем изменения (пока что там просто заливка цветом)
canvas.save();
// очищаем канвас
canvas.clear(APP_BACKGROUND_COLOR);
// рисуем панели
panelRendering.paint(canvas, windowCS);
panelControl.paint(canvas, windowCS);
panelLog.paint(canvas, windowCS);
panelHelp.paint(canvas, windowCS);
canvas.restore();
}

Запустим приложение:

w

Создайте новый коммит 4 panels и отправьте его на сервер.

Точка

Мы будем писать нашу программу, исходя из логики, что все значащие поля задачи сохраняются в json-файле. Подробнее об этом будет рассказано дальше.

Пока что просто перенесём всю логику отображения и взаимодействия с задачей в другой класс Task в пакете app, а в классе панели добавим поле объекта Task.

package app;

/**
* Класс задачи
*/
public class Task {

}

Теперь удалим у панели рисования заголовок и добавим соответствующее поле в класс Application

    /**
* Представление проблемы
*/
public static Task task;

В этом курсе мы решим такую задачу:

Постановка задачи

Заданы два множества точек в вещественном пространстве. Требуется построить пересечения и разность этих множеств.

Добавим поле с текстом нашему классу:

package app;

/**
* Класс задачи
*/
public class Task {
/**
* Текст задачи
*/
public static final String TASK_TEXT = """
ПОСТАНОВКА ЗАДАЧИ:
Заданы два множества точек в вещественном
пространстве. Требуется построить пересечение
и разность этих множеств""";

}

Нам нужно сначала определиться с тем, какие данные нужны для хранения в нашей задаче.

Первое, что нужно хранить, это - точки. Разумнее всего выделить для неё отдельный класс. У каждой точки есть две вещественные координаты: xx и yy. Удобнее всего хранить их в вещественном двумерном векторе.

Двумерный целочисленный вектор нами уже написан, напишем на его основе вещественный:

w

package misc;


import java.util.concurrent.ThreadLocalRandom;

/**
* Класс двумерного вектора double
*/
public class Vector2d {
/**
* x - координата вектора
*/
public double x;
/**
* y - координата вектора
*/
public double y;

/**
* Конструктор вектора
*
* @param x координата X вектора
* @param y координата Y вектора
*/
public Vector2d(double x, double y) {
this.x = x;
this.y = y;
}

/**
* Конструктор вектора создаёт нулевой вектор
*/
public Vector2d() {
this.x = 0;
this.y = 0;
}

/**
* Сложить два вектора
*
* @param a первый вектор
* @param b второй вектор
* @return сумма двух векторов
*/

public static Vector2d sum(Vector2d a, Vector2d b) {
return new Vector2d(a.x + b.x, a.y + b.y);
}


/**
* Добавить вектор к текущему вектору
*
* @param v вектор, который нужно добавить
*/
public void add(Vector2d v) {
this.x = this.x + v.x;
this.y = this.y + v.y;
}

/**
* Вычесть второй вектор из первого
*
* @param a первый вектор
* @param b второй вектор
* @return разность двух векторов
*/
public static Vector2d subtract(Vector2d a, Vector2d b) {
return new Vector2d(a.x - b.x, a.y - b.y);
}

/**
* Вычесть вектор из текущего
*
* @param v вектор, который нужно вычесть
*/
public void subtract(Vector2d v) {
this.x = this.x - v.x;
this.y = this.y - v.y;
}

/**
* Умножение вектора на число
*
* @param v вектор
* @param a число
* @return результат умножения вектора на число
*/

public static Vector2d mul(Vector2d v, double a) {
return new Vector2d(v.x * a, v.y * a);
}

/**
* Получить случайное значение в заданном диапазоне [min,max)
*
* @param min нижняя граница
* @param max верхняя граница
* @return случайное значение в заданном диапазоне [min,max)
*/

public static Vector2d rand(Vector2d min, Vector2d max) {
return new Vector2d(
ThreadLocalRandom.current().nextDouble(min.x, max.x),
ThreadLocalRandom.current().nextDouble(min.y, max.y)
);
}

/**
* Получить длину вектора
*
* @return длина вектора
*/
public double length() {
return Math.sqrt(x * x + y * y);
}

/**
* Строковое представление объекта
*
* @return строковое представление объекта
*/
@Override
public String toString() {
return "(" + String.format("%.2f", x).replace(",", ".") +
", " + String.format("%.2f", y).replace(",", ".") +
')';
}

/**
* Проверка двух объектов на равенство
*
* @param o объект, с которым сравниваем текущий
* @return флаг, равны ли два объекта
*/
@Override
public boolean equals(Object o) {
// если объект сравнивается сам с собой, тогда объекты равны
if (this == o) return true;
// если в аргументе передан null или классы не совпадают, тогда объекты не равны
if (o == null || getClass() != o.getClass()) return false;

// приводим переданный в параметрах объект к текущему классу
Vector2d vector2d = (Vector2d) o;

// если не совпадают x координаты
if (Double.compare(vector2d.x, x) != 0) return false;
// объекты совпадают тогда и только тогда, когда совпадают их координаты
return Double.compare(vector2d.y, y) == 0;
}

/**
* Получить хэш-код объекта
*
* @return хэш-код объекта
*/
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(x);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}

}

Теперь создадим класс точки Point

w

Помимо списка точек, нам нужно определить ещё и принадлежность тому или иному множеству. Мы реализуем это с помощью перечисления PointSet.

package app;

import misc.Misc;
import misc.Vector2d;

import java.util.Objects;

/**
* Класс точки
*/
public class Point {
/**
* Множества
*/
public enum PointSet {
/**
* Первое
*/
FIRST_SET,
/**
* Второе
*/
SECOND_SET
}

/**
* Множество, которому принадлежит точка
*/
protected final PointSet pointSet;
/**
* Координаты точки
*/
public final Vector2d pos;

/**
* Конструктор точки
*
* @param pos положение точки
* @param setType множество, которому она принадлежит
*/
public Point(Vector2d pos, PointSet setType) {
this.pos = pos;
this.pointSet = setType;
}


/**
* Получить цвет точки по её множеству
*
* @return цвет точки
*/
public int getColor() {
return switch (pointSet) {
case FIRST_SET -> Misc.getColor(0xCC, 0x00, 0x00, 0xFF);
case SECOND_SET -> Misc.getColor(0xCC, 0x00, 0xFF, 0x0);
};
}

/**
* Получить положение
* (нужен для json)
*
* @return положение
*/
public Vector2d getPos() {
return pos;
}

/**
* Получить множество
*
* @return множество
*/
public PointSet getSetType() {
return pointSet;
}


/**
* Получить название множества
*
* @return название множества
*/
public String getSetName() {
return switch (pointSet) {
case FIRST_SET -> "Первое множество";
case SECOND_SET -> "Второе множество";
};
}

/**
* Строковое представление объекта
*
* @return строковое представление объекта
*/
@Override
public String toString() {
return "Point{" +
"pointSetType=" + pointSet +
", pos=" + pos +
'}';
}

/**
* Проверка двух объектов на равенство
*
* @param o объект, с которым сравниваем текущий
* @return флаг, равны ли два объекта
*/
@Override
public boolean equals(Object o) {
// если объект сравнивается сам с собой, тогда объекты равны
if (this == o) return true;
// если в аргументе передан null или классы не совпадают, тогда объекты не равны
if (o == null || getClass() != o.getClass()) return false;
// приводим переданный в параметрах объект к текущему классу
Point point = (Point) o;
return pointSet.equals(point.pointSet) && Objects.equals(pos, point.pos);
}

/**
* Получить хэш-код объекта
*
* @return хэш-код объекта
*/
@Override
public int hashCode() {
return Objects.hash(pointSet, pos);
}
}

Запустите программу, должен исчезнуть заголовок на панели рисования.

Создайте новый коммит add task classes и отправьте его на сервер.

Вещественная СК

Для удобства будем считать, что вещественное пространство задачи ограничено областью отображения на экране. Для рисования нам нужно будет связать вещественную СК задачи с целочисленной СК экрана.

Эта задача довольно несложная, но для начала нам нужно просто создать по аналогии с целочисленной ОСК вещественную.

w

Пока что все методы работают одинаково

package misc;

import java.util.Objects;

/**
* ограниченной двумерной вещественной системы координат
*/
public class CoordinateSystem2d {
/**
* максимальная координата
*/

private Vector2d max;
/**
* минимальная координата
*/

private Vector2d min;
/**
* размер СК
*/
private Vector2d size;

/**
* Конструктор ограниченной двумерной вещественной системы координат
*
* @param minX минимальная X координата
* @param minY минимальная Y координата
* @param sizeX размер по оси X
* @param sizeY размер по оси Y
*/
public CoordinateSystem2d(double minX, double minY, double sizeX, double sizeY) {
set(minX, minY, sizeX, sizeY);
}

/**
* Конструктор ограниченной двумерной вещественной системы координат
*
* @param sizeX размер по оси X
* @param sizeY размер по оси Y
*/
public CoordinateSystem2d(double sizeX, double sizeY) {
this(0, 0, sizeX, sizeY);
}


/**
* Конструктор ограниченной двумерной вещественной системы координат
*
* @param min минимальные координаты
* @param max максимальные координаты
*/
public CoordinateSystem2d(Vector2d min, Vector2d max) {
this(min.x, min.y, max.x - min.x, max.y - min.y);
}


/**
* Задать новые границы
*
* @param minX минимальная x-координата
* @param minY максимальная x-координата
* @param sizeX размер по оси X
* @param sizeY размер по оси Y
*/
public void set(double minX, double minY, double sizeX, double sizeY) {
min = new Vector2d(minX, minY);
size = new Vector2d(sizeX, sizeY);
max = Vector2d.sum(size, min);
}


/**
* Получить случайные координаты внутри СК
*
* @return случайные координаты внутри СК
*/
public Vector2d getRandomCoords() {
Vector2d r = Vector2d.rand(min, max);
return r;
}

/**
* Проверить, попадают ли координаты в границы СК
*
* @param coords координаты вектора
* @return флаг, попадают ли координаты в границы СК
*/
public boolean checkCoords(Vector2d coords) {
return coords.x >= min.x && coords.y >= min.y && coords.x <= max.x && coords.y <= max.y;
}

/**
* Проверить, попадают ли координаты в границы СК
*
* @param x координата X
* @param y координата Y
* @return флаг, попадают ли координаты в границы СК
*/
public boolean checkCoords(double x, double y) {
return checkCoords(new Vector2d(x, y));
}


/**
* Получить координаты вектора в текущей систему координат
*
* @param coords координаты вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2d getCoords(Vector2d coords, CoordinateSystem2d coordinateSystem) {
return getCoords(coords.x, coords.y, coordinateSystem);
}

/**
* Получить координаты вектора в текущей систему координат
*
* @param x координата X вектора в другой системе координат
* @param y координата Y вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2d getCoords(double x, double y, CoordinateSystem2d coordinateSystem) {
return new Vector2d(
(x - coordinateSystem.min.x) * size.x / coordinateSystem.size.x + min.x,
(y - coordinateSystem.min.y) * size.y / coordinateSystem.size.y + min.y
);
}

/**
* Получить координаты вектора в текущей систему координат
*
* @param coords координаты вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2d getCoords(Vector2i coords, CoordinateSystem2i coordinateSystem) {
return this.getCoords(coords.x, coords.y, coordinateSystem);
}

/**
* Получить координаты вектора в текущей систему координат
*
* @param x координата X вектора в другой системе координат
* @param y координата Y вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2d getCoords(int x, int y, CoordinateSystem2i coordinateSystem) {
return new Vector2d(
(x - coordinateSystem.getMin().x) * size.x / (coordinateSystem.getSize().x - 1) + min.x,
(y - coordinateSystem.getMin().y) * size.y / (coordinateSystem.getSize().y - 1) + min.y
);
}

/**
* Получить максимальную координата
*
* @return максимальная координата
*/
public Vector2d getMax() {
return max;
}

/**
* Получить минимальную координата
*
* @return минимальная координата
*/
public Vector2d getMin() {
return min;
}

/**
* Получить размер СК
*
* @return размер СК
*/
public Vector2d getSize() {
return size;
}

/**
* Строковое представление объекта вида:
*
* @return "CoordinateSystem2d{min, max}"
*/
@Override
public String toString() {
return "CoordinateSystem2d{" + min + ", " + max + '}';
}

/**
* Проверка двух объектов на равенство
*
* @param o объект, с которым сравниваем текущий
* @return флаг, равны ли два объекта
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

CoordinateSystem2d that = (CoordinateSystem2d) o;

if (!Objects.equals(max, that.max)) return false;
return Objects.equals(min, that.min);
}

/**
* Получить хэш-код объекта
*
* @return хэш-код объекта
*/
@Override
public int hashCode() {
int result = max != null ? max.hashCode() : 0;
result = 31 * result + (min != null ? min.hashCode() : 0);
return result;
}
}

Создайте новый коммит float cs и отправьте его на сервер.

Рисование задачи

Теперь вернёмся к классу нашей задачи. Добавим поле вещественной ОСК и поле с динамическим массивом точек в класс задачи:

package app;

import misc.CoordinateSystem2d;
import java.util.ArrayList;

/**
* Класс задачи
*/
public class Task {
/**
* Текст задачи
*/
public static final String TASK_TEXT = """
ПОСТАНОВКА ЗАДАЧИ:
Заданы два множества точек в вещественном
пространстве. Требуется построить пересечение
и разность этих множеств""";
/**
* Вещественная система координат задачи
*/
private final CoordinateSystem2d ownCS;
/**
* Список точек
*/
private final ArrayList<Point> points;

/**
* Задача
*
* @param ownCS СК задачи
* @param points массив точек
*/
public Task(CoordinateSystem2d ownCS, ArrayList<Point> points) {
this.ownCS = ownCS;
this.points = points;
}
}

Теперь нам нужно прописать рисование задачи. Для этого нужно прописать преобразования из одной ОСК в другую.

В класс целочисленной ОСК добавим методы:

   /**
* Получить координаты вектора в текущей системе координат
*
* @param coords координаты вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2i getCoords(Vector2d coords, CoordinateSystem2d coordinateSystem) {
return getCoords(coords.x, coords.y, coordinateSystem);
}

/**
* Получить координаты вектора в текущей системе координат
*
* @param x координата X вектора в другой системе координат
* @param y координата Y вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2i getCoords(double x, double y, CoordinateSystem2d coordinateSystem) {
return new Vector2i(
(int) ((x - coordinateSystem.getMin().x) * (size.x - 1) / coordinateSystem.getSize().x + min.x),
(int) ((y - coordinateSystem.getMin().y) * (size.y - 1) / coordinateSystem.getSize().y + min.y)
);
}

/**
* Получить координаты вектора в текущей системе координат
*
* @param coords координаты вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2i getCoords(Vector2i coords, CoordinateSystem2i coordinateSystem) {
return this.getCoords(coords.x, coords.y, coordinateSystem);
}

/**
* Получить координаты вектора в текущей системе координат
*
* @param x координата X вектора в другой системе координат
* @param y координата Y вектора в другой системе координат
* @param coordinateSystem система координат, в которой заданы координаты вектора
* @return координаты вектора в текущей системе координат
*/
public Vector2i getCoords(int x, int y, CoordinateSystem2i coordinateSystem) {
return new Vector2i(
(x - coordinateSystem.min.x) * (size.x - 1) / (coordinateSystem.size.x - 1) + min.x,
(y - coordinateSystem.min.y) * (size.y - 1) / (coordinateSystem.size.y - 1) + min.y
);
}

в вещественной аналогичные методы уже определены

Для рисования нам нужно задать размер точек, для этого заведём константу в классе Task:

    /**
* Размер точки
*/
private static final int POINT_SIZE = 3;

Теперь пропишем метод рисования задачи в классе Task:

    /**
* Рисование задачи
*
* @param canvas область рисования
* @param windowCS СК окна
*/
public void paint(Canvas canvas, CoordinateSystem2i windowCS) {
canvas.save();
// создаём перо
try (var paint = new Paint()) {
for (Point p : points) {
// y-координату разворачиваем, потому что у СК окна ось y направлена вниз,
// а в классическом представлении - вверх
Vector2i windowPos = windowCS.getCoords(p.pos.x, p.pos.y, ownCS);
canvas.drawRect(Rect.makeXYWH(windowPos.x - POINT_SIZE, windowPos.y - POINT_SIZE, POINT_SIZE * 2, POINT_SIZE * 2), paint);
}
}
canvas.restore();
}

Весь класс задачи теперь будет таким

package app;

import io.github.humbleui.skija.Canvas;
import io.github.humbleui.skija.Paint;
import io.github.humbleui.skija.Rect;
import misc.CoordinateSystem2d;
import misc.CoordinateSystem2i;
import misc.Vector2i;

import java.util.ArrayList;

/**
* Класс задачи
*/
public class Task {
/**
* Текст задачи
*/
public static final String TASK_TEXT = """
ПОСТАНОВКА ЗАДАЧИ:
Заданы два множества точек в вещественном
пространстве. Требуется построить пересечение
и разность этих множеств""";

/**
* Вещественная система координат задачи
*/
private final CoordinateSystem2d ownCS;
/**
* Список точек
*/
private final ArrayList<Point> points;
/**
* Размер точки
*/
private static final int POINT_SIZE = 3;

/**
* Задача
*
* @param ownCS СК задачи
* @param points массив точек
*/
public Task(CoordinateSystem2d ownCS, ArrayList<Point> points) {
this.ownCS = ownCS;
this.points = points;
}

/**
* Рисование задачи
*
* @param canvas область рисования
* @param windowCS СК окна
*/
public void paint(Canvas canvas, CoordinateSystem2i windowCS) {
canvas.save();
// создаём перо
try (var paint = new Paint()) {
for (Point p : points) {
// получаем цвет точки
paint.setColor(p.getColor());
// y-координату разворачиваем, потому что у СК окна ось y направлена вниз,
// а в классическом представлении - вверх
Vector2i windowPos = windowCS.getCoords(p.pos.x, p.pos.y, ownCS);
// рисуем точку
canvas.drawRect(Rect.makeXYWH(windowPos.x - POINT_SIZE, windowPos.y - POINT_SIZE, POINT_SIZE * 2, POINT_SIZE * 2), paint);
}
}
canvas.restore();
}

}

Нам осталось дописать панель рисования

package panels;

import app.Point;
import app.Task;
import io.github.humbleui.jwm.Event;
import io.github.humbleui.jwm.Window;
import io.github.humbleui.skija.Canvas;
import misc.CoordinateSystem2d;
import misc.CoordinateSystem2i;
import misc.Vector2d;

import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom;


/**
* Панель рисования
*/
public class PanelRendering extends GridPanel {
/**
* Представление проблемы
*/
public static Task task;

/**
* Панель управления
*
* @param window окно
* @param drawBG флаг, нужно ли рисовать подложку
* @param color цвет подложки
* @param padding отступы
* @param gridWidth кол-во ячеек сетки по ширине
* @param gridHeight кол-во ячеек сетки по высоте
* @param gridX координата в сетке x
* @param gridY координата в сетке y
* @param colspan кол-во колонок, занимаемых панелью
* @param rowspan кол-во строк, занимаемых панелью
*/
public PanelRendering(
Window window, boolean drawBG, int color, int padding, int gridWidth, int gridHeight,
int gridX, int gridY, int colspan, int rowspan
) {
super(window, drawBG, color, padding, gridWidth, gridHeight, gridX, gridY, colspan, rowspan);

// ОСК от [-10.0,-10.0] до [10.0,10.0]
CoordinateSystem2d cs = new CoordinateSystem2d(
new Vector2d(-10.0, -10.0), new Vector2d(10.0, 10.0)
);

// создаём массив случайных точек
ArrayList<Point> points = new ArrayList<>();
for (int i = 0; i < 10; i++) {
// получаем случайное множество
Point.PointSet pointSet = ThreadLocalRandom.current().nextBoolean() ?
Point.PointSet.FIRST_SET : Point.PointSet.SECOND_SET;
// добавляем точку в случайном месте ОСК в указанное множество
points.add(new Point(cs.getRandomCoords(), pointSet));
}
task = new Task(cs, points);

}

/**
* Обработчик событий
*
* @param e событие
*/
@Override
public void accept(Event e) {

}

/**
* Метод под рисование в конкретной реализации
*
* @param canvas область рисования
* @param windowCS СК окна
*/
@Override
public void paintImpl(Canvas canvas, CoordinateSystem2i windowCS) {
task.paint(canvas, windowCS);
}
}

Не забудьте удалить заголовок Label и всё, что с ним связано в PanelRendering.

Интерес здесь представляет только инициализация задания. Мы сначала создаём ОСК, а потом генерируем случайные положения внутри неё и случайные множества.

Запустим приложение

w

Всё работает, как задумано. Можно переходить к следующей главе.

Создайте новый коммит task rendering works и отправьте его на сервер.

Задание

Пример готового проекта лежит здесь. Для выполнения первого задания Fork от него делать запрещается.

В ходе работы вам будет нужно сделать несколько коммитов с промежуточными состояниями проекта, поэтому в прямом копировании нет смысла. Готовый проект даётся для того, чтобы было проще разобраться, как выполнить поставленное задание.

Если у вас не выполнено предыдущее задание или выполнено не полностью, то сделайте Fork готового проекта из предыдущей главы.

Вам необходимо создать свой репозиторий, в котором добавлены следующие коммиты (для каждого сначала указывается название, потом требования):

  1. 4 panels - перепишите приложение так, чтобы область рисования была разделена на 4 секции и чтобы в каждой выводился свой текст
  2. add task classes - пропишите шаблоны классов задачи и точки
  3. float cs - пропишите вещественную ограниченную СК
  4. task rendering works - пропишите рисование задачи

w

Ссылку на github репозиторий необходимо отправить в поле ввода задания на сайте mdl.

Ссылка на контест