1 module des.il.region; 2 3 import std.algorithm; 4 import std.string; 5 import std.traits; 6 import std.typetuple; 7 import std.exception; 8 9 import des.ts; 10 import des.math.linear.vector; 11 12 import des.il.util; 13 14 /// rectangle region of space 15 struct Region(size_t N,T) if( isNumeric!T ) 16 { 17 /// 18 alias Vector!(N,T) vec_t; 19 20 /// 21 alias Region!(N,T) self_t; 22 23 /// 24 vec_t pos, size; 25 26 static if( N == 0 ) 27 { 28 invariant 29 { 30 enforce( pos.length == size.length, "pos and size dimension mismatch" ); 31 } 32 } 33 34 /// 35 pure this(size_t Z,K)( in Region!(Z,K) e ) 36 if( (Z==0||N==0||Z==N) ) 37 { 38 pos = vec_t( e.pos ); 39 size = vec_t( e.size ); 40 } 41 42 /// 43 pure this(E...)( in E ext ) 44 //if( is( typeof( Vector!(N*2,T)(ext) ) ) ) 45 { 46 auto vr = Vector!(N*2,T)(ext); 47 static if( N == 0 ) 48 enforce( vr.length % 2 == 0, "wrong size of input" ); 49 pos = vec_t( vr.data[0..$/2] ); 50 size = vec_t( vr.data[$/2..$] ); 51 } 52 53 /// 54 pure static self_t fromSize(E...)( in E vals ) 55 { 56 auto size = Vector!(N,T)(vals); 57 auto pos = size; 58 foreach( ref v; pos.data ) v = 0; 59 return self_t( pos, size ); 60 } 61 62 pure @property 63 { 64 /// 65 vec_t lim() const { return pos + size; } 66 /// 67 vec_t lim( in vec_t nl ) 68 { 69 size = nl - pos; 70 return vec_t( nl ); 71 } 72 73 /// 74 size_t dims() const 75 { 76 static if( N == 0 ) return pos.length; 77 else return N; 78 } 79 80 static if( N == 0 ) 81 { 82 size_t dims( size_t ndim ) 83 { 84 pos.length = ndim; 85 size.length = ndim; 86 return ndim; 87 } 88 } 89 90 /// multiplication of size components 91 T volume() const 92 { 93 T ret = 1; 94 foreach( s; size ) ret *= s; 95 return ret; 96 } 97 98 /// returns false if any of size components is zero 99 bool hasVolume() const 100 { 101 foreach( s; size ) 102 if( s == 0 ) 103 return false; 104 return true; 105 } 106 } 107 108 /// 109 bool contains(size_t Z,E)( in Vector!(Z,E) pnt ) pure const 110 if( (Z==0||N==0||Z==N) && is(typeof(E.init>T.init)) ) 111 { 112 static if( N==0 || Z==0 ) 113 enforce( pnt.length == dims, "dimension mismatch" ); 114 115 auto l = lim; 116 117 foreach( i; 0 .. dims ) 118 if( pnt[i] < pos[i] || pnt[i] >= l[i] ) 119 return false; 120 121 return true; 122 } 123 124 /// 125 bool contains(size_t Z,E)( in Region!(Z,E) reg ) pure const 126 if( (Z==0||N==0||Z==N) && is(typeof(E.init>T.init)) ) 127 { 128 static if( N==0 || Z==0 ) 129 enforce( reg.pos.length == dims, "dimension mismatch" ); 130 131 return contains( reg.pos ) && contains( reg.lim ); 132 } 133 134 /// 135 bool opBinaryRight(string op, size_t Z, E)( in Vector!(Z,E) pnt ) const 136 if( (Z==0||N==0||Z==N) && op == "in" && is(typeof(E.init>T.init)) ) 137 { return contains( pnt ); } 138 139 static if( N>0 ) 140 { 141 /// 142 bool contains(Args...)( Args args ) pure const 143 if( allSatisfy!( isNumeric, Args ) && Args.length == N ) 144 { return contains( vec_t( args ) ); } 145 } 146 147 /// 148 bool opBinaryRight(string op, size_t Z, E)( in Region!(Z,E) reg ) const 149 if( (Z==0||N==0||Z==N) && op == "in" && is(typeof(E.init>T.init)) ) 150 { return contains( reg ); } 151 152 /// logic and 153 auto overlap(size_t Z, E)( in Region!(Z,E) reg ) const 154 if( (Z==0||N==0||Z==N) ) 155 { 156 static if( N==0 || Z==0 ) 157 enforce( reg.pos.length == dims, "dimension mismatch" ); 158 159 vec_t r1, r2; 160 161 static if( N==0 ) 162 { 163 r1.length = dims; 164 r2.length = dims; 165 } 166 167 auto lll = lim; 168 auto reg_lim = reg.lim; 169 170 foreach( i; 0 .. dims ) 171 { 172 r1[i] = cast(T)( min( max( pos[i], reg.pos[i] ), lll[i] ) ); 173 r2[i] = cast(T)( max( min( lll[i], reg_lim[i] ), pos[i] ) ); 174 } 175 176 return self_t( r1, r2 - r1 ); 177 } 178 179 /// 180 auto overlapLocal(size_t Z, E)( in Region!(Z,E) reg ) const 181 if( (Z==0||N==0||Z==N) ) 182 { 183 static if( N==0 || Z==0 ) 184 enforce( reg.pos.length == dims, "dimension mismatch" ); 185 186 auto buf = overlap( self_t( vec_t(reg.pos) + pos, reg.size ) ); 187 return self_t( buf.pos - pos, buf.size ); 188 } 189 190 /// 191 auto expand(size_t Z, E)( in Region!(Z,E) reg ) const 192 if( (Z==0||N==0||Z==N) ) 193 { 194 static if( N==0 || Z==0 ) 195 enforce( reg.pos.length == dims, "dimension mismatch" ); 196 197 vec_t r1, r2; 198 199 static if( N==0 ) 200 { 201 r1.length = dims; 202 r2.length = dims; 203 } 204 205 auto self_lim = lim; 206 auto reg_lim = reg.lim; 207 208 foreach( i; 0 .. dims ) 209 { 210 r1[i] = min( pos[i], reg.pos[i], self_lim[i], reg_lim[i] ); 211 r2[i] = max( pos[i], reg.pos[i], self_lim[i], reg_lim[i] ); 212 } 213 214 return self_t( r1, r2 - r1 ); 215 } 216 217 /// 218 auto expand(size_t Z, E)( in Vector!(Z,E) pnt ) const 219 if( (Z==0||N==0||Z==N) ) 220 { 221 static if( N==0 || Z==0 ) 222 enforce( pnt.length == dims, "dimension mismatch" ); 223 224 vec_t r1, r2; 225 226 static if( N==0 ) 227 { 228 r1.length = dims; 229 r2.length = dims; 230 } 231 232 auto self_lim = lim; 233 234 foreach( i; 0 .. dims ) 235 { 236 r1[i] = min( pos[i], self_lim[i], pnt[i] ); 237 r2[i] = max( pos[i], self_lim[i], pnt[i] ); 238 } 239 240 return self_t( r1, r2 - r1 ); 241 } 242 } 243 244 /// 245 alias Region!(1,float) fRegion1; 246 /// 247 alias Region!(2,float) fRegion2; 248 /// 249 alias Region!(3,float) fRegion3; 250 251 /// 252 alias Region!(1,int) iRegion1; 253 /// 254 alias Region!(2,int) iRegion2; 255 /// 256 alias Region!(3,int) iRegion3; 257 258 unittest 259 { 260 auto a = fRegion1( 1, 5 ); 261 assert( a.contains(2) ); 262 assert( !a.contains(8) ); 263 assert( a.lim[0] == 6 ); 264 auto b = fRegion1( 2, 3 ); 265 assert( b in a ); 266 } 267 268 /// 269 unittest 270 { 271 auto a = fRegion1(1,5); 272 auto b = fRegion1(2,5); 273 assert( a.overlap(b) == b.overlap(a) ); 274 assert( a.overlap(b) == fRegion1(2,4) ); 275 276 assert( a.overlapLocal(b) == fRegion1(2,3) ); 277 } 278 279 /// 280 unittest 281 { 282 auto a = fRegion1(1,2); 283 auto b = fRegion1(4,2); 284 assert( a.expand(b) == fRegion1(1,5) ); 285 } 286 287 unittest 288 { 289 auto a = fRegion3( vec3(0,0,0), vec3(1,1,1) ); 290 //assert( vec3(.5,.2,.8) in a ); 291 assert( a.opBinaryRight!"in"( vec3(.5,.2,.8) ) ); 292 assert( a == a.expand( vec3(.2,.3,.4) ) ); 293 assert( a != a.expand( vec3(1.2,.3,.4) ) ); 294 assert( fRegion3( vec3(0,0,0), vec3(1.2,1,1) ) == 295 a.expand( vec3(1.2,.3,.4) ) ); 296 } 297 298 /// 299 unittest 300 { 301 alias Region!(5,float) MSR; // MultiSpaceRegtion 302 alias MSR.vec_t msrvec; 303 auto a = MSR( msrvec(1,0,3,4,3), msrvec(3,2,4,8,4) ); 304 assert( msrvec(2,1,4,5,5) in a ); 305 } 306 307 /// 308 unittest 309 { 310 auto a = fRegion2( vec2(1,1), vec2(2,2) ); 311 assert( a.contains(2,2) ); 312 } 313 314 /// 315 unittest 316 { 317 alias NReg = Region!(0,float); 318 auto r1 = NReg( 1,2,3,4 ); 319 assertEq( r1.dims, 2 ); 320 assertEq( r1.pos.data, [1,2] ); 321 assertEq( r1.size.data, [3,4] ); 322 323 assert( vec2(2,3) in r1 ); 324 325 auto r2 = NReg( 1,2 ); 326 assertEq( r2.dims, 1 ); 327 assertEq( r2.pos.data, [1] ); 328 assertEq( r2.size.data, [2] ); 329 330 assert( Vector!(0,float)(1.4) in r2 ); 331 r2.dims = 3; 332 r2.pos = vec3(1,2,3); 333 r2.size = vec3(1,2,3); 334 //mustExcept({ r2.size = vec2(1,2); }); // uncatcable exception from invariant 335 r2 = NReg( vec2(1,2), vec2(3,2) ); 336 assert( vec2(2,3) in r2 ); 337 }