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{ 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}