1275 lines
41 KiB
C++
1275 lines
41 KiB
C++
/***************************************************************************
|
||
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||
* *
|
||
* This file is part of the FreeCAD CAx development system. *
|
||
* *
|
||
* This library is free software; you can redistribute it and/or *
|
||
* modify it under the terms of the GNU Library General Public *
|
||
* License as published by the Free Software Foundation; either *
|
||
* version 2 of the License, or (at your option) any later version. *
|
||
* *
|
||
* This library is distributed in the hope that it will be useful, *
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
* GNU Library General Public License for more details. *
|
||
* *
|
||
* You should have received a copy of the GNU Library General Public *
|
||
* License along with this library; see the file COPYING.LIB. If not, *
|
||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||
* Suite 330, Boston, MA 02111-1307, USA *
|
||
* *
|
||
***************************************************************************/
|
||
|
||
|
||
#include "PreCompiled.h"
|
||
#ifndef _PreComp_
|
||
# include <QAction>
|
||
# include <QApplication>
|
||
# include <QLabel>
|
||
# include <QMenu>
|
||
# include <QMessageBox>
|
||
# include <QGLWidget>
|
||
# include <QPainter>
|
||
# include <QSplitter>
|
||
# include <QStatusBar>
|
||
# include <QTimer>
|
||
# include <QVBoxLayout>
|
||
# include <Inventor/SoPickedPoint.h>
|
||
# include <Inventor/actions/SoSearchAction.h>
|
||
# include <Inventor/events/SoMouseButtonEvent.h>
|
||
# include <Inventor/fields/SoSFImage.h>
|
||
# include <Inventor/nodes/SoCoordinate3.h>
|
||
# include <Inventor/nodes/SoDrawStyle.h>
|
||
# include <Inventor/nodes/SoImage.h>
|
||
# include <Inventor/nodes/SoMaterial.h>
|
||
# include <Inventor/nodes/SoOrthographicCamera.h>
|
||
# include <Inventor/nodes/SoPickStyle.h>
|
||
# include <Inventor/nodes/SoPointSet.h>
|
||
# include <Inventor/nodes/SoSeparator.h>
|
||
# include <Inventor/nodes/SoTranslation.h>
|
||
# include <Inventor/sensors/SoNodeSensor.h>
|
||
#endif
|
||
|
||
#include <boost/signals.hpp>
|
||
#include <boost/bind.hpp>
|
||
|
||
#include <App/Document.h>
|
||
#include <App/GeoFeature.h>
|
||
#include <Base/Exception.h>
|
||
#include <Gui/Application.h>
|
||
#include <Gui/Document.h>
|
||
#include <Gui/MainWindow.h>
|
||
#include <Gui/Selection.h>
|
||
#include <Gui/SplitView3DInventor.h>
|
||
#include <Gui/View3DInventor.h>
|
||
#include <Gui/View3DInventorViewer.h>
|
||
#include <Gui/ViewProviderGeometryObject.h>
|
||
#include <Gui/WaitCursor.h>
|
||
|
||
#include "ManualAlignment.h"
|
||
#include "BitmapFactory.h"
|
||
#include "SoAxisCrossKit.h"
|
||
|
||
|
||
using namespace Gui;
|
||
|
||
AlignmentGroup::AlignmentGroup()
|
||
{
|
||
}
|
||
|
||
AlignmentGroup::~AlignmentGroup()
|
||
{
|
||
}
|
||
|
||
void AlignmentGroup::addView(App::DocumentObject* pView)
|
||
{
|
||
if (pView) {
|
||
App::Document* rDoc = pView->getDocument();
|
||
Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc);
|
||
Gui::ViewProviderDocumentObject* pProvider = static_cast<Gui::ViewProviderDocumentObject*>
|
||
(pDoc->getViewProvider(pView));
|
||
this->_views.push_back(pProvider);
|
||
}
|
||
}
|
||
|
||
std::vector<App::DocumentObject*> AlignmentGroup::getViews() const
|
||
{
|
||
std::vector<App::DocumentObject*> views;
|
||
|
||
std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it) {
|
||
App::DocumentObject* pView = (*it)->getObject();
|
||
views.push_back(pView);
|
||
}
|
||
|
||
return views;
|
||
}
|
||
|
||
bool AlignmentGroup::hasView(Gui::ViewProviderDocumentObject* pView) const
|
||
{
|
||
std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it) {
|
||
if (*it == pView)
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void AlignmentGroup::removeView(Gui::ViewProviderDocumentObject* pView)
|
||
{
|
||
std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it) {
|
||
if (*it == pView) {
|
||
this->_views.erase(it);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void AlignmentGroup::addToViewer(Gui::View3DInventorViewer* viewer) const
|
||
{
|
||
std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it)
|
||
viewer->addViewProvider(*it);
|
||
|
||
viewer->viewAll();
|
||
}
|
||
|
||
void AlignmentGroup::removeFromViewer(Gui::View3DInventorViewer* viewer) const
|
||
{
|
||
std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it)
|
||
viewer->removeViewProvider(*it);
|
||
}
|
||
|
||
void AlignmentGroup::setRandomColor()
|
||
{
|
||
std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it) {
|
||
float r = /*(float)rand()/(float)RAND_MAX*/0.0f;
|
||
float g = (float)rand()/(float)RAND_MAX;
|
||
float b = (float)rand()/(float)RAND_MAX;
|
||
if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) {
|
||
SoSearchAction searchAction;
|
||
searchAction.setType(SoMaterial::getClassTypeId());
|
||
searchAction.setInterest(SoSearchAction::FIRST);
|
||
searchAction.apply((*it)->getRoot());
|
||
SoPath* selectionPath = searchAction.getPath();
|
||
|
||
if (selectionPath) {
|
||
SoMaterial* material = static_cast<SoMaterial*>(selectionPath->getTail());
|
||
material->diffuseColor.setValue(r, g, b);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Gui::Document* AlignmentGroup::getDocument() const
|
||
{
|
||
if (this->_views.empty())
|
||
return 0;
|
||
App::DocumentObject* pView = this->_views[0]->getObject();
|
||
if (pView) {
|
||
App::Document* rDoc = pView->getDocument();
|
||
Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc);
|
||
return pDoc;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
void AlignmentGroup::addPoint(const Base::Vector3d& pnt)
|
||
{
|
||
this->_pickedPoints.push_back(pnt);
|
||
}
|
||
|
||
void AlignmentGroup::removeLastPoint()
|
||
{
|
||
this->_pickedPoints.pop_back();
|
||
}
|
||
|
||
int AlignmentGroup::countPoints() const
|
||
{
|
||
return this->_pickedPoints.size();
|
||
}
|
||
|
||
const std::vector<Base::Vector3d>& AlignmentGroup::getPoints() const
|
||
{
|
||
return this->_pickedPoints;
|
||
}
|
||
|
||
void AlignmentGroup::clearPoints()
|
||
{
|
||
this->_pickedPoints.clear();
|
||
}
|
||
|
||
void AlignmentGroup::setAlignable(bool align)
|
||
{
|
||
//std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
|
||
//for (it = this->_views.begin(); it != this->_views.end(); ++it) {
|
||
// if (!align){
|
||
// App::PropertyColor* pColor = (App::PropertyColor*)(*it)->getPropertyByName("ShapeColor");
|
||
// if (pColor)
|
||
// pColor->touch(); // resets to color defined by property
|
||
// }
|
||
//}
|
||
}
|
||
|
||
void AlignmentGroup::moveTo(AlignmentGroup& that)
|
||
{
|
||
std::vector<Gui::ViewProviderDocumentObject*>::iterator it;
|
||
for (it = this->_views.begin(); it != this->_views.end(); ++it)
|
||
that._views.push_back(*it);
|
||
|
||
this->_views.clear();
|
||
}
|
||
|
||
void AlignmentGroup::clear()
|
||
{
|
||
this->_views.clear();
|
||
this->_pickedPoints.clear();
|
||
}
|
||
|
||
bool AlignmentGroup::isEmpty() const
|
||
{
|
||
return this->_views.empty();
|
||
}
|
||
|
||
int AlignmentGroup::count() const
|
||
{
|
||
return this->_views.size();
|
||
}
|
||
|
||
// ------------------------------------------------------------------
|
||
|
||
MovableGroup::MovableGroup()
|
||
{
|
||
}
|
||
|
||
MovableGroup::~MovableGroup()
|
||
{
|
||
}
|
||
|
||
// ------------------------------------------------------------------
|
||
|
||
FixedGroup::FixedGroup()
|
||
{
|
||
}
|
||
|
||
FixedGroup::~FixedGroup()
|
||
{
|
||
}
|
||
|
||
// ------------------------------------------------------------------
|
||
|
||
MovableGroupModel::MovableGroupModel()
|
||
{
|
||
}
|
||
|
||
MovableGroupModel::~MovableGroupModel()
|
||
{
|
||
}
|
||
|
||
void MovableGroupModel::addGroup(const MovableGroup& grp)
|
||
{
|
||
this->_groups.push_back(grp);
|
||
}
|
||
|
||
void MovableGroupModel::addGroups(const std::map<int, MovableGroup>& grps)
|
||
{
|
||
for (std::map<int, MovableGroup>::const_iterator it = grps.begin(); it != grps.end(); ++it)
|
||
this->_groups.push_back(it->second);
|
||
}
|
||
|
||
void MovableGroupModel::removeActiveGroup()
|
||
{
|
||
this->_groups.erase(this->_groups.begin());
|
||
}
|
||
|
||
MovableGroup& MovableGroupModel::activeGroup()
|
||
{
|
||
// Make sure that the array is not empty
|
||
if (this->_groups.empty())
|
||
throw Base::Exception("Empty group");
|
||
return *(this->_groups.begin());
|
||
}
|
||
|
||
const MovableGroup& MovableGroupModel::activeGroup() const
|
||
{
|
||
// Make sure that the array is not empty
|
||
if (this->_groups.empty())
|
||
throw Base::Exception("Empty group");
|
||
return *(this->_groups.begin());
|
||
}
|
||
|
||
void MovableGroupModel::continueAlignment()
|
||
{
|
||
if (!isEmpty())
|
||
removeActiveGroup();
|
||
}
|
||
|
||
void MovableGroupModel::clear()
|
||
{
|
||
this->_groups.clear();
|
||
}
|
||
|
||
bool MovableGroupModel::isEmpty() const
|
||
{
|
||
return this->_groups.empty();
|
||
}
|
||
|
||
int MovableGroupModel::count() const
|
||
{
|
||
return this->_groups.size();
|
||
}
|
||
|
||
// ------------------------------------------------------------------
|
||
|
||
namespace Gui {
|
||
class AlignmentView : public Gui::AbstractSplitView
|
||
{
|
||
public:
|
||
QLabel* myLabel;
|
||
|
||
AlignmentView(Gui::Document* pcDocument, QWidget* parent, QGLWidget* shareWidget=0, Qt::WFlags wflags=0)
|
||
: AbstractSplitView(pcDocument, parent, wflags)
|
||
{
|
||
QSplitter* mainSplitter=0;
|
||
mainSplitter = new QSplitter(Qt::Horizontal, this);
|
||
_viewer.push_back(new View3DInventorViewer(mainSplitter, shareWidget));
|
||
_viewer.back()->setDocument(pcDocument);
|
||
_viewer.push_back(new View3DInventorViewer(mainSplitter, shareWidget));
|
||
_viewer.back()->setDocument(pcDocument);
|
||
|
||
QFrame* vbox = new QFrame(this);
|
||
QVBoxLayout* layout = new QVBoxLayout();
|
||
layout->setMargin(0);
|
||
layout->setSpacing(0);
|
||
vbox->setLayout(layout);
|
||
|
||
myLabel = new QLabel(this);
|
||
myLabel->setAutoFillBackground(true);
|
||
QPalette pal = myLabel->palette();
|
||
pal.setColor(QPalette::Window, Qt::darkGray);
|
||
pal.setColor(QPalette::WindowText, Qt::white);
|
||
myLabel->setPalette(pal);
|
||
mainSplitter->setPalette(pal);
|
||
myLabel->setAlignment(Qt::AlignCenter);
|
||
myLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||
QFont font = myLabel->font();
|
||
font.setPointSize(14);
|
||
myLabel->setFont(font);
|
||
layout->addWidget(myLabel);
|
||
layout->addWidget(mainSplitter);
|
||
|
||
vbox->show();
|
||
setCentralWidget(vbox);
|
||
|
||
// apply the user settings
|
||
setupSettings();
|
||
|
||
static_cast<SoGroup*>(getViewer(0)->getSoRenderManager()->getSceneGraph())->
|
||
addChild(setupHeadUpDisplay(tr("Movable object")));
|
||
static_cast<SoGroup*>(getViewer(1)->getSoRenderManager()->getSceneGraph())->
|
||
addChild(setupHeadUpDisplay(tr("Fixed object")));
|
||
}
|
||
~AlignmentView()
|
||
{
|
||
}
|
||
PyObject* getPyObject()
|
||
{
|
||
Py_Return;
|
||
}
|
||
bool canClose()
|
||
{
|
||
return false;
|
||
}
|
||
SoNode* setupHeadUpDisplay(const QString& text) const
|
||
{
|
||
SoSeparator* hudRoot = new SoSeparator;
|
||
hudRoot->ref();
|
||
|
||
SoOrthographicCamera* hudCam = new SoOrthographicCamera();
|
||
hudCam->viewportMapping = SoCamera::LEAVE_ALONE;
|
||
|
||
// Set the position in the window.
|
||
// [0, 0] is in the center of the screen.
|
||
//
|
||
SoTranslation* hudTrans = new SoTranslation;
|
||
hudTrans->translation.setValue(-0.95f, -0.95f, 0.0f);
|
||
|
||
QFont font = this->font();
|
||
font.setPointSize(24);
|
||
QFontMetrics fm(font);
|
||
|
||
QColor front;
|
||
front.setRgbF(0.8f, 0.8f, 0.8f);
|
||
|
||
int w = fm.width(text);
|
||
int h = fm.height();
|
||
|
||
QImage image(w,h,QImage::Format_ARGB32_Premultiplied);
|
||
image.fill(0x00000000);
|
||
QPainter painter(&image);
|
||
painter.setRenderHint(QPainter::Antialiasing);
|
||
painter.setPen(front);
|
||
painter.setFont(font);
|
||
painter.drawText(0,0,w,h,Qt::AlignLeft,text);
|
||
painter.end();
|
||
SoSFImage sfimage;
|
||
Gui::BitmapFactory().convert(image, sfimage);
|
||
SoImage* hudImage = new SoImage();
|
||
hudImage->image = sfimage;
|
||
|
||
// Assemble the parts...
|
||
//
|
||
hudRoot->addChild(hudCam);
|
||
hudRoot->addChild(hudTrans);
|
||
hudRoot->addChild(hudImage);
|
||
|
||
return hudRoot;
|
||
}
|
||
};
|
||
}
|
||
|
||
class ManualAlignment::Private {
|
||
public:
|
||
SoSeparator * picksepLeft;
|
||
SoSeparator * picksepRight;
|
||
SoNodeSensor* sensorCam1;
|
||
SoNodeSensor* sensorCam2;
|
||
SbRotation rot_cam1, rot_cam2;
|
||
SbVec3f pos_cam1, pos_cam2;
|
||
|
||
Private()
|
||
: sensorCam1(0), sensorCam2(0)
|
||
{
|
||
// left view
|
||
picksepLeft = new SoSeparator;
|
||
picksepLeft->ref();
|
||
// right view
|
||
picksepRight = new SoSeparator;
|
||
picksepRight->ref();
|
||
}
|
||
~Private()
|
||
{
|
||
picksepLeft->unref();
|
||
picksepRight->unref();
|
||
delete sensorCam1;
|
||
delete sensorCam2;
|
||
}
|
||
|
||
static
|
||
void reorientCamera(SoCamera * cam, const SbRotation & rot)
|
||
{
|
||
if (cam == NULL) return;
|
||
|
||
// Find global coordinates of focal point.
|
||
SbVec3f direction;
|
||
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
|
||
SbVec3f focalpoint = cam->position.getValue() +
|
||
cam->focalDistance.getValue() * direction;
|
||
|
||
// Set new orientation value by accumulating the new rotation.
|
||
cam->orientation = rot * cam->orientation.getValue();
|
||
|
||
// Reposition camera so we are still pointing at the same old focal point.
|
||
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
|
||
cam->position = focalpoint - cam->focalDistance.getValue() * direction;
|
||
}
|
||
|
||
static
|
||
void copyCameraSettings(SoCamera* cam1, SbRotation& rot_cam1, SbVec3f& pos_cam1,
|
||
SoCamera* cam2, SbRotation& rot_cam2, SbVec3f& pos_cam2)
|
||
{
|
||
// recompute the diff we have applied to the camera's orientation
|
||
SbRotation rot = cam1->orientation.getValue();
|
||
SbRotation dif = rot * rot_cam1.inverse();
|
||
rot_cam1 = rot;
|
||
|
||
// copy the values
|
||
cam2->enableNotify(FALSE);
|
||
cam2->nearDistance = cam1->nearDistance;
|
||
cam2->farDistance = cam1->farDistance;
|
||
cam2->focalDistance = cam1->focalDistance;
|
||
reorientCamera(cam2,dif);
|
||
rot_cam2 = cam2->orientation.getValue();
|
||
|
||
// reverse engineer the translation part in wc
|
||
SbVec3f pos = cam1->position.getValue();
|
||
SbVec3f difpos = pos - pos_cam1;
|
||
pos_cam1 = pos;
|
||
// the translation in pixel coords
|
||
cam1->orientation.getValue().inverse().multVec(difpos,difpos);
|
||
// the translation again in wc for the second camera
|
||
cam2->orientation.getValue().multVec(difpos,difpos);
|
||
cam2->position.setValue(cam2->position.getValue()+difpos);
|
||
|
||
if (cam1->getTypeId() == cam2->getTypeId()) {
|
||
if (cam1->getTypeId() == SoOrthographicCamera::getClassTypeId())
|
||
static_cast<SoOrthographicCamera*>(cam2)->height =
|
||
static_cast<SoOrthographicCamera*>(cam1)->height;
|
||
}
|
||
|
||
cam2->enableNotify(TRUE);
|
||
}
|
||
static
|
||
void syncCameraCB(void * data, SoSensor * s)
|
||
{
|
||
ManualAlignment* self = reinterpret_cast<ManualAlignment*>(data);
|
||
if (!self->myViewer)
|
||
return; // already destroyed
|
||
SoCamera* cam1 = self->myViewer->getViewer(0)->getSoRenderManager()->getCamera();
|
||
SoCamera* cam2 = self->myViewer->getViewer(1)->getSoRenderManager()->getCamera();
|
||
if (!cam1 || !cam2)
|
||
return; // missing camera
|
||
SoNodeSensor* sensor = static_cast<SoNodeSensor*>(s);
|
||
SoNode* node = sensor->getAttachedNode();
|
||
if (node && node->getTypeId().isDerivedFrom(SoCamera::getClassTypeId())) {
|
||
if (node == cam1) {
|
||
Private::copyCameraSettings(cam1, self->d->rot_cam1, self->d->pos_cam1,
|
||
cam2, self->d->rot_cam2, self->d->pos_cam2);
|
||
self->myViewer->getViewer(1)->redraw();
|
||
}
|
||
else if (node == cam2) {
|
||
Private::copyCameraSettings(cam2, self->d->rot_cam2, self->d->pos_cam2,
|
||
cam1, self->d->rot_cam1, self->d->pos_cam1);
|
||
self->myViewer->getViewer(0)->redraw();
|
||
}
|
||
}
|
||
}
|
||
|
||
static Base::Placement
|
||
transformation2x2(const Base::Vector3d& plane1_base,
|
||
const Base::Vector3d& plane1_xaxis,
|
||
const Base::Vector3d& plane2_base,
|
||
const Base::Vector3d& plane2_xaxis)
|
||
{
|
||
// the transformation is:
|
||
// * move from plane1_base to plane2_base
|
||
// * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point
|
||
Base::Rotation rot(plane1_xaxis, plane2_xaxis);
|
||
|
||
Base::Vector3d pln_base;
|
||
rot.multVec(plane1_base,pln_base);
|
||
Base::Vector3d dif = plane2_base - pln_base;
|
||
return Base::Placement(dif, rot);
|
||
}
|
||
|
||
static Base::Placement
|
||
transformation3x3(const Base::Vector3d& plane1_base,
|
||
const Base::Vector3d& plane1_zaxis,
|
||
const Base::Vector3d& plane1_xaxis,
|
||
const Base::Vector3d& plane2_base,
|
||
const Base::Vector3d& plane2_zaxis,
|
||
const Base::Vector3d& plane2_xaxis)
|
||
{
|
||
// the transformation is:
|
||
// * move from plane1_base to plane2_base
|
||
// * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point
|
||
Base::Rotation rot(plane1_zaxis, plane2_zaxis);
|
||
|
||
// first transformation to align the plane normals and base points
|
||
Base::Vector3d dif1 = plane1_base;
|
||
rot.multVec(dif1,dif1);
|
||
dif1 = plane2_base - dif1;
|
||
Base::Placement plm1(dif1, rot);
|
||
|
||
// second transformation to align the planes' x axes
|
||
Base::Vector3d pln_xaxis;
|
||
rot.multVec(plane1_xaxis,pln_xaxis);
|
||
Base::Rotation rot2(pln_xaxis, plane2_xaxis);
|
||
Base::Vector3d dif2 = plane2_base;
|
||
rot2.multVec(dif2,dif2);
|
||
dif2 = plane2_base - dif2;
|
||
Base::Placement plm2(dif2, rot2);
|
||
plm2 = plm2 * plm1;
|
||
return plm2;
|
||
}
|
||
};
|
||
|
||
/* TRANSLATOR Gui::ManualAlignment */
|
||
|
||
ManualAlignment* ManualAlignment::_instance = 0;
|
||
|
||
/**
|
||
* Construction.
|
||
*/
|
||
ManualAlignment::ManualAlignment()
|
||
: myViewer(0), myDocument(0), myPickPoints(3), d(new Private)
|
||
{
|
||
// connect with the application's signal for deletion of documents
|
||
this->connectApplicationDeletedDocument = Gui::Application::Instance->signalDeleteDocument
|
||
.connect(boost::bind(&ManualAlignment::slotDeletedDocument, this, _1));
|
||
|
||
// setup sensor connection
|
||
d->sensorCam1 = new SoNodeSensor(Private::syncCameraCB, this);
|
||
d->sensorCam2 = new SoNodeSensor(Private::syncCameraCB, this);
|
||
}
|
||
|
||
/**
|
||
* Destruction.
|
||
*/
|
||
ManualAlignment::~ManualAlignment()
|
||
{
|
||
this->connectDocumentDeletedObject.disconnect();
|
||
this->connectApplicationDeletedDocument.disconnect();
|
||
closeViewer();
|
||
delete d;
|
||
_instance = 0;
|
||
}
|
||
|
||
/**
|
||
* Creates the one and only instance of this class.
|
||
*/
|
||
ManualAlignment* ManualAlignment::instance()
|
||
{
|
||
// not initialized?
|
||
if (!_instance)
|
||
_instance = new ManualAlignment();
|
||
return _instance;
|
||
}
|
||
|
||
/**
|
||
* Destructs the one and only instance of this class.
|
||
*/
|
||
void ManualAlignment::destruct()
|
||
{
|
||
if (_instance) {
|
||
ManualAlignment* tmp = _instance;
|
||
_instance = 0;
|
||
delete tmp;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Checks whether the one instance exists.
|
||
*/
|
||
bool ManualAlignment::hasInstance()
|
||
{
|
||
return _instance != 0;
|
||
}
|
||
|
||
void ManualAlignment::setMinPoints(int minPoints)
|
||
{
|
||
if ((minPoints > 0) && (minPoints <= 3))
|
||
myPickPoints = minPoints;
|
||
}
|
||
|
||
void ManualAlignment::setFixedGroup(const FixedGroup& fixed)
|
||
{
|
||
this->myFixedGroup = fixed;
|
||
this->myDocument = fixed.getDocument();
|
||
}
|
||
|
||
void ManualAlignment::setModel(const MovableGroupModel& model)
|
||
{
|
||
this->myAlignModel = model;
|
||
}
|
||
|
||
void ManualAlignment::clearAll()
|
||
{
|
||
myFixedGroup.clear();
|
||
myAlignModel.clear();
|
||
myDocument = 0;
|
||
}
|
||
|
||
void ManualAlignment::setViewingDirections(const Base::Vector3d& view1, const Base::Vector3d& up1,
|
||
const Base::Vector3d& view2, const Base::Vector3d& up2)
|
||
{
|
||
if (myViewer.isNull())
|
||
return;
|
||
|
||
{
|
||
SbRotation rot;
|
||
rot.setValue(SbVec3f(0.0f, 0.0f, 1.0f), SbVec3f(-view1.x,-view1.y,-view1.z));
|
||
|
||
SbRotation rot2;
|
||
SbVec3f up(0.0f, 1.0f, 0.0f);
|
||
rot.multVec(up, up);
|
||
rot2.setValue(up, SbVec3f(up1.x, up1.y, up1.z));
|
||
myViewer->getViewer(0)->getSoRenderManager()->getCamera()->orientation.setValue(rot * rot2);
|
||
myViewer->getViewer(0)->viewAll();
|
||
}
|
||
|
||
{
|
||
SbRotation rot;
|
||
rot.setValue(SbVec3f(0.0f, 0.0f, 1.0f), SbVec3f(-view2.x,-view2.y,-view2.z));
|
||
|
||
SbRotation rot2;
|
||
SbVec3f up(0.0f, 1.0f, 0.0f);
|
||
rot.multVec(up, up);
|
||
rot2.setValue(up, SbVec3f(up2.x, up2.y, up2.z));
|
||
myViewer->getViewer(1)->getSoRenderManager()->getCamera()->orientation.setValue(rot * rot2);
|
||
myViewer->getViewer(1)->viewAll();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Performs the alignment for the specified aligned and non-aligned views specified by setModel() and setFixedGroup().
|
||
*/
|
||
void ManualAlignment::startAlignment(Base::Type mousemodel)
|
||
{
|
||
// allow only one alignment at a time
|
||
if (!myViewer.isNull()) {
|
||
QMessageBox::warning(qApp->activeWindow(), tr("Manual alignment"), tr("The alignment is already in progress."));
|
||
return;
|
||
}
|
||
|
||
myTransform = Base::Placement();
|
||
|
||
if (myFixedGroup.isEmpty())
|
||
return;
|
||
if (myAlignModel.isEmpty())
|
||
return;
|
||
|
||
QGLWidget* shareWidget = 0;
|
||
std::list<MDIView*> theViews = myDocument->getMDIViewsOfType(View3DInventor::getClassTypeId());
|
||
if (!theViews.empty()) {
|
||
shareWidget = qobject_cast<QGLWidget*>(static_cast<View3DInventor*>
|
||
(theViews.front())->getViewer()->getGLWidget());
|
||
}
|
||
|
||
// create a splitted window for picking the points
|
||
myViewer = new AlignmentView(myDocument,Gui::getMainWindow(),shareWidget);
|
||
myViewer->setWindowTitle(tr("Alignment[*]"));
|
||
myViewer->setWindowIcon(QApplication::windowIcon());
|
||
myViewer->resize(400, 300);
|
||
Gui::getMainWindow()->addWindow(myViewer);
|
||
myViewer->showMaximized();
|
||
int n = this->myPickPoints;
|
||
QString msg = n == 1
|
||
? tr("Please, select at least one point in the left and the right view")
|
||
: tr("Please, select at least %1 points in the left and the right view").arg(n);
|
||
myViewer->myLabel->setText(msg);
|
||
|
||
connect(myViewer, SIGNAL(destroyed()), this, SLOT(reset()));
|
||
|
||
// show all aligned views in the 2nd view
|
||
myFixedGroup.addToViewer(myViewer->getViewer(1));
|
||
myFixedGroup.setAlignable(true);
|
||
|
||
// set picked points root
|
||
SoNode* node1 = myViewer->getViewer(0)->getSceneGraph();
|
||
if (node1->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){
|
||
((SoGroup*)node1)->addChild(d->picksepLeft);
|
||
}
|
||
SoNode* node2 = myViewer->getViewer(1)->getSceneGraph();
|
||
if (node2->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){
|
||
((SoGroup*)node2)->addChild(d->picksepRight);
|
||
}
|
||
|
||
myViewer->getViewer(0)->setEditing(true);
|
||
myViewer->getViewer(0)->addEventCallback(SoMouseButtonEvent::getClassTypeId(),
|
||
ManualAlignment::probePickedCallback);
|
||
myViewer->getViewer(1)->setEditing(true);
|
||
myViewer->getViewer(1)->addEventCallback(SoMouseButtonEvent::getClassTypeId(),
|
||
ManualAlignment::probePickedCallback);
|
||
// apply the mouse model
|
||
myViewer->getViewer(0)->setNavigationType(mousemodel);
|
||
myViewer->getViewer(1)->setNavigationType(mousemodel);
|
||
|
||
// Connect to the document's signal as we want to be notified when something happens
|
||
if (this->connectDocumentDeletedObject.connected())
|
||
this->connectDocumentDeletedObject.disconnect();
|
||
this->connectDocumentDeletedObject = myDocument->signalDeletedObject.connect(boost::bind
|
||
(&ManualAlignment::slotDeletedObject, this, _1));
|
||
|
||
continueAlignment();
|
||
}
|
||
|
||
/**
|
||
* 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.
|
||
*/
|
||
void ManualAlignment::continueAlignment()
|
||
{
|
||
myFixedGroup.clearPoints();
|
||
d->picksepLeft->removeAllChildren();
|
||
d->picksepRight->removeAllChildren();
|
||
|
||
if (!myAlignModel.isEmpty()) {
|
||
AlignmentGroup& grp = myAlignModel.activeGroup();
|
||
grp.clearPoints();
|
||
grp.addToViewer(myViewer->getViewer(0));
|
||
grp.setAlignable(true);
|
||
|
||
Gui::getMainWindow()->showMessage(tr("Please pick points in the left and right view"));
|
||
|
||
myViewer->getViewer(0)->setEditingCursor(QCursor(Qt::PointingHandCursor));
|
||
myViewer->getViewer(1)->setEditingCursor(QCursor(Qt::PointingHandCursor));
|
||
}
|
||
else {
|
||
finish();
|
||
}
|
||
}
|
||
|
||
void ManualAlignment::closeViewer()
|
||
{
|
||
if (!myViewer)
|
||
return;
|
||
// Close the viewer
|
||
#if !defined(NO_USE_QT_MDI_AREA)
|
||
if (myViewer->parentWidget())
|
||
myViewer->parentWidget()->deleteLater();
|
||
#else
|
||
myViewer->deleteLater();
|
||
#endif
|
||
myViewer = 0;
|
||
}
|
||
|
||
/**
|
||
* Make all views unpickable and resets internal data.
|
||
*/
|
||
void ManualAlignment::reset()
|
||
{
|
||
if (!myAlignModel.isEmpty()) {
|
||
myAlignModel.activeGroup().setAlignable(false);
|
||
myAlignModel.activeGroup().clear();
|
||
myAlignModel.clear();
|
||
}
|
||
|
||
myFixedGroup.setAlignable(false);
|
||
myFixedGroup.clear();
|
||
|
||
d->picksepLeft->removeAllChildren();
|
||
d->picksepRight->removeAllChildren();
|
||
|
||
if (myDocument) {
|
||
this->connectDocumentDeletedObject.disconnect();
|
||
myDocument = 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Terminates the process and closes the windows.
|
||
*/
|
||
void ManualAlignment::finish()
|
||
{
|
||
if (myViewer.isNull())
|
||
return;
|
||
|
||
if (myDocument)
|
||
myDocument->getDocument()->recompute();
|
||
closeViewer();
|
||
reset();
|
||
|
||
Gui::getMainWindow()->showMessage(tr("The alignment has finished"));
|
||
|
||
// If an event receiver has been defined send the manual alignment finished event to it
|
||
emitFinished();
|
||
}
|
||
|
||
/**
|
||
* Cancels the process and cl<63>ses the windows without performing an alignment.
|
||
*/
|
||
void ManualAlignment::cancel()
|
||
{
|
||
if (myViewer.isNull())
|
||
return;
|
||
|
||
closeViewer();
|
||
myTransform = Base::Placement();
|
||
reset();
|
||
|
||
Gui::getMainWindow()->showMessage(tr("The alignment has been canceled"));
|
||
|
||
// If an event receiver has been defined send the manual alignment cancelled event to it
|
||
emitCanceled();
|
||
}
|
||
|
||
void ManualAlignment::align()
|
||
{
|
||
// Now we can start the actual alignment
|
||
if (myAlignModel.activeGroup().countPoints() < myPickPoints) {
|
||
QMessageBox::warning(myViewer, tr("Manual alignment"),
|
||
tr("Too few points picked in the left view."
|
||
" At least %1 points are needed.").arg(myPickPoints));
|
||
}
|
||
else if (myFixedGroup.countPoints() < myPickPoints) {
|
||
QMessageBox::warning(myViewer, tr("Manual alignment"),
|
||
tr("Too few points picked in the right view."
|
||
" At least %1 points are needed.").arg(myPickPoints));
|
||
}
|
||
else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) {
|
||
QMessageBox::warning(myViewer, tr("Manual alignment"),
|
||
tr("Different number of points picked in left and right view.\n"
|
||
"On the left view %1 points are picked,\n"
|
||
"on the right view %2 points are picked.")
|
||
.arg(myAlignModel.activeGroup().countPoints())
|
||
.arg(myFixedGroup.countPoints()));
|
||
}
|
||
else {
|
||
// do not allow to pick further points
|
||
myAlignModel.activeGroup().removeFromViewer(myViewer->getViewer(0));
|
||
myAlignModel.activeGroup().setAlignable(false);
|
||
std::vector<App::DocumentObject*> pViews = myAlignModel.activeGroup().getViews();
|
||
Gui::getMainWindow()->showMessage(tr("Try to align group of views"));
|
||
|
||
// Compute alignment
|
||
bool ok = computeAlignment(myAlignModel.activeGroup().getPoints(), myFixedGroup.getPoints());
|
||
if (ok && myDocument) {
|
||
// Align views
|
||
myDocument->openCommand("Align");
|
||
for (std::vector<App::DocumentObject*>::iterator it = pViews.begin(); it != pViews.end(); ++it)
|
||
alignObject(*it);
|
||
myDocument->commitCommand();
|
||
|
||
// the alignment was successful so show it in the right view now
|
||
//myAlignModel.activeGroup().setRandomColor();
|
||
myAlignModel.activeGroup().setAlignable(true);
|
||
myAlignModel.activeGroup().addToViewer(myViewer->getViewer(1));
|
||
myAlignModel.activeGroup().moveTo(myFixedGroup);
|
||
myAlignModel.continueAlignment();
|
||
}
|
||
else {
|
||
// Inform user that alignment failed
|
||
int ret = QMessageBox::critical(myViewer, tr("Manual alignment"),
|
||
tr("The alignment failed.\nHow do you want to proceed?"),
|
||
tr("Retry"), tr("Ignore"), tr("Abort"));
|
||
if ( ret == 1 ) {
|
||
myAlignModel.continueAlignment();
|
||
}
|
||
else if ( ret == 2 ) {
|
||
finish();
|
||
return;
|
||
}
|
||
}
|
||
|
||
continueAlignment();
|
||
}
|
||
}
|
||
|
||
void ManualAlignment::showInstructions()
|
||
{
|
||
// Now we can start the actual alignment
|
||
if (myAlignModel.activeGroup().countPoints() < myPickPoints) {
|
||
Gui::getMainWindow()->showMessage(
|
||
tr("Too few points picked in the left view."
|
||
" At least %1 points are needed.").arg(myPickPoints));
|
||
}
|
||
else if (myFixedGroup.countPoints() < myPickPoints) {
|
||
Gui::getMainWindow()->showMessage(
|
||
tr("Too few points picked in the right view."
|
||
" At least %1 points are needed.").arg(myPickPoints));
|
||
}
|
||
else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) {
|
||
Gui::getMainWindow()->showMessage(
|
||
tr("Different number of points picked in left and right view. "
|
||
"On the left view %1 points are picked, "
|
||
"on the right view %2 points are picked.")
|
||
.arg(myAlignModel.activeGroup().countPoints())
|
||
.arg(myFixedGroup.countPoints()));
|
||
}
|
||
}
|
||
|
||
bool ManualAlignment::canAlign() const
|
||
{
|
||
if (myAlignModel.activeGroup().countPoints() == myFixedGroup.countPoints()) {
|
||
if (myFixedGroup.countPoints() >= myPickPoints)
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* This method computes the alignment. For the calculation of the alignment the picked points of both views
|
||
* are taken. If the alignment fails false is returned, true otherwise.
|
||
*/
|
||
bool ManualAlignment::computeAlignment(const std::vector<Base::Vector3d>& movPts,
|
||
const std::vector<Base::Vector3d>& fixPts)
|
||
{
|
||
assert((int)movPts.size() >= myPickPoints);
|
||
assert((int)fixPts.size() >= myPickPoints);
|
||
assert((int)movPts.size() == (int)fixPts.size());
|
||
myTransform = Base::Placement();
|
||
|
||
if (movPts.size() == 1) {
|
||
// 1 point partial solution: Simple translation only
|
||
myTransform.setPosition(fixPts[0] - movPts[0]);
|
||
}
|
||
else if (movPts.size() == 2) {
|
||
const Base::Vector3d& p1 = movPts[0];
|
||
const Base::Vector3d& p2 = movPts[1];
|
||
Base::Vector3d d1 = p2-p1;
|
||
d1.Normalize();
|
||
|
||
const Base::Vector3d& q1 = fixPts[0];
|
||
const Base::Vector3d& q2 = fixPts[1];
|
||
Base::Vector3d d2 = q2-q1;
|
||
d2.Normalize();
|
||
|
||
myTransform = Private::transformation2x2(p1, d1, q1, d2);
|
||
}
|
||
else if (movPts.size() >= 3) {
|
||
const Base::Vector3d& p1 = movPts[0];
|
||
const Base::Vector3d& p2 = movPts[1];
|
||
const Base::Vector3d& p3 = movPts[2];
|
||
Base::Vector3d d1 = p2-p1;
|
||
d1.Normalize();
|
||
Base::Vector3d n1 = (p2-p1) % (p3-p1);
|
||
n1.Normalize();
|
||
|
||
const Base::Vector3d& q1 = fixPts[0];
|
||
const Base::Vector3d& q2 = fixPts[1];
|
||
const Base::Vector3d& q3 = fixPts[2];
|
||
Base::Vector3d d2 = q2-q1;
|
||
d2.Normalize();
|
||
Base::Vector3d n2 = (q2-q1) % (q3-q1);
|
||
n2.Normalize();
|
||
|
||
myTransform = Private::transformation3x3(p1, d1, n1, q1, d2, n2);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* This method performs the actual alignment of view \a pView.
|
||
*/
|
||
void ManualAlignment::alignObject(App::DocumentObject *obj)
|
||
{
|
||
if (obj->getTypeId().isDerivedFrom(App::GeoFeature::getClassTypeId())) {
|
||
App::GeoFeature* geom = static_cast<App::GeoFeature*>(obj);
|
||
geom->transformPlacement(this->myTransform);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Creates a point element as visible feedback for the user.
|
||
*/
|
||
SoNode* ManualAlignment::pickedPointsSubGraph(const SbVec3f& p, const SbVec3f& n, int id)
|
||
{
|
||
static const float color_table [10][3] = {
|
||
{1.0f,0.0f,0.0f}, // red
|
||
{0.0f,1.0f,0.0f}, // green
|
||
{0.0f,0.0f,1.0f}, // blue
|
||
{1.0f,1.0f,0.0f}, // yellow
|
||
{0.0f,1.0f,1.0f}, // cyan
|
||
{0.7f,0.0f,0.0f},
|
||
{0.0f,0.7f,0.0f},
|
||
{0.7f,0.7f,0.0f},
|
||
{0.7f,0.0f,0.5f},
|
||
{1.0f,0.7f,0.0f}
|
||
};
|
||
|
||
int index = (id-1) % 10;
|
||
|
||
SoRegPoint* probe = new SoRegPoint();
|
||
probe->base.setValue(p);
|
||
probe->normal.setValue(n);
|
||
probe->color.setValue(color_table[index][0],color_table[index][1],color_table[index][2]);
|
||
SbString s;
|
||
probe->text.setValue(s.sprintf("RegPoint_%d", id));
|
||
return probe;
|
||
}
|
||
|
||
/**
|
||
* Handle if the current document is about to being closed.
|
||
*/
|
||
void ManualAlignment::slotDeletedDocument(const Gui::Document& Doc)
|
||
{
|
||
if (&Doc == this->myDocument)
|
||
reset();
|
||
}
|
||
|
||
/**
|
||
* Handle if the a view provider is about to being destroyed.
|
||
*/
|
||
void ManualAlignment::slotDeletedObject(const Gui::ViewProvider& Obj)
|
||
{
|
||
// remove the view provider either from the left or the right view
|
||
if (Obj.getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) {
|
||
// remove the view provider immediately from the split window
|
||
bool found = false;
|
||
Gui::ViewProviderDocumentObject* vp = const_cast<Gui::ViewProviderDocumentObject*>
|
||
(static_cast<const Gui::ViewProviderDocumentObject*>(&Obj));
|
||
if (myAlignModel.activeGroup().hasView(vp)) {
|
||
myViewer->getViewer(0)->removeViewProvider(vp);
|
||
found = true;
|
||
}
|
||
if (myFixedGroup.hasView(vp)) {
|
||
myViewer->getViewer(1)->removeViewProvider(vp);
|
||
found = true;
|
||
}
|
||
|
||
if (found)
|
||
cancel();
|
||
}
|
||
}
|
||
|
||
void ManualAlignment::onAlign()
|
||
{
|
||
align();
|
||
}
|
||
|
||
void ManualAlignment::onRemoveLastPointMoveable()
|
||
{
|
||
int nPoints = myAlignModel.activeGroup().countPoints();
|
||
if (nPoints > 0) {
|
||
myAlignModel.activeGroup().removeLastPoint();
|
||
d->picksepLeft->removeChild(nPoints-1);
|
||
}
|
||
}
|
||
|
||
void ManualAlignment::onRemoveLastPointFixed()
|
||
{
|
||
int nPoints = myFixedGroup.countPoints();
|
||
if (nPoints > 0) {
|
||
myFixedGroup.removeLastPoint();
|
||
d->picksepRight->removeChild(nPoints-1);
|
||
}
|
||
}
|
||
|
||
void ManualAlignment::onClear()
|
||
{
|
||
myAlignModel.activeGroup().clear();
|
||
myFixedGroup.clear();
|
||
|
||
d->picksepLeft->removeAllChildren();
|
||
d->picksepRight->removeAllChildren();
|
||
}
|
||
|
||
void ManualAlignment::onCancel()
|
||
{
|
||
cancel();
|
||
}
|
||
|
||
void ManualAlignment::probePickedCallback(void * ud, SoEventCallback * n)
|
||
{
|
||
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
|
||
const SoEvent* ev = n->getEvent();
|
||
if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
|
||
// set as handled
|
||
n->getAction()->setHandled();
|
||
n->setHandled();
|
||
|
||
const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent *>(ev);
|
||
if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
|
||
// if we are in 'align' mode then handle the click event
|
||
ManualAlignment* self = ManualAlignment::instance();
|
||
// Get the closest point to the camera of the whole scene.
|
||
// This point doesn't need to be part of this view provider.
|
||
Gui::WaitCursor wc;
|
||
const SoPickedPoint * point = view->getPickedPoint(n);
|
||
if (point) {
|
||
Gui::ViewProvider* vp = static_cast<Gui::ViewProvider*>(view->getViewProviderByPath(point->getPath()));
|
||
if (vp && vp->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) {
|
||
Gui::ViewProviderDocumentObject* that = static_cast<Gui::ViewProviderDocumentObject*>(vp);
|
||
if (self->applyPickedProbe(that, point)) {
|
||
const SbVec3f& vec = point->getPoint();
|
||
Gui::getMainWindow()->showMessage(
|
||
tr("Point picked at (%1,%2,%3)")
|
||
.arg(vec[0]).arg(vec[1]).arg(vec[2]));
|
||
}
|
||
else {
|
||
Gui::getMainWindow()->showMessage(
|
||
tr("No point was found on model"));
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
Gui::getMainWindow()->showMessage(
|
||
tr("No point was picked"));
|
||
}
|
||
}
|
||
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) {
|
||
ManualAlignment* self = ManualAlignment::instance();
|
||
if (self->myAlignModel.isEmpty() || self->myFixedGroup.isEmpty())
|
||
return;
|
||
self->showInstructions();
|
||
int nPoints;
|
||
if (view == self->myViewer->getViewer(0))
|
||
nPoints = self->myAlignModel.activeGroup().countPoints();
|
||
else
|
||
nPoints = self->myFixedGroup.countPoints();
|
||
QMenu menu;
|
||
QAction* fi = menu.addAction(QLatin1String("&Align"));
|
||
QAction* rem = menu.addAction(QLatin1String("&Remove last point"));
|
||
//QAction* cl = menu.addAction("C&lear");
|
||
QAction* ca = menu.addAction(QLatin1String("&Cancel"));
|
||
fi->setEnabled(self->canAlign());
|
||
rem->setEnabled(nPoints > 0);
|
||
menu.addSeparator();
|
||
QAction* sync = menu.addAction(QLatin1String("&Synchronize views"));
|
||
sync->setCheckable(true);
|
||
if (self->d->sensorCam1->getAttachedNode())
|
||
sync->setChecked(true);
|
||
QAction* id = menu.exec(QCursor::pos());
|
||
if (id == fi) {
|
||
// call align->align();
|
||
QTimer::singleShot(300, self, SLOT(onAlign()));
|
||
}
|
||
else if ((id == rem) && (view == self->myViewer->getViewer(0))) {
|
||
QTimer::singleShot(300, self, SLOT(onRemoveLastPointMoveable()));
|
||
}
|
||
else if ((id == rem) && (view == self->myViewer->getViewer(1))) {
|
||
QTimer::singleShot(300, self, SLOT(onRemoveLastPointFixed()));
|
||
}
|
||
//else if (id == cl) {
|
||
// // call align->clear();
|
||
// QTimer::singleShot(300, self, SLOT(onClear()));
|
||
//}
|
||
else if (id == ca) {
|
||
// call align->cancel();
|
||
QTimer::singleShot(300, self, SLOT(onCancel()));
|
||
}
|
||
else if (id == sync) {
|
||
// setup sensor connection
|
||
if (sync->isChecked()) {
|
||
SoCamera* cam1 = self->myViewer->getViewer(0)->getSoRenderManager()->getCamera();
|
||
SoCamera* cam2 = self->myViewer->getViewer(1)->getSoRenderManager()->getCamera();
|
||
if (cam1 && cam2) {
|
||
self->d->sensorCam1->attach(cam1);
|
||
self->d->rot_cam1 = cam1->orientation.getValue();
|
||
self->d->pos_cam1 = cam1->position.getValue();
|
||
self->d->sensorCam2->attach(cam2);
|
||
self->d->rot_cam2 = cam2->orientation.getValue();
|
||
self->d->pos_cam2 = cam2->position.getValue();
|
||
}
|
||
}
|
||
else {
|
||
self->d->sensorCam1->detach();
|
||
self->d->sensorCam2->detach();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* This method stores the picked point \a pnt from the view provider \a prov. If enough points in both windows have been picked
|
||
* the alignment gets invoked.
|
||
*/
|
||
bool ManualAlignment::applyPickedProbe(Gui::ViewProviderDocumentObject* prov, const SoPickedPoint* pnt)
|
||
{
|
||
const SbVec3f& vec = pnt->getPoint();
|
||
const SbVec3f& nor = pnt->getNormal();
|
||
|
||
// add to the list for the non-aligned view in the left view
|
||
if (myAlignModel.activeGroup().hasView(prov)) {
|
||
std::vector<Base::Vector3d> pts = prov->getModelPoints(pnt);
|
||
if (pts.empty())
|
||
return false;
|
||
myAlignModel.activeGroup().addPoint(pts.front());
|
||
// Adds a point marker for the picked point.
|
||
d->picksepLeft->addChild(pickedPointsSubGraph(vec, nor, myAlignModel.activeGroup().countPoints()));
|
||
return true;
|
||
}
|
||
else if (myFixedGroup.hasView(prov)) {
|
||
std::vector<Base::Vector3d> pts = prov->getModelPoints(pnt);
|
||
if (pts.empty())
|
||
return false;
|
||
myFixedGroup.addPoint(pts.front());
|
||
// Adds a point marker for the picked point.
|
||
d->picksepRight->addChild(pickedPointsSubGraph(vec, nor, myFixedGroup.countPoints()));
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#include "moc_ManualAlignment.cpp"
|
||
|