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