Создание стен. Часть 1. Создание эквидистант.
Для построения стен заданной толщины по заданной полилинии необходимо определение эквидистант к этой линии. Основной задачей построения эквидистант является нахождения точек в углах линии – пересечений эквидистант.

Для каждой точки полилинии определяем внутреннюю и внешнюю точку эквидистанты и добавляем их в соответствующие массивы
for (let i=0; i < points.length; i++){ if (points[i+1] && points[i+2]){ const coner = {}; coner.pointA = points[i]; coner.vertex = points[i+1]; coner.pointC = points[i+2]; const inside = buildEquidistantPoint(coner, WALLTHICKNESS, 'inner'); const outer = buildEquidistantPoint(coner, WALLTHICKNESS, 'outer'); wallArray.push(inside); wallArrayOuter.push(outer); } }
Определение внутренней точки происходит следующим образом
function buildEquidistantPoint(coner, wallThickness, type){ const halfTickness = 0.5 * wallThickness; const leftSide = coner.vertex.clone().sub(coner.pointA.clone()).normalize(); const rightSide = coner.vertex.clone().sub(coner.pointC.clone()).normalize(); const angle = rightSide.angle() - leftSide.angle(); const alfa = angle/2; let bisectorLength; if(type === 'inner'){ bisectorLength = halfTickness/Math.sin(-alfa); } if(type === 'outer'){ bisectorLength = halfTickness/Math.sin(alfa); } const bisector = leftSide.clone().rotateAround(new THREE.Vector2(0, 0), alfa); const point = coner.vertex.clone().add((bisector.clone()).multiplyScalar(bisectorLength)); return point; }
Первое – определяем вектора, компланарные линиям, выходящим из данной точки, для это производим вычитание векторов вершин и нормализуем им для получение единичного вектора.
const leftSide = coner.vertex.clone().sub(coner.pointA.clone()).normalize(); const rightSide = coner.vertex.clone().sub(coner.pointC.clone()).normalize();
второе – определяем угол между ними
const angle = rightSide.angle() - leftSide.angle();
точка эквидистанты всегда лежит на биссектрисе угла, поэтому угол делим пополам
const alfa = angle/2;
затем определяем гипотенузу в треугольнике, образованном половиной толщины стены и полилинией. Обозначим ее bisectorLength
bisectorLength = halfTickness/Math.sin(-alfa);
получим вектор, выходящий из вершины в точку b поворотом вектора leftSide на угол alfa
const bisector = leftSide.clone().rotateAround(new THREE.Vector2(0, 0), alfa);
все, что нам остается – это перенести точку B по полученному вектору. Для этого умножим его на скаляр – длину полученного отрезка bisectorLength и произведём сложение вектора вершины угла и полученного вектора.
const point = coner.vertex.clone().add((bisector.clone()).multiplyScalar(bisectorLength));
построение конечных точек незамкнутых линий осуществляет подобным образом, только угол всегда одинаков const angle = 3 * Math.PI / 4;
function buildEnding(pointB, pointA, wallThickness) { const halfTickness = 0.5 * wallThickness; const ending = []; const BA = pointB.clone().sub(pointA.clone()).normalize(); const angle = 3 * Math.PI / 4; const bisectorLength = halfTickness/Math.sin(angle); const bisectorOuter = BA.clone().rotateAround(new THREE.Vector2(0, 0), -angle); const outerEnding = pointB.clone().add((bisectorOuter.clone().negate()).multiplyScalar(bisectorLength)); ending.push(outerEnding); const bisectorInner = BA.clone().rotateAround(new THREE.Vector2(0, 0), angle); const innerEnding = pointB.clone().add((bisectorInner.clone().negate()).multiplyScalar(bisectorLength)); ending.push(innerEnding); return ending; }
Обработка конечных точек полилинии происходит следующим образом
if(points[0].equals(points[points.length-1])) { const coner = {}; coner.pointA = points[points.length - 2]; coner.vertex = points[0]; coner.pointC = points[1]; const inside = buildEquidistantPoint(coner, WALLTHICKNESS, 'inner'); const outer = buildEquidistantPoint(coner, WALLTHICKNESS, 'outer'); wallArray.push(inside); wallArrayOuter.push(outer); wallArray.push(wallArray[0]); wallArrayOuter.push(wallArrayOuter[0]); } else { const end = buildEnding(points[points.length-1], points[points.length-2], WALLTHICKNESS) wallArrayOuter.push(...end) wallArray.push(wallArrayOuter[wallArrayOuter.length-1]); const start = buildEnding(points[0], points[1], WALLTHICKNESS) wallArrayOuter.unshift(...start); wallArray.unshift(wallArrayOuter[0]); }
Полный код можно увидеть здесь https://jsfiddle.net/Dragon3DGraff/w5pufk04/10/
Great article! We are linking to this particularly great post on our site. Keep up the great writing. Britteny Bing Augie
I was more than happy to discover this site. I wanted to thank you for your time for this particularly wonderful read!! I definitely liked every little bit of it and i also have you book marked to look at new stuff in your blog. Bridget Rosco Melantha