feat(3d-viewer): replica selecao e hover para modelos WRL com destaque magenta e apontamentos
This commit is contained in:
@@ -20,6 +20,53 @@ interface ProductionPieceStatus {
|
|||||||
processOrdem?: number;
|
processOrdem?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Busca de apontamento e status fabril com máxima tolerância e amostragem de chaves para IFC e WRL.
|
||||||
|
*/
|
||||||
|
function findProductionDataForPiece(
|
||||||
|
productionData?: Map<string, ProductionPieceStatus>,
|
||||||
|
piece?: {
|
||||||
|
pieceMark?: string;
|
||||||
|
cleanMark?: string;
|
||||||
|
assemblyMark?: string;
|
||||||
|
cleanAssemblyMark?: string;
|
||||||
|
phase?: string;
|
||||||
|
} | null,
|
||||||
|
selectedOF?: string
|
||||||
|
): ProductionPieceStatus | undefined {
|
||||||
|
if (!productionData || !piece) return undefined;
|
||||||
|
|
||||||
|
const pmark = String(piece.pieceMark || '').trim().toUpperCase();
|
||||||
|
const cleanMark = String(piece.cleanMark || pmark).trim().toUpperCase();
|
||||||
|
const assMark = String(piece.assemblyMark || '').trim().toUpperCase();
|
||||||
|
const cleanAssMark = String(piece.cleanAssemblyMark || cleanMark).trim().toUpperCase();
|
||||||
|
const elementPhase = piece.phase ? String(piece.phase).trim() : '';
|
||||||
|
|
||||||
|
const searchKeys = [
|
||||||
|
elementPhase && selectedOF ? `${selectedOF}-${elementPhase}-${cleanAssMark}` : '',
|
||||||
|
elementPhase ? `${elementPhase}-${cleanAssMark}` : '',
|
||||||
|
elementPhase && selectedOF ? `${selectedOF}-${elementPhase}-${cleanMark}` : '',
|
||||||
|
elementPhase ? `${elementPhase}-${cleanMark}` : '',
|
||||||
|
selectedOF ? `${selectedOF}-${cleanAssMark}` : '',
|
||||||
|
selectedOF ? `${selectedOF}-${cleanMark}` : '',
|
||||||
|
assMark,
|
||||||
|
pmark,
|
||||||
|
cleanAssMark,
|
||||||
|
cleanMark,
|
||||||
|
].filter(Boolean).map((k) => k.toUpperCase());
|
||||||
|
|
||||||
|
for (const key of searchKeys) {
|
||||||
|
const match = productionData.get(key);
|
||||||
|
if (match) {
|
||||||
|
if (!elementPhase || !match.fase || String(match.fase) === String(elementPhase)) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
interface ModelViewer3DProps {
|
interface ModelViewer3DProps {
|
||||||
modelData: LoadedIFCResult | null;
|
modelData: LoadedIFCResult | null;
|
||||||
productionData?: Map<string, ProductionPieceStatus>;
|
productionData?: Map<string, ProductionPieceStatus>;
|
||||||
@@ -721,7 +768,7 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Se a peça física pertencer à seleção permanente, preserva a cor magenta
|
// Se a peça física pertencer à seleção permanente, preserva a cor magenta
|
||||||
const ifcId = mesh.userData.ifcId;
|
const ifcId = mesh.userData.ifcId ?? mesh.userData.expressID;
|
||||||
if (ifcId !== undefined && selectedElementsMapRef.current.has(ifcId)) {
|
if (ifcId !== undefined && selectedElementsMapRef.current.has(ifcId)) {
|
||||||
mesh.userData.originalMaterial = mesh.material;
|
mesh.userData.originalMaterial = mesh.material;
|
||||||
mesh.material = magentaMaterialRef.current;
|
mesh.material = magentaMaterialRef.current;
|
||||||
@@ -889,17 +936,21 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hitMesh) {
|
if (hitMesh) {
|
||||||
const expressID = hitMesh.userData.ifcId;
|
const expressID = hitMesh.userData.ifcId ?? hitMesh.userData.expressID;
|
||||||
const pmark = hitMesh.userData.pieceMark;
|
const pmark = hitMesh.userData.pieceMark;
|
||||||
|
|
||||||
if (modelData && expressID !== undefined) {
|
if (modelData && expressID !== undefined) {
|
||||||
const piece = modelData.pieceByExpressID.get(expressID) || {
|
const piece = modelData.pieceByExpressID.get(expressID) || {
|
||||||
expressID,
|
expressID,
|
||||||
guid: '',
|
guid: hitMesh.userData.guid || '',
|
||||||
name: hitMesh.userData.section || 'Peça',
|
name: hitMesh.userData.name || hitMesh.userData.section || 'Peça',
|
||||||
type: 'PIECE',
|
type: hitMesh.userData.type || 'PIECE',
|
||||||
pieceMark: pmark,
|
pieceMark: pmark,
|
||||||
section: hitMesh.userData.section,
|
cleanMark: hitMesh.userData.cleanMark,
|
||||||
|
assemblyMark: hitMesh.userData.assemblyMark,
|
||||||
|
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark,
|
||||||
|
section: hitMesh.userData.section || hitMesh.userData.name,
|
||||||
|
phase: hitMesh.userData.phase,
|
||||||
};
|
};
|
||||||
setHoveredPiece(piece);
|
setHoveredPiece(piece);
|
||||||
setHoverPosition({ x: clientX, y: clientY });
|
setHoverPosition({ x: clientX, y: clientY });
|
||||||
@@ -956,7 +1007,7 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hitMesh && hitMesh.visible) {
|
if (hitMesh && hitMesh.visible) {
|
||||||
const targetIfcId = hitMesh.userData.ifcId;
|
const targetIfcId = hitMesh.userData.ifcId ?? hitMesh.userData.expressID;
|
||||||
if (targetIfcId === undefined) return;
|
if (targetIfcId === undefined) return;
|
||||||
|
|
||||||
const nextMap = new Map(selectedElementsMapRef.current);
|
const nextMap = new Map(selectedElementsMapRef.current);
|
||||||
@@ -972,27 +1023,33 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
});
|
});
|
||||||
nextMap.delete(targetIfcId);
|
nextMap.delete(targetIfcId);
|
||||||
} else {
|
} else {
|
||||||
// Marcar peça física inteira: localiza e pinta todas as sub-malhas do mesmo ifcId
|
// Marcar peça física inteira: localiza e pinta todas as sub-malhas do mesmo targetIfcId
|
||||||
const relatedMeshes: THREE.Mesh[] = [];
|
const relatedMeshes: THREE.Mesh[] = [];
|
||||||
if (modelGroupRef.current) {
|
if (modelGroupRef.current) {
|
||||||
modelGroupRef.current.traverse((child) => {
|
modelGroupRef.current.traverse((child) => {
|
||||||
if ((child as THREE.Mesh).isMesh && child.userData.ifcId === targetIfcId) {
|
if ((child as THREE.Mesh).isMesh) {
|
||||||
|
const childId = child.userData.ifcId ?? child.userData.expressID;
|
||||||
|
if (childId === targetIfcId) {
|
||||||
const m = child as THREE.Mesh;
|
const m = child as THREE.Mesh;
|
||||||
m.userData.originalMaterial = m.material;
|
m.userData.originalMaterial = m.material;
|
||||||
m.userData.isMagentaSelected = true;
|
m.userData.isMagentaSelected = true;
|
||||||
m.material = magentaMaterialRef.current;
|
m.material = magentaMaterialRef.current;
|
||||||
relatedMeshes.push(m);
|
relatedMeshes.push(m);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pmark = hitMesh.userData.pieceMark;
|
const pmark = hitMesh.userData.pieceMark;
|
||||||
const piece: PieceInfo = (modelData && modelData.pieceByExpressID.get(targetIfcId)) || {
|
const piece: PieceInfo = (modelData && modelData.pieceByExpressID.get(targetIfcId)) || {
|
||||||
expressID: targetIfcId,
|
expressID: targetIfcId,
|
||||||
guid: '',
|
guid: hitMesh.userData.guid || '',
|
||||||
name: hitMesh.userData.section || 'Peça',
|
name: hitMesh.userData.name || hitMesh.userData.section || 'Peça',
|
||||||
type: 'PIECE',
|
type: hitMesh.userData.type || 'PIECE',
|
||||||
pieceMark: pmark,
|
pieceMark: pmark,
|
||||||
|
cleanMark: hitMesh.userData.cleanMark,
|
||||||
|
assemblyMark: hitMesh.userData.assemblyMark,
|
||||||
|
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark,
|
||||||
section: hitMesh.userData.section,
|
section: hitMesh.userData.section,
|
||||||
phase: hitMesh.userData.phase,
|
phase: hitMesh.userData.phase,
|
||||||
};
|
};
|
||||||
@@ -1018,8 +1075,32 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
const mouseX = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
const mouseX = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||||
const mouseY = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
const mouseY = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
||||||
|
|
||||||
raycasterRef.current.setFromCamera(new THREE.Vector2(mouseX, mouseY), activeCameraRef.current);
|
const raycaster = raycasterRef.current;
|
||||||
const intersects = raycasterRef.current.intersectObjects(modelGroupRef.current.children, true);
|
raycaster.params.Line = { threshold: 4.0 };
|
||||||
|
raycaster.params.Points = { threshold: 4.0 };
|
||||||
|
raycaster.setFromCamera(new THREE.Vector2(mouseX, mouseY), activeCameraRef.current);
|
||||||
|
let intersects = raycaster.intersectObjects(modelGroupRef.current.children, true);
|
||||||
|
|
||||||
|
// Amostragem circular magnética de tolerância para peças esbeltas/finas
|
||||||
|
if (intersects.length === 0) {
|
||||||
|
const radiusOffsetsPx = [6, 12, 18];
|
||||||
|
const angles = [0, Math.PI / 4, Math.PI / 2, (3 * Math.PI) / 4, Math.PI, (5 * Math.PI) / 4, (3 * Math.PI) / 2, (7 * Math.PI) / 4];
|
||||||
|
|
||||||
|
for (const rPx of radiusOffsetsPx) {
|
||||||
|
if (intersects.length > 0) break;
|
||||||
|
for (const angle of angles) {
|
||||||
|
const dx = ((rPx * Math.cos(angle)) / rect.width) * 2;
|
||||||
|
const dy = -((rPx * Math.sin(angle)) / rect.height) * 2;
|
||||||
|
const samplePos = new THREE.Vector2(mouseX + dx, mouseY + dy);
|
||||||
|
raycaster.setFromCamera(samplePos, activeCameraRef.current);
|
||||||
|
const sampleIntersects = raycaster.intersectObjects(modelGroupRef.current.children, true);
|
||||||
|
if (sampleIntersects.length > 0) {
|
||||||
|
intersects = sampleIntersects;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const hitPoint = intersects[0].point;
|
const hitPoint = intersects[0].point;
|
||||||
@@ -1033,36 +1114,49 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
|
|
||||||
if (hitMesh) {
|
if (hitMesh) {
|
||||||
const targetPieceMark = String(hitMesh.userData.pieceMark || '').trim().toUpperCase();
|
const targetPieceMark = String(hitMesh.userData.pieceMark || '').trim().toUpperCase();
|
||||||
|
const targetCleanMark = String(hitMesh.userData.cleanMark || targetPieceMark).trim().toUpperCase();
|
||||||
|
const targetAssemblyMark = String(hitMesh.userData.assemblyMark || '').trim().toUpperCase();
|
||||||
|
const targetCleanAssMark = String(hitMesh.userData.cleanAssemblyMark || targetCleanMark).trim().toUpperCase();
|
||||||
const targetPhase = hitMesh.userData.phase ? String(hitMesh.userData.phase).trim() : '';
|
const targetPhase = hitMesh.userData.phase ? String(hitMesh.userData.phase).trim() : '';
|
||||||
|
|
||||||
if (targetPieceMark) {
|
if (targetPieceMark || targetCleanMark) {
|
||||||
const nextMap = new Map(selectedElementsMapRef.current);
|
const nextMap = new Map(selectedElementsMapRef.current);
|
||||||
|
|
||||||
// Agrupa todas as sub-malhas por elemento físico (ifcId único)
|
// Agrupa todas as sub-malhas por elemento físico único (ifcId ?? expressID)
|
||||||
const meshesByIfcId = new Map<number, { meshes: THREE.Mesh[]; sampleMesh: THREE.Mesh }>();
|
const meshesByElementId = new Map<number, { meshes: THREE.Mesh[]; sampleMesh: THREE.Mesh }>();
|
||||||
|
|
||||||
modelGroupRef.current.traverse((child) => {
|
modelGroupRef.current.traverse((child) => {
|
||||||
if ((child as THREE.Mesh).isMesh && child.visible) {
|
if ((child as THREE.Mesh).isMesh && child.visible) {
|
||||||
const mesh = child as THREE.Mesh;
|
const mesh = child as THREE.Mesh;
|
||||||
const pmark = String(mesh.userData.pieceMark || '').trim().toUpperCase();
|
const pmark = String(mesh.userData.pieceMark || '').trim().toUpperCase();
|
||||||
|
const cmark = String(mesh.userData.cleanMark || pmark).trim().toUpperCase();
|
||||||
|
const amark = String(mesh.userData.assemblyMark || '').trim().toUpperCase();
|
||||||
|
const cleanAm = String(mesh.userData.cleanAssemblyMark || cmark).trim().toUpperCase();
|
||||||
const phase = mesh.userData.phase ? String(mesh.userData.phase).trim() : '';
|
const phase = mesh.userData.phase ? String(mesh.userData.phase).trim() : '';
|
||||||
|
|
||||||
// Mesma marca e mesma fase
|
// Mesma marca (peça, conjunto ou limpa) e mesma fase (se especificada)
|
||||||
const isMatch = pmark === targetPieceMark && (!targetPhase || !phase || phase === targetPhase);
|
const isMarkMatch =
|
||||||
if (isMatch) {
|
(pmark && pmark === targetPieceMark) ||
|
||||||
const ifcId = mesh.userData.ifcId;
|
(cmark && cmark === targetCleanMark) ||
|
||||||
if (ifcId !== undefined) {
|
(targetAssemblyMark && amark === targetAssemblyMark) ||
|
||||||
if (!meshesByIfcId.has(ifcId)) {
|
(targetCleanAssMark && cleanAm === targetCleanAssMark);
|
||||||
meshesByIfcId.set(ifcId, { meshes: [], sampleMesh: mesh });
|
|
||||||
|
const isPhaseMatch = !targetPhase || !phase || phase === targetPhase;
|
||||||
|
|
||||||
|
if (isMarkMatch && isPhaseMatch) {
|
||||||
|
const elId = mesh.userData.ifcId ?? mesh.userData.expressID;
|
||||||
|
if (elId !== undefined) {
|
||||||
|
if (!meshesByElementId.has(elId)) {
|
||||||
|
meshesByElementId.set(elId, { meshes: [], sampleMesh: mesh });
|
||||||
}
|
}
|
||||||
meshesByIfcId.get(ifcId)!.meshes.push(mesh);
|
meshesByElementId.get(elId)!.meshes.push(mesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pinta e adiciona cada peça física real como 1 unidade
|
// Pinta e adiciona cada peça física real como 1 unidade
|
||||||
meshesByIfcId.forEach(({ meshes, sampleMesh }, ifcId) => {
|
meshesByElementId.forEach(({ meshes, sampleMesh }, elId) => {
|
||||||
meshes.forEach((m) => {
|
meshes.forEach((m) => {
|
||||||
if (!m.userData.isMagentaSelected) {
|
if (!m.userData.isMagentaSelected) {
|
||||||
m.userData.originalMaterial = m.material;
|
m.userData.originalMaterial = m.material;
|
||||||
@@ -1071,18 +1165,21 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
m.material = magentaMaterialRef.current;
|
m.material = magentaMaterialRef.current;
|
||||||
});
|
});
|
||||||
|
|
||||||
const piece: PieceInfo = (modelData && modelData.pieceByExpressID.get(ifcId)) || {
|
const piece: PieceInfo = (modelData && modelData.pieceByExpressID.get(elId)) || {
|
||||||
expressID: ifcId,
|
expressID: elId,
|
||||||
guid: '',
|
guid: sampleMesh.userData.guid || '',
|
||||||
name: sampleMesh.userData.section || 'Peça',
|
name: sampleMesh.userData.name || sampleMesh.userData.section || 'Peça',
|
||||||
type: 'PIECE',
|
type: sampleMesh.userData.type || 'PIECE',
|
||||||
pieceMark: sampleMesh.userData.pieceMark,
|
pieceMark: sampleMesh.userData.pieceMark,
|
||||||
|
cleanMark: sampleMesh.userData.cleanMark,
|
||||||
|
assemblyMark: sampleMesh.userData.assemblyMark,
|
||||||
|
cleanAssemblyMark: sampleMesh.userData.cleanAssemblyMark,
|
||||||
section: sampleMesh.userData.section,
|
section: sampleMesh.userData.section,
|
||||||
phase: sampleMesh.userData.phase || targetPhase,
|
phase: sampleMesh.userData.phase || targetPhase,
|
||||||
};
|
};
|
||||||
|
|
||||||
nextMap.set(ifcId, {
|
nextMap.set(elId, {
|
||||||
expressID: ifcId,
|
expressID: elId,
|
||||||
piece,
|
piece,
|
||||||
meshes,
|
meshes,
|
||||||
});
|
});
|
||||||
@@ -1118,7 +1215,7 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
const selectedPiecesList: SelectedPieceItem[] = Array.from(selectedElementsMap.values()).map(
|
const selectedPiecesList: SelectedPieceItem[] = Array.from(selectedElementsMap.values()).map(
|
||||||
({ expressID, piece }) => {
|
({ expressID, piece }) => {
|
||||||
const pmark = piece.pieceMark || 'Sem Marca';
|
const pmark = piece.pieceMark || 'Sem Marca';
|
||||||
const prod = productionData?.get(pmark);
|
const prod = findProductionDataForPiece(productionData, piece, selectedOF);
|
||||||
return {
|
return {
|
||||||
id: String(expressID),
|
id: String(expressID),
|
||||||
pieceMark: pmark,
|
pieceMark: pmark,
|
||||||
@@ -1338,16 +1435,17 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
<PieceHoverTooltip
|
<PieceHoverTooltip
|
||||||
piece={hoveredPiece}
|
piece={hoveredPiece}
|
||||||
position={hoverPosition}
|
position={hoverPosition}
|
||||||
productionInfo={
|
productionInfo={(() => {
|
||||||
hoveredPiece?.pieceMark && productionData
|
const prod = findProductionDataForPiece(productionData, hoveredPiece, selectedOF);
|
||||||
|
return prod
|
||||||
? {
|
? {
|
||||||
pointedQty: productionData.get(hoveredPiece.pieceMark)?.pointedQtd,
|
pointedQty: prod.pointedQtd,
|
||||||
totalQty: productionData.get(hoveredPiece.pieceMark)?.totalQtd,
|
totalQty: prod.totalQtd,
|
||||||
currentStage: productionData.get(hoveredPiece.pieceMark)?.currentProcessName,
|
currentStage: prod.currentProcessName,
|
||||||
stageColor: productionData.get(hoveredPiece.pieceMark)?.processColor,
|
stageColor: prod.processColor,
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
|
: undefined;
|
||||||
|
})()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Modal de Lista e Exportação da Seleção 3D */}
|
{/* Modal de Lista e Exportação da Seleção 3D */}
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ export const SmartModelViewer3D: React.FC<SmartModelViewer3DProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4.3. Preserva o destaque magenta se a peça estiver selecionada pelo operador
|
// 4.3. Preserva o destaque magenta se a peça estiver selecionada pelo operador
|
||||||
const ifcId = mesh.userData.ifcId;
|
const ifcId = mesh.userData.ifcId ?? mesh.userData.expressID;
|
||||||
if (ifcId !== undefined && selectedElementsMapRef.current.has(ifcId)) {
|
if (ifcId !== undefined && selectedElementsMapRef.current.has(ifcId)) {
|
||||||
mesh.userData.originalMaterial = mesh.material;
|
mesh.userData.originalMaterial = mesh.material;
|
||||||
mesh.material = magentaMaterialRef.current;
|
mesh.material = magentaMaterialRef.current;
|
||||||
@@ -620,7 +620,7 @@ export const SmartModelViewer3D: React.FC<SmartModelViewer3DProps> = ({
|
|||||||
else if (hitObj.parent && (hitObj.parent as THREE.Mesh).isMesh) hitMesh = hitObj.parent as THREE.Mesh;
|
else if (hitObj.parent && (hitObj.parent as THREE.Mesh).isMesh) hitMesh = hitObj.parent as THREE.Mesh;
|
||||||
|
|
||||||
if (hitMesh && hitMesh.visible) {
|
if (hitMesh && hitMesh.visible) {
|
||||||
const targetIfcId = hitMesh.userData.ifcId;
|
const targetIfcId = hitMesh.userData.ifcId ?? hitMesh.userData.expressID;
|
||||||
if (targetIfcId === undefined) return;
|
if (targetIfcId === undefined) return;
|
||||||
|
|
||||||
const nextMap = new Map(selectedElementsMapRef.current);
|
const nextMap = new Map(selectedElementsMapRef.current);
|
||||||
@@ -644,12 +644,15 @@ export const SmartModelViewer3D: React.FC<SmartModelViewer3DProps> = ({
|
|||||||
// Marca a peça física inteira em Magenta permanente
|
// Marca a peça física inteira em Magenta permanente
|
||||||
const relatedMeshes: THREE.Mesh[] = [];
|
const relatedMeshes: THREE.Mesh[] = [];
|
||||||
modelGroupRef.current.traverse((child) => {
|
modelGroupRef.current.traverse((child) => {
|
||||||
if ((child as THREE.Mesh).isMesh && child.userData.ifcId === targetIfcId) {
|
if ((child as THREE.Mesh).isMesh) {
|
||||||
|
const childId = child.userData.ifcId ?? child.userData.expressID;
|
||||||
|
if (childId === targetIfcId) {
|
||||||
const m = child as THREE.Mesh;
|
const m = child as THREE.Mesh;
|
||||||
m.userData.originalMaterial = m.material;
|
m.userData.originalMaterial = m.material;
|
||||||
m.material = magentaMaterialRef.current;
|
m.material = magentaMaterialRef.current;
|
||||||
relatedMeshes.push(m);
|
relatedMeshes.push(m);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const pmark = hitMesh.userData.pieceMark;
|
const pmark = hitMesh.userData.pieceMark;
|
||||||
|
|||||||
@@ -503,6 +503,8 @@ export async function loadAndAuditWRL(
|
|||||||
}
|
}
|
||||||
mesh.material = material;
|
mesh.material = material;
|
||||||
|
|
||||||
|
const pieceSection = parsed.cleanMark || parsed.pieceMark || 'Perfil';
|
||||||
|
|
||||||
const pieceInfo: PieceInfo = {
|
const pieceInfo: PieceInfo = {
|
||||||
expressID,
|
expressID,
|
||||||
guid,
|
guid,
|
||||||
@@ -512,18 +514,21 @@ export async function loadAndAuditWRL(
|
|||||||
cleanMark: parsed.cleanMark,
|
cleanMark: parsed.cleanMark,
|
||||||
assemblyMark: parsed.assemblyMark,
|
assemblyMark: parsed.assemblyMark,
|
||||||
cleanAssemblyMark: parsed.cleanAssemblyMark,
|
cleanAssemblyMark: parsed.cleanAssemblyMark,
|
||||||
|
section: pieceSection,
|
||||||
phase: parsed.phase,
|
phase: parsed.phase,
|
||||||
mesh,
|
mesh,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Injeta metadados essenciais no userData do Mesh
|
// Injeta metadados essenciais no userData do Mesh (com total compatibilidade IFC / Three.js)
|
||||||
mesh.userData = {
|
mesh.userData = {
|
||||||
|
ifcId: expressID, // Identificador primordial compatível com Raycaster, Hover e Seleção do visualizador
|
||||||
expressID,
|
expressID,
|
||||||
guid,
|
guid,
|
||||||
pieceMark: parsed.pieceMark,
|
pieceMark: parsed.pieceMark,
|
||||||
cleanMark: parsed.cleanMark,
|
cleanMark: parsed.cleanMark,
|
||||||
assemblyMark: parsed.assemblyMark,
|
assemblyMark: parsed.assemblyMark,
|
||||||
cleanAssemblyMark: parsed.cleanAssemblyMark,
|
cleanAssemblyMark: parsed.cleanAssemblyMark,
|
||||||
|
section: pieceSection,
|
||||||
phase: parsed.phase,
|
phase: parsed.phase,
|
||||||
type: parsed.detectedType,
|
type: parsed.detectedType,
|
||||||
name: rawNodeName,
|
name: rawNodeName,
|
||||||
|
|||||||
Reference in New Issue
Block a user