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.

2683 lines
87 KiB
JavaScript

import * as THREE from './lib/three.module.js';
import {ViewManager} from "./view.js";
import {FastToolBox, FloatLabelManager} from "./floatlabel.js";
import {Mouse} from "./mouse.js";
import {BoxEditor, BoxEditorManager} from "./box_editor.js";
import {ImageContextManager} from "./image.js";
import {globalObjectCategory} from "./obj_cfg.js";
import {objIdManager} from "./obj_id_list.js";
import {Header} from "./header.js";
import {BoxOp} from './box_op.js';
import {AutoAdjust} from "./auto-adjust.js";
import {PlayControl} from "./play.js";
import {reloadWorldList, saveWorldList} from "./save.js";
import {logger, create_logger} from "./log.js";
import {autoAnnotate} from "./auto_annotate.js";
import {Calib} from "./calib.js";
import {Trajectory} from "./trajectory.js";
import { ContextMenu } from './context_menu.js';
import { InfoBox } from './info_box.js';
import {CropScene} from './crop_scene.js';
import { ConfigUi } from './config_ui.js';
import { MovableView } from './popup_dialog.js';
import {globalKeyDownManager} from './keydown_manager.js';
import {vector_range} from "./util.js"
import { checkScene } from './error_check.js';
function Editor(editorUi, wrapperUi, editorCfg, data, name="editor"){
// create logger before anything else.
create_logger(editorUi.querySelector("#log-wrapper"), editorUi.querySelector("#log-button"));
this.logger = logger;
this.editorCfg = editorCfg;
this.sideview_enabled = true;
this.editorUi = editorUi;
this.wrapperUi = wrapperUi;
this.container = null;
this.name = name;
this.data = data;
this.scene = null;
this.renderer = null;
this.selected_box = null;
this.windowWidth = null;
this.windowHeight= null;
this.floatLabelManager = null;
this.operation_state = {
key_pressed : false,
box_navigate_index:0,
};
this.view_state = {
lock_obj_track_id : "",
lock_obj_in_highlight : false, // focus mode
autoLock: function(trackid, focus){
this.lock_obj_track_id = trackid;
this.lock_obj_in_highlight = focus;
}
};
this.calib = new Calib(this.data, this);
this.header = null;
this.imageContextManager = null;
this.boxOp = null;
this.boxEditorManager = null;
this.params={};
this.currentMainEditor = this; // who is on focus, this or batch-editor-manager?
this.init = function(editorUi) {
let self = this;
this.editorUi = editorUi;
this.playControl = new PlayControl(this.data);
this.configUi = new ConfigUi(editorUi.querySelector("#config-button"), editorUi.querySelector("#config-wrapper"), this);
this.header = new Header(editorUi.querySelector("#header"), this.data, this.editorCfg,
(e)=>{
this.scene_changed(e.currentTarget.value);
//event.currentTarget.blur();
},
(e)=>{this.frame_changed(e)},
(e)=>{this.object_changed(e)},
(e)=>{this.camera_changed(e)}
);
//
// that way, the operation speed may be better
// if we load all worlds, we can speed up batch-mode operations, but the singl-world operations slows down.
// if we use two seperate scenes. can we solve this problem?
//
this.scene = new THREE.Scene();
this.mainScene = this.scene; //new THREE.Scene();
this.data.set_webglScene(this.scene, this.mainScene);
this.renderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );
this.renderer.setPixelRatio( window.devicePixelRatio );
this.container = editorUi.querySelector("#container");
this.container.appendChild( this.renderer.domElement );
this.boxOp = new BoxOp(this.data);
this.viewManager = new ViewManager(this.container, this.scene, this.mainScene, this.renderer,
function(){self.render();},
function(box){self.on_box_changed(box)},
this.editorCfg);
this.imageContextManager = new ImageContextManager(
this.editorUi.querySelector("#content"),
this.editorUi.querySelector("#camera-selector"),
this.editorCfg,
(lidar_points)=>this.on_img_click(lidar_points));
if (!this.editorCfg.disableRangeCircle)
this.addRangeCircle();
this.floatLabelManager = new FloatLabelManager(this.editorUi, this.container, this.viewManager.mainView,function(box){self.selectBox(box);});
this.fastToolBox = new FastToolBox(this.editorUi.querySelector("#obj-editor"), (event)=>this.handleFastToolEvent(event));
//this.controlGui = this.init_gui();
this.axis = new THREE.AxesHelper(1);
this.scene.add(this.axis);
window.addEventListener( 'resize', function(){self.onWindowResize();}, false );
if (!this.editorCfg.disableMainViewKeyDown){
// this.container.onmouseenter = (event)=>{
// this.container.focus();
// };
// this.container.onmouseleave = (event)=>{
// this.container.blur();
// };
//this.container.addEventListener( 'keydown', function(e){self.keydown(e);} );
//this.editorUi.addEventListener( 'keydown', e=>this.keydown(e); );
this.keydownHandler = (event)=>this.keydown(event);
//this.keydownDisabled = false;
//document.removeEventListener('keydown', this.keydownHandler);
//document.addEventListener( 'keydown', this.keydownHandler);
globalKeyDownManager.register(this.keydownHandler, "main editor");
}
this.globalKeyDownManager = globalKeyDownManager;
this.objectTrackView = new Trajectory(
this.editorUi.querySelector("#object-track-wrapper")
);
this.infoBox = new InfoBox(
this.editorUi.querySelector("#info-wrapper")
);
this.cropScene = new CropScene(
this.editorUi.querySelector("#crop-scene-wrapper"),
this
);
this.contextMenu = new ContextMenu(this.editorUi.querySelector("#context-menu-wrapper"));
this.boxEditorManager = new BoxEditorManager(
document.querySelector("#batch-box-editor"),
this.viewManager,
this.objectTrackView,
this.editorCfg,
this.boxOp,
this.header,
this.contextMenu,
this.configUi,
(b)=>this.on_box_changed(b),
(b,r)=>this.remove_box(b,r), // on box remove
()=>{
// this.on_load_world_finished(this.data.world);
// this.imageContextManager.hide();
// this.floatLabelManager.hide();
// this.viewManager.mainView.disable();
// this.boxEditor.hide();
// this.hideGridLines();
// this.controlGui.hide();
}); //func_on_annotation_reloaded
this.boxEditorManager.hide();
let boxEditorUi = this.editorUi.querySelector("#main-box-editor-wrapper");
this.boxEditor= new BoxEditor(
boxEditorUi,
null, // no box editor manager
this.viewManager,
this.editorCfg,
this.boxOp,
(b)=>this.on_box_changed(b),
(b)=>this.remove_box(b),
"main-boxe-ditor");
this.boxEditor.detach(); // hide it
this.boxEditor.setResize("both");
this.boxEditor.moveHandle = new MovableView(
boxEditorUi.querySelector("#focuscanvas"),
boxEditorUi.querySelector("#sub-views"),
()=>{
this.boxEditor.update();
this.render();
}
);
this.mouse = new Mouse(
this.viewManager.mainView,
this.operation_state,
this.container,
this.editorUi,
function(ev){self.handleLeftClick(ev);},
function(ev){self.handleRightClick(ev);},
function(x,y,w,h,ctl,shift){self.handleSelectRect(x,y,w,h,ctl,shift);});
this.autoAdjust=new AutoAdjust(this.boxOp, this.mouse, this.header);
//this.projectiveViewOps.hide();
if (!this.editorCfg.disableGrid)
this.installGridLines()
window.onbeforeunload = function() {
return "Exit?";
//if we return nothing here (just calling return;) then there will be no pop-up question at all
//return;
};
this.onWindowResize();
};
this.run = function(){
//this.animate();
this.render();
//$( "#maincanvas" ).resizable();
this.imageContextManager.init_image_op(()=>this.selected_box);
this.add_global_obj_type();
};
this.hide = function(){
this.wrapperUi.style.display="none";
};
this.show = function(){
this.wrapperUi.style.display="block";
};
this.moveRangeCircle = function(world){
if (this.rangeCircle.parent){
world.webglGroup.add(this.rangeCircle);
}
};
this.addRangeCircle= function(){
var h = 1;
var body = [
];
var segments=64;
for (var i = 0; i<segments; i++){
var theta1 = (2*Math.PI/segments) * i;
var x1 = Math.cos(theta1);
var y1 = Math.sin(theta1);
var theta2 = 2*Math.PI/segments * ((i+1)%segments);
var x2 = Math.cos(theta2);
var y2 = Math.sin(theta2);
body.push(x1,y1,h,x2,y2,h);
body.push(0.6*x1,0.6*y1,h,0.6*x2,0.6*y2,h);
body.push(2.0*x1,2.0*y1,h,2.0*x2,2.0*y2,h);
}
this.data.dbg.alloc();
var bbox = new THREE.BufferGeometry();
bbox.setAttribute( 'position', new THREE.Float32BufferAttribute(body, 3 ) );
var box = new THREE.LineSegments( bbox,
new THREE.LineBasicMaterial( { color: 0x888800, linewidth: 1, opacity: 0.5, transparent: true } ) );
box.scale.x=50;
box.scale.y=50;
box.scale.z=-3;
box.position.x=0;
box.position.y=0;
box.position.z=0;
box.computeLineDistances();
this.rangeCircle = box;
this.scene.add(box);
};
this.showRangeCircle = function(show){
if (show){
if (this.data.world)
{
this.data.world.webglGroup.add(this.rangeCircle);
}
}
else
{
if (this.rangeCircle.parent)
this.rangeCircle.parent.remove(this.rangeCircle);
}
this.render();
};
this.hideGridLines = function(){
var svg = this.editorUi.querySelector("#grid-lines-wrapper");
svg.style.display="none";
};
this.showGridLines = function(){
var svg = this.editorUi.querySelector("#grid-lines-wrapper");
svg.style.display="";
};
this.installGridLines= function(){
var svg = this.editorUi.querySelector("#grid-lines-wrapper");
for (var i=1; i<10; i++){
const line = document. createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute("x1", "0%");
line.setAttribute("y1", String(i*10)+"%");
line.setAttribute("x2", "100%");
line.setAttribute("y2", String(i*10)+"%");
line.setAttribute("class", "grid-line");
svg.appendChild(line);
}
for (var i=1; i<10; i++){
const line = document. createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute("y1", "0%");
line.setAttribute("x1", String(i*10)+"%");
line.setAttribute("y2", "100%");
line.setAttribute("x2", String(i*10)+"%");
line.setAttribute("class", "grid-line");
svg.appendChild(line);
}
};
this.handleFastToolEvent= function(event){
let self = this;
switch (event.currentTarget.id){
case "label-del":
self.remove_selected_box();
self.header.updateModifiedStatus();
break;
case "label-gen-id":
//self.autoAdjust.mark_bbox(self.selected_box);
//event.currentTarget.blur();
let id = objIdManager.generateNewUniqueId();
self.fastToolBox.setValue(self.selected_box.obj_type, id, self.selected_box.obj_attr);
self.setObjectId(id);
break;
case "label-copy":
if (!this.selected_box.obj_track_id)
{
this.infoBox.show("Error", "Please assign object track ID.");
}
else
{
self.autoAdjust.mark_bbox(self.selected_box);
}
break;
case "label-paste":
//this.autoAdjust.smart_paste(self.selected_box, null, (b)=>this.on_box_changed(b));
this.boxOp.auto_rotate_xyz(this.selected_box, null, null,
(b)=>this.on_box_changed(b),
"noscaling");
//event.currentTarget.blur();
break;
case "label-batchedit":
{
if (!this.ensureBoxTrackIdExist())
break;
if (!this.ensurePreloaded())
break;
this.header.setObject(this.selected_box.obj_track_id);
this.editBatch(
this.data.world.frameInfo.scene,
this.data.world.frameInfo.frame,
this.selected_box.obj_track_id,
this.selected_box.obj_type
);
}
break;
case "label-trajectory":
this.showTrajectory();
break;
case "label-edit":
event.currentTarget.blur();
self.selectBox(self.selected_box);
break;
// case "label-reset":
// event.currentTarget.blur();
// if (self.selected_box){
// //switch_bbox_type(this.selected_box.obj_type);
// self.transform_bbox("reset");
// }
// break;
case "label-highlight":
event.currentTarget.blur();
if (self.selected_box.in_highlight){
self.cancelFocus(self.selected_box);
self.view_state.lock_obj_in_highlight = false
}
else {
self.focusOnSelectedBox(self.selected_box);
}
break;
case "label-rotate":
event.currentTarget.blur();
self.transform_bbox("z_rotate_reverse");
break;
case "object-category-selector":
this.object_category_changed(event);
break;
case "object-track-id-editor":
this.object_track_id_changed(event);
break;
case "attr-input":
this.object_attribute_changed(event.currentTarget.value);
break;
default:
this.handleContextMenuEvent(event);
break;
}
};
this.cancelFocus= function(box){
box.in_highlight = false;
//view_state.lock_obj_in_highlight = false; // when user unhighlight explicitly, set it to false
this.data.world.lidar.cancel_highlight(box);
this.floatLabelManager.restore_all();
this.viewManager.mainView.save_orbit_state(box.scale);
this.viewManager.mainView.orbit.reset();
};
this.focusOnSelectedBox = function(box){
if (this.editorCfg.disableMainView)
return;
if (box){
this.data.world.lidar.highlight_box_points(box);
this.floatLabelManager.hide_all();
this.viewManager.mainView.orbit.saveState();
//this.viewManager.mainView.camera.position.set(this.selected_box.position.x+this.selected_box.scale.x*3, this.selected_box.position.y+this.selected_box.scale.y*3, this.selected_box.position.z+this.selected_box.scale.z*3);
let posG = this.data.world.lidarPosToScene(box.position);
this.viewManager.mainView.orbit.target.x = posG.x;
this.viewManager.mainView.orbit.target.y = posG.y;
this.viewManager.mainView.orbit.target.z = posG.z;
this.viewManager.mainView.restore_relative_orbit_state(box.scale);
this.viewManager.mainView.orbit.update();
this.render();
box.in_highlight=true;
this.view_state.lock_obj_in_highlight = true;
}
};
this.showTrajectory = function(){
if (!this.selected_box)
return;
if (!this.selected_box.obj_track_id){
console.error("no track id");
return;
}
let tracks = this.data.worldList.map(w=>{
let box = w.annotation.findBoxByTrackId(this.selected_box.obj_track_id);
let ann = null;
if (box){
ann = w.annotation.boxToAnn(box);
ann.psr.position = w.lidarPosToUtm(ann.psr.position);
ann.psr.rotation = w.lidarRotToUtm(ann.psr.rotation);
}
return [w.frameInfo.frame, ann, w===this.data.world]
});
tracks.sort((a,b)=> (a[0] > b[0])? 1 : -1);
this.objectTrackView.setObject(
this.selected_box.obj_type,
this.selected_box.obj_track_id,
tracks,
(targetFrame)=>{ //onExit
this.load_world(this.data.world.frameInfo.scene, targetFrame);
}
);
}
// return true to close contextmenu
// return false to keep contextmenu
this.handleContextMenuEvent = function(event){
switch(event.currentTarget.id)
{
case "cm-play-2fps":
this.playControl.play((w)=>{this.on_load_world_finished(w)}, 2);
break;
case "cm-play-10fps":
this.playControl.play((w)=>{this.on_load_world_finished(w)}, 10);
break;
case "cm-play-20fps":
this.playControl.play((w)=>{this.on_load_world_finished(w)}, 20);
break;
case "cm-play-50fps":
this.playControl.play((w)=>{this.on_load_world_finished(w)}, 50);
break;
case 'cm-paste':
{
let box = this.add_box_on_mouse_pos_by_ref();
if (!event.shiftKey)
{
logger.log('paste without auto-adjusting');
this.boxOp.auto_rotate_xyz(box, null, null,
b=>this.on_box_changed(b),
"noscaling");
}
}
break;
case 'cm-prev-frame':
this.previous_frame();
break;
case 'cm-next-frame':
this.next_frame();
break;
case 'cm-last-frame':
this.last_frame();
break;
case 'cm-first-frame':
this.first_frame();
break;
case 'cm-go-to-10hz':
this.load_world(this.data.world.frameInfo.scene+"_10hz", this.data.world.frameInfo.frame)
// {
// let link = document.createElement("a");
// //link.download=`${this.data.world.frameInfo.scene}-${this.data.world.frameInfo.frame}-webgl`;
// link.href="http://localhost";
// link.target="_blank";
// link.click();
// }
break;
case 'cm-go-to-full-2hz':
this.load_world(this.data.world.frameInfo.scene+"_full_2hz", this.data.world.frameInfo.frame)
break;
case 'cm-go-to-2hz':
this.load_world(this.data.world.frameInfo.scene.split("_")[0], this.data.world.frameInfo.frame)
break;
case 'cm-save':
saveWorldList(this.data.worldList);
break;
case "cm-reload":
{
reloadWorldList([this.data.world], ()=>{
this.on_load_world_finished(this.data.world);
this.header.updateModifiedStatus();
});
}
break;
case "cm-reload-all":
{
let modifiedFrames = this.data.worldList.filter(w=>w.annotation.modified);
if (modifiedFrames.length > 0)
{
this.infoBox.show(
"Confirm",
`Discard changes to ${modifiedFrames.length} frames, continue to reload?`,
["yes","no"],
(choice)=>{
if (choice=="yes")
{
reloadWorldList(this.data.worldList, ()=>{
this.on_load_world_finished(this.data.world);
this.header.updateModifiedStatus();
});
}
}
);
}
else
{
reloadWorldList(this.data.worldList, ()=>{
this.on_load_world_finished(this.data.world);
this.header.updateModifiedStatus();
});
objIdManager.forceUpdate();
}
}
break;
case "cm-stop":
this.playControl.stop_play();
break;
case "cm-pause":
this.playControl.pause_resume_play();
break;
case "cm-prev-object":
this.select_previous_object();
break;
case "cm-next-object":
this.select_previous_object();
break;
case "cm-show-frame-info":
{
let info = {"scend-id": this.data.world.frameInfo.scene,
"frame": this.data.world.frameInfo.frame
};
if (this.data.world.frameInfo.sceneMeta.desc)
{
info = {
...info,
...this.data.world.frameInfo.sceneMeta.desc,
};
}
this.infoBox.show("Frame info - " + this.data.world.frameInfo.scene, JSON.stringify(info,null,"<br>"));
}
break;
case "cm-show-stat":
{
let scene = this.data.world.frameInfo.scene;
objIdManager.load_obj_ids_of_scene(scene, (objs)=>{
let info = {
objects: objs.length,
boxes: objs.reduce((a,b)=>a+b.count, 0),
frames: this.data.world.frameInfo.sceneMeta.frames.length,
};
this.infoBox.show("Stat - " + scene, JSON.stringify(info, null,"<br>"));
});
}
break;
/// object
case 'cm-check-scene':
{
let scene = this.data.world.frameInfo.scene;
checkScene(scene);
logger.show();
logger.errorBtn.onclick();
}
break;
case "cm-reset-view":
this.resetView();
break;
case "cm-delete":
this.remove_selected_box();
this.header.updateModifiedStatus();
break;
case "cm-edit-multiple-instances":
this.enterBatchEditMode();
break;
case "cm-auto-ann-background":
{
this.autoAnnInBackground();
}
break;
case "cm-interpolate-background":
{
this.interpolateInBackground();
}
break;
case "cm-show-trajectory":
this.showTrajectory();
break;
case "cm-select-as-ref":
if (!this.selected_box.obj_track_id)
{
this.infoBox.show("Error", "Please assign object track ID.");
return false;
}
else
{
this.autoAdjust.mark_bbox(this.selected_box);
}
break;
case "cm-change-id-to-ref":
if (!this.ensureRefObjExist())
break;
this.setObjectId(this.autoAdjust.marked_object.ann.obj_id);
this.fastToolBox.setValue(this.selected_box.obj_type,
this.selected_box.obj_track_id,
this.selected_box.obj_attr);
break;
case "cm-change-id-to-ref-in-scene":
if (!this.ensureBoxTrackIdExist())
break;
if (!this.ensurePreloaded())
break;
if (!this.ensureRefObjExist())
break;
this.data.worldList.forEach(w=>{
let box = w.annotation.boxes.find(b=>b.obj_track_id === this.selected_box.obj_track_id && b.obj_type === this.selected_box.obj_type);
if (box && box !== this.selected_box){
box.obj_track_id = this.autoAdjust.marked_object.ann.obj_id;
w.annotation.setModified();
}
});
this.setObjectId(this.autoAdjust.marked_object.ann.obj_id);
this.fastToolBox.setValue(this.selected_box.obj_type,
this.selected_box.obj_track_id,
this.selected_box.obj_attr);
break;
case "cm-follow-ref":
if (!this.ensureBoxTrackIdExist())
break;
if (!this.ensurePreloaded())
break;
this.autoAdjust.followsRef(this.selected_box);
this.header.updateModifiedStatus();
this.editBatch(
this.data.world.frameInfo.scene,
this.data.world.frameInfo.frame,
this.selected_box.obj_track_id,
this.selected_box.obj_type
);
break;
case 'cm-follow-static-objects':
if (!this.ensureBoxTrackIdExist())
break;
if (!this.ensurePreloaded())
break;
this.autoAdjust.followStaticObjects(this.selected_box);
this.header.updateModifiedStatus();
this.editBatch(
this.data.world.frameInfo.scene,
this.data.world.frameInfo.frame,
this.selected_box.obj_track_id,
this.selected_box.obj_type
);
break;
case "cm-sync-followers":
if (!this.ensurePreloaded())
break;
this.autoAdjust.syncFollowers(this.selected_box);
this.header.updateModifiedStatus();
this.render();
break;
case "cm-delete-obj":
{
//let saveList=[];
this.data.worldList.forEach(w=>{
let box = w.annotation.boxes.find(b=>b.obj_track_id === this.selected_box.obj_track_id);
if (box && box !== this.selected_box){
w.annotation.unload_box(box);
w.annotation.remove_box(box);
//saveList.push(w);
w.annotation.setModified();
}
});
//saveWorldList(saveList);
this.remove_selected_box();
this.header.updateModifiedStatus();
}
break;
case "cm-modify-obj-type":
{
if (!this.ensurePreloaded())
break;
//let saveList=[];
this.data.worldList.forEach(w=>{
let box = w.annotation.boxes.find(b=>b.obj_track_id === this.selected_box.obj_track_id);
if (box && box !== this.selected_box){
box.obj_type = this.selected_box.obj_type;
box.obj_attr = this.selected_box.obj_attr;
//saveList.push(w);
w.annotation.setModified();
}
});
//saveWorldList(saveList);
this.header.updateModifiedStatus();
}
break;
case "cm-modify-obj-size":
{
if (!this.ensurePreloaded())
break;
//let saveList=[];
this.data.worldList.forEach(w=>{
let box = w.annotation.boxes.find(b=>b.obj_track_id == this.selected_box.obj_track_id);
if (box && box !== this.selected_box){
box.scale.x = this.selected_box.scale.x;
box.scale.y = this.selected_box.scale.y;
box.scale.z = this.selected_box.scale.z;
//saveList.push(w);
w.annotation.setModified();
}
});
//saveWorldList(saveList);
this.header.updateModifiedStatus();
}
break;
default:
console.log('unhandled', event.currentTarget.id, event.type);
}
return true;
};
// this.animate= function() {
// let self=this;
// requestAnimationFrame( function(){self.animate();} );
// this.viewManager.mainView.orbit_orth.update();
// };
this.render= function(){
this.viewManager.mainView.render();
this.boxEditor.boxView.render();
this.floatLabelManager.update_all_position();
if (this.selected_box){
this.fastToolBox.setPos(this.floatLabelManager.getLabelEditorPos(this.selected_box.obj_local_id));
}
};
this.resetView = function(targetPos){
if (!targetPos){
let center = this.data.world.lidar.computeCenter();
targetPos = {...center};//{x:0, y:0, z:50};
targetPos.z += 50;
}
else
targetPos.z = 50;
let pos = this.data.world.lidarPosToScene(targetPos);
this.viewManager.mainView.orbit.object.position.set(pos.x, pos.y, pos.z); //object is camera
this.viewManager.mainView.orbit.target.set(pos.x, pos.y, 0);
this.viewManager.mainView.orbit.update();
this.render();
};
this.scene_changed= async function(sceneName){
//var sceneName = event.currentTarget.value;
if (sceneName.length == 0){
return;
}
console.log("choose sceneName " + sceneName);
var meta = this.data.getMetaBySceneName(sceneName);
if (!meta)
{
this.editorUi.querySelector("#frame-selector").innerHTML = "<option>--frame--</option>";
meta = await this.data.readSceneMetaData(sceneName);
}
var frame_selector_str = meta.frames.map(function(f){
return "<option value="+f+">"+f + "</option>";
}).reduce(function(x,y){return x+y;}, "<option>--frame--</option>");
this.editorUi.querySelector("#frame-selector").innerHTML = frame_selector_str;
if (meta.camera){
this.imageContextManager.updateCameraList(meta.camera);
}
//load_obj_ids_of_scene(sceneName);
};
this.frame_changed= function(event){
var sceneName = this.editorUi.querySelector("#scene-selector").value;
if (sceneName.length == 0 && this.data.world)
{
sceneName = this.data.world.frameInfo.scene;
}
if (sceneName.length == 0){
return;
}
var frame = event.currentTarget.value;
console.log(sceneName, frame);
this.load_world(sceneName, frame);
event.currentTarget.blur();
};
this.ensureBoxTrackIdExist = function()
{
if (!this.selected_box.obj_track_id)
{
this.infoBox.show("Error", "Please assign object track ID.");
return false;
}
return true;
}
this.ensureRefObjExist = function()
{
if (!this.autoAdjust.marked_object)
{
this.infoBox.show("Notice", 'No reference object was selected');
return false;
}
return true;
}
this.ensurePreloaded = function()
{
let worldList = this.data.worldList.filter(w=>w.frameInfo.scene == this.data.world.frameInfo.scene);
worldList = worldList.sort((a,b)=>a.frameInfo.frame_index - b.frameInfo.frame_index);
let meta = this.data.get_current_world_scene_meta();
let allLoaded = worldList.map(w=>w.preloaded()).reduce((a,b)=>a && b, true);
if ((worldList.length < meta.frames.length && worldList.length <= 60) || (!allLoaded))
{
this.data.forcePreloadScene(this.data.world.frameInfo.scene, this.data.world);
this.infoBox.show("Notice",
`Loading scene in background. Please try again later.`);
return false;
}
return true;
}
this.interpolateInBackground = function()
{
if (!this.ensureBoxTrackIdExist())
return;
if (!this.ensurePreloaded())
return;
let worldList = this.data.worldList.filter(w=>w.frameInfo.scene == this.data.world.frameInfo.scene);
worldList = worldList.sort((a,b)=>a.frameInfo.frame_index - b.frameInfo.frame_index);
let boxList = worldList.map(w=>w.annotation.findBoxByTrackId(this.selected_box.obj_track_id));
let applyIndList = boxList.map(b=>true);
this.boxOp.interpolateAsync(worldList, boxList, applyIndList).then(ret=>{
this.header.updateModifiedStatus();
this.viewManager.render();
});
};
this.enterBatchEditMode = function()
{
if (!this.ensureBoxTrackIdExist())
return;
if (!this.ensurePreloaded())
return;
this.header.setObject(this.selected_box.obj_track_id);
this.editBatch(
this.data.world.frameInfo.scene,
this.data.world.frameInfo.frame,
this.selected_box.obj_track_id,
this.selected_box.obj_type
);
};
this.autoAnnInBackground = function()
{
if (!this.ensureBoxTrackIdExist())
return;
if (!this.ensurePreloaded())
return;
let worldList = this.data.worldList.filter(w=>w.frameInfo.scene == this.data.world.frameInfo.scene);
worldList = worldList.sort((a,b)=>a.frameInfo.frame_index - b.frameInfo.frame_index);
let boxList = worldList.map(w=>w.annotation.findBoxByTrackId(this.selected_box.obj_track_id));
let onFinishOneBox = (i)=>{
this.viewManager.render();
}
let applyIndList = boxList.map(b=>true);
let dontRotate = false;
this.boxOp.interpolateAndAutoAdjustAsync(worldList, boxList, onFinishOneBox, applyIndList, dontRotate).then(ret=>{
this.header.updateModifiedStatus();
});
};
this.editBatch = function(sceneName, frame, objectTrackId, objectType){
//this.keydownDisabled = true;
// hide something
this.imageContextManager.hide();
this.floatLabelManager.hide();
//this.floatLabelManager.showFastToolbox();
this.viewManager.mainView.disable();
this.boxEditor.hide();
this.hideGridLines();
//this.controlGui.hide();
this.editorUi.querySelector("#selectors").style.display='none';
//this.editorUi.querySelector("#object-selector").style.display='none';
this.currentMainEditor = this.boxEditorManager;
this.boxEditorManager.edit(this.data,
this.data.getMetaBySceneName(sceneName),
frame,
objectTrackId,
objectType,
(targetFrame, targetTrackId)=>{ //on exit
this.currentMainEditor = this
//this.keydownDisabled = false;
this.viewManager.mainView.enable();
this.imageContextManager.show();
this.floatLabelManager.show();
if (targetTrackId)
this.view_state.lock_obj_track_id = targetTrackId;
this.on_load_world_finished(this.data.world);
// if (this.selected_box){
// // attach again, restore box.boxEditor
// // obj type/id may have changed in batch mode
// this.floatLabelManager.set_object_track_id(this.selected_box.obj_local_id, this.selected_box.obj_track_id);
// this.boxEditor.attachBox(this.selected_box);
// this.boxEditor.update();
// // update fasttoolbox
// this.fastToolBox.setValue(this.selected_box.obj_type, this.selected_box.obj_track_id, this.selected_box.obj_attr);
// }
this.showGridLines();
this.render();
//this.controlGui.show();
this.editorUi.querySelector("#selectors").style.display='inherit';
if (targetFrame)
{
this.load_world(this.data.world.frameInfo.scene, targetFrame, ()=>{ // onfinished
this.makeVisible(targetTrackId);
});
}
}
);
};
this.gotoObjectFrame = function(frame, objId)
{
this.load_world(this.data.world.frameInfo.scene, frame, ()=>{ // onfinished
this.makeVisible(objId);
});
};
this.makeVisible = function(targetTrackId){
let box = this.data.world.annotation.findBoxByTrackId(targetTrackId);
if (box){
if (this.selected_box != box){
this.selectBox(box);
}
this.resetView({x:box.position.x, y:box.position.y, z:50});
}
};
this.object_changed = function(event){
var sceneName = this.data.world.frameInfo.scene; //this.editorUi.querySelector("#scene-selector").value;
let objectTrackId = event.currentTarget.value;
let obj = objIdManager.getObjById(objectTrackId);
this.editBatch(sceneName, null, objectTrackId, obj.category);
};
this.camera_changed= function(event){
var camera_name = event.currentTarget.value;
this.data.set_active_image(camera_name);
this.imageContextManager.render_2d_image();
event.currentTarget.blur();
};
this.downloadWebglScreenShot = function(){
let link = document.createElement("a");
link.download=`${this.data.world.frameInfo.scene}-${this.data.world.frameInfo.frame}-webgl`;
link.href=this.renderer.domElement.toDataURL("image/png", 1);
link.click();
};
this.showLog = function() {
};
this.annotateByAlg1 = function(){
autoAnnotate(this.data.world, ()=>this.on_load_world_finished(this.data.world));
};
this.object_category_changed= function(event){
if (this.selected_box){
let category = event.currentTarget.value;
this.selected_box.obj_type = category;
this.floatLabelManager.set_object_type(this.selected_box.obj_local_id, this.selected_box.obj_type);
// this.header.mark_changed_flag();
// this.updateBoxPointsColor(this.selected_box);
// this.imageContextManager.boxes_manager.update_obj_type(this.selected_box.obj_local_id, this.selected_box.obj_type);
// this.render();
this.on_box_changed(this.selected_box);
//todo: we don't know if the old one is already deleted.
// could use object count number?
objIdManager.addObject({
category: this.selected_box.obj_type,
id: this.selected_box.obj_track_id,
});
}
};
this.setObjectId = function(id)
{
this.selected_box.obj_track_id = id;
this.floatLabelManager.set_object_track_id(this.selected_box.obj_local_id, this.selected_box.obj_track_id);
this.view_state.lock_obj_track_id = id;
//this.header.mark_changed_flag();
this.on_box_changed(this.selected_box);
//
objIdManager.addObject({
category: this.selected_box.obj_type,
id: this.selected_box.obj_track_id,
});
}
this.object_track_id_changed= function(event){
if (this.selected_box){
var id = event.currentTarget.value;
this.setObjectId(id);
}
};
this.object_attribute_changed = function(value){
if (this.selected_box){
this.selected_box.obj_attr = value;
this.floatLabelManager.set_object_attr(this.selected_box.obj_local_id, value);
this.data.world.annotation.setModified();
this.header.updateModifiedStatus();
}
};
// this.updateSubviewRangeByWindowResize= function(box){
// if (box === null)
// return;
// if (box.boxEditor)
// box.boxEditor.onWindowResize();
// this.render();
// };
this.handleRightClick= function(event){
// select new object
if (!this.data.world){
return;
}
if (event.shiftKey || event.ctrlKey)
{
// if ctrl or shift hold, don't select any object.
this.contextMenu.show("world",event.layerX, event.layerY, this);
return;
}
var intersects = this.mouse.getIntersects( this.mouse.onUpPosition, this.data.world.annotation.boxes );
if ( intersects.length > 0 ) {
//var object = intersects[ 0 ].object;
var object = intersects[ 0 ].object;
let target_obj = object.userData.object;
if ( target_obj == undefined ) {
// helper
target_obj = object;
}
if (target_obj != this.selected_box){
this.selectBox(target_obj);
}
// this.hide_world_context_menu();
// this.show_object_context_menu(event.layerX, event.layerY);
this.contextMenu.show("object",event.layerX, event.layerY, this);
} else {
// if no object is selected, popup context menu
//var pos = getMousePosition(renderer.domElement, event.clientX, event.clientY );
this.contextMenu.show("world",event.layerX, event.layerY, this);
}
};
this.show_world_context_menu= function(posX, posY){
let menu = this.editorUi.querySelector("#context-menu");
menu.style.display = "inherit";
menu.style.left = posX+"px";
menu.style.top = posY+"px";
this.editorUi.querySelector("#context-menu-wrapper").style.display = "block";
};
this.hide_world_context_menu= function(){
let menu = this.editorUi.querySelector("#context-menu");
menu.style.display = "none";
};
this.show_object_context_menu= function(posX, posY){
let menu = this.editorUi.querySelector("#object-context-menu");
menu.style.display = "inherit";
menu.style.left = posX+"px";
menu.style.top = posY+"px";
this.editorUi.querySelector("#context-menu-wrapper").style.display = "block";
};
this.hide_object_context_menu= function(){
let menu = this.editorUi.querySelector("#object-context-menu");
menu.style.display = "none";
};
this.on_img_click = function(lidar_point_indices){
console.log(lidar_point_indices);
var self=this;
let obj_type = "Car";
this.data.world.lidar.set_spec_points_color(lidar_point_indices, {x:0,y:0,z:1});
this.data.world.lidar.update_points_color();
this.render();
//return;
let pos = this.data.world.lidar.get_centroid(lidar_point_indices);
pos.z = 0;
let rotation = {x:0, y:0, z:this.viewManager.mainView.camera.rotation.z+Math.PI/2};
let obj_cfg = globalObjectCategory.get_obj_cfg_by_type(obj_type);
let scale = {
x: obj_cfg.size[0],
y: obj_cfg.size[1],
z: obj_cfg.size[2]
};
let box = this.add_box(pos, scale, rotation, obj_type, "");
self.boxOp.auto_rotate_xyz(box, null, null, function(b){
self.on_box_changed(b);
});
return;
/*
var box = this.data.world.lidar.create_box_by_points(lidar_point_indices, this.viewManager.mainView.camera);
this.scene.add(box);
this.imageContextManager.boxes_manager.add_box(box);
this.boxOp.auto_shrink_box(box);
// guess obj type here
box.obj_type = guess_obj_type_by_dimension(box.scale);
this.floatLabelManager.add_label(box);
this.selectBox(box);
this.on_box_changed(box);
this.boxOp.auto_rotate_xyz(box, function(){
box.obj_type = guess_obj_type_by_dimension(box.scale);
self.floatLabelManager.set_object_type(box.obj_local_id, box.obj_type);
self.floatLabelManager.update_label_editor(box.obj_type, box.obj_track_id);
self.on_box_changed(box);
});
*/
};
this.handleSelectRect= function(x,y,w,h, ctrl, shift){
// y = y+h;
// x = x*2-1;
// y = -y*2+1;
// w *= 2;
// h *= 2;
// x,y: start cornor, w: width, h: height
/*
console.log("main select rect", x,y,w,h);
this.viewManager.mainView.camera.updateProjectionMatrix();
this.data.world.select_points_by_view_rect(x,y,w,h, this.viewManager.mainView.camera);
render();
render_2d_image();
*/
// check if any box is inside the rectangle
this.viewManager.mainView.camera.updateProjectionMatrix();
let boxes = this.data.world.annotation.find_boxes_inside_rect(x,y,w,h, this.viewManager.mainView.camera);
if (boxes.length > 0) {
if (boxes.length == 1){
this.selectBox(boxes[0])
}
else{
// this is dangerous
// for (let b in boxes){
// this.remove_box(boxes[b],false)
// }
// this.render();
}
return;
}
let points = this.data.world.lidar.select_points_by_view_rect(x,y,w,h, this.viewManager.mainView.camera);
// show color
//this.render();
// return;
// // create new box
// var self=this;
var center_pos = this.mouse.get_screen_location_in_world(x+w/2, y+h/2);
center_pos = this.data.world.scenePosToLidar(center_pos);
let initRoationZ = this.viewManager.mainView.camera.rotation.z + Math.PI/2;
let box = this.create_box_by_points(points, initRoationZ);
let id = objIdManager.generateNewUniqueId();
box.obj_track_id = id;
//this.scene.add(box);
if (!shift){
try{
this.boxOp.auto_shrink_box(box);
}
catch(e)
{
logger.log(e);
}
}
// guess obj type here
box.obj_type = globalObjectCategory.guess_obj_type_by_dimension(box.scale);
objIdManager.addObject({
category: box.obj_type,
id: box.obj_track_id,
});
this.imageContextManager.boxes_manager.add_box(box);
this.floatLabelManager.add_label(box);
this.selectBox(box);
this.on_box_changed(box);
if (!shift){
this.boxOp.auto_rotate_xyz(box, ()=>{
box.obj_type = globalObjectCategory.guess_obj_type_by_dimension(box.scale);
this.floatLabelManager.set_object_type(box.obj_local_id, box.obj_type);
this.fastToolBox.setValue(box.obj_type, box.obj_track_id, box.obj_attr);
this.on_box_changed(box);
});
}
//floatLabelManager.add_label(box);
};
this.create_box_by_points=function(points, rotationZ){
let localRot = this.data.world.sceneRotToLidar(new THREE.Euler(0,0,rotationZ, "XYZ"));
let transToBoxMatrix = new THREE.Matrix4().makeRotationFromEuler(localRot)
.setPosition(0, 0, 0)
.invert();
// var trans = transpose(euler_angle_to_rotate_matrix({x:0,y:0,z:rotation_z}, {x:0, y:0, z:0}), 4);
let relative_position = [];
let v = new THREE.Vector3();
points.forEach(function(p){
v.set(p[0],p[1],p[2]);
let boxP = v.applyMatrix4(transToBoxMatrix);
relative_position.push([boxP.x,boxP.y, boxP.z]);
});
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
let center = this.boxOp.translateBoxInBoxCoord(
localRot,
{
x: (relative_extreme.max[0] + relative_extreme.min[0])/2,
y: (relative_extreme.max[1] + relative_extreme.min[1])/2,
z: (relative_extreme.max[2] + relative_extreme.min[2])/2,
}
);
return this.data.world.annotation.add_box(center, scale, localRot, "Unknown", "");
};
this.handleLeftClick= function(event) {
if (event.ctrlKey){
//Ctrl+left click to smart paste!
//smart_paste();
}
else{
//select box /unselect box
if (!this.data.world || (!this.data.world.annotation.boxes && this.data.world.radars.radarList.length==0 && !this.calib.calib_box)){
return;
}
let all_boxes = this.data.world.annotation.boxes.concat(this.data.world.radars.getAllBoxes());
all_boxes = all_boxes.concat(this.data.world.aux_lidars.getAllBoxes());
if (this.calib.calib_box){
all_boxes.push(this.calib.calib_box);
}
let intersects = this.mouse.getIntersects( this.mouse.onUpPosition, all_boxes);
if (intersects.length == 0){
if (this.data.world.radar_box){
intersects = this.mouse.getIntersects( this.mouse.onUpPosition, [this.data.world.radar_box]);
}
}
if ( intersects.length > 0 ) {
//var object = intersects[ 0 ].object;
var object = intersects[ 0 ].object;
if ( object.userData.object !== undefined ) {
// helper
this.selectBox( object.userData.object );
} else {
this.selectBox( object );
}
} else {
this.unselectBox(null);
}
//render();
}
};
this.select_locked_object= function(){
var self=this;
if (this.view_state.lock_obj_track_id != ""){
var box = this.data.world.annotation.boxes.find(function(x){
return x.obj_track_id == self.view_state.lock_obj_track_id;
})
if (box){
this.selectBox(box);
if (self.view_state.lock_obj_in_highlight){
this.focusOnSelectedBox(box);
}
}
}
};
// new_object
this.unselectBox = function(new_object, keep_lock){
if (new_object==null){
if (this.viewManager.mainView && this.viewManager.mainView.transform_control.visible)
{
//unselect first time
this.viewManager.mainView.transform_control.detach();
}else{
//unselect second time
if (this.selected_box){
// restore from highlight
if (this.selected_box.in_highlight){
this.cancelFocus(this.selected_box);
if (!keep_lock){
this.view_state.lock_obj_in_highlight = false;
}
} else{
// unselected finally
//this.selected_box.material.color = new THREE.Color(parseInt("0x"+get_obj_cfg_by_type(this.selected_box.obj_type).color.slice(1)));
//this.selected_box.material.opacity = this.data.cfg.box_opacity;
this.boxOp.unhighlightBox(this.selected_box);
//this.floatLabelManager.unselect_box(this.selected_box.obj_local_id, this.selected_box.obj_type);
this.fastToolBox.hide();
if (!keep_lock){
this.view_state.lock_obj_track_id = "";
}
this.imageContextManager.boxes_manager.onBoxUnselected(this.selected_box.obj_local_id, this.selected_box.obj_type);
this.selected_box = null;
this.boxEditor.detach();
this.onSelectedBoxChanged(null);
}
}
else{
// just an empty click
return;
}
}
}
else{
// selected other box
//unselect all
this.viewManager.mainView.transform_control.detach();
if (this.selected_box){
// restore from highlight
if (this.selected_box.in_highlight){
this.cancelFocus(this.selected_box);
if (!keep_lock){
this.view_state.lock_obj_in_highlight = false;
}
}
this.selected_box.material.color = new THREE.Color(parseInt("0x"+globalObjectCategory.get_obj_cfg_by_type(this.selected_box.obj_type).color.slice(1)));
this.selected_box.material.opacity = this.data.cfg.box_opacity;
//this.floatLabelManager.unselect_box(this.selected_box.obj_local_id);
this.fastToolBox.hide();
this.imageContextManager.boxes_manager.onBoxUnselected(this.selected_box.obj_local_id, this.selected_box.obj_type);
this.selected_box = null;
this.boxEditor.detach();
if (!keep_lock)
this.view_state.lock_obj_track_id = "";
}
}
this.render();
};
this.selectBox = function(object){
if (this.selected_box != object){
// unselect old bbox
var in_highlight = false;
if (this.selected_box){
in_highlight = this.selected_box.in_highlight;
this.unselectBox(this.selected_box);
}
// select me, the first time
this.selected_box = object;
// switch camera
if (!this.editorCfg.disableMainImageContext){
var best_camera = this.imageContextManager.choose_best_camera_for_point(
this.selected_box.world.frameInfo.sceneMeta,
this.selected_box.position);
if (best_camera){
//var image_changed = this.data.set_active_image(best_camera);
// if (image_changed){
// this.editorUi.querySelector("#camera-selector").value=best_camera;
// this.imageContextManager.boxes_manager.display_image();
// }
this.imageContextManager.setBestCamera(best_camera);
}
}
// highlight box
// shold change this id if the current selected box changed id.
this.view_state.lock_obj_track_id = object.obj_track_id;
//this.floatLabelManager.select_box(this.selected_box.obj_local_id);
this.fastToolBox.setPos(this.floatLabelManager.getLabelEditorPos(this.selected_box.obj_local_id));
this.fastToolBox.setValue(object.obj_type, object.obj_track_id, object.obj_attr);
this.fastToolBox.show();
this.boxOp.highlightBox(this.selected_box);
if (in_highlight){
this.focusOnSelectedBox(this.selected_box);
}
this.save_box_info(object); // this is needed since when a frame is loaded, all box haven't saved anything.
// we could move this to when a frame is loaded.
this.boxEditor.attachBox(object);
this.onSelectedBoxChanged(object);
}
else {
//reselect the same box
if (this.viewManager.mainView.transform_control.visible){
this.change_transform_control_view();
}
else{
//select me the second time
//object.add(this.viewManager.mainView.transform_control);
this.viewManager.mainView.transform_control.attach( object );
}
}
this.render();
};
this.adjustContainerSize = function()
{
let editorRect = this.editorUi.getBoundingClientRect();
let headerRect = this.editorUi.querySelector("#header").getBoundingClientRect();
this.container.style.height = editorRect.height - headerRect.height + "px";
}
this.onWindowResize= function() {
this.adjustContainerSize();
this.boxEditorManager.onWindowResize();
// use clientwidth and clientheight to resize container
// but use scrollwidth/height to place other things.
if ( this.windowWidth != this.container.clientWidth || this.windowHeight != this.container.clientHeight ) {
//update_mainview();
if (this.viewManager.mainView)
this.viewManager.mainView.onWindowResize();
if (this.boxEditor)
this.boxEditor.update("dontrender");
this.windowWidth = this.container.clientWidth;
this.windowHeight = this.container.clientHeight;
this.renderer.setSize( this.windowWidth, this.windowHeight );
//this.viewManager.updateViewPort();
// update sideview svg if there exists selected box
// the following update is called in updateSubviewRangeByWindowResize
// if (this.selected_box){
// this.projectiveViewOps.update_view_handle(this.selected_box);
// }
}
this.viewManager.render();
};
this.change_transform_control_view= function(){
if (this.viewManager.mainView.transform_control.mode=="scale"){
this.viewManager.mainView.transform_control.setMode( "translate" );
this.viewManager.mainView.transform_control.showY=true;
this.viewManager.mainView.transform_control.showX=true;
this.viewManager.mainView.transform_control.showz=true;
}else if (this.viewManager.mainView.transform_control.mode=="translate"){
this.viewManager.mainView.transform_control.setMode( "rotate" );
this.viewManager.mainView.transform_control.showY=false;
this.viewManager.mainView.transform_control.showX=false;
this.viewManager.mainView.transform_control.showz=true;
}else if (this.viewManager.mainView.transform_control.mode=="rotate"){
this.viewManager.mainView.transform_control.setMode( "scale" );
this.viewManager.mainView.transform_control.showY=true;
this.viewManager.mainView.transform_control.showX=true;
this.viewManager.mainView.transform_control.showz=true;
}
};
this.add_box_on_mouse_pos_by_ref = function(){
let globalP = this.mouse.get_mouse_location_in_world();
// trans pos to world local pos
let pos = this.data.world.scenePosToLidar(globalP);
let refbox = this.autoAdjust.marked_object.ann;
pos.z = refbox.psr.position.z;
let id = refbox.obj_id;
if (this.autoAdjust.marked_object.frame == this.data.world.frameInfo.frame)
{
id = "";
}
let box = this.add_box(pos, refbox.psr.scale, refbox.psr.rotation, refbox.obj_type, id, refbox.obj_attr);
return box;
};
this.add_box_on_mouse_pos= function(obj_type){
// todo: move to this.data.world
let globalP = this.mouse.get_mouse_location_in_world();
// trans pos to world local pos
let pos = this.data.world.scenePosToLidar(globalP);
var rotation = new THREE.Euler(0, 0, this.viewManager.mainView.camera.rotation.z+Math.PI/2, "XYZ");
rotation = this.data.world.sceneRotToLidar(rotation);
var obj_cfg = globalObjectCategory.get_obj_cfg_by_type(obj_type);
var scale = {
x: obj_cfg.size[0],
y: obj_cfg.size[1],
z: obj_cfg.size[2]
};
pos.z = -1.8 + scale.z/2; // -1.8 is height of lidar
let id = objIdManager.generateNewUniqueId();
objIdManager.addObject({
category: obj_type,
id: id,
});
let box = this.add_box(pos, scale, rotation, obj_type, id);
return box;
};
this.add_box= function(pos, scale, rotation, obj_type, obj_track_id, obj_attr){
let box = this.data.world.annotation.add_box(pos, scale, rotation, obj_type, obj_track_id, obj_attr);
this.floatLabelManager.add_label(box);
this.imageContextManager.boxes_manager.add_box(box);
this.selectBox(box);
return box;
};
this.save_box_info= function(box){
box.last_info = {
//obj_type: box.obj_type,
position: {
x: box.position.x,
y: box.position.y,
z: box.position.z,
},
rotation: {
x: box.rotation.x,
y: box.rotation.y,
z: box.rotation.z,
},
scale: {
x: box.scale.x,
y: box.scale.y,
z: box.scale.z,
}
}
};
// axix, xyz, action: scale, move, direction, up/down
this.transform_bbox= function(command){
if (!this.selected_box)
return;
switch (command){
case 'x_move_up':
this.boxOp.translate_box(this.selected_box, 'x', 0.05);
break;
case 'x_move_down':
this.boxOp.translate_box(this.selected_box, 'x', -0.05);
break;
case 'x_scale_up':
this.selected_box.scale.x *= 1.01;
break;
case 'x_scale_down':
this.selected_box.scale.x /= 1.01;
break;
case 'y_move_up':
this.boxOp.translate_box(this.selected_box, 'y', 0.05);
break;
case 'y_move_down':
this.boxOp.translate_box(this.selected_box, 'y', -0.05);
break;
case 'y_scale_up':
this.selected_box.scale.y *= 1.01;
break;
case 'y_scale_down':
this.selected_box.scale.y /= 1.01;
break;
case 'z_move_up':
this.selected_box.position.z += 0.05;
break;
case 'z_move_down':
this.selected_box.position.z -= 0.05;
break;
case 'z_scale_up':
this.selected_box.scale.z *= 1.01;
break;
case 'z_scale_down':
this.selected_box.scale.z /= 1.01;
break;
case 'z_rotate_left':
this.selected_box.rotation.z += 0.01;
break;
case 'z_rotate_right':
this.selected_box.rotation.z -= 0.01;
break;
case 'z_rotate_reverse':
if (this.selected_box.rotation.z > 0){
this.selected_box.rotation.z -= Math.PI;
}else{
this.selected_box.rotation.z += Math.PI;
}
break;
case 'reset':
this.selected_box.rotation.x = 0;
this.selected_box.rotation.y = 0;
this.selected_box.rotation.z = 0;
this.selected_box.position.z = 0;
break;
}
this.on_box_changed(this.selected_box);
};
// function switch_bbox_type(target_type){
// if (!this.selected_box)
// return;
// if (!target_type){
// target_type = get_next_obj_type_name(this.selected_box.obj_type);
// }
// this.selected_box.obj_type = target_type;
// var obj_cfg = get_obj_cfg_by_type(target_type);
// this.selected_box.scale.x=obj_cfg.size[0];
// this.selected_box.scale.y=obj_cfg.size[1];
// this.selected_box.scale.z=obj_cfg.size[2];
// this.floatLabelManager.set_object_type(this.selected_box.obj_local_id, this.selected_box.obj_type);
// this.floatLabelManager.update_label_editor(this.selected_box.obj_type, this.selected_box.obj_track_id);
// }
this.keydown= function( ev ) {
// if (this.keydownDisabled)
// return;
this.operation_state.key_pressed = true;
switch ( ev.key) {
case '+':
case '=':
this.data.scale_point_size(1.2);
this.render();
break;
case '-':
this.data.scale_point_size(0.8);
this.render();
break;
case '1':
this.select_previous_object();
break;
case '2':
this.select_next_object();
break;
case '3':
case 'PageUp':
this.previous_frame();
break;
case 'PageDown':
case '4':
this.next_frame();
break;
case 'p':
this.downloadWebglScreenShot();
break;
// case 'v':
// this.change_transform_control_view();
// break;
/*
case 'm':
case 'M':
smart_paste();
break;
case 'N':
case 'n':
//add_bbox();
//header.mark_changed_flag();
break;
case 'B':
case 'b':
switch_bbox_type();
self.header.mark_changed_flag();
self.on_box_changed(this.selected_box);
break;
*/
case 'z': // X
this.viewManager.mainView.transform_control.showX = ! this.viewManager.mainView.transform_control.showX;
break;
case 'x': // Y
this.viewManager.mainView.transform_control.showY = ! this.viewManager.mainView.transform_control.showY;
break;
case 'c': // Z
if (ev.ctrlKey){
this.mark_bbox(this.selected_box);
} else {
this.viewManager.mainView.transform_control.showZ = ! this.viewManager.mainView.transform_control.showZ;
}
break;
case ' ': // Spacebar
//this.viewManager.mainView.transform_control.enabled = ! this.viewManager.mainView.transform_control.enabled;
this.playControl.pause_resume_play();
break;
case '5':
case '6':
case '7':
this.boxEditor.boxView.views[ev.key-5].cameraHelper.visible = !this.boxEditor.boxView.views[ev.key-5].cameraHelper.visible;
this.render();
break;
case 's':
if (ev.ctrlKey){
saveWorldList(this.data.worldList);
}
else if (this.selected_box)
{
let v = Math.max(this.editorCfg.moveStep * this.selected_box.scale.x, 0.02);
this.boxOp.translate_box(this.selected_box, 'x', -v);
this.on_box_changed(this.selected_box);
}
break;
case 'w':
if (this.selected_box){
let v = Math.max(this.editorCfg.moveStep * this.selected_box.scale.x, 0.02);
this.boxOp.translate_box(this.selected_box, 'x', v);
this.on_box_changed(this.selected_box);
}
break;
case 'a':
if (this.selected_box){
let v = Math.max(this.editorCfg.moveStep * this.selected_box.scale.y, 0.02);
this.boxOp.translate_box(this.selected_box, 'y', v);
this.on_box_changed(this.selected_box);
}
break;
case 'd':
if (this.selected_box){
let v = Math.max(this.editorCfg.moveStep * this.selected_box.scale.y, 0.02);
this.boxOp.translate_box(this.selected_box, 'y', -v);
this.on_box_changed(this.selected_box);
}
break;
case 'q':
if (this.selected_box){
this.boxOp.rotate_z(this.selected_box, this.editorCfg.rotateStep, false);
this.on_box_changed(this.selected_box);
}
break;
case 'e':
if (this.selected_box){
this.boxOp.rotate_z(this.selected_box, -this.editorCfg.rotateStep, false);
this.on_box_changed(this.selected_box);
}
break;
case 'r':
if (this.selected_box){
//this.transform_bbox("z_rotate_left");
this.boxOp.rotate_z(this.selected_box, this.editorCfg.rotateStep, true);
this.on_box_changed(this.selected_box);
}
break;
case 'f':
if (this.selected_box){
//this.transform_bbox("z_rotate_right");
this.boxOp.rotate_z(this.selected_box, -this.editorCfg.rotateStep, true);
this.on_box_changed(this.selected_box);
}
break;
case 'g':
this.transform_bbox("z_rotate_reverse");
break;
case 't':
//this.transform_bbox("reset");
this.showTrajectory();
break;
case 'v':
this.enterBatchEditMode();
break;
case 'd':
case 'D':
if (ev.ctrlKey){
this.remove_selected_box();
this.header.updateModifiedStatus();
}
break;
case 'Delete':
this.remove_selected_box();
this.header.updateModifiedStatus();
break;
case 'Escape':
if (this.selected_box){
this.unselectBox(null);
}
break;
}
};
this.previous_frame= function(){
if (!this.data.meta)
return;
var scene_meta = this.data.get_current_world_scene_meta();
var frame_index = this.data.world.frameInfo.frame_index-1;
if (frame_index < 0){
console.log("first frame");
this.infoBox.show("Notice", "This is the first frame");
return;
}
this.load_world(scene_meta.scene, scene_meta.frames[frame_index]);
};
this.last_frame = function()
{
let scene_meta = this.data.get_current_world_scene_meta();
this.load_world(scene_meta.scene, scene_meta.frames[scene_meta.frames.length-1]);
};
this.first_frame = function()
{
let scene_meta = this.data.get_current_world_scene_meta();
this.load_world(scene_meta.scene, scene_meta.frames[0]);
};
this.next_frame= function(){
if (!this.data.meta)
return;
var scene_meta = this.data.get_current_world_scene_meta();
var num_frames = scene_meta.frames.length;
var frame_index = (this.data.world.frameInfo.frame_index +1);
if (frame_index >= num_frames){
console.log("last frame");
this.infoBox.show("Notice", "This is the last frame");
return;
}
this.load_world(scene_meta.scene, scene_meta.frames[frame_index]);
};
this.select_next_object= function(){
var self=this;
if (this.data.world.annotation.boxes.length<=0)
return;
if (this.selected_box){
this.operation_state.box_navigate_index = this.data.world.annotation.boxes.findIndex(function(x){
return self.selected_box == x;
});
}
this.operation_state.box_navigate_index += 1;
this.operation_state.box_navigate_index %= this.data.world.annotation.boxes.length;
this.selectBox(this.data.world.annotation.boxes[this.operation_state.box_navigate_index]);
};
this.select_previous_object= function(){
var self=this;
if (this.data.world.annotation.boxes.length<=0)
return;
if (this.selected_box){
this.operation_state.box_navigate_index = this.data.world.annotation.boxes.findIndex(function(x){
return self.selected_box == x;
});
}
this.operation_state.box_navigate_index += this.data.world.annotation.boxes.length-1;
this.operation_state.box_navigate_index %= this.data.world.annotation.boxes.length;
this.selectBox(this.data.world.annotation.boxes[this.operation_state.box_navigate_index]);
};
// this.centerMainView =function(){
// let offset = this.data.world.coordinatesOffset;
// this.viewManager.mainView.orbit.target.x += offset[0];
// this.viewManager.mainView.orbit.target.y += offset[1];
// this.viewManager.mainView.orbit.target.z += offset[2];
// };
this.on_load_world_finished= function(world){
document.title = "SUSTech POINTS-" + world.frameInfo.scene;
// switch view positoin
this.moveAxisHelper(world);
this.moveRangeCircle(world);
this.lookAtWorld(world);
this.unselectBox(null, true);
this.unselectBox(null, true);
this.render();
this.imageContextManager.attachWorld(world);
this.imageContextManager.render_2d_image();
this.render2dLabels(world);
this.update_frame_info(world.frameInfo.scene, world.frameInfo.frame);
this.select_locked_object();
//load_obj_ids_of_scene(world.frameInfo.scene);
objIdManager.setCurrentScene(world.frameInfo.scene);
// preload after the first world loaded
// otherwise the loading of the first world would be too slow
this.data.preloadScene(world.frameInfo.scene, world);
};
this.moveAxisHelper = function(world) {
world.webglGroup.add(this.axis);
};
this.mainViewOffset = [0,0,0];
this.lookAtWorld = function(world){
let newOffset = [
world.coordinatesOffset[0] - this.mainViewOffset[0],
world.coordinatesOffset[1] - this.mainViewOffset[1],
world.coordinatesOffset[2] - this.mainViewOffset[2],
];
this.mainViewOffset = world.coordinatesOffset;
this.viewManager.mainView.orbit.target.x += newOffset[0];
this.viewManager.mainView.orbit.target.y += newOffset[1];
this.viewManager.mainView.orbit.target.z += newOffset[2];
this.viewManager.mainView.camera.position.x += newOffset[0];
this.viewManager.mainView.camera.position.y += newOffset[1];
this.viewManager.mainView.camera.position.z += newOffset[2];
this.viewManager.mainView.orbit.update();
};
this.load_world = async function(sceneName, frame, onFinished){
this.data.dbg.dump();
logger.log(`load ${sceneName}, ${frame}`);
var self=this;
//stop if current world is not ready!
if (this.data.world && !this.data.world.preloaded()){
console.error("current world is still loading.");
return;
}
if (this.selected_box && this.selected_box.in_highlight){
this.cancelFocus(this.selected_box);
}
if (this.viewManager.mainView && this.viewManager.mainView.transform_control.visible)
{
//unselect first time
this.viewManager.mainView.transform_control.detach();
}
var world = await this.data.getWorld(sceneName, frame);
if (world)
{
this.data.activate_world(
world,
function(){
self.on_load_world_finished(world);
if (onFinished)
onFinished();
}
);
}
};
this.remove_box = function(box, render=true){
if (box === this.selected_box){
this.unselectBox(null,true);
this.unselectBox(null,true); //twice to safely unselect.
this.selected_box = null;
//this.remove_selected_box();
}
this.do_remove_box(box, false); // render later.
// this should be after do-remove-box
// subview renderings don't need to be done again after
// the box is removed.
if (box.boxEditor)
{
if (box.boxEditor){
box.boxEditor.detach("donthide");
}
else{
console.error("what?");
}
}
this.header.updateModifiedStatus();
if (render)
this.render();
};
this.remove_selected_box= function(){
this.remove_box(this.selected_box);
};
this.do_remove_box = function(box, render=true){
if (!box.annotator)
this.restore_box_points_color(box, render);
this.imageContextManager.boxes_manager.remove_box(box.obj_local_id);
this.floatLabelManager.remove_box(box);
this.fastToolBox.hide();
//this.selected_box.dispose();
box.world.annotation.unload_box(box);
box.world.annotation.remove_box(box);
box.world.annotation.setModified();
},
this.clear= function(){
this.header.clear_box_info();
//this.editorUi.querySelector("#image").innerHTML = '';
this.unselectBox(null);
this.unselectBox(null);
this.header.clear_frame_info();
this.imageContextManager.clear_main_canvas();
this.boxEditor.detach();
this.data.world.unload();
this.data.world= null; //dump it
this.floatLabelManager.remove_all_labels();
this.fastToolBox.hide();
this.render();
};
this.update_frame_info= function(scene, frame){
var self = this;
this.header.set_frame_info(scene, frame, function(sceneName){
self.scene_changed(sceneName)});
};
//box edited
this.on_box_changed = function(box){
if (!this.imageContextManager.hidden())
this.imageContextManager.boxes_manager.update_box(box);
this.header.update_box_info(box);
//floatLabelManager.update_position(box, false); don't update position, or the ui is annoying.
box.world.annotation.setModified();
this.updateBoxPointsColor(box);
this.save_box_info(box);
if (box.boxEditor){
box.boxEditor.onBoxChanged();
}
else{
console.error("what?");
}
this.autoAdjust.syncFollowers(box);
// if (box === this.data.world.radar_box){
// this.data.world.move_radar(box);
// }
if (box.on_box_changed){
box.on_box_changed();
}
this.header.updateModifiedStatus();
this.render();
};
// box removed, restore points color.
this.restore_box_points_color= function(box,render=true){
if (this.data.cfg.color_obj != "no"){
box.world.lidar.reset_box_points_color(box);
box.world.lidar.update_points_color();
if (render)
this.render();
}
};
this.updateBoxPointsColor= function(box){
if (this.data.cfg.color_obj != "no"){
if (box.last_info){
box.world.lidar.set_box_points_color(box.last_info, {x: this.data.cfg.point_brightness, y: this.data.cfg.point_brightness, z: this.data.cfg.point_brightness});
}
box.world.lidar.set_box_points_color(box);
box.world.lidar.update_points_color();
}
};
this.onSelectedBoxChanged= function(box){
if (box){
this.header.update_box_info(box);
// this.floatLabelManager.update_position(box, true);
// this.fastToolBox.setPos(this.floatLabelManager.getLabelEditorPos(box.obj_local_id));
this.imageContextManager.boxes_manager.onBoxSelected(box.obj_local_id, box.obj_type);
//this.boxEditor.attachBox(box);
this.render();
//this.boxEditor.boxView.render();
//this.updateSubviewRangeByWindowResize(box);
} else {
this.header.clear_box_info();
}
};
this.render2dLabels= function(world){
if (this.editorCfg.disableMainView)
return;
this.floatLabelManager.remove_all_labels();
var self=this;
world.annotation.boxes.forEach(function(b){
self.floatLabelManager.add_label(b);
})
if (this.selected_box){
//this.floatLabelManager.select_box(this.selected_box.obj_local_id)
this.fastToolBox.show();
this.fastToolBox.setValue(this.selected_box.obj_type, this.selected_box.obj_track_id, this.selected_box.obj_attr);
}
};
this.add_global_obj_type= function(){
var self = this;
var sheet = window.document.styleSheets[1];
let obj_type_map = globalObjectCategory.obj_type_map;
for (var o in obj_type_map){
var rule = '.'+o+ '{color:'+obj_type_map[o].color+';'+
'stroke:' +obj_type_map[o].color+ ';'+
'fill:' +obj_type_map[o].color+ '22' + ';'+
'}';
sheet.insertRule(rule, sheet.cssRules.length);
}
function color_str(v){
let c = Math.round(v*255);
if (c < 16)
return "0" + c.toString(16);
else
return c.toString(16);
}
for (let idx=0; idx<=32; idx++){
let c = globalObjectCategory.get_color_by_id(idx);
let color = "#" + color_str(c.x) + color_str(c.y) + color_str(c.z);
var rule = '.color-'+idx+ '{color:'+color+';'+
'stroke:' +color+ ';'+
'fill:' +color+ '22' + ';'+
'}';
sheet.insertRule(rule, sheet.cssRules.length);
}
// obj type selector
var options = "";
for (var o in obj_type_map){
options += '<option value="'+o+'" class="' +o+ '">'+o+ '</option>';
}
this.editorUi.querySelector("#floating-things #object-category-selector").innerHTML = options;
//this.editorUi.querySelector("#batch-editor-tools-wrapper #object-category-selector").innerHTML = options;
// submenu of new
var items = "";
for (var o in obj_type_map){
items += '<div class="menu-item cm-new-item ' + o + '" id="cm-new-'+o+'" uservalue="' +o+ '"><div class="menu-item-text">'+o+ '</div></div>';
}
this.editorUi.querySelector("#new-submenu").innerHTML = items;
this.contextMenu.installMenu("newSubMenu", this.editorUi.querySelector("#new-submenu"), (event)=>{
let obj_type = event.currentTarget.getAttribute("uservalue");
let box = self.add_box_on_mouse_pos(obj_type);
//switch_bbox_type(event.currentTarget.getAttribute("uservalue"));
//self.boxOp.grow_box(box, 0.2, {x:2, y:2, z:3});
//self.auto_shrink_box(box);
//self.on_box_changed(box);
let noscaling = event.shiftKey;
self.boxOp.auto_rotate_xyz(box, null, null, function(b){
self.on_box_changed(b);
}, noscaling);
return true;
});
// // install click actions
// for (var o in obj_type_map){
// this.editorUi.querySelector("#cm-new-"+o).onclick = (event)=>{
// // hide context men
// // let context menu object handle this.
// // this.editorUi.querySelector("#context-menu-wrapper").style.display="none";
// // process event
// var obj_type = event.currentTarget.getAttribute("uservalue");
// let box = self.add_box_on_mouse_pos(obj_type);
// //switch_bbox_type(event.currentTarget.getAttribute("uservalue"));
// //self.boxOp.grow_box(box, 0.2, {x:2, y:2, z:3});
// //self.auto_shrink_box(box);
// //self.on_box_changed(box);
// self.boxOp.auto_rotate_xyz(box, null, null, function(b){
// self.on_box_changed(b);
// });
// }
// }
};
this.interpolate_selected_object= function(){
let scene = this.data.world.frameInfo.scene;
let frame = this.data.world.frameInfo.frame;
let obj_id = this.selected_box.obj_track_id;
this.boxOp.interpolate_selected_object(scene, obj_id, frame, (s,fs)=>{
this.onAnnotationUpdatedByOthers(s, fs);
});
};
this.onAnnotationUpdatedByOthers = function(scene, frames){
this.data.onAnnotationUpdatedByOthers(scene, frames);
}
this.init(editorUi);
};
export{Editor}