@@ -163,10 +163,50 @@ export class Roi {
163
163
/**
164
164
* Return an array of ROIs IDs that are included in the current ROI.
165
165
* This will be useful to know if there are some holes in the ROI.
166
+ *
167
+ * @returns internalIDs
166
168
*/
167
169
get internalIDs ( ) {
168
170
return this . #getComputed( 'internalIDs' , ( ) => {
169
- return getInternalIDs ( this ) ;
171
+ let internal = [ this . id ] ;
172
+ let roiMap = this . map ;
173
+ let data = roiMap . data ;
174
+
175
+ if ( this . height > 2 ) {
176
+ for ( let column = 0 ; column < this . width ; column ++ ) {
177
+ let target = this . computeIndex ( 0 , column ) ;
178
+ if ( internal . includes ( data [ target ] ) ) {
179
+ let id = data [ target + roiMap . width ] ;
180
+ if ( ! internal . includes ( id ) && ! this . boxIDs . includes ( id ) ) {
181
+ internal . push ( id ) ;
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ let array = new Array ( 4 ) ;
188
+ for ( let column = 1 ; column < this . width - 1 ; column ++ ) {
189
+ for ( let row = 1 ; row < this . height - 1 ; row ++ ) {
190
+ let target = this . computeIndex ( row , column ) ;
191
+ if ( internal . includes ( data [ target ] ) ) {
192
+ // we check if one of the neighbour is not yet in
193
+
194
+ array [ 0 ] = data [ target - 1 ] ;
195
+ array [ 1 ] = data [ target + 1 ] ;
196
+ array [ 2 ] = data [ target - roiMap . width ] ;
197
+ array [ 3 ] = data [ target + roiMap . width ] ;
198
+
199
+ for ( let i = 0 ; i < 4 ; i ++ ) {
200
+ let id = array [ i ] ;
201
+ if ( ! internal . includes ( id ) && ! this . boxIDs . includes ( id ) ) {
202
+ internal . push ( id ) ;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ return internal ;
170
210
} ) ;
171
211
}
172
212
//TODO externalIds should be an array of {id: number, length: number}
@@ -176,12 +216,91 @@ export class Roi {
176
216
*/
177
217
get externalBorders ( ) : Border [ ] {
178
218
return this . #getComputed( 'externalBorders' , ( ) => {
179
- return this . getExternalBorders ( ) ;
219
+ // take all the borders and remove the internal one ...
220
+ let borders = this . borders ;
221
+
222
+ let externalBorders = [ ] ;
223
+ let externalIDs = [ ] ;
224
+ let internals = this . internalIDs ;
225
+
226
+ for ( let border of borders ) {
227
+ if ( ! internals . includes ( border . connectedID ) ) {
228
+ const element : Border = {
229
+ connectedID : border . connectedID ,
230
+ length : border . length ,
231
+ } ;
232
+ externalIDs . push ( element . connectedID ) ;
233
+ externalBorders . push ( element ) ;
234
+ }
235
+ }
236
+
237
+ return externalBorders ;
180
238
} ) ;
181
239
}
240
+ /**
241
+ * Calculates and caches the number of sides by which each pixel is touched externally
242
+ *
243
+ * @param roi -ROI
244
+ * @returns object which tells how many pixels are exposed externally to how many sides
245
+ */
182
246
get perimeterInfo ( ) {
183
247
return this . #getComputed( 'perimeterInfo' , ( ) => {
184
- return getPerimeterInfo ( this ) ;
248
+ const roiMap = this . map ;
249
+ const data = roiMap . data ;
250
+ let one = 0 ;
251
+ let two = 0 ;
252
+ let three = 0 ;
253
+ let four = 0 ;
254
+ let externalIDs = this . externalBorders . map (
255
+ ( element ) => element . connectedID ,
256
+ ) ;
257
+ for ( let column = 0 ; column < this . width ; column ++ ) {
258
+ for ( let row = 0 ; row < this . height ; row ++ ) {
259
+ let target = this . computeIndex ( row , column ) ;
260
+ if ( data [ target ] === this . id ) {
261
+ let nbAround = 0 ;
262
+ if ( column === 0 ) {
263
+ nbAround ++ ;
264
+ } else if ( externalIDs . includes ( data [ target - 1 ] ) ) {
265
+ nbAround ++ ;
266
+ }
267
+
268
+ if ( column === roiMap . width - 1 ) {
269
+ nbAround ++ ;
270
+ } else if ( externalIDs . includes ( data [ target + 1 ] ) ) {
271
+ nbAround ++ ;
272
+ }
273
+
274
+ if ( row === 0 ) {
275
+ nbAround ++ ;
276
+ } else if ( externalIDs . includes ( data [ target - roiMap . width ] ) ) {
277
+ nbAround ++ ;
278
+ }
279
+
280
+ if ( row === roiMap . height - 1 ) {
281
+ nbAround ++ ;
282
+ } else if ( externalIDs . includes ( data [ target + roiMap . width ] ) ) {
283
+ nbAround ++ ;
284
+ }
285
+ switch ( nbAround ) {
286
+ case 1 :
287
+ one ++ ;
288
+ break ;
289
+ case 2 :
290
+ two ++ ;
291
+ break ;
292
+ case 3 :
293
+ three ++ ;
294
+ break ;
295
+ case 4 :
296
+ four ++ ;
297
+ break ;
298
+ default :
299
+ }
300
+ }
301
+ }
302
+ }
303
+ return { one, two, three, four } ;
185
304
} ) ;
186
305
}
187
306
@@ -225,7 +344,58 @@ export class Roi {
225
344
}
226
345
get boxIDs ( ) {
227
346
return this . #getComputed( 'boxIDs' , ( ) => {
228
- return getBoxIDs ( this ) ;
347
+ let surroundingIDs = new Set < number > ( ) ; // allows to get a unique list without indexOf
348
+
349
+ const roiMap = this . map ;
350
+ const data = roiMap . data ;
351
+
352
+ // we check the first line and the last line
353
+ for ( let row of [ 0 , this . height - 1 ] ) {
354
+ for ( let column = 0 ; column < this . width ; column ++ ) {
355
+ let target = this . computeIndex ( row , column ) ;
356
+ if (
357
+ column - this . origin . column > 0 &&
358
+ data [ target ] === this . id &&
359
+ data [ target - 1 ] !== this . id
360
+ ) {
361
+ let value = data [ target - 1 ] ;
362
+ surroundingIDs . add ( value ) ;
363
+ }
364
+ if (
365
+ roiMap . width - column - this . origin . column > 1 &&
366
+ data [ target ] === this . id &&
367
+ data [ target + 1 ] !== this . id
368
+ ) {
369
+ let value = data [ target + 1 ] ;
370
+ surroundingIDs . add ( value ) ;
371
+ }
372
+ }
373
+ }
374
+
375
+ // we check the first column and the last column
376
+ for ( let column of [ 0 , this . width - 1 ] ) {
377
+ for ( let row = 0 ; row < this . height ; row ++ ) {
378
+ let target = this . computeIndex ( row , column ) ;
379
+ if (
380
+ row - this . origin . row > 0 &&
381
+ data [ target ] === this . id &&
382
+ data [ target - roiMap . width ] !== this . id
383
+ ) {
384
+ let value = data [ target - roiMap . width ] ;
385
+ surroundingIDs . add ( value ) ;
386
+ }
387
+ if (
388
+ roiMap . height - row - this . origin . row > 1 &&
389
+ data [ target ] === this . id &&
390
+ data [ target + roiMap . width ] !== this . id
391
+ ) {
392
+ let value = data [ target + roiMap . width ] ;
393
+ surroundingIDs . add ( value ) ;
394
+ }
395
+ }
396
+ }
397
+
398
+ return Array . from ( surroundingIDs ) ; // the selection takes the whole rectangle
229
399
} ) ;
230
400
}
231
401
@@ -252,44 +422,101 @@ export class Roi {
252
422
/**
253
423
* Number of holes in the ROI and their total surface.
254
424
* Used to calculate fillRatio.
425
+ *
426
+ * @returns the surface of holes in ROI
255
427
*/
256
428
get holesInfo ( ) {
257
429
return this . #getComputed( 'holesInfo' , ( ) => {
258
- return getHolesInfo ( this ) ;
259
- } ) ;
260
- }
261
-
262
- getExternalBorders ( ) : Border [ ] {
263
- // take all the borders and remove the internal one ...
264
- let borders = this . borders ;
265
-
266
- let externalBorders = [ ] ;
267
- let externalIDs = [ ] ;
268
- let internals = this . internalIDs ;
269
-
270
- for ( let border of borders ) {
271
- if ( ! internals . includes ( border . connectedID ) ) {
272
- const element : Border = {
273
- connectedID : border . connectedID ,
274
- length : border . length ,
275
- } ;
276
- externalIDs . push ( element . connectedID ) ;
277
- externalBorders . push ( element ) ;
430
+ let surface = 0 ;
431
+ const data = this . map . data ;
432
+ for ( let column = 1 ; column < this . width - 1 ; column ++ ) {
433
+ for ( let row = 1 ; row < this . height - 1 ; row ++ ) {
434
+ let target = this . computeIndex ( row , column ) ;
435
+ if (
436
+ this . internalIDs . includes ( data [ target ] ) &&
437
+ data [ target ] !== this . id
438
+ ) {
439
+ surface ++ ;
440
+ }
441
+ }
278
442
}
279
- }
280
-
281
- return externalBorders ;
443
+ return {
444
+ number : this . internalIDs . length - 1 ,
445
+ surface,
446
+ } ;
447
+ } ) ;
282
448
}
283
449
284
450
/**
285
- *Calculates the borders' IDs and lengths
451
+ *Calculates and caches border's length and their IDs
452
+ *
453
+ * @returns borders' length and their IDs
286
454
*/
287
455
get borders ( ) {
288
456
return this . #getComputed( 'borders' , ( ) => {
289
- return getBorders ( this ) ;
457
+ const roiMap = this . map ;
458
+ const data = roiMap . data ;
459
+ let surroudingIDs = new Set < number > ( ) ; // allows to get a unique list without indexOf
460
+ let surroundingBorders = new Map ( ) ;
461
+ let visitedData = new Set ( ) ;
462
+ let dx = [ + 1 , 0 , - 1 , 0 ] ;
463
+ let dy = [ 0 , + 1 , 0 , - 1 ] ;
464
+
465
+ for (
466
+ let column = this . origin . column ;
467
+ column <= this . origin . column + this . width ;
468
+ column ++
469
+ ) {
470
+ for (
471
+ let row = this . origin . row ;
472
+ row <= this . origin . row + this . height ;
473
+ row ++
474
+ ) {
475
+ let target = column + row * roiMap . width ;
476
+ if ( data [ target ] === this . id ) {
477
+ for ( let dir = 0 ; dir < 4 ; dir ++ ) {
478
+ let newX = column + dx [ dir ] ;
479
+ let newY = row + dy [ dir ] ;
480
+ if (
481
+ newX >= 0 &&
482
+ newY >= 0 &&
483
+ newX < roiMap . width &&
484
+ newY < roiMap . height
485
+ ) {
486
+ let neighbour = newX + newY * roiMap . width ;
487
+
488
+ if (
489
+ data [ neighbour ] !== this . id &&
490
+ ! visitedData . has ( neighbour )
491
+ ) {
492
+ visitedData . add ( neighbour ) ;
493
+ surroudingIDs . add ( data [ neighbour ] ) ;
494
+ let surroundingBorder = surroundingBorders . get (
495
+ data [ neighbour ] ,
496
+ ) ;
497
+ if ( ! surroundingBorder ) {
498
+ surroundingBorders . set ( data [ neighbour ] , 1 ) ;
499
+ } else {
500
+ surroundingBorders . set (
501
+ data [ neighbour ] ,
502
+ ++ surroundingBorder ,
503
+ ) ;
504
+ }
505
+ }
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
+ let id : number [ ] = Array . from ( surroudingIDs ) ;
512
+ return id . map ( ( id ) => {
513
+ return {
514
+ connectedID : id ,
515
+ length : surroundingBorders . get ( id ) ,
516
+ } ;
517
+ } ) ;
290
518
} ) ;
291
519
}
292
-
293
520
/**
294
521
* Calculates fill ratio of the ROI
295
522
*/
@@ -366,7 +593,7 @@ export class Roi {
366
593
367
594
get centroid ( ) {
368
595
return this . #getComputed( 'centroid' , ( ) => {
369
- const roiMap = this . getMap ( ) ;
596
+ const roiMap = this . map ;
370
597
const data = roiMap . data ;
371
598
let sumColumn = 0 ;
372
599
let sumRow = 0 ;
@@ -400,6 +627,7 @@ export class Roi {
400
627
return this . #computed[ property ] as Computed [ T ] ;
401
628
}
402
629
//TODO Make this private
630
+
403
631
/**
404
632
* Calculates the correct index on the map of ROI
405
633
*
@@ -412,6 +640,7 @@ export class Roi {
412
640
}
413
641
}
414
642
643
+
415
644
/**
416
645
*
417
646
* @param roi -ROI
@@ -754,3 +983,4 @@ function getEllipse(roi: Roi, scale: number): Ellipse {
754
983
surface : ellipseSurface ,
755
984
} ;
756
985
}
986
+
0 commit comments