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