Fixed redrawing a skeleton (Shift+N) (#4906)

* Fixed redrawing a skeleton (Shift+N)

* Updated version

* Added cypress test

* Enabled disabled tests

* Updated test IDs
main
Boris Sekachev 4 years ago committed by GitHub
parent 65a2610636
commit efd43637a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.15.1", "version": "2.15.2",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library", "description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts", "main": "src/canvas.ts",
"scripts": { "scripts": {

@ -263,7 +263,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
} }
if (data) { if (data) {
const { clientID, points } = data as any; const { clientID, elements } = data as any;
const points = data.points || elements.map((el: any) => el.points).flat();
if (typeof clientID === 'number') { if (typeof clientID === 'number') {
const event: CustomEvent = new CustomEvent('canvas.canceled', { const event: CustomEvent = new CustomEvent('canvas.canceled', {
bubbles: false, bubbles: false,

@ -1,6 +1,6 @@
{ {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.41.3", "version": "1.41.4",
"description": "CVAT single-page application", "description": "CVAT single-page application",
"main": "src/index.tsx", "main": "src/index.tsx",
"scripts": { "scripts": {

@ -1,4 +1,5 @@
// Copyright (C) 2020-2022 Intel Corporation // Copyright (C) 2020-2022 Intel Corporation
// Copyright (C) 2022 CVAT.ai Corporation
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
@ -1516,6 +1517,16 @@ export function searchEmptyFrameAsync(sessionInstance: any, frameFrom: number, f
}; };
} }
const ShapeTypeToControl: Record<ShapeType, ActiveControl> = {
[ShapeType.RECTANGLE]: ActiveControl.DRAW_RECTANGLE,
[ShapeType.POLYLINE]: ActiveControl.DRAW_POLYLINE,
[ShapeType.POLYGON]: ActiveControl.DRAW_POLYGON,
[ShapeType.POINTS]: ActiveControl.DRAW_POINTS,
[ShapeType.CUBOID]: ActiveControl.DRAW_CUBOID,
[ShapeType.ELLIPSE]: ActiveControl.DRAW_ELLIPSE,
[ShapeType.SKELETON]: ActiveControl.DRAW_SKELETON,
};
export function pasteShapeAsync(): ThunkAction { export function pasteShapeAsync(): ThunkAction {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => { return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
const { const {
@ -1528,22 +1539,7 @@ export function pasteShapeAsync(): ThunkAction {
} = getStore().getState().annotation; } = getStore().getState().annotation;
if (initialState && canvasInstance) { if (initialState && canvasInstance) {
let activeControl = ActiveControl.CURSOR; const activeControl = ShapeTypeToControl[initialState.shapeType as ShapeType] || ActiveControl.CURSOR;
if (initialState.shapeType === ShapeType.RECTANGLE) {
activeControl = ActiveControl.DRAW_RECTANGLE;
} else if (initialState.shapeType === ShapeType.POINTS) {
activeControl = ActiveControl.DRAW_POINTS;
} else if (initialState.shapeType === ShapeType.POLYGON) {
activeControl = ActiveControl.DRAW_POLYGON;
} else if (initialState.shapeType === ShapeType.POLYLINE) {
activeControl = ActiveControl.DRAW_POLYLINE;
} else if (initialState.shapeType === ShapeType.CUBOID) {
activeControl = ActiveControl.DRAW_CUBOID;
} else if (initialState.shapeType === ShapeType.ELLIPSE) {
activeControl = ActiveControl.DRAW_ELLIPSE;
} else if (initialState.shapeType === ShapeType.SKELETON) {
activeControl = ActiveControl.DRAW_SKELETON;
}
dispatch({ dispatch({
type: AnnotationActionTypes.PASTE_SHAPE, type: AnnotationActionTypes.PASTE_SHAPE,
@ -1623,21 +1619,8 @@ export function repeatDrawShapeAsync(): ThunkAction {
return; return;
} }
if (activeShapeType === ShapeType.RECTANGLE) {
activeControl = ActiveControl.DRAW_RECTANGLE; activeControl = ShapeTypeToControl[activeShapeType];
} else if (activeShapeType === ShapeType.POINTS) {
activeControl = ActiveControl.DRAW_POINTS;
} else if (activeShapeType === ShapeType.POLYGON) {
activeControl = ActiveControl.DRAW_POLYGON;
} else if (activeShapeType === ShapeType.POLYLINE) {
activeControl = ActiveControl.DRAW_POLYLINE;
} else if (activeShapeType === ShapeType.CUBOID) {
activeControl = ActiveControl.DRAW_CUBOID;
} else if (activeShapeType === ShapeType.ELLIPSE) {
activeControl = ActiveControl.DRAW_ELLIPSE;
} else if (activeShapeType === ShapeType.SKELETON) {
activeControl = ActiveControl.DRAW_SKELETON;
}
dispatch({ dispatch({
type: AnnotationActionTypes.REPEAT_DRAW_SHAPE, type: AnnotationActionTypes.REPEAT_DRAW_SHAPE,
@ -1689,31 +1672,20 @@ export function redrawShapeAsync(): ThunkAction {
if (activatedStateID !== null) { if (activatedStateID !== null) {
const [state] = states.filter((_state: any): boolean => _state.clientID === activatedStateID); const [state] = states.filter((_state: any): boolean => _state.clientID === activatedStateID);
if (state && state.objectType !== ObjectType.TAG) { if (state && state.objectType !== ObjectType.TAG) {
let activeControl = ActiveControl.CURSOR; const activeControl = ShapeTypeToControl[state.shapeType as ShapeType] || ActiveControl.CURSOR;
if (state.shapeType === ShapeType.RECTANGLE) {
activeControl = ActiveControl.DRAW_RECTANGLE;
} else if (state.shapeType === ShapeType.POINTS) {
activeControl = ActiveControl.DRAW_POINTS;
} else if (state.shapeType === ShapeType.POLYGON) {
activeControl = ActiveControl.DRAW_POLYGON;
} else if (state.shapeType === ShapeType.POLYLINE) {
activeControl = ActiveControl.DRAW_POLYLINE;
} else if (state.shapeType === ShapeType.CUBOID) {
activeControl = ActiveControl.DRAW_CUBOID;
} else if (state.shapeType === ShapeType.SKELETON) {
activeControl = ActiveControl.DRAW_SKELETON;
}
dispatch({ dispatch({
type: AnnotationActionTypes.REPEAT_DRAW_SHAPE, type: AnnotationActionTypes.REPEAT_DRAW_SHAPE,
payload: { payload: {
activeControl, activeControl,
}, },
}); });
if (canvasInstance instanceof Canvas) { if (canvasInstance instanceof Canvas) {
canvasInstance.cancel(); canvasInstance.cancel();
} }
canvasInstance.draw({ canvasInstance.draw({
skeletonSVG: state.shapeType === ShapeType.SKELETON ? state.label.structure.svg : undefined,
enabled: true, enabled: true,
redraw: activatedStateID, redraw: activatedStateID,
shapeType: state.shapeType, shapeType: state.shapeType,

@ -19,6 +19,12 @@ context('Manipulations with skeletons', () => {
text: 'skeletons pipeline', text: 'skeletons pipeline',
count: 5, count: 5,
}; };
const skeletonPosition = {
xtl: 100,
ytl: 100,
xbr: 300,
ybr: 300,
};
let taskID = null; let taskID = null;
before(() => { before(() => {
@ -135,11 +141,8 @@ context('Manipulations with skeletons', () => {
describe('Working with objects', () => { describe('Working with objects', () => {
function createSkeletonObject(shapeType) { function createSkeletonObject(shapeType) {
cy.createSkeleton({ cy.createSkeleton({
...skeletonPosition,
labelName, labelName,
xtl: 100,
ytl: 100,
xbr: 300,
ybr: 300,
type: `${shapeType[0].toUpperCase()}${shapeType.slice(1).toLowerCase()}`, type: `${shapeType[0].toUpperCase()}${shapeType.slice(1).toLowerCase()}`,
}); });
cy.get('#cvat_canvas_shape_1').should('exist').and('be.visible'); cy.get('#cvat_canvas_shape_1').should('exist').and('be.visible');
@ -172,19 +175,43 @@ context('Manipulations with skeletons', () => {
cy.removeAnnotations(); cy.removeAnnotations();
}); });
it('Creating and removing a skeleton track', () => { it('Creating, re-drawing, and removing a skeleton track', () => {
createSkeletonObject('track'); createSkeletonObject('track');
// redraw a tracked shape on the latest frame
const REDRAW_MARGIN = 400;
let prevX = Number.MAX_SAFE_INTEGER;
let prevY = Number.MAX_SAFE_INTEGER;
cy.goCheckFrameNumber(imageParams.count - 1);
cy.get('#cvat_canvas_shape_1').within(() => {
cy.get('rect').then(($rect) => {
prevX = +$rect[0].getAttribute('x');
prevY = +$rect[0].getAttribute('y');
});
});
cy.get('#cvat_canvas_shape_1').trigger('mousemove').should('have.class', 'cvat_canvas_shape_activated');
cy.get('body').trigger('keydown', { keyCode: 78, code: 'KeyN', shiftKey: true });
cy.get('.cvat-canvas-container')
.click(skeletonPosition.xtl + REDRAW_MARGIN, skeletonPosition.ytl + REDRAW_MARGIN)
.click(skeletonPosition.xbr + REDRAW_MARGIN, skeletonPosition.ybr + REDRAW_MARGIN);
cy.get('.cvat-cursor-control').should('have.class', 'cvat-active-canvas-control');
cy.get('#cvat_canvas_shape_1').within(() => {
cy.get('rect').then(($rect) => {
expect(+$rect[0].getAttribute('x')).to.be.gt(prevX);
expect(+$rect[0].getAttribute('y')).to.be.gt(prevY);
});
});
// and, finally delete the skeleton
deleteSkeleton('#cvat_canvas_shape_1', 'track', false); deleteSkeleton('#cvat_canvas_shape_1', 'track', false);
cy.removeAnnotations(); cy.removeAnnotations();
cy.goCheckFrameNumber(0);
createSkeletonObject('track'); createSkeletonObject('track');
deleteSkeleton('#cvat_canvas_shape_1', 'track', true); deleteSkeleton('#cvat_canvas_shape_1', 'track', true);
cy.removeAnnotations();
}); });
it('Splitting two skeletons and merge them back', () => { it('Splitting two skeletons and merge them back', () => {
cy.removeAnnotations();
createSkeletonObject('track'); createSkeletonObject('track');
const splittingFrame = Math.trunc(imageParams.count / 2); const splittingFrame = Math.trunc(imageParams.count / 2);
@ -195,32 +222,32 @@ context('Manipulations with skeletons', () => {
// check objects after splitting // check objects after splitting
cy.get('#cvat_canvas_shape_1').should('not.exist'); cy.get('#cvat_canvas_shape_1').should('not.exist');
cy.get('#cvat_canvas_shape_18').should('exist').and('not.be.visible'); cy.get('#cvat_canvas_shape_12').should('exist').and('not.be.visible');
cy.get('#cvat_canvas_shape_24').should('exist').and('be.visible'); cy.get('#cvat_canvas_shape_18').should('exist').and('be.visible');
cy.goToNextFrame(splittingFrame + 1); cy.goToNextFrame(splittingFrame + 1);
cy.get('#cvat_canvas_shape_18').should('not.exist'); cy.get('#cvat_canvas_shape_12').should('not.exist');
cy.get('#cvat_canvas_shape_24').should('exist').and('be.visible'); cy.get('#cvat_canvas_shape_18').should('exist').and('be.visible');
// now merge them back // now merge them back
cy.get('.cvat-merge-control').click(); cy.get('.cvat-merge-control').click();
cy.get('#cvat_canvas_shape_24').click(); cy.get('#cvat_canvas_shape_18').click();
cy.goCheckFrameNumber(0); cy.goCheckFrameNumber(0);
cy.get('#cvat_canvas_shape_18').click(); cy.get('#cvat_canvas_shape_12').click();
cy.get('body').type('m'); cy.get('body').type('m');
// and check objects after merge // and check objects after merge
cy.get('#cvat_canvas_shape_12').should('not.exist');
cy.get('#cvat_canvas_shape_18').should('not.exist'); cy.get('#cvat_canvas_shape_18').should('not.exist');
cy.get('#cvat_canvas_shape_24').should('not.exist');
cy.get('#cvat_canvas_shape_30').should('exist').and('be.visible'); cy.get('#cvat_canvas_shape_24').should('exist').and('be.visible');
cy.goCheckFrameNumber(splittingFrame + 1); cy.goCheckFrameNumber(splittingFrame + 1);
cy.get('#cvat_canvas_shape_30').should('exist').and('be.visible'); cy.get('#cvat_canvas_shape_24').should('exist').and('be.visible');
cy.goCheckFrameNumber(imageParams.count - 1); cy.goCheckFrameNumber(imageParams.count - 1);
cy.get('#cvat_canvas_shape_30').should('exist').and('be.visible'); cy.get('#cvat_canvas_shape_24').should('exist').and('be.visible');
cy.removeAnnotations(); cy.removeAnnotations();
}); });

Loading…
Cancel
Save