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 /// line widget implementation
WLine(const Point3d & pt1,const Point3d & pt2,const Color & color)50 cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color)
51 {
52     vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
53     line->SetPoint1(pt1.x, pt1.y, pt1.z);
54     line->SetPoint2(pt2.x, pt2.y, pt2.z);
55     line->Update();
56 
57     vtkSmartPointer<vtkPolyData> polydata = line->GetOutput();
58     VtkUtils::FillScalars(polydata, color);
59 
60     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
61     VtkUtils::SetInputData(mapper, polydata);
62 
63     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
64     actor->SetMapper(mapper);
65 
66     WidgetAccessor::setProp(*this, actor);
67 }
68 
cast()69 template<> cv::viz::WLine cv::viz::Widget::cast<cv::viz::WLine>()
70 {
71     Widget3D widget = this->cast<Widget3D>();
72     return static_cast<WLine&>(widget);
73 }
74 
75 ///////////////////////////////////////////////////////////////////////////////////////////////
76 /// sphere widget implementation
77 
WSphere(const Point3d & center,double radius,int sphere_resolution,const Color & color)78 cv::viz::WSphere::WSphere(const Point3d &center, double radius, int sphere_resolution, const Color &color)
79 {
80     vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
81     sphere->SetRadius(radius);
82     sphere->SetCenter(center.x, center.y, center.z);
83     sphere->SetPhiResolution(sphere_resolution);
84     sphere->SetThetaResolution(sphere_resolution);
85     sphere->LatLongTessellationOff();
86     sphere->Update();
87 
88     vtkSmartPointer<vtkPolyData> polydata = sphere->GetOutput();
89     VtkUtils::FillScalars(polydata, color);
90 
91     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
92     VtkUtils::SetInputData(mapper, polydata);
93 
94     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
95     actor->SetMapper(mapper);
96 
97     WidgetAccessor::setProp(*this, actor);
98 }
99 
cast()100 template<> cv::viz::WSphere cv::viz::Widget::cast<cv::viz::WSphere>()
101 {
102     Widget3D widget = this->cast<Widget3D>();
103     return static_cast<WSphere&>(widget);
104 }
105 
106 ///////////////////////////////////////////////////////////////////////////////////////////////
107 /// plane widget implementation
108 
WPlane(const Size2d & size,const Color & color)109 cv::viz::WPlane::WPlane(const Size2d& size, const Color &color)
110 {
111     vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
112     plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0);
113     plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0);
114     plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
115     plane->Update();
116 
117     vtkSmartPointer<vtkPolyData> polydata = plane->GetOutput();
118     VtkUtils::FillScalars(polydata, color);
119 
120     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
121     VtkUtils::SetInputData(mapper, polydata);
122 
123     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
124     actor->SetMapper(mapper);
125     actor->GetProperty()->LightingOff();
126 
127     WidgetAccessor::setProp(*this, actor);
128 }
129 
WPlane(const Point3d & center,const Vec3d & normal,const Vec3d & new_yaxis,const Size2d & size,const Color & color)130 cv::viz::WPlane::WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Size2d& size, const Color &color)
131 {
132     Vec3d zvec = normalize(normal);
133     Vec3d xvec = normalize(new_yaxis.cross(zvec));
134     Vec3d yvec = zvec.cross(xvec);
135 
136     WPlane plane(size, color);
137     plane.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
138     *this = plane;
139 }
140 
cast()141 template<> cv::viz::WPlane cv::viz::Widget::cast<cv::viz::WPlane>()
142 {
143     Widget3D widget = this->cast<Widget3D>();
144     return static_cast<WPlane&>(widget);
145 }
146 
147 ///////////////////////////////////////////////////////////////////////////////////////////////
148 /// arrow widget implementation
149 
WArrow(const Point3d & pt1,const Point3d & pt2,double thickness,const Color & color)150 cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness, const Color &color)
151 {
152     vtkSmartPointer<vtkArrowSource> arrow_source = vtkSmartPointer<vtkArrowSource>::New();
153     arrow_source->SetShaftRadius(thickness);
154     arrow_source->SetTipRadius(thickness * 3.0);
155     arrow_source->SetTipLength(thickness * 10.0);
156 
157     Vec3d arbitrary = get_random_vec();
158     Vec3d start_point(pt1.x, pt1.y, pt1.z), end_point(pt2.x, pt2.y, pt2.z);
159 
160     double length = norm(end_point - start_point);
161 
162     Vec3d xvec = normalized(end_point - start_point);
163     Vec3d zvec = normalized(xvec.cross(arbitrary));
164     Vec3d yvec = zvec.cross(xvec);
165 
166     Matx33d R = makeTransformToGlobal(xvec, yvec, zvec).rotation();
167     Affine3d transform_with_scale(R * length, start_point);
168 
169     vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale);
170     VtkUtils::FillScalars(polydata, color);
171 
172     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
173     VtkUtils::SetInputData(mapper, polydata);
174 
175     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
176     actor->SetMapper(mapper);
177 
178     WidgetAccessor::setProp(*this, actor);
179 }
180 
cast()181 template<> cv::viz::WArrow cv::viz::Widget::cast<cv::viz::WArrow>()
182 {
183     Widget3D widget = this->cast<Widget3D>();
184     return static_cast<WArrow&>(widget);
185 }
186 
187 ///////////////////////////////////////////////////////////////////////////////////////////////
188 /// circle widget implementation
189 
WCircle(double radius,double thickness,const Color & color)190 cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color)
191 {
192     vtkSmartPointer<vtkDiskSource> disk = vtkSmartPointer<vtkDiskSource>::New();
193     disk->SetCircumferentialResolution(30);
194     disk->SetInnerRadius(radius - thickness);
195     disk->SetOuterRadius(radius + thickness);
196     disk->Update();
197 
198     vtkSmartPointer<vtkPolyData> polydata = disk->GetOutput();
199     VtkUtils::FillScalars(polydata, color);
200 
201     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
202     VtkUtils::SetInputData(mapper, polydata);
203 
204     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
205     actor->GetProperty()->LightingOff();
206     actor->SetMapper(mapper);
207 
208     WidgetAccessor::setProp(*this, actor);
209 }
210 
WCircle(double radius,const Point3d & center,const Vec3d & normal,double thickness,const Color & color)211 cv::viz::WCircle::WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness, const Color &color)
212 {
213     Vec3d arbitrary = get_random_vec();
214     Vec3d zvec = normalized(normal);
215     Vec3d xvec = normalized(zvec.cross(arbitrary));
216     Vec3d yvec = zvec.cross(xvec);
217 
218     WCircle circle(radius, thickness, color);
219     circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
220     *this = circle;
221 }
222 
cast()223 template<> cv::viz::WCircle cv::viz::Widget::cast<cv::viz::WCircle>()
224 {
225     Widget3D widget = this->cast<Widget3D>();
226     return static_cast<WCircle&>(widget);
227 }
228 
229 ///////////////////////////////////////////////////////////////////////////////////////////////
230 /// WCone widget implementation
231 
WCone(double length,double radius,int resolution,const Color & color)232 cv::viz::WCone::WCone(double length, double radius, int resolution, const Color &color)
233 {
234     vtkSmartPointer<vtkConeSource> cone_source = vtkSmartPointer<vtkConeSource>::New();
235     cone_source->SetCenter(length*0.5, 0.0, 0.0);
236     cone_source->SetHeight(length);
237     cone_source->SetRadius(radius);
238     cone_source->SetResolution(resolution);
239     cone_source->Update();
240 
241     vtkSmartPointer<vtkPolyData> polydata = cone_source->GetOutput();
242     VtkUtils::FillScalars(polydata, color);
243 
244     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
245     VtkUtils::SetInputData(mapper, polydata);
246 
247     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
248     actor->SetMapper(mapper);
249 
250     WidgetAccessor::setProp(*this, actor);
251 }
252 
WCone(double radius,const Point3d & center,const Point3d & tip,int resolution,const Color & color)253 cv::viz::WCone::WCone(double radius, const Point3d& center, const Point3d& tip, int resolution, const Color &color)
254 {
255     Vec3d arbitrary = get_random_vec();
256     Vec3d xvec = normalized(Vec3d(tip - center));
257     Vec3d zvec = normalized(xvec.cross(arbitrary));
258     Vec3d yvec = zvec.cross(xvec);
259 
260     WCone circle(norm(tip - center), radius, resolution, color);
261     circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
262     *this = circle;
263 }
264 
cast()265 template<> cv::viz::WCone cv::viz::Widget::cast<cv::viz::WCone>()
266 {
267     Widget3D widget = this->cast<Widget3D>();
268     return static_cast<WCone&>(widget);
269 }
270 
271 ///////////////////////////////////////////////////////////////////////////////////////////////
272 /// cylinder widget implementation
273 
WCylinder(const Point3d & axis_point1,const Point3d & axis_point2,double radius,int numsides,const Color & color)274 cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides, const Color &color)
275 {
276     vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
277     line->SetPoint1(axis_point1.x, axis_point1.y, axis_point1.z);
278     line->SetPoint2(axis_point2.x, axis_point2.y, axis_point2.z);
279 
280     vtkSmartPointer<vtkTubeFilter> tuber = vtkSmartPointer<vtkTubeFilter>::New();
281     tuber->SetInputConnection(line->GetOutputPort());
282     tuber->SetNumberOfSides(numsides);
283     tuber->SetRadius(radius);
284     tuber->Update();
285 
286     vtkSmartPointer<vtkPolyData> polydata = tuber->GetOutput();
287     VtkUtils::FillScalars(polydata, color);
288 
289     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
290     VtkUtils::SetInputData(mapper, polydata);
291 
292     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
293     actor->SetMapper(mapper);
294 
295     WidgetAccessor::setProp(*this, actor);
296 }
297 
cast()298 template<> cv::viz::WCylinder cv::viz::Widget::cast<cv::viz::WCylinder>()
299 {
300     Widget3D widget = this->cast<Widget3D>();
301     return static_cast<WCylinder&>(widget);
302 }
303 
304 ///////////////////////////////////////////////////////////////////////////////////////////////
305 /// cylinder widget implementation
306 
WCube(const Point3d & min_point,const Point3d & max_point,bool wire_frame,const Color & color)307 cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool wire_frame, const Color &color)
308 {
309     double bounds[6];
310     bounds[0] = std::min(min_point.x, max_point.x);
311     bounds[1] = std::max(min_point.x, max_point.x);
312     bounds[2] = std::min(min_point.y, max_point.y);
313     bounds[3] = std::max(min_point.y, max_point.y);
314     bounds[4] = std::min(min_point.z, max_point.z);
315     bounds[5] = std::max(min_point.z, max_point.z);
316 
317     vtkSmartPointer<vtkPolyDataAlgorithm> cube;
318     if (wire_frame)
319     {
320         cube = vtkSmartPointer<vtkOutlineSource>::New();
321         vtkOutlineSource::SafeDownCast(cube)->SetBounds(bounds);
322     }
323     else
324     {
325         cube = vtkSmartPointer<vtkCubeSource>::New();
326         vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds);
327     }
328     cube->Update();
329     vtkSmartPointer<vtkPolyData> polydata =cube->GetOutput();
330     VtkUtils::FillScalars(polydata, color);
331 
332     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
333     VtkUtils::SetInputData(mapper, polydata);
334 
335     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
336     actor->SetMapper(mapper);
337 
338     WidgetAccessor::setProp(*this, actor);
339 }
340 
cast()341 template<> cv::viz::WCube cv::viz::Widget::cast<cv::viz::WCube>()
342 {
343     Widget3D widget = this->cast<Widget3D>();
344     return static_cast<WCube&>(widget);
345 }
346 
347 ///////////////////////////////////////////////////////////////////////////////////////////////
348 /// coordinate system widget implementation
349 
WCoordinateSystem(double scale)350 cv::viz::WCoordinateSystem::WCoordinateSystem(double scale)
351 {
352     vtkSmartPointer<vtkAxes> axes = vtkSmartPointer<vtkAxes>::New();
353     axes->SetOrigin(0, 0, 0);
354     axes->SetScaleFactor(scale);
355     axes->Update();
356 
357     vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
358     colors->SetNumberOfComponents(3);
359     colors->InsertNextTuple3(255, 0, 0);
360     colors->InsertNextTuple3(255, 0, 0);
361     colors->InsertNextTuple3(0, 255, 0);
362     colors->InsertNextTuple3(0, 255, 0);
363     colors->InsertNextTuple3(0, 0, 255);
364     colors->InsertNextTuple3(0, 0, 255);
365 
366     vtkSmartPointer<vtkPolyData> polydata = axes->GetOutput();
367     polydata->GetPointData()->SetScalars(colors);
368 
369     vtkSmartPointer<vtkTubeFilter> tube_filter = vtkSmartPointer<vtkTubeFilter>::New();
370     VtkUtils::SetInputData(tube_filter, polydata);
371     tube_filter->SetRadius(axes->GetScaleFactor() / 50.0);
372     tube_filter->SetNumberOfSides(6);
373     tube_filter->Update();
374 
375     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
376     mapper->SetScalarModeToUsePointData();
377     VtkUtils::SetInputData(mapper, tube_filter->GetOutput());
378 
379     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
380     actor->SetMapper(mapper);
381 
382     WidgetAccessor::setProp(*this, actor);
383 }
384 
cast()385 template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast<cv::viz::WCoordinateSystem>()
386 {
387     Widget3D widget = this->cast<Widget3D>();
388     return static_cast<WCoordinateSystem&>(widget);
389 }
390 
391 ///////////////////////////////////////////////////////////////////////////////////////////////
392 /// polyline widget implementation
393 
WPolyLine(InputArray points,InputArray colors)394 cv::viz::WPolyLine::WPolyLine(InputArray points, InputArray colors)
395 {
396     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
397     cloud_source->SetColorCloud(points, colors);
398     cloud_source->Update();
399 
400     vtkSmartPointer<vtkPolyData> polydata = cloud_source->GetOutput();
401 
402     vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
403     cell_array->Allocate(cell_array->EstimateSize(1, polydata->GetNumberOfPoints()));
404     cell_array->InsertNextCell(polydata->GetNumberOfPoints());
405     for(vtkIdType i = 0; i < polydata->GetNumberOfPoints(); ++i)
406         cell_array->InsertCellPoint(i);
407 
408     polydata->SetLines(cell_array);
409     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
410     VtkUtils::SetInputData(mapper, polydata);
411     mapper->SetScalarRange(0, 255);
412 
413     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
414     actor->SetMapper(mapper);
415 
416     WidgetAccessor::setProp(*this, actor);
417 }
418 
WPolyLine(InputArray points,const Color & color)419 cv::viz::WPolyLine::WPolyLine(InputArray points, const Color &color)
420 {
421     WPolyLine polyline(points, Mat(points.size(), CV_8UC3, color));
422     *this = polyline;
423 }
424 
cast()425 template<> cv::viz::WPolyLine cv::viz::Widget::cast<cv::viz::WPolyLine>()
426 {
427     Widget3D widget = this->cast<Widget3D>();
428     return static_cast<WPolyLine&>(widget);
429 }
430 
431 ///////////////////////////////////////////////////////////////////////////////////////////////
432 /// grid widget implementation
433 
434 
WGrid(const Vec2i & cells,const Vec2d & cells_spacing,const Color & color)435 cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
436 {
437     vtkSmartPointer<vtkImageData> grid_data = vtkSmartPointer<vtkImageData>::New();
438 
439     // Add 1 to dimensions because in ImageData dimensions is the number of lines
440     // - however here it means number of cells
441     grid_data->SetDimensions(cells[0]+1, cells[1]+1, 1);
442     grid_data->SetSpacing(cells_spacing[0], cells_spacing[1], 0.);
443 
444     // Set origin of the grid to be the middle of the grid
445     grid_data->SetOrigin(cells[0] * cells_spacing[0] * (-0.5), cells[1] * cells_spacing[1] * (-0.5), 0);
446 
447     // Extract the edges so we have the grid
448     vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
449     VtkUtils::SetInputData(extract_edges, grid_data);
450     extract_edges->Update();
451 
452     vtkSmartPointer<vtkPolyData> polydata = extract_edges->GetOutput();
453     VtkUtils::FillScalars(polydata, color);
454 
455     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
456     VtkUtils::SetInputData(mapper, polydata);
457 
458     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
459     actor->SetMapper(mapper);
460 
461     WidgetAccessor::setProp(*this, actor);
462 }
463 
WGrid(const Point3d & center,const Vec3d & normal,const Vec3d & new_yaxis,const Vec2i & cells,const Vec2d & cells_spacing,const Color & color)464 cv::viz::WGrid::WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
465 {
466     Vec3d zvec = normalize(normal);
467     Vec3d xvec = normalize(new_yaxis.cross(zvec));
468     Vec3d yvec = zvec.cross(xvec);
469 
470     WGrid grid(cells, cells_spacing, color);
471     grid.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
472     *this = grid;
473 }
474 
cast()475 template<> cv::viz::WGrid cv::viz::Widget::cast<cv::viz::WGrid>()
476 {
477     Widget3D widget = this->cast<Widget3D>();
478     return static_cast<WGrid&>(widget);
479 }
480 
481 ///////////////////////////////////////////////////////////////////////////////////////////////
482 /// text3D widget implementation
483 
WText3D(const String & text,const Point3d & position,double text_scale,bool face_camera,const Color & color)484 cv::viz::WText3D::WText3D(const String &text, const Point3d &position, double text_scale, bool face_camera, const Color &color)
485 {
486     vtkSmartPointer<vtkVectorText> textSource = vtkSmartPointer<vtkVectorText>::New();
487     textSource->SetText(text.c_str());
488     textSource->Update();
489 
490     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
491     mapper->SetInputConnection(textSource->GetOutputPort());
492 
493     if (face_camera)
494     {
495         vtkSmartPointer<vtkFollower> actor = vtkSmartPointer<vtkFollower>::New();
496         actor->SetMapper(mapper);
497         actor->SetPosition(position.x, position.y, position.z);
498         actor->SetScale(text_scale);
499         WidgetAccessor::setProp(*this, actor);
500     }
501     else
502     {
503         vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
504         actor->SetMapper(mapper);
505         actor->SetPosition(position.x, position.y, position.z);
506         actor->SetScale(text_scale);
507         actor->GetProperty()->LightingOff();
508         WidgetAccessor::setProp(*this, actor);
509     }
510 
511     setColor(color);
512 }
513 
setText(const String & text)514 void cv::viz::WText3D::setText(const String &text)
515 {
516     vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
517     CV_Assert("This widget does not support text." && actor);
518 
519     // Update text source
520     vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
521     vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
522     CV_Assert("This widget does not support text." && textSource);
523 
524     textSource->SetText(text.c_str());
525     textSource->Modified();
526     textSource->Update();
527 }
528 
getText() const529 cv::String cv::viz::WText3D::getText() const
530 {
531     vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this));
532     CV_Assert("This widget does not support text." && actor);
533 
534     vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
535     vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
536     CV_Assert("This widget does not support text." && textSource);
537 
538     return textSource->GetText();
539 }
540 
cast()541 template<> cv::viz::WText3D cv::viz::Widget::cast<cv::viz::WText3D>()
542 {
543     Widget3D widget = this->cast<Widget3D>();
544     return static_cast<WText3D&>(widget);
545 }
546 
547 ///////////////////////////////////////////////////////////////////////////////////////////////
548 /// text widget implementation
549 
WText(const String & text,const Point & pos,int font_size,const Color & color)550 cv::viz::WText::WText(const String &text, const Point &pos, int font_size, const Color &color)
551 {
552     vtkSmartPointer<vtkTextActor> actor = vtkSmartPointer<vtkTextActor>::New();
553     actor->SetDisplayPosition(pos.x, pos.y);
554     actor->SetInput(text.c_str());
555 
556     actor->GetProperty()->SetDisplayLocationToForeground();
557 
558     vtkSmartPointer<vtkTextProperty> tprop = actor->GetTextProperty();
559     tprop->SetFontSize(font_size);
560     tprop->SetFontFamilyToCourier();
561     tprop->SetJustificationToLeft();
562     tprop->BoldOn();
563 
564     Color c = vtkcolor(color);
565     tprop->SetColor(c.val);
566 
567     WidgetAccessor::setProp(*this, actor);
568 }
569 
cast()570 template<> cv::viz::WText cv::viz::Widget::cast<cv::viz::WText>()
571 {
572     Widget2D widget = this->cast<Widget2D>();
573     return static_cast<WText&>(widget);
574 }
575 
setText(const String & text)576 void cv::viz::WText::setText(const String &text)
577 {
578     vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
579     CV_Assert("This widget does not support text." && actor);
580     actor->SetInput(text.c_str());
581 }
582 
getText() const583 cv::String cv::viz::WText::getText() const
584 {
585     vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
586     CV_Assert("This widget does not support text." && actor);
587     return actor->GetInput();
588 }
589 
590 ///////////////////////////////////////////////////////////////////////////////////////////////
591 /// image overlay widget implementation
592 
WImageOverlay(InputArray image,const Rect & rect)593 cv::viz::WImageOverlay::WImageOverlay(InputArray image, const Rect &rect)
594 {
595     CV_Assert(!image.empty() && image.depth() == CV_8U);
596     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
597     source->SetImage(image);
598     Size sz = image.size();
599 
600     // Scale the image based on the Rect, and flip to match y-ais orientation
601     vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
602     transform->Scale(sz.width/(double)rect.width, sz.height/(double)rect.height, 1.0);
603     transform->RotateX(180);
604 
605     vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
606     image_reslice->SetResliceTransform(transform);
607     image_reslice->SetInputConnection(source->GetOutputPort());
608     image_reslice->SetOutputDimensionality(2);
609     image_reslice->InterpolateOn();
610     image_reslice->AutoCropOutputOn();
611     image_reslice->Update();
612 
613     vtkSmartPointer<vtkImageMapper> image_mapper = vtkSmartPointer<vtkImageMapper>::New();
614     image_mapper->SetInputConnection(image_reslice->GetOutputPort());
615     image_mapper->SetColorWindow(255); // OpenCV color
616     image_mapper->SetColorLevel(127.5);
617 
618     vtkSmartPointer<vtkActor2D> actor = vtkSmartPointer<vtkActor2D>::New();
619     actor->SetMapper(image_mapper);
620     actor->SetPosition(rect.x, rect.y);
621     actor->GetProperty()->SetDisplayLocationToForeground();
622 
623     WidgetAccessor::setProp(*this, actor);
624 }
625 
setImage(InputArray image)626 void cv::viz::WImageOverlay::setImage(InputArray image)
627 {
628     CV_Assert(!image.empty() && image.depth() == CV_8U);
629 
630     vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
631     CV_Assert("This widget does not support overlay image." && actor);
632 
633     vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper());
634     CV_Assert("This widget does not support overlay image." && mapper);
635     \
636     Vec6i extent;
637     mapper->GetInput()->GetExtent(extent.val);
638     Size size(extent[1], extent[3]);
639 
640     // Create the vtk image and set its parameters based on input image
641     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
642     source->SetImage(image);
643     Size sz = image.size();
644 
645     // Scale the image based on the Rect, and flip to match y-ais orientation
646     vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
647     transform->Scale(sz.width/(double)size.width, sz.height/(double)size.height, 1.0);
648     transform->RotateX(180);
649 
650     vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
651     image_reslice->SetResliceTransform(transform);
652     image_reslice->SetInputConnection(source->GetOutputPort());
653     image_reslice->SetOutputDimensionality(2);
654     image_reslice->InterpolateOn();
655     image_reslice->AutoCropOutputOn();
656     image_reslice->Update();
657 
658     mapper->SetInputConnection(image_reslice->GetOutputPort());
659 }
660 
cast()661 template<> cv::viz::WImageOverlay cv::viz::Widget::cast<cv::viz::WImageOverlay>()
662 {
663     Widget2D widget = this->cast<Widget2D>();
664     return static_cast<WImageOverlay&>(widget);
665 }
666 
667 ///////////////////////////////////////////////////////////////////////////////////////////////
668 /// image 3D widget implementation
669 
WImage3D(InputArray image,const Size2d & size)670 cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size)
671 {
672     CV_Assert(!image.empty() && image.depth() == CV_8U);
673 
674     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
675     source->SetImage(image);
676 
677     vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
678     texture->SetInputConnection(source->GetOutputPort());
679 
680     vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
681     plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0);
682     plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0);
683     plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
684 
685     vtkSmartPointer<vtkTextureMapToPlane> textured_plane = vtkSmartPointer<vtkTextureMapToPlane>::New();
686     textured_plane->SetInputConnection(plane->GetOutputPort());
687 
688     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
689     mapper->SetInputConnection(textured_plane->GetOutputPort());
690 
691     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
692     actor->SetMapper(mapper);
693     actor->SetTexture(texture);
694     actor->GetProperty()->ShadingOff();
695     actor->GetProperty()->LightingOff();
696 
697     WidgetAccessor::setProp(*this, actor);
698 }
699 
WImage3D(InputArray image,const Size2d & size,const Vec3d & center,const Vec3d & normal,const Vec3d & up_vector)700 cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size, const Vec3d &center, const Vec3d &normal, const Vec3d &up_vector)
701 {
702     CV_Assert(!image.empty() && image.depth() == CV_8U);
703 
704     // Compute the transformation matrix for drawing the camera frame in a scene
705     Vec3d n = normalize(normal);
706     Vec3d u = normalize(up_vector.cross(n));
707     Vec3d v = n.cross(u);
708     Affine3d pose = makeTransformToGlobal(u, v, n, center);
709 
710     WImage3D image3d(image, size);
711     image3d.applyTransform(pose);
712     *this = image3d;
713 }
714 
setImage(InputArray image)715 void cv::viz::WImage3D::setImage(InputArray image)
716 {
717     CV_Assert(!image.empty() && image.depth() == CV_8U);
718 
719     vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
720     CV_Assert("This widget does not support 3D image." && actor);
721 
722     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
723     source->SetImage(image);
724 
725     vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
726     texture->SetInputConnection(source->GetOutputPort());
727 
728     actor->SetTexture(texture);
729 }
730 
cast()731 template<> cv::viz::WImage3D cv::viz::Widget::cast<cv::viz::WImage3D>()
732 {
733     Widget3D widget = this->cast<Widget3D>();
734     return static_cast<WImage3D&>(widget);
735 }
736 
737 ///////////////////////////////////////////////////////////////////////////////////////////////
738 /// camera position widget implementation
739 
740 namespace  cv  { namespace viz { namespace
741 {
742     struct CameraPositionUtils
743     {
createFrustumcv::viz::__anone34971ba0111::CameraPositionUtils744         static vtkSmartPointer<vtkPolyData> createFrustum(double aspect_ratio, double fovy, double scale)
745         {
746             vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
747             camera->SetViewAngle(fovy);
748             camera->SetPosition(0.0, 0.0, 0.0);
749             camera->SetViewUp(0.0, 1.0, 0.0);
750             camera->SetFocalPoint(0.0, 0.0, 1.0);
751             camera->SetClippingRange(1e-9, scale);
752 
753             double planes_array[24];
754             camera->GetFrustumPlanes(aspect_ratio, planes_array);
755 
756             vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
757             planes->SetFrustumPlanes(planes_array);
758 
759             vtkSmartPointer<vtkFrustumSource> frustumSource = vtkSmartPointer<vtkFrustumSource>::New();
760             frustumSource->SetPlanes(planes);
761 
762             vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
763             extract_edges->SetInputConnection(frustumSource->GetOutputPort());
764             extract_edges->Update();
765 
766             return extract_edges->GetOutput();
767         }
768 
ensureColorImagecv::viz::__anone34971ba0111::CameraPositionUtils769         static Mat ensureColorImage(InputArray image)
770         {
771             Mat color(image.size(), CV_8UC3);
772             if (image.channels() == 1)
773             {
774                 Vec3b *drow = color.ptr<Vec3b>();
775                 for(int y = 0; y < color.rows; ++y)
776                 {
777                     const unsigned char *srow = image.getMat().ptr<unsigned char>(y);
778                     const unsigned char *send = srow + color.cols;
779                     for(;srow < send;)
780                         *drow++ = Vec3b::all(*srow++);
781                 }
782             }
783             else
784                 image.copyTo(color);
785             return color;
786         }
787     };
788 }}}
789 
WCameraPosition(double scale)790 cv::viz::WCameraPosition::WCameraPosition(double scale)
791 {
792     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
793     VtkUtils::SetInputData(mapper, getPolyData(WCoordinateSystem(scale)));
794     mapper->SetScalarModeToUsePointData();
795 
796     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
797     actor->SetMapper(mapper);
798 
799     WidgetAccessor::setProp(*this, actor);
800 }
801 
WCameraPosition(const Matx33d & K,double scale,const Color & color)802 cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const Color &color)
803 {
804     double f_x = K(0,0), f_y = K(1,1), c_y = K(1,2);
805 
806     // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
807     double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI;
808     double aspect_ratio = f_y / f_x;
809 
810     vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
811     VtkUtils::FillScalars(polydata, color);
812 
813     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
814     VtkUtils::SetInputData(mapper, polydata);
815 
816     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
817     actor->SetMapper(mapper);
818 
819     WidgetAccessor::setProp(*this, actor);
820 }
821 
WCameraPosition(const Vec2d & fov,double scale,const Color & color)822 cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color)
823 {
824     double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5);
825     double fovy = fov[1] * 180 / CV_PI;
826 
827     vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
828     VtkUtils::FillScalars(polydata, color);
829 
830     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
831     VtkUtils::SetInputData(mapper, polydata);
832 
833     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
834     actor->SetMapper(mapper);
835 
836     WidgetAccessor::setProp(*this, actor);
837 }
838 
WCameraPosition(const Matx33d & K,InputArray _image,double scale,const Color & color)839 cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color)
840 {
841     CV_Assert(!_image.empty() && _image.depth() == CV_8U);
842     Mat image = CameraPositionUtils::ensureColorImage(_image);
843     image.at<Vec3b>(0, 0) = Vec3d(color.val); //workaround of VTK limitation
844 
845     double f_y = K(1,1), c_y = K(1,2);
846     // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
847     double fovy = 2.0 * atan2(c_y, f_y) * 180.0 / CV_PI;
848     double far_end_height = 2.00 * c_y * scale / f_y;
849     double aspect_ratio = image.cols/(double)image.rows;
850     double image_scale = far_end_height/image.rows;
851 
852     WImage3D image_widget(image, Size2d(image.size()) * image_scale);
853     image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale)));
854     vtkSmartPointer<vtkPolyData> plane = getPolyData(image_widget);
855 
856     vtkSmartPointer<vtkPolyData> frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
857 
858     // Frustum needs to be textured or else it can't be combined with image
859     vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
860     VtkUtils::SetInputData(frustum_texture, frustum);
861     frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel
862     frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color
863 
864     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
865     append_filter->AddInputConnection(frustum_texture->GetOutputPort());
866     VtkUtils::AddInputData(append_filter, plane);
867 
868     vtkSmartPointer<vtkActor> actor = getActor(image_widget);
869     actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort());
870     WidgetAccessor::setProp(*this, actor);
871 }
872 
WCameraPosition(const Vec2d & fov,InputArray _image,double scale,const Color & color)873 cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, InputArray _image, double scale, const Color &color)
874 {
875     CV_Assert(!_image.empty() && _image.depth() == CV_8U);
876     Mat image = CameraPositionUtils::ensureColorImage(_image);
877     image.at<Vec3b>(0, 0) = Vec3d(color.val); //workaround of VTK limitation
878 
879     double fovy = fov[1] * 180.0 / CV_PI;
880     double far_end_height = 2.0 * scale * tan(fov[1] * 0.5);
881     double aspect_ratio = image.cols/(double)image.rows;
882     double image_scale = far_end_height/image.rows;
883 
884     WImage3D image_widget(image, Size2d(image.size()) * image_scale);
885     image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale)));
886     vtkSmartPointer<vtkPolyData> plane = getPolyData(image_widget);
887 
888     vtkSmartPointer<vtkPolyData> frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
889 
890     // Frustum needs to be textured or else it can't be combined with image
891     vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
892     VtkUtils::SetInputData(frustum_texture, frustum);
893     frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel
894     frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color
895 
896     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
897     append_filter->AddInputConnection(frustum_texture->GetOutputPort());
898     VtkUtils::AddInputData(append_filter, plane);
899 
900     vtkSmartPointer<vtkActor> actor = getActor(image_widget);
901     actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort());
902     WidgetAccessor::setProp(*this, actor);
903 }
904 
cast()905 template<> cv::viz::WCameraPosition cv::viz::Widget::cast<cv::viz::WCameraPosition>()
906 {
907     Widget3D widget = this->cast<Widget3D>();
908     return static_cast<WCameraPosition&>(widget);
909 }
910 
911 ///////////////////////////////////////////////////////////////////////////////////////////////
912 /// trajectory widget implementation
913 
WTrajectory(InputArray _path,int display_mode,double scale,const Color & color)914 cv::viz::WTrajectory::WTrajectory(InputArray _path, int display_mode, double scale, const Color &color)
915 {
916     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
917 
918     // Bitwise and with 3 in order to limit the domain to 2 bits
919     if (display_mode & WTrajectory::PATH)
920     {
921         Mat points = vtkTrajectorySource::ExtractPoints(_path);
922         vtkSmartPointer<vtkPolyData> polydata = getPolyData(WPolyLine(points, color));
923         VtkUtils::AddInputData(append_filter, polydata);
924     }
925 
926     if (display_mode & WTrajectory::FRAMES)
927     {
928         vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
929         source->SetTrajectory(_path);
930 
931         vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCoordinateSystem(scale));
932 
933         vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
934         tensor_glyph->SetInputConnection(source->GetOutputPort());
935         VtkUtils::SetSourceData(tensor_glyph, glyph);
936         tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
937         tensor_glyph->ThreeGlyphsOff();
938         tensor_glyph->SymmetricOff();
939         tensor_glyph->ColorGlyphsOff();
940 
941         append_filter->AddInputConnection(tensor_glyph->GetOutputPort());
942     }
943     append_filter->Update();
944 
945     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
946     VtkUtils::SetInputData(mapper, append_filter->GetOutput());
947     mapper->SetScalarModeToUsePointData();
948     mapper->SetScalarRange(0, 255);
949 
950     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
951     actor->SetMapper(mapper);
952 
953     WidgetAccessor::setProp(*this, actor);
954 }
955 
cast()956 template<> cv::viz::WTrajectory cv::viz::Widget::cast<cv::viz::WTrajectory>()
957 {
958     Widget3D widget = this->cast<Widget3D>();
959     return static_cast<WTrajectory&>(widget);
960 }
961 
962 ///////////////////////////////////////////////////////////////////////////////////////////////
963 /// WTrajectoryFrustums widget implementation
964 
WTrajectoryFrustums(InputArray _path,const Matx33d & K,double scale,const Color & color)965 cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33d &K, double scale, const Color &color)
966 {
967     vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
968     source->SetTrajectory(_path);
969 
970     vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(K, scale));
971     VtkUtils::FillScalars(glyph, color);
972 
973     vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
974     tensor_glyph->SetInputConnection(source->GetOutputPort());
975     VtkUtils::SetSourceData(tensor_glyph, glyph);
976     tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
977     tensor_glyph->ThreeGlyphsOff();
978     tensor_glyph->SymmetricOff();
979     tensor_glyph->ColorGlyphsOff();
980     tensor_glyph->Update();
981 
982     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
983     VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput());
984 
985     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
986     actor->SetMapper(mapper);
987 
988     WidgetAccessor::setProp(*this, actor);
989 }
990 
WTrajectoryFrustums(InputArray _path,const Vec2d & fov,double scale,const Color & color)991 cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color)
992 {
993     vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
994     source->SetTrajectory(_path);
995 
996     vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(fov, scale));
997     VtkUtils::FillScalars(glyph, color);
998 
999     vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
1000     tensor_glyph->SetInputConnection(source->GetOutputPort());
1001     VtkUtils::SetSourceData(tensor_glyph, glyph);
1002     tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
1003     tensor_glyph->ThreeGlyphsOff();
1004     tensor_glyph->SymmetricOff();
1005     tensor_glyph->ColorGlyphsOff();
1006     tensor_glyph->Update();
1007 
1008     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1009     VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput());
1010 
1011     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
1012     actor->SetMapper(mapper);
1013 
1014     WidgetAccessor::setProp(*this, actor);
1015 }
1016 
cast()1017 template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast<cv::viz::WTrajectoryFrustums>()
1018 {
1019     Widget3D widget = this->cast<Widget3D>();
1020     return static_cast<WTrajectoryFrustums&>(widget);
1021 }
1022 
1023 ///////////////////////////////////////////////////////////////////////////////////////////////
1024 /// WTrajectorySpheres widget implementation
1025 
WTrajectorySpheres(InputArray _path,double line_length,double radius,const Color & from,const Color & to)1026 cv::viz::WTrajectorySpheres::WTrajectorySpheres(InputArray _path, double line_length, double radius, const Color &from, const Color &to)
1027 {
1028     CV_Assert(_path.kind() == _InputArray::STD_VECTOR || _path.kind() == _InputArray::MAT);
1029     CV_Assert(_path.type() == CV_32FC(16) || _path.type() == CV_64FC(16));
1030 
1031     Mat path64;
1032     _path.getMat().convertTo(path64, CV_64F);
1033     Affine3d *traj = path64.ptr<Affine3d>();
1034     size_t total = path64.total();
1035 
1036     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
1037 
1038     for(size_t i = 0; i < total; ++i)
1039     {
1040         Vec3d curr = traj[i].translation();
1041 
1042         vtkSmartPointer<vtkSphereSource> sphere_source = vtkSmartPointer<vtkSphereSource>::New();
1043         sphere_source->SetCenter(curr.val);
1044         sphere_source->SetRadius( (i == 0) ? 2 * radius : radius );
1045         sphere_source->Update();
1046 
1047         double alpha = static_cast<double>(i)/total;
1048         Color c = from * (1 - alpha) + to * alpha;
1049 
1050         vtkSmartPointer<vtkPolyData> polydata = sphere_source->GetOutput();
1051         polydata->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata->GetNumberOfCells(), c));
1052         VtkUtils::AddInputData(append_filter, polydata);
1053 
1054         if (i > 0)
1055         {
1056             Vec3d prev = traj[i-1].translation();
1057             Vec3d lvec = prev - curr;
1058 
1059             if(norm(lvec) > line_length)
1060                 lvec = normalize(lvec) * line_length;
1061 
1062             Vec3d lend = curr + lvec;
1063 
1064             vtkSmartPointer<vtkLineSource> line_source = vtkSmartPointer<vtkLineSource>::New();
1065             line_source->SetPoint1(curr.val);
1066             line_source->SetPoint2(lend.val);
1067             line_source->Update();
1068             vtkSmartPointer<vtkPolyData> polydata_ = line_source->GetOutput();
1069             polydata_->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata_->GetNumberOfCells(), c));
1070             VtkUtils::AddInputData(append_filter, polydata_);
1071         }
1072     }
1073     append_filter->Update();
1074 
1075     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1076     mapper->SetScalarModeToUseCellData();
1077     VtkUtils::SetInputData(mapper, append_filter->GetOutput());
1078 
1079     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
1080     actor->SetMapper(mapper);
1081 
1082     WidgetAccessor::setProp(*this, actor);
1083 }
1084 
cast()1085 template<> cv::viz::WTrajectorySpheres cv::viz::Widget::cast<cv::viz::WTrajectorySpheres>()
1086 {
1087     Widget3D widget = this->cast<Widget3D>();
1088     return static_cast<WTrajectorySpheres&>(widget);
1089 }
1090