Skip to content

Commit

Permalink
Fixed: In some cases effect of drag/resize may be reset implicitly fo…
Browse files Browse the repository at this point in the history
…r a user (#9053)
  • Loading branch information
bsekachev authored Feb 5, 2025
1 parent 89c4af5 commit 9a66509
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Fixed

- In some cases effect of drag/resize may be reset implicitly for a user
(<https://github.com/cvat-ai/cvat/pull/9053>)
26 changes: 26 additions & 0 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,32 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.canvas.style.cursor = '';
this.mode = Mode.IDLE;
if (state && points) {
// we need to store "updated" and set "points" to an empty array
// as this information is used to define "updated" objects in diff logic during canvas objects setup
// if because of any reason updating was actually rejected somewhere, we must reset view inside this logic

// there is one more deeper issue:
// somewhere canvas updates drawn views and then sends request,
// updating internal CVAT state (e.g. drag, resize)
// somewhere, however, it just sends request to update internal CVAT state
// (e.g. remove point, edit polygon/polyline)
// if object view was not changed by canvas and points accepted as is without any changes
// the view will not be updated during objects setup if we just set points as is here
// that is why we need to set points to an empty array (something that can't normally come from CVAT)
// I do not think it can be easily fixed now, hovewer in the future we should refactor code
if (Number.isInteger(state.parentID)) {
const { elements } = this.drawnStates[state.parentID];
const drawnElement = elements.find((el) => el.clientID === state.clientID);
drawnElement.updated = Date.now();
drawnElement.points = [];

this.drawnStates[state.parentID].updated = drawnElement.updated;
this.drawnStates[state.parentID].points = [];
} else {
this.drawnStates[state.clientID].updated = Date.now();
this.drawnStates[state.clientID].points = [];
}

const event: CustomEvent = new CustomEvent('canvas.edited', {
bubbles: false,
cancelable: true,
Expand Down
5 changes: 2 additions & 3 deletions cvat-canvas/src/typescript/consts.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

const BASE_STROKE_WIDTH = 1.25;
const BASE_GRID_WIDTH = 2;
const BASE_POINT_SIZE = 4;
const TEXT_MARGIN = 10;
const AREA_THRESHOLD = 9;
const SIZE_THRESHOLD = 3;
const SIZE_THRESHOLD = 1;
const POINTS_STROKE_WIDTH = 1;
const POINTS_SELECTED_STROKE_WIDTH = 4;
const MIN_EDGE_LENGTH = 3;
Expand Down Expand Up @@ -36,7 +36,6 @@ export default {
BASE_GRID_WIDTH,
BASE_POINT_SIZE,
TEXT_MARGIN,
AREA_THRESHOLD,
SIZE_THRESHOLD,
POINTS_STROKE_WIDTH,
POINTS_SELECTED_STROKE_WIDTH,
Expand Down
22 changes: 14 additions & 8 deletions cvat-canvas/src/typescript/drawHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,41 @@ interface FinalCoordinates {
function checkConstraint(shapeType: string, points: number[], box: Box | null = null): boolean {
if (shapeType === 'rectangle') {
const [xtl, ytl, xbr, ybr] = points;
return (xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD;
const [width, height] = [xbr - xtl, ybr - ytl];
return width >= consts.SIZE_THRESHOLD && height >= consts.SIZE_THRESHOLD;
}

if (shapeType === 'polygon') {
return (box.xbr - box.xtl) * (box.ybr - box.ytl) >= consts.AREA_THRESHOLD && points.length >= 3 * 2;
const [width, height] = [box.xbr - box.xtl, box.ybr - box.ytl];
return (width >= consts.SIZE_THRESHOLD || height > consts.SIZE_THRESHOLD) && points.length >= 3 * 2;
}

if (shapeType === 'polyline') {
return (box.xbr - box.xtl >= consts.SIZE_THRESHOLD ||
box.ybr - box.ytl >= consts.SIZE_THRESHOLD) && points.length >= 2 * 2;
const [width, height] = [box.xbr - box.xtl, box.ybr - box.ytl];
return (width >= consts.SIZE_THRESHOLD || height >= consts.SIZE_THRESHOLD) && points.length >= 2 * 2;
}

if (shapeType === 'points') {
return points.length > 2 || (points.length === 2 && points[0] !== 0 && points[1] !== 0);
}

if (shapeType === 'ellipse') {
const [rx, ry] = [points[2] - points[0], points[1] - points[3]];
return rx * ry * Math.PI >= consts.AREA_THRESHOLD;
const [width, height] = [(points[2] - points[0]) * 2, (points[1] - points[3]) * 2];
return width >= consts.SIZE_THRESHOLD && height > consts.SIZE_THRESHOLD;
}

if (shapeType === 'cuboid') {
return points.length === 4 * 2 || points.length === 8 * 2 ||
(points.length === 2 * 2 && (points[2] - points[0]) * (points[3] - points[1]) >= consts.AREA_THRESHOLD);
(points.length === 2 * 2 &&
(points[2] - points[0]) >= consts.SIZE_THRESHOLD &&
(points[3] - points[1]) >= consts.SIZE_THRESHOLD
);
}

if (shapeType === 'skeleton') {
const [xtl, ytl, xbr, ybr] = points;
return (xbr - xtl >= 1 || ybr - ytl >= 1);
const [width, height] = [xbr - xtl, ybr - ytl];
return width >= consts.SIZE_THRESHOLD || height >= consts.SIZE_THRESHOLD;
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/src/typescript/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function displayShapeSize(shapesContainer: SVG.Container, textContainer:
.fill('white')
.addClass('cvat_canvas_text'),
update(shape: SVG.Shape): void {
let text = `${Math.round(shape.width())}x${Math.round(shape.height())}px`;
let text = `${Math.floor(shape.width())}x${Math.floor(shape.height())}px`;
if (shape.type === 'rect' || shape.type === 'ellipse') {
let rotation = shape.transform().rotation || 0;
// be sure, that rotation in range [0; 360]
Expand Down
8 changes: 4 additions & 4 deletions cvat-core/src/object-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ export function checkShapeArea(shapeType: ShapeType, points: number[]): boolean
ymax = Math.max(ymax, points[i + 1]);
}

if (shapeType === ShapeType.POLYLINE) {
// horizontal / vertical lines have one of dimensions equal to zero
const length = Math.max(xmax - xmin, ymax - ymin);
return length >= MIN_SHAPE_SIZE;
if ([ShapeType.POLYLINE, ShapeType.SKELETON, ShapeType.POLYGON].includes(shapeType)) {
// for polyshapes consider at least one dimension
// skeleton in corner cases may be a regular polyshape
return Math.max(xmax - xmin, ymax - ymin) >= MIN_SHAPE_SIZE;
}

[width, height] = [xmax - xmin, ymax - ymin];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ function WorkspaceSettingsComponent(props: Props): JSX.Element {
const maxAutoSaveInterval = 60;
const minAAMMargin = 0;
const maxAAMMargin = 1000;
const minControlPointsSize = 4;
const maxControlPointsSize = 8;
const minControlPointsSize = 2;
const maxControlPointsSize = 10;

return (
<div className='cvat-workspace-settings'>
Expand Down

0 comments on commit 9a66509

Please sign in to comment.