FreeCAD

Форк
0
/
ManualAlignment.cpp 
1338 строк · 43.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25
#ifndef _PreComp_
26
# include <QAction>
27
# include <QApplication>
28
# include <QLabel>
29
# include <QMenu>
30
# include <QMessageBox>
31
# include <QPainter>
32
# include <QSplitter>
33
# include <QTimer>
34
# include <QVBoxLayout>
35
# include <Inventor/SoPickedPoint.h>
36
# include <Inventor/actions/SoSearchAction.h>
37
# include <Inventor/events/SoMouseButtonEvent.h>
38
# include <Inventor/fields/SoSFImage.h>
39
# include <Inventor/nodes/SoImage.h>
40
# include <Inventor/nodes/SoMaterial.h>
41
# include <Inventor/nodes/SoOrthographicCamera.h>
42
# include <Inventor/nodes/SoSeparator.h>
43
# include <Inventor/nodes/SoTranslation.h>
44
# include <Inventor/sensors/SoNodeSensor.h>
45
#endif
46

47
#include <App/Document.h>
48
#include <App/GeoFeature.h>
49
#include <Gui/Application.h>
50
#include <Gui/Document.h>
51
#include <Gui/MainWindow.h>
52
#include <Gui/Selection.h>
53
#include <Gui/SplitView3DInventor.h>
54
#include <Gui/View3DInventorViewer.h>
55
#include <Gui/ViewProviderGeometryObject.h>
56
#include <Gui/WaitCursor.h>
57

58
#include "ManualAlignment.h"
59
#include "BitmapFactory.h"
60
#include "SoAxisCrossKit.h"
61
#include "Tools.h"
62

63

64
using namespace Gui;
65
namespace sp = std::placeholders;
66

67
AlignmentGroup::AlignmentGroup() = default;
68

69
AlignmentGroup::~AlignmentGroup() = default;
70

71
void AlignmentGroup::addView(App::DocumentObject* pView)
72
{
73
    if (pView) {
74
        App::Document* rDoc = pView->getDocument();
75
        Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc);
76
        auto pProvider = static_cast<Gui::ViewProviderDocumentObject*>
77
            (pDoc->getViewProvider(pView));
78
        this->_views.push_back(pProvider);
79
    }
80
}
81

82
std::vector<App::DocumentObject*> AlignmentGroup::getViews() const
83
{
84
    std::vector<App::DocumentObject*> views;
85

86
    std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
87
    for (it = this->_views.begin(); it != this->_views.end(); ++it) {
88
        App::DocumentObject* pView = (*it)->getObject();
89
        views.push_back(pView);
90
    }
91

92
    return views;
93
}
94

95
bool AlignmentGroup::hasView(Gui::ViewProviderDocumentObject* pView) const
96
{
97
    std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
98
    for (it = this->_views.begin(); it != this->_views.end(); ++it) {
99
        if (*it == pView)
100
            return true;
101
    }
102

103
    return false;
104
}
105

106
void AlignmentGroup::removeView(Gui::ViewProviderDocumentObject* pView)
107
{
108
    std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
109
    for (it = this->_views.begin(); it != this->_views.end(); ++it) {
110
        if (*it == pView) {
111
            this->_views.erase(it);
112
            break;
113
        }
114
    }
115
}
116

117
void AlignmentGroup::addToViewer(Gui::View3DInventorViewer* viewer) const
118
{
119
    std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
120
    for (it = this->_views.begin(); it != this->_views.end(); ++it)
121
        viewer->addViewProvider(*it);
122

123
    viewer->viewAll();
124
}
125

126
void AlignmentGroup::removeFromViewer(Gui::View3DInventorViewer* viewer) const
127
{
128
    std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
129
    for (it = this->_views.begin(); it != this->_views.end(); ++it)
130
        viewer->removeViewProvider(*it);
131
}
132

133
void AlignmentGroup::setRandomColor()
134
{
135
    std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
136
    for (it = this->_views.begin(); it != this->_views.end(); ++it) {
137
        float r = /*(float)rand()/(float)RAND_MAX*/0.0f;
138
        float g = (float)rand()/(float)RAND_MAX;
139
        float b = (float)rand()/(float)RAND_MAX;
140
        if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) {
141
            SoSearchAction searchAction;
142
            searchAction.setType(SoMaterial::getClassTypeId());
143
            searchAction.setInterest(SoSearchAction::FIRST);
144
            searchAction.apply((*it)->getRoot());
145
            SoPath* selectionPath = searchAction.getPath();
146

147
            if (selectionPath) {
148
                auto material = static_cast<SoMaterial*>(selectionPath->getTail());
149
                material->diffuseColor.setValue(r, g, b);
150
            }
151
        }
152
    }
153
}
154

155
Gui::Document* AlignmentGroup::getDocument() const
156
{
157
    if (this->_views.empty())
158
        return nullptr;
159
    App::DocumentObject* pView = this->_views[0]->getObject();
160
    if (pView) {
161
        App::Document* rDoc = pView->getDocument();
162
        Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc);
163
        return pDoc;
164
    }
165

166
    return nullptr;
167
}
168

169
void AlignmentGroup::addPoint(const PickedPoint& pnt)
170
{
171
    this->_pickedPoints.push_back(pnt);
172
}
173

174
void AlignmentGroup::removeLastPoint()
175
{
176
    this->_pickedPoints.pop_back();
177
}
178

179
int AlignmentGroup::countPoints() const
180
{
181
    return this->_pickedPoints.size();
182
}
183

184
const std::vector<PickedPoint>& AlignmentGroup::getPoints() const
185
{
186
    return this->_pickedPoints;
187
}
188

189
void AlignmentGroup::clearPoints()
190
{
191
    this->_pickedPoints.clear();
192
}
193

194
void AlignmentGroup::setAlignable(bool align)
195
{
196
    std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
197
    for (it = this->_views.begin(); it != this->_views.end(); ++it) {
198
        auto pAlignMode = dynamic_cast<App::PropertyBool*>((*it)->getPropertyByName("AlignMode"));
199
        if (pAlignMode) {
200
            pAlignMode->setValue(align);
201
        }
202
        // leaving alignment mode
203
        else if (!align){
204
            auto pAppearance =
205
                 dynamic_cast<App::PropertyMaterial*>((*it)->getPropertyByName("ShapeAppearance"));
206
             if (pAppearance) {
207
                 pAppearance->touch();  // resets to color defined by property
208
             }
209
        }
210
    }
211
}
212

213
void AlignmentGroup::moveTo(AlignmentGroup& that)
214
{
215
    std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
216
    for (it = this->_views.begin(); it != this->_views.end(); ++it)
217
        that._views.push_back(*it);
218

219
    this->_views.clear();
220
}
221

222
void AlignmentGroup::clear()
223
{
224
    this->_views.clear();
225
    this->_pickedPoints.clear();
226
}
227

228
bool AlignmentGroup::isEmpty() const
229
{
230
    return this->_views.empty();
231
}
232

233
int AlignmentGroup::count() const
234
{
235
    return this->_views.size();
236
}
237

238
Base::BoundBox3d AlignmentGroup::getBoundingBox() const
239
{
240
    Base::BoundBox3d box;
241
    std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
242
    for (it = this->_views.begin(); it != this->_views.end(); ++it) {
243
        if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) {
244
            auto geo = static_cast<App::GeoFeature*>((*it)->getObject());
245
            const App::PropertyComplexGeoData* prop = geo->getPropertyOfGeometry();
246
            if (prop)
247
                box.Add(prop->getBoundingBox());
248
        }
249
    }
250
    return box;
251
}
252

253
// ------------------------------------------------------------------
254

255
MovableGroup::MovableGroup() = default;
256

257
MovableGroup::~MovableGroup() = default;
258

259
// ------------------------------------------------------------------
260

261
FixedGroup::FixedGroup() = default;
262

263
FixedGroup::~FixedGroup() = default;
264

265
// ------------------------------------------------------------------
266

267
MovableGroupModel::MovableGroupModel() = default;
268

269
MovableGroupModel::~MovableGroupModel() = default;
270

271
void MovableGroupModel::addGroup(const MovableGroup& grp)
272
{
273
    this->_groups.push_back(grp);
274
}
275

276
void MovableGroupModel::addGroups(const std::map<int, MovableGroup>& grps)
277
{
278
    for (const auto & grp : grps)
279
        this->_groups.push_back(grp.second);
280
}
281

282
void MovableGroupModel::removeActiveGroup()
283
{
284
    this->_groups.erase(this->_groups.begin());
285
}
286

287
MovableGroup& MovableGroupModel::activeGroup()
288
{
289
    // Make sure that the array is not empty
290
    if (this->_groups.empty())
291
        throw Base::RuntimeError("Empty group");
292
    return *(this->_groups.begin());
293
}
294

295
const MovableGroup& MovableGroupModel::activeGroup() const
296
{
297
    // Make sure that the array is not empty
298
    if (this->_groups.empty())
299
        throw Base::RuntimeError("Empty group");
300
    return this->_groups.front();
301
}
302

303
void MovableGroupModel::continueAlignment()
304
{
305
    if (!isEmpty())
306
        removeActiveGroup();
307
}
308

309
void MovableGroupModel::clear()
310
{
311
    this->_groups.clear();
312
}
313

314
bool MovableGroupModel::isEmpty() const
315
{
316
    return this->_groups.empty();
317
}
318

319
int MovableGroupModel::count() const
320
{
321
    return this->_groups.size();
322
}
323

324
const MovableGroup& MovableGroupModel::getGroup(int i) const
325
{
326
    if (i >= count())
327
        throw Base::IndexError("Index out of range");
328
    return this->_groups[i];
329
}
330

331
Base::BoundBox3d MovableGroupModel::getBoundingBox() const
332
{
333
    Base::BoundBox3d box;
334
    std::vector<MovableGroup>::const_iterator it;
335
    for (it = this->_groups.begin(); it != this->_groups.end(); ++it) {
336
        box.Add(it->getBoundingBox());
337
    }
338
    return box;
339
}
340

341
// ------------------------------------------------------------------
342

343
namespace Gui {
344
class AlignmentView : public Gui::AbstractSplitView
345
{
346
public:
347
    QLabel* myLabel;
348

349
    AlignmentView(Gui::Document* pcDocument, QWidget* parent, Qt::WindowFlags wflags=Qt::WindowFlags())
350
        : AbstractSplitView(pcDocument, parent, wflags)
351
    {
352
        //anti-aliasing settings
353
        bool smoothing = false;
354
        bool glformat = false;
355
        int samples = View3DInventorViewer::getNumSamples();
356
        QtGLFormat f;
357

358
        if (samples > 1) {
359
            glformat = true;
360
            f.setSamples(samples);
361
        }
362
        else if (samples > 0) {
363
            smoothing = true;
364
        }
365

366
        QSplitter* mainSplitter=nullptr;
367
        mainSplitter = new QSplitter(Qt::Horizontal, this);
368
        if (glformat) {
369
            _viewer.push_back(new View3DInventorViewer(f, mainSplitter));
370
            _viewer.push_back(new View3DInventorViewer(f, mainSplitter));
371
        }
372
        else {
373
            _viewer.push_back(new View3DInventorViewer(mainSplitter));
374
            _viewer.push_back(new View3DInventorViewer(mainSplitter));
375
        }
376
        setDocumentOfViewers(pcDocument);
377

378
        auto vbox = new QFrame(this);
379
        auto layout = new QVBoxLayout();
380
        layout->setContentsMargins(0, 0, 0, 0);
381
        layout->setSpacing(0);
382
        vbox->setLayout(layout);
383

384
        myLabel = new QLabel(this);
385
        myLabel->setAutoFillBackground(true);
386
        QPalette pal = myLabel->palette();
387
        pal.setColor(QPalette::Window, Qt::darkGray);
388
        pal.setColor(QPalette::WindowText, Qt::white);
389
        myLabel->setPalette(pal);
390
        mainSplitter->setPalette(pal);
391
        myLabel->setAlignment(Qt::AlignCenter);
392
        myLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
393
        QFont font = myLabel->font();
394
        font.setPointSize(14);
395
        myLabel->setFont(font);
396
        layout->addWidget(myLabel);
397
        layout->addWidget(mainSplitter);
398

399
        vbox->show();
400
        setCentralWidget(vbox);
401

402
        // apply the user settings
403
        setupSettings();
404

405
        if (smoothing) {
406
            for (const auto & i : _viewer)
407
                i->getSoRenderManager()->getGLRenderAction()->setSmoothing(true);
408
        }
409

410
        static_cast<SoGroup*>(getViewer(0)->getSoRenderManager()->getSceneGraph())->
411
            addChild(setupHeadUpDisplay(tr("Movable object")));
412
        static_cast<SoGroup*>(getViewer(1)->getSoRenderManager()->getSceneGraph())->
413
            addChild(setupHeadUpDisplay(tr("Fixed object")));
414
    }
415
    ~AlignmentView() override = default;
416
    PyObject* getPyObject() override
417
    {
418
        Py_Return;
419
    }
420
    bool canClose() override
421
    {
422
        return false;
423
    }
424
    SoNode* setupHeadUpDisplay(const QString& text) const
425
    {
426
        auto hudRoot = new SoSeparator;
427
        hudRoot->ref();
428

429
        auto hudCam = new SoOrthographicCamera();
430
        hudCam->viewportMapping = SoCamera::LEAVE_ALONE;
431

432
        // Set the position in the window.
433
        // [0, 0] is in the center of the screen.
434
        //
435
        auto hudTrans = new SoTranslation;
436
        hudTrans->translation.setValue(-0.95f, -0.95f, 0.0f);
437

438
        QFont font = this->font();
439
        font.setPointSize(24);
440
        QFontMetrics fm(font);
441

442
        QColor front;
443
        front.setRgbF(0.8f, 0.8f, 0.8f);
444

445
        int w = QtTools::horizontalAdvance(fm, text);
446
        int h = fm.height();
447

448
        QImage image(w,h,QImage::Format_ARGB32_Premultiplied);
449
        image.fill(0x00000000);
450
        QPainter painter(&image);
451
        painter.setRenderHint(QPainter::Antialiasing);
452
        painter.setPen(front);
453
        painter.setFont(font);
454
        painter.drawText(0,0,w,h,Qt::AlignLeft,text);
455
        painter.end();
456
        SoSFImage sfimage;
457
        Gui::BitmapFactory().convert(image, sfimage);
458
        auto hudImage = new SoImage();
459
        hudImage->image = sfimage;
460

461
        // Assemble the parts...
462
        //
463
        hudRoot->addChild(hudCam);
464
        hudRoot->addChild(hudTrans);
465
        hudRoot->addChild(hudImage);
466

467
        return hudRoot;
468
    }
469
};
470
}
471

472
class ManualAlignment::Private {
473
public:
474
    SoSeparator * picksepLeft;
475
    SoSeparator * picksepRight;
476
    SoNodeSensor* sensorCam1{nullptr};
477
    SoNodeSensor* sensorCam2{nullptr};
478
    SbRotation rot_cam1, rot_cam2;
479
    SbVec3f pos_cam1, pos_cam2;
480

481
    Private()
482
    {
483
        // left view
484
        picksepLeft = new SoSeparator;
485
        picksepLeft->ref();
486
        // right view
487
        picksepRight = new SoSeparator;
488
        picksepRight->ref();
489
    }
490
    ~Private()
491
    {
492
        picksepLeft->unref();
493
        picksepRight->unref();
494
        delete sensorCam1;
495
        delete sensorCam2;
496
    }
497

498
    static
499
    void  reorientCamera(SoCamera * cam, const SbRotation & rot)
500
    {
501
        if (!cam)
502
            return;
503

504
        // Find global coordinates of focal point.
505
        SbVec3f direction;
506
        cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
507
        SbVec3f focalpoint = cam->position.getValue() +
508
                             cam->focalDistance.getValue() * direction;
509

510
        // Set new orientation value by accumulating the new rotation.
511
        cam->orientation = rot * cam->orientation.getValue();
512

513
        // Reposition camera so we are still pointing at the same old focal point.
514
        cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
515
        cam->position = focalpoint - cam->focalDistance.getValue() * direction;
516
    }
517

518
    static
519
    void copyCameraSettings(SoCamera* cam1, SbRotation& rot_cam1, SbVec3f& pos_cam1,
520
                            SoCamera* cam2, SbRotation& rot_cam2, SbVec3f& pos_cam2)
521
    {
522
        Q_UNUSED(pos_cam2);
523

524
        // recompute the diff we have applied to the camera's orientation
525
        SbRotation rot = cam1->orientation.getValue();
526
        SbRotation dif = rot * rot_cam1.inverse();
527
        rot_cam1 = rot;
528

529
        // copy the values
530
        cam2->enableNotify(false);
531
        cam2->nearDistance = cam1->nearDistance;
532
        cam2->farDistance = cam1->farDistance;
533
        cam2->focalDistance = cam1->focalDistance;
534
        reorientCamera(cam2,dif);
535
        rot_cam2 = cam2->orientation.getValue();
536

537
        // reverse engineer the translation part in wc
538
        SbVec3f pos = cam1->position.getValue();
539
        SbVec3f difpos = pos - pos_cam1;
540
        pos_cam1 = pos;
541
        // the translation in pixel coords
542
        cam1->orientation.getValue().inverse().multVec(difpos,difpos);
543
        // the translation again in wc for the second camera
544
        cam2->orientation.getValue().multVec(difpos,difpos);
545
        cam2->position.setValue(cam2->position.getValue()+difpos);
546

547
        if (cam1->getTypeId() == cam2->getTypeId()) {
548
            if (cam1->getTypeId() == SoOrthographicCamera::getClassTypeId())
549
                static_cast<SoOrthographicCamera*>(cam2)->height =
550
                static_cast<SoOrthographicCamera*>(cam1)->height;
551
        }
552

553
        cam2->enableNotify(true);
554
    }
555
    static
556
    void syncCameraCB(void * data, SoSensor * s)
557
    {
558
        auto self = static_cast<ManualAlignment*>(data);
559
        if (!self->myViewer)
560
            return; // already destroyed
561
        SoCamera* cam1 = self->myViewer->getViewer(0)->getSoRenderManager()->getCamera();
562
        SoCamera* cam2 = self->myViewer->getViewer(1)->getSoRenderManager()->getCamera();
563
        if (!cam1 || !cam2)
564
            return; // missing camera
565
        auto sensor = static_cast<SoNodeSensor*>(s);
566
        SoNode* node = sensor->getAttachedNode();
567
        if (node && node->getTypeId().isDerivedFrom(SoCamera::getClassTypeId())) {
568
            if (node == cam1) {
569
                Private::copyCameraSettings(cam1, self->d->rot_cam1, self->d->pos_cam1,
570
                                   cam2, self->d->rot_cam2, self->d->pos_cam2);
571
                self->myViewer->getViewer(1)->redraw();
572
            }
573
            else if (node == cam2) {
574
                Private::copyCameraSettings(cam2, self->d->rot_cam2, self->d->pos_cam2,
575
                                   cam1, self->d->rot_cam1, self->d->pos_cam1);
576
                self->myViewer->getViewer(0)->redraw();
577
            }
578
        }
579
    }
580

581
    static Base::Placement
582
    transformation2x2(const Base::Vector3d& plane1_base,
583
                      const Base::Vector3d& plane1_xaxis,
584
                      const Base::Vector3d& plane2_base,
585
                      const Base::Vector3d& plane2_xaxis)
586
    {
587
        // the transformation is:
588
        // * move from plane1_base to plane2_base
589
        // * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point
590
        Base::Rotation rot(plane1_xaxis, plane2_xaxis);
591

592
        Base::Vector3d pln_base;
593
        rot.multVec(plane1_base,pln_base);
594
        Base::Vector3d dif = plane2_base - pln_base;
595
        return {dif, rot};
596
    }
597

598
    static Base::Placement
599
    transformation3x3(const Base::Vector3d& plane1_base,
600
                      const Base::Vector3d& plane1_zaxis,
601
                      const Base::Vector3d& plane1_xaxis,
602
                      const Base::Vector3d& plane2_base,
603
                      const Base::Vector3d& plane2_zaxis,
604
                      const Base::Vector3d& plane2_xaxis)
605
    {
606
        // the transformation is:
607
        // * move from plane1_base to plane2_base
608
        // * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point
609
        Base::Rotation rot(plane1_zaxis, plane2_zaxis);
610

611
        // first transformation to align the plane normals and base points
612
        Base::Vector3d dif1 = plane1_base;
613
        rot.multVec(dif1,dif1);
614
        dif1 = plane2_base - dif1;
615
        Base::Placement plm1(dif1, rot);
616

617
        // second transformation to align the planes' x axes
618
        Base::Vector3d pln_xaxis;
619
        rot.multVec(plane1_xaxis,pln_xaxis);
620
        Base::Rotation rot2(pln_xaxis, plane2_xaxis);
621
        Base::Vector3d dif2 = plane2_base;
622
        rot2.multVec(dif2,dif2);
623
        dif2 = plane2_base - dif2;
624
        Base::Placement plm2(dif2, rot2);
625
        plm2 = plm2 * plm1;
626
        return plm2;
627
    }
628
};
629

630
/* TRANSLATOR Gui::ManualAlignment */
631

632
ManualAlignment* ManualAlignment::_instance = nullptr;
633

634
/**
635
 * Construction.
636
 */
637
ManualAlignment::ManualAlignment()
638
  : myViewer(nullptr), myDocument(nullptr), myPickPoints(3), d(new Private)
639
{
640
    //NOLINTBEGIN
641
    // connect with the application's signal for deletion of documents
642
    this->connectApplicationDeletedDocument = Gui::Application::Instance->signalDeleteDocument
643
        .connect(std::bind(&ManualAlignment::slotDeletedDocument, this, sp::_1));
644
    //NOLINTEND
645

646
    // setup sensor connection
647
    d->sensorCam1 = new SoNodeSensor(Private::syncCameraCB, this);
648
    d->sensorCam2 = new SoNodeSensor(Private::syncCameraCB, this);
649
}
650

651
/**
652
 * Destruction.
653
 */
654
ManualAlignment::~ManualAlignment()
655
{
656
    this->connectDocumentDeletedObject.disconnect();
657
    this->connectApplicationDeletedDocument.disconnect();
658
    closeViewer();
659
    delete d;
660
    _instance = nullptr;
661
}
662

663
/**
664
 * Creates the one and only instance of this class.
665
 */
666
ManualAlignment* ManualAlignment::instance()
667
{
668
    // not initialized?
669
    if (!_instance)
670
        _instance = new ManualAlignment();
671
    return _instance;
672
}
673

674
/**
675
 * Destructs the one and only instance of this class.
676
 */
677
void ManualAlignment::destruct()
678
{
679
    if (_instance) {
680
        ManualAlignment* tmp = _instance;
681
        _instance = nullptr;
682
        delete tmp;
683
    }
684
}
685

686
/**
687
 * Checks whether the one instance exists.
688
 */
689
bool ManualAlignment::hasInstance()
690
{
691
    return _instance != nullptr;
692
}
693

694
void ManualAlignment::setMinPoints(int minPoints)
695
{
696
    if ((minPoints > 0) && (minPoints <= 3))
697
        myPickPoints = minPoints;
698
}
699

700
void ManualAlignment::setFixedGroup(const FixedGroup& fixed)
701
{
702
    this->myFixedGroup = fixed;
703
    this->myDocument = fixed.getDocument();
704
}
705

706
void ManualAlignment::setModel(const MovableGroupModel& model)
707
{
708
    this->myAlignModel = model;
709
}
710

711
void ManualAlignment::clearAll()
712
{
713
    myFixedGroup.clear();
714
    myAlignModel.clear();
715
    myDocument = nullptr;
716
}
717

718
void ManualAlignment::setViewingDirections(const Base::Vector3d& view1, const Base::Vector3d& up1,
719
                                           const Base::Vector3d& view2, const Base::Vector3d& up2)
720
{
721
    if (myViewer.isNull())
722
        return;
723

724
    {
725
        SbVec3f vz(-view1.x, -view1.y, -view1.z);
726
        vz.normalize();
727
        SbVec3f vy(up1.x, up1.y, up1.z);
728
        vy.normalize();
729
        SbVec3f vx = vy.cross(vz);
730
        vy = vz.cross(vx);
731

732
        SbMatrix rot = SbMatrix::identity();
733
        rot[0][0] = vx[0];
734
        rot[0][1] = vx[1];
735
        rot[0][2] = vx[2];
736

737
        rot[1][0] = vy[0];
738
        rot[1][1] = vy[1];
739
        rot[1][2] = vy[2];
740

741
        rot[2][0] = vz[0];
742
        rot[2][1] = vz[1];
743
        rot[2][2] = vz[2];
744

745
        SbRotation total(rot);
746
        myViewer->getViewer(0)->getSoRenderManager()->getCamera()->orientation.setValue(total);
747
        myViewer->getViewer(0)->viewAll();
748
    }
749

750
    {
751
        SbVec3f vz(-view2.x, -view2.y, -view2.z);
752
        vz.normalize();
753
        SbVec3f vy(up2.x, up2.y, up2.z);
754
        vy.normalize();
755
        SbVec3f vx = vy.cross(vz);
756
        vy = vz.cross(vx);
757

758
        SbMatrix rot = SbMatrix::identity();
759
        rot[0][0] = vx[0];
760
        rot[0][1] = vx[1];
761
        rot[0][2] = vx[2];
762

763
        rot[1][0] = vy[0];
764
        rot[1][1] = vy[1];
765
        rot[1][2] = vy[2];
766

767
        rot[2][0] = vz[0];
768
        rot[2][1] = vz[1];
769
        rot[2][2] = vz[2];
770

771
        SbRotation total(rot);
772
        myViewer->getViewer(1)->getSoRenderManager()->getCamera()->orientation.setValue(total);
773
        myViewer->getViewer(1)->viewAll();
774
    }
775
}
776

777
/**
778
 * Performs the alignment for the specified aligned and non-aligned views specified by setModel() and setFixedGroup().
779
 */
780
void ManualAlignment::startAlignment(Base::Type mousemodel)
781
{
782
    // allow only one alignment at a time
783
    if (!myViewer.isNull()) {
784
        QMessageBox::warning(qApp->activeWindow(), tr("Manual alignment"), tr("The alignment is already in progress."));
785
        return;
786
    }
787

788
    myTransform = Base::Placement();
789

790
    if (myFixedGroup.isEmpty())
791
        return;
792
    if (myAlignModel.isEmpty())
793
        return;
794

795
    // create a split window for picking the points
796
    myViewer = new AlignmentView(myDocument,Gui::getMainWindow());
797
    myViewer->setWindowTitle(tr("Alignment[*]"));
798
    myViewer->setWindowIcon(QApplication::windowIcon());
799
    myViewer->resize(400, 300);
800
    Gui::getMainWindow()->addWindow(myViewer);
801
    myViewer->showMaximized();
802
    int n = this->myPickPoints;
803
    QString msg = n == 1
804
        ? tr("Please, select at least one point in the left and the right view")
805
        : tr("Please, select at least %1 points in the left and the right view").arg(n);
806
    myViewer->myLabel->setText(msg);
807

808
    connect(myViewer, &QObject::destroyed, this, &ManualAlignment::reset);
809

810
    // show all aligned views in the 2nd view
811
    myFixedGroup.addToViewer(myViewer->getViewer(1));
812
    myFixedGroup.setAlignable(true);
813

814
    // set picked points root
815
    SoNode* node1 = myViewer->getViewer(0)->getSceneGraph();
816
    if (node1->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){
817
        ((SoGroup*)node1)->addChild(d->picksepLeft);
818
    }
819
    SoNode* node2 = myViewer->getViewer(1)->getSceneGraph();
820
    if (node2->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){
821
        ((SoGroup*)node2)->addChild(d->picksepRight);
822
    }
823

824
    myViewer->getViewer(0)->setEditing(true);
825
    myViewer->getViewer(0)->addEventCallback(SoMouseButtonEvent::getClassTypeId(),
826
        ManualAlignment::probePickedCallback);
827
    myViewer->getViewer(1)->setEditing(true);
828
    myViewer->getViewer(1)->addEventCallback(SoMouseButtonEvent::getClassTypeId(),
829
        ManualAlignment::probePickedCallback);
830
    // apply the mouse model
831
    myViewer->getViewer(0)->setNavigationType(mousemodel);
832
    myViewer->getViewer(1)->setNavigationType(mousemodel);
833

834
    // Connect to the document's signal as we want to be notified when something happens
835
    if (this->connectDocumentDeletedObject.connected())
836
        this->connectDocumentDeletedObject.disconnect();
837
    //NOLINTBEGIN
838
    this->connectDocumentDeletedObject = myDocument->signalDeletedObject.connect(std::bind
839
        (&ManualAlignment::slotDeletedObject, this, sp::_1));
840
    //NOLINTEND
841

842
    continueAlignment();
843
}
844

845
/**
846
 * If still one view needs to be aligned then it is shown in the first window. If all views are aligned the process will be terminated.
847
 */
848
void ManualAlignment::continueAlignment()
849
{
850
    myFixedGroup.clearPoints();
851
    coinRemoveAllChildren(d->picksepLeft);
852
    coinRemoveAllChildren(d->picksepRight);
853

854
    if (!myAlignModel.isEmpty()) {
855
        AlignmentGroup& grp = myAlignModel.activeGroup();
856
        grp.clearPoints();
857
        grp.addToViewer(myViewer->getViewer(0));
858
        grp.setAlignable(true);
859

860
        Gui::getMainWindow()->showMessage(tr("Please pick points in the left and right view"));
861

862
        myViewer->getViewer(0)->setEditingCursor(QCursor(Qt::PointingHandCursor));
863
        myViewer->getViewer(1)->setEditingCursor(QCursor(Qt::PointingHandCursor));
864
    }
865
    else {
866
        finish();
867
    }
868
}
869

870
void ManualAlignment::closeViewer()
871
{
872
    if (!myViewer)
873
        return;
874
    // Close the viewer
875
    if (myViewer->parentWidget())
876
        myViewer->parentWidget()->deleteLater();
877
    myViewer = nullptr;
878
}
879

880
/**
881
 * Make all views unpickable and resets internal data.
882
 */
883
void ManualAlignment::reset()
884
{
885
    if (!myAlignModel.isEmpty()) {
886
        myAlignModel.activeGroup().setAlignable(false);
887
        myAlignModel.activeGroup().clear();
888
        myAlignModel.clear();
889
    }
890

891
    myFixedGroup.setAlignable(false);
892
    myFixedGroup.clear();
893

894
    coinRemoveAllChildren(d->picksepLeft);
895
    coinRemoveAllChildren(d->picksepRight);
896

897
    if (myDocument) {
898
        this->connectDocumentDeletedObject.disconnect();
899
        myDocument = nullptr;
900
    }
901
}
902

903
/**
904
 * Terminates the process and closes the windows.
905
 */
906
void ManualAlignment::finish()
907
{
908
    if (myViewer.isNull())
909
        return;
910

911
    if (myDocument)
912
        myDocument->getDocument()->recompute();
913
    closeViewer();
914
    reset();
915

916
    Gui::getMainWindow()->showMessage(tr("The alignment has finished"));
917

918
    // If an event receiver has been defined send the manual alignment finished event to it
919
    Q_EMIT emitFinished();
920
}
921

922
/**
923
 * Cancels the process and closes the windows without performing an alignment.
924
 */
925
void ManualAlignment::cancel()
926
{
927
    if (myViewer.isNull())
928
        return;
929

930
    closeViewer();
931
    myTransform = Base::Placement();
932
    reset();
933

934
    Gui::getMainWindow()->showMessage(tr("The alignment has been canceled"));
935

936
    // If an event receiver has been defined send the manual alignment cancelled event to it
937
    Q_EMIT emitCanceled();
938
}
939

940
void ManualAlignment::align()
941
{
942
    // Now we can start the actual alignment
943
    if (myAlignModel.activeGroup().countPoints() < myPickPoints) {
944
        QMessageBox::warning(myViewer, tr("Manual alignment"),
945
                tr("Too few points picked in the left view."
946
                   " At least %1 points are needed.").arg(myPickPoints));
947
    }
948
    else if (myFixedGroup.countPoints() < myPickPoints) {
949
        QMessageBox::warning(myViewer, tr("Manual alignment"),
950
                tr("Too few points picked in the right view."
951
                  " At least %1 points are needed.").arg(myPickPoints));
952
    }
953
    else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) {
954
        QMessageBox::warning(myViewer, tr("Manual alignment"),
955
                tr("Different number of points picked in left and right view.\n"
956
                   "On the left view %1 points are picked,\n"
957
                   "on the right view %2 points are picked.")
958
                .arg(myAlignModel.activeGroup().countPoints())
959
                            .arg(myFixedGroup.countPoints()));
960
    }
961
    else {
962
        // do not allow to pick further points
963
        myAlignModel.activeGroup().removeFromViewer(myViewer->getViewer(0));
964
        myAlignModel.activeGroup().setAlignable(false);
965
        std::vector<App::DocumentObject*> pViews = myAlignModel.activeGroup().getViews();
966
        Gui::getMainWindow()->showMessage(tr("Try to align group of views"));
967

968
        // Compute alignment
969
        bool ok = computeAlignment(myAlignModel.activeGroup().getPoints(), myFixedGroup.getPoints());
970
        if (ok && myDocument) {
971
            // Align views
972
            myDocument->openCommand(QT_TRANSLATE_NOOP("Command", "Align"));
973
            for (const auto & pView : pViews)
974
                alignObject(pView);
975
            myDocument->commitCommand();
976

977
            // the alignment was successful so show it in the right view now
978
            //myAlignModel.activeGroup().setRandomColor();
979
            myAlignModel.activeGroup().setAlignable(true);
980
            myAlignModel.activeGroup().addToViewer(myViewer->getViewer(1));
981
            myAlignModel.activeGroup().moveTo(myFixedGroup);
982
            myAlignModel.continueAlignment();
983
        }
984
        else {
985
            // Inform user that alignment failed
986
            auto ret = QMessageBox::critical(myViewer, tr("Manual alignment"),
987
                tr("The alignment failed.\nHow do you want to proceed?"),
988
                QMessageBox::Retry | QMessageBox::Ignore | QMessageBox::Abort);
989
            if ( ret == QMessageBox::Ignore ) {
990
                myAlignModel.continueAlignment();
991
            }
992
            else if ( ret == QMessageBox::Abort ) {
993
                finish();
994
                return;
995
            }
996
        }
997

998
        continueAlignment();
999
    }
1000
}
1001

1002
void ManualAlignment::showInstructions()
1003
{
1004
    // Now we can start the actual alignment
1005
    if (myAlignModel.activeGroup().countPoints() < myPickPoints) {
1006
        Gui::getMainWindow()->showMessage(
1007
            tr("Too few points picked in the left view."
1008
               " At least %1 points are needed.").arg(myPickPoints));
1009
    }
1010
    else if (myFixedGroup.countPoints() < myPickPoints) {
1011
        Gui::getMainWindow()->showMessage(
1012
            tr("Too few points picked in the right view."
1013
               " At least %1 points are needed.").arg(myPickPoints));
1014
    }
1015
    else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) {
1016
        Gui::getMainWindow()->showMessage(
1017
            tr("Different number of points picked in left and right view. "
1018
               "On the left view %1 points are picked, "
1019
               "on the right view %2 points are picked.")
1020
            .arg(myAlignModel.activeGroup().countPoints())
1021
            .arg(myFixedGroup.countPoints()));
1022
    }
1023
}
1024

1025
bool ManualAlignment::canAlign() const
1026
{
1027
    if (myAlignModel.activeGroup().countPoints() == myFixedGroup.countPoints()) {
1028
        if (myFixedGroup.countPoints() >= myPickPoints)
1029
            return true;
1030
    }
1031

1032
    return false;
1033
}
1034

1035
/**
1036
 * This method computes the alignment. For the calculation of the alignment the picked points of both views
1037
 * are taken. If the alignment fails false is returned, true otherwise.
1038
 */
1039
bool ManualAlignment::computeAlignment(const std::vector<PickedPoint>& movPts,
1040
                                       const std::vector<PickedPoint>& fixPts)
1041
{
1042
    assert((int)movPts.size() >= myPickPoints);
1043
    assert((int)fixPts.size() >= myPickPoints);
1044
    assert((int)movPts.size() == (int)fixPts.size());
1045
    myTransform = Base::Placement();
1046

1047
    if (movPts.size() == 1) {
1048
        // 1 point partial solution: Simple translation only
1049
        myTransform.setPosition(fixPts[0].point - movPts[0].point);
1050
    }
1051
    else if (movPts.size() == 2) {
1052
        const Base::Vector3d& p1 = movPts[0].point;
1053
        const Base::Vector3d& p2 = movPts[1].point;
1054
        Base::Vector3d d1 = p2-p1;
1055
        d1.Normalize();
1056

1057
        const Base::Vector3d& q1 = fixPts[0].point;
1058
        const Base::Vector3d& q2 = fixPts[1].point;
1059
        Base::Vector3d d2 = q2-q1;
1060
        d2.Normalize();
1061

1062
        myTransform = Private::transformation2x2(p1, d1, q1, d2);
1063
    }
1064
    else if (movPts.size() >= 3) {
1065
        const Base::Vector3d& p1 = movPts[0].point;
1066
        const Base::Vector3d& p2 = movPts[1].point;
1067
        const Base::Vector3d& p3 = movPts[2].point;
1068
        Base::Vector3d d1 = p2-p1;
1069
        d1.Normalize();
1070
        Base::Vector3d n1 = (p2-p1) % (p3-p1);
1071
        n1.Normalize();
1072

1073
        const Base::Vector3d& q1 = fixPts[0].point;
1074
        const Base::Vector3d& q2 = fixPts[1].point;
1075
        const Base::Vector3d& q3 = fixPts[2].point;
1076
        Base::Vector3d d2 = q2-q1;
1077
        d2.Normalize();
1078
        Base::Vector3d n2 = (q2-q1) % (q3-q1);
1079
        n2.Normalize();
1080

1081
        myTransform = Private::transformation3x3(p1, d1, n1, q1, d2, n2);
1082
    }
1083

1084
    return true;
1085
}
1086

1087
/**
1088
 * This method performs the actual alignment of view \a pView.
1089
 */
1090
void ManualAlignment::alignObject(App::DocumentObject *obj)
1091
{
1092
    if (obj->isDerivedFrom<App::GeoFeature>()) {
1093
        auto geom = static_cast<App::GeoFeature*>(obj);
1094
        geom->transformPlacement(this->myTransform);
1095
    }
1096
}
1097

1098
/**
1099
 * Creates a point element as visible feedback for the user.
1100
 */
1101
SoNode* ManualAlignment::pickedPointsSubGraph(const SbVec3f& p, const SbVec3f& n, int id)
1102
{
1103
    static const float color_table [10][3] = {
1104
        {1.0f,0.0f,0.0f}, // red
1105
        {0.0f,1.0f,0.0f}, // green
1106
        {0.0f,0.0f,1.0f}, // blue
1107
        {1.0f,1.0f,0.0f}, // yellow
1108
        {0.0f,1.0f,1.0f}, // cyan
1109
        {0.7f,0.0f,0.0f},
1110
        {0.0f,0.7f,0.0f},
1111
        {0.7f,0.7f,0.0f},
1112
        {0.7f,0.0f,0.5f},
1113
        {1.0f,0.7f,0.0f}
1114
    };
1115

1116
    int index = (id-1) % 10;
1117

1118
    auto probe = new SoRegPoint();
1119
    probe->base.setValue(p);
1120
    probe->normal.setValue(n);
1121
    probe->color.setValue(color_table[index][0],color_table[index][1],color_table[index][2]);
1122
    SbString s(tr("Point_%1").arg(id).toStdString().c_str());
1123
    probe->text.setValue(s);
1124
    return probe;
1125
}
1126

1127
/**
1128
 * Handle if the current document is about to being closed.
1129
 */
1130
void ManualAlignment::slotDeletedDocument(const Gui::Document& Doc)
1131
{
1132
    if (&Doc == this->myDocument)
1133
        reset();
1134
}
1135

1136
/**
1137
 * Handle if the a view provider is about to being destroyed.
1138
 */
1139
void ManualAlignment::slotDeletedObject(const Gui::ViewProvider& Obj)
1140
{
1141
    // remove the view provider either from the left or the right view
1142
    if (Obj.isDerivedFrom<Gui::ViewProviderDocumentObject>()) {
1143
        // remove the view provider immediately from the split window
1144
        bool found = false;
1145
        auto vp = const_cast<Gui::ViewProviderDocumentObject*>
1146
                                      (static_cast<const Gui::ViewProviderDocumentObject*>(&Obj));
1147
        if (myAlignModel.activeGroup().hasView(vp)) {
1148
            myViewer->getViewer(0)->removeViewProvider(vp);
1149
            found = true;
1150
        }
1151
        if (myFixedGroup.hasView(vp)) {
1152
            myViewer->getViewer(1)->removeViewProvider(vp);
1153
            found = true;
1154
        }
1155

1156
        if (found)
1157
            cancel();
1158
    }
1159
}
1160

1161
void ManualAlignment::onAlign()
1162
{
1163
    align();
1164
}
1165

1166
void ManualAlignment::onRemoveLastPointMoveable()
1167
{
1168
    int nPoints = myAlignModel.activeGroup().countPoints();
1169
    if (nPoints > 0) {
1170
        myAlignModel.activeGroup().removeLastPoint();
1171
        d->picksepLeft->removeChild(nPoints-1);
1172
    }
1173
}
1174

1175
void ManualAlignment::onRemoveLastPointFixed()
1176
{
1177
    int nPoints = myFixedGroup.countPoints();
1178
    if (nPoints > 0) {
1179
        myFixedGroup.removeLastPoint();
1180
        d->picksepRight->removeChild(nPoints-1);
1181
    }
1182
}
1183

1184
void ManualAlignment::onClear()
1185
{
1186
    myAlignModel.activeGroup().clear();
1187
    myFixedGroup.clear();
1188

1189
    coinRemoveAllChildren(d->picksepLeft);
1190
    coinRemoveAllChildren(d->picksepRight);
1191
}
1192

1193
void ManualAlignment::onCancel()
1194
{
1195
    cancel();
1196
}
1197

1198
void ManualAlignment::probePickedCallback(void * ud, SoEventCallback * n)
1199
{
1200
    Q_UNUSED(ud);
1201

1202
    auto view  = static_cast<Gui::View3DInventorViewer*>(n->getUserData());
1203
    const SoEvent* ev = n->getEvent();
1204
    if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
1205
        // set as handled
1206
        n->getAction()->setHandled();
1207
        n->setHandled();
1208

1209
        auto mbe = static_cast<const SoMouseButtonEvent *>(ev);
1210
        if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
1211
            // if we are in 'align' mode then handle the click event
1212
            ManualAlignment* self = ManualAlignment::instance();
1213
            // Get the closest point to the camera of the whole scene.
1214
            // This point doesn't need to be part of this view provider.
1215
            Gui::WaitCursor wc;
1216
            const SoPickedPoint * point = view->getPickedPoint(n);
1217
            if (point) {
1218
                auto vp = static_cast<Gui::ViewProvider*>(view->getViewProviderByPath(point->getPath()));
1219
                if (vp && vp->isDerivedFrom<Gui::ViewProviderDocumentObject>()) {
1220
                    auto that = static_cast<Gui::ViewProviderDocumentObject*>(vp);
1221
                    if (self->applyPickedProbe(that, point)) {
1222
                        const SbVec3f& vec = point->getPoint();
1223
                        Gui::getMainWindow()->showMessage(
1224
                            tr("Point picked at (%1,%2,%3)")
1225
                            .arg(vec[0]).arg(vec[1]).arg(vec[2]));
1226
                    }
1227
                    else {
1228
                        Gui::getMainWindow()->showMessage(
1229
                            tr("No point was found on model"));
1230
                    }
1231
                }
1232
            }
1233
            else {
1234
                Gui::getMainWindow()->showMessage(
1235
                    tr("No point was picked"));
1236
            }
1237
        }
1238
        else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) {
1239
            ManualAlignment* self = ManualAlignment::instance();
1240
            if (self->myAlignModel.isEmpty() || self->myFixedGroup.isEmpty())
1241
                return;
1242
            self->showInstructions();
1243
            int nPoints;
1244
            if (view == self->myViewer->getViewer(0))
1245
                nPoints = self->myAlignModel.activeGroup().countPoints();
1246
            else
1247
                nPoints = self->myFixedGroup.countPoints();
1248
            QMenu menu;
1249
            QAction* fi = menu.addAction(tr("&Align"));
1250
            QAction* rem = menu.addAction(tr("&Remove last point"));
1251
            //QAction* cl = menu.addAction("C&lear");
1252
            QAction* ca = menu.addAction(tr("&Cancel"));
1253
            fi->setEnabled(self->canAlign());
1254
            rem->setEnabled(nPoints > 0);
1255
            menu.addSeparator();
1256
            QAction* sync = menu.addAction(tr("&Synchronize views"));
1257
            sync->setCheckable(true);
1258
            if (self->d->sensorCam1->getAttachedNode())
1259
                sync->setChecked(true);
1260
            QAction* id = menu.exec(QCursor::pos());
1261
            if (id == fi) {
1262
                // call align->align();
1263
                QTimer::singleShot(300, self, &ManualAlignment::onAlign);
1264
            }
1265
            else if ((id == rem) && (view == self->myViewer->getViewer(0))) {
1266
                QTimer::singleShot(300, self, &ManualAlignment::onRemoveLastPointMoveable);
1267
            }
1268
            else if ((id == rem) && (view == self->myViewer->getViewer(1))) {
1269
                QTimer::singleShot(300, self, &ManualAlignment::onRemoveLastPointFixed);
1270
            }
1271
            //else if (id == cl) {
1272
            //    // call align->clear();
1273
            //    QTimer::singleShot(300, self, &ManualAlignment::onClear);
1274
            //}
1275
            else if (id == ca) {
1276
                // call align->cancel();
1277
                QTimer::singleShot(300, self, &ManualAlignment::onCancel);
1278
            }
1279
            else if (id == sync) {
1280
                // setup sensor connection
1281
                if (sync->isChecked()) {
1282
                    SoCamera* cam1 = self->myViewer->getViewer(0)->getSoRenderManager()->getCamera();
1283
                    SoCamera* cam2 = self->myViewer->getViewer(1)->getSoRenderManager()->getCamera();
1284
                    if (cam1 && cam2) {
1285
                        self->d->sensorCam1->attach(cam1);
1286
                        self->d->rot_cam1 = cam1->orientation.getValue();
1287
                        self->d->pos_cam1 = cam1->position.getValue();
1288
                        self->d->sensorCam2->attach(cam2);
1289
                        self->d->rot_cam2 = cam2->orientation.getValue();
1290
                        self->d->pos_cam2 = cam2->position.getValue();
1291
                    }
1292
                }
1293
                else {
1294
                    self->d->sensorCam1->detach();
1295
                    self->d->sensorCam2->detach();
1296
                }
1297
            }
1298
        }
1299
    }
1300
}
1301

1302
/**
1303
 * This method stores the picked point \a pnt from the view provider \a prov. If enough points in both windows have been picked
1304
 * the alignment gets invoked.
1305
 */
1306
bool ManualAlignment::applyPickedProbe(Gui::ViewProviderDocumentObject* prov, const SoPickedPoint* pnt)
1307
{
1308
    const SbVec3f& vec = pnt->getPoint();
1309
    const SbVec3f& nor = pnt->getNormal();
1310

1311
    // add to the list for the non-aligned view in the left view
1312
    if (myAlignModel.activeGroup().hasView(prov)) {
1313
        std::vector<Base::Vector3d> pts = prov->getModelPoints(pnt);
1314
        if (pts.empty())
1315
            return false;
1316
        PickedPoint pp;
1317
        pp.point = pts.front();
1318
        myAlignModel.activeGroup().addPoint(pp);
1319
        // Adds a point marker for the picked point.
1320
        d->picksepLeft->addChild(pickedPointsSubGraph(vec, nor, myAlignModel.activeGroup().countPoints()));
1321
        return true;
1322
    }
1323
    else if (myFixedGroup.hasView(prov)) {
1324
        std::vector<Base::Vector3d> pts = prov->getModelPoints(pnt);
1325
        if (pts.empty())
1326
            return false;
1327
        PickedPoint pp;
1328
        pp.point = pts.front();
1329
        myFixedGroup.addPoint(pp);
1330
        // Adds a point marker for the picked point.
1331
        d->picksepRight->addChild(pickedPointsSubGraph(vec, nor, myFixedGroup.countPoints()));
1332
        return true;
1333
    }
1334

1335
    return false;
1336
}
1337

1338
#include "moc_ManualAlignment.cpp"
1339

1340

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.