Skip to content

Commit 8187e06

Browse files
committed
restore marker visual
1 parent 50742cd commit 8187e06

15 files changed

Lines changed: 1213 additions & 0 deletions

File tree

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
import React, { useState, useEffect, useRef } from "react";
2+
import { states } from "jderobot-commsmanager";
3+
import { useExercise } from "Contexts/ExerciseContext";
4+
import { updatePath, addToPath } from "./helpers/showImageVisual";
5+
import RobotRed from "./resources/robot_red.svg";
6+
import RobotGreen from "./resources/robot_green.svg";
7+
import RobotBlue from "./resources/robot_blue.svg";
8+
import WebGUIImage from "Components/exercise/WebGUIImage";
9+
import WebGUIContainer, {
10+
connectApplication,
11+
} from "Components/exercise/WebGUIContainer";
12+
13+
import house from "./resources/map.png";
14+
import "./css/GUICanvas.css";
15+
16+
interface Beacon {
17+
id: string;
18+
x: number;
19+
y: number;
20+
type: string;
21+
}
22+
23+
function WebGUI() {
24+
const [realPose, setRealPose] = useState<number[] | undefined>();
25+
const [noisyPose, setNoisyPose] = useState<number[] | undefined>();
26+
const [userPose, setUserPose] = useState<number[] | undefined>();
27+
const [realPath, setRealPath] = useState<string>("");
28+
const [noisyPath, setNoisyPath] = useState<string>("");
29+
const [userPath, setUserPath] = useState<string>("");
30+
const [resizedBeacons, setResizedBeacons] = useState<Beacon[]>([]);
31+
const [userImage, setUserImage] = useState<string | undefined>(undefined);
32+
const canvasRef = useRef<HTMLImageElement>(null);
33+
const exerciseContext = useExercise();
34+
const [manager, setManager] = useState(exerciseContext.manager);
35+
36+
useEffect(() => {
37+
setManager(exerciseContext.manager);
38+
}, [exerciseContext]);
39+
40+
let realTrail: number[][] = [];
41+
let noisyTrail: number[][] = [];
42+
let userTrail: number[][] = [];
43+
let realLastPose: number[] | undefined = undefined;
44+
let noisyLastPose: number[] | undefined = undefined;
45+
let userLastPose: number[] | undefined = undefined;
46+
let valuesUntilValid = 0;
47+
48+
const timeout = 0;
49+
50+
const beacons: Beacon[] = [
51+
{ id: "tag_0", x: 518.75, y: 270.325, type: "hor" },
52+
{ id: "tag_1", x: 481.4, y: 810.775, type: "hor" },
53+
{ id: "tag_2", x: 196.395, y: 339.15, type: "vert" },
54+
{ id: "tag_3", x: 400.89, y: 79.9, type: "hor" },
55+
{ id: "tag_4", x: 844.94, y: 712.3, type: "vert" },
56+
{ id: "tag_5", x: 295.03, y: 499.8, type: "vert" },
57+
{ id: "tag_6", x: 730.4, y: 350.55, type: "hor" },
58+
{ id: "tag_7", x: 499.66, y: 140.25, type: "vert" },
59+
];
60+
61+
const resizeObserver = new ResizeObserver((entries) => {
62+
const img = entries[0].target;
63+
//or however you get a handle to the IMG
64+
const width = img.clientWidth / 1012;
65+
const height = img.clientHeight / 1012;
66+
67+
setResizedBeacons(
68+
beacons.map((beacon) => ({
69+
id: beacon.id,
70+
x: beacon.x * width,
71+
y: beacon.y * height,
72+
type: beacon.type,
73+
}))
74+
);
75+
76+
updatePath(realTrail, setRealPath, height, width);
77+
updatePath(noisyTrail, setNoisyPath, height, width);
78+
updatePath(userTrail, setUserPath, height, width);
79+
80+
if (realLastPose) {
81+
setRealPose([
82+
realLastPose[1] * height,
83+
realLastPose[0] * width,
84+
-1.57 - realLastPose[2],
85+
]);
86+
}
87+
88+
if (noisyLastPose) {
89+
setNoisyPose([
90+
noisyLastPose[1] * height,
91+
noisyLastPose[0] * width,
92+
-1.57 - noisyLastPose[2],
93+
]);
94+
}
95+
96+
if (userLastPose) {
97+
setUserPose([
98+
userLastPose[1] * height,
99+
userLastPose[0] * width,
100+
-1.57 - userLastPose[2],
101+
]);
102+
}
103+
104+
valuesUntilValid = 0;
105+
});
106+
107+
const updateCallback = (updateData: unknown) => {
108+
const data = updateData as any;
109+
const update = data.update;
110+
111+
const img = canvasRef.current;
112+
if (img === null) {
113+
return;
114+
}
115+
const width = img.clientWidth / 1012;
116+
const height = img.clientHeight / 1012;
117+
118+
if (update.real_pose) {
119+
const pose = update.real_pose.substring(1, update.real_pose.length - 1);
120+
const content = pose.split(",").map((item: string) => parseFloat(item));
121+
realLastPose = content;
122+
123+
setRealPose([
124+
content[1] * height,
125+
content[0] * width,
126+
-1.57 - content[2],
127+
]);
128+
if (valuesUntilValid > timeout) {
129+
updatePath(realTrail, setRealPath, height, width);
130+
addToPath(content[1], content[0], realTrail);
131+
} else {
132+
valuesUntilValid = valuesUntilValid + 1;
133+
}
134+
}
135+
136+
if (update.noisy_pose) {
137+
const pose = update.noisy_pose.substring(1, update.noisy_pose.length - 1);
138+
const content = pose.split(",").map((item: string) => parseFloat(item));
139+
noisyLastPose = content;
140+
141+
setNoisyPose([
142+
content[1] * height,
143+
content[0] * width,
144+
-1.57 - content[2],
145+
]);
146+
if (valuesUntilValid > timeout) {
147+
updatePath(noisyTrail, setNoisyPath, height, width);
148+
addToPath(content[1], content[0], noisyTrail);
149+
}
150+
}
151+
152+
if (update.estimate_pose) {
153+
const pose = update.estimate_pose.substring(
154+
1,
155+
update.estimate_pose.length - 1
156+
);
157+
const content = pose.split(",").map((item: string) => parseFloat(item));
158+
userLastPose = content;
159+
160+
setUserPose([
161+
content[1] * height,
162+
content[0] * width,
163+
-1.57 - content[2],
164+
]);
165+
if (valuesUntilValid > timeout) {
166+
updatePath(userTrail, setUserPath, height, width);
167+
addToPath(content[1], content[0], userTrail);
168+
}
169+
}
170+
171+
if (update.image) {
172+
const image = JSON.parse(update.image);
173+
if (image.shape instanceof Array) {
174+
setUserImage(`data:image/png;base64,${image.image}`);
175+
}
176+
}
177+
};
178+
179+
const stateCallback = (state: string) => {
180+
if (state === states.TOOLS_READY) {
181+
setRealPose(undefined);
182+
setNoisyPose(undefined);
183+
setUserPose(undefined);
184+
setUserImage(undefined);
185+
setRealPath("");
186+
setNoisyPath("");
187+
setUserPath("");
188+
realTrail = [];
189+
noisyTrail = [];
190+
userTrail = [];
191+
}
192+
193+
valuesUntilValid = 0;
194+
};
195+
196+
connectApplication(
197+
manager,
198+
updateCallback,
199+
stateCallback,
200+
canvasRef,
201+
resizeObserver
202+
);
203+
204+
return (
205+
<WebGUIContainer>
206+
<WebGUIImage
207+
reference={canvasRef}
208+
id="map-img"
209+
src={house}
210+
style={{ left: "0" }}
211+
/>
212+
<WebGUIImage src={userImage} style={{ left: "50%" }} />
213+
{realPose && (
214+
<div
215+
id="real-pos"
216+
style={{
217+
rotate: "z " + realPose[2] + "rad",
218+
top: realPose[0] - 10,
219+
left: realPose[1] - 5,
220+
}}
221+
>
222+
<img src={RobotGreen} id="real-pos" />
223+
</div>
224+
)}
225+
{realPath && (
226+
<svg
227+
height="100%"
228+
width="100%"
229+
xmlns="http://www.w3.org/2000/svg"
230+
style={{ zIndex: 2, position: "absolute" }}
231+
>
232+
<path
233+
xmlns="http://www.w3.org/2000/svg"
234+
d={realPath}
235+
style={{
236+
strokeWidth: "1px",
237+
strokeLinejoin: "round",
238+
stroke: "green",
239+
fill: "none",
240+
opacity: "0.5",
241+
}}
242+
/>
243+
</svg>
244+
)}
245+
{noisyPose && (
246+
<div
247+
id="noisy-pos"
248+
style={{
249+
rotate: "z " + noisyPose[2] + "rad",
250+
top: noisyPose[0] - 10,
251+
left: noisyPose[1] - 5,
252+
}}
253+
>
254+
<img src={RobotBlue} id="noisy-pos" />
255+
</div>
256+
)}
257+
{noisyPath && (
258+
<svg
259+
height="100%"
260+
width="100%"
261+
xmlns="http://www.w3.org/2000/svg"
262+
style={{ zIndex: 2, position: "absolute" }}
263+
>
264+
<path
265+
xmlns="http://www.w3.org/2000/svg"
266+
d={noisyPath}
267+
style={{
268+
strokeWidth: "1px",
269+
strokeLinejoin: "round",
270+
stroke: "blue",
271+
fill: "none",
272+
opacity: "0.5",
273+
}}
274+
/>
275+
</svg>
276+
)}
277+
{userPose && (
278+
<div
279+
id="user-pos"
280+
style={{
281+
rotate: "z " + userPose[2] + "rad",
282+
top: userPose[0] - 10,
283+
left: userPose[1] - 5,
284+
}}
285+
>
286+
<img src={RobotRed} id="user-pos" />
287+
</div>
288+
)}
289+
{userPath && (
290+
<svg
291+
height="100%"
292+
width="100%"
293+
xmlns="http://www.w3.org/2000/svg"
294+
style={{ zIndex: 2, position: "absolute" }}
295+
>
296+
<path
297+
xmlns="http://www.w3.org/2000/svg"
298+
d={userPath}
299+
style={{
300+
strokeWidth: "1px",
301+
strokeLinejoin: "round",
302+
stroke: "red",
303+
fill: "none",
304+
opacity: "0.5",
305+
}}
306+
/>
307+
</svg>
308+
)}
309+
{Object.values(resizedBeacons).map((beacon) => {
310+
return (
311+
<div
312+
key={beacon.id}
313+
className={`beacon ${beacon.type}`}
314+
style={{
315+
top: `${beacon.y}px`,
316+
left: `${beacon.x}px`,
317+
position: "absolute",
318+
border: "2px solid rgb(255, 255, 255)",
319+
cursor: "pointer",
320+
zIndex: "5",
321+
width: `${beacon.type == "vert" ? 0 : 20}px`,
322+
height: `${beacon.type == "hor" ? 0 : 20}px`,
323+
}}
324+
title={`ID: ${beacon.id}`}
325+
/>
326+
);
327+
})}
328+
</WebGUIContainer>
329+
);
330+
}
331+
332+
export default WebGUI;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#real-pos {
2+
position: absolute;
3+
z-index: 3;
4+
width: 20px;
5+
height: 20px;
6+
border-radius: 10px;
7+
transition: left 0.1s ease-out, top 0.1s ease-out;
8+
left: 0;
9+
}
10+
11+
#noisy-pos {
12+
position: absolute;
13+
z-index: 3;
14+
width: 20px;
15+
height: 20px;
16+
border-radius: 10px;
17+
transition: left 0.1s ease-out, top 0.1s ease-out;
18+
left: 0;
19+
}
20+
21+
#user-pos {
22+
position: absolute;
23+
z-index: 3;
24+
width: 20px;
25+
height: 20px;
26+
border-radius: 10px;
27+
transition: left 0.1s ease-out, top 0.1s ease-out;
28+
left: 0;
29+
}
30+
31+
.beacon {
32+
position: absolute;
33+
border: 2px solid rgb(255, 255, 255);
34+
cursor: pointer;
35+
z-index: 5;
36+
}
37+
38+
.beacon-vert {
39+
width: 0px;
40+
height: 20px;
41+
translate: 0 -10px;
42+
}
43+
44+
.beacon-hor {
45+
width: 20px;
46+
height: 0px;
47+
translate: -10px;
48+
}

0 commit comments

Comments
 (0)