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.

418 lines
13 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}