Глава 10  ◄     Содержание     ►   Глава 12

Three.js и геометрия.   Глава 11.   Юбилейная огранка (Jubilee cut)

Юбилейная огранка создана в США к 60-летию вступления на престол королевы Виктории в 1897 году. Площадка этой огранки имеет очень небольшой размер и зачастую грани примыкающие к ней сходятся практически в одну точку. По ссылке Jubilee - Light Dispersion можно увидеть юбилейную огранку отображенную при помощи кубических карт. При нажатии на приведенной по ссылке странице кнопки Inverse многогранник отобразится на черном фоне.


No      All      Cr-Gd-Pav

Нумерация вершин и обозначение граней модели

Как и большинство других огранок, юбилейная огранка (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];
				}	
			}

   Глава 10  ◄     Содержание     ►   Глава 12