feat(3d-viewer): enriquecer identificacao de pecas WRL com marca principal e perfil oficial
This commit is contained in:
@@ -18,6 +18,8 @@ interface ProductionPieceStatus {
|
|||||||
currentProcessName?: string;
|
currentProcessName?: string;
|
||||||
processColor?: string;
|
processColor?: string;
|
||||||
processOrdem?: number;
|
processOrdem?: number;
|
||||||
|
perfilPrincipal?: string;
|
||||||
|
descricao?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,6 +69,42 @@ function findProductionDataForPiece(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper para formatar a Marca Principal da Peça no padrão de Engenharia (OF-Fase-Marca, ex: B138-2-1 / B135-2-8)
|
||||||
|
* e obter o Perfil/Bitola oficial a partir do banco de dados ou do modelo 3D.
|
||||||
|
*/
|
||||||
|
function resolvePieceEngineeringDetails(
|
||||||
|
rawPieceMark: string,
|
||||||
|
rawSection: string | undefined,
|
||||||
|
phase: string | undefined,
|
||||||
|
singlePartMark: string | undefined,
|
||||||
|
prod: ProductionPieceStatus | undefined,
|
||||||
|
selectedOF: string | undefined
|
||||||
|
): {
|
||||||
|
displayMark: string;
|
||||||
|
displaySection: string;
|
||||||
|
} {
|
||||||
|
const baseMark = prod?.marca || rawPieceMark || 'Peça';
|
||||||
|
let displayMark = baseMark;
|
||||||
|
|
||||||
|
// Se tivermos OF e Fase e a marca for pura (ex: "1" ou "8"), formata como "B138-2-1" idêntico ao Print 2 "B135-2-8"
|
||||||
|
if (selectedOF && phase && !baseMark.toUpperCase().startsWith(selectedOF.toUpperCase())) {
|
||||||
|
displayMark = `${selectedOF}-${phase}-${baseMark}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perfil / Bitola oficial: prioriza banco de produção (TS_ERP.pecas.perfil_principal), seguido de section limpo do modelo
|
||||||
|
let displaySection = prod?.perfilPrincipal || '';
|
||||||
|
if (!displaySection || displaySection === '1001' || displaySection === 'Perfil') {
|
||||||
|
if (rawSection && rawSection !== '1001' && rawSection !== 'Perfil') {
|
||||||
|
displaySection = rawSection;
|
||||||
|
} else {
|
||||||
|
displaySection = prod?.descricao || 'Perfil';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { displayMark, displaySection };
|
||||||
|
}
|
||||||
|
|
||||||
interface ModelViewer3DProps {
|
interface ModelViewer3DProps {
|
||||||
modelData: LoadedIFCResult | null;
|
modelData: LoadedIFCResult | null;
|
||||||
productionData?: Map<string, ProductionPieceStatus>;
|
productionData?: Map<string, ProductionPieceStatus>;
|
||||||
@@ -940,17 +978,40 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
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 rawPiece = modelData.pieceByExpressID.get(expressID);
|
||||||
|
const rawMark = hitMesh.userData.pieceMark || rawPiece?.pieceMark || '';
|
||||||
|
const phase = hitMesh.userData.phase || rawPiece?.phase;
|
||||||
|
const singlePartMark = hitMesh.userData.singlePartMark || rawPiece?.singlePartMark;
|
||||||
|
|
||||||
|
const prod = findProductionDataForPiece(productionData, {
|
||||||
|
pieceMark: rawMark,
|
||||||
|
cleanMark: hitMesh.userData.cleanMark || rawPiece?.cleanMark,
|
||||||
|
assemblyMark: hitMesh.userData.assemblyMark || rawPiece?.assemblyMark,
|
||||||
|
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark || rawPiece?.cleanAssemblyMark,
|
||||||
|
phase,
|
||||||
|
}, selectedOF);
|
||||||
|
|
||||||
|
const { displayMark, displaySection } = resolvePieceEngineeringDetails(
|
||||||
|
rawMark,
|
||||||
|
hitMesh.userData.section || rawPiece?.section,
|
||||||
|
phase,
|
||||||
|
singlePartMark,
|
||||||
|
prod,
|
||||||
|
selectedOF
|
||||||
|
);
|
||||||
|
|
||||||
|
const piece: PieceInfo = {
|
||||||
expressID,
|
expressID,
|
||||||
guid: hitMesh.userData.guid || '',
|
guid: hitMesh.userData.guid || rawPiece?.guid || '',
|
||||||
name: hitMesh.userData.name || hitMesh.userData.section || 'Peça',
|
name: hitMesh.userData.name || rawPiece?.name || 'Peça',
|
||||||
type: hitMesh.userData.type || 'PIECE',
|
type: hitMesh.userData.type || rawPiece?.type || 'PIECE',
|
||||||
pieceMark: pmark,
|
pieceMark: displayMark,
|
||||||
cleanMark: hitMesh.userData.cleanMark,
|
cleanMark: hitMesh.userData.cleanMark || rawPiece?.cleanMark,
|
||||||
assemblyMark: hitMesh.userData.assemblyMark,
|
assemblyMark: hitMesh.userData.assemblyMark || rawPiece?.assemblyMark,
|
||||||
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark,
|
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark || rawPiece?.cleanAssemblyMark,
|
||||||
section: hitMesh.userData.section || hitMesh.userData.name,
|
section: displaySection,
|
||||||
phase: hitMesh.userData.phase,
|
phase,
|
||||||
|
singlePartMark,
|
||||||
};
|
};
|
||||||
setHoveredPiece(piece);
|
setHoveredPiece(piece);
|
||||||
setHoverPosition({ x: clientX, y: clientY });
|
setHoverPosition({ x: clientX, y: clientY });
|
||||||
@@ -1040,18 +1101,40 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pmark = hitMesh.userData.pieceMark;
|
const rawPiece = modelData?.pieceByExpressID.get(targetIfcId);
|
||||||
const piece: PieceInfo = (modelData && modelData.pieceByExpressID.get(targetIfcId)) || {
|
const rawMark = hitMesh.userData.pieceMark || rawPiece?.pieceMark || '';
|
||||||
|
const phase = hitMesh.userData.phase || rawPiece?.phase;
|
||||||
|
const singlePartMark = hitMesh.userData.singlePartMark || rawPiece?.singlePartMark;
|
||||||
|
|
||||||
|
const prod = findProductionDataForPiece(productionData, {
|
||||||
|
pieceMark: rawMark,
|
||||||
|
cleanMark: hitMesh.userData.cleanMark || rawPiece?.cleanMark,
|
||||||
|
assemblyMark: hitMesh.userData.assemblyMark || rawPiece?.assemblyMark,
|
||||||
|
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark || rawPiece?.cleanAssemblyMark,
|
||||||
|
phase,
|
||||||
|
}, selectedOF);
|
||||||
|
|
||||||
|
const { displayMark, displaySection } = resolvePieceEngineeringDetails(
|
||||||
|
rawMark,
|
||||||
|
hitMesh.userData.section || rawPiece?.section,
|
||||||
|
phase,
|
||||||
|
singlePartMark,
|
||||||
|
prod,
|
||||||
|
selectedOF
|
||||||
|
);
|
||||||
|
|
||||||
|
const piece: PieceInfo = {
|
||||||
expressID: targetIfcId,
|
expressID: targetIfcId,
|
||||||
guid: hitMesh.userData.guid || '',
|
guid: hitMesh.userData.guid || rawPiece?.guid || '',
|
||||||
name: hitMesh.userData.name || hitMesh.userData.section || 'Peça',
|
name: hitMesh.userData.name || rawPiece?.name || 'Peça',
|
||||||
type: hitMesh.userData.type || 'PIECE',
|
type: hitMesh.userData.type || rawPiece?.type || 'PIECE',
|
||||||
pieceMark: pmark,
|
pieceMark: displayMark,
|
||||||
cleanMark: hitMesh.userData.cleanMark,
|
cleanMark: hitMesh.userData.cleanMark || rawPiece?.cleanMark,
|
||||||
assemblyMark: hitMesh.userData.assemblyMark,
|
assemblyMark: hitMesh.userData.assemblyMark || rawPiece?.assemblyMark,
|
||||||
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark,
|
cleanAssemblyMark: hitMesh.userData.cleanAssemblyMark || rawPiece?.cleanAssemblyMark,
|
||||||
section: hitMesh.userData.section,
|
section: displaySection,
|
||||||
phase: hitMesh.userData.phase,
|
phase,
|
||||||
|
singlePartMark,
|
||||||
};
|
};
|
||||||
|
|
||||||
nextMap.set(targetIfcId, {
|
nextMap.set(targetIfcId, {
|
||||||
@@ -1165,17 +1248,40 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
|
|||||||
m.material = magentaMaterialRef.current;
|
m.material = magentaMaterialRef.current;
|
||||||
});
|
});
|
||||||
|
|
||||||
const piece: PieceInfo = (modelData && modelData.pieceByExpressID.get(elId)) || {
|
const rawPiece = modelData?.pieceByExpressID.get(elId);
|
||||||
|
const rawMark = sampleMesh.userData.pieceMark || rawPiece?.pieceMark || '';
|
||||||
|
const phase = sampleMesh.userData.phase || rawPiece?.phase || targetPhase;
|
||||||
|
const singlePartMark = sampleMesh.userData.singlePartMark || rawPiece?.singlePartMark;
|
||||||
|
|
||||||
|
const prod = findProductionDataForPiece(productionData, {
|
||||||
|
pieceMark: rawMark,
|
||||||
|
cleanMark: sampleMesh.userData.cleanMark || rawPiece?.cleanMark,
|
||||||
|
assemblyMark: sampleMesh.userData.assemblyMark || rawPiece?.assemblyMark,
|
||||||
|
cleanAssemblyMark: sampleMesh.userData.cleanAssemblyMark || rawPiece?.cleanAssemblyMark,
|
||||||
|
phase,
|
||||||
|
}, selectedOF);
|
||||||
|
|
||||||
|
const { displayMark, displaySection } = resolvePieceEngineeringDetails(
|
||||||
|
rawMark,
|
||||||
|
sampleMesh.userData.section || rawPiece?.section,
|
||||||
|
phase,
|
||||||
|
singlePartMark,
|
||||||
|
prod,
|
||||||
|
selectedOF
|
||||||
|
);
|
||||||
|
|
||||||
|
const piece: PieceInfo = {
|
||||||
expressID: elId,
|
expressID: elId,
|
||||||
guid: sampleMesh.userData.guid || '',
|
guid: sampleMesh.userData.guid || rawPiece?.guid || '',
|
||||||
name: sampleMesh.userData.name || sampleMesh.userData.section || 'Peça',
|
name: sampleMesh.userData.name || rawPiece?.name || 'Peça',
|
||||||
type: sampleMesh.userData.type || 'PIECE',
|
type: sampleMesh.userData.type || rawPiece?.type || 'PIECE',
|
||||||
pieceMark: sampleMesh.userData.pieceMark,
|
pieceMark: displayMark,
|
||||||
cleanMark: sampleMesh.userData.cleanMark,
|
cleanMark: sampleMesh.userData.cleanMark || rawPiece?.cleanMark,
|
||||||
assemblyMark: sampleMesh.userData.assemblyMark,
|
assemblyMark: sampleMesh.userData.assemblyMark || rawPiece?.assemblyMark,
|
||||||
cleanAssemblyMark: sampleMesh.userData.cleanAssemblyMark,
|
cleanAssemblyMark: sampleMesh.userData.cleanAssemblyMark || rawPiece?.cleanAssemblyMark,
|
||||||
section: sampleMesh.userData.section,
|
section: displaySection,
|
||||||
phase: sampleMesh.userData.phase || targetPhase,
|
phase,
|
||||||
|
singlePartMark,
|
||||||
};
|
};
|
||||||
|
|
||||||
nextMap.set(elId, {
|
nextMap.set(elId, {
|
||||||
|
|||||||
@@ -62,6 +62,15 @@ export const PieceHoverTooltip: React.FC<PieceHoverTooltipProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{piece.singlePartMark && piece.singlePartMark !== piece.pieceMark && (
|
||||||
|
<div className="flex items-center justify-between text-slate-300">
|
||||||
|
<span className="text-slate-400">Sub-peça / Corte:</span>
|
||||||
|
<span className="font-semibold text-slate-200 font-mono bg-slate-950/60 px-2 py-0.5 rounded border border-slate-800">
|
||||||
|
Pos. {piece.singlePartMark}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{piece.childrenIDs && piece.childrenIDs.length > 0 && (
|
{piece.childrenIDs && piece.childrenIDs.length > 0 && (
|
||||||
<div className="flex items-center justify-between text-slate-300">
|
<div className="flex items-center justify-between text-slate-300">
|
||||||
<span className="text-slate-400">Componentes:</span>
|
<span className="text-slate-400">Componentes:</span>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { VRMLLoader } from 'three-stdlib';
|
import { VRMLLoader } from 'three-stdlib';
|
||||||
import { PieceInfo, LoadedIFCResult, IFCQualityAudit, getColorForMaterialName, isValidMark } from '@/lib/ifc/ifcLoaderService';
|
import { PieceInfo, LoadedIFCResult, IFCQualityAudit, getColorForMaterialName, isValidMark, isSinglePartCutNumber } from '@/lib/ifc/ifcLoaderService';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Função utilitária para descompactar arquivos gzip (como .wrz ou .wrl comprimidos) no navegador.
|
* Função utilitária para descompactar arquivos gzip (como .wrz ou .wrl comprimidos) no navegador.
|
||||||
@@ -57,6 +57,9 @@ function extractPhaseFromAncestors(ancestors: string[]): string | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analisa e normaliza a marca da peça, marca do conjunto e tipo estrutural com suporte completo a Tekla / Bocad.
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Analisa e normaliza a marca da peça, marca do conjunto e tipo estrutural com suporte completo a Tekla / Bocad.
|
* Analisa e normaliza a marca da peça, marca do conjunto e tipo estrutural com suporte completo a Tekla / Bocad.
|
||||||
*/
|
*/
|
||||||
@@ -65,10 +68,15 @@ function parseWrlNodeName(
|
|||||||
inheritedPhase?: string,
|
inheritedPhase?: string,
|
||||||
ancestorAssembly?: string
|
ancestorAssembly?: string
|
||||||
): {
|
): {
|
||||||
|
mainMark: string;
|
||||||
|
cleanMainMark: string;
|
||||||
pieceMark: string;
|
pieceMark: string;
|
||||||
cleanMark: string;
|
cleanMark: string;
|
||||||
assemblyMark?: string;
|
assemblyMark?: string;
|
||||||
cleanAssemblyMark?: string;
|
cleanAssemblyMark?: string;
|
||||||
|
singlePartMark?: string;
|
||||||
|
profile?: string;
|
||||||
|
section?: string;
|
||||||
phase?: string;
|
phase?: string;
|
||||||
detectedType: string;
|
detectedType: string;
|
||||||
} {
|
} {
|
||||||
@@ -79,20 +87,22 @@ function parseWrlNodeName(
|
|||||||
|
|
||||||
let assemblyMark = ancestorAssembly ? ancestorAssembly.trim() : undefined;
|
let assemblyMark = ancestorAssembly ? ancestorAssembly.trim() : undefined;
|
||||||
let pieceMark = name;
|
let pieceMark = name;
|
||||||
|
let singlePartMark: string | undefined = undefined;
|
||||||
let profile = '';
|
let profile = '';
|
||||||
|
|
||||||
const parts = name.split('_');
|
const parts = name.split('_');
|
||||||
|
|
||||||
// CASO 1: Tekla composto com 2 números no início: [Conjunto]_[Peca]_[Perfil] (ex: "121_1127_TUBO44x45X3_121293")
|
// CASO 1: Tekla composto com 2 números no início: [Conjunto]_[Peca]_[Perfil] (ex: "1_1001_W360X44_0", "121_1127_TUBO44x45X3_121293")
|
||||||
if (parts.length >= 3 && /^\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
|
if (parts.length >= 3 && /^\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
|
||||||
assemblyMark = parts[0];
|
assemblyMark = parts[0];
|
||||||
pieceMark = parts[1];
|
pieceMark = parts[1];
|
||||||
profile = parts[2];
|
singlePartMark = parts[1];
|
||||||
|
let rest = parts.slice(2).join('_');
|
||||||
|
rest = rest.replace(/_\d{5,}$/, '');
|
||||||
|
profile = rest;
|
||||||
}
|
}
|
||||||
// CASO 2: Tekla padrão [MarcaPeca]_[Perfil] (ex: "5_W360X44_0", "6_W360X32_9", "1_W360X44_0", "6_VIGA")
|
// CASO 2: Tekla padrão [MarcaPeca]_[Perfil] (ex: "5_W360X44_0", "6_W360X32_9", "1_W360X44_0", "6_VIGA")
|
||||||
else if (parts.length >= 2 && /^\d+$/.test(parts[0])) {
|
else if (parts.length >= 2 && /^\d+$/.test(parts[0])) {
|
||||||
// Se o primeiro segmento é numérico e o segundo não é outro número (é perfil ou descrição),
|
|
||||||
// a marca real da peça é o primeiro segmento (ex: "5", "6", "1")!
|
|
||||||
pieceMark = parts[0];
|
pieceMark = parts[0];
|
||||||
assemblyMark = parts[0];
|
assemblyMark = parts[0];
|
||||||
profile = parts.slice(1).join('_');
|
profile = parts.slice(1).join('_');
|
||||||
@@ -100,7 +110,7 @@ function parseWrlNodeName(
|
|||||||
// CASO 3: Prefixo de conjunto alfanumérico (ex: "V101_1_CHAPA", "P1_2_CANTON")
|
// CASO 3: Prefixo de conjunto alfanumérico (ex: "V101_1_CHAPA", "P1_2_CANTON")
|
||||||
else if (parts.length >= 2 && /^[A-Za-z]+\d+$/i.test(parts[0])) {
|
else if (parts.length >= 2 && /^[A-Za-z]+\d+$/i.test(parts[0])) {
|
||||||
assemblyMark = parts[0];
|
assemblyMark = parts[0];
|
||||||
pieceMark = parts[0]; // ou parts[1]
|
pieceMark = parts[0];
|
||||||
profile = parts.slice(1).join('_');
|
profile = parts.slice(1).join('_');
|
||||||
}
|
}
|
||||||
// CASO 4: Parafusos / Fixadores
|
// CASO 4: Parafusos / Fixadores
|
||||||
@@ -113,18 +123,32 @@ function parseWrlNodeName(
|
|||||||
pieceMark = pieceMark.replace(/^(?:Part|Piece|Peca|Elem|Item|Member|Profile|Mesh)[-_]/i, '');
|
pieceMark = pieceMark.replace(/^(?:Part|Piece|Peca|Elem|Item|Member|Profile|Mesh)[-_]/i, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalização do Perfil / Bitola (ex: W360X44_0 -> W360X44.0, W360X32_9 -> W360X32.9)
|
||||||
|
if (profile) {
|
||||||
|
profile = profile.replace(/_(\d+)$/, '.$1').replace(/_/g, ' ').trim();
|
||||||
|
}
|
||||||
|
|
||||||
let cleanMark = pieceMark.replace(/[-_.#]\d+$/, '').trim().toUpperCase();
|
let cleanMark = pieceMark.replace(/[-_.#]\d+$/, '').trim().toUpperCase();
|
||||||
if (!cleanMark) cleanMark = pieceMark.toUpperCase();
|
if (!cleanMark) cleanMark = pieceMark.toUpperCase();
|
||||||
|
|
||||||
const cleanAssemblyMark = assemblyMark ? assemblyMark.replace(/[-_.#]\d+$/, '').trim().toUpperCase() : cleanMark;
|
const cleanAssemblyMark = assemblyMark ? assemblyMark.replace(/[-_.#]\d+$/, '').trim().toUpperCase() : cleanMark;
|
||||||
|
|
||||||
|
// Em estruturas metálicas, a marca da peça apontada na produção é a marca do conjunto (Assembly Mark).
|
||||||
|
// Se a sub-peça for um número de corte (>= 1000) e houver conjunto pai, a marca principal é o conjunto!
|
||||||
|
let mainMark = pieceMark;
|
||||||
|
let cleanMainMark = cleanMark;
|
||||||
|
if (assemblyMark && (isSinglePartCutNumber(pieceMark) || !mainMark || mainMark === 'indefinido')) {
|
||||||
|
mainMark = assemblyMark;
|
||||||
|
cleanMainMark = cleanAssemblyMark;
|
||||||
|
}
|
||||||
|
|
||||||
// Detecção de tipo de elemento estrutural
|
// Detecção de tipo de elemento estrutural
|
||||||
let detectedType = 'ELEMENT';
|
let detectedType = 'ELEMENT';
|
||||||
const searchStr = `${profile} ${name} ${cleanMark} ${cleanAssemblyMark}`.toUpperCase();
|
const searchStr = `${profile} ${name} ${cleanMark} ${cleanAssemblyMark} ${mainMark}`.toUpperCase();
|
||||||
|
|
||||||
if (searchStr.includes('VIGA') || searchStr.includes('BEAM') || cleanMark.startsWith('V')) {
|
if (searchStr.includes('VIGA') || searchStr.includes('BEAM') || cleanMainMark.startsWith('V')) {
|
||||||
detectedType = 'BEAM';
|
detectedType = 'BEAM';
|
||||||
} else if (searchStr.includes('COLUNA') || searchStr.includes('PILAR') || searchStr.includes('COLUMN') || cleanMark.startsWith('P')) {
|
} else if (searchStr.includes('COLUNA') || searchStr.includes('PILAR') || searchStr.includes('COLUMN') || cleanMainMark.startsWith('P')) {
|
||||||
detectedType = 'COLUMN';
|
detectedType = 'COLUMN';
|
||||||
} else if (searchStr.includes('CHAPA') || searchStr.includes('PLATE') || cleanMark.startsWith('PL') || cleanMark.startsWith('CH')) {
|
} else if (searchStr.includes('CHAPA') || searchStr.includes('PLATE') || cleanMark.startsWith('PL') || cleanMark.startsWith('CH')) {
|
||||||
detectedType = 'PLATE';
|
detectedType = 'PLATE';
|
||||||
@@ -145,10 +169,15 @@ function parseWrlNodeName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
mainMark: mainMark.toUpperCase(),
|
||||||
|
cleanMainMark: cleanMainMark.toUpperCase(),
|
||||||
pieceMark: pieceMark.toUpperCase(),
|
pieceMark: pieceMark.toUpperCase(),
|
||||||
cleanMark,
|
cleanMark,
|
||||||
assemblyMark: assemblyMark ? assemblyMark.toUpperCase() : undefined,
|
assemblyMark: assemblyMark ? assemblyMark.toUpperCase() : undefined,
|
||||||
cleanAssemblyMark,
|
cleanAssemblyMark,
|
||||||
|
singlePartMark,
|
||||||
|
profile: profile || undefined,
|
||||||
|
section: profile || undefined,
|
||||||
phase: inheritedPhase,
|
phase: inheritedPhase,
|
||||||
detectedType,
|
detectedType,
|
||||||
};
|
};
|
||||||
@@ -503,19 +532,22 @@ export async function loadAndAuditWRL(
|
|||||||
}
|
}
|
||||||
mesh.material = material;
|
mesh.material = material;
|
||||||
|
|
||||||
const pieceSection = parsed.cleanMark || parsed.pieceMark || 'Perfil';
|
const pieceSection = parsed.profile || parsed.section || parsed.cleanMainMark || 'Perfil';
|
||||||
|
const mainMark = parsed.mainMark || parsed.cleanMainMark || parsed.pieceMark;
|
||||||
|
const cleanMain = parsed.cleanMainMark || parsed.cleanMark;
|
||||||
|
|
||||||
const pieceInfo: PieceInfo = {
|
const pieceInfo: PieceInfo = {
|
||||||
expressID,
|
expressID,
|
||||||
guid,
|
guid,
|
||||||
name: rawNodeName,
|
name: rawNodeName,
|
||||||
type: parsed.detectedType,
|
type: parsed.detectedType,
|
||||||
pieceMark: parsed.pieceMark,
|
pieceMark: mainMark,
|
||||||
cleanMark: parsed.cleanMark,
|
cleanMark: cleanMain,
|
||||||
assemblyMark: parsed.assemblyMark,
|
assemblyMark: parsed.assemblyMark || mainMark,
|
||||||
cleanAssemblyMark: parsed.cleanAssemblyMark,
|
cleanAssemblyMark: parsed.cleanAssemblyMark || cleanMain,
|
||||||
section: pieceSection,
|
section: pieceSection,
|
||||||
phase: parsed.phase,
|
phase: parsed.phase,
|
||||||
|
singlePartMark: parsed.singlePartMark,
|
||||||
mesh,
|
mesh,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -524,10 +556,11 @@ export async function loadAndAuditWRL(
|
|||||||
ifcId: expressID, // Identificador primordial compatível com Raycaster, Hover e Seleção do visualizador
|
ifcId: expressID, // Identificador primordial compatível com Raycaster, Hover e Seleção do visualizador
|
||||||
expressID,
|
expressID,
|
||||||
guid,
|
guid,
|
||||||
pieceMark: parsed.pieceMark,
|
pieceMark: mainMark, // Peça principal da produção (ex: 1, 8, V101)
|
||||||
cleanMark: parsed.cleanMark,
|
cleanMark: cleanMain,
|
||||||
assemblyMark: parsed.assemblyMark,
|
singlePartMark: parsed.singlePartMark, // Componente de corte (ex: 1001)
|
||||||
cleanAssemblyMark: parsed.cleanAssemblyMark,
|
assemblyMark: parsed.assemblyMark || mainMark,
|
||||||
|
cleanAssemblyMark: parsed.cleanAssemblyMark || cleanMain,
|
||||||
section: pieceSection,
|
section: pieceSection,
|
||||||
phase: parsed.phase,
|
phase: parsed.phase,
|
||||||
type: parsed.detectedType,
|
type: parsed.detectedType,
|
||||||
@@ -538,17 +571,12 @@ export async function loadAndAuditWRL(
|
|||||||
|
|
||||||
pieceByExpressID.set(expressID, pieceInfo);
|
pieceByExpressID.set(expressID, pieceInfo);
|
||||||
|
|
||||||
// Agrupa peças por marca
|
// Agrupa peças por marca de conjunto e por marca de componente
|
||||||
const markKey = parsed.cleanMark || parsed.pieceMark;
|
const markKeys = [mainMark, cleanMain, parsed.singlePartMark, parsed.pieceMark, parsed.cleanMark].filter(Boolean) as string[];
|
||||||
if (markKey) {
|
for (const mKey of Array.from(new Set(markKeys))) {
|
||||||
const list = piecesByMark.get(markKey) || [];
|
const list = piecesByMark.get(mKey) || [];
|
||||||
list.push(pieceInfo);
|
list.push(pieceInfo);
|
||||||
piecesByMark.set(markKey, list);
|
piecesByMark.set(mKey, list);
|
||||||
}
|
|
||||||
if (parsed.cleanAssemblyMark && parsed.cleanAssemblyMark !== markKey) {
|
|
||||||
const listAss = piecesByMark.get(parsed.cleanAssemblyMark) || [];
|
|
||||||
listAss.push(pieceInfo);
|
|
||||||
piecesByMark.set(parsed.cleanAssemblyMark, listAss);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export interface PieceInfo {
|
|||||||
parentAssemblyID?: number;
|
parentAssemblyID?: number;
|
||||||
phase?: string;
|
phase?: string;
|
||||||
ofNumber?: string;
|
ofNumber?: string;
|
||||||
|
singlePartMark?: string;
|
||||||
section?: string;
|
section?: string;
|
||||||
span?: number;
|
span?: number;
|
||||||
material?: string;
|
material?: string;
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ export default function Visualizador3D() {
|
|||||||
marca: marcaStr,
|
marca: marcaStr,
|
||||||
fase,
|
fase,
|
||||||
ofNumber: selectedOF,
|
ofNumber: selectedOF,
|
||||||
|
descricao: p.descricao || '',
|
||||||
|
perfilPrincipal: p.perfil_principal || p.descricao || '',
|
||||||
totalQtd: Number(p.quantidade || 1),
|
totalQtd: Number(p.quantidade || 1),
|
||||||
pesoTotal: Number(p.peso_total || 0),
|
pesoTotal: Number(p.peso_total || 0),
|
||||||
pesoUnitario: Number(p.peso_unitario || 0),
|
pesoUnitario: Number(p.peso_unitario || 0),
|
||||||
|
|||||||
Reference in New Issue
Block a user