pillar Jig half way completed

This commit is contained in:
2025-08-06 18:19:54 +05:30
parent 76f295d9b9
commit a08cec33ab
27 changed files with 1506 additions and 1031 deletions

View File

@@ -0,0 +1,15 @@
import React from 'react'
import CraneInstances from './instances/craneInstances'
function Crane() {
return (
<>
<CraneInstances />
</>
)
}
export default Crane

View File

@@ -0,0 +1,133 @@
import * as THREE from 'three';
import { useEffect, useMemo } from 'react';
import { useThree } from '@react-three/fiber';
function PillarJibAnimator({ crane }: { crane: CraneStatus }) {
const { scene } = useThree();
useEffect(() => {
const model = scene.getObjectByProperty('uuid', crane.modelUuid);
if (model) {
const base = model.getObjectByName('base');
const trolley = model.getObjectByName('trolley');
const hook = model.getObjectByName('hook');
if (base && trolley && hook) {
let trolleyDir = 1;
let hookDir = 1;
const trolleySpeed = 0.01;
const hookSpeed = 0.01;
const rotationSpeed = 0.005;
const trolleyMinOffset = -1;
const trolleyMaxOffset = 1.75;
const hookMinOffset = 0.25;
const hookMaxOffset = -1.5;
const originalTrolleyX = trolley.position.x;
const originalHookY = hook.position.y;
const animate = () => {
if (base) {
base.rotation.y += rotationSpeed;
}
if (trolley) {
trolley.position.x += trolleyDir * trolleySpeed;
if (trolley.position.x >= originalTrolleyX + trolleyMaxOffset ||
trolley.position.x <= originalTrolleyX + trolleyMinOffset) {
trolleyDir *= -1;
}
}
if (hook) {
hook.position.y += hookDir * hookSpeed;
if (hook.position.y >= originalHookY + hookMinOffset ||
hook.position.y <= originalHookY + hookMaxOffset) {
hookDir *= -1;
}
}
requestAnimationFrame(animate);
};
animate();
}
}
}, [crane, scene]);
return (
<PillarJibHelper crane={crane} />
);
}
export default PillarJibAnimator;
function PillarJibHelper({ crane }: { crane: CraneStatus }) {
const { scene } = useThree();
const { geometry, position } = useMemo(() => {
const model = scene.getObjectByProperty('uuid', crane.modelUuid);
if (!model) return { geometry: null, position: null };
const base = model.getObjectByName('base');
const trolley = model.getObjectByName('trolley');
const hook = model.getObjectByName('hook');
if (!base || !trolley || !hook) return { geometry: null, position: null };
const baseWorld = new THREE.Vector3();
base.getWorldPosition(baseWorld);
const trolleyWorld = new THREE.Vector3();
trolley.getWorldPosition(trolleyWorld);
const hookWorld = new THREE.Vector3();
hook.getWorldPosition(hookWorld);
const distFromBase = new THREE.Vector2(trolleyWorld.x - baseWorld.x, trolleyWorld.z - baseWorld.z).length();
const outerRadius = distFromBase + 1.75;
const innerRadius = Math.max(distFromBase - 1, 0.05);
const height = (0.25 - (-1.5));
const cylinderYPosition = hookWorld.y + (height / 2) + (-1.5 + 0.25) / 2;
const shape = new THREE.Shape();
shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);
const hole = new THREE.Path();
hole.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);
shape.holes.push(hole);
const extrudeSettings = {
depth: height,
bevelEnabled: false,
steps: 1
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const position: [number, number, number] = [baseWorld.x, cylinderYPosition, baseWorld.z];
return { geometry, position };
}, [scene, crane.modelUuid]);
if (!geometry || !position) return null;
return (
<mesh
geometry={geometry}
position={position}
rotation={[Math.PI / 2, 0, 0]}
>
<meshStandardMaterial
color={0x888888}
metalness={0.5}
roughness={0.4}
side={THREE.DoubleSide}
transparent={true}
opacity={0.3}
/>
</mesh>
);
}

View File

@@ -0,0 +1,24 @@
import React from 'react'
import PillarJibInstance from './instance/pillarJibInstance';
import { useSceneContext } from '../../../scene/sceneContext';
function CraneInstances() {
const { craneStore } = useSceneContext();
const { cranes } = craneStore();
return (
<>
{cranes.map((crane: CraneStatus) => (
<React.Fragment key={crane.modelUuid}>
{crane.subType === "pillarJib" &&
<PillarJibInstance crane={crane} />
}
</React.Fragment>
))}
</>
)
}
export default CraneInstances

View File

@@ -0,0 +1,14 @@
import PillarJibAnimator from '../animator/pillarJibAnimator'
function PillarJibInstance({ crane }: { crane: CraneStatus }) {
return (
<>
<PillarJibAnimator crane={crane} />
</>
)
}
export default PillarJibInstance

View File

@@ -40,7 +40,7 @@ function PointsCalculator(
}
return {
points: [worldTopMiddle]
points: [new THREE.Vector3(worldTopMiddle.x, worldTopMiddle.y + 0.1, worldTopMiddle.z)]
};
}

View File

@@ -18,6 +18,7 @@ function PointInstances() {
machine: "purple",
storageUnit: "red",
human: "white",
crane: "yellow",
};
return (

View File

@@ -173,6 +173,22 @@ function TriggerConnector() {
});
});
}
// Handle Human point
else if (event.type === "crane" && 'point' in event) {
const point = event.point;
point.actions?.forEach(action => {
action.triggers?.forEach(trigger => {
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
});
});
}
});
setConnections(newConnections);

View File

@@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom';
import { useVersionContext } from '../../builder/version/versionContext';
function Products() {
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, layout, productStore } = useSceneContext();
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, layout, productStore } = useSceneContext();
const { products, getProductById, addProduct, setProducts } = productStore();
const { selectedProductStore } = useProductContext();
const { setMainProduct } = useMainProduct();
@@ -20,7 +20,8 @@ function Products() {
const { addMachine, clearMachines } = machineStore();
const { addConveyor, clearConveyors } = conveyorStore();
const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore();
const { addHuman, addCurrentAction, clearHumans } = humanStore();
const { addHuman, addCurrentAction: addCurrentActionHuman, clearHumans } = humanStore();
const { addCrane, addCurrentAction: addCurrentActionCrane, clearCranes } = craneStore();
const { isReset } = useResetButtonStore();
const { isPlaying } = usePlayButtonStore();
const { mainProduct } = useMainProduct();
@@ -164,7 +165,25 @@ function Products() {
addHuman(selectedProduct.productUuid, events);
if (events.point.actions.length > 0) {
addCurrentAction(events.modelUuid, events.point.actions[0].actionUuid);
addCurrentActionHuman(events.modelUuid, events.point.actions[0].actionUuid);
}
}
});
}
}
}, [selectedProduct, products, isReset, isPlaying]);
useEffect(() => {
if (selectedProduct.productUuid) {
const product = getProductById(selectedProduct.productUuid);
if (product) {
clearCranes();
product.eventDatas.forEach(events => {
if (events.type === 'crane') {
addCrane(selectedProduct.productUuid, events);
if (events.point.actions.length > 0) {
addCurrentActionCrane(events.modelUuid, events.point.actions[0].actionUuid);
}
}
});

View File

@@ -7,6 +7,7 @@ import Materials from './materials/materials';
import Machine from './machine/machine';
import StorageUnit from './storageUnit/storageUnit';
import Human from './human/human';
import Crane from './crane/crane';
import Simulator from './simulator/simulator';
import Products from './products/products';
import Trigger from './triggers/trigger';
@@ -55,6 +56,8 @@ function Simulation() {
<Human />
<Crane />
<Simulator />
<SimulationAnalysis />