1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of the copyright holders may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 // Authors:
41 //  * Ozan Tonkal, ozantonkal@gmail.com
42 //  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
43 //
44 //M*/
45 
46 #include "precomp.hpp"
47 
48 ///////////////////////////////////////////////////////////////////////////////////////////////
49 /// Point Cloud Widget implementation
50 
WCloud(InputArray cloud,InputArray colors)51 cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors)
52 {
53     WCloud cloud_widget(cloud, colors, cv::noArray());
54     *this = cloud_widget;
55 }
56 
WCloud(InputArray cloud,const Color & color)57 cv::viz::WCloud::WCloud(InputArray cloud, const Color &color)
58 {
59     WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color));
60     *this = cloud_widget;
61 }
62 
WCloud(InputArray cloud,const Color & color,InputArray normals)63 cv::viz::WCloud::WCloud(InputArray cloud, const Color &color, InputArray normals)
64 {
65     WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color), normals);
66     *this = cloud_widget;
67 }
68 
WCloud(cv::InputArray cloud,cv::InputArray colors,cv::InputArray normals)69 cv::viz::WCloud::WCloud(cv::InputArray cloud, cv::InputArray colors, cv::InputArray normals)
70 {
71     CV_Assert(!cloud.empty() && !colors.empty());
72 
73     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
74     cloud_source->SetColorCloudNormals(cloud, colors, normals);
75     cloud_source->Update();
76 
77     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
78     VtkUtils::SetInputData(mapper, cloud_source->GetOutput());
79     mapper->SetScalarModeToUsePointData();
80     mapper->ImmediateModeRenderingOff();
81     mapper->SetScalarRange(0, 255);
82     mapper->ScalarVisibilityOn();
83 
84     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
85     actor->GetProperty()->SetInterpolationToFlat();
86     actor->GetProperty()->BackfaceCullingOn();
87     actor->SetMapper(mapper);
88 
89     WidgetAccessor::setProp(*this, actor);
90 
91 }
92 
93 
cast()94 template<> cv::viz::WCloud cv::viz::Widget::cast<cv::viz::WCloud>()
95 {
96     Widget3D widget = this->cast<Widget3D>();
97     return static_cast<WCloud&>(widget);
98 }
99 
100 ///////////////////////////////////////////////////////////////////////////////////////////////
101 /// Painted Cloud Widget implementation
102 
WPaintedCloud(InputArray cloud)103 cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud)
104 {
105     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
106     cloud_source->SetCloud(cloud);
107     cloud_source->Update();
108 
109     Vec6d bounds(cloud_source->GetOutput()->GetPoints()->GetBounds());
110 
111     vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
112     elevation->SetInputConnection(cloud_source->GetOutputPort());
113     elevation->SetLowPoint(bounds[0], bounds[2], bounds[4]);
114     elevation->SetHighPoint(bounds[1], bounds[3], bounds[5]);
115     elevation->SetScalarRange(0.0, 1.0);
116     elevation->Update();
117 
118     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
119     VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
120     mapper->ImmediateModeRenderingOff();
121     mapper->ScalarVisibilityOn();
122     mapper->SetColorModeToMapScalars();
123 
124     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
125     actor->GetProperty()->SetInterpolationToFlat();
126     actor->GetProperty()->BackfaceCullingOn();
127     actor->SetMapper(mapper);
128 
129     WidgetAccessor::setProp(*this, actor);
130 }
131 
WPaintedCloud(InputArray cloud,const Point3d & p1,const Point3d & p2)132 cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2)
133 {
134     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
135     cloud_source->SetCloud(cloud);
136 
137     vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
138     elevation->SetInputConnection(cloud_source->GetOutputPort());
139     elevation->SetLowPoint(p1.x, p1.y, p1.z);
140     elevation->SetHighPoint(p2.x, p2.y, p2.z);
141     elevation->SetScalarRange(0.0, 1.0);
142     elevation->Update();
143 
144     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
145     VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
146     mapper->ImmediateModeRenderingOff();
147     mapper->ScalarVisibilityOn();
148     mapper->SetColorModeToMapScalars();
149 
150     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
151     actor->GetProperty()->SetInterpolationToFlat();
152     actor->GetProperty()->BackfaceCullingOn();
153     actor->SetMapper(mapper);
154 
155     WidgetAccessor::setProp(*this, actor);
156 }
157 
WPaintedCloud(InputArray cloud,const Point3d & p1,const Point3d & p2,const Color & c1,const Color c2)158 cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2)
159 {
160     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
161     cloud_source->SetCloud(cloud);
162 
163     vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
164     elevation->SetInputConnection(cloud_source->GetOutputPort());
165     elevation->SetLowPoint(p1.x, p1.y, p1.z);
166     elevation->SetHighPoint(p2.x, p2.y, p2.z);
167     elevation->SetScalarRange(0.0, 1.0);
168     elevation->Update();
169 
170     Color vc1 = vtkcolor(c1), vc2 = vtkcolor(c2);
171     vtkSmartPointer<vtkColorTransferFunction> color_transfer = vtkSmartPointer<vtkColorTransferFunction>::New();
172     color_transfer->SetColorSpaceToRGB();
173     color_transfer->AddRGBPoint(0.0, vc1[0], vc1[1], vc1[2]);
174     color_transfer->AddRGBPoint(1.0, vc2[0], vc2[1], vc2[2]);
175     color_transfer->SetScaleToLinear();
176     color_transfer->Build();
177 
178     //if in future some need to replace color table with real scalars, then this can be done usine next calls:
179     //vtkDataArray *float_scalars = vtkPolyData::SafeDownCast(elevation->GetOutput())->GetPointData()->GetArray("Elevation");
180     //vtkSmartPointer<vtkPolyData> polydata = cloud_source->GetOutput();
181     //polydata->GetPointData()->SetScalars(color_transfer->MapScalars(float_scalars, VTK_COLOR_MODE_DEFAULT, 0));
182 
183     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
184     VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
185     mapper->ImmediateModeRenderingOff();
186     mapper->ScalarVisibilityOn();
187     mapper->SetColorModeToMapScalars();
188     mapper->SetLookupTable(color_transfer);
189 
190     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
191     actor->GetProperty()->SetInterpolationToFlat();
192     actor->GetProperty()->BackfaceCullingOn();
193     actor->SetMapper(mapper);
194 
195     WidgetAccessor::setProp(*this, actor);
196 }
197 
cast()198 template<> cv::viz::WPaintedCloud cv::viz::Widget::cast<cv::viz::WPaintedCloud>()
199 {
200     Widget3D widget = this->cast<Widget3D>();
201     return static_cast<WPaintedCloud&>(widget);
202 }
203 
204 ///////////////////////////////////////////////////////////////////////////////////////////////
205 /// Cloud Collection Widget implementation
206 
WCloudCollection()207 cv::viz::WCloudCollection::WCloudCollection()
208 {
209     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
210 
211     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
212     mapper->SetInputConnection(append_filter->GetOutputPort());
213     mapper->SetScalarModeToUsePointData();
214     mapper->ImmediateModeRenderingOff();
215     mapper->SetScalarRange(0, 255);
216     mapper->ScalarVisibilityOn();
217 
218     vtkSmartPointer<vtkLODActor> actor = vtkSmartPointer<vtkLODActor>::New();
219     actor->SetNumberOfCloudPoints(1);
220     actor->GetProperty()->SetInterpolationToFlat();
221     actor->GetProperty()->BackfaceCullingOn();
222     actor->SetMapper(mapper);
223 
224     WidgetAccessor::setProp(*this, actor);
225 }
226 
addCloud(InputArray cloud,InputArray colors,const Affine3d & pose)227 void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose)
228 {
229     vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
230     source->SetColorCloud(cloud, colors);
231 
232     vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(source->GetOutputPort(), pose);
233 
234     vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
235     CV_Assert("Correctness check." && actor);
236 
237     vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
238     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
239     VtkUtils::AddInputData(append_filter, polydata);
240 
241     actor->SetNumberOfCloudPoints(std::max<vtkIdType>(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10));
242 }
243 
addCloud(InputArray cloud,const Color & color,const Affine3d & pose)244 void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose)
245 {
246     addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose);
247 }
248 
finalize()249 void cv::viz::WCloudCollection::finalize()
250 {
251     vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
252     CV_Assert("Incompatible widget type." && actor);
253 
254     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
255     CV_Assert("Need to add at least one cloud." && mapper);
256 
257     vtkSmartPointer<vtkAlgorithm> producer = mapper->GetInputConnection(0, 0)->GetProducer();
258     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
259     append_filter->Update();
260 
261     vtkSmartPointer<vtkPolyData> polydata = append_filter->GetOutput();
262     mapper->RemoveInputConnection(0, 0);
263     VtkUtils::SetInputData(mapper, polydata);
264 }
265 
cast()266 template<> cv::viz::WCloudCollection cv::viz::Widget::cast<cv::viz::WCloudCollection>()
267 {
268     Widget3D widget = this->cast<Widget3D>();
269     return static_cast<WCloudCollection&>(widget);
270 }
271 
272 ///////////////////////////////////////////////////////////////////////////////////////////////
273 /// Cloud Normals Widget implementation
274 
WCloudNormals(InputArray _cloud,InputArray _normals,int level,double scale,const Color & color)275 cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, double scale, const Color &color)
276 {
277     Mat cloud = _cloud.getMat();
278     Mat normals = _normals.getMat();
279 
280     CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4);
281     CV_Assert(cloud.size() == normals.size() && cloud.type() == normals.type());
282 
283     int sqlevel = (int)std::sqrt((double)level);
284     int ystep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : 1;
285     int xstep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : level;
286 
287     vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
288     points->SetDataType(cloud.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE);
289 
290     vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
291 
292     int s_chs = cloud.channels();
293     int n_chs = normals.channels();
294     int total = 0;
295 
296     for(int y = 0; y < cloud.rows; y += ystep)
297     {
298         if (cloud.depth() == CV_32F)
299         {
300             const float *srow = cloud.ptr<float>(y);
301             const float *send = srow + cloud.cols * s_chs;
302             const float *nrow = normals.ptr<float>(y);
303 
304             for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs)
305                 if (!isNan(srow) && !isNan(nrow))
306                 {
307                     Vec3f endp = Vec3f(srow) + Vec3f(nrow) * (float)scale;
308 
309                     points->InsertNextPoint(srow);
310                     points->InsertNextPoint(endp.val);
311 
312                     lines->InsertNextCell(2);
313                     lines->InsertCellPoint(total++);
314                     lines->InsertCellPoint(total++);
315                 }
316         }
317         else
318         {
319             const double *srow = cloud.ptr<double>(y);
320             const double *send = srow + cloud.cols * s_chs;
321             const double *nrow = normals.ptr<double>(y);
322 
323             for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs)
324                 if (!isNan(srow) && !isNan(nrow))
325                 {
326                     Vec3d endp = Vec3d(srow) + Vec3d(nrow) * (double)scale;
327 
328                     points->InsertNextPoint(srow);
329                     points->InsertNextPoint(endp.val);
330 
331                     lines->InsertNextCell(2);
332                     lines->InsertCellPoint(total++);
333                     lines->InsertCellPoint(total++);
334                 }
335         }
336     }
337 
338     vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
339     polydata->SetPoints(points);
340     polydata->SetLines(lines);
341     VtkUtils::FillScalars(polydata, color);
342 
343     vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
344     VtkUtils::SetInputData(mapper, polydata);
345 
346     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
347     actor->SetMapper(mapper);
348 
349     WidgetAccessor::setProp(*this, actor);
350 }
351 
cast()352 template<> cv::viz::WCloudNormals cv::viz::Widget::cast<cv::viz::WCloudNormals>()
353 {
354     Widget3D widget = this->cast<Widget3D>();
355     return static_cast<WCloudNormals&>(widget);
356 }
357 
358 ///////////////////////////////////////////////////////////////////////////////////////////////
359 /// Mesh Widget implementation
360 
WMesh(const Mesh & mesh)361 cv::viz::WMesh::WMesh(const Mesh &mesh)
362 {
363     CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1);
364 
365     vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
366     source->SetColorCloudNormalsTCoords(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords);
367     source->Update();
368 
369     Mat lookup_buffer(1, (int)mesh.cloud.total(), CV_32SC1);
370     int *lookup = lookup_buffer.ptr<int>();
371     for(int y = 0, index = 0; y < mesh.cloud.rows; ++y)
372     {
373         int s_chs = mesh.cloud.channels();
374 
375         if (mesh.cloud.depth() == CV_32F)
376         {
377             const float* srow = mesh.cloud.ptr<float>(y);
378             const float* send = srow + mesh.cloud.cols * s_chs;
379 
380             for (; srow != send; srow += s_chs, ++lookup)
381                 if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2]))
382                     *lookup = index++;
383         }
384 
385         if (mesh.cloud.depth() == CV_64F)
386         {
387             const double* srow = mesh.cloud.ptr<double>(y);
388             const double* send = srow + mesh.cloud.cols * s_chs;
389 
390             for (; srow != send; srow += s_chs, ++lookup)
391                 if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2]))
392                     *lookup = index++;
393         }
394     }
395     lookup = lookup_buffer.ptr<int>();
396 
397     vtkSmartPointer<vtkPolyData> polydata = source->GetOutput();
398     polydata->SetVerts(0);
399 
400     const int * polygons = mesh.polygons.ptr<int>();
401     vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
402 
403     int idx = 0;
404     size_t polygons_size = mesh.polygons.total();
405     for (size_t i = 0; i < polygons_size; ++idx)
406     {
407         int n_points = polygons[i++];
408 
409         cell_array->InsertNextCell(n_points);
410         for (int j = 0; j < n_points; ++j, ++idx)
411             cell_array->InsertCellPoint(lookup[polygons[i++]]);
412     }
413     cell_array->GetData()->SetNumberOfValues(idx);
414     cell_array->Squeeze();
415     polydata->SetStrips(cell_array);
416 
417     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
418     mapper->SetScalarModeToUsePointData();
419     mapper->ImmediateModeRenderingOff();
420     VtkUtils::SetInputData(mapper, polydata);
421 
422     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
423     //actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10));
424     actor->GetProperty()->SetRepresentationToSurface();
425     actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency
426     actor->GetProperty()->SetInterpolationToFlat();
427     actor->GetProperty()->EdgeVisibilityOff();
428     actor->GetProperty()->ShadingOff();
429     actor->SetMapper(mapper);
430 
431     if (!mesh.texture.empty())
432     {
433         vtkSmartPointer<vtkImageMatSource> image_source = vtkSmartPointer<vtkImageMatSource>::New();
434         image_source->SetImage(mesh.texture);
435 
436         vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
437         texture->SetInputConnection(image_source->GetOutputPort());
438         actor->SetTexture(texture);
439     }
440 
441     WidgetAccessor::setProp(*this, actor);
442 }
443 
WMesh(InputArray cloud,InputArray polygons,InputArray colors,InputArray normals)444 cv::viz::WMesh::WMesh(InputArray cloud, InputArray polygons, InputArray colors, InputArray normals)
445 {
446     Mesh mesh;
447     mesh.cloud = cloud.getMat();
448     mesh.colors = colors.getMat();
449     mesh.normals = normals.getMat();
450     mesh.polygons = polygons.getMat();
451     *this = WMesh(mesh);
452 }
453 
cast()454 template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast<cv::viz::WMesh>()
455 {
456     Widget3D widget = this->cast<Widget3D>();
457     return static_cast<WMesh&>(widget);
458 }
459 
460 
461 ///////////////////////////////////////////////////////////////////////////////////////////////
462 /// Widget Merger implementation
463 
WWidgetMerger()464 cv::viz::WWidgetMerger::WWidgetMerger()
465 {
466     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
467 
468     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
469     mapper->SetInputConnection(append_filter->GetOutputPort());
470     mapper->SetScalarModeToUsePointData();
471     mapper->ImmediateModeRenderingOff();
472     mapper->SetScalarRange(0, 255);
473     mapper->ScalarVisibilityOn();
474 
475     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
476     actor->GetProperty()->SetInterpolationToFlat();
477     actor->GetProperty()->BackfaceCullingOn();
478     actor->SetMapper(mapper);
479 
480     WidgetAccessor::setProp(*this, actor);
481 }
482 
addWidget(const Widget3D & widget,const Affine3d & pose)483 void cv::viz::WWidgetMerger::addWidget(const Widget3D& widget, const Affine3d &pose)
484 {
485     vtkActor *widget_actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(widget));
486     CV_Assert("Widget is not 3D actor." && widget_actor);
487 
488     vtkSmartPointer<vtkPolyDataMapper> widget_mapper = vtkPolyDataMapper::SafeDownCast(widget_actor->GetMapper());
489     CV_Assert("Widget doesn't have a polydata mapper" && widget_mapper);
490     widget_mapper->Update();
491 
492     vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
493     vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
494     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
495     CV_Assert("Correctness check" && append_filter);
496 
497     VtkUtils::AddInputData(append_filter, VtkUtils::TransformPolydata(widget_mapper->GetInput(), pose));
498 }
499 
finalize()500 void cv::viz::WWidgetMerger::finalize()
501 {
502     vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
503     vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
504     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
505     CV_Assert("Correctness check" && append_filter);
506     append_filter->Update();
507 
508     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
509     mapper->RemoveInputConnection(0, 0);
510     VtkUtils::SetInputData(mapper, append_filter->GetOutput());
511     mapper->Modified();
512 }
513 
cast()514 template<> CV_EXPORTS cv::viz::WWidgetMerger cv::viz::Widget::cast<cv::viz::WWidgetMerger>()
515 {
516     Widget3D widget = this->cast<Widget3D>();
517     return static_cast<WWidgetMerger&>(widget);
518 }
519