diff --git a/cvat-core/src/frames.ts b/cvat-core/src/frames.ts index 591c563cd0d..13b2279a73d 100644 --- a/cvat-core/src/frames.ts +++ b/cvat-core/src/frames.ts @@ -325,7 +325,7 @@ function getDataStartFrame(meta: FramesMetaData, localStartFrame: number): numbe } function getDataFrameNumber(meta: FramesMetaData, frameNumber: number, dataStartFrame: number, step: number): number { - if (meta.includedFrames.length) { + if (meta.includedFrames) { if (frameNumber >= meta.includedFrames.length) { throw new ArgumentError(`Frame number ${frameNumber} is out of included frames range`); } @@ -802,29 +802,63 @@ export async function patchMeta(jobID: number): Promise { } export async function findFrame( - jobID: number, frameFrom: number, frameTo: number, filters: { offset?: number, notDeleted: boolean }, + jobID: number, from: number, to: number, filters: { offset?: number, notDeleted: boolean }, ): Promise { - const offset = filters.offset || 1; const meta = await getFramesMeta('job', jobID); - + let frameFrom = from; + let frameTo = to; const sign = Math.sign(frameTo - frameFrom); - const predicate = sign > 0 ? (frame) => frame <= frameTo : (frame) => frame >= frameTo; - const update = sign > 0 ? (frame) => frame + 1 : (frame) => frame - 1; + + if (meta.includedFrames) { + // adjust start and stop for a ground truth jobs + const [sortedFrom, sortedTo] = [frameFrom, frameTo].sort((a: number, b: number) => a - b); + const minIdx = meta.includedFrames.reduce((acc, val, index) => { + if (acc === null && val >= sortedFrom) { + return index; + } + + return acc; + }, null); + + const maxIdx = meta.includedFrames.reduceRight((acc, val, index) => { + if (acc === null && val <= sortedTo) { + return index; + } + + return acc; + }, null); + + if (minIdx === null || maxIdx === null) { + // passed range is out of gt job range (left or right) + return null; + } + + if (sign > 0) { + frameFrom = meta.includedFrames[minIdx]; + frameTo = meta.includedFrames[maxIdx]; + } else { + frameFrom = meta.includedFrames[maxIdx]; + frameTo = meta.includedFrames[minIdx]; + } + } + + const offset = filters.offset || 1; + const predicate = sign > 0 ? (frame: number) => frame <= frameTo : (frame: number) => frame >= frameTo; + const update = sign > 0 ? (frame: number) => frame + 1 : (frame: number) => frame - 1; let framesCounter = 0; let lastUndeletedFrame = null; - const check = (frame): boolean => { + const check = (frame: number): boolean => { if (meta.includedFrames) { - // meta.includedFrames contains input frame numbers now - const dataStartFrame = meta.startFrame; // this is only true when includedFrames is set - return (meta.includedFrames.includes( - getDataFrameNumber(meta, frame, dataStartFrame, meta.frameStep)) - ) && (!filters.notDeleted || !(frame in meta.deletedFrames)); + return meta.includedFrames.includes(frame) && (!filters.notDeleted || !(frame in meta.deletedFrames)); } + if (filters.notDeleted) { return !(frame in meta.deletedFrames); } + return true; }; + for (let frame = frameFrom; predicate(frame); frame = update(frame)) { if (check(frame)) { lastUndeletedFrame = frame;