Создание стен. Часть 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