shapes.cpp 51.2 KB
Newer Older
Ozan Tonkal's avatar
Ozan Tonkal committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
// Authors:
//  * Ozan Tonkal, ozantonkal@gmail.com
//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
//
//M*/

46 47
#include "precomp.hpp"

ozantonkal's avatar
ozantonkal committed
48 49 50 51 52 53 54 55
namespace cv
{
    namespace viz
    {
        template<typename _Tp> Vec<_Tp, 3>* vtkpoints_data(vtkSmartPointer<vtkPoints>& points);
    }
}

ozantonkal's avatar
ozantonkal committed
56 57
///////////////////////////////////////////////////////////////////////////////////////////////
/// line widget implementation
58
cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
59
{
60
    vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
61 62
    line->SetPoint1(pt1.x, pt1.y, pt1.z);
    line->SetPoint2(pt2.x, pt2.y, pt2.z);
63

64
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
65
    mapper->SetInputConnection(line->GetOutputPort());
66

67
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
68 69
    actor->SetMapper(mapper);

70
    WidgetAccessor::setProp(*this, actor);
71 72
    setColor(color);
}
73

74
template<> cv::viz::WLine cv::viz::Widget::cast<cv::viz::WLine>()
75 76
{
    Widget3D widget = this->cast<Widget3D>();
77
    return static_cast<WLine&>(widget);
78 79
}

ozantonkal's avatar
ozantonkal committed
80 81 82
///////////////////////////////////////////////////////////////////////////////////////////////
/// plane widget implementation

83
namespace cv { namespace viz { namespace
ozantonkal's avatar
ozantonkal committed
84
{
85
    struct PlaneUtils
ozantonkal's avatar
ozantonkal committed
86
    {
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
        template<typename _Tp>
        static vtkSmartPointer<vtkTransformPolyDataFilter> setSize(const Vec<_Tp, 3> &center, vtkSmartPointer<vtkAlgorithmOutput> poly_data_port, double size)
        {
            vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
            transform->PreMultiply();
            transform->Translate(center[0], center[1], center[2]);
            transform->Scale(size, size, size);
            transform->Translate(-center[0], -center[1], -center[2]);

            vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
            transform_filter->SetInputConnection(poly_data_port);
            transform_filter->SetTransform(transform);
            transform_filter->Update();

            return transform_filter;
        }
    };
}}}
ozantonkal's avatar
ozantonkal committed
105

106
cv::viz::WPlane::WPlane(const Vec4d& coefs, double size, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
107
{
Ozan Tonkal's avatar
Ozan Tonkal committed
108 109
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    plane->SetNormal(coefs[0], coefs[1], coefs[2]);
110
    double norm = cv::norm(Vec3d(coefs.val));
Ozan Tonkal's avatar
Ozan Tonkal committed
111
    plane->Push(-coefs[3] / norm);
Ozan Tonkal's avatar
Ozan Tonkal committed
112

ozantonkal's avatar
ozantonkal committed
113 114
    Vec3d p_center;
    plane->GetOrigin(p_center.val);
Ozan Tonkal's avatar
Ozan Tonkal committed
115

116
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
117
    mapper->SetInputConnection(PlaneUtils::setSize(p_center, plane->GetOutputPort(), size)->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
118

119
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
ozantonkal's avatar
ozantonkal committed
120
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
121

122
    WidgetAccessor::setProp(*this, actor);
ozantonkal's avatar
ozantonkal committed
123 124 125
    setColor(color);
}

126
cv::viz::WPlane::WPlane(const Vec4d& coefs, const Point3d& pt, double size, const Color &color)
ozantonkal's avatar
ozantonkal committed
127
{
Ozan Tonkal's avatar
Ozan Tonkal committed
128
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
129
    Point3d coefs3(coefs[0], coefs[1], coefs[2]);
Ozan Tonkal's avatar
Ozan Tonkal committed
130
    double norm_sqr = 1.0 / coefs3.dot(coefs3);
ozantonkal's avatar
ozantonkal committed
131 132 133
    plane->SetNormal(coefs[0], coefs[1], coefs[2]);

    double t = coefs3.dot(pt) + coefs[3];
134
    Vec3d p_center = pt - coefs3 * t * norm_sqr;
Ozan Tonkal's avatar
Ozan Tonkal committed
135
    plane->SetCenter(p_center[0], p_center[1], p_center[2]);
Ozan Tonkal's avatar
Ozan Tonkal committed
136

137
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
138
    mapper->SetInputConnection(PlaneUtils::setSize(p_center, plane->GetOutputPort(), size)->GetOutputPort());
ozantonkal's avatar
ozantonkal committed
139

140
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
ozantonkal's avatar
ozantonkal committed
141
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
142

143
    WidgetAccessor::setProp(*this, actor);
144 145 146
    setColor(color);
}

147
template<> cv::viz::WPlane cv::viz::Widget::cast<cv::viz::WPlane>()
148
{
149
    Widget3D widget = this->cast<Widget3D>();
150
    return static_cast<WPlane&>(widget);
151 152
}

153 154 155
///////////////////////////////////////////////////////////////////////////////////////////////
/// sphere widget implementation

156
cv::viz::WSphere::WSphere(const Point3d &center, double radius, int sphere_resolution, const Color &color)
157
{
Ozan Tonkal's avatar
Ozan Tonkal committed
158 159 160 161 162 163
    vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
    sphere->SetRadius(radius);
    sphere->SetCenter(center.x, center.y, center.z);
    sphere->SetPhiResolution(sphere_resolution);
    sphere->SetThetaResolution(sphere_resolution);
    sphere->LatLongTessellationOff();
Ozan Tonkal's avatar
Ozan Tonkal committed
164

165
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
166
    mapper->SetInputConnection(sphere->GetOutputPort());
167

168
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
169 170
    actor->SetMapper(mapper);

171
    WidgetAccessor::setProp(*this, actor);
ozantonkal's avatar
ozantonkal committed
172
    setColor(color);
173 174
}

175
template<> cv::viz::WSphere cv::viz::Widget::cast<cv::viz::WSphere>()
176
{
177
    Widget3D widget = this->cast<Widget3D>();
178
    return static_cast<WSphere&>(widget);
179 180
}

181 182 183
///////////////////////////////////////////////////////////////////////////////////////////////
/// arrow widget implementation

184
cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness, const Color &color)
185
{
Ozan Tonkal's avatar
Ozan Tonkal committed
186
    vtkSmartPointer<vtkArrowSource> arrowSource = vtkSmartPointer<vtkArrowSource>::New();
187 188 189 190
    arrowSource->SetShaftRadius(thickness);
    // The thickness and radius of the tip are adjusted based on the thickness of the arrow
    arrowSource->SetTipRadius(thickness * 3.0);
    arrowSource->SetTipLength(thickness * 10.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
191

Anatoly Baksheev's avatar
Anatoly Baksheev committed
192 193 194 195
    RNG rng = theRNG();
    Vec3d arbitrary(rng.uniform(-10.0, 10.0), rng.uniform(-10.0, 10.0), rng.uniform(-10.0, 10.0));
    Vec3d startPoint(pt1.x, pt1.y, pt1.z), endPoint(pt2.x, pt2.y, pt2.z);

Anatoly Baksheev's avatar
Anatoly Baksheev committed
196 197
    double length = cv::norm(endPoint - startPoint);

Anatoly Baksheev's avatar
Anatoly Baksheev committed
198 199 200
    Vec3d xvec = normalized(endPoint - startPoint);
    Vec3d zvec = normalized(xvec.cross(arbitrary));
    Vec3d yvec = zvec.cross(xvec);
201

Anatoly Baksheev's avatar
Anatoly Baksheev committed
202
    Affine3d pose = makeTransformToGlobal(xvec, yvec, zvec);
203 204

    // Apply the transforms
205
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
206
    transform->Translate(startPoint.val);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
207
    transform->Concatenate(vtkmatrix(pose.matrix));
208 209 210
    transform->Scale(length, length, length);

    // Transform the polydata
211
    vtkSmartPointer<vtkTransformPolyDataFilter> transformPD = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
212 213
    transformPD->SetTransform(transform);
    transformPD->SetInputConnection(arrowSource->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
214

215
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
216
    mapper->SetInputConnection(transformPD->GetOutputPort());
217

218
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
219
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
220

221
    WidgetAccessor::setProp(*this, actor);
222 223 224
    setColor(color);
}

225
template<> cv::viz::WArrow cv::viz::Widget::cast<cv::viz::WArrow>()
226
{
227
    Widget3D widget = this->cast<Widget3D>();
228
    return static_cast<WArrow&>(widget);
229 230
}

231 232 233
///////////////////////////////////////////////////////////////////////////////////////////////
/// circle widget implementation

234
cv::viz::WCircle::WCircle(const Point3d& pt, double radius, double thickness, const Color& color)
235
{
Ozan Tonkal's avatar
Ozan Tonkal committed
236
    vtkSmartPointer<vtkDiskSource> disk = vtkSmartPointer<vtkDiskSource>::New();
237
    // Maybe the resolution should be lower e.g. 50 or 25
Ozan Tonkal's avatar
Ozan Tonkal committed
238 239 240
    disk->SetCircumferentialResolution(50);
    disk->SetInnerRadius(radius - thickness);
    disk->SetOuterRadius(radius + thickness);
241 242

    // Set the circle origin
Ozan Tonkal's avatar
Ozan Tonkal committed
243 244 245
    vtkSmartPointer<vtkTransform> t = vtkSmartPointer<vtkTransform>::New();
    t->Identity();
    t->Translate(pt.x, pt.y, pt.z);
246

Ozan Tonkal's avatar
Ozan Tonkal committed
247 248 249
    vtkSmartPointer<vtkTransformPolyDataFilter> tf = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    tf->SetTransform(t);
    tf->SetInputConnection(disk->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
250

251
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
252
    mapper->SetInputConnection(tf->GetOutputPort());
253

254
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
255
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
256

257
    WidgetAccessor::setProp(*this, actor);
258 259 260
    setColor(color);
}

261
template<> cv::viz::WCircle cv::viz::Widget::cast<cv::viz::WCircle>()
262
{
263
    Widget3D widget = this->cast<Widget3D>();
264
    return static_cast<WCircle&>(widget);
265 266
}

267 268 269
///////////////////////////////////////////////////////////////////////////////////////////////
/// cylinder widget implementation

270
cv::viz::WCylinder::WCylinder(const Point3d& pt_on_axis, const Point3d& axis_direction, double radius, int numsides, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
271
{
272
    const Point3d pt2 = pt_on_axis + axis_direction;
Ozan Tonkal's avatar
Ozan Tonkal committed
273 274 275
    vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
    line->SetPoint1(pt_on_axis.x, pt_on_axis.y, pt_on_axis.z);
    line->SetPoint2(pt2.x, pt2.y, pt2.z);
Ozan Tonkal's avatar
Ozan Tonkal committed
276

Ozan Tonkal's avatar
Ozan Tonkal committed
277 278 279 280
    vtkSmartPointer<vtkTubeFilter> tuber = vtkSmartPointer<vtkTubeFilter>::New();
    tuber->SetInputConnection(line->GetOutputPort());
    tuber->SetRadius(radius);
    tuber->SetNumberOfSides(numsides);
Ozan Tonkal's avatar
Ozan Tonkal committed
281

282
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
283
    mapper->SetInputConnection(tuber->GetOutputPort());
284

285
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
286
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
287

288
    WidgetAccessor::setProp(*this, actor);
289 290
    setColor(color);
}
ozantonkal's avatar
ozantonkal committed
291

292
template<> cv::viz::WCylinder cv::viz::Widget::cast<cv::viz::WCylinder>()
293
{
294
    Widget3D widget = this->cast<Widget3D>();
295
    return static_cast<WCylinder&>(widget);
296 297
}

ozantonkal's avatar
ozantonkal committed
298 299 300
///////////////////////////////////////////////////////////////////////////////////////////////
/// cylinder widget implementation

301
cv::viz::WCube::WCube(const Point3d& pt_min, const Point3d& pt_max, bool wire_frame, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
302
{
303
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
304 305 306
    if (wire_frame)
    {
        vtkSmartPointer<vtkOutlineSource> cube = vtkSmartPointer<vtkOutlineSource>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
307
        cube->SetBounds(pt_min.x, pt_max.x, pt_min.y, pt_max.y, pt_min.z, pt_max.z);
308
        mapper->SetInputConnection(cube->GetOutputPort());
309 310 311
    }
    else
    {
Ozan Tonkal's avatar
Ozan Tonkal committed
312 313
        vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
        cube->SetBounds(pt_min.x, pt_max.x, pt_min.y, pt_max.y, pt_min.z, pt_max.z);
314
        mapper->SetInputConnection(cube->GetOutputPort());
315
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
316

317
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
ozantonkal's avatar
ozantonkal committed
318
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
319

320
    WidgetAccessor::setProp(*this, actor);
ozantonkal's avatar
ozantonkal committed
321 322
    setColor(color);
}
323

324
template<> cv::viz::WCube cv::viz::Widget::cast<cv::viz::WCube>()
325
{
326
    Widget3D widget = this->cast<Widget3D>();
327
    return static_cast<WCube&>(widget);
328 329
}

330 331 332
///////////////////////////////////////////////////////////////////////////////////////////////
/// coordinate system widget implementation

333
cv::viz::WCoordinateSystem::WCoordinateSystem(double scale)
334
{
Ozan Tonkal's avatar
Ozan Tonkal committed
335 336 337
    vtkSmartPointer<vtkAxes> axes = vtkSmartPointer<vtkAxes>::New();
    axes->SetOrigin(0, 0, 0);
    axes->SetScaleFactor(scale);
338
    axes->Update();
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355

    vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(3);
    colors->InsertNextTuple3(255, 0, 0);
    colors->InsertNextTuple3(255, 0, 0);
    colors->InsertNextTuple3(0, 255, 0);
    colors->InsertNextTuple3(0, 255, 0);
    colors->InsertNextTuple3(0, 0, 255);
    colors->InsertNextTuple3(0, 0, 255);

    vtkSmartPointer<vtkPolyData> polydata = axes->GetOutput();
    polydata->GetPointData()->SetScalars(colors);

    vtkSmartPointer<vtkTubeFilter> tube_filter = vtkSmartPointer<vtkTubeFilter>::New();
    VtkUtils::SetInputData(tube_filter, polydata);
    tube_filter->SetRadius(axes->GetScaleFactor() / 50.0);
    tube_filter->SetNumberOfSides(6);
Ozan Tonkal's avatar
Ozan Tonkal committed
356

357
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
358
    mapper->SetScalarModeToUsePointData();
359
    VtkUtils::SetInputData(mapper, tube_filter->GetOutput());
360

361
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
362
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
363

364
    WidgetAccessor::setProp(*this, actor);
365
}
ozantonkal's avatar
ozantonkal committed
366

367
template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast<cv::viz::WCoordinateSystem>()
368
{
369
    Widget3D widget = this->cast<Widget3D>();
370
    return static_cast<WCoordinateSystem&>(widget);
371 372
}

373 374 375
///////////////////////////////////////////////////////////////////////////////////////////////
/// polyline widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
376
cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
377
{
Anatoly Baksheev's avatar
Anatoly Baksheev committed
378
    CV_Assert(_points.type() == CV_32FC3 || _points.type() == CV_32FC4 || _points.type() == CV_64FC3 || _points.type() == CV_64FC4);
379

Anatoly Baksheev's avatar
Anatoly Baksheev committed
380 381 382 383
    const float *fpoints = _points.getMat().ptr<float>();
    const double *dpoints = _points.getMat().ptr<double>();
    size_t total = _points.total();
    int s_chs = _points.channels();
Ozan Tonkal's avatar
Ozan Tonkal committed
384

Ozan Tonkal's avatar
Ozan Tonkal committed
385
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
386 387
    points->SetDataType(_points.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE);
    points->SetNumberOfPoints(total);
Ozan Tonkal's avatar
Ozan Tonkal committed
388

Anatoly Baksheev's avatar
Anatoly Baksheev committed
389 390 391
    if (_points.depth() == CV_32F)
        for(size_t i = 0; i < total; ++i, fpoints += s_chs)
            points->SetPoint(i, fpoints);
Ozan Tonkal's avatar
Ozan Tonkal committed
392

Anatoly Baksheev's avatar
Anatoly Baksheev committed
393 394 395
    if (_points.depth() == CV_64F)
        for(size_t i = 0; i < total; ++i, dpoints += s_chs)
            points->SetPoint(i, dpoints);
Ozan Tonkal's avatar
Ozan Tonkal committed
396

Anatoly Baksheev's avatar
Anatoly Baksheev committed
397 398 399 400 401
    vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
    cell_array->Allocate(cell_array->EstimateSize(1, total));
    cell_array->InsertNextCell(total);
    for(size_t i = 0; i < total; ++i)
        cell_array->InsertCellPoint(i);
Ozan Tonkal's avatar
Ozan Tonkal committed
402

Anatoly Baksheev's avatar
Anatoly Baksheev committed
403
    vtkSmartPointer<vtkUnsignedCharArray> scalars =  VtkUtils::FillScalars(total, color);
404

Anatoly Baksheev's avatar
Anatoly Baksheev committed
405 406 407
    vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
    polydata->SetPoints(points);
    polydata->SetLines(cell_array);
408
    polydata->GetPointData()->SetScalars(scalars);
Ozan Tonkal's avatar
Ozan Tonkal committed
409

410
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
411
    mapper->SetInputConnection(polydata->GetProducerPort());
412
    mapper->SetScalarRange(0, 255);
Ozan Tonkal's avatar
Ozan Tonkal committed
413

414 415
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
416

417 418 419
    WidgetAccessor::setProp(*this, actor);
}

420
template<> cv::viz::WPolyLine cv::viz::Widget::cast<cv::viz::WPolyLine>()
421 422
{
    Widget3D widget = this->cast<Widget3D>();
423
    return static_cast<WPolyLine&>(widget);
424 425
}

ozantonkal's avatar
ozantonkal committed
426 427 428
///////////////////////////////////////////////////////////////////////////////////////////////
/// grid widget implementation

429
namespace cv { namespace viz { namespace
430
{
431
    struct GridUtils
432
    {
Anatoly Baksheev's avatar
Anatoly Baksheev committed
433
        static vtkSmartPointer<vtkPolyData> createGrid(const Vec2i &dimensions, const Vec2f &spacing)
434 435 436
        {
            // Create the grid using image data
            vtkSmartPointer<vtkImageData> grid = vtkSmartPointer<vtkImageData>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
437

438 439 440 441
            // Add 1 to dimensions because in ImageData dimensions is the number of lines
            // - however here it means number of cells
            grid->SetDimensions(dimensions[0]+1, dimensions[1]+1, 1);
            grid->SetSpacing(spacing[0], spacing[1], 0.);
Ozan Tonkal's avatar
Ozan Tonkal committed
442

443 444
            // Set origin of the grid to be the middle of the grid
            grid->SetOrigin(dimensions[0] * spacing[0] * (-0.5), dimensions[1] * spacing[1] * (-0.5), 0);
Ozan Tonkal's avatar
Ozan Tonkal committed
445

446 447
            // Extract the edges so we have the grid
            vtkSmartPointer<vtkExtractEdges> filter = vtkSmartPointer<vtkExtractEdges>::New();
448
#if VTK_MAJOR_VERSION <= 5
449
            filter->SetInputConnection(grid->GetProducerPort());
450
#else
451
            filter->SetInputData(grid);
452
#endif
453 454 455 456 457
            filter->Update();
            return filter->GetOutput();
        }
    };
}}}
458

459
cv::viz::WGrid::WGrid(const Vec2i &dimensions, const Vec2d &spacing, const Color &color)
ozantonkal's avatar
ozantonkal committed
460
{
461
    vtkSmartPointer<vtkPolyData> grid = GridUtils::createGrid(dimensions, spacing);
Ozan Tonkal's avatar
Ozan Tonkal committed
462

463
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
464
#if VTK_MAJOR_VERSION <= 5
465
    mapper->SetInputConnection(grid->GetProducerPort());
466 467 468
#else
    mapper->SetInputData(grid);
#endif
Ozan Tonkal's avatar
Ozan Tonkal committed
469

470 471
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
472

473 474 475 476
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

477
cv::viz::WGrid::WGrid(const Vec4d &coefs, const Vec2i &dimensions, const Vec2d &spacing, const Color &color)
478
{
479
    vtkSmartPointer<vtkPolyData> grid = GridUtils::createGrid(dimensions, spacing);
Ozan Tonkal's avatar
Ozan Tonkal committed
480

481
    // Estimate the transform to set the normal based on the coefficients
Anatoly Baksheev's avatar
Anatoly Baksheev committed
482 483
    Vec3d normal(coefs[0], coefs[1], coefs[2]);
    Vec3d up_vector(0.0, 1.0, 0.0); // Just set as default
484
    double push_distance = -coefs[3]/cv::norm(Vec3d(coefs.val));
Anatoly Baksheev's avatar
Anatoly Baksheev committed
485 486 487 488 489
    Vec3d n = normalize(normal);
    Vec3d u = normalize(up_vector.cross(n));
    Vec3d v = n.cross(u);

    Affine3d pose = makeTransformToGlobal(u, v, n, n * push_distance);
Ozan Tonkal's avatar
Ozan Tonkal committed
490

491 492
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    transform->PreMultiply();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
493
    transform->SetMatrix(vtkmatrix(pose.matrix));
Ozan Tonkal's avatar
Ozan Tonkal committed
494

495 496
    vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    transform_filter->SetTransform(transform);
497
#if VTK_MAJOR_VERSION <= 5
498
    transform_filter->SetInputConnection(grid->GetProducerPort());
499 500 501
#else
    transform_filter->SetInputData(grid);
#endif
502
    transform_filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
503

504
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
505
    mapper->SetInputConnection(transform_filter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
506

ozantonkal's avatar
ozantonkal committed
507 508
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
509

ozantonkal's avatar
ozantonkal committed
510
    WidgetAccessor::setProp(*this, actor);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
511
    setColor(color);
ozantonkal's avatar
ozantonkal committed
512 513
}

514
template<> cv::viz::WGrid cv::viz::Widget::cast<cv::viz::WGrid>()
ozantonkal's avatar
ozantonkal committed
515 516
{
    Widget3D widget = this->cast<Widget3D>();
517
    return static_cast<WGrid&>(widget);
ozantonkal's avatar
ozantonkal committed
518 519
}

520 521 522
///////////////////////////////////////////////////////////////////////////////////////////////
/// text3D widget implementation

523
cv::viz::WText3D::WText3D(const String &text, const Point3d &position, double text_scale, bool face_camera, const Color &color)
524
{
525 526 527
    vtkSmartPointer<vtkVectorText> textSource = vtkSmartPointer<vtkVectorText>::New();
    textSource->SetText(text.c_str());
    textSource->Update();
528

529
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
530
    mapper->SetInputConnection(textSource->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
531

532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
    if (face_camera)
    {
        vtkSmartPointer<vtkFollower> actor = vtkSmartPointer<vtkFollower>::New();
        actor->SetMapper(mapper);
        actor->SetPosition(position.x, position.y, position.z);
        actor->SetScale(text_scale);
        WidgetAccessor::setProp(*this, actor);
    }
    else
    {
        vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(mapper);
        actor->SetPosition(position.x, position.y, position.z);
        actor->SetScale(text_scale);
        WidgetAccessor::setProp(*this, actor);
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
548

549 550 551
    setColor(color);
}

552
void cv::viz::WText3D::setText(const String &text)
553 554
{
    vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this));
555
    CV_Assert("This widget does not support text." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
556

557 558 559
    // Update text source
    vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
560
    CV_Assert("This widget does not support text." && textSource);
Ozan Tonkal's avatar
Ozan Tonkal committed
561

562 563 564 565
    textSource->SetText(text.c_str());
    textSource->Update();
}

566
cv::String cv::viz::WText3D::getText() const
567 568
{
    vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this));
569
    CV_Assert("This widget does not support text." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
570

571 572
    vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
573
    CV_Assert("This widget does not support text." && textSource);
Ozan Tonkal's avatar
Ozan Tonkal committed
574

575 576 577
    return textSource->GetText();
}

578
template<> cv::viz::WText3D cv::viz::Widget::cast<cv::viz::WText3D>()
579 580
{
    Widget3D widget = this->cast<Widget3D>();
581
    return static_cast<WText3D&>(widget);
582 583
}

584 585 586
///////////////////////////////////////////////////////////////////////////////////////////////
/// text widget implementation

587
cv::viz::WText::WText(const String &text, const Point2i &pos, int font_size, const Color &color)
ozantonkal's avatar
ozantonkal committed
588
{
589
    vtkSmartPointer<vtkTextActor> actor = vtkSmartPointer<vtkTextActor>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
590 591
    actor->SetPosition(pos.x, pos.y);
    actor->SetInput(text.c_str());
ozantonkal's avatar
ozantonkal committed
592

Ozan Tonkal's avatar
Ozan Tonkal committed
593 594 595 596 597
    vtkSmartPointer<vtkTextProperty> tprop = actor->GetTextProperty();
    tprop->SetFontSize(font_size);
    tprop->SetFontFamilyToArial();
    tprop->SetJustificationToLeft();
    tprop->BoldOn();
ozantonkal's avatar
ozantonkal committed
598 599

    Color c = vtkcolor(color);
Ozan Tonkal's avatar
Ozan Tonkal committed
600
    tprop->SetColor(c.val);
Ozan Tonkal's avatar
Ozan Tonkal committed
601

602
    WidgetAccessor::setProp(*this, actor);
ozantonkal's avatar
ozantonkal committed
603
}
604

605
template<> cv::viz::WText cv::viz::Widget::cast<cv::viz::WText>()
606
{
607
    Widget2D widget = this->cast<Widget2D>();
608
    return static_cast<WText&>(widget);
609 610
}

611
void cv::viz::WText::setText(const String &text)
612 613
{
    vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
614
    CV_Assert("This widget does not support text." && actor);
615 616 617
    actor->SetInput(text.c_str());
}

618
cv::String cv::viz::WText::getText() const
619 620
{
    vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
621
    CV_Assert("This widget does not support text." && actor);
622 623
    return actor->GetInput();
}
624 625 626 627

///////////////////////////////////////////////////////////////////////////////////////////////
/// image overlay widget implementation

628
cv::viz::WImageOverlay::WImageOverlay(const Mat &image, const Rect &rect)
629 630
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
631

632 633
    // Create the vtk image and set its parameters based on input image
    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
634
    ConvertToVtkImage::convert(image, vtk_image);
Ozan Tonkal's avatar
Ozan Tonkal committed
635

636 637 638
    // Need to flip the image as the coordinates are different in OpenCV and VTK
    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
    flipFilter->SetFilteredAxis(1); // Vertical flip
639
#if VTK_MAJOR_VERSION <= 5
640
    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
641 642 643
#else
    flipFilter->SetInputData(vtk_image);
#endif
644
    flipFilter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
645

646 647 648
    // Scale the image based on the Rect
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    transform->Scale(double(image.cols)/rect.width,double(image.rows)/rect.height,1.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
649

650 651 652 653 654
    vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
    image_reslice->SetResliceTransform(transform);
    image_reslice->SetInputConnection(flipFilter->GetOutputPort());
    image_reslice->SetOutputDimensionality(2);
    image_reslice->InterpolateOn();
Ozan Tonkal's avatar
Ozan Tonkal committed
655 656
    image_reslice->AutoCropOutputOn();

657
    vtkSmartPointer<vtkImageMapper> imageMapper = vtkSmartPointer<vtkImageMapper>::New();
658
    imageMapper->SetInputConnection(image_reslice->GetOutputPort());
659
    imageMapper->SetColorWindow(255); // OpenCV color
Ozan Tonkal's avatar
Ozan Tonkal committed
660 661
    imageMapper->SetColorLevel(127.5);

662 663
    vtkSmartPointer<vtkActor2D> actor = vtkSmartPointer<vtkActor2D>::New();
    actor->SetMapper(imageMapper);
664
    actor->SetPosition(rect.x, rect.y);
Ozan Tonkal's avatar
Ozan Tonkal committed
665

666 667 668
    WidgetAccessor::setProp(*this, actor);
}

669
void cv::viz::WImageOverlay::setImage(const Mat &image)
670 671
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
672

673
    vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
674
    CV_Assert("This widget does not support overlay image." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
675

676
    vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper());
677
    CV_Assert("This widget does not support overlay image." && mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
678

679 680
    // Create the vtk image and set its parameters based on input image
    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
681
    ConvertToVtkImage::convert(image, vtk_image);
Ozan Tonkal's avatar
Ozan Tonkal committed
682

683 684 685
    // Need to flip the image as the coordinates are different in OpenCV and VTK
    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
    flipFilter->SetFilteredAxis(1); // Vertical flip
686
#if VTK_MAJOR_VERSION <= 5
687
    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
688 689 690
#else
    flipFilter->SetInputData(vtk_image);
#endif
691
    flipFilter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
692

693 694 695
    mapper->SetInputConnection(flipFilter->GetOutputPort());
}

696
template<> cv::viz::WImageOverlay cv::viz::Widget::cast<cv::viz::WImageOverlay>()
697 698
{
    Widget2D widget = this->cast<Widget2D>();
699
    return static_cast<WImageOverlay&>(widget);
700 701 702 703 704
}

///////////////////////////////////////////////////////////////////////////////////////////////
/// image 3D widget implementation

705
cv::viz::WImage3D::WImage3D(const Mat &image, const Size &size)
706 707
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
708

709 710
    // Create the vtk image and set its parameters based on input image
    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
711
    ConvertToVtkImage::convert(image, vtk_image);
Ozan Tonkal's avatar
Ozan Tonkal committed
712

713 714 715
    // Need to flip the image as the coordinates are different in OpenCV and VTK
    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
    flipFilter->SetFilteredAxis(1); // Vertical flip
716
#if VTK_MAJOR_VERSION <= 5
717
    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
718 719 720
#else
    flipFilter->SetInputData(vtk_image);
#endif
721
    flipFilter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
722

723
    Vec3d plane_center(size.width * 0.5, size.height * 0.5, 0.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
724

725 726 727
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    plane->SetCenter(plane_center[0], plane_center[1], plane_center[2]);
    plane->SetNormal(0.0, 0.0, 1.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
728

729 730 731 732 733
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    transform->PreMultiply();
    transform->Translate(plane_center[0], plane_center[1], plane_center[2]);
    transform->Scale(size.width, size.height, 1.0);
    transform->Translate(-plane_center[0], -plane_center[1], -plane_center[2]);
Ozan Tonkal's avatar
Ozan Tonkal committed
734

735 736 737 738
    vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    transform_filter->SetTransform(transform);
    transform_filter->SetInputConnection(plane->GetOutputPort());
    transform_filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
739

740 741 742
    // Apply the texture
    vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    texture->SetInputConnection(flipFilter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
743

744 745
    vtkSmartPointer<vtkTextureMapToPlane> texturePlane = vtkSmartPointer<vtkTextureMapToPlane>::New();
    texturePlane->SetInputConnection(transform_filter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
746

747 748
    vtkSmartPointer<vtkPolyDataMapper> planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    planeMapper->SetInputConnection(texturePlane->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
749

750 751 752
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(planeMapper);
    actor->SetTexture(texture);
Ozan Tonkal's avatar
Ozan Tonkal committed
753

754 755 756
    WidgetAccessor::setProp(*this, actor);
}

757
cv::viz::WImage3D::WImage3D(const Vec3d &position, const Vec3d &normal, const Vec3d &up_vector, const Mat &image, const Size &size)
758 759
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
760

761 762
    // Create the vtk image and set its parameters based on input image
    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
763
    ConvertToVtkImage::convert(image, vtk_image);
Ozan Tonkal's avatar
Ozan Tonkal committed
764

765 766 767
    // Need to flip the image as the coordinates are different in OpenCV and VTK
    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
    flipFilter->SetFilteredAxis(1); // Vertical flip
768
#if VTK_MAJOR_VERSION <= 5
769
    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
770 771 772
#else
    flipFilter->SetInputData(vtk_image);
#endif
773
    flipFilter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
774

775 776
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    plane->SetCenter(0.0, 0.0, 0.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
777 778
    plane->SetNormal(0.0, 0.0, 1.0);

779
    // Compute the transformation matrix for drawing the camera frame in a scene
Anatoly Baksheev's avatar
Anatoly Baksheev committed
780 781 782 783 784
    Vec3d n = normalize(normal);
    Vec3d u = normalize(up_vector.cross(n));
    Vec3d v = n.cross(u);

    Affine3d pose = makeTransformToGlobal(u, v, n, position);
Ozan Tonkal's avatar
Ozan Tonkal committed
785

786 787 788
    // Apply the texture
    vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    texture->SetInputConnection(flipFilter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
789

790 791
    vtkSmartPointer<vtkTextureMapToPlane> texturePlane = vtkSmartPointer<vtkTextureMapToPlane>::New();
    texturePlane->SetInputConnection(plane->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
792

793 794 795
    // Apply the transform after texture mapping
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    transform->PreMultiply();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
796
    transform->SetMatrix(vtkmatrix(pose.matrix));
797
    transform->Scale(size.width, size.height, 1.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
798

799 800 801 802
    vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    transform_filter->SetTransform(transform);
    transform_filter->SetInputConnection(texturePlane->GetOutputPort());
    transform_filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
803

804 805
    vtkSmartPointer<vtkPolyDataMapper> planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    planeMapper->SetInputConnection(transform_filter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
806

807 808 809
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(planeMapper);
    actor->SetTexture(texture);
Ozan Tonkal's avatar
Ozan Tonkal committed
810

811 812 813
    WidgetAccessor::setProp(*this, actor);
}

814
void cv::viz::WImage3D::setImage(const Mat &image)
815 816
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
817

818
    vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
819
    CV_Assert("This widget does not support 3D image." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
820

821 822
    // Create the vtk image and set its parameters based on input image
    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
823
    ConvertToVtkImage::convert(image, vtk_image);
Ozan Tonkal's avatar
Ozan Tonkal committed
824

825 826 827
    // Need to flip the image as the coordinates are different in OpenCV and VTK
    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
    flipFilter->SetFilteredAxis(1); // Vertical flip
828
#if VTK_MAJOR_VERSION <= 5
829
    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
830 831 832
#else
    flipFilter->SetInputData(vtk_image);
#endif
833
    flipFilter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
834

835 836 837
    // Apply the texture
    vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    texture->SetInputConnection(flipFilter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
838

839
    actor->SetTexture(texture);
840 841
}

842
template<> cv::viz::WImage3D cv::viz::Widget::cast<cv::viz::WImage3D>()
843 844
{
    Widget3D widget = this->cast<Widget3D>();
845
    return static_cast<WImage3D&>(widget);
846 847 848 849
}

///////////////////////////////////////////////////////////////////////////////////////////////
/// camera position widget implementation
850

851
namespace  cv  { namespace viz { namespace
852
{
853
    struct CameraPositionUtils
854
    {
855
        static void projectImage(double fovy, double far_end_height, const Mat &image,
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
                                 double scale, const Color &color, vtkSmartPointer<vtkActor> actor)
        {
            // Create a camera
            vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
            float aspect_ratio = float(image.cols)/float(image.rows);

            // Create the vtk image
            vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
            ConvertToVtkImage::convert(image, vtk_image);

            // Adjust a pixel of the vtk_image
            vtk_image->SetScalarComponentFromDouble(0, image.rows-1, 0, 0, color[2]);
            vtk_image->SetScalarComponentFromDouble(0, image.rows-1, 0, 1, color[1]);
            vtk_image->SetScalarComponentFromDouble(0, image.rows-1, 0, 2, color[0]);

            // Need to flip the image as the coordinates are different in OpenCV and VTK
            vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
            flipFilter->SetFilteredAxis(1); // Vertical flip
874
#if VTK_MAJOR_VERSION <= 5
875
            flipFilter->SetInputConnection(vtk_image->GetProducerPort());
876
#else
877
            flipFilter->SetInputData(vtk_image);
878
#endif
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
            flipFilter->Update();

            Vec3d plane_center(0.0, 0.0, scale);

            vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
            plane->SetCenter(plane_center[0], plane_center[1], plane_center[2]);
            plane->SetNormal(0.0, 0.0, 1.0);

            vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
            transform->PreMultiply();
            transform->Translate(plane_center[0], plane_center[1], plane_center[2]);
            transform->Scale(far_end_height*aspect_ratio, far_end_height, 1.0);
            transform->RotateY(180.0);
            transform->Translate(-plane_center[0], -plane_center[1], -plane_center[2]);

            // Apply the texture
            vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
            texture->SetInputConnection(flipFilter->GetOutputPort());

            vtkSmartPointer<vtkTextureMapToPlane> texturePlane = vtkSmartPointer<vtkTextureMapToPlane>::New();
            texturePlane->SetInputConnection(plane->GetOutputPort());

            vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
            transform_filter->SetTransform(transform);
            transform_filter->SetInputConnection(texturePlane->GetOutputPort());
            transform_filter->Update();

            // Create frustum
            camera->SetViewAngle(fovy);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
908 909 910
            camera->SetPosition(0.0, 0.0, 0.0);
            camera->SetViewUp(0.0, 1.0, 0.0);
            camera->SetFocalPoint(0.0, 0.0, 1.0);
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
            camera->SetClippingRange(0.01, scale);

            double planesArray[24];
            camera->GetFrustumPlanes(aspect_ratio, planesArray);

            vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
            planes->SetFrustumPlanes(planesArray);

            vtkSmartPointer<vtkFrustumSource> frustumSource =
            vtkSmartPointer<vtkFrustumSource>::New();
            frustumSource->SetPlanes(planes);
            frustumSource->Update();

            vtkSmartPointer<vtkExtractEdges> filter = vtkSmartPointer<vtkExtractEdges>::New();
            filter->SetInputConnection(frustumSource->GetOutputPort());
            filter->Update();

            // Frustum needs to be textured or else it can't be combined with image
            vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
            frustum_texture->SetInputConnection(filter->GetOutputPort());
            // Texture mapping with only one pixel from the image to have constant color
            frustum_texture->SetSRange(0.0, 0.0);
            frustum_texture->SetTRange(0.0, 0.0);

            vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
            appendFilter->AddInputConnection(frustum_texture->GetOutputPort());
            appendFilter->AddInputConnection(transform_filter->GetOutputPort());

            vtkSmartPointer<vtkPolyDataMapper> planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
            planeMapper->SetInputConnection(appendFilter->GetOutputPort());

            actor->SetMapper(planeMapper);
            actor->SetTexture(texture);
        }
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970

        static vtkSmartPointer<vtkPolyData> createFrustrum(double aspect_ratio, double fovy, double scale)
        {
            vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
            camera->SetViewAngle(fovy);
            camera->SetPosition(0.0, 0.0, 0.0);
            camera->SetViewUp(0.0, 1.0, 0.0);
            camera->SetFocalPoint(0.0, 0.0, 1.0);
            camera->SetClippingRange(0.01, scale);

            double planesArray[24];
            camera->GetFrustumPlanes(aspect_ratio, planesArray);

            vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
            planes->SetFrustumPlanes(planesArray);

            vtkSmartPointer<vtkFrustumSource> frustumSource = vtkSmartPointer<vtkFrustumSource>::New();
            frustumSource->SetPlanes(planes);

            vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
            extract_edges->SetInputConnection(frustumSource->GetOutputPort());
            extract_edges->Update();

            return extract_edges->GetOutput();
        }

971 972
    };
}}}
973

974
cv::viz::WCameraPosition::WCameraPosition(double scale)
975
{
976
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
977 978

    VtkUtils::SetInputData(mapper, getPolyData(WCoordinateSystem(scale)));
Ozan Tonkal's avatar
Ozan Tonkal committed
979
    mapper->SetScalarModeToUsePointData();
980

981
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
982
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
983

984 985 986
    WidgetAccessor::setProp(*this, actor);
}

987
cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const Color &color)
988
{
989
    double f_x = K(0,0), f_y = K(1,1), c_y = K(1,2);
Ozan Tonkal's avatar
Ozan Tonkal committed
990

991 992 993
    // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
    double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI;
    double aspect_ratio = f_y / f_x;
994

995
    vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustrum(aspect_ratio, fovy, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
996

997
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
998
    mapper->SetInputConnection(polydata->GetProducerPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
999

1000 1001
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1002

1003 1004 1005
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}
1006

1007
cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color)
1008
{
1009
    double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5);
1010
    double fovy = fov[1] * 180 / CV_PI;
Ozan Tonkal's avatar
Ozan Tonkal committed
1011

1012
    vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustrum(aspect_ratio, fovy, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
1013

1014
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1015
    mapper->SetInputConnection(polydata->GetProducerPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
1016

1017 1018
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1019

1020 1021 1022
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}
1023

1024
cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, const Mat &image, double scale, const Color &color)
1025 1026
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
1027 1028 1029

    double f_y = K(1,1), c_y = K(1,2);

1030
    // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
1031 1032
    double fovy = 2.0 * atan2(c_y, f_y) * 180.0 / CV_PI;
    double far_end_height = 2.00 * c_y * scale / f_y;
Ozan Tonkal's avatar
Ozan Tonkal committed
1033

1034
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
1035
    CameraPositionUtils::projectImage(fovy, far_end_height, image, scale, color, actor);
1036 1037 1038
    WidgetAccessor::setProp(*this, actor);
}

1039
cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, const Mat &image, double scale, const Color &color)
1040 1041
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
1042 1043
    double fovy = fov[1] * 180.0 / CV_PI;
    double far_end_height = 2.0 * scale * tan(fov[1] * 0.5);
Ozan Tonkal's avatar
Ozan Tonkal committed
1044

1045
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
1046
    CameraPositionUtils::projectImage(fovy, far_end_height, image, scale, color, actor);
1047 1048 1049
    WidgetAccessor::setProp(*this, actor);
}

1050
template<> cv::viz::WCameraPosition cv::viz::Widget::cast<cv::viz::WCameraPosition>()
1051 1052
{
    Widget3D widget = this->cast<Widget3D>();
1053
    return static_cast<WCameraPosition&>(widget);
1054 1055
}

1056 1057 1058
///////////////////////////////////////////////////////////////////////////////////////////////
/// trajectory widget implementation

1059
namespace cv { namespace viz { namespace
1060
{
1061
    struct TrajectoryUtils
Ozan Tonkal's avatar
Ozan Tonkal committed
1062
    {
1063
        static void applyPath(vtkSmartPointer<vtkPolyData> poly_data, vtkSmartPointer<vtkAppendPolyData> append_filter, const std::vector<Affine3d> &path)
1064
        {
1065
            vtkIdType nr_points = path.size();
Ozan Tonkal's avatar
Ozan Tonkal committed
1066

1067 1068 1069 1070
            for (vtkIdType i = 0; i < nr_points; ++i)
            {
                vtkSmartPointer<vtkPolyData> new_data = vtkSmartPointer<vtkPolyData>::New();
                new_data->DeepCopy(poly_data);
Ozan Tonkal's avatar
Ozan Tonkal committed
1071

1072 1073 1074 1075
                // Transform the default coordinate frame
                vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
                transform->PreMultiply();
                vtkSmartPointer<vtkMatrix4x4> mat_trans = vtkSmartPointer<vtkMatrix4x4>::New();
1076
                mat_trans = vtkmatrix(path[i].matrix);
1077 1078 1079
                transform->SetMatrix(mat_trans);

                vtkSmartPointer<vtkTransformPolyDataFilter> filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
1080
#if VTK_MAJOR_VERSION <= 5
1081
                filter->SetInput(new_data);
1082
#else
1083
                filter->SetInputData(new_data);
1084
#endif
1085 1086
                filter->SetTransform(transform);
                filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
1087

1088 1089
                append_filter->AddInputConnection(filter->GetOutputPort());
            }
1090
        }
1091 1092
    };
}}}
1093

1094
cv::viz::WTrajectory::WTrajectory(InputArray _path, int display_mode, double scale, const Color &color)
1095
{
1096
    vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
1097

1098
    // Bitwise and with 3 in order to limit the domain to 2 bits
1099
    if (display_mode & WTrajectory::PATH)
1100
    {
1101 1102 1103
        Mat points = vtkTrajectorySource::ExtractPoints(_path);
        vtkSmartPointer<vtkPolyData> polydata = getPolyData(WPolyLine(points, color));
        appendFilter->AddInputConnection(polydata->GetProducerPort());
1104
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
1105

1106 1107
    vtkSmartPointer<vtkTensorGlyph> tensor_glyph;
    if (display_mode & WTrajectory::FRAMES)
1108
    {
1109 1110
        vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
        source->SetTrajectory(_path);
Ozan Tonkal's avatar
Ozan Tonkal committed
1111

1112 1113 1114 1115 1116 1117 1118 1119 1120
        vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCoordinateSystem(scale));

        tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
        tensor_glyph->SetInputConnection(source->GetOutputPort());
        tensor_glyph->SetSourceConnection(glyph->GetProducerPort());
        tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
        tensor_glyph->ThreeGlyphsOff();
        tensor_glyph->SymmetricOff();
        tensor_glyph->ColorGlyphsOff();
Ozan Tonkal's avatar
Ozan Tonkal committed
1121

1122
        appendFilter->AddInputConnection(tensor_glyph->GetOutputPort());
1123
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
1124

1125
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1126
    VtkUtils::SetInputData(mapper, appendFilter->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
1127
    mapper->SetScalarModeToUsePointData();
1128
    mapper->SetScalarRange(0, 255);
Ozan Tonkal's avatar
Ozan Tonkal committed
1129

1130 1131
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1132

1133 1134 1135
    WidgetAccessor::setProp(*this, actor);
}

1136 1137 1138 1139 1140 1141 1142 1143 1144
template<> cv::viz::WTrajectory cv::viz::Widget::cast<cv::viz::WTrajectory>()
{
    Widget3D widget = this->cast<Widget3D>();
    return static_cast<WTrajectory&>(widget);
}

///////////////////////////////////////////////////////////////////////////////////////////////
/// WTrajectoryFrustums widget implementation

1145
cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(const std::vector<Affine3d> &path, const Matx33d &K, double scale, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
1146
{
1147
    vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
1148 1149 1150 1151
    double f_x = K(0,0);
    double f_y = K(1,1);
    double c_y = K(1,2);
    double aspect_ratio = f_y / f_x;
1152
    // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
1153
    double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI;
Ozan Tonkal's avatar
Ozan Tonkal committed
1154

1155
    camera->SetViewAngle(fovy);
1156 1157 1158
    camera->SetPosition(0.0, 0.0, 0.0);
    camera->SetViewUp(0.0, 1.0, 0.0);
    camera->SetFocalPoint(0.0, 0.0, 1.0);
1159
    camera->SetClippingRange(0.01, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
1160

1161 1162
    double planesArray[24];
    camera->GetFrustumPlanes(aspect_ratio, planesArray);
Ozan Tonkal's avatar
Ozan Tonkal committed
1163

1164 1165
    vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
    planes->SetFrustumPlanes(planesArray);
Ozan Tonkal's avatar
Ozan Tonkal committed
1166

1167 1168 1169 1170 1171 1172
    vtkSmartPointer<vtkFrustumSource> frustumSource = vtkSmartPointer<vtkFrustumSource>::New();
    frustumSource->SetPlanes(planes);
    frustumSource->Update();

    // Extract the edges
    vtkSmartPointer<vtkExtractEdges> filter = vtkSmartPointer<vtkExtractEdges>::New();
1173
    filter->SetInputConnection(frustumSource->GetOutputPort());
1174
    filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
1175

1176
    vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
1177
    TrajectoryUtils::applyPath(filter->GetOutput(), appendFilter, path);
Ozan Tonkal's avatar
Ozan Tonkal committed
1178

1179
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1180
    mapper->SetInputConnection(appendFilter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
1181

1182 1183
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1184

1185 1186 1187 1188
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

1189
cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(const std::vector<Affine3d> &path, const Vec2d &fov, double scale, const Color &color)
1190 1191
{
    vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
1192

1193
    camera->SetViewAngle(fov[1] * 180 / CV_PI); // Vertical field of view
1194 1195 1196
    camera->SetPosition(0.0, 0.0, 0.0);
    camera->SetViewUp(0.0, 1.0, 0.0);
    camera->SetFocalPoint(0.0, 0.0, 1.0);
1197
    camera->SetClippingRange(0.01, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
1198

1199
    double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5);
Ozan Tonkal's avatar
Ozan Tonkal committed
1200

1201 1202
    double planesArray[24];
    camera->GetFrustumPlanes(aspect_ratio, planesArray);
Ozan Tonkal's avatar
Ozan Tonkal committed
1203

1204 1205
    vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
    planes->SetFrustumPlanes(planesArray);
Ozan Tonkal's avatar
Ozan Tonkal committed
1206

1207 1208 1209 1210 1211 1212
    vtkSmartPointer<vtkFrustumSource> frustumSource = vtkSmartPointer<vtkFrustumSource>::New();
    frustumSource->SetPlanes(planes);
    frustumSource->Update();

    // Extract the edges
    vtkSmartPointer<vtkExtractEdges> filter = vtkSmartPointer<vtkExtractEdges>::New();
1213
    filter->SetInputConnection(frustumSource->GetOutputPort());
1214
    filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
1215

1216
    vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
1217
    TrajectoryUtils::applyPath(filter->GetOutput(), appendFilter, path);
Ozan Tonkal's avatar
Ozan Tonkal committed
1218

1219
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1220
    mapper->SetInputConnection(appendFilter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
1221

1222 1223
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1224

1225 1226 1227
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}
1228

1229
template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast<cv::viz::WTrajectoryFrustums>()
1230 1231
{
    Widget3D widget = this->cast<Widget3D>();
1232
    return static_cast<WTrajectoryFrustums&>(widget);
1233 1234 1235
}

///////////////////////////////////////////////////////////////////////////////////////////////
1236
/// WTrajectorySpheres widget implementation
1237

1238
cv::viz::WTrajectorySpheres::WTrajectorySpheres(const std::vector<Affine3d> &path, double line_length, double init_sphere_radius, double sphere_radius,
1239 1240 1241 1242
                                                          const Color &line_color, const Color &sphere_color)
{
    vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
    vtkIdType nr_poses = path.size();
Ozan Tonkal's avatar
Ozan Tonkal committed
1243

1244 1245 1246 1247
    // Create color arrays
    vtkSmartPointer<vtkUnsignedCharArray> line_scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
    line_scalars->SetNumberOfComponents(3);
    line_scalars->InsertNextTuple3(line_color[2], line_color[1], line_color[0]);
Ozan Tonkal's avatar
Ozan Tonkal committed
1248

1249
    // Create color array for sphere
Anatoly Baksheev's avatar
Anatoly Baksheev committed
1250
    vtkSmartPointer<vtkSphereSource> dummy_sphere = vtkSmartPointer<vtkSphereSource>::New();
1251 1252 1253 1254
    // Create the array for big sphere
    dummy_sphere->SetRadius(init_sphere_radius);
    dummy_sphere->Update();
    vtkIdType nr_points = dummy_sphere->GetOutput()->GetNumberOfCells();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
1255 1256
    vtkSmartPointer<vtkUnsignedCharArray> sphere_scalars_init = VtkUtils::FillScalars(nr_points, sphere_color);

1257 1258 1259 1260
    // Create the array for small sphere
    dummy_sphere->SetRadius(sphere_radius);
    dummy_sphere->Update();
    nr_points = dummy_sphere->GetOutput()->GetNumberOfCells();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
1261 1262
    vtkSmartPointer<vtkUnsignedCharArray> sphere_scalars = VtkUtils::FillScalars(nr_points, sphere_color);

Ozan Tonkal's avatar
Ozan Tonkal committed
1263

1264 1265 1266
    for (vtkIdType i = 0; i < nr_poses; ++i)
    {
        Point3f new_pos = path[i].translation();
Ozan Tonkal's avatar
Ozan Tonkal committed
1267

1268
        vtkSmartPointer<vtkSphereSource> sphere_source = vtkSmartPointer<vtkSphereSource>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
1269
        sphere_source->SetCenter(new_pos.x, new_pos.y, new_pos.z);
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
        if (i == 0)
        {
            sphere_source->SetRadius(init_sphere_radius);
            sphere_source->Update();
            sphere_source->GetOutput()->GetCellData()->SetScalars(sphere_scalars_init);
            appendFilter->AddInputConnection(sphere_source->GetOutputPort());
            continue;
        }
        else
        {
            sphere_source->SetRadius(sphere_radius);
            sphere_source->Update();
            sphere_source->GetOutput()->GetCellData()->SetScalars(sphere_scalars);
            appendFilter->AddInputConnection(sphere_source->GetOutputPort());
        }
Ozan Tonkal's avatar
Ozan Tonkal committed
1285 1286


1287 1288
        Affine3d relativeAffine = path[i].inv() * path[i-1];
        Vec3d v = path[i].rotation() * relativeAffine.translation();
1289
        v = normalize(v) * line_length;
Ozan Tonkal's avatar
Ozan Tonkal committed
1290

1291 1292 1293 1294 1295
        vtkSmartPointer<vtkLineSource> line_source = vtkSmartPointer<vtkLineSource>::New();
        line_source->SetPoint1(new_pos.x + v[0], new_pos.y + v[1], new_pos.z + v[2]);
        line_source->SetPoint2(new_pos.x, new_pos.y, new_pos.z);
        line_source->Update();
        line_source->GetOutput()->GetCellData()->SetScalars(line_scalars);
Ozan Tonkal's avatar
Ozan Tonkal committed
1296

1297 1298
        appendFilter->AddInputConnection(line_source->GetOutputPort());
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
1299

1300 1301
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetScalarModeToUseCellData();
1302
    mapper->SetInputConnection(appendFilter->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
1303

1304 1305
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1306

1307 1308 1309
    WidgetAccessor::setProp(*this, actor);
}

1310
template<> cv::viz::WTrajectorySpheres cv::viz::Widget::cast<cv::viz::WTrajectorySpheres>()
1311 1312
{
    Widget3D widget = this->cast<Widget3D>();
1313
    return static_cast<WTrajectorySpheres&>(widget);
Ozan Tonkal's avatar
Ozan Tonkal committed
1314
}