new top down stuff

This commit is contained in:
legop3
2025-12-28 00:06:24 -05:00
parent 1241c867a5
commit 3cc12b76b9
4 changed files with 70 additions and 44 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -11,7 +11,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" /> <meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
<title>Multi Roomba Rover</title> <title>Multi Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-ys6pPVMX.js"></script> <script type="module" crossorigin src="/assets/index-jVd0ekcb.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D2GpvMU5.css"> <link rel="stylesheet" crossorigin href="/assets/index-D2GpvMU5.css">
</head> </head>
<body> <body>
+57 -31
View File
@@ -3,6 +3,9 @@ import React from 'react';
function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overlay = false }) { function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overlay = false }) {
const size = overrideSize || (variant === 'mini' ? 190 : 260); const size = overrideSize || (variant === 'mini' ? 190 : 260);
const center = size / 2; const center = size / 2;
const offsetY = size * 0.07; // nudge everything downward within the viewBox
const centerX = center;
const centerY = center + offsetY;
const innerCircle = center * 0.8; // keep proportions consistent as size changes const innerCircle = center * 0.8; // keep proportions consistent as size changes
const lightRingInner = innerCircle - 4; const lightRingInner = innerCircle - 4;
const lightRingOuter = innerCircle + 4; const lightRingOuter = innerCircle + 4;
@@ -61,32 +64,32 @@ function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overla
</> </>
) : null} ) : null}
<svg width="100%" height="100%" viewBox={`0 0 ${size} ${size}`} preserveAspectRatio="xMidYMid meet" className="mx-auto block"> <svg width="100%" height="100%" viewBox={`0 0 ${size} ${size}`} preserveAspectRatio="xMidYMid meet" className="mx-auto block">
<circle cx={center} cy={center} r={innerCircle} fill="#0f172a" stroke="#334155" strokeWidth="2" /> <circle cx={centerX} cy={centerY} r={innerCircle} fill="#0f172a" stroke="#334155" strokeWidth="2" />
<WheelVisual <WheelVisual
cx={center - wheelLineOffset} cx={centerX - wheelLineOffset}
cy={center} cy={centerY}
current={wheelCurrentLeft} current={wheelCurrentLeft}
drop={bumps.wheelDropLeft} drop={bumps.wheelDropLeft}
overcurrent={wheelOver.leftWheel} overcurrent={wheelOver.leftWheel}
label="L" label="L"
/> />
<WheelVisual <WheelVisual
cx={center + wheelLineOffset} cx={centerX + wheelLineOffset}
cy={center} cy={centerY}
current={wheelCurrentRight} current={wheelCurrentRight}
drop={bumps.wheelDropRight} drop={bumps.wheelDropRight}
overcurrent={wheelOver.rightWheel} overcurrent={wheelOver.rightWheel}
label="R" label="R"
/> />
<SideBrushVisual <SideBrushVisual
cx={center + innerCircle * 0.65} cx={centerX + innerCircle * 0.65}
cy={center - innerCircle * 0.55} cy={centerY - innerCircle * 0.55}
current={sideBrushCurrent} current={sideBrushCurrent}
overcurrent={wheelOver.sideBrush} overcurrent={wheelOver.sideBrush}
/> />
<MainBrushVisual <MainBrushVisual
cx={center} cx={centerX}
cy={center} cy={centerY}
current={mainBrushCurrent} current={mainBrushCurrent}
overcurrent={wheelOver.mainBrush} overcurrent={wheelOver.mainBrush}
variant={variant} variant={variant}
@@ -94,19 +97,21 @@ function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overla
dirtRight={sensors?.dirtDetect} dirtRight={sensors?.dirtDetect}
/> />
{lightSegments.map((seg) => { {lightSegments.map((seg) => {
const color = lightBumpColor(seg.value); const color = lightBumpColor(seg.value, maxLight);
const tipR = lightRingOuter + 4; // point starts just outside bump arc
const baseR = tipR + 28; // extend starting length for more resolution
return ( return (
<ArcSegment <ConeSegment
key={seg.label} key={seg.label}
cx={center} cx={centerX}
cy={center} cy={centerY}
rInner={lightRingInner} rBase={baseR}
rOuter={lightRingOuter} rTip={tipR}
startDeg={seg.start} startDeg={seg.start}
endDeg={seg.end} endDeg={seg.end}
color={color} color={color}
opacity={1} value={seg.value}
pulse={false} max={maxLight}
/> />
); );
})} })}
@@ -115,8 +120,8 @@ function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overla
return ( return (
<ArcSegment <ArcSegment
key={seg.label} key={seg.label}
cx={center} cx={centerX}
cy={center} cy={centerY}
rInner={cliffRingInner} rInner={cliffRingInner}
rOuter={cliffRingOuter} rOuter={cliffRingOuter}
startDeg={seg.start} startDeg={seg.start}
@@ -128,10 +133,10 @@ function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overla
); );
})} })}
<ArcSegment <ArcSegment
cx={center} cx={centerX}
cy={center} cy={centerY}
rInner={lightRingOuter + 2} rInner={lightRingInner}
rOuter={lightRingOuter + 8} rOuter={lightRingOuter}
startDeg={-70} startDeg={-70}
endDeg={-6} endDeg={-6}
color={bumps.bumpLeft ? '#ef4444' : '#475569'} color={bumps.bumpLeft ? '#ef4444' : '#475569'}
@@ -139,10 +144,10 @@ function TopDownMap({ sensors = {}, variant = 'full', size: overrideSize, overla
pulse={Boolean(bumps.bumpLeft)} pulse={Boolean(bumps.bumpLeft)}
/> />
<ArcSegment <ArcSegment
cx={center} cx={centerX}
cy={center} cy={centerY}
rInner={lightRingOuter + 2} rInner={lightRingInner}
rOuter={lightRingOuter + 8} rOuter={lightRingOuter}
startDeg={6} startDeg={6}
endDeg={70} endDeg={70}
color={bumps.bumpRight ? '#ef4444' : '#475569'} color={bumps.bumpRight ? '#ef4444' : '#475569'}
@@ -176,6 +181,23 @@ function ArcSegment({ cx, cy, rInner, rOuter, startDeg, endDeg, color, pulse = f
); );
} }
function ConeSegment({ cx, cy, rBase, rTip, startDeg, endDeg, color, value, max }) {
const mid = (startDeg + endDeg) / 2;
const baseA = polarToCartesian(cx, cy, rBase, startDeg);
const baseB = polarToCartesian(cx, cy, rBase, endDeg);
const tip = polarToCartesian(cx, cy, rTip, mid);
const norm = clamp01(value != null ? value / (max || 1) : 0);
const eased = Math.pow(norm, 0.35); // even more sensitive near the start, softer near the end
// higher value = closer obstacle → bar shrinks toward the tip (reverse fill)
const filledR = rBase - (rBase - rTip) * eased;
const barR = Math.max(rTip, Math.min(filledR, rBase));
const filledA = polarToCartesian(cx, cy, filledR, startDeg);
const filledB = polarToCartesian(cx, cy, filledR, endDeg);
const fg = `M ${tip.x} ${tip.y} L ${filledA.x} ${filledA.y} L ${filledB.x} ${filledB.y} Z`;
return <path d={fg} fill={color} opacity={1} stroke="none" />;
}
function describeArc(cx, cy, r, startDeg, endDeg) { function describeArc(cx, cy, r, startDeg, endDeg) {
let start = startDeg; let start = startDeg;
let end = endDeg; let end = endDeg;
@@ -304,10 +326,14 @@ function MainBrushVisual({ cx, cy, current, overcurrent, variant, dirtLeft, dirt
); );
} }
const LIGHT_BUMP_SENSITIVITY = 0.18; function lightBumpColor(value, max) {
function lightBumpColor(value) { if (value == null || value <= 0) return 'hsl(200 60% 18%)'; // faint blue instead of black
if (value == null || value <= 0) return '#000000'; const maxVal = max || 1;
const hue = (value * LIGHT_BUMP_SENSITIVITY) % 360; const norm = clamp01(value / maxVal);
const eased = Math.pow(norm, 0.45); // match cone fill sensitivity
// offset the start hue so we don't begin at red, still sweep the full rainbow
const startHue = 200; // deep cyan/blue start
const hue = (startHue + eased * 360) % 360;
return `hsl(${hue} 100% 60%)`; return `hsl(${hue} 100% 60%)`;
} }