Главное о кейсе
Проект реализован для крупной инжиниринговой компании, которая применяет 3D модели в пространстве при проектировании зданий и сооружений. Компания - клиент рекламной группы Kokoc Group, к которой относится подразделение аутстафинга Kokoc Staff.
Бизнес-задача и ее решение
ЗАДАЧА
Создать интерфейс моделирования инженерных и оконных систем при проектировании зданий и сооружений. Срок реализации проекта - более 1 года.
ТРУДНОСТИ
Основная трудность — для участие в проекте необходимо предоставить решение задачи с кривой в пространстве.
Для реализации данного проекта необходимы экспертные знания в высшей математике - для построения правильных 3D моделей. Так как клиент не обладал специалистами в данной области, он обратился в компании, которые специализируются в предоставлении разработчиков в аренду. Но после нескольких месяцев поиска ни одна из компаний не смогла предоставить специалиста нужного уровня знаний.
Решение нашлось у специалистов Kostaff.
Для тестирования правильности работы программного кода, реализовали тестовый пример (доступно в разделе Ссылки).
Разработчик вышел на проект, смоделировал и запрограммировал необходимые функции.
Крафт (мастерство), реализация, технические детали
РЕАЛИЗАЦИЯ
Требование к задаче
Входные параметры:
- массив вершин полигона [{x, y}]
- координаты линии по двум точкам (которые лежат снаружи области полигона)
Выходной параметр: массив вершин полигонов. При делении образуются два полигона, нужно получить массивы их вершин.
Решение
Решение задачи на бумаге
На вход принимается массив вершин многоугольника и две точки независимой прямой. Для решения задачи каждый элемент массива проверяем на пересечение с независимой прямой.
Уравнение прямой по двум точкам: Скриншот 1.
Приведем данное уравнение к уравнение прямой:
Скриншот 2.
Таким образом получаем уравнение прямой вида y = ax+k.
Пересечение двух прямых образуют систему линейных алгебраических уравнений (далее СЛАУ) с двумя неизвестными: х и y (Скриншоты 3, 4, 5).
Таким образом, прямые не пересекаются.
РЕЗУЛЬТАТ
Для каждой итерации (грани полигона) производится следующий алгоритм: Скриншот 6.
type Point = { x: number, y: number };
type LinePoint = [Point, Point];
function findIntersectionPoint(points1: LinePoint, points2: LinePoint): Point | null {
function calcOdds([point1, point2]: LinePoint) {
return ({
a: -point2.y + point1.y,
b: -point2.x + point1.x,
c: point1.x * point2.y - point2.x * point1.y,
})
}
const { a: a1, b: b1, c: c1 } = calcOdds(points1);
const { a: a2, b: b2, c: c2 } = calcOdds(points2);
if (b1 === 0 && b2 === 0) return null;
const x2 = a1 * b2 - a2 * b1;
if (x2 === 0) return null;
const x1 = c2 * b1 - c1 * b2;
const x = x1 / x2;
const y = b1 === 0 ? a2 * x / b2 + c2 / b2 : a1 * x / b1 + c1 / b1
return { x, y }
}
function checkPointBetween(linePoints: LinePoint, point: Point): boolean {
if (point.x === linePoints[1].x && point.y === linePoints[1].y) return false;
const xs = [linePoints[0].x, linePoints[1].x].sort((a, b) => a - b)
const ys = [linePoints[0].y, linePoints[1].y].sort((a, b) => a - b)
return point.x >= xs[0] && point.x = ys[0] && point.y {
const lastItem = array[i + 1] ?? array[0];
return lastItem.x != it.x || lastItem.y != it.y
})
}
function findFigures(figurePoints: Point[], line: LinePoint): Point[][] | null {
const points: { value: Point, i: number }[] = [];
for (let i = 0; i <
figurePoints.length; i++) {
let endPoint = figurePoints[i + 1]
if (i ===
figurePoints.length - 1) {
endPoint = figurePoints[0]
}
const intersectionPoint = getIntersectionPoint([figurePoints[i], endPoint], line);
if (intersectionPoint != null) {
points.push({ value: intersectionPoint, i: i })
}
}
if (points.length != 2) return null;
const array1 = [...figurePoints];
const deletedElements =
array1.splice(points[0].i + 1, points[1].i - points[0].i, points[0].value, points[1].value)
const array2 = [points[0].value,
...deletedElements, points[1].value];
return [filteredArray(array1), filteredArray(array2)];
}
Скриншоты