1 /+
2 The MIT License (MIT)
3 
4     Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)>
5 
6     Permission is hereby granted, free of charge, to any person obtaining a copy
7     of this software and associated documentation files (the "Software"), to deal
8     in the Software without restriction, including without limitation the rights
9     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10     copies of the Software, and to permit persons to whom the Software is
11     furnished to do so, subject to the following conditions:
12 
13     The above copyright notice and this permission notice shall be included in
14     all copies or substantial portions of the Software.
15 
16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22     THE SOFTWARE.
23 +/
24 
25 module des.il.region;
26 
27 import std.algorithm;
28 import std.string;
29 import std.traits;
30 import des.math.linear.vector;
31 
32 import des.il.util;
33 
34 /// rectangle region of space
35 struct Region(size_t N,T)
36     if( N >= 1 && isNumeric!T )
37 {
38     ///
39     alias CoordVector!(N,T) ptype;
40     ///
41     alias VolumeVector!(N,T) rtype;
42 
43     ///
44     alias Region!(N,T) selftype;
45 
46     union
47     {
48         /// in union with [pt](des/il/region/Region.pt.html)
49         rtype vr;
50         /// in union with [vr](des/il/region/Region.vr.html)
51         ptype[2] pt;
52     }
53 
54     ///
55     alias vr this;
56 
57     ///
58     pure this(K)( in Region!(N,K) e ) { vr = e.vr; }
59 
60     ///
61     pure this(E...)( in E ext )
62         if( is( typeof( rtype(ext) ) ) )
63     { vr = rtype(ext); }
64 
65     @property
66     {
67         ///
68         ref ptype pos() { return pt[0]; }
69         ///
70         ref ptype size() { return pt[1]; }
71 
72         ///
73         ptype pos() const { return pt[0]; }
74         ///
75         ptype size() const { return pt[1]; }
76 
77         ///
78         ptype lim() const { return pt[0] + pt[1]; }
79         ///
80         ptype lim( in ptype nl )
81         {
82             pt[1] = nl - pt[0];
83             return nl;
84         }
85     }
86 
87     ///
88     bool opBinaryRight(string op, E, alias string AS)( in Vector!(N,E,AS) p ) const
89         if( op == "in" && is(typeof(typeof(p).init[0] > rtype.init[0])) )
90     { 
91         foreach( i; 0 .. N )
92             if( p[i] < vr[i] || p[i] >= vr[i] + vr[i+N] )
93                 return false;
94         return true;
95     }
96 
97     static if(N==1)
98     {
99         bool opBinaryRight(string op, E)( in E p ) const
100             if( isNumeric!E && op == "in" )
101         { return p >= vr[0] && p < vr[0] + vr[1]; }
102     }
103 
104     ///
105     bool opBinaryRight(string op, E)( in Region!(N,E) p ) const
106         if( is( generalType!(T,E) ) && op == "in" )
107     { return ( p.pt[0] in this ) && ( p.pt[1] in this ); }
108 
109     /// logic and
110     auto overlap(E)( in Region!(N,E) reg ) const
111     {
112         ptype r1, r2;
113 
114         foreach( i; 0 .. N )
115         {
116             r1[i] = min( max( pos[i], reg.pos[i] ), lim[i] );
117             r2[i] = max( min( lim[i], reg.lim[i] ), pos[i] );
118         }
119 
120         return selftype( r1, r2 - r1 );
121     }
122 
123     ///
124     auto overlapLocal(E)( in Region!(N,E) reg ) const
125     {
126         auto buf = overlap( selftype( ptype(reg.pt[0]) + pt[0], reg.pt[1] ) );
127         return selftype( buf.pt[0] - pt[0], buf.pt[1] );
128     }
129 
130     ///
131     auto expand(E)( in Region!(N,E) reg ) const
132     {
133         ptype r1, r2;
134 
135         foreach( i; 0 .. N )
136         {
137             r1[i] = min( pos[i], reg.pos[i], lim[i], reg.lim[i] );
138             r2[i] = max( pos[i], reg.pos[i], lim[i], reg.lim[i] );
139         }
140 
141         return selftype( r1, r2 - r1 );
142     }
143 
144     ///
145     auto expand(E)( in E pnt ) const
146         if( isCompatibleVector!(N,T,E) )
147     {
148         ptype r1, r2;
149 
150         foreach( i; 0 .. N )
151         {
152             r1[i] = min( pos[i], lim[i], pnt[i] );
153             r2[i] = max( pos[i], lim[i], pnt[i] );
154         }
155 
156         return selftype( r1, r2 - r1 );
157     }
158 }
159 
160 ///
161 alias Region!(1,float) fRegion1;
162 ///
163 alias Region!(2,float) fRegion2;
164 ///
165 alias Region!(3,float) fRegion3;
166 
167 ///
168 alias Region!(1,int) iRegion1;
169 ///
170 alias Region!(2,int) iRegion2;
171 ///
172 alias Region!(3,int) iRegion3;
173 
174 unittest
175 {
176     auto a = fRegion1( 1, 5 );
177     assert( 2 in a );
178     assert( 8 !in a );
179     assert( a.lim[0] == 6 );
180     auto b = fRegion1( 2, 3 );
181     assert( b in a );
182 }
183 
184 ///
185 unittest
186 {
187     auto a = fRegion1(1,5);
188     auto b = fRegion1(2,5);
189     assert( a.overlap(b) == b.overlap(a) );
190     assert( a.overlap(b) == fRegion1(2,4) );
191 
192     assert( a.overlapLocal(b) == fRegion1(2,3) );
193 }
194 
195 ///
196 unittest
197 {
198     auto a = fRegion1(1,2);
199     auto b = fRegion1(4,2);
200     assert( a.expand(b) = fRegion1(1,5) );
201 }
202 
203 unittest
204 {
205     auto a = fRegion3( vec3(0,0,0), vec3(1,1,1) );
206     assert( vec3(.5,.2,.8) in a );
207     assert( a == a.expand( vec3(.2,.3,.4) ) );
208     assert( a != a.expand( vec3(1.2,.3,.4) ) );
209     assert( fRegion3( vec3(0,0,0), vec3(1.2,1,1) ) == 
210              a.expand( vec3(1.2,.3,.4) ) );
211 }
212 
213 ///
214 unittest
215 {
216     alias Region!(5,float) MSR; // MultiSpaceRegtion
217     alias MSR.ptype msrvec;
218     auto a = MSR( msrvec(1,0,3,4,3), msrvec(3,2,4,8,4) );
219     assert( msrvec(2,1,4,5,5) in a );
220 }