Height limit

This commit is contained in:
Халимов Рустам
2026-01-11 22:53:38 +03:00
parent ade10e0aaf
commit 0f071c9587

View File

@@ -2,6 +2,37 @@ import * as THREE from 'three';
import { STLExporter, mergeBufferGeometries } from 'three-stdlib';
import { AppConfig, LayoutSplits, GeneratedPart, Partition } from '../types';
type Limits = { min: number; max: number };
type LimitMap = Record<string, Limits>;
// --- SOLVER ---
const solveWallLimits = (partitions: Partition[]): LimitMap => {
const limits: LimitMap = {};
partitions.forEach(p => { limits[p.id] = { min: 0, max: 1 }; });
for (let pass = 0; pass < 3; pass++) {
partitions.forEach(target => {
let newMin = 0;
let newMax = 1;
const center = target.offset;
partitions.forEach(obstacle => {
if (target.id === obstacle.id || target.axis === obstacle.axis) return;
const obsMin = limits[obstacle.id].min;
const obsMax = limits[obstacle.id].max;
if (target.offset > obsMin && target.offset < obsMax) {
if (obstacle.offset < center) newMin = Math.max(newMin, obstacle.offset);
else if (obstacle.offset > center) newMax = Math.min(newMax, obstacle.offset);
}
});
limits[target.id] = { min: newMin, max: newMax };
});
}
return limits;
};
export const calculateParts = (config: AppConfig, splits: LayoutSplits): GeneratedPart[] => {
const parts: GeneratedPart[] = [];
const safeX = Array.isArray(splits?.x) ? splits.x : [];
@@ -111,11 +142,10 @@ export const createBinGeometry = (
geometries.push(wallGeo);
// ВНУТРЕННИЕ ПЕРЕГОРОДКИ
// Мы просто верим сохраненным данным (p.min/p.max). Они должны быть корректны при создании.
partitions.forEach(p => {
const pMin = p.min ?? 0;
const pMax = p.max ?? 1;
const limitMap = solveWallLimits(partitions);
partitions.forEach(p => {
const { min: pMin, max: pMax } = limitMap[p.id];
if (pMax - pMin < 0.01) return;
const lengthRatio = pMax - pMin;
@@ -141,38 +171,77 @@ export const createBinGeometry = (
partGeo.translate(pX, thickness, pY);
geometries.push(partGeo);
// СКРУГЛЕНИЯ
// --- ДОБАВЛЕНИЕ ГАЛТЕЛЕЙ (FILLETS) ---
if (p.rounded && radius > 1) {
const filletR = Math.min(radius, 5);
const filletShape = createConcaveFilletShape(filletR);
const filletExtrude = { depth: p.height, bevelEnabled: false };
const addFillet = (x: number, y: number, rotY: number) => {
const geo = new THREE.ExtrudeGeometry(filletShape, filletExtrude);
// ФУНКЦИЯ ДЛЯ ПОИСКА ВЫСОТЫ СОСЕДА
const getNeighborHeight = (pos: number) => {
// Если это край ящика (0 или 1), то высота равна высоте ящика
if (pos < 0.001 || pos > 0.999) return height;
// Ищем внутреннюю стенку в этой точке
const neighbor = partitions.find(n => {
if (n.axis === p.axis) return false; // Должна быть перпендикулярна
// Соседка должна находиться в точке pos (по своей оси смещения)
if (Math.abs(n.offset - pos) > 0.001) return false;
// И соседка должна перекрывать нашу стенку (по своей длине)
const nLims = limitMap[n.id];
return p.offset >= nLims.min && p.offset <= nLims.max;
});
// Если нашли соседа - возвращаем его высоту, иначе 0 (не должно случаться при корректном Solver)
return neighbor ? neighbor.height : 0;
};
// Вычисляем высоту скругления для начала и конца стенки
// Высота не может быть больше самой стенки (p.height) и больше соседа
const startNeighborH = getNeighborHeight(pMin);
const endNeighborH = getNeighborHeight(pMax);
const hStart = Math.min(p.height, startNeighborH);
const hEnd = Math.min(p.height, endNeighborH);
// Функция добавления с конкретной высотой
const addFillet = (x: number, y: number, rotY: number, h: number) => {
if (h <= 1) return; // Если высота слишком мала, не рисуем
const geo = new THREE.ExtrudeGeometry(filletShape, { depth: h, bevelEnabled: false });
geo.rotateX(-Math.PI / 2);
geo.rotateY(rotY);
geo.translate(x, thickness, y);
geometries.push(geo);
};
const h = thickness / 2;
const t = thickness / 2;
if (p.axis === 'x') {
// VERTICAL WALL
const topY = (-innerDepth / 2) + (innerDepth * pMin);
addFillet(pX - h, topY, Math.PI);
addFillet(pX + h, topY, -Math.PI / 2);
const botY = (-innerDepth / 2) + (innerDepth * pMax);
addFillet(pX - h, botY, Math.PI / 2);
addFillet(pX + h, botY, 0);
} else {
const leftX = (-innerWidth / 2) + (innerWidth * pMin);
addFillet(leftX, pY - h, 0);
addFillet(leftX, pY + h, -Math.PI / 2);
// Top End (pMin) -> hStart
addFillet(pX - t, topY, Math.PI, hStart);
addFillet(pX + t, topY, -Math.PI / 2, hStart);
// Bottom End (pMax) -> hEnd
addFillet(pX - t, botY, Math.PI / 2, hEnd);
addFillet(pX + t, botY, 0, hEnd);
} else {
// HORIZONTAL WALL
const leftX = (-innerWidth / 2) + (innerWidth * pMin);
const rightX = (-innerWidth / 2) + (innerWidth * pMax);
addFillet(rightX, pY - h, Math.PI / 2);
addFillet(rightX, pY + h, Math.PI);
// Left End (pMin) -> hStart
addFillet(leftX, pY - t, 0, hStart);
addFillet(leftX, pY + t, -Math.PI / 2, hStart);
// Right End (pMax) -> hEnd
addFillet(rightX, pY - t, Math.PI / 2, hEnd);
addFillet(rightX, pY + t, Math.PI, hEnd);
}
}
});