Radius
This commit is contained in:
@@ -46,6 +46,9 @@ export const calculateParts = (config: AppConfig, splits: LayoutSplits): Generat
|
||||
return parts;
|
||||
};
|
||||
|
||||
// --- ГЕОМЕТРИЯ ---
|
||||
|
||||
// 1. Форма скругленного прямоугольника (для дна и внешних стенок)
|
||||
const createRoundedRectShape = (width: number, height: number, radius: number): THREE.Shape => {
|
||||
const shape = new THREE.Shape();
|
||||
const x = -width / 2;
|
||||
@@ -72,16 +75,35 @@ const createRoundedRectShape = (width: number, height: number, radius: number):
|
||||
return shape;
|
||||
};
|
||||
|
||||
// 2. Форма галтели (вогнутого треугольника) для углов
|
||||
const createFilletShape = (radius: number): THREE.Shape => {
|
||||
const shape = new THREE.Shape();
|
||||
// Начинаем из угла (0,0)
|
||||
shape.moveTo(0, 0);
|
||||
// Линия вдоль одной стенки
|
||||
shape.lineTo(radius, 0);
|
||||
// Вогнутая дуга к другой стенке
|
||||
// Центр окружности (radius, radius), радиус radius.
|
||||
// Рисуем дугу от 270 (-PI/2) до 180 (PI) градусов по часовой стрелке
|
||||
shape.absarc(radius, radius, radius, 1.5 * Math.PI, Math.PI, true);
|
||||
// Замыкаем в угол
|
||||
shape.lineTo(0, 0);
|
||||
|
||||
return shape;
|
||||
};
|
||||
|
||||
export const createBinGeometry = (
|
||||
width: number, depth: number, height: number, thickness: number, radius: number = 0, partitions: Partition[] = []
|
||||
): THREE.BufferGeometry => {
|
||||
const geometries: THREE.BufferGeometry[] = [];
|
||||
|
||||
// ДНО
|
||||
const floorShape = createRoundedRectShape(width, depth, radius);
|
||||
const floorGeo = new THREE.ExtrudeGeometry(floorShape, { depth: thickness, bevelEnabled: false, curveSegments: 12 });
|
||||
floorGeo.rotateX(-Math.PI / 2);
|
||||
geometries.push(floorGeo);
|
||||
|
||||
// ВНЕШНИЕ СТЕНКИ
|
||||
const outerShape = createRoundedRectShape(width, depth, radius);
|
||||
const innerRadius = Math.max(0, radius - thickness);
|
||||
const innerWidth = width - (2 * thickness);
|
||||
@@ -98,6 +120,7 @@ export const createBinGeometry = (
|
||||
wallGeo.translate(0, thickness, 0);
|
||||
geometries.push(wallGeo);
|
||||
|
||||
// ВНУТРЕННИЕ ПЕРЕГОРОДКИ И СКРУГЛЕНИЯ
|
||||
partitions.forEach(p => {
|
||||
const pMin = p.min ?? 0;
|
||||
const pMax = p.max ?? 1;
|
||||
@@ -106,6 +129,7 @@ export const createBinGeometry = (
|
||||
|
||||
let pWidth = 0, pDepth = 0, pX = 0, pY = 0;
|
||||
|
||||
// Размеры самой стенки
|
||||
if (p.axis === 'x') {
|
||||
pWidth = thickness;
|
||||
pDepth = lengthRatio * innerDepth;
|
||||
@@ -118,12 +142,73 @@ export const createBinGeometry = (
|
||||
pY = (-innerDepth / 2) + (innerDepth * p.offset);
|
||||
}
|
||||
|
||||
const pRadius = p.rounded ? Math.min(radius, thickness / 1.5) : 0;
|
||||
const partShape = createRoundedRectShape(pWidth, pDepth, pRadius);
|
||||
const partGeo = new THREE.ExtrudeGeometry(partShape, { depth: p.height, bevelEnabled: false, curveSegments: 8 });
|
||||
// Создаем стенку
|
||||
const partShape = createRoundedRectShape(pWidth, pDepth, 0.1); // Чуть-чуть скругляем саму стенку, чтобы не была острой
|
||||
const partGeo = new THREE.ExtrudeGeometry(partShape, { depth: p.height, bevelEnabled: false, curveSegments: 2 });
|
||||
partGeo.rotateX(-Math.PI / 2);
|
||||
partGeo.translate(pX, thickness, pY);
|
||||
geometries.push(partGeo);
|
||||
|
||||
// --- ДОБАВЛЕНИЕ ГАЛТЕЛЕЙ (FILLETS) ---
|
||||
if (p.rounded && radius > 0.5) {
|
||||
// Радиус скругления такой же, как у углов ящика, но не больше разумного предела
|
||||
const filletR = Math.min(radius, 6);
|
||||
const filletShape = createFilletShape(filletR);
|
||||
const filletExtrudeSettings = { depth: p.height, bevelEnabled: false, curveSegments: 8 };
|
||||
|
||||
// Функция для создания и позиционирования одной галтели
|
||||
const addFillet = (x: number, y: number, rotation: number) => {
|
||||
const geo = new THREE.ExtrudeGeometry(filletShape, filletExtrudeSettings);
|
||||
geo.rotateX(-Math.PI / 2); // Положить на пол
|
||||
geo.rotateY(rotation); // Повернуть в нужный угол
|
||||
|
||||
// Корректировка позиции после вращения вокруг (0,0)
|
||||
// Нам нужно сместить так, чтобы угол (0,0) галтели совпал с углом стыка
|
||||
geo.translate(x, thickness, y);
|
||||
geometries.push(geo);
|
||||
};
|
||||
|
||||
const halfThick = thickness / 2;
|
||||
|
||||
if (p.axis === 'x') {
|
||||
// Вертикальная стенка. Концы: Top (pMin) и Bottom (pMax) (в 2D координатах Y)
|
||||
// Y координата начала: -innerDepth/2 + innerDepth * pMin
|
||||
// Y координата конца: -innerDepth/2 + innerDepth * pMax
|
||||
// X координата центра: pX
|
||||
|
||||
const startY = (-innerDepth / 2) + (innerDepth * pMin);
|
||||
const endY = (-innerDepth / 2) + (innerDepth * pMax);
|
||||
|
||||
// 4 Угла:
|
||||
// 1. Start Left: X = pX - halfThick, Y = startY. Rotation: 0 (смотрит вправо-вверх? нет)
|
||||
// Галтель рисуется в +X, +Y квадранте от 0,0.
|
||||
// Нам нужно заполнить угол между стенкой (идет вниз) и перпендикуляром.
|
||||
|
||||
// Start (Top in 2D view, actually Min Y in 3D logic here usually means "Back")
|
||||
// Let's assume standard plan view:
|
||||
// Min Y is "Top" edge visually in SVG usually 0. In 3D Z is Y.
|
||||
|
||||
// Min End (Start of wall):
|
||||
addFillet(pX - halfThick, startY, 0); // Left side, pointing towards +Z (down in visual)
|
||||
addFillet(pX + halfThick, startY, -Math.PI/2); // Right side
|
||||
|
||||
// Max End (End of wall):
|
||||
addFillet(pX - halfThick, endY, Math.PI/2); // Left side
|
||||
addFillet(pX + halfThick, endY, Math.PI); // Right side
|
||||
} else {
|
||||
// Горизонтальная стенка
|
||||
const startX = (-innerWidth / 2) + (innerWidth * pMin);
|
||||
const endX = (-innerWidth / 2) + (innerWidth * pMax);
|
||||
|
||||
// Min End (Left side):
|
||||
addFillet(startX, pY + halfThick, -Math.PI/2);
|
||||
addFillet(startX, pY - halfThick, 0);
|
||||
|
||||
// Max End (Right side):
|
||||
addFillet(endX, pY + halfThick, Math.PI);
|
||||
addFillet(endX, pY - halfThick, Math.PI/2);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const merged = mergeBufferGeometries(geometries);
|
||||
|
||||
Reference in New Issue
Block a user