diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 9c9399ccb..d70734bfa 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -987,8 +987,10 @@ void Document::restore (void) reader.readFiles(zipstream); // reset all touched - for (std::map::iterator It= d->objectMap.begin();It!=d->objectMap.end();++It) + for (std::map::iterator It= d->objectMap.begin();It!=d->objectMap.end();++It) { + It->second->onDocumentRestored(); It->second->purgeTouched(); + } GetApplication().signalRestoreDocument(*this); } diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 9658d6527..48c3f6751 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -179,6 +179,8 @@ protected: virtual void onBeforeChange(const Property* prop); /// get called by the container when a property was changed virtual void onChanged(const Property* prop); + /// get called after a document has been fully restored + virtual void onDocumentRestored() {} /// python object of this class and all descendend protected: // attributes diff --git a/src/Gui/CallTips.cpp b/src/Gui/CallTips.cpp index 25a3ccc11..72aa941c1 100644 --- a/src/Gui/CallTips.cpp +++ b/src/Gui/CallTips.cpp @@ -156,6 +156,13 @@ void CallTipsList::validateCursor() cursor.setPosition(this->cursorPos); cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); QString word = cursor.selectedText(); + if (!word.isEmpty()) { + // the following text might be an operator, brackets, ... + const QChar underscore = QLatin1Char('_'); + const QChar ch = word.at(0); + if (!ch.isLetterOrNumber() && ch != underscore) + word.clear(); + } if (currentPos > this->cursorPos+word.length()) { hide(); } diff --git a/src/Gui/InputVector.cpp b/src/Gui/InputVector.cpp index 4d1d2a6e8..de8683dfc 100644 --- a/src/Gui/InputVector.cpp +++ b/src/Gui/InputVector.cpp @@ -22,12 +22,195 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif #include "InputVector.h" #include "ui_InputVector.h" using namespace Gui; +LocationWidget::LocationWidget (QWidget * parent) + : QWidget(parent) +{ + box = new QGridLayout(); + + xValue = new QDoubleSpinBox(this); + xValue->setMinimum(-2.14748e+09); + xValue->setMaximum(2.14748e+09); + xLabel = new QLabel(this); + box->addWidget(xLabel, 0, 0, 1, 1); + box->addWidget(xValue, 0, 1, 1, 1); + + yValue = new QDoubleSpinBox(this); + yValue->setMinimum(-2.14748e+09); + yValue->setMaximum(2.14748e+09); + yLabel = new QLabel(this); + box->addWidget(yLabel, 1, 0, 1, 1); + box->addWidget(yValue, 1, 1, 1, 1); + + zValue = new QDoubleSpinBox(this); + zValue->setMinimum(-2.14748e+09); + zValue->setMaximum(2.14748e+09); + zLabel = new QLabel(this); + box->addWidget(zLabel, 2, 0, 1, 1); + box->addWidget(zValue, 2, 1, 1, 1); + + dLabel = new QLabel(this); + dValue = new QComboBox(this); + dValue->setCurrentIndex(-1); + box->addWidget(dLabel, 3, 0, 1, 1); + box->addWidget(dValue, 3, 1, 1, 1); + + QGridLayout* gridLayout = new QGridLayout(this); + gridLayout->addLayout(box, 0, 0, 1, 2); + + connect(dValue, SIGNAL(activated(int)), + this, SLOT(on_direction_activated(int))); + retranslateUi(); +} + +LocationWidget::~LocationWidget() +{ +} + +QSize LocationWidget::sizeHint() const +{ + return QSize(150,100); +} + +void LocationWidget::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::LanguageChange) { + this->retranslateUi(); + } + QWidget::changeEvent(e); +} + +void LocationWidget::retranslateUi() +{ + xLabel->setText(QApplication::translate("Gui::LocationWidget", "X:")); + yLabel->setText(QApplication::translate("Gui::LocationWidget", "Y:")); + zLabel->setText(QApplication::translate("Gui::LocationWidget", "Z:")); + dLabel->setText(QApplication::translate("Gui::LocationWidget", "Direction:")); + + if (dValue->count() == 0) { + dValue->insertItems(0, QStringList() + << QApplication::translate("Gui::LocationDialog", "X") + << QApplication::translate("Gui::LocationDialog", "Y") + << QApplication::translate("Gui::LocationDialog", "Z") + << QApplication::translate("Gui::LocationDialog", "User defined...") + ); + + dValue->setCurrentIndex(2); + + // Vector3f declared to use with QVariant see Gui/propertyeditor/PropertyItem.h + dValue->setItemData(0, QVariant::fromValue(Base::Vector3f(1,0,0))); + dValue->setItemData(1, QVariant::fromValue(Base::Vector3f(0,1,0))); + dValue->setItemData(2, QVariant::fromValue(Base::Vector3f(0,0,1))); + } + else { + dValue->setItemText(0, QApplication::translate("Gui::LocationDialog", "X")); + dValue->setItemText(1, QApplication::translate("Gui::LocationDialog", "Y")); + dValue->setItemText(2, QApplication::translate("Gui::LocationDialog", "Z")); + dValue->setItemText(dValue->count()-1, + QApplication::translate("Gui::LocationDialog", "User defined...")); + } +} + +Base::Vector3f LocationWidget::getPosition() const +{ + return Base::Vector3f((float)this->xValue->value(), + (float)this->yValue->value(), + (float)this->zValue->value()); +} + +void LocationWidget::setPosition(const Base::Vector3f& v) +{ + this->xValue->setValue(v.x); + this->yValue->setValue(v.y); + this->zValue->setValue(v.z); +} + +void LocationWidget::setDirection(const Base::Vector3f& dir) +{ + if (dir.Length() < FLT_EPSILON) { + return; + } + + // check if the user-defined direction is already there + for (int i=0; icount()-1; i++) { + QVariant data = dValue->itemData (i); + if (data.canConvert()) { + const Base::Vector3f val = data.value(); + if (val == dir) { + dValue->setCurrentIndex(i); + return; + } + } + } + + // add a new item before the very last item + QString display = QString::fromAscii("(%1,%2,%3)") + .arg(dir.x) + .arg(dir.y) + .arg(dir.z); + dValue->insertItem(dValue->count()-1, display, + QVariant::fromValue(dir)); + dValue->setCurrentIndex(dValue->count()-2); +} + +Base::Vector3f LocationWidget::getDirection() const +{ + QVariant data = dValue->itemData (this->dValue->currentIndex()); + if (data.canConvert()) { + return data.value(); + } + else { + return Base::Vector3f(0,0,1); + } +} + +Base::Vector3f LocationWidget::getUserDirection(bool* ok) const +{ + Gui::Dialog::Ui_InputVector iv; + QDialog dlg(const_cast(this)); + iv.setupUi(&dlg); + Base::Vector3f dir; + if (dlg.exec()) { + dir.x = (float)iv.vectorX->value(); + dir.y = (float)iv.vectorY->value(); + dir.z = (float)iv.vectorZ->value(); + if (ok) *ok = true; + } + else { + if (ok) *ok = false; + } + + return dir; +} + +void LocationWidget::on_direction_activated(int index) +{ + // last item is selected to define direction by user + if (index+1 == dValue->count()) { + bool ok; + Base::Vector3f dir = this->getUserDirection(&ok); + if (ok) { + if (dir.Length() < FLT_EPSILON) { + QMessageBox::critical(this, LocationDialog::tr("Wrong direction"), + LocationDialog::tr("Direction must not be the null vector")); + return; + } + + setDirection(dir); + } + } +} + +// ---------------------------------------------------------------------------- + LocationDialog::LocationDialog(QWidget* parent, Qt::WFlags fl) : QDialog(parent, fl) { diff --git a/src/Gui/InputVector.h b/src/Gui/InputVector.h index 4508e1986..b5c101251 100644 --- a/src/Gui/InputVector.h +++ b/src/Gui/InputVector.h @@ -30,8 +30,47 @@ #include +class QGridLayout; +class QLabel; +class QDoubleSpinBox; +class QComboBox; + namespace Gui { +class GuiExport LocationWidget : public QWidget +{ + Q_OBJECT + +public: + LocationWidget (QWidget * parent = 0); + virtual ~LocationWidget(); + QSize sizeHint() const; + + Base::Vector3f getPosition() const; + void setPosition(const Base::Vector3f&); + void setDirection(const Base::Vector3f& dir); + Base::Vector3f getDirection() const; + Base::Vector3f getUserDirection(bool* ok=0) const; + +private Q_SLOTS: + void on_direction_activated(int); + +private: + void changeEvent(QEvent*); + void retranslateUi(); + +private: + QGridLayout *box; + QLabel *xLabel; + QLabel *yLabel; + QLabel *zLabel; + QLabel *dLabel; + QDoubleSpinBox *xValue; + QDoubleSpinBox *yValue; + QDoubleSpinBox *zValue; + QComboBox *dValue; +}; + /** This is the base dialog class that defines the interface for * specifying a direction vector by the user. * @author Werner Mayer diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index a9ce79959..cc4f66ffb 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -548,8 +548,20 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) restartHistory = false; } break; - case Qt::Key_Backspace: case Qt::Key_Left: + { + if (cursor > inputLineBegin) + { TextEdit::keyPressEvent(e); } + restartHistory = false; + } break; + + case Qt::Key_Right: + { + TextEdit::keyPressEvent(e); + restartHistory = false; + } break; + + case Qt::Key_Backspace: { if (cursor > inputLineBegin) { TextEdit::keyPressEvent(e); } diff --git a/src/Mod/Drawing/App/FeatureProjection.cpp b/src/Mod/Drawing/App/FeatureProjection.cpp index a0905952c..50a8e088b 100644 --- a/src/Mod/Drawing/App/FeatureProjection.cpp +++ b/src/Mod/Drawing/App/FeatureProjection.cpp @@ -26,6 +26,7 @@ #ifndef _PreComp_ # include # include +# include # include #endif diff --git a/src/Mod/Drawing/Gui/TaskOrthoViews.cpp b/src/Mod/Drawing/Gui/TaskOrthoViews.cpp index 4cb50e288..055244a6a 100644 --- a/src/Mod/Drawing/Gui/TaskOrthoViews.cpp +++ b/src/Mod/Drawing/Gui/TaskOrthoViews.cpp @@ -39,6 +39,7 @@ #include #include #include +#include using namespace Gui; using namespace DrawingGui; diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index f4a1d4093..3905c2644 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -157,7 +157,7 @@ void PartExport initPart() Part::Polygon ::init(); Part::Circle ::init(); Part::Vertex ::init(); - Part::Edge ::init(); + Part::Line ::init(); Part::Ellipsoid ::init(); Part::Plane ::init(); Part::Sphere ::init(); diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index d24476215..40c81da59 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -119,6 +119,7 @@ SOURCE_GROUP("Features" FILES ${Features_SRCS}) IF(MSVC) SET_SOURCE_FILES_PROPERTIES(FeatureFillet.cpp PROPERTIES COMPILE_FLAGS "/EHa") SET_SOURCE_FILES_PROPERTIES(FeaturePartBoolean.cpp PROPERTIES COMPILE_FLAGS "/EHa") +SET_SOURCE_FILES_PROPERTIES(FeatureExtrusion.cpp PROPERTIES COMPILE_FLAGS "/EHa") ENDIF(MSVC) SET(Properties_SRCS @@ -229,6 +230,7 @@ SET(Part_SRCS edgecluster.h modelRefine.cpp modelRefine.h + Tools.h ) SET(Part_Scripts diff --git a/src/Mod/Part/App/FeatureExtrusion.cpp b/src/Mod/Part/App/FeatureExtrusion.cpp index 6633d2e39..9b9aa70e2 100644 --- a/src/Mod/Part/App/FeatureExtrusion.cpp +++ b/src/Mod/Part/App/FeatureExtrusion.cpp @@ -23,10 +23,24 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif #include "FeatureExtrusion.h" +#include +#include using namespace Part; @@ -38,12 +52,16 @@ Extrusion::Extrusion() { ADD_PROPERTY(Base,(0)); ADD_PROPERTY(Dir,(Base::Vector3f(0.0f,0.0f,1.0f))); + ADD_PROPERTY(Solid,(false)); + ADD_PROPERTY(TaperAngle,(0.0f)); } short Extrusion::mustExecute() const { if (Base.isTouched() || - Dir.isTouched() ) + Dir.isTouched() || + Solid.isTouched() || + TaperAngle.isTouched()) return 1; return 0; } @@ -59,13 +77,78 @@ App::DocumentObjectExecReturn *Extrusion::execute(void) Base::Vector3f v = Dir.getValue(); gp_Vec vec(v.x,v.y,v.z); + float taperAngle = TaperAngle.getValue(); + bool makeSolid = Solid.getValue(); try { - // Now, let's get the TopoDS_Shape - TopoDS_Shape swept = base->Shape.getShape().makePrism(vec); - if (swept.IsNull()) - return new App::DocumentObjectExecReturn("Resulting shape is null"); - this->Shape.setValue(swept); + if (std::fabs(taperAngle) >= Precision::Confusion()) { +#if defined(__GNUC__) && defined (FC_OS_LINUX) + Base::SignalException se; +#endif + double distance = std::tan(Base::toRadians(taperAngle)) * vec.Magnitude(); + const TopoDS_Shape& shape = base->Shape.getValue(); + bool isWire = (shape.ShapeType() == TopAbs_WIRE); + bool isFace = (shape.ShapeType() == TopAbs_FACE); + if (!isWire && !isFace) + return new App::DocumentObjectExecReturn("Only a wire or a face is supported"); + + std::list wire_list; + BRepOffsetAPI_MakeOffset mkOffset; + if (isWire) { +#if 1 //OCC_HEX_VERSION < 0x060502 + // The input wire may have erorrs in its topology + // and thus may cause a crash in the Perfrom() method + // See also: + // http://www.opencascade.org/org/forum/thread_17640/ + // http://www.opencascade.org/org/forum/thread_12012/ + ShapeFix_Wire aFix; + aFix.Load(TopoDS::Wire(shape)); + aFix.FixReorder(); + aFix.FixConnected(); + aFix.FixClosed(); + mkOffset.AddWire(aFix.Wire()); + wire_list.push_back(aFix.Wire()); +#else + mkOffset.AddWire(TopoDS::Wire(shape)); +#endif + } + else if (isFace) { + TopoDS_Wire outerWire = ShapeAnalysis::OuterWire(TopoDS::Face(shape)); + wire_list.push_back(outerWire); + mkOffset.AddWire(outerWire); + } + + mkOffset.Perform(distance); + + gp_Trsf mat; + mat.SetTranslation(vec); + BRepBuilderAPI_Transform mkTransform(mkOffset.Shape(),mat); + wire_list.push_back(TopoDS::Wire(mkTransform.Shape())); + + BRepOffsetAPI_ThruSections mkGenerator(makeSolid ? Standard_True : Standard_False, Standard_False); + for (std::list::const_iterator it = wire_list.begin(); it != wire_list.end(); ++it) { + const TopoDS_Wire &wire = *it; + mkGenerator.AddWire(wire); + } + + mkGenerator.Build(); + this->Shape.setValue(mkGenerator.Shape()); + } + else { + // Now, let's get the TopoDS_Shape + TopoDS_Shape myShape = base->Shape.getValue(); + if (myShape.IsNull()) + Standard_Failure::Raise("Cannot extrude empty shape"); + if (makeSolid && myShape.ShapeType() == TopAbs_WIRE) { + BRepBuilderAPI_MakeFace mkFace(TopoDS::Wire(myShape)); + myShape = mkFace.Face(); + } + BRepPrimAPI_MakePrism mkPrism(myShape, vec); + TopoDS_Shape swept = mkPrism.Shape(); + if (swept.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is null"); + this->Shape.setValue(swept); + } return App::DocumentObject::StdReturn; } catch (Standard_Failure) { diff --git a/src/Mod/Part/App/FeatureExtrusion.h b/src/Mod/Part/App/FeatureExtrusion.h index c5db68103..6576d0b17 100644 --- a/src/Mod/Part/App/FeatureExtrusion.h +++ b/src/Mod/Part/App/FeatureExtrusion.h @@ -25,6 +25,7 @@ #define PART_FEATUREEXTRUSION_H #include +#include #include "PartFeature.h" namespace Part @@ -39,6 +40,8 @@ public: App::PropertyLink Base; App::PropertyVector Dir; + App::PropertyBool Solid; + App::PropertyAngle TaperAngle; /** @name methods override feature */ //@{ diff --git a/src/Mod/Part/App/Makefile.am b/src/Mod/Part/App/Makefile.am index 5a9a45605..91c711564 100644 --- a/src/Mod/Part/App/Makefile.am +++ b/src/Mod/Part/App/Makefile.am @@ -189,6 +189,7 @@ include_HEADERS=\ ProgressIndicator.h \ PropertyGeometryList.h \ PropertyTopoShape.h \ + Tools.h \ TopoShape.h diff --git a/src/Mod/Part/App/PrimitiveFeature.cpp b/src/Mod/Part/App/PrimitiveFeature.cpp index 9a4deb390..004166532 100644 --- a/src/Mod/Part/App/PrimitiveFeature.cpp +++ b/src/Mod/Part/App/PrimitiveFeature.cpp @@ -163,9 +163,9 @@ void Vertex::onChanged(const App::Property* prop) Part::Feature::onChanged(prop); } -PROPERTY_SOURCE(Part::Edge, Part::Primitive) +PROPERTY_SOURCE(Part::Line, Part::Primitive) -Edge::Edge() +Line::Line() { ADD_PROPERTY_TYPE(X1,(0.0f),"Vertex 1 - Start",App::Prop_None,"X value of the start vertex"); ADD_PROPERTY_TYPE(Y1,(0.0f),"Vertex 1 - Start",App::Prop_None,"Y value of the Start vertex"); @@ -175,11 +175,11 @@ Edge::Edge() ADD_PROPERTY_TYPE(Z2,(1.0f),"Vertex 2 - Finish",App::Prop_None,"Z value of the finish vertex"); } -Edge::~Edge() +Line::~Line() { } -short Edge::mustExecute() const +short Line::mustExecute() const { if (X1.isTouched() || Y1.isTouched() || @@ -191,7 +191,7 @@ short Edge::mustExecute() const return Part::Feature::mustExecute(); } -App::DocumentObjectExecReturn *Edge::execute(void) +App::DocumentObjectExecReturn *Line::execute(void) { gp_Pnt point1; point1.SetX(this->X1.getValue()); @@ -212,7 +212,7 @@ App::DocumentObjectExecReturn *Edge::execute(void) return App::DocumentObject::StdReturn; } -void Edge::onChanged(const App::Property* prop) +void Line::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &X1 || prop == &Y1 || prop == &Z1 || prop == &X2 || prop == &Y2 || prop == &Z2){ diff --git a/src/Mod/Part/App/PrimitiveFeature.h b/src/Mod/Part/App/PrimitiveFeature.h index 7100b2ecd..250bf1564 100644 --- a/src/Mod/Part/App/PrimitiveFeature.h +++ b/src/Mod/Part/App/PrimitiveFeature.h @@ -70,13 +70,13 @@ public: //@} }; -class PartExport Edge : public Part::Primitive +class PartExport Line : public Part::Primitive { - PROPERTY_HEADER(Part::Edge); + PROPERTY_HEADER(Part::Line); public: - Edge(); - virtual ~Edge(); + Line(); + virtual ~Line(); App::PropertyFloat X1; App::PropertyFloat Y1; diff --git a/src/Mod/Part/App/Tools.h b/src/Mod/Part/App/Tools.h new file mode 100644 index 000000000..b48ab6ab6 --- /dev/null +++ b/src/Mod/Part/App/Tools.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (c) 2011 Werner Mayer * + * * + * 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 * + * * + ***************************************************************************/ + + +#ifndef PART_TOOLS_H +#define PART_TOOLS_H + +#include +#include +#include +#include + +namespace Base { +// Specialization for gp_Pnt +template <> +struct vec_traits { + typedef gp_Pnt vec_type; + typedef double float_type; + vec_traits(const vec_type& v) : v(v){} + inline float_type x() { return v.X(); } + inline float_type y() { return v.Y(); } + inline float_type z() { return v.Z(); } +private: + const vec_type& v; +}; +// Specialization for gp_Vec +template <> +struct vec_traits { + typedef gp_Vec vec_type; + typedef double float_type; + vec_traits(const vec_type& v) : v(v){} + inline float_type x() { return v.X(); } + inline float_type y() { return v.Y(); } + inline float_type z() { return v.Z(); } +private: + const vec_type& v; +}; +// Specialization for gp_Dir +template <> +struct vec_traits { + typedef gp_Dir vec_type; + typedef double float_type; + vec_traits(const vec_type& v) : v(v){} + inline float_type x() { return v.X(); } + inline float_type y() { return v.Y(); } + inline float_type z() { return v.Z(); } +private: + const vec_type& v; +}; +// Specialization for gp_XYZ +template <> +struct vec_traits { + typedef gp_XYZ vec_type; + typedef double float_type; + vec_traits(const vec_type& v) : v(v){} + inline float_type x() { return v.X(); } + inline float_type y() { return v.Y(); } + inline float_type z() { return v.Z(); } +private: + const vec_type& v; +}; +} + +namespace Part +{ + +} //namespace Part + + +#endif // PART_TOOLS_H diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 0206d8569..f81a04122 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -156,6 +156,7 @@ #include "TopoShapeVertexPy.h" #include "ProgressIndicator.h" #include "modelRefine.h" +#include "Tools.h" using namespace Part; @@ -355,7 +356,11 @@ void TopoShape::getFacesFromSubelement(const Data::Segment* element, TopoDS_Shape TopoShape::getSubShape(const char* Type) const { - if (!Type) return TopoDS_Shape(); + if (!Type) + Standard_Failure::Raise("No sub-shape type given"); + if (this->_Shape.IsNull()) + Standard_Failure::Raise("Cannot get sub-shape from empty shape"); + std::string shapetype(Type); if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face") { int index=std::atoi(&shapetype[4]); @@ -376,7 +381,8 @@ TopoDS_Shape TopoShape::getSubShape(const char* Type) const return anIndices.FindKey(index); } - return TopoDS_Shape(); + Standard_Failure::Raise("Not supported sub-shape type"); + return TopoDS_Shape(); // avoid compiler warning } unsigned long TopoShape::countSubShapes(const char* Type) const @@ -1738,27 +1744,27 @@ TopoDS_Shape TopoShape::removeSplitter() const Standard_Failure::Raise("Cannot remove splitter from empty shape"); if (_Shape.ShapeType() == TopAbs_SOLID) { - const TopoDS_Solid& solid = TopoDS::Solid(_Shape); - ModelRefine::FaceUniter uniter(solid); - if (uniter.process()) { - TopoDS_Solid solidMod; - if (!uniter.getSolid(solidMod)) - Standard_Failure::Raise("Getting solid failed"); - return solidMod; - } - else { + const TopoDS_Solid& solid = TopoDS::Solid(_Shape); + ModelRefine::FaceUniter uniter(solid); + if (uniter.process()) { + TopoDS_Solid solidMod; + if (!uniter.getSolid(solidMod)) + Standard_Failure::Raise("Getting solid failed"); + return solidMod; + } + else { Standard_Failure::Raise("Removing splitter failed"); - } + } } else if (_Shape.ShapeType() == TopAbs_SHELL) { - const TopoDS_Shell& shell = TopoDS::Shell(_Shape); - ModelRefine::FaceUniter uniter(shell); - if (uniter.process()) { - return uniter.getShell(); - } - else { + const TopoDS_Shell& shell = TopoDS::Shell(_Shape); + ModelRefine::FaceUniter uniter(shell); + if (uniter.process()) { + return uniter.getShell(); + } + else { Standard_Failure::Raise("Removing splitter failed"); - } + } } else if (_Shape.ShapeType() == TopAbs_COMPOUND) { BRep_Builder builder; @@ -1768,21 +1774,21 @@ TopoDS_Shape TopoShape::removeSplitter() const TopExp_Explorer xp; // solids for (xp.Init(_Shape, TopAbs_SOLID); xp.More(); xp.Next()) { - const TopoDS_Solid& solid = TopoDS::Solid(xp.Current()); - ModelRefine::FaceUniter uniter(solid); - if (uniter.process()) { - TopoDS_Solid solidMod; - if (uniter.getSolid(solidMod)) - builder.Add(comp, solidMod); - } + const TopoDS_Solid& solid = TopoDS::Solid(xp.Current()); + ModelRefine::FaceUniter uniter(solid); + if (uniter.process()) { + TopoDS_Solid solidMod; + if (uniter.getSolid(solidMod)) + builder.Add(comp, solidMod); + } } // free shells for (xp.Init(_Shape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next()) { - const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); - ModelRefine::FaceUniter uniter(shell); - if (uniter.process()) { - builder.Add(comp, uniter.getShell()); - } + const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); + ModelRefine::FaceUniter uniter(shell); + if (uniter.process()) { + builder.Add(comp, uniter.getShell()); + } } // the rest for (xp.Init(_Shape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index e2855e510..389511d05 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -25,53 +25,14 @@ #define PART_TOPOSHAPE_H #include -#include -#include #include #include #include #include +class gp_Ax1; class gp_Ax2; - -namespace Base { -// Specialization for gp_Pnt -template <> -struct vec_traits { - typedef gp_Pnt vec_type; - typedef double float_type; - vec_traits(const vec_type& v) : v(v){} - inline float_type x() { return v.X(); } - inline float_type y() { return v.Y(); } - inline float_type z() { return v.Z(); } -private: - const vec_type& v; -}; -// Specialization for gp_Vec -template <> -struct vec_traits { - typedef gp_Vec vec_type; - typedef double float_type; - vec_traits(const vec_type& v) : v(v){} - inline float_type x() { return v.X(); } - inline float_type y() { return v.Y(); } - inline float_type z() { return v.Z(); } -private: - const vec_type& v; -}; -// Specialization for gp_Dir -template <> -struct vec_traits { - typedef gp_Dir vec_type; - typedef double float_type; - vec_traits(const vec_type& v) : v(v){} - inline float_type x() { return v.X(); } - inline float_type y() { return v.Y(); } - inline float_type z() { return v.Z(); } -private: - const vec_type& v; -}; -} +class gp_Vec; namespace Part { diff --git a/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp b/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp index 438e31da2..c329042c8 100644 --- a/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp @@ -23,9 +23,10 @@ #include "PreCompiled.h" #include +#include #include -#include "Mod/Part/App/TopoShape.h" +#include "TopoShape.h" // inclusion of the generated files (generated out of TopoShapeCompSolidPy.xml) #include "TopoShapeSolidPy.h" diff --git a/src/Mod/Part/App/TopoShapeCompoundPyImp.cpp b/src/Mod/Part/App/TopoShapeCompoundPyImp.cpp index b8e3a0d5e..489abda5e 100644 --- a/src/Mod/Part/App/TopoShapeCompoundPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeCompoundPyImp.cpp @@ -23,8 +23,9 @@ #include "PreCompiled.h" -#include "Mod/Part/App/TopoShape.h" +#include "TopoShape.h" #include +#include #include // inclusion of the generated files (generated out of TopoShapeCompoundPy.xml) diff --git a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp index ca1a952c3..8af8b1300 100644 --- a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp @@ -40,7 +40,8 @@ #include #include -#include "Mod/Part/App/TopoShape.h" +#include "TopoShape.h" +#include "Tools.h" // inclusion of the generated files (generated out of TopoShapeSolidPy.xml) #include "TopoShapeShellPy.h" diff --git a/src/Mod/Part/App/modelRefine.cpp b/src/Mod/Part/App/modelRefine.cpp index 0fa258ef7..72b6c6486 100644 --- a/src/Mod/Part/App/modelRefine.cpp +++ b/src/Mod/Part/App/modelRefine.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include #include @@ -201,18 +203,38 @@ const FaceVectorType& FaceTypeSplitter::getTypedFaceVector(const GeomAbs_Surface ///////////////////////////////////////////////////////////////////////////////////////////////////////// +FaceAdjacencySplitter::FaceAdjacencySplitter(const TopoDS_Shell &shell) +{ + TopExp_Explorer shellIt; + for (shellIt.Init(shell, TopAbs_FACE); shellIt.More(); shellIt.Next()) + { + TopTools_ListOfShape shapeList; + TopExp_Explorer it; + for (it.Init(shellIt.Current(), TopAbs_EDGE); it.More(); it.Next()) + shapeList.Append(it.Current()); + faceToEdgeMap.Add(shellIt.Current(), shapeList); + } + TopExp::MapShapesAndAncestors(shell, TopAbs_EDGE, TopAbs_FACE, edgeToFaceMap); +} + + void FaceAdjacencySplitter::split(const FaceVectorType &facesIn) { + facesInMap.Clear(); + processedMap.Clear(); + adjacencyArray.clear(); + + FaceVectorType::const_iterator it; + for (it = facesIn.begin(); it != facesIn.end(); ++it) + facesInMap.Add(*it); //the reserve call guarantees the vector will never get "pushed back" in the //recursiveFind calls, thus invalidating the iterators. We can be sure of this as any one //matched set can't be bigger than the set passed in. if we have seg faults, we will //want to turn this tempFaces vector back into a std::list ensuring valid iterators //at the expense of std::find speed. - buildMap(facesIn); FaceVectorType tempFaces; tempFaces.reserve(facesIn.size() + 1); - FaceVectorType::const_iterator it; for (it = facesIn.begin(); it != facesIn.end(); ++it) { //skip already processed shapes. @@ -220,9 +242,8 @@ void FaceAdjacencySplitter::split(const FaceVectorType &facesIn) continue; tempFaces.clear(); - tempFaces.push_back(*it); processedMap.Add(*it); - recursiveFind(tempFaces, facesIn); + recursiveFind(*it, tempFaces); if (tempFaces.size() > 1) { adjacencyArray.push_back(tempFaces); @@ -230,70 +251,28 @@ void FaceAdjacencySplitter::split(const FaceVectorType &facesIn) } } -void FaceAdjacencySplitter::recursiveFind(FaceVectorType &tempFaces, const FaceVectorType &facesIn) +void FaceAdjacencySplitter::recursiveFind(const TopoDS_Face &face, FaceVectorType &outVector) { - FaceVectorType::iterator tempIt; - FaceVectorType::const_iterator faceIt; + outVector.push_back(face); - for (tempIt = tempFaces.begin(); tempIt != tempFaces.end(); ++tempIt) + const TopTools_ListOfShape &edges = faceToEdgeMap.FindFromKey(face); + TopTools_ListIteratorOfListOfShape edgeIt; + for (edgeIt.Initialize(edges); edgeIt.More(); edgeIt.Next()) { - for(faceIt = facesIn.begin(); faceIt != facesIn.end(); ++faceIt) + const TopTools_ListOfShape &faces = edgeToFaceMap.FindFromKey(edgeIt.Value()); + TopTools_ListIteratorOfListOfShape faceIt; + for (faceIt.Initialize(faces); faceIt.More(); faceIt.Next()) { - if ((*tempIt).IsSame(*faceIt)) + if (!facesInMap.Contains(faceIt.Value())) continue; - if (processedMap.Contains(*faceIt)) + if (processedMap.Contains(faceIt.Value())) continue; - if (adjacentTest(*tempIt, *faceIt)) - { - tempFaces.push_back(*faceIt); - processedMap.Add(*faceIt); - recursiveFind(tempFaces, facesIn); - } + processedMap.Add(faceIt.Value()); + recursiveFind(TopoDS::Face(faceIt.Value()), outVector); } } } -bool FaceAdjacencySplitter::hasBeenMapped(const TopoDS_Face &shape) -{ - for (std::vector::iterator it(adjacencyArray.begin()); it != adjacencyArray.end(); ++it) - { - if (std::find((*it).begin(), (*it).end(), shape) != (*it).end()) - return true; - } - return false; -} - -void FaceAdjacencySplitter::buildMap(const FaceVectorType &facesIn) -{ - FaceVectorType::const_iterator vit; - for (vit = facesIn.begin(); vit != facesIn.end(); ++vit) - { - TopTools_ListOfShape shapeList; - TopExp_Explorer it; - for (it.Init(*vit, TopAbs_EDGE); it.More(); it.Next()) - shapeList.Append(it.Current()); - faceEdgeMap.Bind((*vit), shapeList); - } -} - -bool FaceAdjacencySplitter::adjacentTest(const TopoDS_Face &faceOne, const TopoDS_Face &faceTwo) -{ - const TopTools_ListOfShape &faceOneEdges = faceEdgeMap.Find(faceOne); - const TopTools_ListOfShape &faceTwoEdges = faceEdgeMap.Find(faceTwo); - TopTools_ListIteratorOfListOfShape itOne, itTwo; - - for (itOne.Initialize(faceOneEdges); itOne.More(); itOne.Next()) - { - for (itTwo.Initialize(faceTwoEdges); itTwo.More(); itTwo.Next()) - { - if ((itOne.Value()).IsSame(itTwo.Value())) - return true; - } - } - - return false; -} - ////////////////////////////////////////////////////////////////////////////////////////////////////// void FaceEqualitySplitter::split(const FaceVectorType &faces, FaceTypedBase *object) @@ -406,8 +385,7 @@ TopoDS_Face FaceTypedPlane::buildFace(const FaceVectorType &faces) const current = faceFix.Face(); } - BRepLib_FuseEdges edgeFuse(current, Standard_True); - return TopoDS::Face(edgeFuse.Shape()); + return current; } FaceTypedPlane& ModelRefine::getPlaneObject() @@ -489,6 +467,8 @@ bool FaceUniter::process() ModelRefine::FaceVectorType facesToRemove; ModelRefine::FaceVectorType facesToSew; + ModelRefine::FaceAdjacencySplitter adjacencySplitter(workShell); + for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) { ModelRefine::FaceVectorType typedFaces = splitter.getTypedFaceVector((*typeIt)->getType()); @@ -496,7 +476,6 @@ bool FaceUniter::process() equalitySplitter.split(typedFaces, *typeIt); for (std::size_t indexEquality(0); indexEquality < equalitySplitter.getGroupCount(); ++indexEquality) { - ModelRefine::FaceAdjacencySplitter adjacencySplitter; adjacencySplitter.split(equalitySplitter.getGroup(indexEquality)); // std::cout << " adjacency group count: " << adjacencySplitter.getGroupCount() << std::endl; for (std::size_t adjacentIndex(0); adjacentIndex < adjacencySplitter.getGroupCount(); ++adjacentIndex) @@ -544,6 +523,17 @@ bool FaceUniter::process() for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) builder.Add(workShell, *sewIt); } + + BRepLib_FuseEdges edgeFuse(workShell, Standard_True); + TopTools_DataMapOfShapeShape affectedFaces; + edgeFuse.Faces(affectedFaces); + TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt; + for (mapIt.Initialize(affectedFaces); mapIt.More(); mapIt.Next()) + { + ShapeFix_Face faceFixer(TopoDS::Face(mapIt.Value())); + faceFixer.Perform(); + } + workShell = TopoDS::Shell(edgeFuse.Shape()); } return true; } diff --git a/src/Mod/Part/App/modelRefine.h b/src/Mod/Part/App/modelRefine.h index 08a146294..1f51b8ded 100644 --- a/src/Mod/Part/App/modelRefine.h +++ b/src/Mod/Part/App/modelRefine.h @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -105,20 +106,20 @@ namespace ModelRefine class FaceAdjacencySplitter { public: - FaceAdjacencySplitter(){} + FaceAdjacencySplitter(const TopoDS_Shell &shell); void split(const FaceVectorType &facesIn); int getGroupCount() const {return adjacencyArray.size();} const FaceVectorType& getGroup(const std::size_t &index) const {return adjacencyArray[index];} private: - bool hasBeenMapped(const TopoDS_Face &shape); - void recursiveFind(FaceVectorType &tempSet, const FaceVectorType &facesIn); - void buildMap(const FaceVectorType &facesIn); - bool adjacentTest(const TopoDS_Face &faceOne, const TopoDS_Face &faceTwo); + FaceAdjacencySplitter(){} + void recursiveFind(const TopoDS_Face &face, FaceVectorType &outVector); std::vector adjacencyArray; - TopTools_DataMapOfShapeListOfShape faceEdgeMap; TopTools_MapOfShape processedMap; + TopTools_MapOfShape facesInMap; + TopTools_IndexedDataMapOfShapeListOfShape faceToEdgeMap; + TopTools_IndexedDataMapOfShapeListOfShape edgeToFaceMap; }; class FaceEqualitySplitter diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index 0626ca749..38a984c5e 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -58,6 +58,7 @@ set(PartGui_UIC_SRCS DlgPartImportIges.ui DlgPartImportStep.ui DlgPrimitives.ui + Location.ui DlgRevolution.ui DlgSettings3DViewPart.ui DlgSettingsGeneral.ui @@ -104,6 +105,7 @@ SET(PartGui_SRCS DlgPrimitives.cpp DlgPrimitives.h DlgPrimitives.ui + Location.ui DlgRevolution.cpp DlgRevolution.h DlgRevolution.ui diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index e5ccaaac5..f4288f997 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -208,16 +208,13 @@ CmdPartPrimitives::CmdPartPrimitives() void CmdPartPrimitives::activated(int iMsg) { - static QPointer dlg = 0; - if (!dlg) - dlg = new PartGui::DlgPrimitives(Gui::getMainWindow()); - dlg->setAttribute(Qt::WA_DeleteOnClose); - dlg->show(); + PartGui::TaskPrimitives* dlg = new PartGui::TaskPrimitives(); + Gui::Control().showDialog(dlg); } bool CmdPartPrimitives::isActive(void) { - return hasActiveDocument(); + return (hasActiveDocument() && !Gui::Control().activeDialog()); } //=========================================================================== diff --git a/src/Mod/Part/Gui/DlgExtrusion.cpp b/src/Mod/Part/Gui/DlgExtrusion.cpp index 5450f83a9..38e167657 100644 --- a/src/Mod/Part/Gui/DlgExtrusion.cpp +++ b/src/Mod/Part/Gui/DlgExtrusion.cpp @@ -162,6 +162,8 @@ void DlgExtrusion::apply() double dirX = ui->dirX->value(); double dirY = ui->dirY->value(); double dirZ = ui->dirZ->value(); + double angle = ui->taperAngle->value(); + bool makeSolid = ui->makeSolid->isChecked(); // inspect geometry App::DocumentObject* obj = activeDoc->getObject((const char*)shape.toAscii()); @@ -192,12 +194,16 @@ void DlgExtrusion::apply() "FreeCAD.getDocument(\"%1\").addObject(\"%2\",\"%3\")\n" "FreeCAD.getDocument(\"%1\").%3.Base = FreeCAD.getDocument(\"%1\").%4\n" "FreeCAD.getDocument(\"%1\").%3.Dir = (%5,%6,%7)\n" + "FreeCAD.getDocument(\"%1\").%3.Solid = (%8)\n" + "FreeCAD.getDocument(\"%1\").%3.TaperAngle = (%9)\n" "FreeCADGui.getDocument(\"%1\").%4.Visibility = False\n") .arg(QString::fromAscii(this->document.c_str())) .arg(type).arg(name).arg(shape) .arg(dirX*len) .arg(dirY*len) - .arg(dirZ*len); + .arg(dirZ*len) + .arg(makeSolid ? QLatin1String("True") : QLatin1String("False")) + .arg(angle); Gui::Application::Instance->runPythonCode((const char*)code.toAscii()); QByteArray to = name.toAscii(); QByteArray from = shape.toAscii(); diff --git a/src/Mod/Part/Gui/DlgExtrusion.h b/src/Mod/Part/Gui/DlgExtrusion.h index 60d5254bc..deeabe375 100644 --- a/src/Mod/Part/Gui/DlgExtrusion.h +++ b/src/Mod/Part/Gui/DlgExtrusion.h @@ -68,7 +68,7 @@ public: void clicked(int); virtual QDialogButtonBox::StandardButtons getStandardButtons() const - { return QDialogButtonBox::Apply | QDialogButtonBox::Cancel; } + { return QDialogButtonBox::Apply | QDialogButtonBox::Close; } private: DlgExtrusion* widget; diff --git a/src/Mod/Part/Gui/DlgExtrusion.ui b/src/Mod/Part/Gui/DlgExtrusion.ui index 0244152f2..3fad61682 100644 --- a/src/Mod/Part/Gui/DlgExtrusion.ui +++ b/src/Mod/Part/Gui/DlgExtrusion.ui @@ -181,6 +181,37 @@ + + + Create solid + + + + + + + + + Taper outward angle + + + + + + + -180.000000000000000 + + + 180.000000000000000 + + + 5.000000000000000 + + + + + + diff --git a/src/Mod/Part/Gui/DlgPrimitives.cpp b/src/Mod/Part/Gui/DlgPrimitives.cpp index 0092cf756..30cdb79d1 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.cpp +++ b/src/Mod/Part/Gui/DlgPrimitives.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include "DlgPrimitives.h" @@ -47,15 +49,13 @@ using namespace PartGui; /* TRANSLATOR PartGui::DlgPrimitives */ -DlgPrimitives::DlgPrimitives(QWidget* parent, Qt::WFlags fl) - : Gui::LocationDialogComp(parent, fl) +DlgPrimitives::DlgPrimitives(QWidget* parent) + : QWidget(parent) { + ui.setupUi(this); Gui::Command::doCommand(Gui::Command::Doc, "from FreeCAD import Base"); Gui::Command::doCommand(Gui::Command::Doc, "import Part,PartGui"); - connect(ui.viewPositionButton, SIGNAL(clicked()), - this, SLOT(on_viewPositionButton_clicked())); - // set limits // // plane @@ -114,7 +114,7 @@ DlgPrimitives::DlgPrimitives(QWidget* parent, Qt::WFlags fl) ui.vertexX->setMinimum(INT_MIN); ui.vertexY->setMinimum(INT_MIN); ui.vertexZ->setMinimum(INT_MIN); - // edge + // line ui.edgeX1->setMaximum(INT_MAX); ui.edgeX1->setMinimum(INT_MIN); ui.edgeY1->setMaximum(INT_MAX); @@ -134,6 +134,247 @@ DlgPrimitives::DlgPrimitives(QWidget* parent, Qt::WFlags fl) */ DlgPrimitives::~DlgPrimitives() { +} + +void DlgPrimitives::createPrimitive(const QString& placement) +{ + try { + QString cmd; QString name; + App::Document* doc = App::GetApplication().getActiveDocument(); + if (!doc) { + QMessageBox::warning(this, tr("Create %1") + .arg(ui.comboBox1->currentText()), tr("No active document")); + return; + } + if (ui.comboBox1->currentIndex() == 0) { // plane + name = QString::fromAscii(doc->getUniqueObjectName("Plane").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Plane\",\"%1\")\n" + "App.ActiveDocument.%1.Length=%2\n" + "App.ActiveDocument.%1.Width=%3\n" + "App.ActiveDocument.%1.Placement=%4\n") + .arg(name) + .arg(ui.planeLength->value(),0,'f',2) + .arg(ui.planeWidth->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 1) { // box + name = QString::fromAscii(doc->getUniqueObjectName("Box").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Box\",\"%1\")\n" + "App.ActiveDocument.%1.Length=%2\n" + "App.ActiveDocument.%1.Width=%3\n" + "App.ActiveDocument.%1.Height=%4\n" + "App.ActiveDocument.%1.Placement=%5\n") + .arg(name) + .arg(ui.boxLength->value(),0,'f',2) + .arg(ui.boxWidth->value(),0,'f',2) + .arg(ui.boxHeight->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 2) { // cylinder + name = QString::fromAscii(doc->getUniqueObjectName("Cylinder").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Cylinder\",\"%1\")\n" + "App.ActiveDocument.%1.Radius=%2\n" + "App.ActiveDocument.%1.Height=%3\n" + "App.ActiveDocument.%1.Angle=%4\n" + "App.ActiveDocument.%1.Placement=%5\n") + .arg(name) + .arg(ui.cylinderRadius->value(),0,'f',2) + .arg(ui.cylinderHeight->value(),0,'f',2) + .arg(ui.cylinderAngle->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 3) { // cone + name = QString::fromAscii(doc->getUniqueObjectName("Cone").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Cone\",\"%1\")\n" + "App.ActiveDocument.%1.Radius1=%2\n" + "App.ActiveDocument.%1.Radius2=%3\n" + "App.ActiveDocument.%1.Height=%4\n" + "App.ActiveDocument.%1.Angle=%5\n" + "App.ActiveDocument.%1.Placement=%6\n") + .arg(name) + .arg(ui.coneRadius1->value(),0,'f',2) + .arg(ui.coneRadius2->value(),0,'f',2) + .arg(ui.coneHeight->value(),0,'f',2) + .arg(ui.coneAngle->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 4) { // sphere + name = QString::fromAscii(doc->getUniqueObjectName("Sphere").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Sphere\",\"%1\")\n" + "App.ActiveDocument.%1.Radius=%2\n" + "App.ActiveDocument.%1.Angle1=%3\n" + "App.ActiveDocument.%1.Angle2=%4\n" + "App.ActiveDocument.%1.Angle3=%5\n" + "App.ActiveDocument.%1.Placement=%6\n") + .arg(name) + .arg(ui.sphereRadius->value(),0,'f',2) + .arg(ui.sphereAngle1->value(),0,'f',2) + .arg(ui.sphereAngle2->value(),0,'f',2) + .arg(ui.sphereAngle3->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 5) { // ellipsoid + name = QString::fromAscii(doc->getUniqueObjectName("Ellipsoid").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Ellipsoid\",\"%1\")\n" + "App.ActiveDocument.%1.Radius1=%2\n" + "App.ActiveDocument.%1.Radius2=%3\n" + "App.ActiveDocument.%1.Angle1=%4\n" + "App.ActiveDocument.%1.Angle2=%5\n" + "App.ActiveDocument.%1.Angle3=%6\n" + "App.ActiveDocument.%1.Placement=%7\n") + .arg(name) + .arg(ui.ellipsoidRadius1->value(),0,'f',2) + .arg(ui.ellipsoidRadius2->value(),0,'f',2) + .arg(ui.ellipsoidAngle1->value(),0,'f',2) + .arg(ui.ellipsoidAngle2->value(),0,'f',2) + .arg(ui.ellipsoidAngle3->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 6) { // torus + name = QString::fromAscii(doc->getUniqueObjectName("Torus").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Torus\",\"%1\")\n" + "App.ActiveDocument.%1.Radius1=%2\n" + "App.ActiveDocument.%1.Radius2=%3\n" + "App.ActiveDocument.%1.Angle1=%4\n" + "App.ActiveDocument.%1.Angle2=%5\n" + "App.ActiveDocument.%1.Angle3=%6\n" + "App.ActiveDocument.%1.Placement=%7\n") + .arg(name) + .arg(ui.torusRadius1->value(),0,'f',2) + .arg(ui.torusRadius2->value(),0,'f',2) + .arg(ui.torusAngle1->value(),0,'f',2) + .arg(ui.torusAngle2->value(),0,'f',2) + .arg(ui.torusAngle3->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 7) { // wedge + name = QString::fromAscii(doc->getUniqueObjectName("Wedge").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Wedge\",\"%1\")\n" + "App.ActiveDocument.%1.Xmin=%2\n" + "App.ActiveDocument.%1.Ymin=%3\n" + "App.ActiveDocument.%1.Zmin=%4\n" + "App.ActiveDocument.%1.X2min=%5\n" + "App.ActiveDocument.%1.Z2min=%6\n" + "App.ActiveDocument.%1.Xmax=%7\n" + "App.ActiveDocument.%1.Ymax=%8\n" + "App.ActiveDocument.%1.Zmax=%9\n" + "App.ActiveDocument.%1.X2max=%10\n" + "App.ActiveDocument.%1.Z2max=%11\n" + "App.ActiveDocument.%1.Placement=%12\n") + .arg(name) + .arg(ui.wedgeXmin->value(),0,'f',2) + .arg(ui.wedgeYmin->value(),0,'f',2) + .arg(ui.wedgeZmin->value(),0,'f',2) + .arg(ui.wedgeX2min->value(),0,'f',2) + .arg(ui.wedgeZ2min->value(),0,'f',2) + .arg(ui.wedgeXmax->value(),0,'f',2) + .arg(ui.wedgeYmax->value(),0,'f',2) + .arg(ui.wedgeZmax->value(),0,'f',2) + .arg(ui.wedgeX2max->value(),0,'f',2) + .arg(ui.wedgeZ2max->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 8) { // helix + name = QString::fromAscii(doc->getUniqueObjectName("Helix").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Helix\",\"%1\")\n" + "App.ActiveDocument.%1.Pitch=%2\n" + "App.ActiveDocument.%1.Height=%3\n" + "App.ActiveDocument.%1.Radius=%4\n" + "App.ActiveDocument.%1.Angle=%5\n" + "App.ActiveDocument.%1.Placement=%6\n") + .arg(name) + .arg(ui.helixPitch->value(),0,'f',2) + .arg(ui.helixHeight->value(),0,'f',2) + .arg(ui.helixRadius->value(),0,'f',2) + .arg(ui.helixAngle->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 9) { // circle + name = QString::fromAscii(doc->getUniqueObjectName("Circle").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Circle\",\"%1\")\n" + "App.ActiveDocument.%1.Radius=%2\n" + "App.ActiveDocument.%1.Angle0=%3\n" + "App.ActiveDocument.%1.Angle1=%4\n" + "App.ActiveDocument.%1.Placement=%5\n") + .arg(name) + .arg(ui.circleRadius->value(),0,'f',2) + .arg(ui.circleAngle0->value(),0,'f',2) + .arg(ui.circleAngle1->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 10) { // vertex + name = QString::fromAscii(doc->getUniqueObjectName("Vertex").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Vertex\",\"%1\")\n" + "App.ActiveDocument.%1.X=%2\n" + "App.ActiveDocument.%1.Y=%3\n" + "App.ActiveDocument.%1.Z=%4\n" + "App.ActiveDocument.%1.Placement=%5\n") + .arg(name) + .arg(ui.vertexX->value(),0,'f',2) + .arg(ui.vertexY->value(),0,'f',2) + .arg(ui.vertexZ->value(),0,'f',2) + .arg(placement); + } + else if (ui.comboBox1->currentIndex() == 11) { // line + name = QString::fromAscii(doc->getUniqueObjectName("Line").c_str()); + cmd = QString::fromAscii( + "App.ActiveDocument.addObject(\"Part::Line\",\"%1\")\n" + "App.ActiveDocument.%1.X1=%2\n" + "App.ActiveDocument.%1.Y1=%3\n" + "App.ActiveDocument.%1.Z1=%4\n" + "App.ActiveDocument.%1.X2=%5\n" + "App.ActiveDocument.%1.Y2=%6\n" + "App.ActiveDocument.%1.Z2=%7\n" + "App.ActiveDocument.%1.Placement=%8\n") + .arg(name) + .arg(ui.edgeX1->value(),0,'f',2) + .arg(ui.edgeY1->value(),0,'f',2) + .arg(ui.edgeZ1->value(),0,'f',2) + .arg(ui.edgeX2->value(),0,'f',2) + .arg(ui.edgeY2->value(),0,'f',2) + .arg(ui.edgeZ2->value(),0,'f',2) + .arg(placement); + } + + // Execute the Python block + QString prim = tr("Create %1").arg(ui.comboBox1->currentText()); + Gui::Application::Instance->activeDocument()->openCommand(prim.toUtf8()); + Gui::Command::doCommand(Gui::Command::Doc, (const char*)cmd.toAscii()); + Gui::Application::Instance->activeDocument()->commitCommand(); + Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); + } + catch (const Base::PyException& e) { + QMessageBox::warning(this, tr("Create %1") + .arg(ui.comboBox1->currentText()), QString::fromLatin1(e.what())); + } +} + +// ---------------------------------------------- + +/* TRANSLATOR PartGui::Location */ + +Location::Location(QWidget* parent) +{ + ui.setupUi(this); + + connect(ui.viewPositionButton, SIGNAL(clicked()), + this, SLOT(on_viewPositionButton_clicked())); +} + +Location::~Location() +{ // no need to delete child widgets, Qt does it all for us if (!this->activeView.isNull()) { Gui::View3DInventorViewer* viewer = static_cast @@ -142,26 +383,60 @@ DlgPrimitives::~DlgPrimitives() viewer->setRedirectToSceneGraph(false); viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,this); } -} - -namespace Base { -// Specialization for gp_XYZ -template <> -struct vec_traits { - typedef gp_XYZ vec_type; - typedef double float_type; - vec_traits(const vec_type& v) : v(v){} - inline float_type x() { return v.X(); } - inline float_type y() { return v.Y(); } - inline float_type z() { return v.Z(); } -private: - const vec_type& v; -}; } -QString DlgPrimitives::toPlacement() const +void Location::on_viewPositionButton_clicked() { - Base::Vector3f d = ui.getDirection(); + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (!doc) { + return; + } + + Gui::View3DInventor* view = static_cast(doc->getActiveView()); + if (view && !this->activeView) { + Gui::View3DInventorViewer* viewer = view->getViewer(); + if (!viewer->isEditing()) { + this->activeView = view; + viewer->setEditing(true); + viewer->setRedirectToSceneGraph(true); + viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, this); + } + } +} + +void Location::pickCallback(void * ud, SoEventCallback * n) +{ + const SoMouseButtonEvent * mbe = static_cast(n->getEvent()); + Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData()); + + // Mark all incoming mouse button events as handled, especially, to deactivate the selection node + n->getAction()->setHandled(); + if (mbe->getButton() == SoMouseButtonEvent::BUTTON1) { + if (mbe->getState() == SoButtonEvent::UP) { + n->setHandled(); + view->setEditing(false); + view->setRedirectToSceneGraph(false); + Location* dlg = reinterpret_cast(ud); + dlg->activeView = 0; + view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud); + } + else if (mbe->getState() == SoButtonEvent::DOWN) { + const SoPickedPoint * point = n->getPickedPoint(); + if (point) { + SbVec3f pnt = point->getPoint(); + SbVec3f nor = point->getNormal(); + Location* dlg = reinterpret_cast(ud); + dlg->ui.loc->setPosition(Base::Vector3f(pnt[0],pnt[1],pnt[2])); + dlg->ui.loc->setDirection(Base::Vector3f(nor[0],nor[1],nor[2])); + n->setHandled(); + } + } + } +} + +QString Location::toPlacement() const +{ + Base::Vector3f d = ui.loc->getDirection(); gp_Dir dir = gp_Dir(d.x,d.y,d.z); gp_Pnt pnt = gp_Pnt(0.0,0.0,0.0); gp_Ax3 ax3; @@ -204,293 +479,63 @@ QString DlgPrimitives::toPlacement() const Trf.GetRotation(theAxis,theAngle); Base::Rotation rot(Base::convertTo(theAxis), theAngle); + Base::Vector3f loc = ui.loc->getPosition(); return QString::fromAscii("Base.Placement(Base.Vector(%1,%2,%3),Base.Rotation(%4,%5,%6,%7))") - .arg(ui.xPos->value(),0,'f',2) - .arg(ui.yPos->value(),0,'f',2) - .arg(ui.zPos->value(),0,'f',2) + .arg(loc.x,0,'f',2) + .arg(loc.y,0,'f',2) + .arg(loc.z,0,'f',2) .arg(rot[0],0,'f',2) .arg(rot[1],0,'f',2) .arg(rot[2],0,'f',2) .arg(rot[3],0,'f',2); } + +// ---------------------------------------------- + +/* TRANSLATOR PartGui::TaskPrimitives */ + +TaskPrimitives::TaskPrimitives() +{ + Gui::TaskView::TaskBox* taskbox; + widget = new DlgPrimitives(); + taskbox = new Gui::TaskView::TaskBox(QPixmap(), widget->windowTitle(),true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); + + location = new Location(); + taskbox = new Gui::TaskView::TaskBox(QPixmap(), location->windowTitle(),true, 0); + taskbox->groupLayout()->addWidget(location); + taskbox->hideGroupBox(); + Content.push_back(taskbox); +} + +TaskPrimitives::~TaskPrimitives() +{ + // automatically deleted in the sub-class +} + +QDialogButtonBox::StandardButtons TaskPrimitives::getStandardButtons() const +{ + return QDialogButtonBox::Close| + QDialogButtonBox::Ok; +} -void DlgPrimitives::pickCallback(void * ud, SoEventCallback * n) +void TaskPrimitives::modifyStandardButtons(QDialogButtonBox* box) { - const SoMouseButtonEvent * mbe = static_cast(n->getEvent()); - Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData()); - - // Mark all incoming mouse button events as handled, especially, to deactivate the selection node - n->getAction()->setHandled(); - if (mbe->getButton() == SoMouseButtonEvent::BUTTON1) { - if (mbe->getState() == SoButtonEvent::UP) { - n->setHandled(); - view->setEditing(false); - view->setRedirectToSceneGraph(false); - DlgPrimitives* dlg = reinterpret_cast(ud); - dlg->activeView = 0; - view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud); - } - else if (mbe->getState() == SoButtonEvent::DOWN) { - const SoPickedPoint * point = n->getPickedPoint(); - if (point) { - SbVec3f pnt = point->getPoint(); - SbVec3f nor = point->getNormal(); - DlgPrimitives* dlg = reinterpret_cast(ud); - dlg->ui.xPos->setValue(pnt[0]); - dlg->ui.yPos->setValue(pnt[1]); - dlg->ui.zPos->setValue(pnt[2]); - dlg->ui.setDirection(Base::Vector3f(nor[0],nor[1],nor[2])); - n->setHandled(); - } - } - } -} - -void DlgPrimitives::on_viewPositionButton_clicked() -{ - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (!doc) { - QMessageBox::warning(this, tr("Create %1") - .arg(ui.comboBox1->currentText()), tr("No active document")); - return; - } - - Gui::View3DInventor* view = static_cast(doc->getActiveView()); - if (view && !this->activeView) { - Gui::View3DInventorViewer* viewer = view->getViewer(); - if (!viewer->isEditing()) { - this->activeView = view; - viewer->setEditing(true); - viewer->setRedirectToSceneGraph(true); - viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, this); - } - } -} - -void DlgPrimitives::accept() -{ - try { - QString cmd; QString name; - App::Document* doc = App::GetApplication().getActiveDocument(); - if (!doc) { - QMessageBox::warning(this, tr("Create %1") - .arg(ui.comboBox1->currentText()), tr("No active document")); - return; - } - if (ui.comboBox1->currentIndex() == 0) { // plane - name = QString::fromAscii(doc->getUniqueObjectName("Plane").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Plane\",\"%1\")\n" - "App.ActiveDocument.%1.Length=%2\n" - "App.ActiveDocument.%1.Width=%3\n" - "App.ActiveDocument.%1.Placement=%4\n") - .arg(name) - .arg(ui.planeLength->value(),0,'f',2) - .arg(ui.planeWidth->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 1) { // box - name = QString::fromAscii(doc->getUniqueObjectName("Box").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Box\",\"%1\")\n" - "App.ActiveDocument.%1.Length=%2\n" - "App.ActiveDocument.%1.Width=%3\n" - "App.ActiveDocument.%1.Height=%4\n" - "App.ActiveDocument.%1.Placement=%5\n") - .arg(name) - .arg(ui.boxLength->value(),0,'f',2) - .arg(ui.boxWidth->value(),0,'f',2) - .arg(ui.boxHeight->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 2) { // cylinder - name = QString::fromAscii(doc->getUniqueObjectName("Cylinder").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Cylinder\",\"%1\")\n" - "App.ActiveDocument.%1.Radius=%2\n" - "App.ActiveDocument.%1.Height=%3\n" - "App.ActiveDocument.%1.Angle=%4\n" - "App.ActiveDocument.%1.Placement=%5\n") - .arg(name) - .arg(ui.cylinderRadius->value(),0,'f',2) - .arg(ui.cylinderHeight->value(),0,'f',2) - .arg(ui.cylinderAngle->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 3) { // cone - name = QString::fromAscii(doc->getUniqueObjectName("Cone").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Cone\",\"%1\")\n" - "App.ActiveDocument.%1.Radius1=%2\n" - "App.ActiveDocument.%1.Radius2=%3\n" - "App.ActiveDocument.%1.Height=%4\n" - "App.ActiveDocument.%1.Angle=%5\n" - "App.ActiveDocument.%1.Placement=%6\n") - .arg(name) - .arg(ui.coneRadius1->value(),0,'f',2) - .arg(ui.coneRadius2->value(),0,'f',2) - .arg(ui.coneHeight->value(),0,'f',2) - .arg(ui.coneAngle->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 4) { // sphere - name = QString::fromAscii(doc->getUniqueObjectName("Sphere").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Sphere\",\"%1\")\n" - "App.ActiveDocument.%1.Radius=%2\n" - "App.ActiveDocument.%1.Angle1=%3\n" - "App.ActiveDocument.%1.Angle2=%4\n" - "App.ActiveDocument.%1.Angle3=%5\n" - "App.ActiveDocument.%1.Placement=%6\n") - .arg(name) - .arg(ui.sphereRadius->value(),0,'f',2) - .arg(ui.sphereAngle1->value(),0,'f',2) - .arg(ui.sphereAngle2->value(),0,'f',2) - .arg(ui.sphereAngle3->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 5) { // ellipsoid - name = QString::fromAscii(doc->getUniqueObjectName("Ellipsoid").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Ellipsoid\",\"%1\")\n" - "App.ActiveDocument.%1.Radius1=%2\n" - "App.ActiveDocument.%1.Radius2=%3\n" - "App.ActiveDocument.%1.Angle1=%4\n" - "App.ActiveDocument.%1.Angle2=%5\n" - "App.ActiveDocument.%1.Angle3=%6\n" - "App.ActiveDocument.%1.Placement=%7\n") - .arg(name) - .arg(ui.ellipsoidRadius1->value(),0,'f',2) - .arg(ui.ellipsoidRadius2->value(),0,'f',2) - .arg(ui.ellipsoidAngle1->value(),0,'f',2) - .arg(ui.ellipsoidAngle2->value(),0,'f',2) - .arg(ui.ellipsoidAngle3->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 6) { // torus - name = QString::fromAscii(doc->getUniqueObjectName("Torus").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Torus\",\"%1\")\n" - "App.ActiveDocument.%1.Radius1=%2\n" - "App.ActiveDocument.%1.Radius2=%3\n" - "App.ActiveDocument.%1.Angle1=%4\n" - "App.ActiveDocument.%1.Angle2=%5\n" - "App.ActiveDocument.%1.Angle3=%6\n" - "App.ActiveDocument.%1.Placement=%7\n") - .arg(name) - .arg(ui.torusRadius1->value(),0,'f',2) - .arg(ui.torusRadius2->value(),0,'f',2) - .arg(ui.torusAngle1->value(),0,'f',2) - .arg(ui.torusAngle2->value(),0,'f',2) - .arg(ui.torusAngle3->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 7) { // wedge - name = QString::fromAscii(doc->getUniqueObjectName("Wedge").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Wedge\",\"%1\")\n" - "App.ActiveDocument.%1.Xmin=%2\n" - "App.ActiveDocument.%1.Ymin=%3\n" - "App.ActiveDocument.%1.Zmin=%4\n" - "App.ActiveDocument.%1.X2min=%5\n" - "App.ActiveDocument.%1.Z2min=%6\n" - "App.ActiveDocument.%1.Xmax=%7\n" - "App.ActiveDocument.%1.Ymax=%8\n" - "App.ActiveDocument.%1.Zmax=%9\n" - "App.ActiveDocument.%1.X2max=%10\n" - "App.ActiveDocument.%1.Z2max=%11\n" - "App.ActiveDocument.%1.Placement=%12\n") - .arg(name) - .arg(ui.wedgeXmin->value(),0,'f',2) - .arg(ui.wedgeYmin->value(),0,'f',2) - .arg(ui.wedgeZmin->value(),0,'f',2) - .arg(ui.wedgeX2min->value(),0,'f',2) - .arg(ui.wedgeZ2min->value(),0,'f',2) - .arg(ui.wedgeXmax->value(),0,'f',2) - .arg(ui.wedgeYmax->value(),0,'f',2) - .arg(ui.wedgeZmax->value(),0,'f',2) - .arg(ui.wedgeX2max->value(),0,'f',2) - .arg(ui.wedgeZ2max->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 8) { // helix - name = QString::fromAscii(doc->getUniqueObjectName("Helix").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Helix\",\"%1\")\n" - "App.ActiveDocument.%1.Pitch=%2\n" - "App.ActiveDocument.%1.Height=%3\n" - "App.ActiveDocument.%1.Radius=%4\n" - "App.ActiveDocument.%1.Angle=%5\n" - "App.ActiveDocument.%1.Placement=%6\n") - .arg(name) - .arg(ui.helixPitch->value(),0,'f',2) - .arg(ui.helixHeight->value(),0,'f',2) - .arg(ui.helixRadius->value(),0,'f',2) - .arg(ui.helixAngle->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 9) { // circle - name = QString::fromAscii(doc->getUniqueObjectName("Circle").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Circle\",\"%1\")\n" - "App.ActiveDocument.%1.Radius=%2\n" - "App.ActiveDocument.%1.Angle0=%3\n" - "App.ActiveDocument.%1.Angle1=%4\n" - "App.ActiveDocument.%1.Placement=%5\n") - .arg(name) - .arg(ui.circleRadius->value(),0,'f',2) - .arg(ui.circleAngle0->value(),0,'f',2) - .arg(ui.circleAngle1->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 10) { // vertex - name = QString::fromAscii(doc->getUniqueObjectName("Vertex").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Vertex\",\"%1\")\n" - "App.ActiveDocument.%1.X=%2\n" - "App.ActiveDocument.%1.Y=%3\n" - "App.ActiveDocument.%1.Z=%4\n" - "App.ActiveDocument.%1.Placement=%5\n") - .arg(name) - .arg(ui.vertexX->value(),0,'f',2) - .arg(ui.vertexY->value(),0,'f',2) - .arg(ui.vertexZ->value(),0,'f',2) - .arg(this->toPlacement()); - } - else if (ui.comboBox1->currentIndex() == 11) { // edge - name = QString::fromAscii(doc->getUniqueObjectName("Edge").c_str()); - cmd = QString::fromAscii( - "App.ActiveDocument.addObject(\"Part::Edge\",\"%1\")\n" - "App.ActiveDocument.%1.X1=%2\n" - "App.ActiveDocument.%1.Y1=%3\n" - "App.ActiveDocument.%1.Z1=%4\n" - "App.ActiveDocument.%1.X2=%5\n" - "App.ActiveDocument.%1.Y2=%6\n" - "App.ActiveDocument.%1.Z2=%7\n" - "App.ActiveDocument.%1.Placement=%8\n") - .arg(name) - .arg(ui.edgeX1->value(),0,'f',2) - .arg(ui.edgeY1->value(),0,'f',2) - .arg(ui.edgeZ1->value(),0,'f',2) - .arg(ui.edgeX2->value(),0,'f',2) - .arg(ui.edgeY2->value(),0,'f',2) - .arg(ui.edgeZ2->value(),0,'f',2) - .arg(this->toPlacement()); - } - - // Execute the Python block - QString prim = tr("Create %1").arg(ui.comboBox1->currentText()); - Gui::Application::Instance->activeDocument()->openCommand(prim.toUtf8()); - Gui::Command::doCommand(Gui::Command::Doc, (const char*)cmd.toAscii()); - Gui::Application::Instance->activeDocument()->commitCommand(); - Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); - Gui::Command::doCommand(Gui::Command::Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); - } - catch (const Base::PyException& e) { - QMessageBox::warning(this, tr("Create %1") - .arg(ui.comboBox1->currentText()), QString::fromLatin1(e.what())); - } + QPushButton* btn = box->button(QDialogButtonBox::Ok); + btn->setText(QApplication::translate("PartGui::DlgPrimitives", "&Create")); } + +bool TaskPrimitives::accept() +{ + widget->createPrimitive(location->toPlacement()); + return false; +} + +bool TaskPrimitives::reject() +{ + return true; +} #include "moc_DlgPrimitives.cpp" diff --git a/src/Mod/Part/Gui/DlgPrimitives.h b/src/Mod/Part/Gui/DlgPrimitives.h index 0e50ab4f6..d485047df 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.h +++ b/src/Mod/Part/Gui/DlgPrimitives.h @@ -24,21 +24,34 @@ #define PARTGUI_DLGPRIMITIVES_H #include -#include +#include #include "ui_DlgPrimitives.h" +#include "ui_Location.h" class SoEventCallback; namespace PartGui { -class DlgPrimitives : public Gui::LocationDialogComp +class DlgPrimitives : public QWidget { Q_OBJECT public: - DlgPrimitives(QWidget* parent = 0, Qt::WFlags fl = 0); + DlgPrimitives(QWidget* parent = 0); ~DlgPrimitives(); - void accept(); + void createPrimitive(const QString&); + +private: + Ui_DlgPrimitives ui; +}; + +class Location : public QWidget +{ + Q_OBJECT + +public: + Location(QWidget* parent = 0); + ~Location(); QString toPlacement() const; private Q_SLOTS: @@ -47,6 +60,27 @@ private Q_SLOTS: private: static void pickCallback(void * ud, SoEventCallback * n); QPointer activeView; + Ui_Location ui; +}; + +class TaskPrimitives : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskPrimitives(); + ~TaskPrimitives(); + +public: + bool accept(); + bool reject(); + + QDialogButtonBox::StandardButtons getStandardButtons() const; + void modifyStandardButtons(QDialogButtonBox*); + +private: + DlgPrimitives* widget; + Location* location; }; } // namespace PartGui diff --git a/src/Mod/Part/Gui/DlgPrimitives.ui b/src/Mod/Part/Gui/DlgPrimitives.ui index afbcc9441..5423a5de0 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.ui +++ b/src/Mod/Part/Gui/DlgPrimitives.ui @@ -1,96 +1,102 @@ PartGui::DlgPrimitives - + 0 0 - 480 - 341 + 285 + 370 Geometric Primitives - + true - - - 9 - - - 6 - - - - - 6 - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - &Create - - - Alt+C - - - true - - - true - - - - - - - Cl&ose - - - Alt+O - - - true - - - - - + Primitive - - - 9 - - - 6 - - + + + + + + 0 + 0 + + + + 14 + + + + Plane + + + + + Box + + + + + Cylinder + + + + + Cone + + + + + Sphere + + + + + Ellipsoid + + + + + Torus + + + + + Wedge + + + + + Helix + + + + + Circle + + + + + Point + + + + + Line + + + + + Parameter @@ -947,134 +953,179 @@ - + - - - X min - - - - - - - - - - x max - - - - - - - 10.000000000000000 - - + + + + + X min/max: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + 10.000000000000000 + + + + + + + Y min/max: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + 10.000000000000000 + + + + + + + Z min/max: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + 10.000000000000000 + + + + + + + X2 min/max: + + + + + + + + 0 + 0 + + + + 2.000000000000000 + + + + + + + + 0 + 0 + + + + 8.000000000000000 + + + + + + + Z2 min/max: + + + + + + + + 0 + 0 + + + + 2.000000000000000 + + + + + + + + 0 + 0 + + + + 8.000000000000000 + + + + - - - Y min + + + Qt::Vertical - - - - - - - - - Y max + + + 20 + 81 + - - - - - - 10.000000000000000 - - - - - - - Z min - - - - - - - - - - Z max - - - - - - - 10.000000000000000 - - - - - - - X2 min - - - - - - - 2.000000000000000 - - - - - - - X2 max - - - - - - - 8.000000000000000 - - - - - - - Z2 min - - - - - - - 2.000000000000000 - - - - - - - Z2 max - - - - - - - 8.000000000000000 - - + @@ -1161,7 +1212,7 @@ - Angle - 0 for cyl + Angle: @@ -1215,7 +1266,7 @@ - Angle0 + Angle 1: @@ -1232,7 +1283,7 @@ - Angle1 + Angle 2: @@ -1270,57 +1321,64 @@ - - - - 10 - 10 - 201 - 76 - - - - - - - - - - - - - - - - X Value: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Y Value: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Z Value: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - + + + + + + + + + + + + + + + + X: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Y: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Z: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + Qt::Vertical + + + + 20 + 139 + + + + + @@ -1329,30 +1387,30 @@ - X + X: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - Y + Y: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - Z + Z: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -1366,7 +1424,7 @@ - Finish Vertex + End point Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -1376,37 +1434,37 @@ - Start Vertex + Start point - X + X: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - Y + Y: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - Z + Z: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -1457,6 +1515,19 @@ + + + + Qt::Vertical + + + + 20 + 0 + + + + @@ -1464,196 +1535,6 @@ - - - - Qt::Horizontal - - - - 221 - 20 - - - - - - - - - 0 - 0 - - - - 14 - - - - Plane - - - - - Box - - - - - Cylinder - - - - - Cone - - - - - Sphere - - - - - Ellipsoid - - - - - Torus - - - - - Wedge - - - - - Helix - - - - - Circle - - - - - Vertex - - - - - Edge - - - - - - - - Position - - - - - - 0 - - - 6 - - - - - -2147480000.000000000000000 - - - 2147480000.000000000000000 - - - - - - - Z: - - - - - - - X: - - - - - - - Direction: - - - - - - - -2147480000.000000000000000 - - - 2147480000.000000000000000 - - - - - - - Y: - - - - - - - -1 - - - - - - - -2147480000.000000000000000 - - - 2147480000.000000000000000 - - - - - - - - - 3D View - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - @@ -1662,10 +1543,6 @@ comboBox1 - xPos - yPos - zPos - direction planeLength planeWidth boxLength @@ -1692,8 +1569,6 @@ torusAngle1 torusAngle2 torusAngle3 - createSolidButton - buttonClose @@ -1713,37 +1588,5 @@ - - buttonClose - clicked() - PartGui::DlgPrimitives - reject() - - - 254 - 282 - - - 44 - 268 - - - - - createSolidButton - clicked() - PartGui::DlgPrimitives - accept() - - - 160 - 276 - - - 8 - 277 - - - diff --git a/src/Mod/Part/Gui/Location.ui b/src/Mod/Part/Gui/Location.ui new file mode 100644 index 000000000..69f22d4dd --- /dev/null +++ b/src/Mod/Part/Gui/Location.ui @@ -0,0 +1,81 @@ + + + PartGui::Location + + + + 0 + 0 + 209 + 205 + + + + Location + + + true + + + + + + Position + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 3D View + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Gui::LocationWidget + QWidget +
Gui/InputVector.h
+
+
+ + +
diff --git a/src/Mod/Part/Gui/Makefile.am b/src/Mod/Part/Gui/Makefile.am index 4f9c63311..fe7d7a8dd 100644 --- a/src/Mod/Part/Gui/Makefile.am +++ b/src/Mod/Part/Gui/Makefile.am @@ -12,6 +12,7 @@ BUILT_SOURCES=\ ui_DlgPartImportIges.h \ ui_DlgPartImportStep.h \ ui_DlgPrimitives.h \ + ui_Location.h \ ui_DlgSettings3DViewPart.h \ ui_DlgSettingsGeneral.h \ ui_Mirroring.h \ @@ -220,6 +221,7 @@ EXTRA_DIST = \ DlgPartImportIges.ui \ DlgPartImportStep.ui \ DlgPrimitives.ui \ + Location.ui \ DlgSettings3DViewPart.ui \ DlgSettingsGeneral.ui \ Mirroring.ui \ diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 15372ad85..8a902b2b9 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -75,19 +75,10 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,QWidget *parent) ui->doubleSpinBox->setValue(l); ui->doubleSpinBox->selectAll(); ui->checkBoxMirrored->setChecked(mirrored); - - // check if the sketch has support - Sketcher::SketchObject *pcSketch; - if (pcPad->Sketch.getValue()) { - pcSketch = static_cast(pcPad->Sketch.getValue()); - if (pcSketch->Support.getValue()) - // in case of sketch with support, reverse makes no sense (goes into the part) - ui->checkBoxReversed->setEnabled(0); - else - ui->checkBoxReversed->setChecked(reversed); - } - + // According to bug #0000521 the reversed option + // shouldn't be de-activated if the pad has a support face ui->checkBoxReversed->setChecked(reversed); + // Make sure that the spin box has the focus to get key events // Calling setFocus() directly doesn't work because the spin box is not // yet visible. diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui index e7a062aa7..a80c300fe 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui @@ -53,6 +53,9 @@ 1 + + -360.000000000000000 + 360.000000000000000 diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 4f99c7844..35f6bdb64 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -321,7 +321,8 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed) Geoms.push_back(def); // arcs require an ArcRules constraint for the end points - GCSsys.addConstraintArcRules(a); + if (!fixed) + GCSsys.addConstraintArcRules(a); // return the position of the newly added geometry return Geoms.size()-1; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 904b8b063..1bde4c70f 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -26,12 +26,16 @@ # include # include # include +# include # include # include +# include # include # include # include # include +# include +# include #endif #include @@ -92,7 +96,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) // setup and diagnose the sketch rebuildExternalGeometry(); Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), true, getExternalGeometryCount()); if (dofs < 0) { // over-constrained sketch std::string msg="Over-constrained sketch\n"; @@ -123,7 +127,7 @@ int SketchObject::hasConflicts(void) const { // set up a sketch (including dofs counting and diagnosing of conflicts) Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), true, getExternalGeometryCount()); if (dofs < 0) // over-constrained sketch return -2; @@ -161,7 +165,7 @@ int SketchObject::setDatum(int ConstrId, double Datum) // set up a sketch (including dofs counting and diagnosing of conflicts) Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), true, getExternalGeometryCount()); int err=0; if (dofs < 0) // over-constrained sketch @@ -187,7 +191,7 @@ int SketchObject::setDatum(int ConstrId, double Datum) int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative) { Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), true, getExternalGeometryCount()); if (dofs < 0) // over-constrained sketch return -1; @@ -668,7 +672,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; - for (std::vector::const_iterator it=constraints.begin(); + for (std::vector::const_iterator it=constraints.begin(); it != constraints.end(); ++it) { Constraint *constr = *(it); if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) { @@ -691,7 +695,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) newConstr->SecondPos = secondPos1; delConstraintOnPoint(GeoId1, secondPos1, false); } - + addConstraint(newConstr); // Reset the second pos @@ -737,7 +741,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) ConstraintType constrType = Sketcher::PointOnObject; PointPos secondPos = Sketcher::none; - for (std::vector::const_iterator it=constraints.begin(); + for (std::vector::const_iterator it=constraints.begin(); it != constraints.end(); ++it) { Constraint *constr = *(it); if ((constr->First == GeoId1 && constr->Second == GeoId)) { @@ -818,7 +822,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; - for (std::vector::const_iterator it=constraints.begin(); + for (std::vector::const_iterator it=constraints.begin(); it != constraints.end(); ++it) { Constraint *constr = *(it); if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) { @@ -904,7 +908,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; - for (std::vector::const_iterator it=constraints.begin(); + for (std::vector::const_iterator it=constraints.begin(); it != constraints.end(); ++it) { Constraint *constr = *(it); if (secondPos1 == Sketcher::none && @@ -970,7 +974,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) ConstraintType constrType = Sketcher::PointOnObject; PointPos secondPos = Sketcher::none; - for (std::vector::const_iterator it=constraints.begin(); + for (std::vector::const_iterator it=constraints.begin(); it != constraints.end(); ++it) { Constraint *constr = *(it); if ((constr->First == GeoId1 && constr->Second == GeoId)) { @@ -1013,7 +1017,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) if (constrType == Sketcher::Coincident) newConstr->SecondPos = secondPos; - + addConstraint(newConstr); delete newConstr; return 0; @@ -1038,6 +1042,13 @@ int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) std::vector originalObjects = Objects; std::vector originalSubElements = SubElements; + std::vector ::iterator it; + it = std::find(originalSubElements.begin(), originalSubElements.end(), SubName); + + // avoid duplicates + if (it != originalSubElements.end()) + return -1; + // add the new ones Objects.push_back(Obj); SubElements.push_back(std::string(SubName)); @@ -1065,7 +1076,7 @@ int SketchObject::delExternal(int ExtGeoId) return 0; } - + const Part::Geometry* SketchObject::getGeometry(int GeoId) const { if (GeoId >= 0) { @@ -1096,6 +1107,12 @@ void SketchObject::rebuildExternalGeometry(void) Rot.multVec(dX,dX); Base::Placement invPlm = Plm.inverse(); + Base::Matrix4D invMat = invPlm.toMatrix(); + gp_Trsf mov; + mov.SetValues(invMat[0][0],invMat[0][1],invMat[0][2],invMat[0][3], + invMat[1][0],invMat[1][1],invMat[1][2],invMat[1][3], + invMat[2][0],invMat[2][1],invMat[2][2],invMat[2][3], + 0.00001,0.00001); gp_Ax3 sketchAx3(gp_Pnt(Pos.x,Pos.y,Pos.z), gp_Dir(dN.x,dN.y,dN.z), @@ -1103,6 +1120,8 @@ void SketchObject::rebuildExternalGeometry(void) gp_Pln sketchPlane(sketchAx3); Handle(Geom_Plane) gPlane = new Geom_Plane(sketchPlane); + BRepBuilderAPI_MakeFace mkFace(sketchPlane); + TopoDS_Shape aProjFace = mkFace.Shape(); for (std::vector::iterator it=ExternalGeo.begin(); it != ExternalGeo.end(); ++it) if (*it) delete *it; @@ -1122,7 +1141,14 @@ void SketchObject::rebuildExternalGeometry(void) const Part::Feature *refObj=static_cast(Obj); const Part::TopoShape& refShape=refObj->Shape.getShape(); - TopoDS_Shape refSubShape=refShape.getSubShape(SubElement.c_str()); + TopoDS_Shape refSubShape; + try { + refSubShape = refShape.getSubShape(SubElement.c_str()); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } switch (refSubShape.ShapeType()) { @@ -1165,7 +1191,69 @@ void SketchObject::rebuildExternalGeometry(void) ExternalGeo.push_back(line); } else { - throw Base::Exception("Not yet supported geometry for external geometry"); + try { + BRepOffsetAPI_NormalProjection mkProj(aProjFace); + mkProj.Add(edge); + mkProj.Build(); + const TopoDS_Shape& projShape = mkProj.Projection(); + if (!projShape.IsNull()) { + TopExp_Explorer xp; + for (xp.Init(projShape, TopAbs_EDGE); xp.More(); xp.Next()) { + TopoDS_Edge edge = TopoDS::Edge(xp.Current()); + TopLoc_Location loc(mov); + edge.Location(loc); + BRepAdaptor_Curve curve(edge); + if (curve.GetType() == GeomAbs_Line) { + gp_Pnt P1 = curve.Value(curve.FirstParameter()); + gp_Pnt P2 = curve.Value(curve.LastParameter()); + Base::Vector3d p1(P1.X(),P1.Y(),P1.Z()); + Base::Vector3d p2(P2.X(),P2.Y(),P2.Z()); + + if (Base::Distance(p1,p2) < Precision::Confusion()) { + std::string msg = SubElement + " perpendicular to the sketch plane cannot be used as external geometry"; + throw Base::Exception(msg.c_str()); + } + + Part::GeomLineSegment* line = new Part::GeomLineSegment(); + line->setPoints(p1,p2); + + line->Construction = true; + ExternalGeo.push_back(line); + } + else if (curve.GetType() == GeomAbs_Circle) { + gp_Circ c = curve.Circle(); + gp_Pnt p = c.Location(); + gp_Pnt P1 = curve.Value(curve.FirstParameter()); + gp_Pnt P2 = curve.Value(curve.LastParameter()); + + if (P1.SquareDistance(P2) < Precision::Confusion()) { + Part::GeomCircle* circle = new Part::GeomCircle(); + circle->setRadius(c.Radius()); + circle->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z())); + + circle->Construction = true; + ExternalGeo.push_back(circle); + } + else { + Part::GeomArcOfCircle* arc = new Part::GeomArcOfCircle(); + arc->setRadius(c.Radius()); + arc->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z())); + arc->setRange(curve.FirstParameter(), curve.LastParameter()); + + arc->Construction = true; + ExternalGeo.push_back(arc); + } + } + else { + throw Base::Exception("Not yet supported geometry for external geometry"); + } + } + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } } } break; @@ -1177,7 +1265,6 @@ void SketchObject::rebuildExternalGeometry(void) break; } } - } std::vector SketchObject::getCompleteGeometry(void) const @@ -1293,7 +1380,6 @@ void SketchObject::Restore(XMLReader &reader) { // read the father classes Part::Part2DObject::Restore(reader); - rebuildExternalGeometry(); Constraints.acceptGeometry(getCompleteGeometry()); rebuildVertexIndex(); } @@ -1305,6 +1391,16 @@ void SketchObject::onChanged(const App::Property* prop) Part::Part2DObject::onChanged(prop); } +void SketchObject::onDocumentRestored() +{ + try { + rebuildExternalGeometry(); + Constraints.acceptGeometry(getCompleteGeometry()); + } + catch (...) { + } +} + void SketchObject::getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) { if (VertexId < 0 || VertexId >= (int)VertexId2GeoId.size()) { diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index e3ae6b800..84f2dd0c7 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -148,6 +148,7 @@ public: protected: /// get called by the container when a property has changed virtual void onChanged(const App::Property* /*prop*/); + virtual void onDocumentRestored(); private: std::vector ExternalGeo; diff --git a/src/Mod/Sketcher/App/SketchObjectPy.xml b/src/Mod/Sketcher/App/SketchObjectPy.xml index e4eae9a3d..e5b93b44e 100644 --- a/src/Mod/Sketcher/App/SketchObjectPy.xml +++ b/src/Mod/Sketcher/App/SketchObjectPy.xml @@ -45,7 +45,7 @@ - add a link to a external geometry to use them in a constraint + add a link to an external geometry to use it in a constraint diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index c57e6865c..d7ecedd90 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -143,7 +143,7 @@ PyObject* SketchObjectPy::addExternal(PyObject *args) PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } - // check if its belong to the sketch support + // check if it belongs to the sketch support if (this->getSketchObjectPtr()->Support.getValue() != Obj) { std::stringstream str; str << ObjectName << "is not supported by this sketch"; diff --git a/src/Mod/Sketcher/App/SketchObjectSF.cpp b/src/Mod/Sketcher/App/SketchObjectSF.cpp index 2f82b4cc3..a0adf0bc1 100644 --- a/src/Mod/Sketcher/App/SketchObjectSF.cpp +++ b/src/Mod/Sketcher/App/SketchObjectSF.cpp @@ -52,7 +52,7 @@ short SketchObjectSF::mustExecute() const App::DocumentObjectExecReturn *SketchObjectSF::execute(void) { - Base::Console().Warning("%s: This feature is deprecated and will not longer supported in future version of FreeCAD \n",this->getNameInDocument()); + Base::Console().Warning("%s: This feature is deprecated and won't be longer supported in future FreeCAD versions\n",this->getNameInDocument()); // do nothing return App::DocumentObject::StdReturn; } diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index 5b3795b57..069e18162 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -755,6 +755,9 @@ int System::solve_DL(SubSystem* subsys) int xsize = subsys->pSize(); int csize = subsys->cSize(); + if (xsize == 0) + return Success; + Eigen::VectorXd x(xsize), x_new(xsize); Eigen::VectorXd fx(csize), fx_new(csize); Eigen::MatrixXd Jx(csize, xsize), Jx_new(csize, xsize); diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index b00676d5e..f6f77b7e6 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -66,6 +66,17 @@ void updateDatumDistance(Gui::Document *doc, Constraint *constr) } } +bool checkBothExternal(int GeoId1, int GeoId2) +{ + if (GeoId1 < 0 && GeoId2 < 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a constraint between two external geometries!")); + return true; + } + else + return false; +} + namespace SketcherGui { struct SketchSelection{ @@ -188,7 +199,7 @@ void CmdSketcherConstrainHorizontal::activated(int iMsg) std::vector ids; // go through the selected subelements - for(std::vector::const_iterator it=SubNames.begin();it!=SubNames.end();++it){ + for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle edges if (it->size() > 4 && it->substr(0,4) == "Edge") { int index=std::atoi(it->substr(4,4000).c_str()); @@ -217,6 +228,13 @@ void CmdSketcherConstrainHorizontal::activated(int iMsg) ids.push_back(index); } } + + if (ids.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Impossible constraint"), + QObject::tr("The selected item(s) can't accept a horizontal constraint!")); + return; + } + // undo command open openCommand("add horizontal constraint"); for (std::vector::iterator it=ids.begin(); it != ids.end(); it++) { @@ -272,7 +290,6 @@ void CmdSketcherConstrainVertical::activated(int iMsg) const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); std::vector ids; - // go through the selected subelements for (std::vector::const_iterator it=SubNames.begin();it!=SubNames.end();++it) { // only handle edges @@ -304,6 +321,12 @@ void CmdSketcherConstrainVertical::activated(int iMsg) } } + if (ids.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Impossible constraint"), + QObject::tr("The selected item(s) can't accept a vertical constraint!")); + return; + } + // undo command open openCommand("add vertical constraint"); for (std::vector::iterator it=ids.begin(); it != ids.end(); it++) { @@ -500,13 +523,6 @@ CmdSketcherConstrainDistance::CmdSketcherConstrainDistance() void CmdSketcherConstrainDistance::activated(int iMsg) { -#if 0 - - SketchSelection selection; - - int num = selection.setUp(); - -#else // get the selection std::vector selection = getSelection().getSelectionEx(); @@ -568,8 +584,9 @@ void CmdSketcherConstrainDistance::activated(int iMsg) getSelection().clearSelection(); return; } - else if ((VtId1 >= 0 && GeoId2 >= 0) || (VtId2 >= 0 && GeoId1 >= 0)) { // point to line distance - if (VtId2 >= 0 && GeoId1 >= 0) { + else if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) || + (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) { // point to line distance + if (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef) { std::swap(VtId1,VtId2); std::swap(GeoId1,GeoId2); } @@ -602,7 +619,13 @@ void CmdSketcherConstrainDistance::activated(int iMsg) return; } } - else if (GeoId1 >= 0) { // line length + else if (GeoId1 != Constraint::GeoUndef) { // line length + if (GeoId1 < 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a length constraint on an external geometry!")); + return; + } + const Part::Geometry *geom = Obj->getGeometry(GeoId1); if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *lineSeg; @@ -630,7 +653,6 @@ void CmdSketcherConstrainDistance::activated(int iMsg) QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly one line or one point and one line or two points from the sketch.")); return; -#endif } bool CmdSketcherConstrainDistance::isActive(void) @@ -696,8 +718,9 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) VtId2 = std::atoi(SubNames[1].substr(6,4000).c_str()); } - if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) || (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) { - if (VtId2 >= 0 && GeoId1 >= 0) { + if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) || + (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) { + if (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef) { std::swap(VtId1,VtId2); std::swap(GeoId1,GeoId2); } @@ -705,6 +728,9 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) Sketcher::PointPos PosId1; Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1); + if (checkBothExternal(GeoId1, GeoId2)) + return; + const Part::Geometry *geom = Obj->getGeometry(GeoId2); // Currently only accepts line segments and circles @@ -820,7 +846,15 @@ void CmdSketcherConstrainDistanceX::activated(int iMsg) getSelection().clearSelection(); return; } - else if (GeoId1 >= 0 && GeoId2 == Constraint::GeoUndef && VtId2 < 0) { // horizontal length of a line + else if (GeoId1 != Constraint::GeoUndef && + GeoId2 == Constraint::GeoUndef && VtId2 < 0) { // horizontal length of a line + + if (GeoId1 < 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a horizontal length constraint on an external geometry!")); + return; + } + const Part::Geometry *geom = Obj->getGeometry(GeoId1); if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *lineSeg; @@ -965,7 +999,15 @@ void CmdSketcherConstrainDistanceY::activated(int iMsg) getSelection().clearSelection(); return; } - else if (GeoId1 >= 0 && GeoId2 == Constraint::GeoUndef && VtId2 < 0) { // horizontal length of a line + else if (GeoId1 != Constraint::GeoUndef && + GeoId2 == Constraint::GeoUndef && VtId2 < 0) { // vertical length of a line + + if (GeoId1 < 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a vertical length constraint on an external geometry!")); + return; + } + const Part::Geometry *geom = Obj->getGeometry(GeoId1); if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *lineSeg; @@ -1149,6 +1191,8 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) int GeoId1,GeoId2; if (SubNames[0].size() > 4 && SubNames[0].substr(0,4) == "Edge") GeoId1 = std::atoi(SubNames[0].substr(4,4000).c_str()); + else if (SubNames[0].size() > 12 && SubNames[0].substr(0,12) == "ExternalEdge") + GeoId1 = -3 - std::atoi(SubNames[0].substr(12,4000).c_str()); else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly two lines from the sketch.")); @@ -1157,12 +1201,17 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) if (SubNames[1].size() > 4 && SubNames[1].substr(0,4) == "Edge") GeoId2 = std::atoi(SubNames[1].substr(4,4000).c_str()); + else if (SubNames[1].size() > 12 && SubNames[1].substr(0,12) == "ExternalEdge") + GeoId2 = -3 - std::atoi(SubNames[1].substr(12,4000).c_str()); else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly two lines from the sketch.")); return; } + if (checkBothExternal(GeoId1, GeoId2)) + return; + const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); @@ -1235,11 +1284,15 @@ void CmdSketcherConstrainTangent::activated(int iMsg) int GeoId1=Constraint::GeoUndef, VtId1=-1, GeoId2=Constraint::GeoUndef, VtId2=-1; if (SubNames[0].size() > 4 && SubNames[0].substr(0,4) == "Edge") GeoId1 = std::atoi(SubNames[0].substr(4,4000).c_str()); + else if (SubNames[0].size() > 12 && SubNames[0].substr(0,12) == "ExternalEdge") + GeoId1 = -3 - std::atoi(SubNames[0].substr(12,4000).c_str()); else if (SubNames[0].size() > 6 && SubNames[0].substr(0,6) == "Vertex") VtId1 = std::atoi(SubNames[0].substr(6,4000).c_str()); if (SubNames[1].size() > 4 && SubNames[1].substr(0,4) == "Edge") GeoId2 = std::atoi(SubNames[1].substr(4,4000).c_str()); + else if (SubNames[1].size() > 12 && SubNames[1].substr(0,12) == "ExternalEdge") + GeoId2 = -3 - std::atoi(SubNames[1].substr(12,4000).c_str()); else if (SubNames[1].size() > 6 && SubNames[1].substr(0,6) == "Vertex") VtId2 = std::atoi(SubNames[1].substr(6,4000).c_str()); @@ -1247,6 +1300,10 @@ void CmdSketcherConstrainTangent::activated(int iMsg) if (VtId1 >= 0 && VtId2 >= 0) { // tangency at common point Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1); Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2); + + if (checkBothExternal(GeoId1, GeoId2)) + return; + openCommand("add tangent constraint"); Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ", @@ -1256,14 +1313,19 @@ void CmdSketcherConstrainTangent::activated(int iMsg) getSelection().clearSelection(); return; } - else if ((VtId1 >= 0 && GeoId2 >= 0) || (VtId2 >= 0 && GeoId1 >= 0)) { // VtId1 is a tangency point - if (VtId2 >= 0 && GeoId1 >= 0) { + else if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) || + (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) { // VtId1 is a tangency point + if (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef) { VtId1 = VtId2; VtId2 = -1; GeoId2 = GeoId1; GeoId1 = -1; } Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1); + + if (checkBothExternal(GeoId1, GeoId2)) + return; + openCommand("add tangent constraint"); Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d)) ", @@ -1273,7 +1335,11 @@ void CmdSketcherConstrainTangent::activated(int iMsg) getSelection().clearSelection(); return; } - else if (GeoId1 >= 0 && GeoId2 >= 0) { // simple tangency between GeoId1 and GeoId2 + else if (GeoId1 != Constraint::GeoUndef && GeoId2 != Constraint::GeoUndef) { // simple tangency between GeoId1 and GeoId2 + + if (checkBothExternal(GeoId1, GeoId2)) + return; + openCommand("add tangent constraint"); Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", @@ -1416,12 +1482,21 @@ void CmdSketcherConstrainAngle::activated(int iMsg) int GeoId1=Constraint::GeoUndef, GeoId2=Constraint::GeoUndef; if (SubNames[0].size() > 4 && SubNames[0].substr(0,4) == "Edge") GeoId1 = std::atoi(SubNames[0].substr(4,4000).c_str()); + else if (SubNames[0].size() > 12 && SubNames[0].substr(0,12) == "ExternalEdge") + GeoId1 = -3 - std::atoi(SubNames[0].substr(12,4000).c_str()); + if (SubNames.size() == 2) { if (SubNames[1].size() > 4 && SubNames[1].substr(0,4) == "Edge") GeoId2 = std::atoi(SubNames[1].substr(4,4000).c_str()); + else if (SubNames[1].size() > 12 && SubNames[1].substr(0,12) == "ExternalEdge") + GeoId2 = -3 - std::atoi(SubNames[1].substr(12,4000).c_str()); } - if (GeoId2 >= 0) { // line to line angle + if (GeoId2 != Constraint::GeoUndef) { // line to line angle + + if (checkBothExternal(GeoId1, GeoId2)) + return; + const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); if (geom1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && @@ -1475,7 +1550,13 @@ void CmdSketcherConstrainAngle::activated(int iMsg) getSelection().clearSelection(); return; } - } else if (GeoId1 >= 0) { // line angle + } else if (GeoId1 != Constraint::GeoUndef) { // line angle + if (GeoId1 < 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add an angle constraint on an external geometry!")); + return; + } + const Part::Geometry *geom = Obj->getGeometry(GeoId1); if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *lineSeg; diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 468a49a27..d530b08f8 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -364,19 +364,19 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe float dci = (float) QApplication::doubleClickInterval()/1000.0f; float length = (point - prvClickPoint).length(); - if (edit->PreselectPoint >= 0) { + if (edit->PreselectPoint != -1) { //Base::Console().Log("start dragging, point:%d\n",this->DragPoint); Mode = STATUS_SELECT_Point; done = true; - } else if (edit->PreselectCurve >= 0) { + } else if (edit->PreselectCurve != -1) { //Base::Console().Log("start dragging, point:%d\n",this->DragPoint); Mode = STATUS_SELECT_Edge; done = true; - } else if (edit->PreselectCross >= 0) { + } else if (edit->PreselectCross != -1) { //Base::Console().Log("start dragging, point:%d\n",this->DragPoint); Mode = STATUS_SELECT_Cross; done = true; - } else if (edit->PreselectConstraint >= 0) { + } else if (edit->PreselectConstraint != -1) { //Base::Console().Log("start dragging, point:%d\n",this->DragPoint); Mode = STATUS_SELECT_Constraint; done = true; @@ -435,14 +435,11 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe case STATUS_SELECT_Edge: if (pp) { //Base::Console().Log("Select Point:%d\n",this->DragPoint); - int maxGeoId = getSketchObject()->getHighestCurveIndex(); std::stringstream ss; - if (edit->PreselectCurve <= maxGeoId) + if (edit->PreselectCurve >= 0) ss << "Edge" << edit->PreselectCurve; - else { // external geometry - int extGeoCount = getSketchObject()->getExternalGeometryCount(); - ss << "ExternalEdge" << extGeoCount - 2 - (edit->PreselectCurve - maxGeoId); - } + else // external geometry + ss << "ExternalEdge" << -edit->PreselectCurve - 3; // If edge already selected move from selection if (Gui::Selection().isSelected(getSketchObject()->getDocument()->getName() @@ -590,11 +587,11 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe case STATUS_NONE: { // A right click shouldn't change the Edit Mode - if (edit->PreselectPoint >= 0) { + if (edit->PreselectPoint != -1) { return true; - } else if (edit->PreselectCurve >= 0) { + } else if (edit->PreselectCurve != -1) { return true; - } else if (edit->PreselectConstraint >= 0) { + } else if (edit->PreselectConstraint != -1) { return true; } else { //Get Viewer @@ -665,7 +662,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe if (edit->PreselectCurve == index) rightClickOnSelectedLine = true; } else { - // The selection is not exclusivly edges + // The selection is not exclusively edges rightClickOnSelectedLine = false; } } // End of Iteration @@ -700,16 +697,16 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe void ViewProviderSketch::editDoubleClicked(void) { - if (edit->PreselectPoint >= 0) { + if (edit->PreselectPoint != -1) { Base::Console().Log("double click point:%d\n",edit->PreselectPoint); } - else if (edit->PreselectCurve >= 0) { + else if (edit->PreselectCurve != -1) { Base::Console().Log("double click edge:%d\n",edit->PreselectCurve); } - else if (edit->PreselectCross >= 0) { + else if (edit->PreselectCross != -1) { Base::Console().Log("double click cross:%d\n",edit->PreselectCross); } - else if (edit->PreselectConstraint >= 0) { + else if (edit->PreselectConstraint != -1) { // Find the constraint Base::Console().Log("double click constraint:%d\n",edit->PreselectConstraint); @@ -1170,7 +1167,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI assert(edit); PtIndex = -1; - CurvIndex = -1; + CurvIndex = -1; // valid values are 0,1,2,... for normal geometry and -3,-4,-5,... for external geometry CrossIndex = -1; ConstrIndex = -1; @@ -1195,6 +1192,11 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI if (curve_detail && curve_detail->getTypeId() == SoLineDetail::getClassTypeId()) { // get the index CurvIndex = static_cast(curve_detail)->getLineIndex(); + int maxGeoId = getSketchObject()->getHighestCurveIndex(); + if (CurvIndex > maxGeoId) { // hit on external geometry + int extGeoCount = getSketchObject()->getExternalGeometryCount(); + CurvIndex = -extGeoCount + (CurvIndex - maxGeoId - 1); + } } // checking for a hit in the cross } else if (tail == edit->RootCrossSet) { @@ -1215,7 +1217,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI } } - if (PtIndex >= 0 && PtIndex != edit->PreselectPoint) { // if a new point is hit + if (PtIndex != -1 && PtIndex != edit->PreselectPoint) { // if a new point is hit std::stringstream ss; ss << "Vertex" << PtIndex; bool accepted = @@ -1235,15 +1237,12 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI edit->sketchHandler->applyCursor(); return true; } - } else if (CurvIndex >= 0 && CurvIndex != edit->PreselectCurve) { // if a new curve is hit - int maxGeoId = getSketchObject()->getHighestCurveIndex(); + } else if (CurvIndex != -1 && CurvIndex != edit->PreselectCurve) { // if a new curve is hit std::stringstream ss; - if (CurvIndex <= maxGeoId) + if (CurvIndex >= 0) ss << "Edge" << CurvIndex; - else { // external geometry - int extGeoCount = getSketchObject()->getExternalGeometryCount(); - ss << "ExternalEdge" << extGeoCount - 2 - (CurvIndex - maxGeoId); - } + else // external geometry + ss << "ExternalEdge" << -CurvIndex - 3; // convert index start from -3 to 0 bool accepted = Gui::Selection().setPreselect(getSketchObject()->getDocument()->getName() ,getSketchObject()->getNameInDocument() @@ -1261,7 +1260,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI edit->sketchHandler->applyCursor(); return true; } - } else if (CrossIndex >= 0 && CrossIndex != edit->PreselectCross) { // if a cross line is hit + } else if (CrossIndex != -1 && CrossIndex != edit->PreselectCross) { // if a cross line is hit std::stringstream ss; switch(CrossIndex){ case 0: ss << "RootPoint" ; break; @@ -1285,7 +1284,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI edit->sketchHandler->applyCursor(); return true; } - } else if (ConstrIndex >= 0 && ConstrIndex != edit->PreselectConstraint) { // if a constraint is hit + } else if (ConstrIndex != -1 && ConstrIndex != edit->PreselectConstraint) { // if a constraint is hit std::stringstream ss; ss << "Constraint" << ConstrIndex; bool accepted = @@ -1305,9 +1304,9 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI edit->sketchHandler->applyCursor(); return true; } - } else if ((PtIndex < 0 && CurvIndex < 0 && CrossIndex < 0 && ConstrIndex < 0) && - (edit->PreselectPoint >= 0 || edit->PreselectCurve >= 0 || edit->PreselectCross >= 0 - || edit->PreselectConstraint >= 0 || edit->blockedPreselection)) { + } else if ((PtIndex == -1 && CurvIndex == -1 && CrossIndex == -1 && ConstrIndex == -1) && + (edit->PreselectPoint != -1 || edit->PreselectCurve != -1 || edit->PreselectCross != -1 + || edit->PreselectConstraint != -1 || edit->blockedPreselection)) { // we have just left a preselection resetPreselectPoint(); edit->PreselectCurve = -1; @@ -1321,8 +1320,8 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI Gui::Selection().setPreselectCoord(Point->getPoint()[0] ,Point->getPoint()[1] ,Point->getPoint()[2]); - } else if (edit->PreselectCurve >= 0 || edit->PreselectPoint >= 0 || - edit->PreselectConstraint >= 0 || edit->PreselectCross >= 0 || edit->blockedPreselection) { + } else if (edit->PreselectCurve != -1 || edit->PreselectPoint != -1 || + edit->PreselectConstraint != -1 || edit->PreselectCross != -1 || edit->blockedPreselection) { resetPreselectPoint(); edit->PreselectCurve = -1; edit->PreselectCross = -1; @@ -1366,7 +1365,7 @@ void ViewProviderSketch::updateColor(void) int GeoId = (i < intGeoCount) ? i : -(extGeoCount - (i - intGeoCount)); if (edit->SelCurvSet.find(GeoId) != edit->SelCurvSet.end()) color[i] = SelectColor; - else if (edit->PreselectCurve == i) + else if (edit->PreselectCurve == GeoId) color[i] = PreselectColor; else if (GeoId < -2) // external Geometry color[i] = CurveExternalColor; @@ -2208,7 +2207,8 @@ Restart: case Angle: { assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); - assert(Constr->Second >= -extGeoCount && Constr->Second < intGeoCount); + assert((Constr->Second >= -extGeoCount && Constr->Second < intGeoCount) || + Constr->Second == Constraint::GeoUndef); SbVec3f p0; double startangle,range,endangle; diff --git a/src/Tools/plugins/widget/customwidgets.cpp b/src/Tools/plugins/widget/customwidgets.cpp index 321fec30e..6a2280377 100644 --- a/src/Tools/plugins/widget/customwidgets.cpp +++ b/src/Tools/plugins/widget/customwidgets.cpp @@ -71,6 +71,69 @@ void UrlLabel::setUrl(const QString& u) setToolTip(this->_url); } +LocationWidget::LocationWidget (QWidget * parent) + : QWidget(parent) +{ + box = new QGridLayout(); + + xValue = new QDoubleSpinBox(this); + xValue->setMinimum(-2.14748e+09); + xValue->setMaximum(2.14748e+09); + xLabel = new QLabel(this); + box->addWidget(xLabel, 0, 0, 1, 1); + box->addWidget(xValue, 0, 1, 1, 1); + + yValue = new QDoubleSpinBox(this); + yValue->setMinimum(-2.14748e+09); + yValue->setMaximum(2.14748e+09); + yLabel = new QLabel(this); + box->addWidget(yLabel, 1, 0, 1, 1); + box->addWidget(yValue, 1, 1, 1, 1); + + zValue = new QDoubleSpinBox(this); + zValue->setMinimum(-2.14748e+09); + zValue->setMaximum(2.14748e+09); + zLabel = new QLabel(this); + box->addWidget(zLabel, 2, 0, 1, 1); + box->addWidget(zValue, 2, 1, 1, 1); + + dLabel = new QLabel(this); + dValue = new QComboBox(this); + dValue->setCurrentIndex(-1); + box->addWidget(dLabel, 3, 0, 1, 1); + box->addWidget(dValue, 3, 1, 1, 1); + + QGridLayout* gridLayout = new QGridLayout(this); + gridLayout->addLayout(box, 0, 0, 1, 2); + + retranslateUi(); +} + +LocationWidget::~LocationWidget() +{ +} + +QSize LocationWidget::sizeHint() const +{ + return QSize(150,100); +} + +void LocationWidget::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::LanguageChange) { + this->retranslateUi(); + } + QWidget::changeEvent(e); +} + +void LocationWidget::retranslateUi() +{ + xLabel->setText(QApplication::translate("Gui::LocationWidget", "X:")); + yLabel->setText(QApplication::translate("Gui::LocationWidget", "Y:")); + zLabel->setText(QApplication::translate("Gui::LocationWidget", "Z:")); + dLabel->setText(QApplication::translate("Gui::LocationWidget", "Direction:")); +} + FileChooser::FileChooser( QWidget *parent ) : QWidget( parent ), md( File ), _filter( QString::null ) { diff --git a/src/Tools/plugins/widget/customwidgets.h b/src/Tools/plugins/widget/customwidgets.h index cd22ccadd..2543a119e 100644 --- a/src/Tools/plugins/widget/customwidgets.h +++ b/src/Tools/plugins/widget/customwidgets.h @@ -35,6 +35,8 @@ #include #include #include +#include +#include namespace Gui { @@ -62,6 +64,33 @@ private: QString _url; }; +class LocationWidget : public QWidget +{ + Q_OBJECT + +public: + LocationWidget (QWidget * parent = 0); + virtual ~LocationWidget(); + QSize sizeHint() const; + +public Q_SLOTS: + +private: + void changeEvent(QEvent*); + void retranslateUi(); + +private: + QGridLayout *box; + QLabel *xLabel; + QLabel *yLabel; + QLabel *zLabel; + QLabel *dLabel; + QDoubleSpinBox *xValue; + QDoubleSpinBox *yValue; + QDoubleSpinBox *zValue; + QComboBox *dValue; +}; + /** * There is a bug in QtDesigner of Qt version 4.0, 4.1 and 4.2. If a class declaration * is inside a namespace and it uses the Q_ENUMS macro then QtDesigner doesn't handle diff --git a/src/Tools/plugins/widget/plugin.cpp b/src/Tools/plugins/widget/plugin.cpp index f23c057e6..d0a2aca92 100644 --- a/src/Tools/plugins/widget/plugin.cpp +++ b/src/Tools/plugins/widget/plugin.cpp @@ -108,6 +108,47 @@ public: } }; +class LocationWidgetPlugin : public QDesignerCustomWidgetInterface +{ + Q_INTERFACES(QDesignerCustomWidgetInterface) +public: + LocationWidgetPlugin() + { + } + QWidget *createWidget(QWidget *parent) + { + return new Gui::LocationWidget(parent); + } + QString group() const + { + return QLatin1String("Display Widgets"); + } + QIcon icon() const + { + return QIcon( QPixmap( urllabel_pixmap ) ); + } + QString includeFile() const + { + return QLatin1String("Gui/InputVector.h"); + } + QString toolTip() const + { + return QLatin1String("Location"); + } + QString whatsThis() const + { + return QLatin1String("A widget to define a location."); + } + bool isContainer() const + { + return false; + } + QString name() const + { + return QLatin1String("Gui::LocationWidget"); + } +}; + static const char *filechooser_pixmap[] = { "22 22 8 1", " c Gray100", @@ -1017,6 +1058,7 @@ QList CustomWidgetPlugin::customWidgets () con { QList cw; cw.append(new UrlLabelPlugin); + cw.append(new LocationWidgetPlugin); cw.append(new FileChooserPlugin); cw.append(new AccelLineEditPlugin); cw.append(new CommandIconViewPlugin);