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.
1559 lines
42 KiB
JavaScript
1559 lines
42 KiB
JavaScript
import { matmul2 } from "./util.js";
|
|
|
|
import { Quaternion, Vector3 } from "./lib/three.module.js";
|
|
|
|
class ProjectiveView {
|
|
constructor(
|
|
ui,
|
|
cfg,
|
|
on_edge_changed,
|
|
on_direction_changed,
|
|
on_auto_shrink,
|
|
on_moved,
|
|
on_scale,
|
|
on_wheel,
|
|
on_fit_size,
|
|
on_auto_rotate,
|
|
on_reset_rotate,
|
|
on_focus,
|
|
on_box_remove,
|
|
fn_isActive
|
|
) {
|
|
this.ui = ui;
|
|
this.cfg = cfg;
|
|
this.on_edge_changed = on_edge_changed;
|
|
this.on_direction_changed = on_direction_changed;
|
|
this.on_auto_shrink = on_auto_shrink;
|
|
this.on_moved = on_moved;
|
|
this.on_scale = on_scale;
|
|
this.on_wheel = on_wheel;
|
|
this.on_fit_size = on_fit_size;
|
|
this.on_auto_rotate = on_auto_rotate;
|
|
this.on_reset_rotate = on_reset_rotate;
|
|
this.on_focus = on_focus;
|
|
this.on_box_remove = on_box_remove;
|
|
this.isActive = fn_isActive;
|
|
|
|
this.lines = {
|
|
top: ui.querySelector("#line-top"),
|
|
bottom: ui.querySelector("#line-bottom"),
|
|
left: ui.querySelector("#line-left"),
|
|
right: ui.querySelector("#line-right"),
|
|
direction: ui.querySelector("#line-direction"),
|
|
};
|
|
|
|
this.orgPointInd = ui.querySelector("#origin-point-indicator");
|
|
|
|
this.svg = ui.querySelector("#view-svg");
|
|
|
|
this.handles = {
|
|
top: ui.querySelector("#line-top-handle"),
|
|
bottom: ui.querySelector("#line-bottom-handle"),
|
|
left: ui.querySelector("#line-left-handle"),
|
|
right: ui.querySelector("#line-right-handle"),
|
|
direction: ui.querySelector("#line-direction-handle"),
|
|
|
|
topleft: ui.querySelector("#top-left-handle"),
|
|
topright: ui.querySelector("#top-right-handle"),
|
|
bottomleft: ui.querySelector("#bottom-left-handle"),
|
|
bottomright: ui.querySelector("#bottom-right-handle"),
|
|
|
|
move: ui.querySelector("#move-handle"),
|
|
};
|
|
|
|
this.buttons = {
|
|
fit_position: ui.querySelector("#v-fit-position"),
|
|
fit_size: ui.querySelector("#v-fit-size"),
|
|
fit_rotation: ui.querySelector("#v-fit-rotation"),
|
|
fit_all: ui.querySelector("#v-fit-all"),
|
|
reset_rotation: ui.querySelector("#v-reset-rotation"),
|
|
fit_moving_direction: ui.querySelector("#v-fit-moving-direction"),
|
|
};
|
|
|
|
ui.onkeydown = this.on_key_down.bind(this);
|
|
ui.onmouseenter = (event) => {
|
|
if (this.isActive()) {
|
|
ui.focus();
|
|
|
|
ui.querySelector("#v-buttons").style.display = "inherit";
|
|
|
|
if (this.on_focus) this.on_focus();
|
|
}
|
|
};
|
|
ui.onmouseleave = (event) => {
|
|
if (this.showButtonsTimer) clearTimeout(this.showButtonsTimer);
|
|
|
|
this.hide_buttons();
|
|
|
|
ui.blur();
|
|
};
|
|
|
|
ui.onwheel = (event) => {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
this.on_wheel(event.deltaY);
|
|
};
|
|
|
|
this.install_edge_hanler("left", this.handles.left, this.lines, {
|
|
x: -1,
|
|
y: 0,
|
|
});
|
|
this.install_edge_hanler("right", this.handles.right, this.lines, {
|
|
x: 1,
|
|
y: 0,
|
|
});
|
|
this.install_edge_hanler("top", this.handles.top, this.lines, {
|
|
x: 0,
|
|
y: 1,
|
|
});
|
|
this.install_edge_hanler("bottom", this.handles.bottom, this.lines, {
|
|
x: 0,
|
|
y: -1,
|
|
});
|
|
this.install_edge_hanler("top,left", this.handles.topleft, this.lines, {
|
|
x: -1,
|
|
y: 1,
|
|
});
|
|
this.install_edge_hanler("top,right", this.handles.topright, this.lines, {
|
|
x: 1,
|
|
y: 1,
|
|
});
|
|
this.install_edge_hanler(
|
|
"bottom,left",
|
|
this.handles.bottomleft,
|
|
this.lines,
|
|
{ x: -1, y: -1 }
|
|
);
|
|
this.install_edge_hanler(
|
|
"bottom,right",
|
|
this.handles.bottomright,
|
|
this.lines,
|
|
{ x: 1, y: -1 }
|
|
);
|
|
this.install_edge_hanler(
|
|
"left,right,top,bottom",
|
|
this.handles.move,
|
|
this.lines,
|
|
null
|
|
);
|
|
|
|
if (this.on_direction_changed) {
|
|
this.install_direction_handler("line-direction");
|
|
}
|
|
|
|
this.install_buttons();
|
|
}
|
|
|
|
mouse_start_pos = null;
|
|
|
|
view_handle_dimension = {
|
|
//dimension of the enclosed box
|
|
x: 0, //width
|
|
y: 0, //height
|
|
};
|
|
|
|
view_center = {
|
|
x: 0,
|
|
y: 0,
|
|
};
|
|
|
|
line(name) {
|
|
return this.lines[name];
|
|
}
|
|
|
|
show_lines() {
|
|
let theme = document.documentElement.className;
|
|
|
|
let lineColor = "yellow";
|
|
if (theme == "theme-light") lineColor = "red";
|
|
|
|
for (var l in this.lines) {
|
|
this.lines[l].style.stroke = lineColor;
|
|
}
|
|
}
|
|
hide_lines() {
|
|
for (var l in this.lines) {
|
|
this.lines[l].style.stroke = "#00000000";
|
|
}
|
|
}
|
|
|
|
hightlight_line(line) {
|
|
let theme = document.documentElement.className;
|
|
|
|
let lineColor = "red";
|
|
if (theme == "theme-light") lineColor = "blue";
|
|
|
|
line.style.stroke = lineColor;
|
|
}
|
|
|
|
disable_handle_except(exclude) {
|
|
for (var h in this.handles) {
|
|
if (this.handles[h] != exclude) this.handles[h].style.display = "none";
|
|
}
|
|
}
|
|
|
|
enable_handles() {
|
|
for (var h in this.handles) {
|
|
this.handles[h].style.display = "inherit";
|
|
}
|
|
}
|
|
|
|
move_lines(delta, direction) {
|
|
var x1 = this.view_center.x - this.view_handle_dimension.x / 2;
|
|
var y1 = this.view_center.y - this.view_handle_dimension.y / 2;
|
|
var x2 = this.view_center.x + this.view_handle_dimension.x / 2;
|
|
var y2 = this.view_center.y + this.view_handle_dimension.y / 2;
|
|
|
|
if (direction) {
|
|
if (direction.x == 1) {
|
|
//right
|
|
x2 += delta.x;
|
|
} else if (direction.x == -1) {
|
|
//left
|
|
x1 += delta.x;
|
|
}
|
|
|
|
if (direction.y == -1) {
|
|
//bottom
|
|
y2 += delta.y;
|
|
} else if (direction.y == 1) {
|
|
//top
|
|
y1 += delta.y;
|
|
}
|
|
} else {
|
|
x1 += delta.x;
|
|
y1 += delta.y;
|
|
x2 += delta.x;
|
|
y2 += delta.y;
|
|
}
|
|
|
|
this.set_line_pos(
|
|
Math.ceil(x1),
|
|
Math.ceil(x2),
|
|
Math.ceil(y1),
|
|
Math.ceil(y2)
|
|
);
|
|
}
|
|
|
|
set_line_pos(x1, x2, y1, y2) {
|
|
this.lines.top.setAttribute("x1", "0%");
|
|
this.lines.top.setAttribute("y1", y1);
|
|
this.lines.top.setAttribute("x2", "100%");
|
|
this.lines.top.setAttribute("y2", y1);
|
|
|
|
this.lines.bottom.setAttribute("x1", "0%");
|
|
this.lines.bottom.setAttribute("y1", y2);
|
|
this.lines.bottom.setAttribute("x2", "100%");
|
|
this.lines.bottom.setAttribute("y2", y2);
|
|
|
|
this.lines.left.setAttribute("x1", x1);
|
|
this.lines.left.setAttribute("y1", "0%");
|
|
this.lines.left.setAttribute("x2", x1);
|
|
this.lines.left.setAttribute("y2", "100%");
|
|
|
|
this.lines.right.setAttribute("x1", x2);
|
|
this.lines.right.setAttribute("y1", "0%");
|
|
this.lines.right.setAttribute("x2", x2);
|
|
this.lines.right.setAttribute("y2", "100%");
|
|
}
|
|
|
|
set_org_point_ind_pos(viewWidth, viewHeight, objPos, objRot) {
|
|
/*
|
|
cos -sin
|
|
sin cos
|
|
*
|
|
objPos.x
|
|
objPos.y
|
|
|
|
*/
|
|
let c = Math.cos(objRot); // for topview, x goes upward, so we add pi/2
|
|
let s = Math.sin(objRot);
|
|
|
|
let relx = c * -objPos.x + s * -objPos.y;
|
|
let rely = -s * -objPos.x + c * -objPos.y;
|
|
|
|
let radius = Math.sqrt(
|
|
(viewWidth * viewWidth) / 4 + (viewHeight * viewHeight) / 4
|
|
);
|
|
let distToRog = Math.sqrt(relx * relx + rely * rely);
|
|
|
|
let indPosX3d = (relx * radius) / distToRog;
|
|
let indPosY3d = (rely * radius) / distToRog;
|
|
|
|
let indPosX = -indPosY3d;
|
|
let indPosY = -indPosX3d;
|
|
|
|
let dotRelPos = 0.8;
|
|
// now its pixel coordinates, x goes right, y goes down
|
|
if (indPosX > (viewWidth / 2) * dotRelPos) {
|
|
let shrinkRatio = ((viewWidth / 2) * dotRelPos) / indPosX;
|
|
|
|
indPosX = (viewWidth / 2) * dotRelPos;
|
|
indPosY = indPosY * shrinkRatio;
|
|
}
|
|
|
|
if (indPosX < (-viewWidth / 2) * dotRelPos) {
|
|
let shrinkRatio = ((-viewWidth / 2) * dotRelPos) / indPosX;
|
|
|
|
indPosX = (-viewWidth / 2) * dotRelPos;
|
|
indPosY = indPosY * shrinkRatio;
|
|
}
|
|
|
|
if (indPosY > (viewHeight / 2) * dotRelPos) {
|
|
let shrinkRatio = ((viewHeight / 2) * dotRelPos) / indPosY;
|
|
|
|
indPosY = (viewHeight / 2) * dotRelPos;
|
|
indPosX = indPosX * shrinkRatio;
|
|
}
|
|
|
|
if (indPosY < (-viewHeight / 2) * dotRelPos) {
|
|
let shrinkRatio = ((-viewHeight / 2) * dotRelPos) / indPosY;
|
|
|
|
indPosY = (-viewHeight / 2) * dotRelPos;
|
|
indPosX = indPosX * shrinkRatio;
|
|
}
|
|
|
|
this.orgPointInd.setAttribute("cx", viewWidth / 2 + indPosX);
|
|
this.orgPointInd.setAttribute("cy", viewHeight / 2 + indPosY);
|
|
}
|
|
|
|
// when direction handler is draging
|
|
rotate_lines(theta) {
|
|
console.log(theta);
|
|
theta = -theta - Math.PI / 2;
|
|
console.log(theta);
|
|
// we use rotation matrix
|
|
var trans_matrix = [
|
|
Math.cos(theta),
|
|
Math.sin(theta),
|
|
this.view_center.x,
|
|
-Math.sin(theta),
|
|
Math.cos(theta),
|
|
this.view_center.y,
|
|
0,
|
|
0,
|
|
1,
|
|
];
|
|
|
|
var points; /*= `[
|
|
-view_handle_dimension.x/2, view_handle_dimension.x/2,view_handle_dimension.x/2,-view_handle_dimension.x/2, 0,
|
|
-view_handle_dimension.y/2, -view_handle_dimension.y/2,view_handle_dimension.y/2, view_handle_dimension.y/2, -this.view_center.y,
|
|
1,1,1,1,1
|
|
]; */
|
|
var trans_points; //= matmul2(trans_matrix, points, 3);
|
|
|
|
//console.log(points);
|
|
//var trans_points ;//= matmul2(trans_matrix, points, 3);
|
|
//console.log(trans_points);
|
|
|
|
points = [0, -this.view_center.y, 1];
|
|
trans_points = matmul2(trans_matrix, points, 3);
|
|
this.lines.direction.setAttribute("x2", Math.ceil(trans_points[0]));
|
|
this.lines.direction.setAttribute("y2", Math.ceil(trans_points[1]));
|
|
|
|
points = [
|
|
-this.view_center.x,
|
|
this.view_center.x, //-view_handle_dimension.x/2, view_handle_dimension.x/2,
|
|
-this.view_handle_dimension.y / 2,
|
|
-this.view_handle_dimension.y / 2,
|
|
1,
|
|
1,
|
|
];
|
|
var trans_points = matmul2(trans_matrix, points, 3);
|
|
|
|
this.lines.top.setAttribute("x1", Math.ceil(trans_points[0]));
|
|
this.lines.top.setAttribute("y1", Math.ceil(trans_points[0 + 2]));
|
|
this.lines.top.setAttribute("x2", Math.ceil(trans_points[1]));
|
|
this.lines.top.setAttribute("y2", Math.ceil(trans_points[1 + 2]));
|
|
|
|
points = [
|
|
-this.view_handle_dimension.x / 2,
|
|
-this.view_handle_dimension.x / 2,
|
|
-this.view_center.y,
|
|
this.view_center.y,
|
|
1,
|
|
1,
|
|
];
|
|
trans_points = matmul2(trans_matrix, points, 3);
|
|
|
|
this.lines.left.setAttribute("x1", Math.ceil(trans_points[0]));
|
|
this.lines.left.setAttribute("y1", Math.ceil(trans_points[0 + 2]));
|
|
this.lines.left.setAttribute("x2", Math.ceil(trans_points[1]));
|
|
this.lines.left.setAttribute("y2", Math.ceil(trans_points[1 + 2]));
|
|
|
|
points = [
|
|
this.view_center.x,
|
|
-this.view_center.x,
|
|
this.view_handle_dimension.y / 2,
|
|
this.view_handle_dimension.y / 2,
|
|
1,
|
|
1,
|
|
];
|
|
trans_points = matmul2(trans_matrix, points, 3);
|
|
this.lines.bottom.setAttribute("x1", Math.ceil(trans_points[1]));
|
|
this.lines.bottom.setAttribute("y1", Math.ceil(trans_points[1 + 2]));
|
|
this.lines.bottom.setAttribute("x2", Math.ceil(trans_points[0]));
|
|
this.lines.bottom.setAttribute("y2", Math.ceil(trans_points[0 + 2]));
|
|
|
|
points = [
|
|
this.view_handle_dimension.x / 2,
|
|
this.view_handle_dimension.x / 2,
|
|
-this.view_center.y,
|
|
this.view_center.y,
|
|
1,
|
|
1,
|
|
];
|
|
trans_points = matmul2(trans_matrix, points, 3);
|
|
|
|
this.lines.right.setAttribute("x1", Math.ceil(trans_points[0]));
|
|
this.lines.right.setAttribute("y1", Math.ceil(trans_points[0 + 2]));
|
|
this.lines.right.setAttribute("x2", Math.ceil(trans_points[1]));
|
|
this.lines.right.setAttribute("y2", Math.ceil(trans_points[1 + 2]));
|
|
}
|
|
|
|
update_view_handle(viewport, obj_dimension, obj_pos, obj_rot) {
|
|
var viewport_ratio = viewport.width / viewport.height;
|
|
var box_ratio = obj_dimension.x / obj_dimension.y;
|
|
|
|
var width = 0;
|
|
var height = 0;
|
|
|
|
if (box_ratio > viewport_ratio) {
|
|
//handle width is viewport.width*2/3
|
|
width = (viewport.width * (2 / 3)) / viewport.zoom_ratio;
|
|
height = width / box_ratio;
|
|
} else {
|
|
//handle height is viewport.height*2/3
|
|
height = (viewport.height * 2) / 3 / viewport.zoom_ratio;
|
|
width = height * box_ratio;
|
|
}
|
|
|
|
this.view_handle_dimension.x = width;
|
|
this.view_handle_dimension.y = height;
|
|
|
|
// viewport width/height is position-irrelavent
|
|
// so x and y is relative value.
|
|
var x = viewport.width / 2; //viewport.left + viewport.width/2;
|
|
var y = viewport.height / 2; //viewport.bottom - viewport.height/2;
|
|
|
|
var left = x - width / 2;
|
|
var right = x + width / 2;
|
|
var top = y - height / 2;
|
|
var bottom = y + height / 2;
|
|
|
|
this.view_center.x = x;
|
|
this.view_center.y = y;
|
|
|
|
this.set_line_pos(left, right, top, bottom);
|
|
|
|
if (obj_pos && obj_rot) {
|
|
this.set_org_point_ind_pos(
|
|
viewport.width,
|
|
viewport.height,
|
|
obj_pos,
|
|
obj_rot
|
|
);
|
|
}
|
|
|
|
// note when the object is too thin, the height/width value may be negative,
|
|
// this causes error reporting, but we just let it be.
|
|
var de = this.handles.left;
|
|
de.setAttribute("x", Math.ceil(left - 10));
|
|
de.setAttribute("y", "0%"); //Math.ceil(top+10));
|
|
de.setAttribute("height", "100%"); //Math.ceil(bottom-top-20));
|
|
de.setAttribute("width", 20);
|
|
|
|
de = this.handles.right;
|
|
de.setAttribute("x", Math.ceil(right - 10));
|
|
de.setAttribute("y", "0%"); //Math.ceil(top+10));
|
|
de.setAttribute("height", "100%"); //Math.ceil(bottom-top-20));
|
|
de.setAttribute("width", 20);
|
|
|
|
de = this.handles.top;
|
|
de.setAttribute("x", "0%"); //Math.ceil(left+10));
|
|
de.setAttribute("y", Math.ceil(top - 10));
|
|
de.setAttribute("width", "100%"); //Math.ceil(right-left-20));
|
|
de.setAttribute("height", 20);
|
|
|
|
de = this.handles.bottom;
|
|
de.setAttribute("x", "0%"); //Math.ceil(left+10));
|
|
de.setAttribute("y", Math.ceil(bottom - 10));
|
|
de.setAttribute("width", "100%"); //Math.ceil(right-left-20));
|
|
de.setAttribute("height", 20);
|
|
|
|
de = this.handles.topleft;
|
|
de.setAttribute("x", Math.ceil(left - 10));
|
|
de.setAttribute("y", Math.ceil(top - 10));
|
|
|
|
de = this.handles.topright;
|
|
de.setAttribute("x", Math.ceil(right - 10));
|
|
de.setAttribute("y", Math.ceil(top - 10));
|
|
|
|
de = this.handles.bottomleft;
|
|
de.setAttribute("x", Math.ceil(left - 10));
|
|
de.setAttribute("y", Math.ceil(bottom - 10));
|
|
|
|
de = this.handles.bottomright;
|
|
de.setAttribute("x", Math.ceil(right - 10));
|
|
de.setAttribute("y", Math.ceil(bottom - 10));
|
|
|
|
//direction
|
|
if (this.on_direction_changed) {
|
|
de = this.lines.direction;
|
|
de.setAttribute("x1", Math.ceil((left + right) / 2));
|
|
de.setAttribute("y1", Math.ceil((top + bottom) / 2));
|
|
de.setAttribute("x2", Math.ceil((left + right) / 2));
|
|
de.setAttribute("y2", Math.ceil(0));
|
|
|
|
de = this.handles.direction;
|
|
de.setAttribute("x", Math.ceil((left + right) / 2 - 10));
|
|
de.setAttribute("y", 0); //Math.ceil(top+10));
|
|
de.setAttribute("height", Math.ceil((bottom - top) / 2 - 10 + top));
|
|
} else {
|
|
de = this.lines.direction;
|
|
de.style.display = "none";
|
|
|
|
de = this.handles.direction;
|
|
de.style.display = "none";
|
|
}
|
|
|
|
// move handle
|
|
de = this.ui.querySelector("#move-handle");
|
|
de.setAttribute("x", Math.ceil((left + right) / 2 - 10));
|
|
de.setAttribute("y", Math.ceil((top + bottom) / 2 - 10));
|
|
}
|
|
|
|
showButtonsTimer = null;
|
|
hide_buttons(delay) {
|
|
this.ui.querySelector("#v-buttons").style.display = "none";
|
|
|
|
if (delay) {
|
|
if (this.showButtonsTimer) {
|
|
clearTimeout(this.showButtonsTimer);
|
|
}
|
|
|
|
this.showButtonsTimer = setTimeout(() => {
|
|
this.ui.querySelector("#v-buttons").style.display = "inherit";
|
|
}, 200);
|
|
}
|
|
}
|
|
|
|
hide() {
|
|
this.hide_lines(this.lines);
|
|
}
|
|
//install_move_handler();
|
|
|
|
install_edge_hanler(name, handle, lines, direction) {
|
|
handle.onmouseenter = () => {
|
|
if (this.isActive()) {
|
|
this.show_lines();
|
|
|
|
if (name)
|
|
name.split(",").forEach((n) => this.hightlight_line(lines[n]));
|
|
}
|
|
};
|
|
handle.onmouseleave = () => this.hide();
|
|
|
|
// handle.onmouseup = event=>{
|
|
// if (event.which!=1)
|
|
// return;
|
|
|
|
// //line.style["stroke-dasharray"]="none";
|
|
// //hide();
|
|
// handle.onmouseleave = hide;
|
|
// };
|
|
|
|
handle.ondblclick = (event) => {
|
|
if (event.which != 1) return;
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
this.on_auto_shrink(direction); //if double click on 'move' handler, the directoin is null
|
|
};
|
|
|
|
handle.onmousedown = (event) => {
|
|
if (event.which != 1) return;
|
|
|
|
var svg = this.svg;
|
|
|
|
//
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
|
|
this.disable_handle_except(handle);
|
|
this.hide_buttons();
|
|
|
|
handle.onmouseleave = null;
|
|
|
|
this.mouse_start_pos = { x: event.layerX, y: event.layerY };
|
|
let mouse_cur_pos = {
|
|
x: this.mouse_start_pos.x,
|
|
y: this.mouse_start_pos.y,
|
|
};
|
|
|
|
console.log(this.mouse_start_pos);
|
|
|
|
svg.onmouseup = (event) => {
|
|
svg.onmousemove = null;
|
|
svg.onmouseup = null;
|
|
this.enable_handles();
|
|
// restore color
|
|
//hide();
|
|
handle.onmouseleave = this.hide.bind(this);
|
|
|
|
this.ui.querySelector("#v-buttons").style.display = "inherit";
|
|
|
|
var handle_delta = {
|
|
x: mouse_cur_pos.x - this.mouse_start_pos.x,
|
|
y: -(mouse_cur_pos.y - this.mouse_start_pos.y), //reverse since it'll be used by 3d-coord system
|
|
};
|
|
|
|
console.log("delta", handle_delta);
|
|
if (
|
|
handle_delta.x == 0 &&
|
|
handle_delta.y == 0 &&
|
|
!event.ctrlKey &&
|
|
!event.shiftKey
|
|
) {
|
|
return;
|
|
}
|
|
|
|
var ratio_delta = {
|
|
x: handle_delta.x / this.view_handle_dimension.x,
|
|
y: handle_delta.y / this.view_handle_dimension.y,
|
|
};
|
|
|
|
if (direction) {
|
|
this.on_edge_changed(
|
|
ratio_delta,
|
|
direction,
|
|
event.ctrlKey,
|
|
event.shiftKey
|
|
);
|
|
|
|
// if (event.ctrlKey){
|
|
// this.on_auto_shrink(direction);
|
|
// }
|
|
} else {
|
|
// when intall handler for mover, the direcion is left null
|
|
this.on_moved(ratio_delta);
|
|
}
|
|
};
|
|
|
|
svg.onmousemove = (event) => {
|
|
if (event.which != 1) return;
|
|
|
|
mouse_cur_pos = { x: event.layerX, y: event.layerY };
|
|
|
|
var handle_delta = {
|
|
x: mouse_cur_pos.x - this.mouse_start_pos.x,
|
|
y: mouse_cur_pos.y - this.mouse_start_pos.y, // don't reverse direction
|
|
};
|
|
|
|
this.move_lines(handle_delta, direction);
|
|
};
|
|
};
|
|
}
|
|
|
|
install_direction_handler(linename) {
|
|
var handle = this.ui.querySelector("#" + linename + "-handle");
|
|
var line = this.ui.querySelector("#" + linename);
|
|
var svg = this.svg;
|
|
|
|
handle.onmouseenter = (event) => {
|
|
if (this.isActive()) {
|
|
this.show_lines();
|
|
this.hightlight_line(line);
|
|
}
|
|
};
|
|
|
|
handle.onmouseleave = () => this.hide();
|
|
|
|
handle.ondblclick = (event) => {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
//transform_bbox(this_axis+"_rotate_reverse");
|
|
this.on_direction_changed(Math.PI);
|
|
};
|
|
|
|
// function hide(event){
|
|
// line.style.stroke="#00000000";
|
|
// };
|
|
|
|
// handle.onmouseup = event=>{
|
|
// if (event.which!=1)
|
|
// return;
|
|
// //line.style["stroke-dasharray"]="none";
|
|
// //line.style.stroke="#00000000";
|
|
// handle.onmouseleave = hide;
|
|
// };
|
|
|
|
handle.onmousedown = (event) => {
|
|
if (event.which != 1) return;
|
|
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
|
|
//line.style.stroke="yellow";
|
|
handle.onmouseleave = null;
|
|
//show_lines(lines);
|
|
|
|
this.disable_handle_except(handle);
|
|
|
|
this.hide_buttons();
|
|
|
|
let handle_center = {
|
|
x: parseInt(line.getAttribute("x1")),
|
|
};
|
|
|
|
this.mouse_start_pos = {
|
|
x: event.layerX,
|
|
y: event.layerY,
|
|
|
|
handle_offset_x: handle_center.x - event.layerX,
|
|
};
|
|
|
|
let mouse_cur_pos = {
|
|
x: this.mouse_start_pos.x,
|
|
y: this.mouse_start_pos.y,
|
|
};
|
|
|
|
console.log(this.mouse_start_pos);
|
|
|
|
let theta = 0;
|
|
|
|
svg.onmousemove = (event) => {
|
|
mouse_cur_pos = { x: event.layerX, y: event.layerY };
|
|
|
|
let handle_center_cur_pos = {
|
|
x: mouse_cur_pos.x + this.mouse_start_pos.handle_offset_x,
|
|
y: mouse_cur_pos.y,
|
|
};
|
|
|
|
theta = Math.atan2(
|
|
handle_center_cur_pos.y - this.view_center.y,
|
|
handle_center_cur_pos.x - this.view_center.x
|
|
);
|
|
console.log(theta);
|
|
|
|
this.rotate_lines(theta);
|
|
};
|
|
|
|
svg.onmouseup = (event) => {
|
|
svg.onmousemove = null;
|
|
svg.onmouseup = null;
|
|
|
|
// restore color
|
|
//line.style.stroke="#00000000";
|
|
this.enable_handles();
|
|
handle.onmouseleave = this.hide.bind(this);
|
|
|
|
this.ui.querySelector("#v-buttons").style.display = "inherit";
|
|
|
|
if (theta == 0) {
|
|
return;
|
|
}
|
|
|
|
this.on_direction_changed(-theta - Math.PI / 2, event.ctrlKey);
|
|
};
|
|
};
|
|
}
|
|
|
|
on_key_down(event) {
|
|
switch (event.key) {
|
|
case "e":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_direction_changed(-this.cfg.rotateStep, event.ctrlKey);
|
|
this.hide_buttons(true);
|
|
return true;
|
|
case "q":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_direction_changed(this.cfg.rotateStep, event.ctrlKey);
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "f":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_direction_changed(-this.cfg.rotateStep, true);
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "r":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_direction_changed(this.cfg.rotateStep, true);
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "g":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_direction_changed(Math.PI, false);
|
|
break;
|
|
case "w":
|
|
case "ArrowUp":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_moved({ x: 0, y: this.cfg.moveStep });
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "s":
|
|
if (!event.ctrlKey) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_moved({ x: 0, y: -this.cfg.moveStep });
|
|
this.hide_buttons(true);
|
|
break;
|
|
} else {
|
|
console.log("ctrl+s");
|
|
}
|
|
break;
|
|
case "ArrowDown":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_moved({ x: 0, y: -this.cfg.moveStep });
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "a":
|
|
if (event.ctrlKey) {
|
|
break;
|
|
}
|
|
// no break;
|
|
case "ArrowLeft":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_moved({ x: -this.cfg.moveStep, y: 0 });
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "d":
|
|
if (event.ctrlKey) {
|
|
console.log("ctrl+d");
|
|
this.on_box_remove();
|
|
break;
|
|
}
|
|
case "ArrowRight":
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.on_moved({ x: this.cfg.moveStep, y: 0 });
|
|
this.hide_buttons(true);
|
|
break;
|
|
case "Delete":
|
|
this.on_box_remove();
|
|
break;
|
|
}
|
|
}
|
|
|
|
install_buttons() {
|
|
let buttons = this.buttons;
|
|
let ignore_left_mouse_down = (event) => {
|
|
if (event.which == 1) {
|
|
event.stopPropagation();
|
|
}
|
|
};
|
|
|
|
if (buttons.fit_rotation) {
|
|
buttons.fit_rotation.onmousedown = ignore_left_mouse_down;
|
|
buttons.fit_rotation.onclick = (event) => {
|
|
this.on_auto_rotate("noscaling");
|
|
};
|
|
}
|
|
|
|
if (buttons.fit_position && this.on_fit_size) {
|
|
buttons.fit_position.onmousedown = ignore_left_mouse_down;
|
|
buttons.fit_position.onclick = (event) => {
|
|
this.on_fit_size("noscaling");
|
|
};
|
|
}
|
|
|
|
if (buttons.fit_size && this.on_fit_size) {
|
|
buttons.fit_size.onmousedown = ignore_left_mouse_down;
|
|
buttons.fit_size.onclick = (event) => {
|
|
this.on_fit_size();
|
|
};
|
|
}
|
|
|
|
buttons.fit_all.onmousedown = ignore_left_mouse_down;
|
|
buttons.fit_all.onclick = (event) => {
|
|
//console.log("auto rotate button clicked.");
|
|
this.on_auto_rotate();
|
|
//event.currentTarget.blur(); // this bluring will disable focus on sideview also, which is not expected.
|
|
};
|
|
|
|
if (buttons.reset_rotation) {
|
|
buttons.reset_rotation.onmousedown = ignore_left_mouse_down;
|
|
|
|
buttons.reset_rotation.onclick = (event) => {
|
|
//console.log("auto rotate button clicked.");
|
|
this.on_reset_rotate();
|
|
//event.currentTarget.blur(); // this bluring will disable focus on sideview also, which is not expected.
|
|
};
|
|
}
|
|
|
|
if (buttons.fit_moving_direction) {
|
|
buttons.fit_moving_direction.onmousedown = ignore_left_mouse_down;
|
|
buttons.fit_moving_direction.onclick = (event) => {
|
|
//console.log("auto rotate button clicked.");
|
|
this.on_auto_rotate("noscaling", "moving-direction");
|
|
//event.currentTarget.blur(); // this bluring will disable focus on sideview also, which is not expected.
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
class ProjectiveViewOps {
|
|
constructor(
|
|
ui,
|
|
editorCfg,
|
|
boxEditor,
|
|
views,
|
|
boxOp,
|
|
func_on_box_changed,
|
|
func_on_box_remove
|
|
) {
|
|
this.ui = ui;
|
|
this.cfg = editorCfg;
|
|
this.on_box_changed = func_on_box_changed;
|
|
this.views = views;
|
|
this.boxOp = boxOp;
|
|
this.boxEditor = boxEditor;
|
|
//internals
|
|
var scope = this;
|
|
|
|
function default_on_del() {
|
|
if (scope.box) {
|
|
func_on_box_remove(scope.box);
|
|
}
|
|
}
|
|
|
|
function default_on_focus() {
|
|
// this is a long chain!
|
|
if (scope.box && scope.box.boxEditor.boxEditorManager)
|
|
scope.box.boxEditor.boxEditorManager.globalHeader.update_box_info(
|
|
scope.box
|
|
);
|
|
}
|
|
|
|
// direction: 1, -1
|
|
// axis: x,y,z
|
|
|
|
function auto_shrink(extreme, direction) {
|
|
for (var axis in direction) {
|
|
if (direction[axis] != 0) {
|
|
var end = "max";
|
|
if (direction[axis] === -1) {
|
|
end = "min";
|
|
}
|
|
|
|
var delta =
|
|
direction[axis] * extreme[end][axis] - scope.box.scale[axis] / 2;
|
|
|
|
console.log(extreme, delta);
|
|
scope.boxOp.translate_box(
|
|
scope.box,
|
|
axis,
|
|
(direction[axis] * delta) / 2
|
|
);
|
|
scope.box.scale[axis] += delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
//direction is in 3d
|
|
function auto_stick(delta, direction, use_box_bottom_as_limit) {
|
|
//let old_dim = scope.box.world.lidar.get_points_dimmension_of_box(scope.box, true);
|
|
//let old_scale = scope.box.scale;
|
|
|
|
let virtbox = {
|
|
position: {
|
|
x: scope.box.position.x,
|
|
y: scope.box.position.y,
|
|
z: scope.box.position.z,
|
|
},
|
|
scale: {
|
|
x: scope.box.scale.x,
|
|
y: scope.box.scale.y,
|
|
z: scope.box.scale.z,
|
|
},
|
|
rotation: {
|
|
x: scope.box.rotation.x,
|
|
y: scope.box.rotation.y,
|
|
z: scope.box.rotation.z,
|
|
},
|
|
};
|
|
|
|
scope.boxOp.translate_box(virtbox, "x", (delta.x / 2) * direction.x);
|
|
scope.boxOp.translate_box(virtbox, "y", (delta.y / 2) * direction.y);
|
|
scope.boxOp.translate_box(virtbox, "z", (delta.z / 2) * direction.z);
|
|
|
|
virtbox.scale.x += delta.x;
|
|
virtbox.scale.y += delta.y;
|
|
virtbox.scale.z += delta.z;
|
|
|
|
// note dim is the relative value
|
|
let new_dim = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
virtbox,
|
|
use_box_bottom_as_limit
|
|
);
|
|
|
|
for (var axis in direction) {
|
|
if (direction[axis] != 0) {
|
|
var end = "max";
|
|
if (direction[axis] === -1) {
|
|
end = "min";
|
|
}
|
|
|
|
//scope.box.scale[axis]/2 - direction[axis]*extreme[end][axis];
|
|
var truedelta =
|
|
delta[axis] / 2 +
|
|
direction[axis] * new_dim[end][axis] -
|
|
scope.box.scale[axis] / 2;
|
|
|
|
console.log(new_dim, delta);
|
|
scope.boxOp.translate_box(
|
|
scope.box,
|
|
axis,
|
|
direction[axis] * truedelta
|
|
);
|
|
//scope.box.scale[axis] -= delta;
|
|
}
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_edge_changed(delta, direction) {
|
|
console.log(delta);
|
|
|
|
scope.boxOp.translate_box(scope.box, "x", (delta.x / 2) * direction.x);
|
|
scope.boxOp.translate_box(scope.box, "y", (delta.y / 2) * direction.y);
|
|
scope.boxOp.translate_box(scope.box, "z", (delta.z / 2) * direction.z);
|
|
|
|
scope.box.scale.x += delta.x;
|
|
scope.box.scale.y += delta.y;
|
|
scope.box.scale.z += delta.z;
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function get_wheel_multiplier(wheel_direction) {
|
|
var multiplier = 1.0;
|
|
if (wheel_direction > 0) {
|
|
multiplier = 1.1;
|
|
} else {
|
|
multiplier = 0.9;
|
|
}
|
|
return multiplier;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// direction is null if triggered by dbclick on 'move' handler
|
|
function on_z_auto_shrink(direction) {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
true
|
|
);
|
|
|
|
if (!direction) {
|
|
["x", "y"].forEach(function (axis) {
|
|
scope.boxOp.translate_box(
|
|
scope.box,
|
|
axis,
|
|
(extreme.max[axis] + extreme.min[axis]) / 2
|
|
);
|
|
scope.box.scale[axis] = extreme.max[axis] - extreme.min[axis];
|
|
});
|
|
} else {
|
|
direction = {
|
|
x: direction.y,
|
|
y: -direction.x,
|
|
z: 0,
|
|
};
|
|
|
|
auto_shrink(extreme, direction);
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_z_edge_changed(ratio, direction2d, autoShrink, lockScale) {
|
|
var delta = {
|
|
x: scope.box.scale.x * ratio.y * direction2d.y,
|
|
y: scope.box.scale.y * ratio.x * direction2d.x,
|
|
z: 0,
|
|
};
|
|
|
|
let direction3d = {
|
|
x: direction2d.y,
|
|
y: -direction2d.x,
|
|
z: 0,
|
|
};
|
|
|
|
if (!autoShrink && !lockScale) {
|
|
on_edge_changed(delta, direction3d);
|
|
} else if (autoShrink) {
|
|
on_edge_changed(delta, direction3d);
|
|
on_z_auto_shrink(direction2d);
|
|
} else if (lockScale) {
|
|
auto_stick(delta, direction3d, true);
|
|
}
|
|
}
|
|
|
|
function on_z_direction_changed(theta, sticky) {
|
|
// points indices shall be obtained before rotation.
|
|
let box = scope.box;
|
|
scope.boxOp.rotate_z(box, theta, sticky);
|
|
scope.on_box_changed(box);
|
|
}
|
|
|
|
//ratio.y vertical
|
|
//ratio.x horizental
|
|
// box.x vertical
|
|
// box.y horizental
|
|
|
|
function limit_move_step(v, min_abs_v) {
|
|
if (v < 0) return Math.min(v, -min_abs_v);
|
|
else if (v > 0) return Math.max(v, min_abs_v);
|
|
else return v;
|
|
}
|
|
|
|
function on_z_moved(ratio) {
|
|
let delta = {
|
|
x: scope.box.scale.x * ratio.y,
|
|
y: -scope.box.scale.y * ratio.x,
|
|
};
|
|
|
|
delta.x = limit_move_step(delta.x, 0.02);
|
|
delta.y = limit_move_step(delta.y, 0.02);
|
|
|
|
// scope.boxOp.translate_box(scope.box, "x", delta.x);
|
|
// scope.boxOp.translate_box(scope.box, "y", delta.y);
|
|
|
|
// scope.on_box_changed(scope.box);
|
|
scope.boxEditor.onOpCmd({
|
|
op: "translate",
|
|
params: {
|
|
delta,
|
|
},
|
|
});
|
|
}
|
|
|
|
function on_z_scaled(ratio) {
|
|
ratio = {
|
|
x: ratio.y,
|
|
y: ratio.x,
|
|
z: 0,
|
|
};
|
|
|
|
for (var axis in ratio) {
|
|
if (ratio[axis] != 0) {
|
|
scope.box.scale[axis] *= 1 + ratio[axis];
|
|
}
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_z_wheel(wheel_direction) {
|
|
let multiplier = get_wheel_multiplier(wheel_direction);
|
|
let newRatio = (scope.views[0].zoom_ratio *= multiplier);
|
|
scope.boxEditor.updateViewZoomRatio(0, newRatio);
|
|
//z_view_handle.update_view_handle(scope.views[0].getViewPort(), {x: scope.box.scale.y, y:scope.box.scale.x});
|
|
}
|
|
|
|
function on_z_fit_size(noscaling) {
|
|
if (noscaling) {
|
|
// fit position only
|
|
scope.boxOp.auto_rotate_xyz(
|
|
scope.box,
|
|
null,
|
|
{ x: true, y: true, z: false },
|
|
scope.on_box_changed,
|
|
noscaling,
|
|
"dontrotate"
|
|
);
|
|
} else {
|
|
scope.boxOp.fit_size(scope.box, ["x", "y"]);
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
}
|
|
|
|
function on_z_auto_rotate(noscaling, rotate_method) {
|
|
if (rotate_method == "moving-direction") {
|
|
let estimatedRot = scope.boxOp.estimate_rotation_by_moving_direciton(
|
|
scope.box
|
|
);
|
|
|
|
if (estimatedRot) {
|
|
scope.box.rotation.z = estimatedRot.z;
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
} else {
|
|
scope.boxOp.auto_rotate_xyz(
|
|
scope.box,
|
|
null,
|
|
noscaling ? null : { x: false, y: false, z: true },
|
|
scope.on_box_changed,
|
|
noscaling
|
|
);
|
|
}
|
|
}
|
|
|
|
function on_z_reset_rotate() {
|
|
scope.box.rotation.z = 0;
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
this.z_view_handle = new ProjectiveView(
|
|
scope.ui.querySelector("#z-view-manipulator"),
|
|
editorCfg,
|
|
on_z_edge_changed,
|
|
on_z_direction_changed,
|
|
on_z_auto_shrink,
|
|
on_z_moved,
|
|
on_z_scaled,
|
|
on_z_wheel,
|
|
on_z_fit_size,
|
|
on_z_auto_rotate,
|
|
on_z_reset_rotate,
|
|
default_on_focus,
|
|
default_on_del,
|
|
this.isActive.bind(this)
|
|
);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function on_y_edge_changed(ratio, direction2d, autoShrink, lockScale) {
|
|
var delta = {
|
|
x: scope.box.scale.x * ratio.x * direction2d.x,
|
|
z: scope.box.scale.z * ratio.y * direction2d.y,
|
|
y: 0,
|
|
};
|
|
|
|
let direction3d = {
|
|
x: direction2d.x,
|
|
z: direction2d.y,
|
|
y: 0,
|
|
};
|
|
|
|
if (!autoShrink && !lockScale) {
|
|
on_edge_changed(delta, direction3d);
|
|
} else if (autoShrink) {
|
|
on_edge_changed(delta, direction3d);
|
|
on_y_auto_shrink(direction2d);
|
|
} else if (lockScale) {
|
|
auto_stick(delta, direction3d, direction2d.y === 0);
|
|
}
|
|
}
|
|
|
|
function on_y_auto_shrink(direction) {
|
|
if (!direction) {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
false
|
|
);
|
|
["x", "z"].forEach(function (axis) {
|
|
scope.boxOp.translate_box(
|
|
scope.box,
|
|
axis,
|
|
(extreme.max[axis] + extreme.min[axis]) / 2
|
|
);
|
|
scope.box.scale[axis] = extreme.max[axis] - extreme.min[axis];
|
|
});
|
|
} else {
|
|
direction = {
|
|
x: direction.x,
|
|
y: 0,
|
|
z: direction.y,
|
|
};
|
|
|
|
if (direction.z != 0) {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
false
|
|
);
|
|
auto_shrink(extreme, direction);
|
|
} else {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
true
|
|
);
|
|
auto_shrink(extreme, direction);
|
|
}
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_y_moved(ratio) {
|
|
var delta = {
|
|
x: limit_move_step(scope.box.scale.x * ratio.x, 0.02),
|
|
z: limit_move_step(scope.box.scale.z * ratio.y, 0.02),
|
|
};
|
|
|
|
// scope.boxOp.translate_box(scope.box, "x", delta.x);
|
|
// scope.boxOp.translate_box(scope.box, "z", delta.z);
|
|
|
|
// scope.on_box_changed(scope.box);
|
|
scope.boxEditor.onOpCmd({
|
|
op: "translate",
|
|
params: {
|
|
delta,
|
|
},
|
|
});
|
|
}
|
|
|
|
function on_y_direction_changed(theta, sticky) {
|
|
scope.boxOp.change_rotation_y(
|
|
scope.box,
|
|
theta,
|
|
sticky,
|
|
scope.on_box_changed
|
|
);
|
|
}
|
|
|
|
function on_y_scaled(ratio) {
|
|
ratio = {
|
|
x: ratio.x,
|
|
y: 0,
|
|
z: ratio.y,
|
|
};
|
|
|
|
for (var axis in ratio) {
|
|
if (ratio[axis] != 0) {
|
|
scope.box.scale[axis] *= 1 + ratio[axis];
|
|
}
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_y_wheel(wheel_direction) {
|
|
let multiplier = get_wheel_multiplier(wheel_direction);
|
|
let newRatio = (scope.views[1].zoom_ratio *= multiplier);
|
|
scope.boxEditor.updateViewZoomRatio(1, newRatio);
|
|
}
|
|
|
|
function on_y_reset_rotate() {
|
|
scope.box.rotation.y = 0;
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_y_auto_rotate() {
|
|
scope.boxOp.auto_rotate_y(scope.box, scope.on_box_changed);
|
|
}
|
|
|
|
this.y_view_handle = new ProjectiveView(
|
|
scope.ui.querySelector("#y-view-manipulator"),
|
|
editorCfg,
|
|
on_y_edge_changed,
|
|
on_y_direction_changed,
|
|
on_y_auto_shrink,
|
|
on_y_moved,
|
|
on_y_scaled,
|
|
on_y_wheel,
|
|
null,
|
|
on_y_auto_rotate,
|
|
on_y_reset_rotate,
|
|
default_on_focus,
|
|
default_on_del,
|
|
this.isActive.bind(this)
|
|
);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function on_x_edge_changed(ratio, direction2d, autoShrink, lockScale) {
|
|
var delta = {
|
|
y: scope.box.scale.y * ratio.x * direction2d.x,
|
|
z: scope.box.scale.z * ratio.y * direction2d.y,
|
|
x: 0,
|
|
};
|
|
|
|
let direction3d = {
|
|
y: -direction2d.x,
|
|
z: direction2d.y,
|
|
x: 0,
|
|
};
|
|
|
|
if (!autoShrink && !lockScale) {
|
|
on_edge_changed(delta, direction3d);
|
|
} else if (autoShrink) {
|
|
on_edge_changed(delta, direction3d);
|
|
on_x_auto_shrink(direction2d);
|
|
} else if (lockScale) {
|
|
auto_stick(delta, direction3d, direction2d.y === 0);
|
|
}
|
|
}
|
|
|
|
function on_x_auto_shrink(direction) {
|
|
if (!direction) {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
false
|
|
);
|
|
|
|
["y", "z"].forEach(function (axis) {
|
|
scope.boxOp.translate_box(
|
|
scope.box,
|
|
axis,
|
|
(extreme.max[axis] + extreme.min[axis]) / 2
|
|
);
|
|
scope.box.scale[axis] = extreme.max[axis] - extreme.min[axis];
|
|
});
|
|
} else {
|
|
direction = {
|
|
x: 0,
|
|
y: -direction.x,
|
|
z: direction.y,
|
|
};
|
|
|
|
if (direction.z != 0) {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
false
|
|
);
|
|
auto_shrink(extreme, direction);
|
|
} else {
|
|
var extreme = scope.box.world.lidar.get_points_dimmension_of_box(
|
|
scope.box,
|
|
true
|
|
);
|
|
auto_shrink(extreme, direction);
|
|
}
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_x_moved(ratio) {
|
|
var delta = {
|
|
y: limit_move_step(scope.box.scale.y * -ratio.x, 0.02),
|
|
z: limit_move_step(scope.box.scale.z * ratio.y, 0.02),
|
|
};
|
|
|
|
// scope.boxOp.translate_box(scope.box, "y", delta.y);
|
|
// scope.boxOp.translate_box(scope.box, "z", delta.z);
|
|
|
|
// scope.on_box_changed(scope.box);
|
|
|
|
scope.boxEditor.onOpCmd({
|
|
op: "translate",
|
|
params: {
|
|
delta,
|
|
},
|
|
});
|
|
}
|
|
|
|
function on_x_direction_changed(theta, sticky) {
|
|
scope.boxOp.change_rotation_x(
|
|
scope.box,
|
|
-theta,
|
|
sticky,
|
|
scope.on_box_changed
|
|
);
|
|
}
|
|
|
|
function on_x_scaled(ratio) {
|
|
ratio = {
|
|
y: ratio.x,
|
|
z: ratio.y,
|
|
};
|
|
|
|
for (var axis in ratio) {
|
|
if (ratio[axis] != 0) {
|
|
scope.box.scale[axis] *= 1 + ratio[axis];
|
|
}
|
|
}
|
|
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_x_wheel(wheel_direction) {
|
|
let multiplier = get_wheel_multiplier(wheel_direction);
|
|
let newRatio = (scope.views[2].zoom_ratio *= multiplier);
|
|
scope.boxEditor.updateViewZoomRatio(2, newRatio);
|
|
}
|
|
|
|
function on_x_reset_rotate() {
|
|
scope.box.rotation.x = 0;
|
|
scope.on_box_changed(scope.box);
|
|
}
|
|
|
|
function on_x_auto_rotate() {
|
|
scope.boxOp.auto_rotate_x(scope.box, scope.on_box_changed);
|
|
}
|
|
|
|
this.x_view_handle = new ProjectiveView(
|
|
scope.ui.querySelector("#x-view-manipulator"),
|
|
editorCfg,
|
|
on_x_edge_changed,
|
|
on_x_direction_changed,
|
|
on_x_auto_shrink,
|
|
on_x_moved,
|
|
on_x_scaled,
|
|
on_x_wheel,
|
|
null,
|
|
on_x_auto_rotate,
|
|
on_x_reset_rotate,
|
|
default_on_focus,
|
|
default_on_del,
|
|
this.isActive.bind(this)
|
|
);
|
|
} // end of constructor
|
|
|
|
// exports
|
|
|
|
hideAllHandlers() {
|
|
this.ui
|
|
.querySelectorAll(".subview-svg")
|
|
.forEach((ui) => (ui.style.display = "none"));
|
|
//this.ui.querySelectorAll(".v-buttons-wrapper").forEach(ui=>ui.style.display="none");
|
|
}
|
|
|
|
showAllHandlers() {
|
|
this.ui
|
|
.querySelectorAll(".subview-svg")
|
|
.forEach((ui) => (ui.style.display = ""));
|
|
//this.ui.querySelectorAll(".v-buttons-wrapper").forEach(ui=>ui.style.display="");
|
|
}
|
|
|
|
isActive() {
|
|
return !!this.box;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// public interface
|
|
|
|
box = undefined;
|
|
attachBox(box) {
|
|
this.box = box;
|
|
//this.show();
|
|
this.showAllHandlers();
|
|
this.update_view_handle(box);
|
|
}
|
|
detach(box) {
|
|
this.box = null;
|
|
this.hideAllHandlers();
|
|
}
|
|
|
|
update_view_handle() {
|
|
if (this.box) {
|
|
let boxPos = this.box.position;
|
|
|
|
this.z_view_handle.update_view_handle(
|
|
this.views[0].getViewPort(),
|
|
{ x: this.box.scale.y, y: this.box.scale.x },
|
|
{ x: boxPos.x, y: boxPos.y },
|
|
this.box.rotation.z
|
|
);
|
|
this.y_view_handle.update_view_handle(this.views[1].getViewPort(), {
|
|
x: this.box.scale.x,
|
|
y: this.box.scale.z,
|
|
});
|
|
this.x_view_handle.update_view_handle(this.views[2].getViewPort(), {
|
|
x: this.box.scale.y,
|
|
y: this.box.scale.z,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
export { ProjectiveViewOps };
|