🚀 Auto-deploy: melhoria no snap e medição AR em 24/05/2026 16:22:27
This commit is contained in:
@@ -384,16 +384,28 @@ function useLabelDistanceFactor(position: [number, number, number]): number {
|
|||||||
const dist = camera.position.distanceTo(v);
|
const dist = camera.position.distanceTo(v);
|
||||||
const perspCam = camera as THREE.PerspectiveCamera;
|
const perspCam = camera as THREE.PerspectiveCamera;
|
||||||
const fov = (perspCam.fov ?? 50) * (Math.PI / 180);
|
const fov = (perspCam.fov ?? 50) * (Math.PI / 180);
|
||||||
const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / size.height;
|
const height = size.height || 1;
|
||||||
|
const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / height;
|
||||||
// distanceFactor scales the html so it stays ~140 px tall at this distance
|
// distanceFactor scales the html so it stays ~140 px tall at this distance
|
||||||
ref.current = Math.max(0.05, worldPerPixel * 140);
|
ref.current = isNaN(worldPerPixel) || !isFinite(worldPerPixel) ? 1.5 : Math.max(0.05, worldPerPixel * 140);
|
||||||
});
|
});
|
||||||
return ref.current;
|
return ref.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MeasurementLabel({ position, text, variant, fixed = false }: { position: [number, number, number]; text: string; variant: 'success' | 'primary' | 'accent'; fixed?: boolean }) {
|
function DynamicLabel({ position, text, borderClass, textClass }: { position: [number, number, number]; text: string; borderClass: string; textClass: string }) {
|
||||||
const dfDynamic = useLabelDistanceFactor(position);
|
const dfDynamic = useLabelDistanceFactor(position);
|
||||||
const df = fixed ? dfDynamic : 1.5;
|
return (
|
||||||
|
<Html position={position} center distanceFactor={dfDynamic} zIndexRange={[100, 0]} style={{ pointerEvents: 'none' }}>
|
||||||
|
<div className={`rounded bg-card/95 border ${borderClass} px-2 py-0.5 shadow-lg backdrop-blur-sm`}>
|
||||||
|
<span className={`font-mono text-[11px] font-bold ${textClass} whitespace-nowrap`}>
|
||||||
|
{text}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MeasurementLabel({ position, text, variant, fixed = false }: { position: [number, number, number]; text: string; variant: 'success' | 'primary' | 'accent'; fixed?: boolean }) {
|
||||||
const borderClass = variant === 'success'
|
const borderClass = variant === 'success'
|
||||||
? 'border-success/60'
|
? 'border-success/60'
|
||||||
: variant === 'accent'
|
: variant === 'accent'
|
||||||
@@ -404,8 +416,11 @@ function MeasurementLabel({ position, text, variant, fixed = false }: { position
|
|||||||
: variant === 'accent'
|
: variant === 'accent'
|
||||||
? 'text-amber-400'
|
? 'text-amber-400'
|
||||||
: 'text-primary';
|
: 'text-primary';
|
||||||
return (
|
|
||||||
<Html position={position} center distanceFactor={df} zIndexRange={[100, 0]} style={{ pointerEvents: 'none' }}>
|
return fixed ? (
|
||||||
|
<DynamicLabel position={position} text={text} borderClass={borderClass} textClass={textClass} />
|
||||||
|
) : (
|
||||||
|
<Html position={position} center distanceFactor={1.5} zIndexRange={[100, 0]} style={{ pointerEvents: 'none' }}>
|
||||||
<div className={`rounded bg-card/95 border ${borderClass} px-2 py-0.5 shadow-lg backdrop-blur-sm`}>
|
<div className={`rounded bg-card/95 border ${borderClass} px-2 py-0.5 shadow-lg backdrop-blur-sm`}>
|
||||||
<span className={`font-mono text-[11px] font-bold ${textClass} whitespace-nowrap`}>
|
<span className={`font-mono text-[11px] font-bold ${textClass} whitespace-nowrap`}>
|
||||||
{text}
|
{text}
|
||||||
@@ -473,15 +488,12 @@ function ModelMeasurements({ modelId }: { modelId: string }) {
|
|||||||
|
|
||||||
/** Renders snap indicator, hover tooltip, pending point and any *legacy*
|
/** Renders snap indicator, hover tooltip, pending point and any *legacy*
|
||||||
* world-frame measurements that aren't attached to a specific model. */
|
* world-frame measurements that aren't attached to a specific model. */
|
||||||
function HoverLabelOverlay({ hoverInfo }: { hoverInfo: HoverInfo | null }) {
|
function HoverLabelOverlay({ hoverInfo }: { hoverInfo: HoverInfo }) {
|
||||||
const visible = !!hoverInfo;
|
const position = hoverInfo.position;
|
||||||
const position = hoverInfo?.position ?? [0, 0, 0];
|
const text = hoverInfo.type === 'hole'
|
||||||
const text = hoverInfo
|
? `Ø ${hoverInfo.value.toFixed(1)}`
|
||||||
? hoverInfo.type === 'hole'
|
: `${hoverInfo.value.toFixed(1)} mm`;
|
||||||
? `Ø ${hoverInfo.value.toFixed(1)}`
|
const variant = hoverInfo.type === 'hole' ? 'accent' : 'primary';
|
||||||
: `${hoverInfo.value.toFixed(1)} mm`
|
|
||||||
: '';
|
|
||||||
const variant = hoverInfo?.type === 'hole' ? 'accent' : 'primary';
|
|
||||||
|
|
||||||
const dfDynamic = useLabelDistanceFactor(position);
|
const dfDynamic = useLabelDistanceFactor(position);
|
||||||
|
|
||||||
@@ -500,8 +512,6 @@ function HoverLabelOverlay({ hoverInfo }: { hoverInfo: HoverInfo | null }) {
|
|||||||
zIndexRange={[100, 0]}
|
zIndexRange={[100, 0]}
|
||||||
style={{
|
style={{
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
display: visible ? 'block' : 'none',
|
|
||||||
opacity: visible ? 1 : 0,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className={`rounded bg-card/95 border ${borderClass} px-2 py-0.5 shadow-lg backdrop-blur-sm`}>
|
<div className={`rounded bg-card/95 border ${borderClass} px-2 py-0.5 shadow-lg backdrop-blur-sm`}>
|
||||||
@@ -530,7 +540,9 @@ function MeasurementOverlay() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Hover auto-detect tooltip (works both inside and outside measure mode) */}
|
{/* Hover auto-detect tooltip (works both inside and outside measure mode) */}
|
||||||
<HoverLabelOverlay hoverInfo={hoverInfo} />
|
{hoverInfo && (
|
||||||
|
<HoverLabelOverlay hoverInfo={hoverInfo} />
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Pending first point (always in world coords) */}
|
{/* Pending first point (always in world coords) */}
|
||||||
{measurePoints.length === 1 && (
|
{measurePoints.length === 1 && (
|
||||||
|
|||||||
Reference in New Issue
Block a user