Компьютерная математика II, ММФ, БГУ
Лаврова О.А., март 2022
Треугольник Рело представляет собой область пересечения трех кругов радуса $r$ с центрами в вершинах равностороннего треугольника с длиной стороны $r$.
Правильный $n$-угольник Рело представляет собой область пересечения $n$ кругов радуса $r$ с центрами в вершинах правильного $n$-угольника с нечетным числом сторон длины $l$. Радиус круга $r$ согласован с длиной стороны $l$ правильного многоугольника таким образом, чтобы окружность радиуса $r$ проходила через две соседние вершины правильного $n$-угольника.
Правильный многоугольник Рело и круг являются примерами фигур постоянной ширины. Для фигуры постоянной ширины можно построить пары параллельных опорных прямых, которые касаются фигуры, но не пересекают ее, и, независимо от выбора пары опорных прямых, расстояние между прямыми будет всегда одинаковым.
Расстояние между опорными прямыми называется шириной фигуры. Ширина правильного многоугольника Рело равна радиусу $r$ пересекающихся кругов. Ширина круга равна диаметру круга. Среди всех фигур постоянной ширины треугольник Рело имеет наименьшую площадь, круг имеет наибольшую площадь.
$\color{red}{Напишите}$ пользовательскую функцию regular_polygon_Relo(n, center, r, N), которая возвращает матрицу, каждая строка которой содержит координаты точек, описывающих границу правильного многоугольника Рело.
Аргументы пользовательской функции имеют следующий смысл:
import math
import numpy as np
import matplotlib.pyplot as plt
n = 3 # количество вершин треугольника Рело
center = np.array([0,0]) # координаты центра треугольника Рело
r = 10. # ширина треугольника Рело
N = 100 # количество точек для описания стороны треугольника Рело
Вершины правильного многоугольника расположены на окружности, описанной вокруг многоугольника. Радиус $R$ окружности, описанной вокруг правильного $n$-угольника с длиной стороны $l$, вычисляется по формуле $$ R = \frac{l}{2 \sin{\pi/n}}. $$
Длина стороны $l$ правильного треугольника, на котором будем строить треугольник Рело, совпадает с шириной треугольника Рело $r$
l = r # !!! равенство справедливо только для треугольника Рело
Вычислим радиус $R$ описанной окружности
R = l/(2*math.sin(math.pi/n))
Введем прямоугольную декартову систему координат. Построим матрицу с координатами вершин правильного треугольника. Центр треуголника размещаем в точке $center$, радиус описанной окружности полагаем равным $R$
t = np.arange(0,2*np.pi,2*np.pi/n)
# обратите внимание на векторизацию вычислений с массивами без использования циклов
vertices = center + R*np.transpose([np.cos(t), np.sin(t)])
vertices
array([[ 5.77350269, 0. ], [-2.88675135, 5. ], [-2.88675135, -5. ]])
plt.plot(vertices[:,0],vertices[:,1],'r.',markersize=20)
plt.axis('equal');
Обозначим через $\alpha$ центральный угол, соответствующий стороне правильног $n$-угольника. Тогда $$\alpha = 2 \pi /n.$$
Обозначим через $\beta$ центральный угол, соответствующий стороне правильного многоугольника Рело, когда центр окружности расположен в вершине правильного многоугольника. Тогда $$\beta = \alpha/2.$$
Построим матрицу с координатами точек, описывающих сторону треугольника Рело относительно вершины vertices[0]. Сторона представляет собой дугу окружности радиуса $r$ с центром в точке vertices[0] и значением угла $[\pi-\beta/2, \pi+\beta/2]$.
Вычислим значения введенных величин
alpha = 2*math.pi/n
beta = alpha/2
Введем вспомогательную последовательность значений угла для построения координат точек стороны треугольника Рело
angle = np.linspace(-beta/2, beta/2, N)
Строим матрицу с координатами точек первой стороны
# обратите внимание на векторизацию вычислений с массивами без использования циклов
side0 = vertices[0] + r*np.transpose([np.cos(angle + np.pi), np.sin(angle + np.pi)])
plt.plot(vertices[:,0],vertices[:,1],'r.',markersize=20)
plt.plot(side0[:,0],side0[:,1],'b-',markersize=20)
plt.axis('equal');
Построим матрицу с координатами точек, описывающих сторону треугольника Рело относительно второй вершины vertices[1]. Сторона представляет собой дугу окружности радиуса $r$ с центром в точке vertices[1] и значением угла $[\pi+\alpha-\beta/2, \pi+\alpha+\beta/2]$
# обратите внимание на векторизацию вычислений с массивами без использования циклов
side1 = vertices[1] + r*np.transpose([np.cos(angle + np.pi + alpha), np.sin(angle + np.pi + alpha)])
plt.plot(vertices[:,0],vertices[:,1],'r.',markersize=20)
plt.plot(side0[:,0],side0[:,1],'b-',markersize=20)
plt.plot(side1[:,0],side1[:,1],'g-',markersize=20)
plt.axis('equal');
Создадим список из матриц, каждая их которых содержит координаты точек одной из сторон треугольника Рело
# обратите внимание на векторизацию вычислений с массивами без использования циклов
list_sides = [vertices[i] + r*np.transpose([np.cos(angle + np.pi + i*alpha), np.sin(angle + np.pi + i*alpha)]) for i in range(n)]
С помощью фунции concatenate из расширения numpy объединим массивы для каждой из сторон в единый массив sides
sides = np.concatenate(list_sides)
plt.plot(vertices[:,0],vertices[:,1],'r.',markersize=20)
plt.plot(sides[:,0],sides[:,1],'b-',markersize=20)
plt.axis('equal');
Следуя аналогичным рассуждениям из Этапа 1, $\color{red}{создайте}$ матричное описание границы правильного многоугольника Рело для произвольных значений переменных n, center, r, N.
$\color{red}{Внимание}$: длина стороны $l$ правильного многоугольника, на основании которого строится многоугольник Рело, является неизвестной величиной и должна быть выражена через количество вершин $n$ и ширину $r$ многоугольника Рело.
$\color{red}{Напишите}$ подробно, как получена аналитическая зависимость $l$ от $n$ и $r$. Объяснения оформите в тексте документа с лабораторной работой.
$\color{red}{\text{Напишите}}$ результирующую пользовательскую функцию regular_polygon_Relo(n, center, r, N) на основании кода из Этапа 2.
Для функции regular_polygon_Relo $\color{red}{напишите}$ строки документации.
$\color{red}{Протестируйте}$ функцию regular_polygon_Relo для различных значений аргументов в предположении, что корректность вводимых данных не гарантируется.
$\color{red}{Постройте}$ в одной системе координат правильные многоугольники Рело для различного количества вершин и различных положений центров. При этом $\color{red}{вызывайте}$ функцию regular_polygon_Relo с различными способами указания позиционных и ключевых аргументов.
$\color{red}{Создайте}$ модуль relo.py, в котором будет содержаться пользовательская функция regular_polygon_Relo.
Оператор assert может использоваться для контроля за передаваемыми значеними аргументов при вызове функции. Оператор assert генерирует исключение по условию. Например,
def f(r):
assert r>0, 'radius r should be positive'
...
return None
Если условие $r>0$ истинно, то код, следующий за оператором assert, выполняется
f(1)
Если условие $r>0$ ложно, то оператор assert генерирует исключение AssertionError, прерывает процесс выполнения кода и выдает сообщение об ошибке с использованием строкового объекта, указанного при вызове оператора assert
f(0)
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) ~\AppData\Local\Temp/ipykernel_4772/1333598009.py in <module> ----> 1 f(0) ~\AppData\Local\Temp/ipykernel_4772/3553163912.py in f(r) 1 def f(r): ----> 2 assert r>0, 'radius r should be positive' 3 ... 4 return None AssertionError: radius r should be positive