Юбилейная огранка создана в США к 60-летию вступления на престол королевы Виктории в 1897 году. Площадка этой огранки имеет очень небольшой размер и зачастую грани примыкающие к ней сходятся практически в одну точку. По ссылке Jubilee - Light Dispersion можно увидеть юбилейную огранку отображенную при помощи кубических карт. При нажатии на приведенной по ссылке странице кнопки Inverse многогранник отобразится на черном фоне.
Как и большинство других огранок, юбилейная огранка (jubilee) состоит из трех частей – короны (верхняя часть огранки),
рундиста (средняя часть огранки) и павильона (нижняя часть огранки).
Нумерация вершин огранки показаны на рисунках 1 и 2.
На рисунке 1 показана нумерация вершин короны при взгляде на нее сверху, а на рисунке 2 - нумерация вершин павильона
при взгляде на него сверху и наблюдателе находящимся при этом внутри модели огранки. Это сделано для того, чтобы положение
граней короны и павильона на рисунках соответствовало друг другу. Поэтому, так как при рассматривании огранки
в запущенной программе мы находимся снаружи модели, то нумерация вершин павльона будет отличаться от нумерации
показанной на рисунке 2 соответствущем образом.
// СДМ - структура данных модели var lw = 1.0; // Отношение длины огранки к ее ширине // Рундист var r = 0.2; // Толщина рундиста var square_deviation = 0.0001; // Квадратичность рундиста // Корона var hCrown = 0.28; // Высота короны var t = 0.05; // Размер площадки var crown_middle_diameter = 0.77; // Определяет размер эллипса опоясывающего корону в ее средней части. // На этом диаметре расположены вершины короны 16, 17, 18, .... 23. var hCrownMid = 0.16; // Задает высоту вершин короны 16, 17, 18, .... 23. var hCrownDown = 0.085; // Задает высоту вершин короны 24, 25, ... 31 // Павильон var hp = 0.46; // Глубина павильона var ang_pav = 52*DEGREE; // Задает угол наклона граней D0, D1, .... D7. // Эти грани сходятся в одной точке если их продожить вниз. var DownCleanLevel = 0.1; // Задает глубину вершин павильона 0, 1, 2, 3, 4, 5, 6, 7. // Также задает глубину вершин павильона 40, 41, 42, 43, 44, 45, 46, 47. var hPavFacet1 = 0.75; // Задает глубину вершин павильона 8, 9, 10, ... 22, 23. var hPavFacet2 = 0.60; // Определяет размер и положение самых нижних граней павильона F0 - F7.
// Также как в бриллианте
InitGirdle(64);
var nCrown = 32;
var nGirdle = 64;
var nPav = 49;
// Вспомогательные переменные и объекты
var Z1 = new Vector3D(0,0,1); // Единичный вертикально расположенный ветор.
var norm2d = new Vector2D;
var normPlaneVector = new Vector3D();
var i, j;
// Конструируем корону
// Плоскость на которой расположена площадка
var planeTable = new Plane3D();
planeTable.CreatePlaneNormalDistOXYZ(Z1, hCrown + r/2);
// этот угол можно услоно назвать углом наклона короны
// (напоминаем, что 0.5 это ширина огранки в условных единицах)
var tan_beta = hCrown / (0.5 - t/2);
// Виртуальная точка upPoint необходима для определения
// вершин короны лежащих на площадке
var upPoint = new Point3D(0.0, 0.0, r/2 + 0.5 * tan_beta);
// Сначала проводим прямые через upPoint и соответствующие вершины рундиста.
// Затем находим пересечение этих прямых с плоскостью площадки.
for (i = 0; i < 8; i++)
{
var line = new Line3D(girdle[i*8], upPoint);
crown[i] = line.IntersectionLinePlane(planeTable);
}
// Координаты на плоскости OXY средних (middle) по высоте
// вершин короны 16, 17, 18, .... 23 расположены на эллипсе.
// Поэтому создаем (супер)эллипс на котором будут находиться 8 вершин короны.
// Эллипс располагается на высоте задаваемой параметром hCrownMid.
// Размер эллипса задается параметром crown_middle_diameter.
// Функция FillEllipse подобна функции расчитывающей линию рундиста.
FillEllipse(0.5 * crown_middle_diameter);
// Средние по высоте вершины короны расположились на (супер)эллипсе.
for (i = 0; i < 8; i++)
{
crown[16+i] = new Point3D(temp[i][0], temp[i][1], r/2 + hCrownMid);
}
// Нижние грани короны - рядом с рундистом - A0, A1, .... A7
// Определяем векторы vec0 - vec7 задающие азимуты граней A0 - A7
var vec0 = new Vector3D(girdle[0][0] - girdle[8][0], girdle[0][1] - girdle[8][1], 0.0);
var vec1 = new Vector3D(girdle[8][0] - girdle[16][0], girdle[8][1] - girdle[16][1], 0.0);
...............................................
var vec7 = new Vector3D(girdle[56][0] - girdle[64][0], girdle[56][1] - girdle[64][1], 0.0);
// грани A0 - A7 расчитываем по векторам vec0 - vec7 и соответствущим парам точек
var A0 = new Plane3D();
A0.CreatePlaneVectorTwoPoints(vec0, crown[16], girdle[4]);
var A1 = new Plane3D();
A1.CreatePlaneVectorTwoPoints(vec1, crown[17], girdle[12]);
var A2 = new Plane3D();
................................................
var A7 = new Plane3D();
A7.CreatePlaneVectorTwoPoints(vec7, crown[23], girdle[60]);
// Пятиугольные C0, C1, C2, C3, C4, C5, C6, C7;
var C0 = new Plane3D();
C0.CreatePlaneThreePoints(crown[0], crown[1], crown[16]);
var C1 = new Plane3D();
C1.CreatePlaneThreePoints(crown[1], crown[2], crown[17]);
........................................................
var C7 = new Plane3D();
C7.CreatePlaneThreePoints(crown[7], crown[0], crown[23]);
// Плоскость определяющая высоту треугольных граней примыкающих к рундисту
var pl_crown_down = new Plane3D;
pl_crown_down.CreatePlaneNormalDistOXYZ(Z1, hCrownDown + r/2);
// вершины короны 24, 25, ... 31 находим как точки пересечения трех плоскостей
crown[24] = pl_crown_down.IntersectionThreePlanes(A7, A0);
crown[25] = pl_crown_down.IntersectionThreePlanes(A0, A1);
.........................................................
crown[31] = pl_crown_down.IntersectionThreePlanes(A6, A7);
// Четырехугольные средние грани короны B0, B1, B2;
var B0 = new Plane3D();
B0.CreatePlaneThreePoints(crown[23], crown[16], crown[24]);
var B1 = new Plane3D();
B1.CreatePlaneThreePoints(crown[16], crown[17], crown[25]);
var B2 = new Plane3D();
B2.CreatePlaneThreePoints(crown[17], crown[18], crown[26]);
// Вершины верхнего яруса короны (чуть ниже площадки)
crown[8] = B0.IntersectionThreePlanes(C7, C0);
crown[9] = B1.IntersectionThreePlanes(C0, C1);
crown[10] = B2.IntersectionThreePlanes(C1, C2);
// Исходя из симметрии огранки
crown[11] = new Point3D( crown[9][0], -crown[9][1], crown[9][2]);
crown[12] = new Point3D( crown[8][0], -crown[8][1], crown[8][2]);
crown[13] = new Point3D(-crown[11][0], crown[11][1], crown[11][2]);
crown[14] = new Point3D(-crown[10][0], crown[10][1], crown[10][2]);
crown[15] = new Point3D(-crown[9][0], crown[9][1], crown[9][2]);
// Корректировка положения вершин рундиста по оси Z
corr_gd_crown(0, 4, 24);
corr_gd_crown(4, 8, 25);
.........................
corr_gd_crown(60, 0, 24);
.......................................................................
.......................................................................
function corr_gd_crown(gd1, gd2, cr)
{
var planeT = new Plane3D();
planeT.CreatePlaneThreePoints(girdle[gd1], girdle[gd2], crown[cr]);
var n = 4; //gd2 - gd1;
var i = 0;
for (i = 1; i < n; i++)
{
var vert_line = new Line3D(girdle[gd1 + i], girdle[gd1 + i + 64]);
var pt = vert_line.IntersectionLinePlane(planeT);
girdle[gd1 + i][2] = pt[2];
}
}
// Конструируем павильон
var kollet = new Point3D(0, 0, - hp - r/2);
// Находим вершину где сходятся все грани D0, D1, .... D7
var dnPoint = new Point3D(0.0, 0.0, - 0.5 * Math.tan(ang_pav) - r/2);
// Точки пересечения основных граней павильона между собой на уровне рундиста
// (как у стандартного бриллианта)
var line = [8]; // касательные к 8 точкам на рундисте то есть касательные
// в вершинах рундиста 68, 76, 84, 92, 100, 108, 116, 124
var j = 3;
var k = 5;
for ( i = 0; i < 8; i++ )
{
var dir = new Vector2D(girdle[j][0] - girdle[k][0], girdle[j][1] - girdle[k][1]);
dir.Normer();
var pt = new Point2D(girdle[4+i*8][0], girdle[4+i*8][1]);
var ln = new Line2D();
ln.CreateLineVectorPoint(dir, pt);
line[i] = ln;
j = j + 8;
k = k + 8;
}
var u = [8]; // точки пересечения предыдущих касательных между собой
u[1] = line[0].IntersectionTwoLines(line[1]);
.............................................
u[7] = line[6].IntersectionTwoLines(line[7]);
u[0] = line[7].IntersectionTwoLines(line[0]);
// Расчет виртуальных вершин, которых в натуре нет.
// Эти виртуальные вершины используются для создания плоскостей,
// в которых лежит большинство граней павильона.
// Построение (до некоторой степени) подобно построению,
// фасет павильона бриллианта
// Внимание ! При изменени параметров, если hPavFacet2 = hPavFacet1
// происходит неправильное построение павильона так как координаты части
// вершин павильона совпадает со значением координат некоторых других его вершин.
// Иными словами часть вершин сливается в единые вершины !
var v = [16]; // шестнадцать виртуальных вершин
for (i = 0; i < 8; i++)
{
// Сравнить с вектором dir при построении павильона бриллианта !!!
// Предполагаем, что все трехмерные точки двумерные координаты которых лежат в массиве u,
// имеют глубину равную -r/2. Поэтому векторы имеют следующий вид:
var dir = new Vector3D(dnPoint[0] - u[i][0], dnPoint[1] - u[i][1], dnPoint[2] - (-r/2));
// dir.Normer(); // нормировка вектора dir все испортит !!!
v[i] = new Point3D(dnPoint[0] - hPavFacet1 * dir[0], // вершины расположенные
dnPoint[1] - hPavFacet1 * dir[1], // ближе к рундисту
dnPoint[2] - hPavFacet1 * dir[2]);
v[8+i] = new Point3D(dnPoint[0] - hPavFacet2 * dir[0], // вершины расположенные
dnPoint[1] - hPavFacet2 * dir[1], // ближе к калетте
dnPoint[2] - hPavFacet2 * dir[2]);
}
// Плоскости в которых лежат грани расположенные рядом с калетой
// F0, F1, F2, F3, F4, F5, F6, F7;
var F0 = new Plane3D();
F0.CreatePlaneThreePoints(kollet, v[8], v[9]);
var F1 = new Plane3D();
F1.CreatePlaneThreePoints(kollet, v[9], v[10]);
...............................................
var F7 = new Plane3D();
F7.CreatePlaneThreePoints(kollet, v[15], v[8]);
// Плоскости в которых лежат грани D0 ... D7
var D0 = new Plane3D();
D0.CreatePlaneThreePoints(girdle[68], v[0], v[1]);
var D1 = new Plane3D();
D1.CreatePlaneThreePoints(girdle[76], v[1], v[2]);
..................................................
var D7 = new Plane3D();
D7.CreatePlaneThreePoints(girdle[124], v[7], v[0]);
// Плоскости, опирающиеся на рундист
// G0, G1, G2, G3, G4, G5, G6, G7, G8, G9, G10, G11, G12, G13, G14, G15;
var G15 = new Plane3D();
G15.CreatePlaneThreePoints(girdle[124], girdle[64], v[0]);
var G0 = new Plane3D();
G0.CreatePlaneThreePoints(girdle[64], girdle[68], v[0]);
........................................................
........................................................
var G13 = new Plane3D();
G13.CreatePlaneThreePoints(girdle[116], girdle[120], v[7]);
var G14 = new Plane3D();
G14.CreatePlaneThreePoints(girdle[120], girdle[124], v[7]);
// Горизонтальная плоскость на уровне DownCleanLevel
// Параметр DownCleanLevel влияет не только на положение
// вершин 0 - 7 павильона, но также на положение вершин 40 - 47 павидьона.
var pl_hPavFacet0 = new Plane3D();
pl_hPavFacet0.CreatePlaneNormalDistOXYZ(Z1, DownCleanLevel * (dnPoint[2] + r/2) - r/2 );
pavil[0] = pl_hPavFacet0.IntersectionThreePlanes(G15, G0);
pavil[1] = pl_hPavFacet0.IntersectionThreePlanes(G1, G2);
...........................................................
pavil[7] = pl_hPavFacet0.IntersectionThreePlanes(G13, G14);
// Два вектора для расчета плоскости E0
var vec_E0_1 = new Vector3D(girdle[68][0] - girdle[124][0], girdle[68][1] - girdle[124][1], 0.0);
vec_E0_1.Normer();
var vec_E0_2 = new Vector3D(v[0][0] - v[8][0], v[0][1] - v[8][1], v[0][2] - v[8][2]);
vec_E0_2.Normer();
var vec_0 = vec_E0_1.Cross(vec_E0_2);
vec_0.Normer();
// Два вектора для расчета плоскости E1
var vec_E1_1 = new Vector3D(girdle[76][0] - girdle[68][0], girdle[76][1] - girdle[68][1], 0.0);
vec_E1_1.Normer();
var vec_E1_2 = new Vector3D(v[1][0] - v[9][0], v[1][1] - v[9][1], v[1][2] - v[9][2]);
vec_E1_2.Normer();
var vec_1 = vec_E1_1.Cross(vec_E1_2);
vec_1.Normer();
// Два вектора для расчета плоскости E2
var vec_E2_1 = new Vector3D(girdle[84][0] - girdle[76][0], girdle[84][1] - girdle[76][1], 0.0);
vec_E2_1.Normer();
var vec_E2_2 = new Vector3D(v[2][0] - v[10][0], v[2][1] - v[10][1], v[2][2] - v[10][2]);
vec_E2_2.Normer();
var vec_2 = vec_E2_1.Cross(vec_E2_2);
vec_2.Normer();
// Создаем плоскости в которых расположены грани E0, E1 и E2
var E0 = new Plane3D();
E0.CreatePlaneNormalVectorPoint(vec_0, pavil[0]);
var E1 = new Plane3D();
E1.CreatePlaneNormalVectorPoint(vec_1, pavil[1]);
var E2 = new Plane3D();
E2.CreatePlaneNormalVectorPoint(vec_2, pavil[2]);
// Расчет положения шести вершин ограничивающих грань E0
pavil[23] = E0.IntersectionThreePlanes(D7, G15);
pavil[8] = E0.IntersectionThreePlanes(D0, G0);
pavil[39] = E0.IntersectionThreePlanes(D7, F7);
pavil[40] = E0.IntersectionThreePlanes(F7, F0);
pavil[24] = E0.IntersectionThreePlanes(D0, F0);
// Расчет положения шести вершин ограничивающих грань E1
pavil[9] = E1.IntersectionThreePlanes(D0, G1);
pavil[10] = E1.IntersectionThreePlanes(D1, G2);
pavil[25] = E1.IntersectionThreePlanes(D0, F0);
pavil[41] = E1.IntersectionThreePlanes(F0, F1);
pavil[26] = E1.IntersectionThreePlanes(D1, F1);
// Расчет положения шести вершин ограничивающих грань E2
pavil[11] = E2.IntersectionThreePlanes(D1, G3);
pavil[12] = E2.IntersectionThreePlanes(D2, G4);
pavil[27] = E2.IntersectionThreePlanes(D1, F1);
pavil[42] = E2.IntersectionThreePlanes(F1, F2);
pavil[28] = E2.IntersectionThreePlanes(D2, F2);
// Исходя из симметрии модели огранки
pavil[13] = new Point3D(pavil[10][0], -pavil[10][1], pavil[10][2]);
pavil[14] = new Point3D(pavil[9][0], -pavil[9][1], pavil[9][2]);
....................................................................
....................................................................
pavil[47] = new Point3D(-pavil[41][0], pavil[41][1], pavil[41][2]);
// калетта
pavil[48] = new Point3D(kollet[0], kollet[1], kollet[2]);
// Корректировка положения вершин рундиста по оси Z
corr_gd_pav(64, 68, 0);
corr_gd_pav(68, 72, 1);
........................
........................
corr_gd_pav(124, 64, 0);
.........................................................................
.........................................................................
function corr_gd_pav(gd1, gd2, pav)
{
var planeT = new Plane3D();
planeT.CreatePlaneThreePoints(girdle[gd1], girdle[gd2], pavil[pav]);
var n = 4; //gd2 - gd1;
var i;
for (i = 1; i < n; i++)
{
var vert_line = new Line3D(girdle[gd1 + i], girdle[gd1 + i - 64]);
var pt = vert_line.IntersectionLinePlane(planeT);
girdle[gd1 + i][2] = pt[2];
}
}