You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
11 KiB
JavaScript
424 lines
11 KiB
JavaScript
import * as THREE from "./lib/three.module.js";
|
|
import { PCDLoader } from "./lib/PCDLoader.js";
|
|
import { matmul, euler_angle_to_rotate_matrix_3by3 } from "./util.js";
|
|
|
|
function Radar(sceneMeta, world, frameInfo, radarName) {
|
|
this.world = world;
|
|
this.frameInfo = frameInfo;
|
|
this.name = radarName;
|
|
this.sceneMeta = sceneMeta;
|
|
this.coordinatesOffset = world.coordinatesOffset;
|
|
|
|
this.showPointsOnly = false;
|
|
this.showRadarBoxFlag = false;
|
|
this.cssStyleSelector =
|
|
this.sceneMeta.calib.radar[this.name].cssstyleselector;
|
|
this.color = this.sceneMeta.calib.radar[this.name].color;
|
|
this.velocityScale = 0.3;
|
|
|
|
if (!this.color) {
|
|
this.color = [1.0, 0.0, 0.0];
|
|
}
|
|
|
|
this._radar_points_raw = null; // read from file, centered at 0
|
|
this.elements = null; // geometry points
|
|
|
|
this.preloaded = false;
|
|
this.loaded = false;
|
|
|
|
this.go_cmd_received = false;
|
|
this.webglScene = null;
|
|
this.on_go_finished = null;
|
|
this.go = function (webglScene, on_go_finished) {
|
|
this.webglScene = webglScene;
|
|
|
|
if (this.preloaded) {
|
|
if (this.elements) {
|
|
this.webglScene.add(this.elements.points);
|
|
|
|
if (!this.showPointsOnly)
|
|
this.elements.arrows.forEach((a) => this.webglScene.add(a));
|
|
|
|
if (this.showRadarBoxFlag) this.webglScene.add(this.radar_box);
|
|
}
|
|
|
|
this.loaded = true;
|
|
if (on_go_finished) on_go_finished();
|
|
}
|
|
|
|
//anyway we save go cmd
|
|
{
|
|
this.go_cmd_received = true;
|
|
this.on_go_finished = on_go_finished;
|
|
}
|
|
};
|
|
|
|
this.showRadarBox = function () {
|
|
this.showRadarBoxFlag = true;
|
|
this.webglScene.add(this.radar_box);
|
|
};
|
|
|
|
this.hideRadarBox = function () {
|
|
this.showRadarBoxFlag = false;
|
|
this.webglScene.remove(this.radar_box);
|
|
};
|
|
|
|
this.get_unoffset_radar_points = function () {
|
|
if (this.elements) {
|
|
let pts = this.elements.points.geometry.getAttribute("position").array;
|
|
return pts.map((p, i) => p - this.world.coordinatesOffset[i % 3]);
|
|
} else {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
// todo: what if it's not preloaded yet
|
|
this.unload = function (keep_box) {
|
|
if (this.elements) {
|
|
this.webglScene.remove(this.elements.points);
|
|
if (!this.showPointsOnly)
|
|
this.elements.arrows.forEach((a) => this.webglScene.remove(a));
|
|
|
|
if (!keep_box) this.webglScene.remove(this.radar_box);
|
|
}
|
|
this.loaded = false;
|
|
};
|
|
|
|
// todo: its possible to remove points before preloading,
|
|
this.deleteAll = function (keep_box) {
|
|
if (this.loaded) {
|
|
this.unload();
|
|
}
|
|
|
|
if (this.elements) {
|
|
//this.scene.remove(this.points);
|
|
this.world.data.dbg.free();
|
|
|
|
if (this.elements.points) {
|
|
this.elements.points.geometry.dispose();
|
|
this.elements.points.material.dispose();
|
|
}
|
|
|
|
if (this.elements.arrows) {
|
|
this.elements.arrows.forEach((a) => {
|
|
this.world.data.dbg.free();
|
|
a.geometry.dispose();
|
|
a.material.dispose();
|
|
});
|
|
}
|
|
|
|
this.elements = null;
|
|
}
|
|
|
|
if (!keep_box && this.radar_box) {
|
|
this.world.data.dbg.free();
|
|
this.radar_box.geometry.dispose();
|
|
this.radar_box.material.dispose();
|
|
this.radar_box = null;
|
|
}
|
|
};
|
|
|
|
this.preload = function (on_preload_finished) {
|
|
var loader = new PCDLoader();
|
|
|
|
var _self = this;
|
|
loader.load(
|
|
this.frameInfo.get_radar_path(this.name),
|
|
//ok
|
|
function (pcd) {
|
|
var position = pcd.position;
|
|
//var velocity = pcd.velocity;
|
|
// velocity is a vector anchored at position,
|
|
// we translate them into position of the vector head
|
|
var velocity = position.map(
|
|
(p, i) => pcd.velocity[i] + pcd.position[i]
|
|
);
|
|
|
|
// scale velocity
|
|
// velocity = velocity.map(v=>v*_self.velocityScale);
|
|
|
|
//_self.points_parse_time = new Date().getTime();
|
|
//console.log(_self.points_load_time, _self.frameInfo.scene, _self.frameInfo.frame, "parse pionts ", _self.points_parse_time - _self.create_time, "ms");
|
|
_self._radar_points_raw = position;
|
|
_self._radar_velocity_raw = velocity;
|
|
|
|
// add one box to calibrate radar with lidar
|
|
_self.radar_box = _self.createRadarBox();
|
|
|
|
// install callback for box changing
|
|
_self.radar_box.on_box_changed = () => {
|
|
_self.move_radar(_self.radar_box);
|
|
};
|
|
|
|
//position = _self.transformPointsByOffset(position);
|
|
position = _self.move_radar_points(_self.radar_box);
|
|
velocity = _self.move_radar_velocity(_self.radar_box);
|
|
let elements = _self.buildRadarGeometry(position, velocity);
|
|
|
|
_self.elements = elements;
|
|
//_self.points_backup = mesh;
|
|
|
|
_self._afterPreload();
|
|
},
|
|
|
|
// on progress,
|
|
function () {},
|
|
|
|
// on error
|
|
function () {
|
|
//error
|
|
console.log("load radar failed.");
|
|
_self._afterPreload();
|
|
},
|
|
|
|
// on file loaded
|
|
function () {
|
|
//_self.points_readfile_time = new Date().getTime();
|
|
//console.log(_self.points_load_time, _self.frameInfo.scene, _self.frameInfo.frame, "read file ", _self.points_readfile_time - _self.create_time, "ms");
|
|
}
|
|
);
|
|
};
|
|
|
|
// internal funcs below
|
|
this._afterPreload = function () {
|
|
this.preloaded = true;
|
|
console.log(`radar ${this.radarname} preloaded`);
|
|
if (this.on_preload_finished) {
|
|
this.on_preload_finished();
|
|
}
|
|
if (this.go_cmd_received) {
|
|
this.go(this.webglScene, this.on_go_finished);
|
|
}
|
|
};
|
|
|
|
this.createRadarBox = function () {
|
|
if (this.sceneMeta.calib.radar && this.sceneMeta.calib.radar[this.name]) {
|
|
return this.world.annotation.createCuboid(
|
|
{
|
|
x:
|
|
this.sceneMeta.calib.radar[this.name].translation[0] +
|
|
this.coordinatesOffset[0],
|
|
y:
|
|
this.sceneMeta.calib.radar[this.name].translation[1] +
|
|
this.coordinatesOffset[1],
|
|
z:
|
|
this.sceneMeta.calib.radar[this.name].translation[2] +
|
|
this.coordinatesOffset[2],
|
|
},
|
|
{ x: 1, y: 1, z: 1 },
|
|
{
|
|
x: this.sceneMeta.calib.radar[this.name].rotation[0],
|
|
y: this.sceneMeta.calib.radar[this.name].rotation[1],
|
|
z: this.sceneMeta.calib.radar[this.name].rotation[2],
|
|
},
|
|
"radar",
|
|
this.name
|
|
);
|
|
} else {
|
|
return this.world.annotation.createCuboid(
|
|
{
|
|
x: this.coordinatesOffset[0],
|
|
y: this.coordinatesOffset[1],
|
|
z: this.coordinatesOffset[2],
|
|
},
|
|
{ x: 1, y: 1, z: 1 },
|
|
{ x: 0, y: 0, z: 0 },
|
|
"radar",
|
|
this.name
|
|
);
|
|
}
|
|
};
|
|
|
|
this.buildPoints = function (position) {
|
|
// build geometry
|
|
this.world.data.dbg.alloc();
|
|
let geometry = new THREE.BufferGeometry();
|
|
if (position.length > 0)
|
|
geometry.addAttribute(
|
|
"position",
|
|
new THREE.Float32BufferAttribute(position, 3)
|
|
);
|
|
|
|
let pointColor = this.color;
|
|
let color = [];
|
|
for (var i = 0; i < position.length; i += 3) {
|
|
color.push(pointColor[0]);
|
|
color.push(pointColor[1]);
|
|
color.push(pointColor[2]);
|
|
}
|
|
|
|
geometry.addAttribute("color", new THREE.Float32BufferAttribute(color, 3));
|
|
|
|
geometry.computeBoundingSphere();
|
|
|
|
// build material
|
|
let pointSize = this.sceneMeta.calib.radar[this.name].point_size;
|
|
if (!pointSize) pointSize = 2;
|
|
|
|
let material = new THREE.PointsMaterial({
|
|
size: pointSize,
|
|
vertexColors: THREE.VertexColors,
|
|
});
|
|
//material.size = 2;
|
|
material.sizeAttenuation = false;
|
|
|
|
// build mesh
|
|
let mesh = new THREE.Points(geometry, material);
|
|
mesh.name = "radar";
|
|
|
|
return mesh;
|
|
};
|
|
|
|
this.buildArrow = function (position, velocity) {
|
|
var h = 0.5;
|
|
|
|
let p = position;
|
|
let v = velocity;
|
|
|
|
var body = [p[0], p[1], p[2], v[0], v[1], v[2]];
|
|
|
|
this.world.data.dbg.alloc();
|
|
var geo = new THREE.BufferGeometry();
|
|
geo.addAttribute("position", new THREE.Float32BufferAttribute(body, 3));
|
|
|
|
let color = this.color
|
|
.map((c) => Math.round(c * 255))
|
|
.reduce((a, b) => a * 256 + b, 0);
|
|
|
|
var material = new THREE.LineBasicMaterial({
|
|
color: color,
|
|
linewidth: 1,
|
|
opacity: 1,
|
|
transparent: true,
|
|
});
|
|
var arrow = new THREE.LineSegments(geo, material);
|
|
return arrow;
|
|
};
|
|
|
|
this.buildRadarGeometry = function (position, velocity) {
|
|
let points = this.buildPoints(position);
|
|
|
|
let arrows = [];
|
|
|
|
if (!this.showPointsOnly) {
|
|
for (let i = 0; i < position.length / 3; i++) {
|
|
let arr = this.buildArrow(
|
|
position.slice(i * 3, i * 3 + 3),
|
|
velocity.slice(i * 3, i * 3 + 3)
|
|
);
|
|
arrows.push(arr);
|
|
}
|
|
}
|
|
|
|
return {
|
|
points: points,
|
|
arrows: arrows,
|
|
};
|
|
};
|
|
|
|
this.move_points = function (points, box) {
|
|
let trans = euler_angle_to_rotate_matrix_3by3(box.rotation);
|
|
let rotated_points = matmul(trans, points, 3);
|
|
let translation = [box.position.x, box.position.y, box.position.z];
|
|
let translated_points = rotated_points.map((p, i) => {
|
|
return p + translation[i % 3];
|
|
});
|
|
return translated_points;
|
|
};
|
|
|
|
this.move_radar_points = function (box) {
|
|
return this.move_points(this._radar_points_raw, box);
|
|
};
|
|
|
|
this.move_radar_velocity = function (box) {
|
|
return this.move_points(this._radar_velocity_raw, box);
|
|
};
|
|
|
|
this.move_radar = function (box) {
|
|
let translated_points = this.move_radar_points(box);
|
|
let translated_velocity = this.move_radar_velocity(box);
|
|
|
|
let elements = this.buildRadarGeometry(
|
|
translated_points,
|
|
translated_velocity
|
|
);
|
|
|
|
// remove old points
|
|
this.unload(true);
|
|
this.deleteAll(true);
|
|
|
|
this.elements = elements;
|
|
//_self.points_backup = mesh;
|
|
if (this.go_cmd_received) {
|
|
// this should be always true
|
|
this.webglScene.add(this.elements.points);
|
|
if (!this.showPointsOnly)
|
|
this.elements.arrows.forEach((a) => this.webglScene.add(a));
|
|
}
|
|
};
|
|
}
|
|
|
|
function RadarManager(sceneMeta, world, frameInfo) {
|
|
this.radarList = [];
|
|
|
|
if (world.data.cfg.enableRadar && sceneMeta.radar) {
|
|
let radars = [];
|
|
|
|
for (let r in sceneMeta.calib.radar) {
|
|
if (!sceneMeta.calib.radar[r].disable) radars.push(r);
|
|
}
|
|
|
|
this.radarList = radars.map((name) => {
|
|
return new Radar(sceneMeta, world, frameInfo, name);
|
|
});
|
|
}
|
|
|
|
this.getAllBoxes = function () {
|
|
if (this.showRadarBoxFlag) {
|
|
return this.radarList.map((r) => r.radar_box);
|
|
} else {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
this.preloaded = function () {
|
|
for (let r in this.radarList) {
|
|
if (!this.radarList[r].preloaded) return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
this.go = function (webglScene, on_go_finished) {
|
|
this.radarList.forEach((r) => r.go(webglScene, on_go_finished));
|
|
};
|
|
|
|
this.preload = function (on_preload_finished) {
|
|
this.radarList.forEach((r) => r.preload(on_preload_finished));
|
|
};
|
|
|
|
this.unload = function () {
|
|
this.radarList.forEach((r) => r.unload());
|
|
};
|
|
|
|
this.deleteAll = function () {
|
|
this.radarList.forEach((r) => r.deleteAll());
|
|
};
|
|
|
|
this.getOperableObjects = function () {
|
|
return this.radarList.flatMap((r) => r.getOperableObjects());
|
|
};
|
|
|
|
this.showRadarBoxFlag = false;
|
|
this.showRadarBox = function () {
|
|
this.showRadarBoxFlag = true;
|
|
this.radarList.forEach((r) => r.showRadarBox());
|
|
};
|
|
|
|
this.hideRadarBox = function () {
|
|
this.showRadarBoxFlag = false;
|
|
this.radarList.forEach((r) => r.hideRadarBox());
|
|
};
|
|
}
|
|
|
|
export { RadarManager };
|