import { transpose, matmul2, euler_angle_to_rotate_matrix_3by3, normalizeAngle, } from "./util.js"; import { logger } from "./log.js"; // todo: this module needs a proper name function AutoAdjust(boxOp, mouse, header) { (this.boxOp = boxOp), (this.mouse = mouse); this.header = header; var marked_object = null; // mark bbox, which will be used as reference-bbox of an object. this.mark_bbox = function (box) { if (box) { this.marked_object = { frame: box.world.frameInfo.frame, scene: box.world.frameInfo.scene, ann: box.world.annotation.boxToAnn(box), }; logger.log(`selected reference objcet ${this.marked_object}`); this.header.set_ref_obj(this.marked_object); } }; this.followStaticObjects = function (box) { let world = box.world; let staticObjects = world.annotation.boxes .filter((b) => b != box && b.obj_attr && b.obj_attr.search("static") >= 0) .map((refObj) => { let coord = euler_angle_to_rotate_matrix_3by3(refObj.rotation); let trans = transpose(coord, 3); let p = [ box.position.x - refObj.position.x, box.position.y - refObj.position.y, box.position.z - refObj.position.z, ]; let relativePos = matmul2(trans, p, 3); let relativeRot = { x: normalizeAngle(box.rotation.x - refObj.rotation.x), y: normalizeAngle(box.rotation.y - refObj.rotation.y), z: normalizeAngle(box.rotation.z - refObj.rotation.z), }; let distance = Math.sqrt( relativePos[0] * relativePos[0] + relativePos[1] * relativePos[1] + relativePos[2] * relativePos[2] ); return { obj_track_id: refObj.obj_track_id, relativePos, relativeRot, distance, }; }); let worldList = box.world.data.worldList; //let saveList = []; worldList.forEach((w) => { if (w === box.world) { //current frame return; } let existedBox = w.annotation.boxes.find( (b) => b.obj_track_id == box.obj_track_id ); if (existedBox && !existedBox.annotator) { // have same objects annotated. // if its generated by machine, lets overwrite it return; } let candPoseSets = staticObjects.map((refObj) => { let refObjInW = w.annotation.boxes.find( (b) => b.obj_track_id == refObj.obj_track_id ); if (!refObjInW) { // not found refobj in this world, give up return null; } let relativePos = refObj.relativePos; let relativeRot = refObj.relativeRot; let coord = euler_angle_to_rotate_matrix_3by3(refObjInW.rotation); let rp = matmul2(coord, relativePos, 3); let newObjPos = { x: refObjInW.position.x + rp[0], y: refObjInW.position.y + rp[1], z: refObjInW.position.z + rp[2], }; let newObjRot = { x: normalizeAngle(refObjInW.rotation.x + relativeRot.x), y: normalizeAngle(refObjInW.rotation.y + relativeRot.y), z: normalizeAngle(refObjInW.rotation.z + relativeRot.z), }; return { distance: refObj.distance, weight: Math.exp(-refObj.distance * (refObjInW.annotator ? 1 : 0.1)), position: newObjPos, rotation: newObjRot, }; }); candPoseSets = candPoseSets.filter((p) => !!p); if (candPoseSets.length == 0) { return; } // calculate mean pos/rot let denorm = candPoseSets.reduce((a, b) => a + b.weight, 0); let newObjPos = { x: 0, y: 0, z: 0 }; let newObjRot = { x: 0, y: 0, z: 0, cosZ: 0, sinZ: 0 }; candPoseSets.forEach((p) => { newObjPos.x += p.position.x * p.weight; newObjPos.y += p.position.y * p.weight; newObjPos.z += p.position.z * p.weight; newObjRot.x += p.rotation.x * p.weight; newObjRot.y += p.rotation.y * p.weight; //newObjRot.z += p.rotation.z * p.weight; newObjRot.cosZ += Math.cos(p.rotation.z) * p.weight; newObjRot.sinZ += Math.sin(p.rotation.z) * p.weight; }); newObjPos.x /= denorm; newObjPos.y /= denorm; newObjPos.z /= denorm; newObjRot.x /= denorm; newObjRot.y /= denorm; newObjRot.cosZ /= denorm; newObjRot.sinZ /= denorm; newObjRot.z = Math.atan2(newObjRot.sinZ, newObjRot.cosZ); // ignor distant objects if (pointsGlobalConfig.ignoreDistantObject) { let objDistance = Math.sqrt( newObjPos.x * newObjPos.x + newObjPos.y * newObjPos.y + newObjPos.z * newObjPos.z ); if ((box.scale.z < 2 && objDistance > 100) || objDistance > 150) { return; } } // apply if (existedBox) { existedBox.position.x = newObjPos.x; existedBox.position.y = newObjPos.y; existedBox.position.z = newObjPos.z; existedBox.rotation.x = newObjRot.x; existedBox.rotation.y = newObjRot.y; existedBox.rotation.z = newObjRot.z; existedBox.scale.x = box.scale.x; existedBox.scale.y = box.scale.y; existedBox.scale.z = box.scale.z; existedBox.annotator = "S"; logger.log(`modified box in ${w}`); } else { let newBox = w.annotation.add_box( newObjPos, box.scale, newObjRot, box.obj_type, box.obj_track_id, box.obj_attr ); newBox.annotator = "S"; w.annotation.load_box(newBox); logger.log(`inserted box in ${w}`); } console.log("added box in ", w.frameInfo.frame); //saveList.push(w); w.annotation.setModified(); }); }; this.followsRef = function (box) { //find ref object in current frame let world = box.world; let refObj = world.annotation.boxes.find( (b) => b.obj_track_id == this.marked_object.ann.obj_id ); if (refObj) { console.log("found ref obj in current frame"); world.annotation.setModified(); //compute relative position // represent obj in coordinate system of refobj let coord = euler_angle_to_rotate_matrix_3by3(refObj.rotation); let trans = transpose(coord, 3); let p = [ box.position.x - refObj.position.x, box.position.y - refObj.position.y, box.position.z - refObj.position.z, ]; const relativePos = matmul2(trans, p, 3); const relativeRot = { x: box.rotation.x - refObj.rotation.x, y: box.rotation.y - refObj.rotation.y, z: box.rotation.z - refObj.rotation.z, }; let worldList = box.world.data.worldList; //let saveList = []; worldList.forEach((w) => { if (w === box.world) { //current frame return; } let existedBox = w.annotation.boxes.find( (b) => b.obj_track_id == box.obj_track_id ); if (existedBox && !existedBox.annotator) { // have same objects annotated. // if its generated by machine, lets overwrite it return; } let refObjInW = w.annotation.boxes.find( (b) => b.obj_track_id == refObj.obj_track_id ); if (!refObjInW) { // not found refobj in this world, give up return; } let coord = euler_angle_to_rotate_matrix_3by3(refObjInW.rotation); let rp = matmul2(coord, relativePos, 3); let newObjPos = { x: refObjInW.position.x + rp[0], y: refObjInW.position.y + rp[1], z: refObjInW.position.z + rp[2], }; let newObjRot = { x: refObjInW.rotation.x + relativeRot.x, y: refObjInW.rotation.y + relativeRot.y, z: refObjInW.rotation.z + relativeRot.z, }; if (existedBox) { existedBox.position.x = newObjPos.x; existedBox.position.y = newObjPos.y; existedBox.position.z = newObjPos.z; existedBox.rotation.x = newObjRot.x; existedBox.rotation.y = newObjRot.y; existedBox.rotation.z = newObjRot.z; existedBox.scale.x = box.scale.x; existedBox.scale.y = box.scale.y; existedBox.scale.z = box.scale.z; existedBox.annotator = "F"; existedBox.follows = { obj_track_id: refObj.obj_track_id, relative_position: { x: relativePos[0], y: relativePos[1], z: relativePos[2], }, relative_rotation: relativeRot, }; logger.log(`modified box in ${w}`); } else { let newBox = w.annotation.add_box( newObjPos, box.scale, newObjRot, box.obj_type, box.obj_track_id, box.obj_attr ); newBox.annotator = "F"; newBox.follows = { obj_track_id: refObj.obj_track_id, relative_position: { x: relativePos[0], y: relativePos[1], z: relativePos[2], }, relative_rotation: relativeRot, }; w.annotation.load_box(newBox); logger.log(`inserted box in ${w}`); } console.log("added box in ", w.frameInfo.frame); //saveList.push(w); w.annotation.setModified(); }); //saveWorldList(saveList); } }; this.syncFollowers = function (box) { let world = box.world; let allFollowers = world.annotation.boxes.filter( (b) => b.follows && b.follows.obj_track_id === box.obj_track_id ); if (allFollowers.length == 0) { console.log("no followers"); return; } let refObj = box; let coord = euler_angle_to_rotate_matrix_3by3(refObj.rotation); allFollowers.forEach((fb) => { let relpos = [ fb.follows.relative_position.x, fb.follows.relative_position.y, fb.follows.relative_position.z, ]; let rp = matmul2(coord, relpos, 3); fb.position.x = refObj.position.x + rp[0]; fb.position.y = refObj.position.y + rp[1]; fb.position.z = refObj.position.z + rp[2]; fb.rotation.x = refObj.rotation.x + fb.follows.relative_rotation.x; fb.rotation.y = refObj.rotation.y + fb.follows.relative_rotation.y; fb.rotation.z = refObj.rotation.z + fb.follows.relative_rotation.z; }); }; this.paste_bbox = function (pos, add_box) { if (!pos) pos = this.marked_object.ann.psr.position; else pos.z = this.marked_object.ann.psr.position.z; return add_box( pos, this.marked_object.ann.psr.scale, this.marked_object.ann.psr.rotation, this.marked_object.ann.obj_type, this.marked_object.ann.obj_id, this.marked_object.ann.obj_attr ); }; // this.auto_adjust_bbox=function(box, done, on_box_changed){ // saveWorld(function(){ // do_adjust(box, on_box_changed); // }); // let _self =this; // function do_adjust(box, on_box_changed){ // console.log("auto adjust highlighted bbox"); // var xhr = new XMLHttpRequest(); // // we defined the xhr // xhr.onreadystatechange = function () { // if (this.readyState != 4) return; // if (this.status == 200) { // console.log(this.responseText) // console.log(box.position); // console.log(box.rotation); // var trans_mat = JSON.parse(this.responseText); // var rotation = Math.atan2(trans_mat[4], trans_mat[0]) + box.rotation.z; // var transform = { // x: -trans_mat[3], // y: -trans_mat[7], // z: -trans_mat[11], // } // /* // cos sin x // -sin cos y // */ // var new_pos = { // x: Math.cos(-rotation) * transform.x + Math.sin(-rotation) * transform.y, // y: -Math.sin(-rotation) * transform.x + Math.cos(-rotation) * transform.y, // z: transform.z, // }; // box.position.x += new_pos.x; // box.position.y += new_pos.y; // box.position.z += new_pos.z; // box.scale.x = marked_object.scale.x; // box.scale.y = marked_object.scale.y; // box.scale.z = marked_object.scale.z; // box.rotation.z -= Math.atan2(trans_mat[4], trans_mat[0]); // console.log(box.position); // console.log(box.rotation); // on_box_changed(box); // _self.header.mark_changed_flag(); // if (done){ // done(); // } // } // // end of state change: it can be after some time (async) // }; // xhr.open('GET', // "/auto_adjust"+"?scene="+marked_object.scene + "&"+ // "ref_frame=" + marked_object.frame + "&" + // "object_id=" + marked_object.obj_track_id + "&" + // "adj_frame=" + data.world.frameInfo.frame, // true); // xhr.send(); // } // }; this.smart_paste = function (selected_box, add_box, on_box_changed) { var box = selected_box; if (!box) { let sceneP = this.mouse.get_mouse_location_in_world(); // trans pos to world local pos //let pos = this.data.world.scenePosToLidar(sceneP); box = this.paste_bbox(pos, add_box); } else if (this.marked_object) { box.scale.x = this.marked_object.ann.psr.scale.x; box.scale.y = this.marked_object.ann.psr.scale.y; box.scale.z = this.marked_object.ann.psr.scale.z; } // this.auto_adjust_bbox(box, // function(){saveWorld();}, // on_box_changed); // this.header.mark_changed_flag(); this.boxOp.auto_rotate_xyz(box, null, null, on_box_changed, "noscaling"); }; } export { AutoAdjust };