1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCompositePolyDataMapper2.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 
16 #include "vtkActor.h"
17 #include "vtkCamera.h"
18 #include "vtkCellData.h"
19 #include "vtkDataObjectTreeIterator.h"
20 #include "vtkCompositeDataSet.h"
21 #include "vtkCompositeDataDisplayAttributes.h"
22 #include "vtkCompositePolyDataMapper2.h"
23 #include "vtkCullerCollection.h"
24 #include "vtkHardwareSelector.h"
25 #include "vtkInformation.h"
26 #include "vtkMultiBlockDataSet.h"
27 #include "vtkNew.h"
28 #include "vtkPlaneSource.h"
29 #include "vtkProperty.h"
30 #include "vtkRenderer.h"
31 #include "vtkRenderWindow.h"
32 #include "vtkRenderWindowInteractor.h"
33 #include "vtkSelection.h"
34 #include "vtkSelectionNode.h"
35 #include "vtkSmartPointer.h"
36 #include "vtkUnsignedIntArray.h"
37 
38 #include "vtkTestUtilities.h"
39 #include "vtkRegressionTestImage.h"
40 
41 #include <functional>
42 #include <set>
43 
44 template<typename T, typename U, typename V>
prepareDisplayAttribute(T & expected,U attr,V mbds,std::function<std::pair<bool,bool> (int)> config)45 void prepareDisplayAttribute(
46   T& expected,
47   U attr,
48   V mbds,
49   std::function<std::pair<bool,bool>(int)> config)
50 {
51   expected.clear();
52   auto bit = mbds->NewTreeIterator();
53   for (bit->InitTraversal(); !bit->IsDoneWithTraversal(); bit->GoToNextItem())
54   {
55     int ii = bit->GetCurrentFlatIndex();
56     auto cfg = config(ii);
57     bool visible = cfg.first;
58     bool pickable = cfg.second;
59     auto dataObj = bit->GetCurrentDataObject();
60     if (visible && pickable)
61     {
62       auto pd = vtkPolyData::SafeDownCast(dataObj);
63       if (pd)
64       {
65         auto cid = pd->GetCellData()->GetArray("vtkCompositeIndex");
66         int idx = cid ? cid->GetTuple1(0) : ii;
67         expected.insert(idx);
68       }
69     }
70     attr->SetBlockVisibility(dataObj, visible);
71     attr->SetBlockPickability(dataObj, pickable);
72   }
73   bit->Delete();
74 }
75 
76 template<typename T>
addCompositeIndex(T mbds,int & nextIndex)77 void addCompositeIndex(T mbds, int& nextIndex)
78 {
79   int nblk = static_cast<int>(mbds->GetNumberOfBlocks());
80   for (int i = 0; i < nblk; ++i)
81   {
82     auto blk = mbds->GetBlock(i);
83     if (blk->IsA("vtkCompositeDataSet"))
84     {
85       addCompositeIndex(vtkMultiBlockDataSet::SafeDownCast(blk), nextIndex);
86     }
87     else if (blk->IsA("vtkPolyData"))
88     {
89       auto pdata = vtkPolyData::SafeDownCast(blk);
90       vtkIdType nc = pdata->GetNumberOfCells();
91       auto cid = vtkSmartPointer<vtkUnsignedIntArray>::New();
92       cid->SetName("vtkCompositeIndex");
93       cid->SetNumberOfTuples(nc);
94       cid->FillComponent(0, nextIndex);
95       pdata->GetCellData()->AddArray(cid);
96       ++nextIndex;
97     }
98   }
99 }
100 
101 template<typename T, typename U>
checkSelection(T seln,const U & expected,int & tt)102 int checkSelection(T seln, const U& expected, int& tt)
103 {
104   std::cout << "Test " << tt << "\n";
105   ++tt;
106   int numNodes = seln->GetNumberOfNodes();
107   U actual;
108   for (int nn = 0; nn < numNodes; ++nn)
109   {
110     auto sn = seln->GetNode(nn);
111     auto actor = vtkActor::SafeDownCast(sn->GetProperties()->Get(vtkSelectionNode::PROP()));
112     if (actor)
113     {
114       auto ci = sn->GetProperties()->Get(vtkSelectionNode::COMPOSITE_INDEX());
115       actual.insert(ci);
116     }
117   }
118 
119   std::cout << "  Expected:";
120   for (auto ee : expected)
121   {
122     std::cout << " " << ee;
123   }
124   std::cout << "\n  Actual:";
125   for (auto aa : actual)
126   {
127     std::cout << " " << aa;
128   }
129   std::cout << "\n";
130   int result = (expected == actual ? 1 : 0);
131   if (!result)
132   {
133     vtkGenericWarningMacro("Mismatch between expected selection and actual selection.");
134   }
135   return result;
136 }
137 
TestCompositePolyDataMapper2Pickability(int argc,char * argv[])138 int TestCompositePolyDataMapper2Pickability(int argc, char* argv[])
139 {
140   auto rw = vtkSmartPointer<vtkRenderWindow>::New();
141   auto ri = vtkSmartPointer<vtkRenderWindowInteractor>::New();
142   auto rr = vtkSmartPointer<vtkRenderer>::New();
143   auto mp = vtkSmartPointer<vtkCompositePolyDataMapper2>::New();
144   auto ac = vtkSmartPointer<vtkActor>::New();
145   auto mb = vtkSmartPointer<vtkMultiBlockDataSet>::New();
146   auto da = vtkSmartPointer<vtkCompositeDataDisplayAttributes>::New();
147   rw->AddRenderer(rr);
148   rw->SetInteractor(ri);
149   mp->SetCompositeDataDisplayAttributes(da);
150 
151   vtkNew<vtkPlaneSource> plane;
152   mb->SetNumberOfBlocks(4);
153   for (int ii = 0; ii < static_cast<int>(mb->GetNumberOfBlocks()); ++ii)
154   {
155     double ll[2];
156     ll[0] = -0.5 + 1.0 * (ii % 2);
157     ll[1] = -0.5 + 1.0 * (ii / 2);
158     plane->SetOrigin(ll[0],       ll[1],       ii);
159     plane->SetPoint1(ll[0] + 1.0, ll[1],       ii);
160     plane->SetPoint2(ll[0],       ll[1] + 1.0, ii);
161     plane->Update();
162     vtkNew<vtkPolyData> pblk;
163     pblk->DeepCopy(plane->GetOutputDataObject(0));
164     mb->SetBlock(ii, pblk.GetPointer());
165   }
166 
167   // Note this also tests that the mapper accepts a composite ID array name:
168   int nextId = 7;
169   addCompositeIndex(mb, nextId);
170 
171   mp->SetInputDataObject(0, mb.GetPointer());
172   ac->SetMapper(mp);
173   rr->AddActor(ac);
174   rw->SetSize(400,400);
175   rr->RemoveCuller(rr->GetCullers()->GetLastItem());
176   rr->ResetCamera();
177   rw->Render();  // get the window up
178 
179   double rgb[4][3] = {
180     { .5, .5, .5 },
181     { 0., 1., 1. },
182     { 1., 1., 0. },
183     { 1., 0., 1. }
184   };
185 
186   auto it = mb->NewIterator();
187   int ii = 0;
188   for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem())
189   {
190     auto dataObj = it->GetCurrentDataObject();
191     da->SetBlockColor(dataObj, rgb[ii++]);
192   }
193   it->Delete();
194 
195   mp->SetCompositeIdArrayName("vtkCompositeIndex");
196 
197   vtkNew<vtkHardwareSelector> hw;
198   hw->SetArea(130, 130, 270, 270);
199   hw->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_CELLS);
200   hw->SetRenderer(rr);
201   hw->SetProcessID(0);
202 
203   int testNum = 0;
204   std::set<int> expected;
205 
206 
207   // Nothing visible, but everything pickable.
208   prepareDisplayAttribute(
209     expected, da, mb, [](int) { return std::pair<bool,bool>(false, true); });
210   mp->Modified();
211   auto sel = hw->Select();
212   int retVal = checkSelection(sel, expected, testNum);
213   sel->Delete();
214 
215   // Everything visible, but nothing pickable.
216   prepareDisplayAttribute(
217     expected, da, mb, [](int) { return std::pair<bool,bool>(true, false); });
218   mp->Modified();
219   sel = hw->Select();
220   retVal &= checkSelection(sel, expected, testNum);
221   sel->Delete();
222 
223   // One block in every possible state.
224   prepareDisplayAttribute(
225     expected, da, mb, [](int nn) { --nn; return std::pair<bool,bool>(!!(nn / 2), !!(nn % 2)); });
226   mp->Modified();
227   sel = hw->Select();
228   retVal &= checkSelection(sel, expected, testNum);
229   sel->Delete();
230 
231   // One block in every possible state (but different).
232   prepareDisplayAttribute(
233     expected, da, mb, [](int nn) { --nn; return std::pair<bool,bool>(!(nn / 2), !(nn % 2)); });
234   mp->Modified();
235   sel = hw->Select();
236   retVal &= checkSelection(sel, expected, testNum);
237   sel->Delete();
238 
239   // Everything visible and pickable..
240   prepareDisplayAttribute(
241     expected, da, mb, [](int) { return std::pair<bool,bool>(true, true); });
242   mp->Modified();
243   sel = hw->Select();
244   retVal &= checkSelection(sel, expected, testNum);
245   sel->Delete();
246 
247   int retTestImage = vtkRegressionTestImage(rw);
248   retVal &= retTestImage;
249   if (retTestImage == vtkRegressionTester::DO_INTERACTOR)
250   {
251     ri->Start();
252   }
253 
254   return !retVal;
255 }
256