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 ///
15 class ImageException : Exception
16 {
17     ///
18     this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow
19     { super( msg, file, line ); } 
20 }
21 
22 string coordinateAccessString( size_t N ) pure
23 {
24     if( N > 3 ) return "";
25 
26     string[] v1 = [ "x", "y", "z" ][0 .. N];
27     string[] v2 = [ "abscissa", "ordinate", "applicate" ][0 .. N];
28 
29     return arrayAccessStringCtor( VVASES, VVASVS, v1, v2 );
30 }
31 
32 unittest
33 {
34     static assert( coordinateAccessString(4) == "" );
35     static assert( coordinateAccessString(3) == "x y z|abscissa ordinate applicate" );
36     static assert( coordinateAccessString(2) == "x y|abscissa ordinate" );
37     static assert( isCompatibleArrayAccessStrings( 2, coordinateAccessString(2), VVASES, VVASVS ) ); 
38 }
39 
40 string sizeAccessString( size_t N ) pure 
41 {
42     if( N > 3 ) return "";
43 
44     string[] v1 = [ "w", "h", "d" ][0 .. N];
45     string[] v2 = [ "width", "height", "depth" ][0 .. N];
46 
47     return arrayAccessStringCtor( VVASES, VVASVS, v1, v2 );
48 }
49 
50 unittest
51 {
52     static assert( sizeAccessString(4) == "" );
53     static assert( sizeAccessString(3) == "w h d|width height depth" );
54     static assert( sizeAccessString(2) == "w h|width height" );
55     static assert( isCompatibleArrayAccessStrings( 2, sizeAccessString(2), VVASES, VVASVS ) ); 
56 }
57 
58 string volumeAccessString( size_t N )
59 {
60     if( N > 3 ) return "";
61 
62     string[] c1 = [ "x", "y", "z" ][0 .. N];
63     string[] c2 = [ "abscissa", "ordinate", "applicate" ][0 .. N];
64 
65     string[] s1 = [ "w", "h", "d" ][0 .. N];
66     string[] s2 = [ "width", "height", "depth" ][0 .. N];
67 
68     return arrayAccessStringCtor( VVASES, VVASVS, c1 ~ s1, c2 ~ s2 );
69 }
70 
71 unittest
72 {
73     static assert( volumeAccessString(4) == "" );
74     static assert( volumeAccessString(3) == "x y z w h d|abscissa ordinate applicate width height depth" );
75     static assert( volumeAccessString(2) == "x y w h|abscissa ordinate width height" );
76     static assert( isCompatibleArrayAccessStrings( 4, volumeAccessString(2), VVASES, VVASVS ) ); 
77 }
78 
79 ///
80 alias CoordType = ptrdiff_t;
81 ///
82 alias CoordVector(size_t N,T=CoordType) = Vector!(N,T,coordinateAccessString(N));
83 ///
84 alias SizeVector(size_t N,T=CoordType) = Vector!(N,T,sizeAccessString(N));
85 ///
86 alias VolumeVector(size_t N,T=CoordType) = Vector!(N*2,T,volumeAccessString(N));
87 
88 /++ checks all components
89  Returns:
90  true if all is positive
91  +/
92 bool isAllCompPositive(V)( in V v )
93     if( is( typeof( v[0] ) ) && isNumeric!(typeof(v[0])) )
94 {
95     foreach( e; v ) if( e < 0 ) return false;
96     return true;
97 }
98 
99 ///
100 unittest
101 {
102     assert(  isAllCompPositive( [1,2,3] ) );
103     assert(  isAllCompPositive( vec3( 1,2,3 ) ) );
104     assert(  isAllCompPositive( SizeVector!3( 1,2,3 ) ) );
105     assert( !isAllCompPositive( [-1,2,3] ) );
106 }
107 
108 /++ get index of element in 1-dim array by N-dim coordinate
109 
110  Params:
111  size = N-dim array of sizes by each dimension
112  crd = N-dim array of coordinates in N-dim space
113 
114  Returns:
115  index in 1-dim array
116  +/
117 size_t getIndex(size_t N)( in CoordType[N] size, in CoordType[N] crd ) pure
118 in
119 {
120     assert( isAllCompPositive( size ) );
121     assert( isAllCompPositive( crd ) );
122     assert( all!"a[0]>a[1]"( zip( size.dup, crd.dup ) ), "range violation" );
123 }
124 body
125 {
126     size_t ret;
127     foreach( i; 0 .. N )
128     {
129         auto v = reduce!((a,b)=>(a*=b))(1UL,size[0..i]);
130         ret += crd[i] * v;
131     }
132     return ret;
133 }
134 
135 version(todos) pragma( msg, __FILE__,":", __LINE__, " TODO: add tests to indexCalc" );
136 
137 /++ get coordinate in N-dim space by N-dim size and line index
138  
139  Params:
140  size = N-dim array of sizes by each dimension
141  index = index in 1-dim array
142 
143  Retrurns:
144  N-dim array of coordinates in N-dim space
145  +/
146 CoordType[N] getCoord(size_t N)( in CoordType[N] size, size_t index ) pure
147 in
148 {
149     assert( isAllCompPositive( size ) );
150     assert( index <= getIndex( size, to!(CoordType[N])( amap!(a=>a-1)(size.dup) ) ), "range violation" );
151 }
152 body
153 {
154     size_t buf = index;
155     CoordType[N] ret;
156     foreach_reverse( i; 0 .. N )
157     {
158         auto vol = reduce!((a,b)=>(a*=b))(1U,size[0..i]);
159         ret[i] = buf / vol;
160         buf = buf % vol;
161     }
162     return ret;
163 }
164 
165 unittest
166 {
167     CoordType[4] size = [ 10, 20, 30, 40 ];
168     CoordType[4] crd = [ 3, 5, 8, 10 ];
169     assert( eq( crd, getCoord( size, getIndex( size, crd ) ) ) );
170 }
171 
172 /++ get line index in origin array by layer line index and layer number
173 
174  Params:
175  size = original size
176  K = number of dimension
177  lindex = line index in layer
178  lno = layer number
179  +/
180 size_t getOrigIndexByLayerCoord(size_t N)( in CoordType[N] size, size_t K, size_t lindex, size_t lno ) pure
181 in { assert( K < N ); } body
182 {
183     auto lcrd = getCoord( removeStat( size, K ), lindex );
184     return getIndex( size, pasteStat( lcrd, K, lno ) );
185 }
186 
187 /++ remove value from static array
188 
189  Params:
190  arr = array
191  K = index to remove
192  +/
193 T[N-1] removeStat(T,size_t N)( in T[N] arr, size_t K ) pure
194 in { assert( K < N ); } body
195 {
196     if( K == N-1 ) return cast(T[N-1])arr[0..$-1];
197     else return to!(T[N-1])( arr[0..K] ~ arr[K+1..$] );
198 }
199 
200 ///
201 unittest
202 {
203     size_t[3] arr = [ 0, 1, 2 ];
204     static assert( is( typeof( removeStat( arr, 0 ) ) == size_t[2] ) );
205 
206     assert( eq( removeStat( arr, 0 ), [1,2] ) );
207     assert( eq( removeStat( arr, 1 ), [0,2] ) );
208     assert( eq( removeStat( arr, 2 ), [0,1] ) );
209 }
210 
211 /++ paste value to static array
212 
213  Params:
214  arr = array
215  K = index to paste
216  val = value to paste
217  +/
218 T[N+1] pasteStat(T,size_t N)( in T[N] arr, size_t K, T val ) pure
219 in { assert( K <= N ); } body
220 {
221     if( K == N ) return to!(T[N+1])( arr ~ val );
222     else return to!(T[N+1])( arr[0..K] ~ val ~ arr[K..$] );
223 }
224 
225 ///
226 unittest
227 {
228     size_t[3] arr = [ 0, 1, 2 ];
229     static assert( is( typeof( pasteStat( arr, 0, 10 ) ) == size_t[4] ) );
230 
231     assert( eq( pasteStat( arr, 0, 10 ), [10,0,1,2] ) );
232     assert( eq( pasteStat( arr, 1, 10 ), [0,10,1,2] ) );
233     assert( eq( pasteStat( arr, 3, 10 ), [0,1,2,10] ) );
234 }