test #2

Merged
rust merged 4 commits from test into main 2025-12-27 21:50:54 +03:00
Showing only changes of commit 16b92ca364 - Show all commits
+34 -36
View File
@@ -11,6 +11,7 @@ export const calculateParts = (
): GeneratedPart[] => { ): GeneratedPart[] => {
const parts: GeneratedPart[] = []; const parts: GeneratedPart[] = [];
// Сортируем линии разреза
const xPoints = [0, ...[...splits.x].sort((a, b) => a - b), 1]; const xPoints = [0, ...[...splits.x].sort((a, b) => a - b), 1];
const yPoints = [0, ...[...splits.y].sort((a, b) => a - b), 1]; const yPoints = [0, ...[...splits.y].sort((a, b) => a - b), 1];
@@ -24,12 +25,13 @@ export const calculateParts = (
const segmentW = (xPoints[i + 1] - xPoints[i]) * config.drawer.width; const segmentW = (xPoints[i + 1] - xPoints[i]) * config.drawer.width;
const segmentD = (yPoints[j + 1] - yPoints[j]) * config.drawer.depth; const segmentD = (yPoints[j + 1] - yPoints[j]) * config.drawer.depth;
// Apply Printer Tolerance // Применяем зазор (Tolerance)
const realWidth = segmentW - config.printerTolerance; const realWidth = segmentW - config.printerTolerance;
const realDepth = segmentD - config.printerTolerance; const realDepth = segmentD - config.printerTolerance;
const realX = segmentX + (config.printerTolerance / 2); const realX = segmentX + (config.printerTolerance / 2);
const realY = segmentY + (config.printerTolerance / 2); const realY = segmentY + (config.printerTolerance / 2);
// Игнорируем слишком мелкие детали
if (realWidth < 5 || realDepth < 5) { if (realWidth < 5 || realDepth < 5) {
continue; continue;
} }
@@ -52,25 +54,25 @@ export const calculateParts = (
}; };
/** /**
* Helper to create a rounded rectangle Shape * Создает 2D форму прямоугольника со скругленными краями
*/ */
const createRoundedRectShape = (width: number, height: number, radius: number): THREE.Shape => { const createRoundedRectShape = (width: number, height: number, radius: number): THREE.Shape => {
const shape = new THREE.Shape(); const shape = new THREE.Shape();
const x = -width / 2; const x = -width / 2;
const y = -height / 2; const y = -height / 2;
// Clamp radius to not exceed half of width or height // Ограничиваем радиус, чтобы он не сломал геометрию (не больше половины стороны)
const r = Math.min(radius, width / 2, height / 2); const r = Math.min(radius, width / 2, height / 2);
if (r <= 0) { if (r <= 0.1) {
// Regular rectangle // Обычный прямоугольник (если радиус 0)
shape.moveTo(x, y); shape.moveTo(x, y);
shape.lineTo(x + width, y); shape.lineTo(x + width, y);
shape.lineTo(x + width, y + height); shape.lineTo(x + width, y + height);
shape.lineTo(x, y + height); shape.lineTo(x, y + height);
shape.lineTo(x, y); shape.lineTo(x, y);
} else { } else {
// Rounded rectangle // Прямоугольник со скруглениями
shape.moveTo(x, y + r); shape.moveTo(x, y + r);
shape.lineTo(x, y + height - r); shape.lineTo(x, y + height - r);
shape.quadraticCurveTo(x, y + height, x + r, y + height); shape.quadraticCurveTo(x, y + height, x + r, y + height);
@@ -86,42 +88,34 @@ const createRoundedRectShape = (width: number, height: number, radius: number):
} }
/** /**
* Generates a Three.js Geometry for a hollow bin with fillets (rounded corners). * Генерирует 3D геометрию ящика
*/ */
export const createBinGeometry = ( export const createBinGeometry = (
width: number, width: number,
depth: number, depth: number,
height: number, height: number,
thickness: number, thickness: number,
radius: number = 0 // Default radius radius: number = 0
): THREE.BufferGeometry => { ): THREE.BufferGeometry => {
// 1. Создаем форму ДНА (Floor) // 1. ГЕОМЕТРИЯ ДНА (Сплошная)
// Это сплошной прямоугольник со скруглениями
const floorShape = createRoundedRectShape(width, depth, radius); const floorShape = createRoundedRectShape(width, depth, radius);
const floorGeo = new THREE.ExtrudeGeometry(floorShape, { const floorGeo = new THREE.ExtrudeGeometry(floorShape, {
depth: thickness, // Толщина дна depth: thickness, // Выдавливаем на толщину дна
bevelEnabled: false, bevelEnabled: false,
curveSegments: 12 // Гладкость скругления curveSegments: 16 // Количество сегментов на скруглениях
}); });
// ExtrudeGeometry создает объект "лежа" на XY, нам нужно повернуть его, чтобы он стал дном (XZ) // Extrude выдавливает по оси Z. Нам нужно повернуть, чтобы "глубина" стала "высотой" (Y).
floorGeo.rotateX(Math.PI / 2); // Поворот на -90 градусов вокруг X кладет Z на Y.
// Сдвигаем на высоту thickness, так как extrude идет в +Z (после поворота это +Y, но перевернуто... проще подобрать) floorGeo.rotateX(-Math.PI / 2);
// По умолчанию extrude создает от 0 до Z. После поворота X(90deg): // Теперь дно занимает пространство от Y=0 до Y=thickness.
// Z становится -Y. То есть дно уходит вниз от 0.
// Нам нужно, чтобы дно было от 0 до thickness по Y.
// Возвращаем поворот в -90 (стандарт для топологии)
floorGeo.rotateX(-Math.PI);
floorGeo.translate(0, thickness, 0); // Поднимаем, чтобы верх дна был на уровне thickness
// 2. ГЕОМЕТРИЯ СТЕНОК (С дыркой)
// 2. Создаем форму СТЕНОК (Walls)
// Это внешняя форма МИНУС внутренняя форма (дырка)
const outerShape = createRoundedRectShape(width, depth, radius); const outerShape = createRoundedRectShape(width, depth, radius);
// Внутренний радиус должен быть меньше внешнего на толщину стенки, но не меньше 0 // Вырезаем внутреннюю часть
const innerRadius = Math.max(0, radius - thickness); const innerRadius = Math.max(0, radius - thickness);
const innerWidth = width - (2 * thickness); const innerWidth = width - (2 * thickness);
const innerDepth = depth - (2 * thickness); const innerDepth = depth - (2 * thickness);
@@ -131,28 +125,32 @@ export const createBinGeometry = (
outerShape.holes.push(innerHole); outerShape.holes.push(innerHole);
} }
// Высота стенок = общая высота минус толщина дна
const wallHeight = height - thickness; const wallHeight = height - thickness;
const wallGeo = new THREE.ExtrudeGeometry(outerShape, { const wallGeo = new THREE.ExtrudeGeometry(outerShape, {
depth: wallHeight, depth: wallHeight,
bevelEnabled: false, bevelEnabled: false,
curveSegments: 12 curveSegments: 16
}); });
// Поворачиваем стенки так же, как дно // Поворачиваем стенки так же, как дно
wallGeo.rotateX(Math.PI / 2); wallGeo.rotateX(-Math.PI / 2);
wallGeo.rotateX(-Math.PI);
// Стенки начинаются ОТ дна (y = thickness)
wallGeo.translate(0, thickness + wallHeight, 0);
// Объединяем геометрии // Сейчас стенки тоже начинаются с Y=0.
// Нам нужно поднять их НАД дном.
wallGeo.translate(0, thickness, 0);
// Теперь стенки занимают пространство от Y=thickness до Y=height.
// 3. ОБЪЕДИНЕНИЕ
// Сливаем две геометрии в одну. Слайсеры поймут это как единый объект,
// так как поверхности идеально соприкасаются.
const merged = mergeBufferGeometries([floorGeo, wallGeo]); const merged = mergeBufferGeometries([floorGeo, wallGeo]);
// Центрируем геометрию, чтобы Pivot был в центре дна (как раньше в BinMesh) // Центрирование не нужно, так как createRoundedRectShape строит форму вокруг (0,0) по X и Z.
// Ранее мы использовали BoxGeometry который центрирован. // А по Y мы выстроили от 0 вверх.
// Extrude создает форму вокруг (0,0), так что по X/Z она уже центрирована. // Pivot point (опорная точка) осталась внизу в центре (0,0,0), что идеально для позиционирования.
// По Y она сейчас от 0 до height.
// Вернем как было: Pivot внизу.
return merged || new THREE.BoxGeometry(1, 1, 1); return merged || new THREE.BoxGeometry(1, 1, 1);
}; };