1 module des.il.util; 2 3 import std.algorithm; 4 import std.exception; 5 import std.traits; 6 import std.range; 7 import std.conv : to; 8 9 import des.ts; 10 11 import des.math.linear.vector; 12 13 import des.il.region; 14 15 /// 16 class ImageException : Exception 17 { 18 /// 19 this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow 20 { super( msg, file, line ); } 21 } 22 23 void imEnforce(string file=__FILE__, size_t line=__LINE__)( bool val, lazy string msg ) 24 { enforce( val, new ImageException( msg, file, line ) ); } 25 26 alias coord_t = ptrdiff_t; 27 alias CrdVector(size_t N) = Vector!(N,coord_t); 28 alias CrdRegion(size_t N) = Region!(N,coord_t); 29 alias CrdVectorD = CrdVector!0; 30 alias CrdRegionD = CrdRegion!0; 31 32 /++ checks all components 33 Returns: 34 true if all is positive 35 +/ 36 bool isAllCompPositive(V)( in V v ) 37 if( is( typeof( v[0] ) ) && isNumeric!(typeof(v[0])) ) 38 { 39 foreach( e; v ) if( e < 0 ) return false; 40 return true; 41 } 42 43 /// 44 unittest 45 { 46 assert( isAllCompPositive( [1,2,3] ) ); 47 assert( isAllCompPositive( vec3( 1,2,3 ) ) ); 48 assert( isAllCompPositive( CrdVector!3( 1,2,3 ) ) ); 49 assert( !isAllCompPositive( [-1,2,3] ) ); 50 } 51 52 /// 53 coord_t[] redimSize(A)( size_t K, size_t N, in A[] size ) pure 54 if( isIntegral!A ) 55 in 56 { 57 assert( K >= N ); 58 assert( isAllCompPositive( size ) ); 59 } 60 body 61 { 62 auto ret = new coord_t[](K); 63 ret[] = 1; 64 foreach( i; 0 .. min( N, size.length ) ) 65 ret[i] = size[i]; 66 if( size.length > N ) 67 ret[N-1] *= reduce!((r,v)=>r*=v)( 1, size[N..$] ); 68 return ret; 69 } 70 71 /// 72 unittest 73 { 74 assertEq( [1,2,3], redimSize( 3, 3, [1,2,3] ) ); 75 assertEq( [1,6,1], redimSize( 3, 2, [1,2,3] ) ); 76 assertEq( [5,6,1], redimSize( 3, 2, [5,3,2] ) ); 77 assertEq( [5,6], redimSize( 2, 2, [5,3,2] ) ); 78 assertEq( [30,1,1,1], redimSize( 4, 1, [5,3,2] ) ); 79 } 80 81 /// 82 coord_t[] redimSize(A)( size_t N, in A[] size ) pure 83 if( isIntegral!A ) 84 in { assert( isAllCompPositive( size ) ); } 85 body { return redimSize( N, N, size ); } 86 87 /// 88 unittest 89 { 90 assertEq( [1,2,3], redimSize( 3, [1,2,3] ) ); 91 assertEq( [1,2,3,1,1], redimSize( 5, [1,2,3] ) ); 92 assertEq( [1,6], redimSize( 2, [1,2,3] ) ); 93 assertEq( [6], redimSize( 1, [1,2,3] ) ); 94 assertEq( [1,1,1,1], redimSize( 4, cast(int[])[] ) ); 95 } 96 97 /++ get index of element in 1-dim array by N-dim coordinate 98 99 Params: 100 size = N-dim array of sizes by each dimension 101 crd = N-dim array of coordinates in N-dim space 102 103 Returns: 104 index in 1-dim array 105 +/ 106 coord_t getIndex(A,B)( in A[] size, in B[] crd ) pure 107 if( isIntegral!A && isIntegral!B ) 108 in 109 { 110 assert( size.length == crd.length, "array length mismatch" ); 111 assert( isAllCompPositive( size ), "negative size" ); 112 assert( isAllCompPositive( crd ), "negative coordinate" ); 113 assert( all!"a[0]>a[1]"( zip( size, crd ) ), "range violation" ); 114 } 115 body 116 { 117 size_t ret; 118 foreach( i; 0 .. size.length ) 119 { 120 size_t cm = 1UL; 121 foreach( j; 0 .. i ) cm *= size[j]; 122 ret += crd[i] * cm; 123 } 124 return ret; 125 } 126 127 /// 128 unittest 129 { 130 assertEq( getIndex( [3,3], [1,1] ), 4 ); 131 assertEq( getIndex( [4,3], [1,1] ), 5 ); 132 assertEq( getIndex( [3,3,3], [1,1,1] ), 13 ); 133 } 134 135 /++ get coordinate in N-dim space by N-dim size and line index 136 137 Params: 138 size = N-dim array of sizes by each dimension 139 index = index in 1-dim array 140 141 Retrurns: 142 N-dim array of coordinates in N-dim space 143 +/ 144 size_t[] getCoord(A)( in A[] size, size_t index ) pure 145 if( isIntegral!A ) 146 in 147 { 148 assert( isAllCompPositive( size ), "negative size" ); 149 auto maxindex = new A[]( size.length ); 150 foreach( i, ref mi; maxindex ) mi = size[i] - 1; 151 assert( index <= getIndex( size, maxindex ), "range violation" ); 152 } 153 body 154 { 155 size_t buf = index; 156 auto ret = new size_t[]( size.length ); 157 foreach_reverse( i; 0 .. size.length ) 158 { 159 auto vol = reduce!((a,b)=>(a*=b))(1U,size[0..i]); 160 ret[i] = buf / vol; 161 buf = buf % vol; 162 } 163 return ret; 164 } 165 166 /// 167 unittest 168 { 169 assertEq( getCoord( [3,3,3], 13 ), [1,1,1] ); 170 auto size = CrdVector!4( 10, 20, 30, 40 ); 171 auto crd = CrdVector!4( 3, 5, 8, 10 ); 172 assertEq( crd, getCoord( size, getIndex( size, crd ) ) ); 173 } 174 175 /// get line index in origin array by layer line index and layer number 176 size_t getOrigIndexByLayerCoord(A)( in A[] size, size_t dimNo, 177 size_t layerIndex, size_t layerNo ) pure 178 if( isIntegral!A ) 179 in 180 { 181 assert( isAllCompPositive( size ), "negative size" ); 182 assert( dimNo < size.length ); 183 } 184 body 185 { 186 auto layerCrd = getCoord( cut( size, dimNo ), layerIndex ); 187 return getIndex( size, paste( layerCrd, dimNo, layerNo ) ); 188 } 189 190 unittest 191 { 192 assertEq( getOrigIndexByLayerCoord( [3,3,3], 2, 4, 1 ), 13 ); 193 } 194 195 T[] cut(T)( in T[] arr, size_t N ) pure 196 in{ assert( N < arr.length ); } body 197 { return arr[0..N].dup ~ ( arr.length-1 == N ? [] : arr[N+1..$] ); } 198 199 unittest 200 { 201 assertEq( [1,2,3,4].cut(0), [2,3,4] ); 202 assertEq( [1,2,3,4].cut(2), [1,2,4] ); 203 assertEq( [1,2,3,4].cut(3), [1,2,3] ); 204 } 205 206 T[] paste(T)( in T[] arr, size_t N, T value ) pure 207 in{ assert( N <= arr.length ); } body 208 { return arr[0..N].dup ~ value ~ ( arr.length == N ? [] : arr[N..$] ); } 209 210 unittest 211 { 212 assertEq( [1,2,3,4].paste(0,8), [8,1,2,3,4] ); 213 assertEq( [1,2,3,4].paste(3,8), [1,2,3,8,4] ); 214 assertEq( [1,2,3,4].paste(4,8), [1,2,3,4,8] ); 215 } 216 217 unittest 218 { 219 auto orig = [1,2,3,4]; 220 assertEq( orig.paste(0,666).cut(0), orig ); 221 assertEq( orig.paste(1,666).cut(1), orig ); 222 assertEq( orig.paste(2,666).cut(2), orig ); 223 assertEq( orig.paste(3,666).cut(3), orig ); 224 }