@@ -101,7 +101,7 @@ function makeTrackFilterControls(markPending: MarkChangesPendingFilter = markCha
101101 remove,
102102 markChangesPending : markPending ,
103103 groupFilterControls,
104- lookupGroups : cameraStore . lookupGroups ,
104+ lookupGroups : cameraStore . lookupGroups . bind ( cameraStore ) ,
105105 getTracks : ( track : AnnotationId ) => cameraStore . getTrackAll ( track ) ,
106106 renameTrackPair : ( id , currentType , newType ) => (
107107 cameraStore . renameTrackPair ( id , currentType , newType )
@@ -126,7 +126,7 @@ function makePairFixture(
126126 remove : ( id ) => cameraStore . removeTracks ( id ) ,
127127 markChangesPending : markPending ,
128128 groupFilterControls,
129- lookupGroups : cameraStore . lookupGroups ,
129+ lookupGroups : cameraStore . lookupGroups . bind ( cameraStore ) ,
130130 getTracks : ( id ) => cameraStore . getTrackAll ( id ) ,
131131 renameTrackPair : ( id , currentType , newType ) => (
132132 cameraStore . renameTrackPair ( id , currentType , newType )
@@ -449,6 +449,132 @@ describe('useAnnotationFilters', () => {
449449 expect ( cameraStore . getTrack ( 1 ) . confidencePairs ) . toEqual ( [ [ 'baz' , 0.7 ] ] ) ;
450450 } ) ;
451451
452+ it ( 'selects whole hidden tracks without stripping their other class scores' , ( ) => {
453+ const { cameraStore, filters } = makePairFixture ( [
454+ [ [ 'fish' , 0.9 ] , [ 'shark' , 0.1 ] ] ,
455+ [ [ 'fish' , 0.2 ] , [ 'shark' , 0.1 ] ] ,
456+ [ [ 'shark' , 0.1 ] ] ,
457+ [ [ 'fish' , 0.5 ] ] ,
458+ ] ) ;
459+ filters . setConfidenceFilters ( { default : 0.5 } ) ;
460+ filters . updateCheckedTypes ( [ 'fish' ] ) ;
461+ const ids = filters . annotationIdsBelowThreshold ( [ 'fish' ] ) ;
462+ expect ( ids ) . toEqual ( [ 1 ] ) ;
463+ expect ( cameraStore . getTrack ( 1 ) . confidencePairs ) . toEqual ( [ [ 'fish' , 0.2 ] , [ 'shark' , 0.1 ] ] ) ;
464+ ids . forEach ( ( id ) => cameraStore . removeTracks ( id ) ) ;
465+ expect ( cameraStore . getPossibleTrack ( 1 ) ) . toBeUndefined ( ) ;
466+ expect ( cameraStore . getTrack ( 0 ) . confidencePairs ) . toEqual ( [ [ 'fish' , 0.9 ] , [ 'shark' , 0.1 ] ] ) ;
467+ expect ( cameraStore . getPossibleTrack ( 2 ) ) . toBeDefined ( ) ;
468+ expect ( cameraStore . getPossibleTrack ( 3 ) ) . toBeDefined ( ) ;
469+ } ) ;
470+
471+ it ( 'does not classify a visible track by its low-scoring secondary class' , ( ) => {
472+ const { filters } = makePairFixture ( [
473+ [ [ 'fish' , 0.9 ] , [ 'shark' , 0.1 ] ] ,
474+ [ [ 'fish' , 0.2 ] , [ 'shark' , 0.7 ] ] ,
475+ [ [ 'fish' , 0.2 ] , [ 'shark' , 0.1 ] ] ,
476+ ] ) ;
477+ filters . setConfidenceFilters ( { default : 0.5 } ) ;
478+ expect ( filters . annotationIdsBelowThreshold ( [ 'fish' , 'shark' ] ) ) . toEqual ( [ 2 ] ) ;
479+ expect ( filters . annotationIdsBelowThreshold ( [ ] ) ) . toEqual ( [ ] ) ;
480+ } ) ;
481+
482+ it ( 'limits below-threshold delete to the active time filter' , ( ) => {
483+ const cameraStore = new CameraStore ( { markChangesPending } ) ;
484+ const trackStore = cameraStore . camMap . value . get ( 'singleCam' ) ?. trackStore ;
485+ const lateFeatures : Feature [ ] = [ ] ;
486+ lateFeatures [ 10 ] = { frame : 10 , bounds : [ 0 , 0 , 1 , 1 ] , keyframe : true } ;
487+ trackStore ?. insert ( new Track ( 0 , {
488+ begin : 0 ,
489+ end : 0 ,
490+ confidencePairs : [ [ 'fish' , 0.2 ] ] ,
491+ features,
492+ } ) ) ;
493+ trackStore ?. insert ( new Track ( 1 , {
494+ begin : 10 ,
495+ end : 10 ,
496+ confidencePairs : [ [ 'fish' , 0.2 ] ] ,
497+ features : lateFeatures ,
498+ } ) ) ;
499+ trackStore ?. setEnableSorting ( ) ;
500+ const groupFilterControls = makeGroupFilterControls ( cameraStore ) ;
501+ const filters = new TrackFilterControls ( {
502+ sorted : cameraStore . sortedTracks ,
503+ remove : ( id ) => cameraStore . removeTracks ( id ) ,
504+ markChangesPending,
505+ groupFilterControls,
506+ lookupGroups : cameraStore . lookupGroups . bind ( cameraStore ) ,
507+ getTracks : ( id ) => cameraStore . getTrackAll ( id ) ,
508+ renameTrackPair : ( id , currentType , newType ) => (
509+ cameraStore . renameTrackPair ( id , currentType , newType )
510+ ) ,
511+ removeTypes : ( id , types ) => cameraStore . removeTypes ( id , types ) ,
512+ } ) ;
513+ filters . setConfidenceFilters ( { default : 0.5 } ) ;
514+ filters . setTimeFilters ( [ 0 , 5 ] ) ;
515+ expect ( filters . annotationIdsBelowThreshold ( [ 'fish' ] ) ) . toEqual ( [ 0 ] ) ;
516+ filters . setTimeFilters ( null ) ;
517+ expect ( filters . annotationIdsBelowThreshold ( [ 'fish' ] ) ) . toEqual ( [ 0 , 1 ] ) ;
518+ } ) ;
519+
520+ it ( 'limits below-threshold delete to enabled groups' , ( ) => {
521+ const cameraStore = new CameraStore ( { markChangesPending } ) ;
522+ const cam = cameraStore . camMap . value . get ( 'singleCam' ) ;
523+ cam ?. trackStore . insert ( new Track ( 0 , {
524+ confidencePairs : [ [ 'fish' , 0.2 ] ] ,
525+ features,
526+ } ) ) ;
527+ cam ?. trackStore . insert ( new Track ( 1 , {
528+ confidencePairs : [ [ 'fish' , 0.2 ] ] ,
529+ features,
530+ } ) ) ;
531+ cam ?. trackStore . setEnableSorting ( ) ;
532+ cam ?. groupStore . insert ( new Group ( 10 , {
533+ confidencePairs : [ [ 'school' , 1 ] ] ,
534+ members : { 0 : { ranges : [ [ 0 , 0 ] ] } } ,
535+ } ) , { imported : true } ) ;
536+ cam ?. groupStore . insert ( new Group ( 11 , {
537+ confidencePairs : [ [ 'pod' , 1 ] ] ,
538+ members : { 1 : { ranges : [ [ 0 , 0 ] ] } } ,
539+ } ) , { imported : true } ) ;
540+ cam ?. groupStore . setEnableSorting ( ) ;
541+ const groupFilterControls = makeGroupFilterControls ( cameraStore ) ;
542+ groupFilterControls . checkedTypes . value = [ 'school' ] ;
543+ const filters = new TrackFilterControls ( {
544+ sorted : cameraStore . sortedTracks ,
545+ remove : ( id ) => cameraStore . removeTracks ( id ) ,
546+ markChangesPending,
547+ groupFilterControls,
548+ lookupGroups : cameraStore . lookupGroups . bind ( cameraStore ) ,
549+ getTracks : ( id ) => cameraStore . getTrackAll ( id ) ,
550+ renameTrackPair : ( id , currentType , newType ) => (
551+ cameraStore . renameTrackPair ( id , currentType , newType )
552+ ) ,
553+ removeTypes : ( id , types ) => cameraStore . removeTypes ( id , types ) ,
554+ } ) ;
555+ filters . setConfidenceFilters ( { default : 0.5 } ) ;
556+ expect ( filters . annotationIdsBelowThreshold ( [ 'fish' ] ) ) . toEqual ( [ 0 ] ) ;
557+ } ) ;
558+
559+ it ( 'limits below-threshold delete with attribute filters' , ( ) => {
560+ const { cameraStore, filters } = makePairFixture ( [
561+ [ [ 'fish' , 0.2 ] ] ,
562+ [ [ 'fish' , 0.2 ] ] ,
563+ ] ) ;
564+ cameraStore . getTrack ( 0 ) . attributes . quality = 'good' ;
565+ cameraStore . getTrack ( 1 ) . attributes . quality = 'bad' ;
566+ filters . setConfidenceFilters ( { default : 0.5 } ) ;
567+ filters . loadTrackAttributesFilter ( [ {
568+ name : 'fish quality' ,
569+ type : 'track' ,
570+ typeFilter : [ 'fish' ] ,
571+ attribute : 'quality' ,
572+ filter : { op : '=' , val : 'good' } ,
573+ enabled : true ,
574+ } ] ) ;
575+ expect ( filters . annotationIdsBelowThreshold ( [ 'fish' ] ) ) . toEqual ( [ 0 ] ) ;
576+ } ) ;
577+
452578 it ( 'returns the caller fallback without recomputing flat pair selection' , ( ) => {
453579 const { cameraStore, filters } = makePairFixture ( [
454580 [ [ 'root' , 0.1 ] , [ 'leaf' , 0.9 ] ] ,
@@ -655,7 +781,7 @@ describe('useAnnotationFilters', () => {
655781 remove : ( id ) => cameraStore . removeTracks ( id ) ,
656782 markChangesPending,
657783 groupFilterControls : groupFilters ,
658- lookupGroups : cameraStore . lookupGroups ,
784+ lookupGroups : cameraStore . lookupGroups . bind ( cameraStore ) ,
659785 getTracks : ( id ) => cameraStore . getTrackAll ( id ) ,
660786 renameTrackPair : ( id , currentType , newType ) => (
661787 cameraStore . renameTrackPair ( id , currentType , newType )
0 commit comments