v2-ui #84
|
@ -21,7 +21,7 @@ interface ModelProps extends React.ComponentProps<'group'> {
|
|||
matRef: React.Ref<THREE.Group<THREE.Object3DEventMap>>
|
||||
}
|
||||
|
||||
export function MaterialModel({ materialType, matRef, ...props }: ModelProps) {
|
||||
export function MaterialModel({ materialType, matRef, ...props }: Readonly<ModelProps>) {
|
||||
const path = modelPaths[materialType] || modelPaths['Default material'];
|
||||
const gltf = useGLTF(path);
|
||||
const cloned = useMemo(() => gltf?.scene.clone(), [gltf]);
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
import React, { useEffect, useRef, useState, useMemo } from "react";
|
||||
import { MaterialModel } from "../../../materials/instances/material/materialModel";
|
||||
import { Object3D, Box3, Vector3 } from "three";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
|
||||
const MaterialAnimator = ({
|
||||
storage,
|
||||
}: Readonly<{ storage: StorageUnitStatus }>) => {
|
||||
const meshRef = useRef<any>(null!);
|
||||
const [hasLoad, setHasLoad] = useState(false);
|
||||
const { scene } = useThree();
|
||||
const padding = 0.1;
|
||||
|
||||
useEffect(() => {
|
||||
setHasLoad(storage.currentLoad > 0);
|
||||
}, [storage.currentLoad]);
|
||||
|
||||
const storageModel = useMemo(() => {
|
||||
return scene.getObjectByProperty("uuid", storage.modelUuid) as Object3D;
|
||||
}, [scene, storage.modelUuid]);
|
||||
|
||||
const materialPositions = useMemo(() => {
|
||||
if (!storageModel || storage.currentMaterials.length === 0) return [];
|
||||
|
||||
const box = new Box3().setFromObject(storageModel);
|
||||
const size = new Vector3();
|
||||
box.getSize(size);
|
||||
|
||||
const matCount = storage.currentMaterials.length;
|
||||
|
||||
// Assumed size each material needs in world units
|
||||
const materialWidth = 0.45;
|
||||
const materialDepth = 0.45;
|
||||
const materialHeight = 0.3;
|
||||
|
||||
const cols = Math.floor(size.x / materialWidth);
|
||||
const rows = Math.floor(size.z / materialDepth);
|
||||
const itemsPerLayer = cols * rows;
|
||||
|
||||
const origin = new Vector3(
|
||||
box.min.x + materialWidth / 2,
|
||||
box.max.y + padding, // slightly above the surface
|
||||
box.min.z + materialDepth / 2
|
||||
);
|
||||
|
||||
return Array.from({ length: matCount }, (_, i) => {
|
||||
const layer = Math.floor(i / itemsPerLayer);
|
||||
const layerIndex = i % itemsPerLayer;
|
||||
const row = Math.floor(layerIndex / cols);
|
||||
const col = layerIndex % cols;
|
||||
|
||||
return new Vector3(
|
||||
origin.x + col * materialWidth,
|
||||
origin.y + layer * (materialHeight + padding),
|
||||
origin.z + row * materialDepth
|
||||
);
|
||||
});
|
||||
}, [storageModel, storage.currentMaterials]);
|
||||
|
||||
return (
|
||||
<group position={[0, -padding, 0]}>
|
||||
{hasLoad &&
|
||||
storage.currentMaterials.map((mat, index) => (
|
||||
<MaterialModel
|
||||
key={`${index}-${mat.materialId}`}
|
||||
matRef={meshRef}
|
||||
materialType={mat.materialType ?? "Default material"}
|
||||
position={materialPositions[index]}
|
||||
/>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default MaterialAnimator;
|
|
@ -1,14 +1,14 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import MaterialAnimator from '../animator/MaterialAnimator'
|
||||
|
||||
function StorageUnitInstance({ storageUnit }: { storageUnit: StorageUnitStatus }) {
|
||||
function StorageUnitInstance({ storageUnit }: Readonly<{ storageUnit: StorageUnitStatus }>) {
|
||||
|
||||
useEffect(()=>{
|
||||
// console.log('storageUnit: ', storageUnit);
|
||||
},[storageUnit])
|
||||
|
||||
return (
|
||||
<>
|
||||
</>
|
||||
<MaterialAnimator storage={storageUnit}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import React from 'react'
|
||||
import StorageUnitInstance from './storageUnitInstance/storageUnitInstance'
|
||||
import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'
|
||||
import StorageContentUi from '../../ui3d/StorageContentUi';
|
||||
|
||||
function StorageUnitInstances() {
|
||||
const { storageUnits } = useStorageUnitStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
{storageUnits.map((storageUnit: StorageUnitStatus) => (
|
||||
<React.Fragment key={storageUnit.modelUuid}>
|
||||
<StorageUnitInstance storageUnit={storageUnit} />
|
||||
<StorageContentUi storageUnit={storageUnit}/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import { Html } from "@react-three/drei";
|
||||
import React from "react";
|
||||
import AssetDetailsCard from "../../../components/ui/simulation/AssetDetailsCard";
|
||||
import { Vector3 } from "three";
|
||||
|
||||
type StorageContentUiProps = {
|
||||
storageUnit: StorageUnitStatus;
|
||||
};
|
||||
|
||||
const StorageContentUi: React.FC<StorageContentUiProps> = ({ storageUnit }) => {
|
||||
return (
|
||||
<Html
|
||||
// data
|
||||
position={
|
||||
new Vector3(
|
||||
storageUnit.position[0],
|
||||
storageUnit.point.position[1],
|
||||
storageUnit.position[2]
|
||||
)
|
||||
}
|
||||
// class none
|
||||
// other
|
||||
zIndexRange={[1, 0]}
|
||||
prepend
|
||||
sprite
|
||||
center
|
||||
distanceFactor={20}
|
||||
>
|
||||
<AssetDetailsCard
|
||||
name={storageUnit.modelName}
|
||||
status={storageUnit.state}
|
||||
count={storageUnit.currentLoad}
|
||||
/>
|
||||
</Html>
|
||||
);
|
||||
};
|
||||
|
||||
export default StorageContentUi;
|
Loading…
Reference in New Issue