1271 lines
41 KiB
C++
1271 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::WindowFlags 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 (myViewer->parentWidget())
|
|
myViewer->parentWidget()->deleteLater();
|
|
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ö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"
|
|
|