Height limit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user