Продолжим рассмотрение функций библиотеки WebGeometry применительно к построению
геометрических фигур на плоскости. В данном разделе кривые линии на плоскости будут отрисовываться
путем соединения предварительно рассчитанных координат точек принадлежащих этим линиям
отрезками прямых.
Предположим, что функциональная зависимость y от x не задана непосредственно y = f(x),
а через промежуточную величину t, называемую параметром.
Тогда уже две формулы задают параметрическое представление функции.
При построении кривых на плоскости в качестве параметра t мы будем обычно брать угол φ.
Этот угол обычно определяется как угол наклона к оси абсцисс прямой проведенный из начала координат
(или из некоторой точки характерной для данной кривой) до точки лежащей непосредственно на кривой.
В качестве линий определяющих форму рундиста огранок часто используется эллипс (или окружность), а также замкнутая кривая имеющая название суперэллипс
Для расчета координат точек лежащих на суперэллипсе достаточно рассчитать его вид только для первого квадранта, а для остальных квадрантов суперэллипса можно найти координаты принадлежащих ему точек исходя из соображений симметрии.
Для расчета точек на суперэллипсе используется функция init_superellipse.
Параметр square_deviation задает величину отклонения суперэллипса от эллипса.
Степень суперэллипса равна
2 / ( 1 - square_deviation ).
Параметр lw задает удлинение эллипса вдоль оси X.
При значениях square_deviation = 0.0 и lw = 1.0 суперэллипс становится окружностью.
function init_superellipse(O, R, lw, square_deviation)
{
var fi_0 = -90*DEGREE;
var r1 = R * lw; // Полуось эллипса по оси X
var r2 = -R; // Полуось эллипса по оси Y
if ( square_deviation < -1 || square_deviation >= 0.995 )
return null;
var p = 2 / ( 1 - square_deviation ); // Степень суперэллипса
var del_fi = 2 * M_PI / 64; // Шаг углового параметра
var x, y, w, fi;
var i;
for (i = 0; i < 64; i++)
{
fi = fi_0 + i*del_fi; // Значение углового параметра
x = Math.cos(fi);
y = Math.sin(fi);
w = Math.pow (Math.abs (x), p) + Math.pow (Math.abs (y), p);
w = 1 / Math.pow ( w, 1/p );
var point = new Point2D ( O[0] + r1 * w * x, O[1] + r2 * w * y);
points[i] = point;
}
}
Отрисовку на холсте осуществляет функция draw_superellipse,
текст которой находится в файле superellipse.js.
Кривая с названием фолиум (simple folium) имеет форму листа. В справочниках по плоским кривым можно
найти ее параметрическое представление и по приведенным в них формулам построить эту кривую (рисунок 2).
Однако мы построим ее не по формулам, а чисто геометрическим способом. Для этого проведем окружность cir
имеющую диаметр OA. Из точки O проведем прямую до пересечения в точке P с этой окружностью.
Найдем проекцию точки P на прямую OA. Эта проекция будет находиться в точке Q.
Из точки Q опустим перпендикуляр на прямую OP.
Точка М пересечения этого перпендикуляра с прямой OP будет принадлежать искомой прямой.
Построение остальных точек кривой можно осуществить повторением приведенного построения
путем проведения последовательности прямых пересекающих окружность cir.
// Кривую будем проводить через 32 точки.
var points_folium = [32];
..........................
..........................
var i;
// Рассчитаем 16 точек лежащих на верхней части искомой кривой.
var n = 16;
var fi = 0;
var d_fi = 90*DEGREE / n;
var cir_center = new Point2D(O[0] + a, O[1]);
var cir = new Circle2D(cir_center, a);
var pt = new Point2D(O[0] + 1, O[1]);
for (i = 1; i < n; i++)
{
fi = fi + d_fi;
pt[1] = O[1] + Math.tan(fi);
// Создаем прямую составляющую угол fi с осью OX
// (она проходит через точки O и pt - на рисунке это прямая OP)
var line = new Line2D(O, pt);
var point1 = new Point2D();
var point2 = new Point2D();
var P = new Point2D();
// Определяем точку P
if(!cir.IntersectionLineCircle (line, point1, point2))
{
return null;
}
// Выбор точки P из двух точек пересечения прямой с окружностью
if (point1[1] > point2[1])
{
P[0] = point1[0];
P[1] = point1[1];
}
else
{
P[0] = point2[0];
P[1] = point2[1];
}
// Определяем координаты точки Q
var Q = new Point2D(P[0], O[1]);
// Создаем прямую QM перпендикулярную прямой line
// и проходящую через точку Q.
var QM = line.CreateNormalLinePoint(Q);
// Находим точку M лежащую на кривой simple folium
var M = line.IntersectionTwoLines(QM);
points_folium[i] = M;
}
points_folium[0] = new Point2D(O[0] + 2*a, O[1]);
points_folium[16] = new Point2D(O[0], O[1]);
// Все остальные точки лежащие на кривой simple folium
// находим из соображений симметрии.
for (i = 1; i < 16; i++)
{
points_folium[16+i] = new Point2D(points_folium[16-i][0],
- points_folium[16-i][1] + 2 * O[1] );
}
Полный текст программы осуществляющий расчет и построение на холсте кривой фолиум находится в файле folium.js.
Построение производится следующим образом. Пусть задана точка A находящаяся на расстоянии a от оси ординат. Вокруг точки A вращается луч на котором откладывается отрезок BM равный отрезку OB. Геометрическое место точек M и будет являться искомой кривой.
// Кривую будем проводить через 32 точки.
var points_strophoid = [32];
........................................
........................................
var i;
// Рассчитаем 16 точек лежащих на верхней части искомой кривой.
var n = 16;
var fi = 0;
var d_fi = 90*DEGREE / n;
// Создаем вертикальную прямую проходящую через точку O.
// При запуске программы эта прямая совпадает с осью ординат.
var OY = new Line2D(O, new Point2D(O[0], O[1] + 1));
var A = new Point2D(O[0] - a, O[1]);
var pt = new Point2D(A[0] + 1, A[1]);
var B; // Объявление переменной для точки на вертикальной
// прямой проходящей через точку O. Мы будем вычислять
// координаты этой точки внутри цикла.
for (i = 1; i < n; i++)
{
fi = fi + d_fi;
pt[1] = A[1] + Math.tan(fi);
// Создаем прямую составляющую угол fi с осью OX
// (она проходит через точки A и pt - на рисунке это прямая AB)
var line = new Line2D(A, pt);
B = line.IntersectionTwoLines(OY);
var dist_OB = B.Distance(O);
var dist_AB = B.Distance(A);
var dist_AM = dist_AB - dist_OB;
var dist_MB = dist_OB;
var relation = dist_AM / dist_MB;
var M = new Point2D();
// точка M делит отрезок AB в отношении равным величине relation
// ( вспоминаем аналитическую геометрию )
M[0] = (A[0] + relation * B[0]) / (1 + relation);
M[1] = (A[1] + relation * B[1]) / (1 + relation);
points_strophoid[i] = M;
}
points_strophoid[0] = O;
points_strophoid[16] = A;
// Все остальные точки лежащие на кривой strophoid
// находим из соображений симметрии.
for (i = 1; i < 16; i++)
{
points_strophoid[16+i] = new Point2D(points_strophoid[16-i][0],
- points_strophoid[16-i][1] + 2 * O[1] );
}
Полный текст программы осуществляющий расчет и построение строфоиды находится в файле strophoid.js.
Улитка паскаля - это плоская линия, которая описывается фиксированной точкой одной окружности,
катящейся по неподвижной другой окружности. Если радиусы обеих окружностей равны,
то такая кривая называется кардиоидой. Обозначим через R1 расстояние от центра O до центра
подвижной окружности, а через R2 - радиус подвижной окружности (смотри работу программы).
Кардиода получается из улитки Паскаля когда R1 = 2 × R2.
Построение улитки Паскаля иллюстрирует следующий код:
// Кривую будем проводить через 32 точки.
var points_cardioid = [32];
...........................
...........................
var n = 32;
var fi = 0;
var d_fi = 180*DEGREE / n;
var O = new Point2D (0, 0.0);
for (i = 0; i < n; i++)
{
fi = fi + d_fi;
var x1 = R1 * Math.cos(fi); // одинарное значение угла φ
var y1 = R1 * Math.sin(fi); // одинарное значение угла φ
// Точка на одной окружности
var pt1 = new Point2D(x1, y1);
var x2 = - R2 * Math.cos(2*fi); // удвоенное значение угла φ
var y2 = - R2 * Math.sin(2*fi); // удвоенное значение угла φ
// Точка на другой окружности
var pt2 = new Point2D(x2, y2);
// Складываем координаты точек на двух окружностях
var pt = pt1.Add(pt2);
points_cardioid[i] = pt;
fi = fi + d_fi;
}
Полный текст программы осуществляющий расчет и построение улитки Паскаля находится в файле cardioid.js.
Waviness - это плоская линия, образованная комбинацией двух тригонометрических функций:
var N = 96;
var i;
var del = 2 * M_PI / N;
var fi = 0;
for(i = 0; i < N; i++)
{
fi = 90*DEGREE - i*del;
var x = R * (1 / ( 1 + e * Math.cos(m * fi))) * Math.cos(fi) + O[0];
var y = R * (1 / ( 1 + e * Math.cos(m * fi))) * Math.sin(fi) + O[1];
var point = new Point2D ( lw * x, y);
points_w[i] = point;
}
Форма эллипса (или окружности) изменяется путем умножения координат каждой его точки на
величину равную
1 / ( 1 + e * Math.cos(m * fi))
Значение m задает количество холмов и впадин на эллипсе,
а величина e определяет их глубину/высоту. Желательно задавать величине e
значение равное целому положительному числу. В этом случае количество холмов и впадин также
будет равно целому (а не дробному) числу.
В дальнейшем 2D-функции входящие в библиотеку WebGeometry нам понадобятся для построения рундистов огранок, а также программ-чертежей иллюстрирующих соответствующие построения.
В следующей главе мы перейдем к созданию 3D-моделей сложных многогранников и будем для этого использовать 3D-функции входящие в библиотеку WebGeometry.