Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
3D annotation view significant performance update & refactoring (cvat…
Browse files Browse the repository at this point in the history
…-ai#5442)

<!-- Raised an issue to propose your change
(https://github.com/cvat-ai/cvat/issues).
It helps to avoid duplication of efforts from multiple independent
contributors.
Discuss your ideas with maintainers to be sure that changes will be
approved and merged.
Read the
[CONTRIBUTION](https://github.com/cvat-ai/cvat/blob/develop/CONTRIBUTING.md)
guide. -->

<!-- Provide a general summary of your changes in the Title above -->

### Motivation and context
<!-- Why is this change required? What problem does it solve? If it
fixes an open
issue, please link to the issue here. Describe your changes in detail,
add
screenshots. -->

### How has this been tested?
<!-- Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc. -->

### Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply.
If an item isn't applicable by a reason then ~~explicitly
strikethrough~~ the whole
line. If you don't do that github will show an incorrect process for the
pull request.
If you're unsure about any of these, don't hesitate to ask. We're here
to help! -->
- [x] I submit my changes into the `develop` branch
- [ ] I have added a description of my changes into
[CHANGELOG](https://github.com/cvat-ai/cvat/blob/develop/CHANGELOG.md)
file
- [ ] I have updated the [documentation](
https://github.com/cvat-ai/cvat/blob/develop/README.md#documentation)
accordingly
- [ ] I have added tests to cover my changes
- [ ] I have linked related issues ([read github docs](

https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword))
- [x] I have increased versions of npm packages if it is necessary
([cvat-canvas](https://github.com/cvat-ai/cvat/tree/develop/cvat-canvas#versioning),

[cvat-core](https://github.com/cvat-ai/cvat/tree/develop/cvat-core#versioning),
[cvat-data](https://github.com/cvat-ai/cvat/tree/develop/cvat-data#versioning)
and
[cvat-ui](https://github.com/cvat-ai/cvat/tree/develop/cvat-ui#versioning))

### License

- [x] I submit _my code changes_ under the same [MIT License](
https://github.com/cvat-ai/cvat/blob/develop/LICENSE) that covers the
project.
  Feel free to contact the maintainers if that's a concern.
  • Loading branch information
bsekachev authored and mikhail-treskin committed Jul 1, 2023
1 parent efd84fd commit 5f95ec4
Show file tree
Hide file tree
Showing 11 changed files with 939 additions and 816 deletions.
3 changes: 2 additions & 1 deletion cvat-canvas3d/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas3d",
"version": "0.0.5",
"version": "0.0.6",
"description": "Part of Computer Vision Annotation Tool which presents its canvas3D library",
"main": "src/canvas3d.ts",
"scripts": {
Expand All @@ -17,6 +17,7 @@
],
"devDependencies": {},
"dependencies": {
"cvat-core": "link:./../cvat-core",
"@types/three": "^0.125.3",
"camera-controls": "^1.25.3",
"three": "^0.126.1"
Expand Down
11 changes: 6 additions & 5 deletions cvat-canvas3d/src/typescript/canvas3dController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
//
// SPDX-License-Identifier: MIT

import { ObjectState } from '.';
import {
Canvas3dModel, Mode, DrawData, ActiveElement, GroupData, Configuration,
} from './canvas3dModel';

export interface Canvas3dController {
readonly drawData: DrawData;
readonly activeElement: ActiveElement;
readonly selected: any;
readonly groupData: GroupData;
readonly configuration: Configuration;
readonly imageIsDeleted: boolean;
readonly objects: ObjectState[];
mode: Mode;
group(groupData: GroupData): void;
}
Expand Down Expand Up @@ -41,10 +42,6 @@ export class Canvas3dControllerImpl implements Canvas3dController {
return this.model.data.activeElement;
}

public get selected(): any {
return this.model.data.selected;
}

public get imageIsDeleted(): any {
return this.model.imageIsDeleted;
}
Expand All @@ -57,6 +54,10 @@ export class Canvas3dControllerImpl implements Canvas3dController {
return this.model.configuration;
}

public get objects(): ObjectState[] {
return this.model.objects;
}

public group(groupData: GroupData): void {
this.model.group(groupData);
}
Expand Down
109 changes: 71 additions & 38 deletions cvat-canvas3d/src/typescript/canvas3dModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//
// SPDX-License-Identifier: MIT

import { ObjectState } from '.';
import { MasterImpl } from './master';

export interface Size {
Expand All @@ -17,7 +18,7 @@ export interface ActiveElement {

export interface GroupData {
enabled: boolean;
grouped?: [];
grouped: ObjectState[];
}

export interface Configuration {
Expand Down Expand Up @@ -76,24 +77,20 @@ export enum UpdateReasons {
DRAW = 'draw',
SELECT = 'select',
CANCEL = 'cancel',
DATA_FAILED = 'data_failed',
DRAG_CANVAS = 'drag_canvas',
SHAPE_ACTIVATED = 'shape_activated',
GROUP = 'group',
FITTED_CANVAS = 'fitted_canvas',
CONFIG_UPDATED = 'config_updated',
SHAPES_CONFIG_UPDATED = 'shapes_config_updated',
}

export enum Mode {
IDLE = 'idle',
DRAG = 'drag',
RESIZE = 'resize',
DRAW = 'draw',
EDIT = 'edit',
INTERACT = 'interact',
DRAG_CANVAS = 'drag_canvas',
GROUP = 'group',
BUSY = 'busy',
}

export interface Canvas3dDataModel {
Expand All @@ -106,13 +103,15 @@ export interface Canvas3dDataModel {
imageIsDeleted: boolean;
drawData: DrawData;
mode: Mode;
exception: Error | null;
objects: any[];
groupedObjects: any[];
selected: any;
objects: ObjectState[];
shapeProperties: ShapeProperties;
groupData: GroupData;
configuration: Configuration;
isFrameUpdating: boolean;
nextSetupRequest: {
frameData: any;
objectStates: ObjectState[];
} | null;
}

export interface Canvas3dModel {
Expand All @@ -121,17 +120,20 @@ export interface Canvas3dModel {
readonly imageIsDeleted: boolean;
readonly groupData: GroupData;
readonly configuration: Configuration;
setup(frameData: any, objectStates: any[]): void;
readonly objects: ObjectState[];
setup(frameData: any, objectStates: ObjectState[]): void;
isAbleToChangeFrame(): boolean;
draw(drawData: DrawData): void;
cancel(): void;
dragCanvas(enable: boolean): void;
activate(clientID: string | null, attributeID: number | null): void;
configureShapes(shapeProperties: any): void;
configureShapes(shapeProperties: ShapeProperties): void;
configure(configuration: Configuration): void;
fit(): void;
group(groupData: GroupData): void;
destroy(): void;
updateCanvasObjects(): void;
unlockFrameUpdating(): void;
}

export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
Expand All @@ -149,7 +151,6 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
width: 0,
},
objects: [],
groupedObjects: [],
image: null,
imageID: null,
imageOffset: 0,
Expand All @@ -163,12 +164,10 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
initialState: null,
},
mode: Mode.IDLE,
exception: null,
groupData: {
enabled: false,
grouped: [],
},
selected: null,
shapeProperties: {
opacity: 40,
outlined: false,
Expand All @@ -179,16 +178,38 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
configuration: {
resetZoom: false,
},
isFrameUpdating: false,
nextSetupRequest: null,
};
}

public setup(frameData: any, objectStates: any[]): void {
public updateCanvasObjects(): void {
this.notify(UpdateReasons.OBJECTS_UPDATED);
}

public unlockFrameUpdating(): void {
this.data.isFrameUpdating = false;
if (this.data.nextSetupRequest) {
try {
const { frameData, objectStates } = this.data.nextSetupRequest;
this.setup(frameData, objectStates);
} finally {
this.data.nextSetupRequest = null;
}
}
}

public setup(frameData: any, objectStates: ObjectState[]): void {
if (this.data.imageID !== frameData.number) {
if ([Mode.EDIT, Mode.DRAG, Mode.RESIZE].includes(this.data.mode)) {
if ([Mode.EDIT].includes(this.data.mode)) {
throw Error(`Canvas is busy. Action: ${this.data.mode}`);
}
}
if ([Mode.EDIT, Mode.BUSY].includes(this.data.mode)) {

if (this.data.isFrameUpdating) {
this.data.nextSetupRequest = {
frameData, objectStates,
};
return;
}

Expand All @@ -198,31 +219,25 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
return;
}

this.data.isFrameUpdating = true;
this.data.imageID = frameData.number;
frameData
.data((): void => {
this.data.image = null;
this.notify(UpdateReasons.IMAGE_CHANGED);
})
.then((data: Image): void => {
if (frameData.number !== this.data.imageID) {
// already another image
return;
}

this.data.imageSize = {
height: frameData.height as number,
width: frameData.width as number,
};
this.data.imageIsDeleted = frameData.deleted;
this.data.image = data;
this.notify(UpdateReasons.IMAGE_CHANGED);
this.data.objects = objectStates;
this.notify(UpdateReasons.OBJECTS_UPDATED);
this.notify(UpdateReasons.IMAGE_CHANGED);
})
.catch((exception: any): void => {
this.data.exception = exception;
this.notify(UpdateReasons.DATA_FAILED);
this.data.isFrameUpdating = false;
throw exception;
});
}
Expand All @@ -235,9 +250,13 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
return this.data.mode;
}

public get objects(): ObjectState[] {
return [...this.data.objects];
}

public isAbleToChangeFrame(): boolean {
const isUnable = [Mode.DRAG, Mode.EDIT, Mode.RESIZE, Mode.INTERACT, Mode.BUSY].includes(this.data.mode) ||
(this.data.mode === Mode.DRAW && typeof this.data.drawData.redraw === 'number');
const isUnable = [Mode.EDIT].includes(this.data.mode) ||
this.data.isFrameUpdating || (this.data.mode === Mode.DRAW && typeof this.data.drawData.redraw === 'number');
return !isUnable;
}

Expand Down Expand Up @@ -288,11 +307,11 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
this.notify(UpdateReasons.DRAG_CANVAS);
}

public activate(clientID: string, attributeID: number | null): void {
public activate(clientID: string | null, attributeID: number | null): void {
if (this.data.activeElement.clientID === clientID && this.data.activeElement.attributeID === attributeID) {
return;
}
if (this.data.mode !== Mode.IDLE) {
if (this.data.mode !== Mode.IDLE && clientID !== null) {
throw Error(`Canvas is busy. Action: ${this.data.mode}`);
}
if (typeof clientID === 'number') {
Expand Down Expand Up @@ -334,13 +353,27 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
}

public configureShapes(shapeProperties: ShapeProperties): void {
this.data.drawData.enabled = false;
this.data.mode = Mode.IDLE;
this.cancel();
this.data.shapeProperties = {
...shapeProperties,
};
this.notify(UpdateReasons.OBJECTS_UPDATED);
if (typeof shapeProperties.opacity === 'number') {
this.data.shapeProperties.opacity = Math.max(0, Math.min(shapeProperties.opacity, 100));
}

if (typeof shapeProperties.selectedOpacity === 'number') {
this.data.shapeProperties.selectedOpacity = Math.max(0, Math.min(shapeProperties.selectedOpacity, 100));
}

if (['Label', 'Instance', 'Group'].includes(shapeProperties.colorBy)) {
this.data.shapeProperties.colorBy = shapeProperties.colorBy;
}

if (typeof shapeProperties.outlined === 'boolean') {
this.data.shapeProperties.outlined = shapeProperties.outlined;
}

if (typeof shapeProperties.outlineColor === 'string') {
this.data.shapeProperties.outlineColor = shapeProperties.outlineColor;
}

this.notify(UpdateReasons.SHAPES_CONFIG_UPDATED);
}

public fit(): void {
Expand Down
Loading

0 comments on commit 5f95ec4

Please sign in to comment.