import { psr_to_xyz } from "./util.js";
import * as THREE from "./lib/three.module.js";
import { categoryZh, globalObjectCategory } from "./obj_cfg.js";
class FastToolBox {
constructor(ui, eventHandler) {
let self = this;
this.ui = ui;
this.eventHandler = eventHandler;
this.installEventHandler();
this.ui.querySelector("#attr-editor").onmouseenter = function (event) {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
event.target.querySelector("#attr-selector").style.display = "";
};
this.ui.querySelector("#attr-editor").onmouseleave = function (event) {
let ui = event.target.querySelector("#attr-selector");
this.timerId = setTimeout(() => {
ui.style.display = "none";
this.timerId = null;
}, 200);
};
this.ui.querySelector("#label-more").onmouseenter = function (event) {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
let ui = event.target.querySelector("#object-dropdown-menu");
ui.style.display = "inherit";
ui.style.top = "100%";
ui.style.left = "0%";
ui.style.right = null;
ui.style.bottom = null;
let rect = ui.getClientRects()[0];
if (window.innerHeight < rect.y + rect.height) {
ui.style.top = null;
ui.style.bottom = "100%";
}
if (window.innerWidth < rect.x + rect.width) {
ui.style.left = null;
ui.style.right = "0%";
}
};
this.ui.querySelector("#label-more").onmouseleave = function (event) {
let ui = event.target.querySelector("#object-dropdown-menu");
this.timerId = setTimeout(() => {
ui.style.display = "none";
this.timerId = null;
}, 200);
};
let dropdownMenu = this.ui.querySelector("#object-dropdown-menu");
for (let i = 0; i < dropdownMenu.children.length; i++) {
dropdownMenu.children[i].onclick = (event) => {
//event.preventDefault();
event.stopPropagation();
this.eventHandler(event);
this.ui.querySelector("#object-dropdown-menu").style.display = "none";
};
}
}
hide() {
this.ui.style.display = "none";
}
show() {
this.ui.style.display = "inline-block";
this.ui.querySelector("#attr-selector").style.display = "none";
}
setValue(obj_type, obj_track_id, obj_attr) {
this.ui.querySelector("#object-category-selector").value = obj_type;
this.setAttrOptions(obj_type, obj_attr);
this.ui.querySelector("#object-track-id-editor").value = obj_track_id;
if (obj_attr) this.ui.querySelector("#attr-input").value = obj_attr;
else this.ui.querySelector("#attr-input").value = "";
}
setPos(pos) {
if (pos) {
this.ui.style.top = pos.top;
this.ui.style.left = pos.left;
}
}
setAttrOptions(obj_type, obj_attr) {
let attrs = ["static"];
if (
globalObjectCategory.obj_type_map[obj_type] &&
globalObjectCategory.obj_type_map[obj_type].attr
)
attrs = attrs.concat(globalObjectCategory.obj_type_map[obj_type].attr);
// merge attrs
let objAttrs = [];
if (obj_attr) {
objAttrs = obj_attr.split(",").map((a) => a.trim());
objAttrs.forEach((a) => {
if (!attrs.find((x) => x == a)) {
attrs.push(a);
}
});
}
let items = ``;
attrs.forEach((a) => {
if (objAttrs.find((x) => x == a)) {
items += `
${a}
`;
} else {
items += `${a}
`;
}
});
this.ui.querySelector("#attr-selector").innerHTML = items;
this.ui.querySelector("#attr-selector").onclick = (event) => {
let attrs = this.ui.querySelector("#attr-input").value;
let objCurrentAttrs = [];
if (attrs) objCurrentAttrs = attrs.split(",").map((a) => a.trim());
let clickedAttr = event.target.innerText;
if (objCurrentAttrs.find((x) => x == clickedAttr)) {
objCurrentAttrs = objCurrentAttrs.filter((x) => x != clickedAttr);
event.target.className = "attr-item";
} else {
objCurrentAttrs.push(clickedAttr);
event.target.className = "attr-item attr-selected";
}
attrs = "";
if (objCurrentAttrs.length > 0) {
attrs = objCurrentAttrs.reduce((a, b) => a + (a ? "," : "") + b);
}
this.ui.querySelector("#attr-input").value = attrs;
this.eventHandler({
currentTarget: {
id: "attr-input",
value: attrs,
},
});
};
}
installEventHandler() {
let btns = [
"#label-del",
"#label-gen-id",
"#label-copy",
"#label-paste",
"#label-batchedit",
"#label-trajectory",
"#label-edit",
"#label-highlight",
"#label-rotate",
];
btns.forEach((btn) => {
this.ui.querySelector(btn).onclick = (event) => {
this.eventHandler(event);
};
});
this.ui.querySelector("#object-category-selector").onchange = (event) => {
//this.ui.querySelector("#attr-input").value="";
this.setAttrOptions(
event.currentTarget.value,
this.ui.querySelector("#attr-input").value
);
this.eventHandler(event);
};
this.ui.querySelector("#object-track-id-editor").onchange = (event) =>
this.eventHandler(event);
this.ui
.querySelector("#object-track-id-editor")
.addEventListener("keydown", (e) => e.stopPropagation());
this.ui
.querySelector("#object-track-id-editor")
.addEventListener("keyup", (event) => {
event.stopPropagation();
this.eventHandler(event);
});
this.ui.querySelector("#attr-input").onchange = (event) =>
this.eventHandler(event);
this.ui
.querySelector("#attr-input")
.addEventListener("keydown", (e) => e.stopPropagation());
this.ui.querySelector("#attr-input").addEventListener("keyup", (event) => {
event.stopPropagation();
this.eventHandler(event);
});
}
}
class FloatLabelManager {
id_enabled = true;
category_enabled = true;
color_scheme = "category";
constructor(editor_ui, container_div, view, func_on_label_clicked) {
this.view = view; //access camera by view, since camera is dynamic
this.editor_ui = editor_ui;
this.container = container_div;
this.labelsUi = editor_ui.querySelector("#floating-labels");
this.floatingUi = editor_ui.querySelector("#floating-things");
this.style = document.createElement("style");
this.temp_style = document.createElement("style");
this.on_label_clicked = func_on_label_clicked;
document.head.appendChild(this.style);
document.head.appendChild(this.temp_style);
this.id_enabled = !pointsGlobalConfig.hideId;
this.category_enabled = !pointsGlobalConfig.hideCategory;
}
hide() {
this.floatingUi.style.display = "none";
}
show() {
this.floatingUi.style.display = "";
}
show_id(show) {
this.id_enabled = show;
if (!show) {
this.temp_style.sheet.insertRule(".label-obj-id-text {display: none}");
} else {
for (let i = this.temp_style.sheet.cssRules.length - 1; i >= 0; i--) {
var r = this.temp_style.sheet.cssRules[i];
if (r.selectorText === ".label-obj-id-text") {
this.temp_style.sheet.deleteRule(i);
}
}
}
}
show_category(show) {
this.category_enabled = show;
if (!show) {
this.temp_style.sheet.insertRule(".label-obj-type-text {display: none}");
this.temp_style.sheet.insertRule(".label-obj-attr-text {display: none}");
} else {
for (let i = this.temp_style.sheet.cssRules.length - 1; i >= 0; i--) {
var r = this.temp_style.sheet.cssRules[i];
if (
r.selectorText === ".label-obj-type-text" ||
r.selectorText === ".label-obj-attr-text"
) {
this.temp_style.sheet.deleteRule(i);
}
}
}
}
// hide all temporarily when zoom in one object.
hide_all() {
// if (this.temp_style.sheet.cssRules.length == 0){
// this.temp_style.sheet.insertRule(".label-obj-id-text {display: none}");
// this.temp_style.sheet.insertRule(".label-obj-type-text {display: none}");
// this.temp_style.sheet.insertRule(".label-obj-attr-text {display: none}");
// }
this.labelsUi.style.display = "none";
}
restore_all() {
// this.show_category(this.category_enabled);
// this.show_id(this.id_enabled);
this.labelsUi.style.display = "";
}
remove_all_labels() {
var _self = this;
if (this.labelsUi.children.length > 0) {
for (var c = this.labelsUi.children.length - 1; c >= 0; c--) {
this.labelsUi.children[c].remove();
}
}
}
update_all_position() {
if (this.labelsUi.children.length > 0) {
for (var c = 0; c < this.labelsUi.children.length; c++) {
var element = this.labelsUi.children[c];
var best_pos = this.compute_best_position(element.vertices);
var pos = this.coord_to_pixel(best_pos);
element.style.top = Math.round(pos.y) + "px";
element.style.left = Math.round(pos.x) + "px";
element.className = element.orgClassName;
if (pos.out_view) {
element.className += " label-out-view";
}
}
}
}
getLabelEditorPos(local_id) {
let label = this.editor_ui.querySelector("#obj-local-" + local_id);
if (label) {
// if label is hidden, we can't use its pos directly.
let best_pos = this.compute_best_position(label.vertices);
let pos = this.coord_to_pixel(best_pos);
return {
top: Math.round(pos.y) + label.offsetHeight + "px",
left: Math.round(pos.x) + 30 + "px",
};
}
}
set_object_type(local_id, obj_type) {
var label = this.editor_ui.querySelector("#obj-local-" + local_id);
if (label) {
label.obj_type = obj_type;
label.update_text();
this.update_color(label);
}
}
set_object_attr(local_id, obj_attr) {
var label = this.editor_ui.querySelector("#obj-local-" + local_id);
if (label) {
label.obj_attr = obj_attr;
label.update_text();
this.update_color(label);
}
}
set_object_track_id(local_id, track_id) {
var label = this.editor_ui.querySelector("#obj-local-" + local_id);
if (label) {
label.obj_track_id = track_id;
label.update_text();
this.update_color(label);
}
}
translate_vertices_to_global(world, vertices) {
let ret = [];
for (let i = 0; i < vertices.length; i += 4) {
let p = new THREE.Vector4()
.fromArray(vertices, i)
.applyMatrix4(world.webglGroup.matrix);
ret.push(p.x);
ret.push(p.y);
ret.push(p.z);
ret.push(p.w);
}
return ret;
}
update_position(box, refresh) {
var label = this.editor_ui.querySelector("#obj-local-" + box.obj_local_id);
if (label) {
label.vertices = this.translate_vertices_to_global(
box.world,
psr_to_xyz(box.position, box.scale, box.rotation)
);
if (refresh) {
var best_pos = this.compute_best_position(label.vertices);
var pos = this.coord_to_pixel(best_pos);
label.style.top = Math.round(pos.y) + "px";
label.style.left = Math.round(pos.x) + "px";
label.className = label.orgClassName;
if (pos.out_view) {
label.className += " label-out-view";
}
}
}
}
remove_box(box) {
var label = this.editor_ui.querySelector("#obj-local-" + box.obj_local_id);
if (label) label.remove();
}
set_color_scheme(color_scheme) {
this.color_scheme = color_scheme;
}
update_color(label) {
if (this.color_scheme == "id") {
label.className = "float-label color-" + (label.obj_track_id % 33);
} // by id
else {
label.className = "float-label " + label.obj_type;
}
label.orgClassName = label.className;
}
add_label(box) {
var label = document.createElement("div");
label.id = "obj-local-" + box.obj_local_id;
var _self = this;
label.update_text = function () {
let label_text = '';
label_text += categoryZh[this.obj_type];
label_text += "
";
if (this.obj_attr) {
label_text += '';
label_text += this.obj_attr;
label_text += "
";
}
label_text += '';
label_text += this.obj_track_id;
label_text += "
";
this.innerHTML = label_text;
};
label.obj_type = box.obj_type;
label.obj_local_id = box.obj_local_id;
label.obj_track_id = box.obj_track_id;
label.obj_attr = box.obj_attr;
label.update_text();
this.update_color(label);
label.vertices = this.translate_vertices_to_global(
box.world,
psr_to_xyz(box.position, box.scale, box.rotation)
);
var best_pos = this.compute_best_position(label.vertices);
best_pos = this.coord_to_pixel(best_pos);
var pos = best_pos;
label.style.top = Math.round(pos.y) + "px";
label.style.left = Math.round(pos.x) + "px";
if (pos.out_view) {
label.className += " label-out-view";
}
this.labelsUi.appendChild(label);
let self = this;
label.onclick = () => {
this.on_label_clicked(box);
};
}
coord_to_pixel(p) {
var width = this.container.clientWidth,
height = this.container.clientHeight;
var widthHalf = width / 2,
heightHalf = height / 2;
var ret = {
x: p.x * widthHalf + widthHalf + 10,
y: -(p.y * heightHalf) + heightHalf - 10,
out_view:
p.x > 0.9 ||
p.x < -0.6 ||
p.y < -0.9 ||
p.y > 0.9 ||
p.z < -1 ||
p.z > 1,
// p.x<-0.6 to prevent it from appearing ontop of sideviews.
};
return ret;
}
compute_best_position(vertices) {
var _self = this;
var camera_p = [0, 1, 2, 3, 4, 5, 6, 7].map(function (i) {
return new THREE.Vector3(
vertices[i * 4 + 0],
vertices[i * 4 + 1],
vertices[i * 4 + 2]
);
});
camera_p.forEach(function (x) {
x.project(_self.view.camera);
});
var visible_p = camera_p;
var best_p = { x: -1, y: -1, z: -2 };
visible_p.forEach(function (p) {
if (p.x > best_p.x) {
best_p.x = p.x;
}
if (p.y > best_p.y) {
best_p.y = p.y;
}
if (p.z > best_p.z) {
best_p.z = p.z;
}
});
return best_p;
}
}
export { FloatLabelManager, FastToolBox };