1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkSurfaceLICComposite.cxx
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 "vtkSurfaceLICComposite.h"
16 
17 #include "vtkObjectFactory.h"
18 #include "vtkPixelExtent.h"
19 #include "vtkPixelExtentIO.h"
20 
21 #include <algorithm>
22 #include <cmath>
23 
24 using std::deque;
25 using std::vector;
26 
27 // Enable debug output
28 // 0 -- off
29 // 1 -- dump extents
30 // 2 -- all
31 #define vtkSurfaceLICCompositeDEBUG 0
32 
33 //------------------------------------------------------------------------------
34 vtkObjectFactoryNewMacro(vtkSurfaceLICComposite);
35 
36 //------------------------------------------------------------------------------
vtkSurfaceLICComposite()37 vtkSurfaceLICComposite::vtkSurfaceLICComposite()
38   : Pass(0)
39   , WindowExt()
40   , Strategy(COMPOSITE_AUTO)
41   , StepSize(0)
42   , NumberOfSteps(0)
43   , NormalizeVectors(1)
44   , NumberOfGuardLevels(1)
45 {
46 }
47 
48 //------------------------------------------------------------------------------
49 vtkSurfaceLICComposite::~vtkSurfaceLICComposite() = default;
50 
51 //------------------------------------------------------------------------------
Initialize(const vtkPixelExtent & winExt,const deque<vtkPixelExtent> & blockExts,int strategy,double stepSize,int nSteps,int normalizeVectors,int enhancedLIC,int antialias)52 void vtkSurfaceLICComposite::Initialize(const vtkPixelExtent& winExt,
53   const deque<vtkPixelExtent>& blockExts, int strategy, double stepSize, int nSteps,
54   int normalizeVectors, int enhancedLIC, int antialias)
55 {
56   this->Pass = 0;
57   this->WindowExt = winExt;
58   this->BlockExts = blockExts;
59   this->CompositeExt.clear();
60   this->GuardExt.clear();
61   this->DisjointGuardExt.clear();
62   this->Strategy = strategy;
63   this->StepSize = stepSize;
64   this->NumberOfSteps = nSteps;
65   this->NormalizeVectors = normalizeVectors;
66   // TODO -- FIXME
67   // type of NumberOfGuardLevels should be float. The change is
68   // fairly involved and needs to be thoroughly tested. Note too
69   // few guard pixels and you get an incorrect result, too many
70   // and you destroy performance and scaling. while getting this
71   // right the following will quiets dashboard warnings and keeps
72   // the existing well tested behavior.
73   this->NumberOfGuardLevels = 1;
74   // this->NumberOfGuardLevels = enhancedLIC ? 1.5 : 1;
75   this->NumberOfEEGuardPixels = enhancedLIC ? 1 : 0;
76   this->NumberOfAAGuardPixels = 2 * antialias;
77 }
78 
79 //------------------------------------------------------------------------------
VectorMax(const deque<vtkPixelExtent> & exts,float * vectors,vector<float> & vMax)80 int vtkSurfaceLICComposite::VectorMax(
81   const deque<vtkPixelExtent>& exts, float* vectors, vector<float>& vMax)
82 {
83 #if vtkSurfaceLICCompositeDEBUG >= 2
84   cerr << "=====vtkSurfaceLICComposite::VectorMax" << endl;
85 #endif
86 
87   // find the max on each extent
88   size_t nBlocks = exts.size();
89   vector<float> tmpMax(nBlocks, 0.0f);
90   for (size_t b = 0; b < nBlocks; ++b)
91   {
92     tmpMax[b] = this->VectorMax(exts[b], vectors);
93   }
94 
95   // use larger of this extent and its neighbors
96   vMax.resize(nBlocks, 0.0f);
97   for (size_t a = 0; a < nBlocks; ++a)
98   {
99     vtkPixelExtent extA = exts[a];
100     extA.Grow(1);
101     for (size_t b = 0; b < nBlocks; ++b)
102     {
103       vtkPixelExtent extB = exts[b];
104       extB &= extA;
105 
106       // it's a neighbor(or self) use the larger of ours and theirs
107       if (!extB.Empty())
108       {
109         vMax[a] = vMax[a] < tmpMax[b] ? tmpMax[b] : vMax[a];
110       }
111     }
112   }
113 
114   return 0;
115 }
116 
117 //------------------------------------------------------------------------------
VectorMax(const vtkPixelExtent & ext,float * vectors)118 float vtkSurfaceLICComposite::VectorMax(const vtkPixelExtent& ext, float* vectors)
119 {
120 #if vtkSurfaceLICCompositeDEBUG >= 2
121   cerr << "=====vtkSurfaceLICComposite::VectorMax" << endl;
122 #endif
123 
124   int nx[2];
125   this->WindowExt.Size(nx);
126 
127   // find the max over this region
128   // scaling by 1/nx since that's what LIC'er does.
129   float eMax = 0.0;
130   for (int j = ext[2]; j <= ext[3]; ++j)
131   {
132     int idx = 4 * (nx[0] * j + ext[0]);
133     for (int i = ext[0]; i <= ext[1]; ++i, idx += 4)
134     {
135       float eMag = 0.0;
136       for (int c = 0; c < 2; ++c)
137       {
138         float eVec = vectors[idx + c] / static_cast<float>(nx[c]);
139         eMag += eVec * eVec;
140       }
141       eMag = sqrt(eMag);
142       eMax = eMax < eMag ? eMag : eMax;
143     }
144   }
145 
146   return eMax;
147 }
148 
149 //------------------------------------------------------------------------------
MakeDecompDisjoint(const deque<vtkPixelExtent> & in,deque<vtkPixelExtent> & out,float * vectors)150 int vtkSurfaceLICComposite::MakeDecompDisjoint(
151   const deque<vtkPixelExtent>& in, deque<vtkPixelExtent>& out, float* vectors)
152 {
153 #if vtkSurfaceLICCompositeDEBUG >= 2
154   cerr << "=====vtkSurfaceLICComposite::MakeDecompDisjoint" << endl;
155 #endif
156 
157   // serial implementation
158 
159   // sort by size
160   deque<vtkPixelExtent> tmpIn(in);
161   sort(tmpIn.begin(), tmpIn.end());
162 
163   // from largest to smallest, make it disjoint
164   // to others. This order has the best chance of
165   // leaving each rank with some data.
166   deque<vtkPixelExtent> tmpOut0;
167 
168   vtkSurfaceLICComposite::MakeDecompDisjoint(tmpIn, tmpOut0);
169 
170   // minimize and remove empty extents.
171   int nx[2];
172   this->WindowExt.Size(nx);
173   while (!tmpOut0.empty())
174   {
175     vtkPixelExtent outExt = tmpOut0.back();
176     tmpOut0.pop_back();
177 
178     GetPixelBounds(vectors, nx[0], outExt);
179     if (!outExt.Empty())
180     {
181       out.push_back(outExt);
182     }
183   }
184 
185   /*
186   // merge compatible extents
187   vtkPixelExtent::Merge(tmpOut0);
188   */
189 
190   return 0;
191 }
192 
193 //------------------------------------------------------------------------------
MakeDecompDisjoint(deque<vtkPixelExtent> & in,deque<vtkPixelExtent> & out)194 int vtkSurfaceLICComposite::MakeDecompDisjoint(
195   deque<vtkPixelExtent>& in, deque<vtkPixelExtent>& out)
196 {
197   while (!in.empty())
198   {
199     // for each element
200     deque<vtkPixelExtent> tmpOut(1, in.back());
201     in.pop_back();
202 
203     // subtract other elements
204     // to make it disjoint
205     size_t ns = in.size();
206     for (size_t se = 0; se < ns; ++se)
207     {
208       vtkPixelExtent& selem = in[se];
209       deque<vtkPixelExtent> tmpOut2;
210       size_t nl = tmpOut.size();
211       for (size_t le = 0; le < nl; ++le)
212       {
213         vtkPixelExtent& lelem = tmpOut[le];
214         vtkPixelExtent::Subtract(lelem, selem, tmpOut2);
215       }
216       tmpOut = tmpOut2;
217     }
218 
219     // append new disjoint elements
220     out.insert(out.end(), tmpOut.begin(), tmpOut.end());
221   }
222 
223   return 0;
224 }
225 
226 // TODO -- this is needed in part because our step size is incorrect
227 // due to anisotropic (in aspect ratio) trasnsform to texture
228 // space. see how we transform step size in surface lic painter.
229 // also there is bleeding at the edges so you do need a bit extra
230 // paddding.
231 //------------------------------------------------------------------------------
GetFudgeFactor(int nx[2])232 float vtkSurfaceLICComposite::GetFudgeFactor(int nx[2])
233 {
234   float aspect = float(nx[0]) / float(nx[1]);
235   float fudge = (aspect > 4.0f) ? 3.0f
236                                 : (aspect > 1.0f)
237       ? (2.0f / 3.0f) * aspect + (5.0f / 6.0f)
238       : (aspect < 0.25) ? 3.0f : (aspect < 1.0f) ? (-8.0f / 3.0f) * aspect + (25.0f / 6.0f) : 1.5f;
239   return fudge;
240 }
241 
242 //------------------------------------------------------------------------------
AddGuardPixels(const deque<vtkPixelExtent> & exts,deque<vtkPixelExtent> & guardExts,deque<vtkPixelExtent> & disjointGuardExts,float * vectors)243 int vtkSurfaceLICComposite::AddGuardPixels(const deque<vtkPixelExtent>& exts,
244   deque<vtkPixelExtent>& guardExts, deque<vtkPixelExtent>& disjointGuardExts, float* vectors)
245 {
246 #if vtkSurfaceLICCompositeDEBUG >= 2
247   cerr << "=====vtkSurfaceLICComposite::AddGuardPixles" << endl;
248 #endif
249 
250   int nx[2];
251   this->WindowExt.Size(nx);
252   float fudge = this->GetFudgeFactor(nx);
253   float arc = this->StepSize * this->NumberOfSteps * this->NumberOfGuardLevels * fudge;
254 
255   if (this->NormalizeVectors)
256   {
257     // when normalizing velocity is always 1, all extents have the
258     // same number of guard cells.
259     int ng = static_cast<int>(arc) + this->NumberOfEEGuardPixels + this->NumberOfAAGuardPixels;
260     ng = ng < 2 ? 2 : ng;
261     // cerr << "ng=" << ng << endl;
262     deque<vtkPixelExtent> tmpExts(exts);
263     size_t nExts = tmpExts.size();
264     // add guard pixels
265     for (size_t b = 0; b < nExts; ++b)
266     {
267       tmpExts[b].Grow(ng);
268       tmpExts[b] &= this->DataSetExt;
269     }
270     guardExts = tmpExts;
271     // make sure it's disjoint
272     disjointGuardExts.clear();
273     this->MakeDecompDisjoint(tmpExts, disjointGuardExts);
274   }
275   else
276   {
277     // when not normailzing during integration we need max(V) on the LIC
278     // decomp. Each domain has the potential to require a unique number
279     // of guard cells.
280     vector<float> vectorMax;
281     this->VectorMax(exts, vectors, vectorMax);
282     // cerr << "ng=";
283     deque<vtkPixelExtent> tmpExts(exts);
284     size_t nExts = tmpExts.size();
285     // add guard pixels
286     for (size_t b = 0; b < nExts; ++b)
287     {
288       int ng = static_cast<int>(
289         vectorMax[b] * arc + this->NumberOfEEGuardPixels + this->NumberOfAAGuardPixels);
290       ng = ng < 2 ? 2 : ng;
291       // cerr << " " << ng;
292       tmpExts[b].Grow(ng);
293       tmpExts[b] &= this->DataSetExt;
294     }
295     guardExts = tmpExts;
296     // cerr << endl;
297     // make sure it's disjoint
298     disjointGuardExts.clear();
299     this->MakeDecompDisjoint(tmpExts, disjointGuardExts);
300   }
301 
302   return 0;
303 }
304 
305 //------------------------------------------------------------------------------
GetPixelBounds(float * rgba,int ni,vtkPixelExtent & ext)306 void vtkSurfaceLICComposite::GetPixelBounds(float* rgba, int ni, vtkPixelExtent& ext)
307 {
308   vtkPixelExtent text;
309   for (int j = ext[2]; j <= ext[3]; ++j)
310   {
311     for (int i = ext[0]; i <= ext[1]; ++i)
312     {
313       if (rgba[4 * (j * ni + i) + 3] > 0.0f)
314       {
315         text[0] = text[0] > i ? i : text[0];
316         text[1] = text[1] < i ? i : text[1];
317         text[2] = text[2] > j ? j : text[2];
318         text[3] = text[3] < j ? j : text[3];
319       }
320     }
321   }
322   ext = text;
323 }
324 
325 //------------------------------------------------------------------------------
InitializeCompositeExtents(float * vectors)326 int vtkSurfaceLICComposite::InitializeCompositeExtents(float* vectors)
327 {
328   // determine screen bounds of all blocks
329   size_t nBlocks = this->BlockExts.size();
330   for (size_t b = 0; b < nBlocks; ++b)
331   {
332     this->DataSetExt |= this->BlockExts[b];
333   }
334 
335   // Make all of the input block extents disjoint so that
336   // LIC is computed once per pixel.
337   this->MakeDecompDisjoint(this->BlockExts, this->CompositeExt, vectors);
338 
339   // add guard cells to the new decomp that prevent artifacts
340   this->AddGuardPixels(this->CompositeExt, this->GuardExt, this->DisjointGuardExt, vectors);
341 
342 #if vtkSurfaceLICCompositeDEBUG >= 1
343   vtkPixelExtentIO::Write(0, "SerViewExtent.vtk", this->WindowExt);
344   vtkPixelExtentIO::Write(0, "SerGeometryDecomp.vtk", this->BlockExts);
345   vtkPixelExtentIO::Write(0, "SerLICDecomp.vtk", this->CompositeExt);
346   vtkPixelExtentIO::Write(0, "SerLICDecompGuard.vtk", this->GuardExt);
347   vtkPixelExtentIO::Write(0, "SerLICDecompDisjointGuard.vtk", this->DisjointGuardExt);
348 #endif
349 
350   return 0;
351 }
352 
353 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)354 void vtkSurfaceLICComposite::PrintSelf(ostream& os, vtkIndent indent)
355 {
356   vtkObject::PrintSelf(os, indent);
357   os << *this << endl;
358 }
359 
360 // ****************************************************************************
operator <<(ostream & os,vtkSurfaceLICComposite & ss)361 ostream& operator<<(ostream& os, vtkSurfaceLICComposite& ss)
362 {
363   os << "winExt=" << ss.WindowExt << endl;
364   os << "blockExts=" << endl;
365   size_t nExts = ss.BlockExts.size();
366   for (size_t i = 0; i < nExts; ++i)
367   {
368     os << "  " << ss.BlockExts[i] << endl;
369   }
370   os << "compositeExts=" << endl;
371   nExts = ss.CompositeExt.size();
372   for (size_t i = 0; i < nExts; ++i)
373   {
374     os << ss.CompositeExt[i] << endl;
375   }
376   os << "guardExts=" << endl;
377   for (size_t i = 0; i < nExts; ++i)
378   {
379     os << ss.GuardExt[i] << endl;
380   }
381   os << "disjointGuardExts=" << endl;
382   for (size_t i = 0; i < nExts; ++i)
383   {
384     os << ss.DisjointGuardExt[i] << endl;
385   }
386   return os;
387 }
388