@@ -13,6 +13,15 @@ const config = `
1313 </RectangleLabels>
1414 </View>` ;
1515
16+ const configEllipse = `
17+ <View>
18+ <Image name="img" value="$image"></Image>
19+ <EllipseLabels name="tag" toName="img">
20+ <Label value="Planet"></Label>
21+ <Label value="Moonwalker" background="blue"></Label>
22+ </EllipseLabels>
23+ </View>` ;
24+
1625const perRegionConfig = `
1726 <View>
1827 <Image name="img" value="$image"></Image>
@@ -138,3 +147,150 @@ Scenario('Image with perRegion tags', async function({ I, AtImageView, AtSidebar
138147 assert . strictEqual ( result . length , 1 ) ;
139148 assert . deepStrictEqual ( result [ 0 ] . value . rectanglelabels , [ 'Moonwalker' ] ) ;
140149} ) ;
150+
151+ const outOfBoundsFFs = new DataTable ( [ 'FF_DEV_3793' ] )
152+
153+ outOfBoundsFFs . add ( [ true ] ) ;
154+ outOfBoundsFFs . add ( [ false ] )
155+
156+ Data ( outOfBoundsFFs )
157+ . Scenario ( 'Can\'t create rectangles outside of canvas' , async ( {
158+ I,
159+ AtLabels,
160+ AtSidebar,
161+ AtImageView,
162+ LabelStudio,
163+ current,
164+ } ) => {
165+ LabelStudio . setFeatureFlags ( {
166+ fflag_fix_front_dev_3793_relative_coords_short : current . FF_DEV_3793 ,
167+ } ) ;
168+
169+ I . amOnPage ( '/' ) ;
170+
171+ LabelStudio . init ( {
172+ config,
173+ data : { image } ,
174+ task : {
175+ id : 0 ,
176+ annotations : [ { id : 1001 , result : [ ] } ] ,
177+ predictions : [ ] ,
178+ } ,
179+ } ) ;
180+
181+ await AtImageView . waitForImage ( ) ;
182+ await AtImageView . lookForStage ( ) ;
183+
184+ const stage = AtImageView . stageBBox ( ) ;
185+
186+ I . say ( 'Drawing region in the upper left corner' ) ;
187+ AtLabels . clickLabel ( 'Planet' ) ;
188+ AtImageView . drawByDrag ( 100 , 100 , - 200 , - 200 ) ;
189+
190+ I . say ( 'Drawing region in the upper right corner' ) ;
191+ AtLabels . clickLabel ( 'Planet' ) ;
192+ AtImageView . drawByDrag ( stage . width - 100 , 100 , stage . width + 100 , - 100 ) ;
193+
194+ I . say ( 'Drawing region in the bottom left corner' ) ;
195+ AtLabels . clickLabel ( 'Planet' ) ;
196+ AtImageView . drawByDrag ( 100 , stage . height - 100 , - 100 , stage . height + 100 ) ;
197+
198+ I . say ( 'Drawing region in the bottom right corner' ) ;
199+ AtLabels . clickLabel ( 'Planet' ) ;
200+ AtImageView . drawByDrag ( stage . width - 100 , stage . height - 100 , stage . width + 100 , stage . height + 100 ) ;
201+
202+ AtSidebar . seeRegions ( 4 ) ;
203+
204+ const result = await LabelStudio . serialize ( ) ;
205+
206+ const [ r1 , r2 , r3 , r4 ] = result . map ( r => r . value ) ;
207+
208+ I . say ( 'First region should be in the corner' ) ;
209+ assert . strictEqual ( r1 . x , 0 ) ;
210+ assert . equal ( r1 . y , 0 ) ;
211+
212+ I . say ( 'Second region should be in the corner' ) ;
213+ assert . equal ( Math . round ( r2 . x + r2 . width ) , 100 ) ;
214+ assert . equal ( r2 . y , 0 ) ;
215+
216+ I . say ( 'Third region should be in the corner' ) ;
217+ assert . equal ( r3 . x , 0 ) ;
218+ assert . equal ( Math . round ( r3 . y + r3 . height ) , 100 ) ;
219+
220+ I . say ( 'Fourth region should be in the corner' ) ;
221+ assert . equal ( Math . round ( r4 . x + r4 . width ) , 100 ) ;
222+ assert . equal ( Math . round ( r4 . y + r4 . height ) , 100 ) ;
223+ } ) ;
224+
225+ Data ( outOfBoundsFFs ) .
226+ Scenario ( 'Can\'t create ellipses outside of canvas' , async ( {
227+ I,
228+ AtLabels,
229+ AtSidebar,
230+ AtImageView,
231+ LabelStudio,
232+ current,
233+ } ) => {
234+ LabelStudio . setFeatureFlags ( {
235+ fflag_fix_front_dev_3793_relative_coords_short : current . FF_DEV_3793 ,
236+ } ) ;
237+
238+ I . amOnPage ( '/' ) ;
239+
240+ LabelStudio . init ( {
241+ config : configEllipse ,
242+ data : { image } ,
243+ task : {
244+ id : 0 ,
245+ annotations : [ { id : 1001 , result : [ ] } ] ,
246+ predictions : [ ] ,
247+ } ,
248+ } ) ;
249+
250+ await AtImageView . waitForImage ( ) ;
251+ await AtImageView . lookForStage ( ) ;
252+
253+ const stage = AtImageView . stageBBox ( ) ;
254+ const ellipses = [
255+ // top-left corner
256+ [ 100 , 100 , - 200 , - 200 ] ,
257+ // top-right corner
258+ [ stage . width - 100 , 100 , stage . width + 100 , - 100 ] ,
259+ // bottom-left corner
260+ [ 100 , stage . height - 100 , - 100 , stage . height + 100 ] ,
261+ // bottom-right corner
262+ [ stage . width - 100 , stage . height - 100 , stage . width + 100 , stage . height + 100 ] ,
263+ ] ;
264+
265+ for ( const ellipse of ellipses ) {
266+ I . say ( 'Drawing region in the upper left corner' ) ;
267+ AtLabels . clickLabel ( 'Planet' ) ;
268+ AtImageView . drawByDrag ( ...ellipse ) ;
269+ }
270+
271+ AtSidebar . seeRegions ( 4 ) ;
272+
273+ const result = await LabelStudio . serialize ( ) ;
274+ const radiusX = 100 / stage . width * 100 ;
275+ const radiusY = 100 / stage . height * 100 ;
276+
277+ for ( let i = 0 ; i < result . length ; i ++ ) {
278+ const res = result [ i ] . value ;
279+ const region = ellipses [ i ] ;
280+
281+ I . say ( 'Make sure ellipse radius is correct (should be same for all)' ) ;
282+ // toFixed is to bypass JS floating point precision limitations (f32 sucks)
283+ assert . strictEqual ( res . radiusX . toFixed ( 3 ) , radiusX . toFixed ( 3 ) ) ;
284+ assert . strictEqual ( res . radiusY . toFixed ( 3 ) , radiusY . toFixed ( 3 ) ) ;
285+
286+ I . say ( 'Make sure that center is in correct spot' ) ;
287+ const [ expectedX , expectedY ] = [
288+ region [ 0 ] / stage . width * 100 ,
289+ region [ 1 ] / stage . height * 100 ,
290+ ] ;
291+
292+ assert . strictEqual ( res . x . toFixed ( 3 ) , expectedX . toFixed ( 3 ) ) ;
293+ assert . strictEqual ( res . y . toFixed ( 3 ) , expectedY . toFixed ( 3 ) ) ;
294+ }
295+ } ) ;
296+
0 commit comments