Transform.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #include <QDialogButtonBox>
00026 #include <QSignalMapper>
00027 
00028 #include "Transform.h"
00029 #include "Selection.h"
00030 #include "ViewProvider.h"
00031 #include "ui_Placement.h"
00032 #include "Application.h"
00033 #include "Document.h"
00034 #include "WaitCursor.h"
00035 #include <App/PropertyGeo.h>
00036 #include <App/DocumentObject.h>
00037 
00038 using namespace Gui::Dialog;
00039 
00040 namespace Gui { namespace Dialog {
00041 class find_geometry_data
00042 {
00043 public:
00044     bool operator () (const std::pair<std::string, App::Property*>& elem) const
00045     {
00046         if (elem.first == "Points") {
00047             return elem.second->isDerivedFrom
00048                 (Base::Type::fromName("Points::PropertyPointKernel"));
00049         }
00050         else if (elem.first == "Mesh") {
00051             return elem.second->isDerivedFrom
00052                 (Base::Type::fromName("Mesh::PropertyMeshKernel"));
00053         }
00054         else if (elem.first == "Shape") {
00055             return elem.second->isDerivedFrom
00056                 (Base::Type::fromName("Part::PropertyPartShape"));
00057         }
00058 
00059         // any other geometry type
00060         return elem.second->isDerivedFrom
00061             (Base::Type::fromName("App::PropertyGeometry"));
00062     }
00063 };
00064 class find_placement
00065 {
00066 public:
00067     bool operator () (const std::pair<std::string, App::Property*>& elem) const
00068     {
00069         if (elem.first == "Placement") {
00070             return elem.second->isDerivedFrom
00071                 (Base::Type::fromName("App::PropertyPlacement"));
00072         }
00073 
00074         return false;
00075     }
00076 };
00077 }
00078 }
00079 
00080 // ----------------------------------------------------------------------------
00081 
00082 TransformStrategy::TransformStrategy()
00083 {
00084 }
00085 
00086 TransformStrategy::~TransformStrategy()
00087 {
00088 }
00089 
00090 Base::Vector3d TransformStrategy::getRotationCenter() const
00091 {
00092     // get the global bounding box of all selected objects and use its center as
00093     // rotation center
00094     std::set<App::DocumentObject*> objects = transformObjects();
00095     if (!objects.empty()) {
00096         Base::BoundBox3d bbox;
00097         bool first=true;
00098         for (std::set<App::DocumentObject*>::const_iterator it=objects.begin();it!=objects.end();++it) {
00099             std::map<std::string,App::Property*> props;
00100             (*it)->getPropertyMap(props);
00101             // search for a data property
00102             std::map<std::string,App::Property*>::iterator jt;
00103             jt = std::find_if(props.begin(), props.end(), find_geometry_data());
00104             if (jt != props.end()) {
00105                 if (first)
00106                     bbox = (static_cast<App::PropertyGeometry*>(jt->second)->getBoundingBox());
00107                 else
00108                     bbox.Add(static_cast<App::PropertyGeometry*>(jt->second)->getBoundingBox());
00109                 first = false;
00110             }
00111         }
00112 
00113         return Base::Vector3d((bbox.MinX+bbox.MaxX)/2,
00114                               (bbox.MinY+bbox.MaxY)/2,
00115                               (bbox.MinZ+bbox.MaxZ)/2);
00116     }
00117 
00118     return Base::Vector3d();
00119 }
00120 
00121 void TransformStrategy::commitTransform(const Base::Matrix4D& mat)
00122 {
00123     std::set<App::DocumentObject*> objects = transformObjects();
00124     Gui::Document* doc = Gui::Application::Instance->activeDocument();
00125     if (doc) {
00126         doc->openCommand("Transform");
00127         for (std::set<App::DocumentObject*>::iterator it=objects.begin();it!=objects.end();++it) {
00128             acceptDataTransform(mat, *it);
00129         }
00130         doc->commitCommand();
00131     }
00132 }
00133 
00134 void TransformStrategy::acceptDataTransform(const Base::Matrix4D& mat, App::DocumentObject* obj)
00135 {
00136     Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
00137     std::map<std::string,App::Property*> props;
00138     obj->getPropertyMap(props);
00139     // search for the placement property
00140     std::map<std::string,App::Property*>::iterator jt;
00141     jt = std::find_if(props.begin(), props.end(), find_placement());
00142     if (jt != props.end()) {
00143         Base::Placement local = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
00144         Gui::ViewProvider* vp = doc->getViewProvider(obj);
00145         if (vp) vp->setTransformation(local.toMatrix());
00146     }
00147     else {
00148         // No placement found
00149         Gui::ViewProvider* vp = doc->getViewProvider(obj);
00150         if (vp) vp->setTransformation(Base::Matrix4D());
00151     }
00152 
00153     // Apply the transformation
00154     jt = std::find_if(props.begin(), props.end(), find_geometry_data());
00155     if (jt != props.end()) {
00156         static_cast<App::PropertyGeometry*>(jt->second)->transformGeometry(mat);
00157     }
00158 }
00159 
00160 void TransformStrategy::applyTransform(const Base::Placement& plm)
00161 {
00162     std::set<App::DocumentObject*> objects = transformObjects();
00163     for (std::set<App::DocumentObject*>::iterator it=objects.begin();it!=objects.end();++it) {
00164         applyViewTransform(plm, *it);
00165     }
00166 }
00167 
00168 void TransformStrategy::resetTransform()
00169 {
00170     std::set<App::DocumentObject*> objects = transformObjects();
00171     for (std::set<App::DocumentObject*>::iterator it=objects.begin();it!=objects.end();++it) {
00172         resetViewTransform(*it);
00173     }
00174 }
00175 
00176 void TransformStrategy::applyViewTransform(const Base::Placement& plm, App::DocumentObject* obj)
00177 {
00178     Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
00179     std::map<std::string,App::Property*> props;
00180     obj->getPropertyMap(props);
00181     // search for the placement property
00182     std::map<std::string,App::Property*>::iterator jt;
00183     jt = std::find_if(props.begin(), props.end(), find_placement());
00184     if (jt != props.end()) {
00185         Base::Placement local = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
00186         local *= plm; // in case a placement is already set
00187         Gui::ViewProvider* vp = doc->getViewProvider(obj);
00188         if (vp) vp->setTransformation(local.toMatrix());
00189     }
00190     else {
00191         // No placement found, so apply the transformation directly
00192         Gui::ViewProvider* vp = doc->getViewProvider(obj);
00193         if (vp) vp->setTransformation(plm.toMatrix());
00194     }
00195 }
00196 
00197 void TransformStrategy::resetViewTransform(App::DocumentObject* obj)
00198 {
00199     Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
00200     std::map<std::string,App::Property*> props;
00201     obj->getPropertyMap(props);
00202     // search for the placement property
00203     std::map<std::string,App::Property*>::iterator jt;
00204     jt = std::find_if(props.begin(), props.end(), find_placement());
00205     if (jt != props.end()) {
00206         Base::Placement local = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
00207         Gui::ViewProvider* vp = doc->getViewProvider(obj);
00208         if (vp) vp->setTransformation(local.toMatrix());
00209     }
00210     else {
00211         // No placement found
00212         Gui::ViewProvider* vp = doc->getViewProvider(obj);
00213         if (vp) vp->setTransformation(Base::Matrix4D());
00214     }
00215 }
00216 
00217 // ----------------------------------------------------------------------------
00218 
00219 DefaultTransformStrategy::DefaultTransformStrategy(QWidget* w) : widget(w)
00220 {
00221     Gui::SelectionChanges mod;
00222     mod.Type = Gui::SelectionChanges::SetSelection;
00223     onSelectionChanged(mod);
00224 }
00225 
00226 DefaultTransformStrategy::~DefaultTransformStrategy()
00227 {
00228 }
00229 
00230 std::set<App::DocumentObject*> DefaultTransformStrategy::transformObjects() const
00231 {
00232     return selection;
00233 }
00234 
00235 void DefaultTransformStrategy::onSelectionChanged(const Gui::SelectionChanges& msg)
00236 {
00237     if (msg.Type == SelectionChanges::SetPreselect ||
00238         msg.Type == SelectionChanges::RmvPreselect)
00239         return; // nothing to do
00240     if (msg.Type == SelectionChanges::ClrSelection) {
00241         widget->setDisabled(true);
00242         for (std::set<App::DocumentObject*>::iterator it = selection.begin();
00243              it != selection.end(); ++it)
00244              resetViewTransform(*it);
00245         selection.clear();
00246         return;
00247     }
00248 
00249     std::set<App::DocumentObject*> update_selection;
00250     std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType
00251         (App::DocumentObject::getClassTypeId());
00252     for (std::vector<App::DocumentObject*>::iterator it=sel.begin();it!=sel.end();++it) {
00253         std::map<std::string,App::Property*> props;
00254         (*it)->getPropertyMap(props);
00255         // search for the placement property
00256         std::map<std::string,App::Property*>::iterator jt;
00257         jt = std::find_if(props.begin(), props.end(), find_geometry_data());
00258         if (jt != props.end()) {
00259             update_selection.insert(*it);
00260         }
00261     }
00262 
00263     // now we remove all objects which links to another object
00264     // of the selected objects because if the source object changes
00265     // it is touched and thus a recompute later would overwrite the
00266     // changes here anyway
00267     std::set<App::DocumentObject*> filter;
00268     for (std::set<App::DocumentObject*>::iterator it=update_selection.begin();
00269         it!=update_selection.end();++it) {
00270         std::vector<App::DocumentObject*> deps = (*it)->getOutList();
00271         std::vector<App::DocumentObject*>::iterator jt;
00272         for (jt = deps.begin(); jt != deps.end(); ++jt) {
00273             if (update_selection.find(*jt) != update_selection.end()) {
00274                 filter.insert(*it);
00275                 break;
00276             }
00277         }
00278     }
00279 
00280     if (!filter.empty()) {
00281         std::set<App::DocumentObject*> diff;
00282         std::insert_iterator< std::set<App::DocumentObject*> > biit(diff, diff.begin());
00283         std::set_difference(update_selection.begin(), update_selection.end(),
00284             filter.begin(), filter.end(), biit);
00285         update_selection = diff;
00286     }
00287 
00288     // reset transform for all deselected objects
00289     std::vector<App::DocumentObject*> diff;
00290     std::back_insert_iterator< std::vector<App::DocumentObject*> > biit(diff);
00291     std::set_difference(selection.begin(), selection.end(),
00292         update_selection.begin(), update_selection.end(), biit);
00293     for (std::vector<App::DocumentObject*>::iterator it = diff.begin(); it != diff.end(); ++it)
00294          resetViewTransform(*it);
00295     selection = update_selection;
00296 
00297     widget->setDisabled(selection.empty());
00298 }
00299 
00300 // ----------------------------------------------------------------------------
00301 
00302 /* TRANSLATOR Gui::Dialog::Transform */
00303 
00304 Transform::Transform(QWidget* parent, Qt::WFlags fl)
00305   : Gui::LocationDialog(parent, fl), strategy(0)
00306 {
00307     ui = new Ui_TransformComp(this);
00308     ui->resetButton->hide();
00309     ui->applyPlacementChange->hide();
00310     ui->applyIncrementalPlacement->hide();
00311 
00312     ui->angle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00313     ui->yawAngle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00314     ui->pitchAngle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00315     ui->rollAngle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00316 
00317     ui->closeButton->setText(tr("Cancel"));
00318     this->setWindowTitle(tr("Transform"));
00319 
00320     // create a signal mapper in order to have one slot to perform the change
00321     QSignalMapper* signalMapper = new QSignalMapper(this);
00322     connect(this, SIGNAL(directionChanged()), signalMapper, SLOT(map()));
00323     signalMapper->setMapping(this, 0);
00324 
00325     int id = 1;
00326     QList<QDoubleSpinBox*> sb = this->findChildren<QDoubleSpinBox*>();
00327     for (QList<QDoubleSpinBox*>::iterator it = sb.begin(); it != sb.end(); ++it) {
00328         connect(*it, SIGNAL(valueChanged(double)), signalMapper, SLOT(map()));
00329         signalMapper->setMapping(*it, id++);
00330     }
00331 
00332     connect(signalMapper, SIGNAL(mapped(int)),
00333             this, SLOT(onTransformChanged(int)));
00334 
00335     setTransformStrategy(new DefaultTransformStrategy(this));
00336 }
00337 
00338 Transform::~Transform()
00339 {
00340     delete ui;
00341     delete strategy;
00342 }
00343 
00344 void Transform::setTransformStrategy(TransformStrategy* ts)
00345 {
00346     if (!ts || ts == strategy)
00347         return;
00348     if (strategy)
00349         delete strategy;
00350     strategy = ts;
00351     Base::Vector3d cnt = strategy->getRotationCenter();
00352     ui->xCnt->setValue(cnt.x);
00353     ui->yCnt->setValue(cnt.y);
00354     ui->zCnt->setValue(cnt.z);
00355     this->setDisabled(strategy->transformObjects().empty());
00356 }
00357 
00358 void Transform::showStandardButtons(bool b)
00359 {
00360     ui->closeButton->setVisible(b);
00361     ui->oKButton->setVisible(b);
00362     ui->applyButton->setVisible(b);
00363 }
00364 
00365 void Transform::onTransformChanged(int)
00366 {
00367     Base::Placement plm = this->getPlacementData();
00368     strategy->applyTransform(plm);
00369 }
00370 
00371 void Transform::accept()
00372 {
00373     on_applyButton_clicked();
00374     QDialog::accept();
00375 }
00376 
00377 void Transform::reject()
00378 {
00379     strategy->resetTransform();
00380     QDialog::reject();
00381 }
00382 
00383 void Transform::on_applyButton_clicked()
00384 {
00385     Gui::WaitCursor wc;
00386     Base::Placement plm = this->getPlacementData();
00387     Base::Matrix4D mat = plm.toMatrix();
00388     strategy->commitTransform(mat);
00389 
00390     // nullify the values
00391     QList<QDoubleSpinBox*> sb = this->findChildren<QDoubleSpinBox*>();
00392     for (QList<QDoubleSpinBox*>::iterator it = sb.begin(); it != sb.end(); ++it) {
00393         (*it)->blockSignals(true);
00394         (*it)->setValue(0.0);
00395         (*it)->blockSignals(false);
00396     }
00397 
00398     Base::Vector3d cnt = strategy->getRotationCenter();
00399     ui->xCnt->setValue(cnt.x);
00400     ui->yCnt->setValue(cnt.y);
00401     ui->zCnt->setValue(cnt.z);
00402 }
00403 
00404 void Transform::directionActivated(int index)
00405 {
00406     if (ui->directionActivated(this, index)) {
00407         /*emit*/ directionChanged();
00408     }
00409 }
00410 
00411 Base::Vector3f Transform::getDirection() const
00412 {
00413     return ui->getDirection();
00414 }
00415 
00416 Base::Placement Transform::getPlacementData() const
00417 {
00418     int index = ui->rotationInput->currentIndex();
00419     Base::Rotation rot;
00420     Base::Vector3d pos;
00421     Base::Vector3d cnt;
00422 
00423     pos = Base::Vector3d(ui->xPos->value(),ui->yPos->value(),ui->zPos->value());
00424     cnt = Base::Vector3d(ui->xCnt->value(),ui->yCnt->value(),ui->zCnt->value());
00425 
00426     if (index == 0) {
00427         Base::Vector3f dir = getDirection();
00428         rot.setValue(Base::Vector3d(dir.x,dir.y,dir.z),ui->angle->value()*D_PI/180.0);
00429     }
00430     else if (index == 1) {
00431         rot.setYawPitchRoll(
00432             ui->yawAngle->value(),
00433             ui->pitchAngle->value(),
00434             ui->rollAngle->value());
00435     }
00436 
00437     Base::Placement p(pos, rot, cnt);
00438     return p;
00439 }
00440 
00441 void Transform::changeEvent(QEvent *e)
00442 {
00443     if (e->type() == QEvent::LanguageChange) {
00444         ui->retranslate(this);
00445         ui->closeButton->setText(tr("Cancel"));
00446         this->setWindowTitle(tr("Transform"));
00447     }
00448     else {
00449         QDialog::changeEvent(e);
00450     }
00451 }
00452 
00453 // ---------------------------------------
00454 
00455 TaskTransform::TaskTransform()
00456 {
00457     this->setButtonPosition(TaskTransform::South);
00458     dialog = new Transform();
00459     dialog->showStandardButtons(false);
00460     taskbox = new Gui::TaskView::TaskBox(QPixmap(), dialog->windowTitle(), true, 0);
00461     taskbox->groupLayout()->addWidget(dialog);
00462     Content.push_back(taskbox);
00463 }
00464 
00465 TaskTransform::~TaskTransform()
00466 {
00467     // automatically deleted in the sub-class
00468 }
00469 
00470 void TaskTransform::setTransformStrategy(TransformStrategy* ts)
00471 {
00472     dialog->setTransformStrategy(ts);
00473 }
00474 
00475 bool TaskTransform::accept()
00476 {
00477     dialog->accept();
00478     return (dialog->result() == QDialog::Accepted);
00479 }
00480 
00481 bool TaskTransform::reject()
00482 {
00483     dialog->reject();
00484     return (dialog->result() == QDialog::Rejected);
00485 }
00486 
00487 void TaskTransform::clicked(int id)
00488 {
00489     if (id == QDialogButtonBox::Apply) {
00490         dialog->on_applyButton_clicked();
00491     }
00492 }
00493 
00494 #include "moc_Transform.cpp"

Generated on Wed Nov 23 19:00:50 2011 for FreeCAD by  doxygen 1.6.1