import * as THREE from './lib/three.module.js'; import { matmul, euler_angle_to_rotate_matrix, transpose, psr_to_xyz, array_as_vector_range, array_as_vector_index_range, vector_range, euler_angle_to_rotate_matrix_3by3} from "./util.js" import { PCDLoader } from './lib/PCDLoader.js'; import {globalObjectCategory} from './obj_cfg.js'; import {settings} from "./settings.js" function Lidar(sceneMeta, world, frameInfo){ this.world = world; this.data = world.data; this.frameInfo = frameInfo; this.sceneMeta = sceneMeta; this.points = null; this.points_load_time = 0; this.remove_high_ponts = function(pcd, z){ let position = []; let color = []; let normal = []; let intensity = []; //3, 3, 3, 1 for (let i = 0; i < pcd.position.length/3; i++){ if (pcd.position[i*3+2] < z){ position.push(pcd.position[i*3+0]); position.push(pcd.position[i*3+1]); position.push(pcd.position[i*3+2]); if (pcd.color.length>0){ color.push(pcd.color[i*3+0]); color.push(pcd.color[i*3+1]); color.push(pcd.color[i*3+2]); } if (pcd.normal.length>0){ normal.push(pcd.normal[i*3+0]); normal.push(pcd.normal[i*3+1]); normal.push(pcd.normal[i*3+2]); } if (pcd.intensity){ intensity.push(pcd.intensity[i]); } } } pcd.position = position; pcd.intensity = intensity; pcd.color = color; pcd.normal = normal; return pcd; }; this.preload=function(on_preload_finished){ this.on_preload_finished = on_preload_finished; var loader = new PCDLoader(); var _self = this; loader.load( this.frameInfo.get_pcd_path(), //ok function ( pcd ) { _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"); // if (_self.frameInfo.transform_matrix){ // var arr = position; // var num = position.length; // var ni = 3; // for (var i=0; i 0 ) geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( position, 3 ) ); let normal = pcd.normal; // normal and colore are note used in av scenes. if ( normal.length > 0 ) geometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( normal, 3 ) ); let color = pcd.color; if ( color.length == 0 ) { color = [] // by default we set all points to same color for (let i =0; i< position.length; ++i){ color.push(_self.data.cfg.point_brightness); } // if enabled intensity we color points by intensity. if (_self.data.cfg.color_points=="intensity" && pcd.intensity.length>0){ // map intensity to color for (var i =0; i< pcd.intensity.length; ++i){ let intensity = pcd.intensity[i]; intensity *= 8; if (intensity > 1) intensity = 1.0; //color.push( 2 * Math.abs(0.5-intensity)); color[i*3] = intensity; color[i*3+1] = intensity; color[i*3+2] = 1 - intensity; } } // save color, in case color needs to be restored. pcd.color = color; } geometry.setAttribute( 'color', new THREE.Float32BufferAttribute(color, 3 ) ); geometry.computeBoundingSphere(); // build material var material = new THREE.PointsMaterial( { size: _self.data.cfg.point_size, vertexColors: THREE.VertexColors } ); /* if ( color.length > 0 ) { material.vertexColors = color; } else { //material.color.setHex(0xffffff); material.color.r = 0.6; material.color.g = 0.6; material.color.b = 0.6; } */ //material.size = 2; material.sizeAttenuation = false; // build mesh var mesh = new THREE.Points( geometry, material ); mesh.name = "pcd"; //return mesh; // add to parent. _self.world.webglGroup.add(mesh); _self.points = mesh; _self.pcd = pcd; //_self.points_backup = mesh; _self.build_points_index(); _self.points_load_time = new Date().getTime(); console.log(_self.points_load_time, _self.frameInfo.scene, _self.frameInfo.frame, "loaded pionts ", _self.points_load_time - _self.create_time, "ms"); _self._afterPreload(); }, // on progress, function(){ }, // on error function(){ //error console.log("load pcd 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"); } ); }; this.deleteAll = function(){ return this.remove_all_points(); } this._afterPreload = function(){ this.preloaded = true; console.log("lidar preloaded"); //go ahead, may load picture if (this.on_preload_finished){ this.on_preload_finished(); } if (this.go_cmd_received){ this.go(this.webglScene, this.on_go_finished); } }; this.loaded = false; this.webglScene = null; this.go_cmd_received = false; this.on_go_finished = null; this.go = function(webglScene, on_go_finished){ this.webglScene = webglScene; if (this.preloaded){ if (!this.world.data.cfg.show_background){ this.hide_background(); } if (this.data.cfg.color_obj != "no"){ this.color_objects(); } if (on_go_finished) on_go_finished(); } else { this.go_cmd_received = true; this.on_go_finished = on_go_finished; } }; this.unload = function(){ this.cancel_highlight(); if (this.points){ // this.world.webglGroup.remove(this.points); // if (this.points.points_backup){ // let backup = this.points.points_backup; // this.points.points_backup = null; // this.remove_all_points(); // this.points = backup; // } } }; this.deleteAll = function(){ this.remove_all_points(); } this.set_point_size=function(v){ if (this.points){ this.points.material.size = v; // this could happen if the points are still loading if (this.points.points_backup){ this.points.points_backup.material.size = v; if (this.points.points_backup.points_backup){ this.points.points_backup.points_backup.material.size = v; } } } }; this.color_objects = function(){ if (this.data.cfg.color_obj != "no"){ this.world.annotation.boxes.map((b)=>{ if (!b.annotator) this.set_box_points_color(b); }) } }; // color points according to object category this.color_points=function(){ // color all points inside these boxes let color = this.points.geometry.getAttribute("color").array; // step 1, color all points. if (this.data.cfg.color_points=="intensity" && this.pcd.intensity.length>0){ // by intensity for (var i =0; i< this.pcd.intensity.length; ++i){ let intensity = this.pcd.intensity[i]; intensity *= 8; if (intensity > 1) intensity = 1.0; //color.push( 2 * Math.abs(0.5-intensity)); color[i*3] = intensity; color[i*3+1] = intensity; color[i*3+2] = 1 - intensity; } } else { // mono color for (let i =0; i< this.pcd.position.length; ++i){ color[i] = this.data.cfg.point_brightness; } } // step 2 color objects this.color_objects(); //this.update_points_color(); }; this.transformPointsByEgoPose = function(points){ if (!this.world.transLidar) return points; let newPoints=[]; for (let i=0; i 0 ) { geometry.setAttribute( 'position', new THREE.Float32BufferAttribute(hl_point, 3 ) ); geometry.setAttribute( 'color', new THREE.Float32BufferAttribute(hl_color, 3 ) ); } geometry.computeBoundingSphere(); var material = new THREE.PointsMaterial( { size: _self.data.cfg.point_size, vertexColors: THREE.VertexColors } ); material.sizeAttenuation = false; var mesh = new THREE.Points( geometry, material ); mesh.name = "pcd"; mesh.points_backup = this.points; mesh.highlight_point_indices = highlight_point_indices; //swith geometry this.world.webglGroup.remove(this.points); this.points = mesh; this.build_points_index(); this.world.webglGroup.add(mesh); }; this.cancel_highlight=function(box){ if (this.points && this.points.points_backup){ this.world.annotation.set_box_opacity(this.data.cfg.box_opacity); //copy colors, maybe changed. if (this.data.cfg.color_obj != "no"){ var highlight_point_color = this.points.geometry.getAttribute("color"); var backup_point_color = this.points.points_backup.geometry.getAttribute("color"); this.points.highlight_point_indices.forEach(function(n, i){ backup_point_color.array[n*3] = highlight_point_color.array[i*3]; backup_point_color.array[n*3+1] = highlight_point_color.array[i*3+1]; backup_point_color.array[n*3+2] = highlight_point_color.array[i*3+2]; }); } //switch var points_backup = this.points.points_backup; this.points.points_backup = null; this.world.webglGroup.remove(this.points); this.remove_all_points(); //this.points is null now this.points = points_backup; if (box){ // in highlighted mode, the box my be moved outof the highlighted area, so // we need to color them again. if (this.data.cfg.color_obj != "no") this.set_box_points_color(box); } if (this.data.cfg.color_obj != "no") this.update_points_color(); this.world.webglGroup.add(this.points); } }; this.reset_points=function(points){ // coordinates of points this.world.data.dbg.alloc(); var geometry = new THREE.BufferGeometry(); geometry.setAttribute( 'position', new THREE.Float32BufferAttribute(points, 3 ) ); geometry.computeBoundingSphere(); var material = new THREE.PointsMaterial( { size: this.data.cfg.point_size} ); material.sizeAttenuation = false; var mesh = new THREE.Points( geometry, material ); mesh.name = "pcd"; //swith geometry this.world.webglGroup.remove(this.points); this.remove_all_points(); this.points = mesh; this.world.webglGroup.add(mesh); }; this.highlight_box_points=function(box){ if (this.points.highlighted_box){ //already highlighted. return; } // hide all other boxes this.world.annotation.set_box_opacity(0); // keep myself box.material.opacity = 1; var _self = this; var pos = this.points.geometry.getAttribute("position"); var color = this.points.geometry.getAttribute("color"); var hl_point=[]; var hl_color=[]; var highlight_point_indices= this._get_points_index_of_box(this.points, box, 3); highlight_point_indices.forEach(function(i){ hl_point.push(pos.array[i*3]); hl_point.push(pos.array[i*3+1]); hl_point.push(pos.array[i*3+2]); hl_color.push(color.array[i*3]); hl_color.push(color.array[i*3+1]); hl_color.push(color.array[i*3+2]); }) // build new geometry this.world.data.dbg.alloc(); var geometry = new THREE.BufferGeometry(); if (hl_point.length > 0 ) { geometry.setAttribute( 'position', new THREE.Float32BufferAttribute(hl_point, 3 ) ); geometry.setAttribute( 'color', new THREE.Float32BufferAttribute(hl_color, 3 ) ); } geometry.computeBoundingSphere(); var material = new THREE.PointsMaterial( { size: _self.data.cfg.point_size, vertexColors: THREE.VertexColors } ); material.sizeAttenuation = false; var mesh = new THREE.Points( geometry, material ); mesh.name = "highlighted_pcd"; //swith geometry this.world.webglGroup.remove(this.points); mesh.points_backup = this.points; mesh.highlight_point_indices = highlight_point_indices; mesh.highlighted_box = box; this.points = mesh; this.build_points_index(); this.world.webglGroup.add(mesh); }; this.get_points_indices_of_box=function(box){ return this._get_points_of_box(this.points, box, 1).index; }; this.get_points_of_box_in_box_coord=function(box){ return this._get_points_of_box(this.points, box, 1).position; }; // IMPORTANT // ground plane affects auto-adjustment // we don't count in the ponits of lowest part to reduce the affection. // note how the 'lower part' is defined, we count // lowest_part_type has two options: lowest_point, or lowest_box this.get_points_dimmension_of_box=function(box, use_box_bottom_as_limit){ var p = this._get_points_of_box(this.points, box, 1).position; //position is relative to box coordinates var lowest_limit = - box.scale.z/2; if (!use_box_bottom_as_limit){ var extreme1 = vector_range(p, 3); lowest_limit = extreme1.min[2]; } //filter out lowest part var p = p.filter(function(x){ return x[2] - settings.ground_filter_height > lowest_limit; }) //compute range again. var extreme2 = vector_range(p, 3); return { max:{ x: extreme2.max[0], y: extreme2.max[1], z: extreme2.max[2], }, min:{ x: extreme2.min[0], y: extreme2.min[1], z: lowest_limit, } } }; // given points and box, calculate new box scale this.get_dimension_of_points=function(indices, box){ var p = this._get_points_of_box(this.points, box, 1, indices).position; var extreme1 = vector_range(p, 3); //filter out lowest part, to calculate x-y size. var p = p.filter(function(x){ return x[2] - settings.ground_filter_height > extreme1.min[2]; }) //compute range again. var extreme2 = vector_range(p, 3); return { max:{ x: extreme2.max[0], y: extreme2.max[1], z: extreme1.max[2], // orignal extreme. }, min:{ x: extreme2.min[0], y: extreme2.min[1], z: extreme1.min[2], } } }; //centered, but without rotation this.get_points_relative_coordinates_of_box_wo_rotation=function(box, scale_ratio){ return this._get_points_of_box(this.points, box, scale_ratio).position_wo_rotation; }; this.get_points_of_box=function(box, scale_ratio){ return this._get_points_of_box(this.points, box, scale_ratio); }; this.get_points_relative_coordinates_of_box=function(box, scale_ratio){ var ret = this._get_points_of_box(this.points, box, scale_ratio); return ret.position; }; this._get_points_index_of_box=function(points, box, scale_ratio){ return this._get_points_of_box(points, box, scale_ratio).index; }; // this this._get_points_of_box=function(points, box, scale_ratio, point_indices){ if (!scale_ratio){ scale_ratio = 1; } var pos_array = points.geometry.getAttribute("position").array; var relative_position = []; var relative_position_wo_rotation = []; var r = box.rotation; var trans = transpose(euler_angle_to_rotate_matrix(r, {x:0, y:0, z:0}), 4); var indices=[]; var cand_point_indices = point_indices; if (!point_indices) { cand_point_indices = this.get_covering_position_indices(points, box.position, box.scale, box.rotation, scale_ratio); } cand_point_indices.forEach(function(i){ //for (var i = 0; i < pos.count; i++){ var x = pos_array[i*3]; var y = pos_array[i*3+1]; var z = pos_array[i*3+2]; var p = [x-box.position.x, y-box.position.y, z-box.position.z, 1]; var tp = matmul(trans, p, 4); if (!point_indices){ // if indices is provided by caller, don't filter if ((Math.abs(tp[0]) > box.scale.x/2 * scale_ratio+0.01) || (Math.abs(tp[1]) > box.scale.y/2 * scale_ratio+0.01) || (Math.abs(tp[2]) > box.scale.z/2 *scale_ratio+0.01) ){ return; } indices.push(i); } relative_position.push([tp[0],tp[1],tp[2]]); relative_position_wo_rotation.push([p[0], p[1], p[2]]) }); //console.log("found indices: " + indices.length); return { index: indices, position: relative_position, position_wo_rotation: relative_position_wo_rotation, } }; this.findTop = function(box, init_scale_ratio){ var points = this.points; var pos_array = points.geometry.getAttribute("position").array; var trans = transpose(euler_angle_to_rotate_matrix(box.rotation, {x:0, y:0, z:0}), 4); var cand_point_indices = this.get_covering_position_indices(points, box.position, box.scale, box.rotation, init_scale_ratio); // all cand points are translated into box coordinates let translated_cand_points = cand_point_indices.map(function(i){ let x = pos_array[i*3]; let y = pos_array[i*3+1]; let z = pos_array[i*3+2]; let p = [x-box.position.x, y-box.position.y, z-box.position.z, 1]; let tp = matmul(trans, p, 4); return tp; }); let maxZ = -1000; translated_cand_points.forEach((tp, i)=>{ if (Math.abs(tp[0]) < box.scale.x * init_scale_ratio.x/2 && Math.abs(tp[1]) < box.scale.y * init_scale_ratio.y/2 && Math.abs(tp[2]) < box.scale.z * init_scale_ratio.z/2) { if (tp[2] > maxZ) maxZ = tp[2]; } }); return maxZ; } // find bottom and top points, in range of init_scale_ratio this.findBottom = function(box, init_scale_ratio){ var points = this.points; var pos_array = points.geometry.getAttribute("position").array; var trans = transpose(euler_angle_to_rotate_matrix(box.rotation, {x:0, y:0, z:0}), 4); var cand_point_indices = this.get_covering_position_indices(points, box.position, box.scale, box.rotation, init_scale_ratio); // all cand points are translated into box coordinates let translated_cand_points = cand_point_indices.map(function(i){ let x = pos_array[i*3]; let y = pos_array[i*3+1]; let z = pos_array[i*3+2]; let p = [x-box.position.x, y-box.position.y, z-box.position.z, 1]; let tp = matmul(trans, p, 4); return tp; }); let minZ = 1000; translated_cand_points.forEach((tp, i)=>{ if (Math.abs(tp[0]) < box.scale.x * init_scale_ratio.x/2 && Math.abs(tp[1]) < box.scale.y * init_scale_ratio.y/2 && Math.abs(tp[2]) < box.scale.z * init_scale_ratio.z/2) { if (tp[2] < minZ) minZ = tp[2]; } }); return minZ; }; this.grow_box = function(box, min_distance, init_scale_ratio){ console.log("grow box, min_distance", min_distance, box.scale, init_scale_ratio); let start_time = new Date().getTime(); var points = this.points; var pos_array = points.geometry.getAttribute("position").array; var trans = transpose(euler_angle_to_rotate_matrix(box.rotation, {x:0, y:0, z:0}), 4); var cand_point_indices = this.get_covering_position_indices(points, box.position, box.scale, box.rotation, init_scale_ratio); //todo: different definition. let groundLevel = 0.3; if (this.data.cfg.enableDynamicGroundLevel) { groundLevel = Math.min(box.scale.z/3, Math.max(0.2, box.scale.x/10, box.scale.y/10)); console.log('ground level', groundLevel, box.scale); } // all cand points are translated into box coordinates let translated_cand_points = cand_point_indices.map(function(i){ let x = pos_array[i*3]; let y = pos_array[i*3+1]; let z = pos_array[i*3+2]; let p = [x-box.position.x, y-box.position.y, z-box.position.z, 1]; let tp = matmul(trans, p, 4); return tp; }); let extreme= { max: { x:-100000, y:-100000, z:-100000, }, min: { x:1000000, y:1000000, z:1000000, }, }; let inside_points = 0; translated_cand_points.forEach((tp, i)=>{ if ((Math.abs(tp[0]) > box.scale.x/2+0.01) || (Math.abs(tp[1]) > box.scale.y/2+0.01) || (Math.abs(tp[2]) > box.scale.z/2+0.01) ){ return; } else{ if ((box.scale.z < 0.6) || ((box.scale.z > 0.6) && (tp[2] > -box.scale.z/2 + groundLevel))) { inside_points += 1; if (tp[0] > extreme.max.x) { extreme.max.x = tp[0]; } if (tp[0] < extreme.min.x){ extreme.min.x = tp[0]; } if (tp[1] > extreme.max.y){ extreme.max.y = tp[1]; } if (tp[1] < extreme.min.y){ extreme.min.y = tp[1]; } } if (tp[2] > extreme.max.z){ extreme.max.z = tp[2]; } if (tp[2] < extreme.min.z){ extreme.min.z = tp[2]; } } }); if (inside_points < 10) //too few points, give up. { return { max:{ x: box.scale.x/2, y: box.scale.y/2, z: box.scale.z/2, }, min:{ x: -box.scale.x/2, y: -box.scale.y/2, z: -box.scale.z/2, } }; } //let translated_cand_points_with_ground = translated_cand_points; // filter ground points // translated_cand_points = translated_cand_points.filter(function(tp, i){ // return tp[2] > -box.scale.z/2 + groundLevel; // }); let extreme_adjusted = true; let loop_count = 0; while (extreme_adjusted){ loop_count++; if (loop_count > 100000) { console.log("deep loops in grow_box"); break; } extreme_adjusted = false; // x+ let find_point = translated_cand_points.find(tp=>{ return tp[0] > extreme.max.x && tp[0] < extreme.max.x + min_distance/2 && tp[1] < extreme.max.y && tp[1] > extreme.min.y && tp[2] < extreme.max.z && tp[2] > extreme.min.z + groundLevel; }); if (find_point){ extreme.max.x += min_distance/2; extreme_adjusted = true; } // x - find_point = translated_cand_points.find(tp=>{ return tp[0] < extreme.min.x && tp[0] > extreme.min.x - min_distance/2 && tp[1] < extreme.max.y && tp[1] > extreme.min.y && tp[2] < extreme.max.z && tp[2] > extreme.min.z + groundLevel; }); if (find_point){ extreme.min.x -= min_distance/2; extreme_adjusted = true; } // y+ find_point = translated_cand_points.find(tp=>{ return tp[1] > extreme.max.y && tp[1] < extreme.max.y + min_distance/2 && tp[0] < extreme.max.x && tp[0] > extreme.min.x && tp[2] < extreme.max.z && tp[2] > extreme.min.z + groundLevel; }); if (find_point){ extreme.max.y += min_distance/2; extreme_adjusted = true; } // y - find_point = translated_cand_points.find(tp=>{ return tp[1] < extreme.min.y && tp[1] > extreme.min.y - min_distance/2 && tp[0] < extreme.max.x && tp[0] > extreme.min.x && tp[2] < extreme.max.z && tp[2] > extreme.min.z + groundLevel; }); if (find_point){ extreme.min.y -= min_distance/2; extreme_adjusted = true; } // z+ find_point = translated_cand_points.find(tp=>{ return tp[0] < extreme.max.x && tp[0] > extreme.min.x && tp[1] < extreme.max.y && tp[1] > extreme.min.y && tp[2] > extreme.max.z && tp[2] < extreme.max.z + min_distance/2; }); if (find_point){ extreme.max.z += min_distance/2; extreme_adjusted = true; } // z- find_point = translated_cand_points.find(tp=>{ return tp[0] < extreme.max.x && tp[0] > extreme.min.x && tp[1] < extreme.max.y && tp[1] > extreme.min.y && tp[2] < extreme.min.z && tp[2] > extreme.min.z - min_distance/2; }); if (find_point){ extreme.min.z -= min_distance/2; extreme_adjusted = true; } } // refine extreme values //1 set initial value let refined_extreme= { max: { x: extreme.max.x - min_distance/2, y: extreme.max.y - min_distance/2, z: extreme.max.z - min_distance/2, }, min: { x: extreme.min.x + min_distance/2, y: extreme.min.y + min_distance/2, z: extreme.min.z + min_distance/2, }, }; //2 find refined values. translated_cand_points.forEach(tp=>{ if (tp[0] > extreme.max.x || tp[0] < extreme.min.x || tp[1] > extreme.max.y || tp[1] < extreme.min.y || tp[2] > extreme.max.z || tp[2] < extreme.min.z) { } else{ if (tp[0] > refined_extreme.max.x && tp[2] > extreme.min.z + groundLevel) { refined_extreme.max.x = tp[0]; } if (tp[0] < refined_extreme.min.x && tp[2] > extreme.min.z + groundLevel){ refined_extreme.min.x = tp[0]; } if (tp[1] > refined_extreme.max.y && tp[2] > extreme.min.z + groundLevel){ refined_extreme.max.y = tp[1]; } if (tp[1] < refined_extreme.min.y && tp[2] > extreme.min.z + groundLevel){ refined_extreme.min.y = tp[1]; } if (tp[2] > refined_extreme.max.z){ refined_extreme.max.z = tp[2]; } if (tp[2] < refined_extreme.min.z){ refined_extreme.min.z = tp[2]; } } }); refined_extreme.min.z -= groundLevel; console.log("refined extreme", JSON.stringify(refined_extreme)); return refined_extreme; } this.get_box_points_number=function(box){ var indices = this._get_points_index_of_box(this.points, box, 1.0); return indices.length; }; this.reset_box_points_color = function(box){ let color = this.points.geometry.getAttribute("color").array; let indices = this._get_points_index_of_box(this.points, box, 1.0); if (this.data.cfg.color_points=="intensity") { indices.forEach((i)=>{ let intensity = this.pcd.intensity[i]; intensity *= 8; if (intensity > 1) intensity = 1.0; color[i*3] = intensity; color[i*3+1] = intensity; color[i*3+2] = 1 - intensity; }); } else { indices.forEach((i)=>{ color[i*3] = this.data.cfg.point_brightness; color[i*3+1] = this.data.cfg.point_brightness; color[i*3+2] = this.data.cfg.point_brightness; }); } }; this.set_box_points_color=function(box, target_color){ //var pos = this.points.geometry.getAttribute("position"); var color = this.points.geometry.getAttribute("color"); if (!target_color){ if (this.data.cfg.color_obj == "category") { target_color = globalObjectCategory.get_color_by_category(box.obj_type); } else if (this.data.cfg.color_obj == "id")// by id { let idx = (box.obj_track_id)?parseInt(box.obj_track_id): box.obj_local_id; target_color = globalObjectCategory.get_color_by_id(idx); } else // no color { } } if (target_color) { var indices = this._get_points_index_of_box(this.points, box, 1.0); indices.forEach(function(i){ color.array[i*3] = target_color.x; color.array[i*3+1] = target_color.y; color.array[i*3+2] = target_color.z; }); } }; this.set_spec_points_color=function(point_indices, target_color){ //var pos = this.points.geometry.getAttribute("position"); var color = this.points.geometry.getAttribute("color"); point_indices.forEach(function(i){ color.array[i*3] = target_color.x; color.array[i*3+1] = target_color.y; color.array[i*3+2] = target_color.z; }); }; // this is used when pointbrightness is updated. this.recolor_all_points = function(){ this.set_points_color({ x: this.data.cfg.point_brightness, y: this.data.cfg.point_brightness, z: this.data.cfg.point_brightness, }); this.color_points(); this.update_points_color(); }; // set all points to specified color this.set_points_color=function(target_color){ var color = this.points.geometry.getAttribute("color"); for (var i = 0; i= x) && (p.x <= x+w) && (p.y>=y) && (p.y<=y+h) && (p.z>0)){ indices.push(i); points.push([pos_array[i*3], pos_array[i*3+1], pos_array[i*3+2]]); } } console.log("select rect points", indices.length); //this.set_spec_points_color(indices, {x:1,y:0,z:0}); //this.update_points_color(); return points; }; this.get_centroid = function(point_indices){ let points = this.points; let pos_array = points.geometry.getAttribute("position").array; let center ={ x:0,y:0,z:0 }; point_indices.forEach(i=>{ center.x += pos_array[i*3]; center.y += pos_array[i*3+1]; center.z += pos_array[i*3+2]; }); center.x /= point_indices.length; center.y /= point_indices.length; center.z /= point_indices.length; return center; }; this.create_box_by_points = function(point_indices, camera){ let indices = point_indices; let points = this.points; let pos_array = points.geometry.getAttribute("position").array; // todo: copied the following code from next function. refactor it! console.log("select rect points", indices.length); //compute center, no need to tranform to box coordinates, and can't do it in this stage. /* var extreme = array_as_vector_index_range(pos_array, 3, indices); var center = { x: (extreme.max[0]+extreme.min[0])/2, y: (extreme.max[1]+extreme.min[1])/2, z: (extreme.max[2]+extreme.min[2])/2, }; */ var rotation_z = camera.rotation.z + Math.PI/2; var trans = transpose(euler_angle_to_rotate_matrix({x:0,y:0,z:rotation_z}, {x:0, y:0, z:0}), 4); let center ={ x:0,y:0,z:0 }; point_indices.forEach(i=>{ center.x += pos_array[i*3]; center.y += pos_array[i*3+1]; center.z += pos_array[i*3+2]; }); center.x /= point_indices.length; center.y /= point_indices.length; center.z /= point_indices.length; center.z = 0; var relative_position = []; indices.forEach(function(i){ //for (var i = 0; i < pos.count; i++){ var x = pos_array[i*3]; var y = pos_array[i*3+1]; var z = pos_array[i*3+2]; var p = [x-center.x, y-center.y, z-center.z, 1]; var tp = matmul(trans, p, 4); relative_position.push([tp[0],tp[1],tp[2]]); }); var relative_extreme = vector_range(relative_position); var scale = { x: relative_extreme.max[0] - relative_extreme.min[0], y: relative_extreme.max[1] - relative_extreme.min[1], z: relative_extreme.max[2] - relative_extreme.min[2], }; // enlarge scale a little // adjust center this.world.annotation.translate_box_position(center, rotation_z, "x", relative_extreme.min[0] + scale.x/2); this.world.annotation.translate_box_position(center, rotation_z, "y", relative_extreme.min[1] + scale.y/2); this.world.annotation.translate_box_position(center, rotation_z, "z", relative_extreme.min[2] + scale.z/2); scale.x += 0.02; scale.y += 0.02; scale.z += 0.02; return this.world.annotation.add_box(center, scale, {x:0,y:0,z:rotation_z}, "Unknown", ""); }; } export{Lidar}