@@ -13,20 +13,23 @@ import { RoiMap } from './RoiMapManager';
13
13
import { getBorderPoints } from './getBorderPoints' ;
14
14
import { getMask , GetMaskOptions } from './getMask' ;
15
15
16
+ interface Border {
17
+ connectedID : number ; // refers to the roiID of the contiguous ROI
18
+ length : number ;
19
+ }
16
20
interface Computed {
17
21
perimeter : number ;
18
- borderIDs : number [ ] ;
22
+ borders : Border [ ] ; // external and internal ids which are not equal to the current roi ID
19
23
perimeterInfo : { one : number ; two : number ; three : number ; four : number } ;
20
24
externalLengths : number [ ] ;
21
25
borderLengths : number [ ] ;
22
26
box : number ;
23
27
points : number [ ] [ ] ;
24
28
holesInfo : { number : number ; surface : number } ;
25
- external : number ;
26
29
boxIDs : number [ ] ;
27
30
eqpc : number ;
28
31
ped : number ;
29
- externalIDs : number [ ] ;
32
+ externalBorders : Border [ ] ;
30
33
roundness : number ;
31
34
convexHull : { points : Point [ ] ; surface : number ; perimeter : number } ;
32
35
mbr : Mbr ;
@@ -60,9 +63,10 @@ export class Roi {
60
63
/**
61
64
* Surface of the ROI.
62
65
*/
63
-
64
66
public readonly surface : number ;
65
-
67
+ /**
68
+ * Cached values of properties to improve performance
69
+ */
66
70
#computed: Partial < Computed > ;
67
71
68
72
public constructor (
@@ -91,7 +95,7 @@ export class Roi {
91
95
}
92
96
93
97
/**
94
- * Return the value at the given coordinates in an ROI map.
98
+ * Returns the value at the given coordinates in an ROI map.
95
99
*
96
100
* @param column - Column of the value.
97
101
* @param row - Row of the value.
@@ -102,7 +106,7 @@ export class Roi {
102
106
}
103
107
104
108
/**
105
- * Return the ratio between the width and the height of the bounding rectangle of the ROI.
109
+ * Returns the ratio between the width and the height of the bounding rectangle of the ROI.
106
110
*
107
111
* @returns The width by height ratio.
108
112
*/
@@ -111,7 +115,7 @@ export class Roi {
111
115
}
112
116
113
117
/**
114
- * Generate a mask of an ROI. You can specify the kind of mask you want using the `kind` option.
118
+ * Generates a mask of an ROI. You can specify the kind of mask you want using the `kind` option.
115
119
*
116
120
* @param options - Get Mask options
117
121
* @returns The ROI mask.
@@ -139,13 +143,6 @@ export class Roi {
139
143
public getBorderPoints ( options ?: GetBorderPointsOptions ) : Array < Point > {
140
144
return getBorderPoints ( this , options ) ;
141
145
}
142
- //TODO The ids and length should be in one computed property which returns an array of {id: number, length: number}
143
- _computeBorderIDs ( ) : { ids : number [ ] ; lengths : number [ ] } {
144
- const borders = getBorders ( this ) ;
145
- this . #computed. borderIDs = borders . ids ;
146
- this . #computed. borderLengths = borders . lengths ;
147
- return borders ;
148
- }
149
146
150
147
/**
151
148
* Return an array of ROIs IDs that are included in the current ROI.
@@ -161,9 +158,9 @@ export class Roi {
161
158
/**
162
159
* Return an array of ROIs IDs that touch the current ROI.
163
160
*/
164
- get externalIDs ( ) : number [ ] {
165
- return this . #getComputed( 'externalIDs ' , ( ) => {
166
- return this . getExternalIDs ( ) . externalIDs ;
161
+ get externalBorders ( ) : Border [ ] {
162
+ return this . #getComputed( 'externalBorders ' , ( ) => {
163
+ return this . getExternalBorders ( ) ;
167
164
} ) ;
168
165
}
169
166
get perimeterInfo ( ) {
@@ -189,7 +186,10 @@ export class Roi {
189
186
delta * ( info . two + info . three * 2 + info . four )
190
187
) ;
191
188
}
192
-
189
+ /**
190
+ * An array of tuples, each tuple being the x and y coordinates of the ROI point.
191
+ * the current ROI points
192
+ */
193
193
get points ( ) {
194
194
return this . #getComputed( 'points' , ( ) => {
195
195
let points = [ ] ;
@@ -221,63 +221,62 @@ export class Roi {
221
221
return 2 * Math . sqrt ( this . surface / Math . PI ) ;
222
222
} ) ;
223
223
}
224
-
224
+ /**
225
+ * Number of holes in the ROI and their total surface.
226
+ * Used to calculate fillRatio.
227
+ */
225
228
get holesInfo ( ) {
226
229
return this . #getComputed( 'holesInfo' , ( ) => {
227
230
return getHolesInfo ( this ) ;
228
231
} ) ;
229
232
}
230
233
231
- getExternalIDs ( ) : {
232
- externalIDs : number [ ] ;
233
- externalLengths : number [ ] ;
234
- } {
234
+ getExternalBorders ( ) : Border [ ] {
235
235
// take all the borders and remove the internal one ...
236
- let borders = this . borderIDs ;
237
- let lengths = this . borderLengths ;
238
-
239
- this . #computed. externalLengths = [ ] ;
240
- this . #computed. externalIDs = [ ] ;
236
+ let borders = this . borders ;
241
237
238
+ let externalBorders = [ ] ;
239
+ let externalIDs = [ ] ;
242
240
let internals = this . internalIDs ;
243
241
244
- for ( let i = 0 ; i < borders . length ; i ++ ) {
245
- if ( ! internals . includes ( borders [ i ] ) ) {
246
- this . #computed. externalIDs . push ( borders [ i ] ) ;
247
- this . #computed. externalLengths . push ( lengths [ i ] ) ;
242
+ for ( let border of borders ) {
243
+ if ( ! internals . includes ( border . connectedID ) ) {
244
+ const element : Border = {
245
+ connectedID : border . connectedID ,
246
+ length : border . length ,
247
+ } ;
248
+ externalIDs . push ( element . connectedID ) ;
249
+ externalBorders . push ( element ) ;
248
250
}
249
251
}
250
- const externalIDs = this . #computed. externalIDs ;
251
- const externalLengths = this . #computed. externalLengths ;
252
- return { externalIDs, externalLengths } ;
253
- }
254
- //TODO Should be merged together in one borders property
255
- get borderIDs ( ) {
256
- return this . #getComputed( 'borderIDs' , ( ) => {
257
- return this . _computeBorderIDs ( ) . ids ;
258
- } ) ;
252
+
253
+ return externalBorders ;
259
254
}
260
255
261
- get borderLengths ( ) {
262
- return this . #getComputed( 'borderLengths' , ( ) => {
263
- return this . _computeBorderIDs ( ) . lengths ;
256
+ /**
257
+ *Calculates the borders' IDs and lengths
258
+ */
259
+ get borders ( ) {
260
+ return this . #getComputed( 'borders' , ( ) => {
261
+ return getBorders ( this ) ;
264
262
} ) ;
265
263
}
264
+
266
265
/**
267
- * Getter that calculates fill ratio of the ROI
266
+ * Calculates fill ratio of the ROI
268
267
*/
269
268
get fillRatio ( ) {
270
269
return this . surface / ( this . surface + this . holesInfo . surface ) ;
271
270
}
272
271
/**
273
- * Getter that calculates sphericity of the ROI
272
+ * Calculates sphericity of the ROI
274
273
*/
275
274
get sphericity ( ) {
276
275
return ( 2 * Math . sqrt ( this . surface * Math . PI ) ) / this . perimeter ;
277
276
}
278
277
279
278
/**
280
- * Getter that calculates solidity of the ROI
279
+ * Calculates solidity of the ROI
281
280
*/
282
281
get solidity ( ) {
283
282
return this . surface / getConvexHull ( this . getMask ( ) ) . surface ;
@@ -288,7 +287,9 @@ export class Roi {
288
287
return getConvexHull ( this . getMask ( ) ) ;
289
288
} ) ;
290
289
}
291
-
290
+ /**
291
+ * Calculates minimum bounding rectangle
292
+ */
292
293
get mbr ( ) {
293
294
return this . #getComputed( 'mbr' , ( ) => {
294
295
return getMbr ( this . getMask ( ) ) ;
@@ -353,6 +354,7 @@ export class Roi {
353
354
} ) ;
354
355
}
355
356
357
+ // A helper function to cache already calculated properties
356
358
#getComputed< T extends keyof Computed > (
357
359
property : T ,
358
360
callback : ( ) => Computed [ T ] ,
@@ -365,6 +367,12 @@ export class Roi {
365
367
return this . #computed[ property ] as Computed [ T ] ;
366
368
}
367
369
//TODO Make this private
370
+ /**
371
+ * Calculates the correct index on the map of ROI
372
+ *
373
+ * @param y
374
+ * @param x
375
+ */
368
376
computeIndex ( y : number , x : number ) : number {
369
377
const roiMap = this . getMap ( ) ;
370
378
return ( y + this . origin . row ) * roiMap . width + x + this . origin . column ;
@@ -383,33 +391,33 @@ function getPerimeterInfo(roi: Roi) {
383
391
let two = 0 ;
384
392
let three = 0 ;
385
393
let four = 0 ;
386
-
394
+ let externalIDs = roi . externalBorders . map ( ( element ) => element . connectedID ) ;
387
395
for ( let column = 0 ; column < roi . width ; column ++ ) {
388
396
for ( let row = 0 ; row < roi . height ; row ++ ) {
389
397
let target = roi . computeIndex ( row , column ) ;
390
398
if ( data [ target ] === roi . id ) {
391
399
let nbAround = 0 ;
392
400
if ( column === 0 ) {
393
401
nbAround ++ ;
394
- } else if ( roi . externalIDs . includes ( data [ target - 1 ] ) ) {
402
+ } else if ( externalIDs . includes ( data [ target - 1 ] ) ) {
395
403
nbAround ++ ;
396
404
}
397
405
398
406
if ( column === roiMap . width - 1 ) {
399
407
nbAround ++ ;
400
- } else if ( roi . externalIDs . includes ( data [ target + 1 ] ) ) {
408
+ } else if ( externalIDs . includes ( data [ target + 1 ] ) ) {
401
409
nbAround ++ ;
402
410
}
403
411
404
412
if ( row === 0 ) {
405
413
nbAround ++ ;
406
- } else if ( roi . externalIDs . includes ( data [ target - roiMap . width ] ) ) {
414
+ } else if ( externalIDs . includes ( data [ target - roiMap . width ] ) ) {
407
415
nbAround ++ ;
408
416
}
409
417
410
418
if ( row === roiMap . height - 1 ) {
411
419
nbAround ++ ;
412
- } else if ( roi . externalIDs . includes ( data [ target + roiMap . width ] ) ) {
420
+ } else if ( externalIDs . includes ( data [ target + roiMap . width ] ) ) {
413
421
nbAround ++ ;
414
422
}
415
423
switch ( nbAround ) {
@@ -454,7 +462,12 @@ function getHolesInfo(roi: Roi) {
454
462
surface,
455
463
} ;
456
464
}
457
-
465
+ /**
466
+ * Calculates internal IDs of the ROI
467
+ *
468
+ * @param roi
469
+ * @returns internalIDs
470
+ */
458
471
function getInternalIDs ( roi : Roi ) {
459
472
let internal = [ roi . id ] ;
460
473
let roiMap = roi . getMap ( ) ;
@@ -557,7 +570,7 @@ function getBoxIDs(roi: Roi): number[] {
557
570
* @param roi - ROI
558
571
* @returns borders' length and their IDs
559
572
*/
560
- function getBorders ( roi : Roi ) : { ids : number [ ] ; lengths : number [ ] } {
573
+ function getBorders ( roi : Roi ) : Border [ ] {
561
574
const roiMap = roi . getMap ( ) ;
562
575
const data = roiMap . data ;
563
576
let surroudingIDs = new Set < number > ( ) ; // allows to get a unique list without indexOf
@@ -600,12 +613,11 @@ function getBorders(roi: Roi): { ids: number[]; lengths: number[] } {
600
613
}
601
614
}
602
615
}
603
- let ids : number [ ] = Array . from ( surroudingIDs ) ;
604
- let borderLengths = ids . map ( ( id ) => {
605
- return surroundingBorders . get ( id ) ;
616
+ let id : number [ ] = Array . from ( surroudingIDs ) ;
617
+ return id . map ( ( id ) => {
618
+ return {
619
+ connectedID : id ,
620
+ length : surroundingBorders . get ( id ) ,
621
+ } ;
606
622
} ) ;
607
- return {
608
- ids,
609
- lengths : borderLengths ,
610
- } ;
611
623
}
0 commit comments