diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 431ec584e..5ef714b33 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -75,17 +75,25 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) { } catch(dcm::solving_error& e) { - Base::Console().Error("Solver failed with error %i: %s", + Base::Console().Error("Solver failed with error %i: %s\n", *boost::get_error_info(e), boost::get_error_info(e)->c_str()); } catch(dcm::creation_error& e) { - Base::Console().Error("Creation failed with error %i: %s", + Base::Console().Error("Creation failed with error %i: %s\n", + *boost::get_error_info(e), + boost::get_error_info(e)->c_str()); + } + catch(boost::exception& e) { + Base::Console().Error("Solver exception raised: %i: %s\n", *boost::get_error_info(e), boost::get_error_info(e)->c_str()); } catch(std::exception& e) { - Base::Console().Error("Exception raised in assembly solver: %s", e.what()); + Base::Console().Error("Exception raised in assembly solver: %s\n", e.what()); + } + catch(...) { + Base::Console().Error("Unknown Exception raised in assembly solver during execution\n"); }; this->touch(); return App::DocumentObject::StdReturn; diff --git a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp index 23893ac3f..df4764556 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp @@ -22,12 +22,107 @@ #include #include "distance.hpp" +#include "coincident.hpp" namespace dcm { -struct Alignment : public constraint_sequence< fusion::vector2< Distance, Orientation > > { +namespace details { +//we need a custom orientation type to allow coincidents with points. We can't use the ci_orietation +//as some geometries are supporte by align but not by coincident +struct al_orientation : public Equation { + + using Equation::operator=; + using Equation::options; + al_orientation() : Equation() { + setDefault(); + }; + + al_orientation& operator=(const al_orientation& d) { + return Equation::operator=(d); + }; + + void setDefault() { + fusion::at_key(values) = std::make_pair(false, parallel); + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + type() { + throw constraint_error() << boost::errinfo_errno(103) << error_message("unsupported geometry in alignment orientation constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + typename al_orientation::options values; + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { + assert(false); + return 0; + }; + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { + assert(false); + return 0; + }; + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { + assert(false); + return 0; + }; + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { + assert(false); + }; + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { + assert(false); + }; + }; +}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::line3D, tag::line3D > : public ci_orientation::type< Kernel, tag::line3D, tag::line3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::line3D, tag::plane3D > : public ci_orientation::type< Kernel, tag::line3D, tag::plane3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::cylinder3D > { + //we missuse the scale method to change whatever direction was set to the only valid one: perpendicular + void setScale(typename Kernel::number_type scale) { + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D >::values).second = perpendicular; + }; +}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; + - using constraint_sequence::operator=; +}; //namespace details + +//use al_orientation to ensure the correct orientations for alignment (distance is only defined for special +//orientations) +struct Alignment : public constraint_sequence< fusion::vector2< Distance, details::al_orientation > > { + + using constraint_sequence::operator=; }; static Alignment alignment; diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index 566075453..86fb69016 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -35,7 +35,7 @@ struct ci_orientation : public Equation { ci_orientation() : Equation() { setDefault(); }; - + ci_orientation& operator=(const ci_orientation& d) { return Equation::operator=(d); }; @@ -138,19 +138,48 @@ template< typename Kernel > struct ci_orientation::type< Kernel, tag::point3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::point3D, tag::point3D > {}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::line3D > {}; +struct ci_orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::line3D > { + //we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::line3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::line3D >::values).second = parallel; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D > {}; +struct ci_orientation::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D > { + //we missuse the scale method to change whatever direction was set to the only valid one: perpendicular + void setScale(typename Kernel::number_type scale) { + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D >::values).second = perpendicular; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D > {}; +struct ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D > { + //we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D >::values).second = parallel; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D > {}; +struct ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D > { +//we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D >::values).second = parallel; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; +struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > { + //we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D >::values).second = parallel; + }; +}; @@ -162,7 +191,7 @@ struct ci_distance : public Equation : public Distance: typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; + using Distance::type< Kernel, tag::line3D, tag::line3D >::sc_value; + Scalar result; + SolutionSpace sspace; #ifdef USE_LOGGING type() : Distance::type< Kernel, tag::line3D, tag::line3D >() { @@ -578,11 +581,22 @@ struct Distance::type< Kernel, tag::line3D, tag::cylinder3D > : public Distance: }; #endif + void setScale(Scalar scale) { + Distance::type< Kernel, tag::line3D, tag::line3D >::setScale(scale); + sspace = fusion::at_key(Distance::type< Kernel, tag::line3D, tag::line3D >::values).second; + }; + template Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance - const Scalar res = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2); - return res - param2(6); + result = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2) - param2(6); + + //for parallel line and cylinder we may use the solution space methods + if(Kernel::isSame(Distance::type< Kernel, tag::line3D, tag::line3D >::nxn_n, 0, 1e-6) && + (sspace==negative_directional || (sspace == bidirectional && (result+sc_value)<0.))) + return result+2*sc_value; + + return result; }; template diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp index 7f8b504ba..f93eebf22 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -47,7 +47,8 @@ inline typename Kernel::number_type calc(const E::MatrixBase& d1, return (d1+d2).norm(); case perpendicular: return d1.dot(d2); - default: + default + : assert(false); } return 0; @@ -265,13 +266,9 @@ struct Orientation::type< Kernel, tag::line3D, tag::plane3D > : public Orientati options values; - dcm::Direction getValue() { - dcm::Direction value = fusion::at_key(values).second; - if(value==parallel) - return perpendicular; - if(value==perpendicular) - return parallel; - return value; + //makes it possible to allow only partial directions for derived constraints + inline dcm::Direction getValue() { + return fusion::at_key(values).second; }; //template definition diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp index b4e9a265c..7e27153b0 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp @@ -108,6 +108,7 @@ TaskAssemblyConstraints::TaskAssemblyConstraints(ViewProviderConstraint* vp) setPossibleConstraints(); + setPossibleOptions(); //setup all signals for event processing QObject::connect( @@ -188,7 +189,8 @@ void TaskAssemblyConstraints::setOrientation(dcm::Direction d) case dcm::opposite: ui->opposite->setChecked(true); break; - default: + default + : ui->parallel->setChecked(true); } } @@ -212,7 +214,8 @@ void TaskAssemblyConstraints::setSolutionSpace(dcm::SolutionSpace d) case dcm::positiv_directional: ui->pos_direction->setChecked(true); break; - default: + default + : ui->neg_direction->setChecked(true); } } @@ -246,6 +249,7 @@ void TaskAssemblyConstraints::onSelectionChanged(const Gui::SelectionChanges& ms App::GetApplication().getActiveDocument()->recompute(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); return; } @@ -268,6 +272,7 @@ void TaskAssemblyConstraints::onSelectionChanged(const Gui::SelectionChanges& ms App::GetApplication().getActiveDocument()->recompute(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); return; } @@ -300,6 +305,7 @@ void TaskAssemblyConstraints::on_constraint_selection(bool clicked) App::GetApplication().getActiveDocument()->recompute(); view->draw(); } + setPossibleOptions(); } @@ -341,6 +347,7 @@ void TaskAssemblyConstraints::on_clear_first() obj->First.setValue(NULL); ui->first_geom->clear(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); } @@ -351,11 +358,107 @@ void TaskAssemblyConstraints::on_clear_second() obj->Second.setValue(NULL); ui->second_geom->clear(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); } +void TaskAssemblyConstraints::setPossibleOptions() { + + //disable all orientations for later easy disabling + ui->parallel->setEnabled(false); + ui->equal->setEnabled(false); + ui->opposite->setEnabled(false); + ui->perpendicular->setEnabled(false); + + //disable solution spaces for later easy enabling + ui->bidirectional->setEnabled(false); + ui->pos_direction->setEnabled(false); + ui->neg_direction->setEnabled(false); + + //this only works if both objects are set + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + if(obj->First.getValue()) { + + Assembly::ItemPart* p1 = dynamic_cast(obj->First.getValue()); + if(!p1) + return; + + Assembly::ItemAssembly* ass = p1->getParentAssembly(); + + //extract the geometries to use for comparison + boost::shared_ptr g1 = ass->m_solver->getGeometry3D(obj->First.getSubValues()[0].c_str()); + if(obj->Second.getValue()) { + + Assembly::ItemPart* p2 = dynamic_cast(obj->Second.getValue()); + if(!p2) + return; + boost::shared_ptr g2 = ass->m_solver->getGeometry3D(obj->Second.getSubValues()[0].c_str()); + + //distance + if(obj->Type.getValue() == 1) { + + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::point, dcm::geometry::cylinder)) { + ui->bidirectional->setEnabled(true); + ui->pos_direction->setEnabled(true); + ui->neg_direction->setEnabled(true); + }; + }; + //align & coincident + if(obj->Type.getValue() == 4 || obj->Type.getValue() == 5) { + + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::point, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { + ui->bidirectional->setEnabled(true); + ui->pos_direction->setEnabled(true); + ui->neg_direction->setEnabled(true); + }; + + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder)) { + ui->parallel->setEnabled(true); + ui->equal->setEnabled(true); + ui->opposite->setEnabled(true); + + //ensure that perpendicular is not checked + if(ui->perpendicular->isChecked()) { + ui->parallel->setChecked(true); + obj->Orientation.setValue((long)0); + } + }; + + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { + ui->perpendicular->setEnabled(true); + + //ensure that perpendicular is checked + if(!ui->perpendicular->isChecked()) { + ui->perpendicular->setChecked(true); + obj->Orientation.setValue((long)3); + } + }; + }; + + //orientation + if(obj->Type.getValue() == 2) { + ui->parallel->setEnabled(true); + ui->equal->setEnabled(true); + ui->opposite->setEnabled(true); + ui->perpendicular->setEnabled(true); + } + + } + } +}; + void TaskAssemblyConstraints::setPossibleConstraints() { + //diasble all constraints for easyer enabling ui->fix->setEnabled(false); ui->distance->setEnabled(false); ui->orientation->setEnabled(false); @@ -428,11 +531,12 @@ void TaskAssemblyConstraints::setPossibleConstraints() if(isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { ui->orientation->setEnabled(true); ui->angle->setEnabled(true); - ui->coincident->setEnabled(true); ui->align->setEnabled(true); }; if(isCombination(g1,g2, dcm::geometry::cylinder, dcm::geometry::cylinder)) { ui->coincident->setEnabled(true); + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); }; } else { diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h index 7f176faef..a745ce53f 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h @@ -67,6 +67,7 @@ private: void setSolutionSpace(dcm::SolutionSpace d); dcm::SolutionSpace getSolutionSpace(); void setPossibleConstraints(); + void setPossibleOptions(); bool isCombination(boost::shared_ptr g1, boost::shared_ptr g2, dcm::geometry::types t1, dcm::geometry::types t2); };