Add sizes
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { Suspense, useEffect, useRef, useState, useMemo } from 'react';
|
||||
import { Canvas } from '@react-three/fiber';
|
||||
import { OrbitControls, Center, Environment } from '@react-three/drei';
|
||||
import { OrbitControls, Center, Environment, Text } from '@react-three/drei';
|
||||
import * as THREE from 'three';
|
||||
import JSZip from 'jszip';
|
||||
import { AppConfig, GeneratedPart, LayoutSplits, PerforationConfig } from '../types';
|
||||
@@ -52,18 +52,138 @@ const BinMesh: React.FC<BinMeshProps> = ({ part, thickness, cornerRadius, perfor
|
||||
return new THREE.EdgesGeometry(geometry, 20);
|
||||
}, [geometry]);
|
||||
|
||||
// 3. Вычисляем размеры и позиции для каждой под-ячейки
|
||||
// 3. Вычисляем размеры и позиции для реальных отсеков (с учетом мерджинга)
|
||||
const dimLabels = useMemo(() => {
|
||||
const xOffsets = new Set<number>([0, 1]);
|
||||
const zOffsets = new Set<number>([0, 1]);
|
||||
|
||||
part.internalPartitions.forEach(p => {
|
||||
if (p.axis === 'x') xOffsets.add(p.offset);
|
||||
if (p.axis === 'y') zOffsets.add(p.offset);
|
||||
});
|
||||
|
||||
const xSplits = Array.from(xOffsets).sort((a, b) => a - b);
|
||||
const zSplits = Array.from(zOffsets).sort((a, b) => a - b);
|
||||
|
||||
const numCols = xSplits.length - 1;
|
||||
const numRows = zSplits.length - 1;
|
||||
if (numCols === 0 || numRows === 0) return [];
|
||||
|
||||
// Union-Find для объединения ячеек, не разделенных стеной
|
||||
const parent = new Int32Array(numCols * numRows).map((_, i) => i);
|
||||
const find = (i: number): number => {
|
||||
if (parent[i] === i) return i;
|
||||
parent[i] = find(parent[i]);
|
||||
return parent[i];
|
||||
}
|
||||
const union = (i: number, j: number) => {
|
||||
const rootI = find(i);
|
||||
const rootJ = find(j);
|
||||
if (rootI !== rootJ) parent[rootJ] = rootI;
|
||||
}
|
||||
const getIdx = (c: number, r: number) => r * numCols + c;
|
||||
|
||||
// Вертикальные границы (X)
|
||||
for (let i = 0; i < numCols - 1; i++) {
|
||||
const boundaryX = xSplits[i + 1];
|
||||
for (let j = 0; j < numRows; j++) {
|
||||
const zMid = (zSplits[j] + zSplits[j + 1]) / 2;
|
||||
// Проверяем наличие перегородки axis='x'
|
||||
const isBlocked = part.internalPartitions.some(p =>
|
||||
p.axis === 'x' &&
|
||||
Math.abs(p.offset - boundaryX) < 0.001 &&
|
||||
(p.min ?? 0) <= zMid && (p.max ?? 1) >= zMid
|
||||
);
|
||||
if (!isBlocked) union(getIdx(i, j), getIdx(i + 1, j));
|
||||
}
|
||||
}
|
||||
|
||||
// Горизонтальные границы (Z/Y)
|
||||
for (let j = 0; j < numRows - 1; j++) {
|
||||
const boundaryZ = zSplits[j + 1];
|
||||
for (let i = 0; i < numCols; i++) {
|
||||
const xMid = (xSplits[i] + xSplits[i + 1]) / 2;
|
||||
// Проверяем наличие перегородки axis='y'
|
||||
const isBlocked = part.internalPartitions.some(p =>
|
||||
p.axis === 'y' &&
|
||||
Math.abs(p.offset - boundaryZ) < 0.001 &&
|
||||
(p.min ?? 0) <= xMid && (p.max ?? 1) >= xMid
|
||||
);
|
||||
if (!isBlocked) union(getIdx(i, j), getIdx(i, j + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Агрегируем регионы
|
||||
const regions: Record<number, { minC: number, maxC: number, minR: number, maxR: number }> = {};
|
||||
for (let j = 0; j < numRows; j++) {
|
||||
for (let i = 0; i < numCols; i++) {
|
||||
const root = find(getIdx(i, j));
|
||||
if (!regions[root]) regions[root] = { minC: i, maxC: i, minR: j, maxR: j };
|
||||
else {
|
||||
const r = regions[root];
|
||||
r.minC = Math.min(r.minC, i);
|
||||
r.maxC = Math.max(r.maxC, i);
|
||||
r.minR = Math.min(r.minR, j);
|
||||
r.maxR = Math.max(r.maxR, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(regions).map((r, idx) => {
|
||||
const fXStart = xSplits[r.minC];
|
||||
const fXEnd = xSplits[r.maxC + 1];
|
||||
const fZStart = zSplits[r.minR];
|
||||
const fZEnd = zSplits[r.maxR + 1];
|
||||
|
||||
const fracW = fXEnd - fXStart;
|
||||
const fracD = fZEnd - fZStart;
|
||||
|
||||
const dimX = Math.max(0, fracW * (part.width - thickness) - thickness);
|
||||
const dimZ = Math.max(0, fracD * (part.depth - thickness) - thickness);
|
||||
|
||||
const cx = -part.width / 2 + (fXStart + fXEnd) / 2 * part.width;
|
||||
const cz = -part.depth / 2 + (fZStart + fZEnd) / 2 * part.depth;
|
||||
|
||||
return {
|
||||
key: `region-${idx}`,
|
||||
pos: [cx, thickness + 0.2, cz] as [number, number, number],
|
||||
text: `${dimX.toFixed(0)} x ${dimZ.toFixed(0)}`
|
||||
};
|
||||
});
|
||||
}, [part, thickness]);
|
||||
|
||||
return (
|
||||
<group position={[part.x + part.width / 2, 0, part.y + part.depth / 2]}>
|
||||
<group
|
||||
position={[part.x + part.width / 2, 0, part.y + part.depth / 2]}
|
||||
onClick={(e) => { e.stopPropagation(); onClick(); }}
|
||||
>
|
||||
{/* Сама модель */}
|
||||
<mesh geometry={geometry} onClick={(e) => { e.stopPropagation(); onClick(); }}>
|
||||
<mesh geometry={geometry}>
|
||||
<meshStandardMaterial
|
||||
color={isSelected ? '#f59e0b' : part.color}
|
||||
roughness={0.5}
|
||||
metalness={0.1}
|
||||
side={THREE.DoubleSide} // Рисуем обе стороны стенок
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</mesh>
|
||||
|
||||
{/* Текстовые метки размеров внутри каждой ячейки */}
|
||||
{dimLabels.map(label => (
|
||||
<Text
|
||||
key={label.key}
|
||||
position={label.pos}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
fontSize={Math.min(part.width, part.depth) * 0.035}
|
||||
color="#1e293b"
|
||||
anchorX="center"
|
||||
anchorY="middle"
|
||||
characters="0123456789x "
|
||||
>
|
||||
{label.text}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
{/* Белая подсветка при выборе */}
|
||||
{isSelected && (
|
||||
<lineSegments geometry={edgesGeometry}>
|
||||
|
||||
Reference in New Issue
Block a user