1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkPixelExtenth.h
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkPixelExtent.h"
16
17 using std::deque;
18 using std::ostream;
19
20 //-----------------------------------------------------------------------------
Grow(const vtkPixelExtent & inputExt,const vtkPixelExtent & problemDomain,int n)21 vtkPixelExtent vtkPixelExtent::Grow(
22 const vtkPixelExtent &inputExt,
23 const vtkPixelExtent &problemDomain,
24 int n)
25 {
26 vtkPixelExtent outputExt = vtkPixelExtent::Grow(inputExt, n);
27 outputExt &= problemDomain;
28 return outputExt;
29 }
30
31 //-----------------------------------------------------------------------------
Grow(const vtkPixelExtent & inputExt,int n)32 vtkPixelExtent vtkPixelExtent::Grow(
33 const vtkPixelExtent &inputExt,
34 int n)
35 {
36 vtkPixelExtent outputExt(inputExt);
37 outputExt.Grow(0, n);
38 outputExt.Grow(1, n);
39 return outputExt;
40 }
41
42 //-----------------------------------------------------------------------------
GrowLow(const vtkPixelExtent & inputExt,int q,int n)43 vtkPixelExtent vtkPixelExtent::GrowLow(
44 const vtkPixelExtent &inputExt,
45 int q,
46 int n)
47 {
48 vtkPixelExtent outputExt(inputExt);
49 outputExt[2*q] -= n;
50 return outputExt;
51 }
52
53 //-----------------------------------------------------------------------------
GrowHigh(const vtkPixelExtent & inputExt,int q,int n)54 vtkPixelExtent vtkPixelExtent::GrowHigh(
55 const vtkPixelExtent &inputExt,
56 int q,
57 int n)
58 {
59 vtkPixelExtent outputExt(inputExt);
60 outputExt[2*q+1] += n;
61 return outputExt;
62 }
63
64 //-----------------------------------------------------------------------------
Shrink(const vtkPixelExtent & inputExt,int n)65 vtkPixelExtent vtkPixelExtent::Shrink(
66 const vtkPixelExtent &inputExt,
67 int n)
68 {
69 return vtkPixelExtent::Grow(inputExt, -n);
70 }
71
72 //-----------------------------------------------------------------------------
Shrink(const vtkPixelExtent & inputExt,const vtkPixelExtent & problemDomain,int n)73 vtkPixelExtent vtkPixelExtent::Shrink(
74 const vtkPixelExtent &inputExt,
75 const vtkPixelExtent &problemDomain,
76 int n)
77 {
78 vtkPixelExtent outputExt(inputExt);
79
80 outputExt.Grow(0, -n);
81 outputExt.Grow(1, -n);
82
83 // don't shrink at the problem domain
84 // because you don't grow outside the problem domain.
85 for (int i=0; i<4; ++i)
86 {
87 if (inputExt[i] == problemDomain[i])
88 {
89 outputExt[i] = problemDomain[i];
90 }
91 }
92
93 return outputExt;
94 }
95
96 //-----------------------------------------------------------------------------
CellToNode(const vtkPixelExtent & inputExt)97 vtkPixelExtent vtkPixelExtent::CellToNode(
98 const vtkPixelExtent &inputExt)
99 {
100 vtkPixelExtent outputExt(inputExt);
101 ++outputExt[1];
102 ++outputExt[3];
103 return outputExt;
104 }
105
106 //-----------------------------------------------------------------------------
NodeToCell(const vtkPixelExtent & inputExt)107 vtkPixelExtent vtkPixelExtent::NodeToCell(const vtkPixelExtent &inputExt)
108 {
109 vtkPixelExtent outputExt(inputExt);
110 --outputExt[1];
111 --outputExt[3];
112 return outputExt;
113 }
114
115 //-----------------------------------------------------------------------------
Shift(int * ij,int n)116 void vtkPixelExtent::Shift(
117 int *ij,
118 int n)
119 {
120 ij[0] += n;
121 ij[1] += n;
122 }
123
124 //-----------------------------------------------------------------------------
Shift(int * ij,int * n)125 void vtkPixelExtent::Shift(
126 int *ij,
127 int *n)
128 {
129 ij[0] += n[0];
130 ij[1] += n[1];
131 }
132
133 //-----------------------------------------------------------------------------
Split(int i1,int j1,const vtkPixelExtent & ext,deque<vtkPixelExtent> & newExts)134 void vtkPixelExtent::Split(
135 int i1,
136 int j1,
137 const vtkPixelExtent &ext,
138 deque<vtkPixelExtent> &newExts)
139 {
140 // cell is inside, split results in as many as
141 // 4 new extents. check for each one.
142 int i0 = i1 - 1;
143 int j0 = j1 - 1;
144
145 int outside = 1;
146
147 // lower left
148 if (ext.Contains(i0, j0))
149 {
150 newExts.push_back(vtkPixelExtent(ext[0], i0, ext[2], j0));
151 outside = 0;
152 }
153 // lower right
154 if (ext.Contains(i1, j0))
155 {
156 newExts.push_back(vtkPixelExtent(i1, ext[1], ext[2], j0));
157 outside = 0;
158 }
159 // upper left
160 if (ext.Contains(i0, j1))
161 {
162 newExts.push_back(vtkPixelExtent(ext[0], i0, j1, ext[3]));
163 outside = 0;
164 }
165 // upper right
166 if (ext.Contains(i1, j1))
167 {
168 newExts.push_back(vtkPixelExtent(i1, ext[1], j1, ext[3]));
169 outside = 0;
170 }
171
172 // split cell is outside, pass through
173 if (outside)
174 {
175 newExts.push_back(ext);
176 return;
177 }
178 }
179
180 //-----------------------------------------------------------------------------
Subtract(const vtkPixelExtent & A,vtkPixelExtent B,deque<vtkPixelExtent> & C)181 void vtkPixelExtent::Subtract(
182 const vtkPixelExtent &A,
183 vtkPixelExtent B,
184 deque<vtkPixelExtent> &C)
185 {
186 // split method requires split point inside the extent
187 vtkPixelExtent I(A);
188 I &= B;
189
190 if (I.Empty())
191 {
192 // do nothing if disjoint
193 C.push_back(A);
194 return;
195 }
196 if (B.Contains(A))
197 {
198 // if A is covered by B then remove A
199 return;
200 }
201
202 // split left and bellow this cells
203 I.CellToNode();
204
205 deque<vtkPixelExtent> tmpA0;
206 tmpA0.push_back(A);
207 for (int q=0; q<4; ++q)
208 {
209 const int ids[8] = {0,2, 1,2, 1,3, 0,3};
210 int qq = 2*q;
211 int i = I[ids[qq]];
212 int j = I[ids[qq+1]];
213 deque<vtkPixelExtent> tmpA1;
214 while ( !tmpA0.empty() )
215 {
216 vtkPixelExtent ext = tmpA0.back();
217 tmpA0.pop_back();
218 vtkPixelExtent::Split(i,j, ext, tmpA1);
219 }
220 tmpA0 = tmpA1;
221 }
222
223 // remove anything covered by B
224 size_t n = tmpA0.size();
225 for (size_t q=0; q<n; ++q)
226 {
227 const vtkPixelExtent &ext = tmpA0[q];
228 if (!B.Contains(ext))
229 {
230 C.push_back(ext);
231 }
232 }
233 }
234
235 // ----------------------------------------------------------------------------
Merge(deque<vtkPixelExtent> & exts)236 void vtkPixelExtent::Merge(deque<vtkPixelExtent> &exts)
237 {
238 size_t ne = exts.size();
239
240 // working in point space simplifies things because
241 // points overlap in adjacent extents while cells do not
242 deque<vtkPixelExtent> tmpExts(ne);
243 for (size_t t=0; t<ne; ++t)
244 {
245 vtkPixelExtent ext(exts[t]);
246 ext.CellToNode();
247 tmpExts[t] = ext;
248 }
249
250 // one pass for each direction
251 for (int q=0; q<2; ++q)
252 {
253 int qq = 2*q;
254 // consider each extent as a target to be merged
255 for (size_t t=0; t<ne; ++t)
256 {
257 // if a merger occurs the merged extent is added
258 // as a new target with the constituents marked empty
259 // and the current pass is terminated early
260 bool nextPass = false;
261
262 // current target
263 vtkPixelExtent &ext0 = tmpExts[t];
264 if (ext0.Empty())
265 {
266 // was merged in preceeding pass
267 continue;
268 }
269
270 for (size_t c=0; c<ne; ++c)
271 {
272 if (c == t)
273 {
274 // don't attempt merge with self
275 continue;
276 }
277
278 // candidate
279 vtkPixelExtent &ext1 = tmpExts[c];
280 if (ext1.Empty())
281 {
282 // was merged in preceeding pass
283 continue;
284 }
285
286 // must be same size and coordinate in merge dir
287 if ( (ext0[qq] == ext1[qq]) && (ext0[qq+1] == ext1[qq+1]) )
288 {
289 // must overlap overlap
290 vtkPixelExtent ext2(ext0);
291 ext2 &= ext1;
292 if (!ext2.Empty())
293 {
294 // merge and add as new target
295 // in a later pass
296 vtkPixelExtent ext3(ext0);
297 ext3 |= ext1;
298 tmpExts.push_back(ext3);
299 ++ne;
300
301 // mark the merged extents empty
302 ext0.Clear();
303 ext1.Clear();
304
305 // move to next target
306 nextPass = true;
307 }
308 }
309 if (nextPass)
310 {
311 break;
312 }
313 }
314 }
315 }
316 // discard merged targets copy to output
317 exts.clear();
318 for (size_t t=0; t<ne; ++t)
319 {
320 vtkPixelExtent &ext = tmpExts[t];
321 if (!ext.Empty())
322 {
323 ext.NodeToCell();
324 exts.push_back(ext);
325 }
326 }
327 }
328
329 //*****************************************************************************
operator <<(ostream & os,const vtkPixelExtent & ext)330 ostream &operator<<(ostream &os, const vtkPixelExtent &ext)
331 {
332 if (ext.Empty())
333 {
334 os << "(empty)";
335 }
336 else
337 {
338 os
339 << "("
340 << ext[0] << ", "
341 << ext[1] << ", "
342 << ext[2] << ", "
343 << ext[3] << ")";
344 }
345 return os;
346 }
347