未验证 提交 d4788ee6 编写于 作者: B Boris Sekachev 提交者: GitHub

Multiple fixes in 3D drawing, see description (#5410)

### Motivation and context
Related #3438 

- When dblclick one of sideviews during drawing - UI is broken
- When mouseleave sideviews during drawing - bbox disappears, need to
draw again
- Sometimes multiple draw boxes exist on view

Example:

![bug_1](https://user-images.githubusercontent.com/40690378/205139685-2c348b4f-30c0-4bcc-a101-e07c880ff358.gif)
上级 9b0d963d
......@@ -83,6 +83,7 @@ non-ascii paths while adding files from "Connected file share" (issue #4428)
- Fixed job exporting (<https://github.com/opencv/cvat/pull/5282>)
- Visibility and ignored information fail to be loaded (MOT dataset format) (<https://github.com/opencv/cvat/pull/5270>)
- Added force logout on CVAT app start if token is missing (<https://github.com/opencv/cvat/pull/5331>)
- Drawing issues on 3D canvas (<https://github.com/opencv/cvat/pull/5410>)
- Missed token with using social account authentication (<https://github.com/opencv/cvat/pull/5344>)
- An exception when run export for an empty task (<https://github.com/opencv/cvat/pull/5396>)
- Fixed FBRS serverless function runtime error on images with alpha channel (<https://github.com/opencv/cvat/pull/5384>)
......
{
"name": "cvat-canvas3d",
"version": "0.0.3",
"version": "0.0.4",
"description": "Part of Computer Vision Annotation Tool which presents its canvas3D library",
"main": "src/canvas3d.ts",
"scripts": {
......
......@@ -101,7 +101,7 @@ class Canvas3dImpl implements Canvas3d {
}
public activate(clientID: number | null, attributeID: number | null = null): void {
this.model.activate(String(clientID), attributeID);
this.model.activate(typeof clientID === 'number' ? String(clientID) : null, attributeID);
}
public fit(): void {
......
......@@ -110,7 +110,6 @@ export interface Canvas3dDataModel {
imageIsDeleted: boolean;
drawData: DrawData;
mode: Mode;
objectUpdating: boolean;
exception: Error | null;
objects: any[];
groupedObjects: any[];
......@@ -154,7 +153,6 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
height: 0,
width: 0,
},
objectUpdating: false,
objects: [],
groupedObjects: [],
image: null,
......@@ -203,11 +201,7 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
}
if (frameData.number === this.data.imageID && frameData.deleted === this.data.imageIsDeleted) {
if (this.data.objectUpdating) {
return;
}
this.data.objects = objectStates;
this.data.objectUpdating = true;
this.notify(UpdateReasons.OBJECTS_UPDATED);
return;
}
......
......@@ -133,7 +133,6 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.action = {
loading: false,
oldState: '',
scan: null,
selectable: true,
frameCoordinates: {
......@@ -255,9 +254,10 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
cancelable: true,
detail: {
state: {
...initState,
attributes: { ...initState.attributes },
shapeType: 'cuboid',
frame: this.model.data.imageID,
group: initState.group?.id || null,
points,
label,
},
......@@ -266,7 +266,6 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
},
}),
);
this.action.oldState = Mode.DRAW;
}
});
......@@ -508,7 +507,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
}
private setDefaultZoom(): void {
if (this.model.data.activeElement === 'null') {
if (this.model.data.activeElement === null) {
Object.keys(this.views).forEach((view: string): void => {
const viewType = this.views[view as keyof Views];
if (view !== ViewType.PERSPECTIVE) {
......@@ -580,7 +579,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
if (event.detail !== 1) return;
if (this.model.mode === Mode.DRAG_CANVAS) return;
const { clientID } = this.model.data.activeElement;
if (clientID === 'null') return;
if (clientID === null) return;
const canvas = this.views[view as keyof Views].renderer.domElement;
const rect = canvas.getBoundingClientRect();
const { mouseVector } = this.views[view as keyof Views].rayCaster as { mouseVector: THREE.Vector2 };
......@@ -605,7 +604,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
event.preventDefault();
if (this.model.mode === Mode.DRAG_CANVAS) return;
const { clientID } = this.model.data.activeElement;
if (clientID === 'null') return;
if (clientID === null) return;
const canvas = this.views[view as keyof Views].renderer.domElement;
const rect = canvas.getBoundingClientRect();
const { mouseVector } = this.views[view as keyof Views].rayCaster as { mouseVector: THREE.Vector2 };
......@@ -664,7 +663,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
private completeActions(): void {
const { scan, detected } = this.action;
if (this.model.mode === Mode.DRAG_CANVAS) return;
if (this.model.data.activeElement.clientID === null) return;
if (!detected) {
this.resetActions();
return;
......@@ -807,6 +806,11 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.setupObject(object, true);
}
this.action.loading = false;
if (this.mode === Mode.DRAW) {
// if setupObjects was called during drawing, need to restore drawable object
this.views.perspective.scene.children[0].add(this.cube.perspective);
}
}
}
......@@ -871,23 +875,33 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
} else if (reason === UpdateReasons.SHAPE_ACTIVATED) {
const { clientID } = this.model.data.activeElement;
this.setupObjects();
if (clientID !== 'null') {
if (clientID !== null) {
this.setDefaultZoom();
}
} else if (reason === UpdateReasons.DRAW) {
const data: DrawData = this.controller.drawData;
this.cube = new CuboidModel('line', '#ffffff');
if (data.redraw) {
const object = this.views.perspective.scene.getObjectByName(String(data.redraw));
if (object) {
this.cube.perspective = object.clone() as THREE.Mesh;
object.visible = false;
}
} else if (data.initialState) {
this.model.data.activeElement.clientID = 'null';
this.setupObjects();
this.cube = this.setupObject(data.initialState, false);
} else {
this.cube = new CuboidModel('line', '#ffffff');
}
this.cube.setName('drawTemplate');
this.model.data.activeElement.clientID = null;
this.setupObjects();
if (data.redraw) {
const object = this.views.perspective.scene.getObjectByName(String(data.redraw));
if (object) {
object.visible = false;
}
}
this.setHelperVisibility(false);
} else if (reason === UpdateReasons.OBJECTS_UPDATED) {
this.setupObjects();
......@@ -899,7 +913,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
cancelable: true,
}),
);
this.model.data.activeElement.clientID = 'null';
this.model.data.activeElement.clientID = null;
this.setupObjects();
} else if (reason === UpdateReasons.CANCEL) {
if (this.mode === Mode.DRAG_CANVAS) {
......@@ -933,7 +947,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.onGroupDone(this.model.data.groupData.grouped);
} else {
this.model.data.groupData.grouped = [];
this.model.data.activeElement.clientID = 'null';
this.model.data.activeElement.clientID = null;
this.setupObjects();
}
}
......@@ -1235,15 +1249,11 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
private renderRayCaster = (viewType: RenderView): void => {
viewType.rayCaster.renderer.setFromCamera(viewType.rayCaster.mouseVector, viewType.camera);
if (this.mode === Mode.DRAW) {
const intersects = this.views.perspective.rayCaster.renderer.intersectObjects(
this.views.perspective.scene.children,
false,
);
if (intersects.length > 0) {
this.views.perspective.scene.children[0].add(this.cube.perspective);
const newPoints = intersects[0].point;
this.cube.perspective.position.copy(newPoints);
this.views.perspective.renderer.domElement.style.cursor = 'default';
const [intersection] = viewType.rayCaster.renderer.intersectObjects(this.views.perspective.scene.children);
if (intersection) {
const object = this.views.perspective.scene.getObjectByName('drawTemplate');
const { x, y, z } = intersection.point;
object.position.set(x, y, z);
}
} else if (this.mode === Mode.IDLE && !this.isPerspectiveBeingDragged) {
const { children } = this.views.perspective.scene.children[0];
......@@ -1300,7 +1310,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.renderRayCaster(viewType);
}
const { clientID } = this.model.data.activeElement;
if (clientID !== 'null' && view !== ViewType.PERSPECTIVE) {
if (clientID !== null && view !== ViewType.PERSPECTIVE) {
viewType.rayCaster.renderer.setFromCamera(viewType.rayCaster.mouseVector, viewType.camera);
// First Scan
if (this.action.scan === view) {
......@@ -1324,6 +1334,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
}
}
});
if (this.action.detachCam && this.action.detachCamRef === this.model.data.activeElement.clientID) {
try {
this.detachCamera(null);
......@@ -1332,16 +1343,10 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.action.detachCam = false;
}
}
if (this.model.mode === Mode.BUSY && !this.action.loading) {
if (this.action.oldState !== '') {
this.model.mode = this.action.oldState;
this.action.oldState = '';
} else {
this.model.mode = Mode.IDLE;
}
} else if (this.model.data.objectUpdating && !this.action.loading) {
this.model.data.objectUpdating = false;
}
}
private adjustPerspectiveCameras(): void {
......
// Copyright (C) 2021-2022 Intel Corporation
// Copyright (C) 2022 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册