Merge branch 'master' of git://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad

This commit is contained in:
jrheinlaender 2012-12-03 14:02:10 +04:30
commit 7aeed0695a
64 changed files with 3369 additions and 452 deletions

View File

@ -345,6 +345,14 @@ void Document::abortTransaction()
}
}
bool Document::hasPendingTransaction() const
{
if (d->activeUndoTransaction)
return true;
else
return false;
}
void Document::clearUndos()
{
if (d->activeUndoTransaction)
@ -738,11 +746,13 @@ Document::readObjects(Base::XMLReader& reader)
// otherwise we may cause a dependency to itself
// Example: Object 'Cut001' references object 'Cut' and removing the
// digits we make an object 'Cut' referencing itself.
App::DocumentObject* o = addObject(type.c_str(),name.c_str());
objs.push_back(o);
// use this name for the later access because an object with
// the given name may already exist
reader.addName(name.c_str(), o->getNameInDocument());
App::DocumentObject* obj = addObject(type.c_str(),name.c_str());
if (obj) {
objs.push_back(obj);
// use this name for the later access because an object with
// the given name may already exist
reader.addName(name.c_str(), obj->getNameInDocument());
}
}
catch (Base::Exception&) {
Base::Console().Message("Cannot create object '%s'\n", name.c_str());

View File

@ -208,6 +208,8 @@ public:
void commitTransaction();
/// Abort the actually running transaction.
void abortTransaction();
/// Check if a transaction is open
bool hasPendingTransaction() const;
/// Set the Undo limit in Byte!
void setUndoLimit(unsigned int UndoMemSize=0);
/// Returns the actual memory consumption of the Undo redo stuff.

View File

@ -23,6 +23,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
# include <QDir>
# include <QKeySequence>
# include <QMessageBox>
@ -389,6 +390,11 @@ void Command::abortCommand(void)
Gui::Application::Instance->activeDocument()->abortCommand();
}
bool Command::hasPendingCommand(void)
{
return Gui::Application::Instance->activeDocument()->hasPendingCommand();
}
bool Command::_blockCmd = false;
void Command::blockCommand(bool block)
@ -447,6 +453,20 @@ void Command::copyVisual(const char* to, const char* attr_to, const char* from,
doCommand(Gui,"Gui.ActiveDocument.%s.%s=Gui.ActiveDocument.%s.%s", to, attr_to, from, attr_from);
}
std::string Command::getPythonTuple(const std::string& name, const std::vector<std::string>& subnames)
{
std::stringstream str;
std::vector<std::string>::const_iterator last = --subnames.end();
str << "(App.ActiveDocument." << name << ",[";
for (std::vector<std::string>::const_iterator it = subnames.begin();it!=subnames.end();++it){
str << "\"" << *it << "\"";
if (it != last)
str << ",";
}
str << "])";
return str.str();
}
const std::string Command::strToPython(const char* Str)
{
return Base::InterpreterSingleton::strToPython(Str);

View File

@ -209,6 +209,8 @@ public:
static void commitCommand(void);
/// Abort the Undo transaction on the active document
static void abortCommand(void);
/// Check if an Undo transaction is open on the active document
static bool hasPendingCommand(void);
/// Updates the (active) document (propagate changes)
static void updateActive(void);
/// Updates the (all or listed) documents (propagate changes)
@ -237,6 +239,8 @@ public:
static void runCommand(DoCmd_Type eType,const char* sCmd);
static void copyVisual(const char* to, const char* attr, const char* from);
static void copyVisual(const char* to, const char* attr_to, const char* from, const char* attr_from);
/// Get Python tuple from object and sub-elements
static std::string getPythonTuple(const std::string& name, const std::vector<std::string>& subnames);
/// import an external module only once
//static void addModule(const char* sModuleName);
/// translate a string to a python string literal (needed e.g. in file names for windows...)

View File

@ -1067,6 +1067,7 @@ StdCmdRefresh::StdCmdRefresh()
sStatusTip = QT_TR_NOOP("Recomputes the current active document");
sPixmap = "view-refresh";
sAccel = keySequenceToAccel(QKeySequence::Refresh);
eType = AlterDoc | Alter3DView | AlterSelection | ForEdit;
}
void StdCmdRefresh::activated(int iMsg)

View File

@ -64,20 +64,22 @@ public:
/// This method start an Task dialog in the TaskView
void showDialog(Gui::TaskView::TaskDialog *dlg);
Gui::TaskView::TaskDialog* activeDialog() const;
void closeDialog();
//@}
/** @name task view handling
*/
//@{
Gui::TaskView::TaskView* taskPanel() const;
void showTaskView();
//@}
bool isAllowedAlterDocument(void) const;
bool isAllowedAlterView(void) const;
bool isAllowedAlterSelection(void) const;
public Q_SLOTS:
void closeDialog();
void showTaskView();
private Q_SLOTS:
/// This get called by the TaskView when the Dialog is finished
void closedDialog();

View File

@ -1090,7 +1090,12 @@ void Document::commitCommand(void)
void Document::abortCommand(void)
{
getDocument()->abortTransaction();
getDocument()->abortTransaction();
}
bool Document::hasPendingCommand(void) const
{
return getDocument()->hasPendingTransaction();
}
/// Get a string vector with the 'Undo' actions

View File

@ -181,6 +181,8 @@ public:
void commitCommand(void);
/// Abort the Undo transaction on the document
void abortCommand(void);
/// Check if an Undo transaction is open
bool hasPendingCommand(void) const;
/// Get an Undo string vector with the Undo names
std::vector<std::string> getUndoVector(void) const;
/// Get an Redo string vector with the Redo names

View File

@ -724,7 +724,10 @@ void NavigationStyle::zoomByCursor(const SbVec2f & thispos, const SbVec2f & prev
{
// There is no "geometrically correct" value, 20 just seems to give
// about the right "feel".
zoom(viewer->getCamera(), (thispos[1] - prevpos[1]) * 10.0f/*20.0f*/);
float value = (thispos[1] - prevpos[1]) * 10.0f/*20.0f*/;
if (this->invertZoom)
value = -value;
zoom(viewer->getCamera(), value);
}
void NavigationStyle::zoomIn()

View File

@ -255,7 +255,12 @@ void TreeWidget::onStartEditing()
Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
MDIView *view = doc->getActiveView();
if (view) getMainWindow()->setActiveWindow(view);
doc->setEdit(objitem->object(), edit);
// open a transaction before starting edit mode
std::string cmd("Edit ");
cmd += obj->Label.getValue();
doc->openCommand(cmd.c_str());
bool ok = doc->setEdit(objitem->object(), edit);
if (!ok) doc->abortCommand();
}
}
}
@ -268,6 +273,7 @@ void TreeWidget::onFinishEditing()
App::DocumentObject* obj = objitem->object()->getObject();
if (!obj) return;
Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
doc->commitCommand();
doc->resetEdit();
doc->getDocument()->recompute();
}

View File

@ -233,6 +233,53 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Mesh_Segmentation"
<< "Mesh_VertexCurvature";
// Sketch **************************************************************************************************
Gui::MenuItem* sketch = new Gui::MenuItem(menuBar);
sketch->setCommand("S&ketch");
Gui::MenuItem* geom = new Gui::MenuItem();
geom->setCommand("Sketcher geometries");
*geom << "Sketcher_CreatePoint"
<< "Sketcher_CreateArc"
<< "Sketcher_CreateCircle"
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Separator"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
<< "Sketcher_ToggleConstruction";
Gui::MenuItem* cons = new Gui::MenuItem();
cons->setCommand("Sketcher constraints");
*cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric"
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainAngle";
*sketch
<< "Sketcher_NewSketch"
<< "Sketcher_LeaveSketch"
<< "Sketcher_ViewSketch"
<< "Sketcher_MapSketch"
<< geom
<< cons
;
// Part ****************************************************************************************************
Gui::MenuItem* part = new Gui::MenuItem(menuBar);
@ -251,44 +298,16 @@ Gui::MenuItem* Workbench::setupMenuBar() const
Gui::MenuItem* PartDesign = new Gui::MenuItem();
PartDesign->setCommand("Part design");
*PartDesign << "Sketcher_NewSketch"
<< "Sketcher_LeaveSketch"
<< "Sketcher_ViewSketch"
<< "Sketcher_MapSketch"
<< "Separator"
<< "Sketcher_CreatePoint"
<< "Sketcher_CreateArc"
<< "Sketcher_CreateCircle"
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
<< "Sketcher_ToggleConstruction"
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainAngle"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric"
<< "Separator"
<< "PartDesign_Pad"
*PartDesign << "PartDesign_Pad"
<< "PartDesign_Pocket"
<< "PartDesign_Revolution"
<< "PartDesign_Groove"
<< "PartDesign_Fillet"
<< "PartDesign_Chamfer";
<< "PartDesign_Chamfer"
<< "PartDesign_Mirrored"
<< "PartDesign_LinearPattern"
<< "PartDesign_PolarPattern"
<< "PartDesign_MultiTransform";
*part << para
<< PartDesign
@ -478,46 +497,58 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
<< "Part_Chamfer"
;
// Sketch based
Gui::ToolBarItem* sketch_based = new Gui::ToolBarItem( root );
sketch_based->setCommand("Sketch based");
*sketch_based
<< "Sketcher_NewSketch"
<< "Sketcher_LeaveSketch"
<< "Separator"
<< "Sketcher_CreatePoint"
<< "Sketcher_CreateArc"
<< "Sketcher_CreateCircle"
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
<< "Sketcher_ToggleConstruction"
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainAngle"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric"
<< "Separator"
Gui::ToolBarItem* geom = new Gui::ToolBarItem(root);
geom->setCommand("Sketcher geometries");
*geom << "Sketcher_NewSketch"
<< "Sketcher_LeaveSketch"
<< "Separator"
<< "Sketcher_CreatePoint"
<< "Sketcher_CreateArc"
<< "Sketcher_CreateCircle"
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Separator"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
<< "Sketcher_ToggleConstruction"
/*<< "Sketcher_CreateText"*/
/*<< "Sketcher_CreateDraftLine"*/;
Gui::ToolBarItem* cons = new Gui::ToolBarItem(root);
cons->setCommand("Sketcher constraints");
*cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric"
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainAngle";
// Part Design
Gui::ToolBarItem* partdesign = new Gui::ToolBarItem(root);
partdesign->setCommand("Part Design");
*partdesign
<< "PartDesign_Pad"
<< "PartDesign_Pocket"
<< "PartDesign_Revolution"
<< "PartDesign_Groove"
<< "PartDesign_Fillet"
<< "PartDesign_Chamfer";
<< "PartDesign_Chamfer"
<< "PartDesign_Mirrored"
<< "PartDesign_LinearPattern"
<< "PartDesign_PolarPattern"
<< "PartDesign_MultiTransform";
// Drawing
Gui::ToolBarItem* drawing = new Gui::ToolBarItem( root );

View File

@ -199,9 +199,9 @@ App::DocumentObjectExecReturn *FeatureViewPart::execute(void)
<< " transform=\"rotate("<< Rotation.getValue() << ","<< X.getValue()<<","<<Y.getValue()<<") translate("<< X.getValue()<<","<<Y.getValue()<<") scale("<< Scale.getValue()<<","<<Scale.getValue()<<")\"" << endl
<< " >" << endl;
ProjectionAlgos::SvgExtractionType type = ProjectionAlgos::Plain;
if (hidden) type = (ProjectionAlgos::SvgExtractionType)(type|ProjectionAlgos::WithHidden);
if (smooth) type = (ProjectionAlgos::SvgExtractionType)(type|ProjectionAlgos::WithSmooth);
ProjectionAlgos::ExtractionType type = ProjectionAlgos::Plain;
if (hidden) type = (ProjectionAlgos::ExtractionType)(type|ProjectionAlgos::WithHidden);
if (smooth) type = (ProjectionAlgos::ExtractionType)(type|ProjectionAlgos::WithSmooth);
result << Alg.getSVG(type, this->LineWidth.getValue() / this->Scale.getValue(), this->Tolerance.getValue());
result << "</g>" << endl;

View File

@ -149,7 +149,7 @@ void ProjectionAlgos::execute(void)
}
std::string ProjectionAlgos::getSVG(SvgExtractionType type, float scale, float tolerance)
std::string ProjectionAlgos::getSVG(ExtractionType type, float scale, float tolerance)
{
std::stringstream result;
SVGOutput output;
@ -251,7 +251,7 @@ std::string ProjectionAlgos::getSVG(SvgExtractionType type, float scale, float t
/* dxf output section - Dan Falck 2011/09/25 */
std::string ProjectionAlgos::getDXF(SvgExtractionType type, float scale, float tolerance)
std::string ProjectionAlgos::getDXF(ExtractionType type, float scale, float tolerance)
{
std::stringstream result;
DXFOutput output;

View File

@ -45,14 +45,14 @@ public:
void execute(void);
static TopoDS_Shape invertY(const TopoDS_Shape&);
enum SvgExtractionType {
enum ExtractionType {
Plain = 0,
WithHidden = 1,
WithSmooth = 2
};
std::string getSVG(SvgExtractionType type, float scale, float tolerance);
std::string getDXF(SvgExtractionType type, float scale, float tolerance);//added by Dan Falck 2011/09/25
std::string getSVG(ExtractionType type, float scale, float tolerance);
std::string getDXF(ExtractionType type, float scale, float tolerance);//added by Dan Falck 2011/09/25
const TopoDS_Shape &Input;

View File

@ -29,6 +29,9 @@
#include "DrawingView.h"
#include <Mod/Drawing/App/FeaturePage.h>
#include <Mod/Drawing/App/FeatureViewPart.h>
#include <Mod/Drawing/App/ProjectionAlgos.h>
#include <Mod/Part/App/PartFeature.h>
#include <Base/Console.h>
#include <Base/Exception.h>
@ -115,16 +118,6 @@ exporter(PyObject *self, PyObject *args)
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
if (obj->getTypeId().isDerivedFrom(Drawing::FeaturePage::getClassTypeId())) {
std::string fn = static_cast<Drawing::FeaturePage*>(obj)->PageResult.getValue();
Base::FileInfo fi_in(fn);
Base::ifstream str_in(fi_in, std::ios::in | std::ios::binary);
if (!str_in) {
std::stringstream str;
str << "Cannot open file '" << fn << "' for reading";
PyErr_SetString(PyExc_IOError, str.str().c_str());
return NULL;
}
Base::FileInfo fi_out(filename);
Base::ofstream str_out(fi_out, std::ios::out | std::ios::binary);
if (!str_out) {
@ -133,14 +126,64 @@ exporter(PyObject *self, PyObject *args)
PyErr_SetString(PyExc_IOError, str.str().c_str());
return NULL;
}
if (fi_out.hasExtension("svg")) {
std::string fn = static_cast<Drawing::FeaturePage*>(obj)->PageResult.getValue();
Base::FileInfo fi_in(fn);
Base::ifstream str_in(fi_in, std::ios::in | std::ios::binary);
if (!str_in) {
std::stringstream str;
str << "Cannot open file '" << fn << "' for reading";
PyErr_SetString(PyExc_IOError, str.str().c_str());
return NULL;
}
str_in >> str_out.rdbuf();
str_in.close();
str_out.close();
break;
str_in >> str_out.rdbuf();
str_in.close();
str_out.close();
break;
}
else if (fi_out.hasExtension("dxf")) {
const std::vector<App::DocumentObject*>& views = static_cast<Drawing::FeaturePage*>(obj)->Group.getValues();
for (std::vector<App::DocumentObject*>::const_iterator it = views.begin(); it != views.end(); ++it) {
if ((*it)->getTypeId().isDerivedFrom(Drawing::FeatureViewPart::getClassTypeId())) {
Drawing::FeatureViewPart* view = static_cast<Drawing::FeatureViewPart*>(*it);
std::string viewName = view->Label.getValue();
App::DocumentObject* link = view->Source.getValue();
if (!link) {
PyErr_SetString(PyExc_Exception, "No object linked");
return 0;
}
if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
PyErr_SetString(PyExc_TypeError, "Linked object is not a Part object");
return 0;
}
TopoDS_Shape shape = static_cast<Part::Feature*>(link)->Shape.getShape()._Shape;
if (!shape.IsNull()) {
Base::Vector3f dir = view->Direction.getValue();
bool hidden = view->ShowHiddenLines.getValue();
bool smooth = view->ShowSmoothLines.getValue();
Drawing::ProjectionAlgos::ExtractionType type = Drawing::ProjectionAlgos::Plain;
if (hidden) type = (Drawing::ProjectionAlgos::ExtractionType)(type|Drawing::ProjectionAlgos::WithHidden);
if (smooth) type = (Drawing::ProjectionAlgos::ExtractionType)(type|Drawing::ProjectionAlgos::WithSmooth);
float scale = view->Scale.getValue();
float tol = view->Tolerance.getValue();
Drawing::ProjectionAlgos project(shape, dir);
str_out << project.getDXF(type, scale, tol);
break; // TODO: How to add several shapes?
}
}
}
str_out.close();
break;
}
else {
PyErr_SetString(PyExc_TypeError, "Export of page object as this file format is not supported by Drawing module");
return 0;
}
}
else {
PyErr_SetString(PyExc_TypeError, "Export as SVG of this object type is not supported by Drawing module");
PyErr_SetString(PyExc_TypeError, "Export of this object type is not supported by Drawing module");
return 0;
}
}

View File

@ -116,4 +116,4 @@ Gui.addWorkbench(DrawingWorkbench())
# Append the open handler
FreeCAD.addImportType("Drawing (*.svg *.svgz)","DrawingGui")
FreeCAD.addExportType("Drawing (*.svg *.svgz)","DrawingGui")
FreeCAD.addExportType("Drawing (*.svg *.svgz *.dxf)","DrawingGui")

View File

@ -199,6 +199,7 @@ void PartExport initPart()
Part::Loft ::init();
Part::Sweep ::init();
Part::Offset ::init();
Part::Thickness ::init();
// Geometry types
Part::Geometry ::init();

View File

@ -30,6 +30,7 @@
# include <BRepBuilderAPI_MakeWire.hxx>
# include <BRepOffsetAPI_MakePipeShell.hxx>
# include <TopTools_ListIteratorOfListOfShape.hxx>
# include <TopExp_Explorer.hxx>
# include <Precision.hxx>
#endif
@ -375,11 +376,6 @@ short Offset::mustExecute() const
return 0;
}
void Offset::onChanged(const App::Property* prop)
{
Part::Feature::onChanged(prop);
}
App::DocumentObjectExecReturn *Offset::execute(void)
{
App::DocumentObject* source = Source.getValue();
@ -399,3 +395,78 @@ App::DocumentObjectExecReturn *Offset::execute(void)
this->Shape.setValue(shape);
return App::DocumentObject::StdReturn;
}
// ----------------------------------------------------------------------------
const char* Part::Thickness::ModeEnums[]= {"Skin","Pipe", "RectoVerso",NULL};
const char* Part::Thickness::JoinEnums[]= {"Arc","Tangent", "Intersection",NULL};
PROPERTY_SOURCE(Part::Thickness, Part::Feature)
Thickness::Thickness()
{
ADD_PROPERTY_TYPE(Faces,(0),"Thickness",App::Prop_None,"Source shape");
ADD_PROPERTY_TYPE(Value,(1.0),"Thickness",App::Prop_None,"Thickness value");
ADD_PROPERTY_TYPE(Mode,(long(0)),"Thickness",App::Prop_None,"Mode");
Mode.setEnums(ModeEnums);
ADD_PROPERTY_TYPE(Join,(long(0)),"Thickness",App::Prop_None,"Join type");
Join.setEnums(JoinEnums);
ADD_PROPERTY_TYPE(Intersection,(false),"Thickness",App::Prop_None,"Intersection");
ADD_PROPERTY_TYPE(SelfIntersection,(false),"Thickness",App::Prop_None,"Self Intersection");
}
short Thickness::mustExecute() const
{
if (Faces.isTouched())
return 1;
if (Value.isTouched())
return 1;
if (Mode.isTouched())
return 1;
if (Join.isTouched())
return 1;
if (Intersection.isTouched())
return 1;
if (SelfIntersection.isTouched())
return 1;
return 0;
}
App::DocumentObjectExecReturn *Thickness::execute(void)
{
App::DocumentObject* source = Faces.getValue();
if (!(source && source->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
return new App::DocumentObjectExecReturn("No source shape linked.");
const TopoShape& shape = static_cast<Part::Feature*>(source)->Shape.getShape();
if (shape.isNull())
return new App::DocumentObjectExecReturn("Source shape is empty.");
int countSolids = 0;
TopExp_Explorer xp;
xp.Init(shape._Shape,TopAbs_SOLID);
for (;xp.More(); xp.Next()) {
countSolids++;
}
if (countSolids != 1)
return new App::DocumentObjectExecReturn("Source shape is not a solid.");
TopTools_ListOfShape closingFaces;
const std::vector<std::string>& subStrings = Faces.getSubValues();
for (std::vector<std::string>::const_iterator it = subStrings.begin(); it != subStrings.end(); ++it) {
TopoDS_Face face = TopoDS::Face(shape.getSubShape(it->c_str()));
closingFaces.Append(face);
}
double thickness = Value.getValue();
double tol = Precision::Confusion();
bool inter = Intersection.getValue();
bool self = SelfIntersection.getValue();
short mode = (short)Mode.getValue();
short join = (short)Join.getValue();
if (fabs(thickness) > 2*tol)
this->Shape.setValue(shape.makeThickSolid(closingFaces, thickness, tol, inter, self, mode, join));
else
this->Shape.setValue(shape);
return App::DocumentObject::StdReturn;
}

View File

@ -132,8 +132,34 @@ public:
}
//@}
protected:
void onChanged (const App::Property* prop);
private:
static const char* ModeEnums[];
static const char* JoinEnums[];
};
class Thickness : public Part::Feature
{
PROPERTY_HEADER(Part::Thickness);
public:
Thickness();
App::PropertyLinkSub Faces;
App::PropertyFloat Value;
App::PropertyEnumeration Mode;
App::PropertyEnumeration Join;
App::PropertyBool Intersection;
App::PropertyBool SelfIntersection;
/** @name methods override feature */
//@{
/// recalculate the feature
App::DocumentObjectExecReturn *execute(void);
short mustExecute() const;
const char* getViewProviderName(void) const {
return "PartGui::ViewProviderThickness";
}
//@}
private:
static const char* ModeEnums[];

View File

@ -84,10 +84,17 @@
</Attribute>
<Attribute Name="Wire" ReadOnly="true">
<Documentation>
<UserDocu>The Wire of this face</UserDocu>
<UserDocu>The outer wire of this face
deprecated -- please use OuterWire</UserDocu>
</Documentation>
<Parameter Name="Wire" Type="Object"/>
</Attribute>
<Attribute Name="OuterWire" ReadOnly="true">
<Documentation>
<UserDocu>The outer wire of this face</UserDocu>
</Documentation>
<Parameter Name="OuterWire" Type="Object"/>
</Attribute>
<Attribute Name="CenterOfMass" ReadOnly="true">
<Documentation>
<UserDocu>

View File

@ -548,7 +548,22 @@ Py::Tuple TopoShapeFacePy::getParameterRange(void) const
return t;
}
// deprecated
Py::Object TopoShapeFacePy::getWire(void) const
{
try {
Py::Object sys_out(PySys_GetObject(const_cast<char*>("stdout")));
Py::Callable write(sys_out.getAttr("write"));
Py::Tuple arg(1);
arg.setItem(0, Py::String("Warning: Wire is deprecated, please use OuterWire\n"));
write.apply(arg);
}
catch (const Py::Exception&) {
}
return getOuterWire();
}
Py::Object TopoShapeFacePy::getOuterWire(void) const
{
const TopoDS_Shape& clSh = getTopoShapePtr()->_Shape;
if (clSh.IsNull())

View File

@ -106,6 +106,7 @@ void PartGuiExport initPartGui()
PartGui::ViewProviderLoft ::init();
PartGui::ViewProviderSweep ::init();
PartGui::ViewProviderOffset ::init();
PartGui::ViewProviderThickness ::init();
PartGui::ViewProviderCustom ::init();
PartGui::ViewProviderCustomPython ::init();
PartGui::ViewProviderBoolean ::init();

View File

@ -43,6 +43,7 @@ set(PartGui_MOC_HDRS
TaskLoft.h
TaskOffset.h
TaskSweep.h
TaskThickness.h
TaskCheckGeometry.h
)
fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS})
@ -166,6 +167,8 @@ SET(PartGui_SRCS
TaskSweep.cpp
TaskSweep.h
TaskSweep.ui
TaskThickness.cpp
TaskThickness.h
TaskCheckGeometry.cpp
TaskCheckGeometry.h
)

View File

@ -31,6 +31,7 @@
# include <QPointer>
# include <Standard_math.hxx>
# include <TopoDS_Shape.hxx>
# include <TopExp_Explorer.hxx>
# include <Inventor/events/SoMouseButtonEvent.h>
#endif
@ -1035,6 +1036,78 @@ bool CmdPartOffset::isActive(void)
//--------------------------------------------------------------------------------------
DEF_STD_CMD_A(CmdPartThickness);
CmdPartThickness::CmdPartThickness()
: Command("Part_Thickness")
{
sAppModule = "Part";
sGroup = QT_TR_NOOP("Part");
sMenuText = QT_TR_NOOP("Thickness...");
sToolTipText = QT_TR_NOOP("Utility to apply a thickness");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "Part_Thickness";
}
void CmdPartThickness::activated(int iMsg)
{
Gui::SelectionFilter faceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1..");
if (!faceFilter.match()) {
QMessageBox::warning(Gui::getMainWindow(),
QApplication::translate("CmdPartThickness", "Wrong selection"),
QApplication::translate("CmdPartThickness", "Selected one or more faces of a shape"));
return;
}
// get the selected object
const std::vector<Gui::SelectionObject>& result = faceFilter.Result[0];
std::string selection = result.front().getAsPropertyLinkSubString();
const Part::Feature* shape = static_cast<const Part::Feature*>(result.front().getObject());
if (shape->Shape.getValue().IsNull())
return;
int countSolids = 0;
TopExp_Explorer xp;
xp.Init(shape->Shape.getValue(),TopAbs_SOLID);
for (;xp.More(); xp.Next()) {
countSolids++;
}
if (countSolids != 1) {
QMessageBox::warning(Gui::getMainWindow(),
QApplication::translate("CmdPartThickness", "Wrong selection"),
QApplication::translate("CmdPartThickness", "Selected shape is not a solid"));
return;
}
std::string thick = getUniqueObjectName("Thickness");
openCommand("Make Thickness");
doCommand(Doc,"App.ActiveDocument.addObject(\"Part::Thickness\",\"%s\")",thick.c_str());
doCommand(Doc,"App.ActiveDocument.%s.Faces = %s" ,thick.c_str(), selection.c_str());
doCommand(Doc,"App.ActiveDocument.%s.Value = 1.0",thick.c_str());
updateActive();
if (isActiveObjectValid())
doCommand(Gui,"Gui.ActiveDocument.hide(\"%s\")",shape->getNameInDocument());
doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",thick.c_str());
//commitCommand();
adjustCameraPosition();
copyVisual(thick.c_str(), "ShapeColor", shape->getNameInDocument());
copyVisual(thick.c_str(), "LineColor" , shape->getNameInDocument());
copyVisual(thick.c_str(), "PointColor", shape->getNameInDocument());
}
bool CmdPartThickness::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
bool objectsSelected = Gui::Selection().countObjectsOfType(partid) > 0;
return (objectsSelected && !Gui::Control().activeDialog());
}
//--------------------------------------------------------------------------------------
DEF_STD_CMD_A(CmdShapeInfo);
CmdShapeInfo::CmdShapeInfo()
@ -1306,5 +1379,6 @@ void CreatePartCommands(void)
rcCmdMgr.addCommand(new CmdPartLoft());
rcCmdMgr.addCommand(new CmdPartSweep());
rcCmdMgr.addCommand(new CmdPartOffset());
rcCmdMgr.addCommand(new CmdPartThickness());
rcCmdMgr.addCommand(new CmdCheckGeometry());
}

View File

@ -27,6 +27,7 @@
<file>icons/Part_ShapeInfo.svg</file>
<file>icons/Part_Sphere.svg</file>
<file>icons/Part_Sweep.svg</file>
<file>icons/Part_Thickness.svg</file>
<file>icons/Part_Torus.svg</file>
<file>icons/preferences-part_design.svg</file>
<file>icons/Tree_Part.svg</file>

View File

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2682"
sodipodi:version="0.32"
inkscape:version="0.48.0 r9654"
sodipodi:docname="Part_Extrude.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2684">
<linearGradient
id="linearGradient3593">
<stop
style="stop-color:#c8e0f9;stop-opacity:1;"
offset="0"
id="stop3595" />
<stop
style="stop-color:#637dca;stop-opacity:1;"
offset="1"
id="stop3597" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3593"
id="radialGradient3354"
gradientUnits="userSpaceOnUse"
cx="330.63791"
cy="39.962704"
fx="330.63791"
fy="39.962704"
r="19.571428"
gradientTransform="matrix(0.9327663,0,0,0.9327663,-298.15651,8.1913381)" />
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2690" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3864"
id="radialGradient2401"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.959337,5.1799939e-2,0,0.7352325,-29.610908,-1.2314128)"
cx="51.105499"
cy="23.807407"
fx="51.105499"
fy="23.807407"
r="19.571428" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3864"
id="radialGradient2404"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2993671,-1.5757258e-2,8.4161044e-3,0.9850979,-94.354208,-10.998387)"
cx="48.288067"
cy="46.74614"
fx="48.288067"
fy="46.74614"
r="19.571428" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3593"
id="radialGradient3377"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9327663,0,0,0.9327663,-267.16323,12.515981)"
cx="317.68173"
cy="35.227276"
fx="317.68173"
fy="35.227276"
r="19.571428" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.75"
inkscape:cx="61.342448"
inkscape:cy="37.42735"
inkscape:current-layer="g3381"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1280"
inkscape:window-height="758"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="0" />
<metadata
id="metadata2687">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3381">
<path
sodipodi:nodetypes="cccccc"
id="path3379"
d="M 36.363637,60.272727 L 59.454546,53.545455 L 62.363637,51.363636 L 62.363637,43.181818 L 54.909091,42.090909 L 36.363637,60.272727 z"
style="opacity:0.63944205;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="opacity:1;fill:url(#radialGradient3354);fill-opacity:1;fill-rule:evenodd;stroke:#4b4dba;stroke-width:2.2;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 4.9501369,37.23429 L 36.070613,40.053788 L 35.816223,59.36629 L 5.1197308,56.292401 L 4.9501369,37.23429 z"
id="rect2568"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:1;fill:url(#radialGradient3377);fill-opacity:1;fill-rule:evenodd;stroke:#4b4dba;stroke-width:2.20000000000000018;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 35.773823,40.117385 L 55.107525,31.319703 L 54.768337,49.869032 L 35.604229,59.429887 L 35.773823,40.117385 z"
id="path3375"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
id="rect3633"
d="M 23.530174,28.496274 L 55.6968,30.8755 L 36.406189,40.084227 L 4.2395647,37.705001 L 23.530174,28.496274 z"
style="fill:url(#radialGradient2404);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:2.2;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -72,9 +72,10 @@ OffsetWidget::OffsetWidget(Part::Offset* offset, QWidget* parent)
d->offset = offset;
d->ui.setupUi(this);
d->ui.spinOffset->setValue(d->offset->Value.getValue());
d->ui.spinOffset->setRange(-INT_MAX, INT_MAX);
d->ui.spinOffset->setSingleStep(0.1);
d->ui.spinOffset->setValue(d->offset->Value.getValue());
d->ui.facesButton->hide();
}
OffsetWidget::~OffsetWidget()
@ -177,6 +178,7 @@ bool OffsetWidget::reject()
// roll back the done things
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()");
Gui::Command::updateActive();
return true;
}

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>260</height>
<width>264</width>
<height>244</height>
</rect>
</property>
<property name="windowTitle">
@ -21,7 +21,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="0" column="2">
<widget class="QDoubleSpinBox" name="spinOffset"/>
</item>
<item row="1" column="0">
@ -31,7 +31,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="1" column="2">
<widget class="QComboBox" name="modeType">
<item>
<property name="text">
@ -57,7 +57,7 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="2" column="2">
<widget class="QComboBox" name="joinType">
<item>
<property name="text">
@ -83,30 +83,13 @@
</property>
</widget>
</item>
<item row="4" column="0">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="selfIntersection">
<property name="text">
<string>Self-intersection</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="updateView">
<property name="text">
<string>Update view</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="fillOffset">
<property name="text">
@ -114,6 +97,50 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QLabel" name="labelFaces">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QPushButton" name="facesButton">
<property name="text">
<string>Faces</string>
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>152</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="updateView">
<property name="text">
<string>Update view</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>

View File

@ -0,0 +1,311 @@
/***************************************************************************
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QEventLoop>
# include <QMessageBox>
# include <QTextStream>
#endif
#include "ui_TaskOffset.h"
#include "TaskThickness.h"
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/Selection.h>
#include <Gui/SelectionFilter.h>
#include <Gui/ViewProvider.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <Mod/Part/App/PartFeatures.h>
using namespace PartGui;
class ThicknessWidget::Private
{
public:
Ui_TaskOffset ui;
QEventLoop loop;
QString text;
std::string selection;
Part::Thickness* thickness;
Private()
{
}
~Private()
{
}
class FaceSelection : public Gui::SelectionFilterGate
{
const App::DocumentObject* object;
public:
FaceSelection(const App::DocumentObject* obj)
: Gui::SelectionFilterGate((Gui::SelectionFilter*)0), object(obj)
{
}
bool allow(App::Document*pDoc, App::DocumentObject*pObj, const char*sSubName)
{
if (pObj != this->object)
return false;
if (!sSubName || sSubName[0] == '\0')
return false;
std::string element(sSubName);
return element.substr(0,4) == "Face";
}
};
};
/* TRANSLATOR PartGui::ThicknessWidget */
ThicknessWidget::ThicknessWidget(Part::Thickness* thickness, QWidget* parent)
: d(new Private())
{
Gui::Application::Instance->runPythonCode("from FreeCAD import Base");
Gui::Application::Instance->runPythonCode("import Part");
d->thickness = thickness;
d->ui.setupUi(this);
d->ui.spinOffset->setRange(-INT_MAX, INT_MAX);
d->ui.spinOffset->setSingleStep(0.1);
d->ui.spinOffset->setValue(d->thickness->Value.getValue());
d->ui.labelOffset->setText(tr("Thickness"));
d->ui.fillOffset->hide();
}
ThicknessWidget::~ThicknessWidget()
{
delete d;
}
Part::Thickness* ThicknessWidget::getObject() const
{
return d->thickness;
}
void ThicknessWidget::on_spinOffset_valueChanged(double val)
{
d->thickness->Value.setValue((float)val);
if (d->ui.updateView->isChecked())
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
void ThicknessWidget::on_modeType_activated(int val)
{
d->thickness->Mode.setValue(val);
if (d->ui.updateView->isChecked())
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
void ThicknessWidget::on_joinType_activated(int val)
{
d->thickness->Join.setValue((float)val);
if (d->ui.updateView->isChecked())
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
void ThicknessWidget::on_intersection_toggled(bool on)
{
d->thickness->Intersection.setValue(on);
if (d->ui.updateView->isChecked())
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
void ThicknessWidget::on_selfIntersection_toggled(bool on)
{
d->thickness->SelfIntersection.setValue(on);
if (d->ui.updateView->isChecked())
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
void ThicknessWidget::on_facesButton_clicked()
{
if (!d->loop.isRunning()) {
QList<QWidget*> c = this->findChildren<QWidget*>();
for (QList<QWidget*>::iterator it = c.begin(); it != c.end(); ++it)
(*it)->setEnabled(false);
d->ui.facesButton->setEnabled(true);
d->ui.labelFaces->setText(tr("Select faces of the source object and press 'Done'"));
d->ui.labelFaces->setEnabled(true);
d->text = d->ui.facesButton->text();
d->ui.facesButton->setText(tr("Done"));
Gui::Application::Instance->showViewProvider(d->thickness->Faces.getValue());
Gui::Application::Instance->hideViewProvider(d->thickness);
Gui::Selection().clearSelection();
Gui::Selection().addSelectionGate(new Private::FaceSelection(d->thickness->Faces.getValue()));
d->loop.exec();
}
else {
QList<QWidget*> c = this->findChildren<QWidget*>();
for (QList<QWidget*>::iterator it = c.begin(); it != c.end(); ++it)
(*it)->setEnabled(true);
d->ui.facesButton->setText(d->text);
d->ui.labelFaces->clear();
d->loop.quit();
d->selection = Gui::Command::getPythonTuple
(d->thickness->Faces.getValue()->getNameInDocument(), d->thickness->Faces.getSubValues());
std::vector<Gui::SelectionObject> sel = Gui::Selection().getSelectionEx();
for (std::vector<Gui::SelectionObject>::iterator it = sel.begin(); it != sel.end(); ++it) {
if (it->getObject() == d->thickness->Faces.getValue()) {
d->thickness->Faces.setValue(it->getObject(), it->getSubNames());
d->selection = it->getAsPropertyLinkSubString();
break;
}
}
Gui::Selection().rmvSelectionGate();
Gui::Application::Instance->showViewProvider(d->thickness);
Gui::Application::Instance->hideViewProvider(d->thickness->Faces.getValue());
if (d->ui.updateView->isChecked())
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
}
void ThicknessWidget::on_updateView_toggled(bool on)
{
if (on) {
d->thickness->getDocument()->recomputeFeature(d->thickness);
}
}
bool ThicknessWidget::accept()
{
if (d->loop.isRunning())
return false;
std::string name = d->thickness->getNameInDocument();
try {
if (!d->selection.empty()) {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Faces = %s",
name.c_str(),d->selection.c_str());
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Value = %f",
name.c_str(),d->ui.spinOffset->value());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Mode = %i",
name.c_str(),d->ui.modeType->currentIndex());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Join = %i",
name.c_str(),d->ui.joinType->currentIndex());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Intersection = %s",
name.c_str(),d->ui.intersection->isChecked() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.SelfIntersection = %s",
name.c_str(),d->ui.selfIntersection->isChecked() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!d->thickness->isValid())
throw Base::Exception(d->thickness->getStatusString());
Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()");
Gui::Command::commitCommand();
}
catch (const Base::Exception& e) {
QMessageBox::warning(this, tr("Input error"), QString::fromAscii(e.what()));
return false;
}
return true;
}
bool ThicknessWidget::reject()
{
if (d->loop.isRunning())
return false;
// save this and check if the object is still there after the
// transaction is aborted
std::string objname = d->thickness->getNameInDocument();
App::DocumentObject* source = d->thickness->Faces.getValue();
// roll back the done things
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()");
Gui::Command::updateActive();
// Thickness object was deleted
if (source && !source->getDocument()->getObject(objname.c_str())) {
Gui::Application::Instance->getViewProvider(source)->show();
}
return true;
}
void ThicknessWidget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
d->ui.retranslateUi(this);
d->ui.labelOffset->setText(tr("Thickness"));
}
}
/* TRANSLATOR PartGui::TaskThickness */
TaskThickness::TaskThickness(Part::Thickness* offset)
{
widget = new ThicknessWidget(offset);
widget->setWindowTitle(ThicknessWidget::tr("Thickness"));
taskbox = new Gui::TaskView::TaskBox(
Gui::BitmapFactory().pixmap("Part_Thickness"),
widget->windowTitle(), true, 0);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
}
TaskThickness::~TaskThickness()
{
}
Part::Thickness* TaskThickness::getObject() const
{
return widget->getObject();
}
void TaskThickness::open()
{
}
void TaskThickness::clicked(int)
{
}
bool TaskThickness::accept()
{
return widget->accept();
}
bool TaskThickness::reject()
{
return widget->reject();
}
#include "moc_TaskThickness.cpp"

View File

@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef PARTGUI_TASKTHICKNESS_H
#define PARTGUI_TASKTHICKNESS_H
#include <Gui/TaskView/TaskView.h>
#include <Gui/TaskView/TaskDialog.h>
namespace Part { class Thickness; }
namespace PartGui {
class ThicknessWidget : public QWidget
{
Q_OBJECT
public:
ThicknessWidget(Part::Thickness*, QWidget* parent = 0);
~ThicknessWidget();
bool accept();
bool reject();
Part::Thickness* getObject() const;
private Q_SLOTS:
void on_spinOffset_valueChanged(double);
void on_modeType_activated(int);
void on_joinType_activated(int);
void on_intersection_toggled(bool);
void on_selfIntersection_toggled(bool);
void on_facesButton_clicked();
void on_updateView_toggled(bool);
private:
void changeEvent(QEvent *e);
private:
class Private;
Private* d;
};
class TaskThickness : public Gui::TaskView::TaskDialog
{
Q_OBJECT
public:
TaskThickness(Part::Thickness*);
~TaskThickness();
public:
void open();
bool accept();
bool reject();
void clicked(int);
Part::Thickness* getObject() const;
QDialogButtonBox::StandardButtons getStandardButtons() const
{ return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
private:
ThicknessWidget* widget;
Gui::TaskView::TaskBox* taskbox;
};
} //namespace PartGui
#endif // PARTGUI_TASKTHICKNESS_H

View File

@ -81,6 +81,7 @@
#include <Base/Exception.h>
#include <App/Application.h>
#include <App/Document.h>
#include <Gui/Command.h>
#include <Gui/SoFCSelection.h>
#include <Gui/Selection.h>
#include <Gui/View3DInventorViewer.h>
@ -107,6 +108,17 @@ ViewProviderPart::ViewProviderPart()
ViewProviderPart::~ViewProviderPart()
{
}
bool ViewProviderPart::doubleClicked(void)
{
std::string Msg("Edit ");
Msg += this->pcObject->Label.getValue();
Gui::Command::openCommand(Msg.c_str());
Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.setEdit('%s',0)",
this->pcObject->getNameInDocument());
return true;
}
#else
PROPERTY_SOURCE(PartGui::ViewProviderPart, PartGui::ViewProviderPartBase)

View File

@ -156,6 +156,7 @@ public:
ViewProviderPart();
/// destructor
virtual ~ViewProviderPart();
virtual bool doubleClicked(void);
};
#else
class PartGuiExport ViewProviderPart : public ViewProviderPartBase

View File

@ -26,6 +26,7 @@
#ifndef _PreComp_
# include <QAction>
# include <QMenu>
# include <QTimer>
# include <Standard_math.hxx>
# include <Inventor/actions/SoSearchAction.h>
# include <Inventor/draggers/SoDragger.h>
@ -47,6 +48,7 @@
#include "ViewProviderMirror.h"
#include "DlgFilletEdges.h"
#include "TaskOffset.h"
#include "TaskThickness.h"
using namespace PartGui;
@ -477,3 +479,84 @@ bool ViewProviderOffset::onDelete(const std::vector<std::string> &)
return true;
}
// ---------------------------------------
PROPERTY_SOURCE(PartGui::ViewProviderThickness, PartGui::ViewProviderPart)
ViewProviderThickness::ViewProviderThickness()
{
sPixmap = "Part_Thickness";
}
ViewProviderThickness::~ViewProviderThickness()
{
}
void ViewProviderThickness::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
QAction* act;
act = menu->addAction(QObject::tr("Edit thickness"), receiver, member);
act->setData(QVariant((int)ViewProvider::Default));
PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member);
}
bool ViewProviderThickness::setEdit(int ModNum)
{
if (ModNum == ViewProvider::Default ) {
Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
TaskThickness* thicknessDlg = qobject_cast<TaskThickness*>(dlg);
if (thicknessDlg && thicknessDlg->getObject() != this->getObject())
thicknessDlg = 0; // another pad left open its task panel
if (dlg && !thicknessDlg) {
if (dlg->canClose())
Gui::Control().closeDialog();
else
return false;
}
// clear the selection (convenience)
Gui::Selection().clearSelection();
// start the edit dialog
if (thicknessDlg)
Gui::Control().showDialog(thicknessDlg);
else
Gui::Control().showDialog(new TaskThickness(static_cast<Part::Thickness*>(getObject())));
return true;
}
else {
return ViewProviderPart::setEdit(ModNum);
}
}
void ViewProviderThickness::unsetEdit(int ModNum)
{
if (ModNum == ViewProvider::Default) {
// when pressing ESC make sure to close the dialog
QTimer::singleShot(0, &Gui::Control(), SLOT(closeDialog()));
}
else {
PartGui::ViewProviderPart::unsetEdit(ModNum);
}
}
std::vector<App::DocumentObject*> ViewProviderThickness::claimChildren() const
{
std::vector<App::DocumentObject*> child;
child.push_back(static_cast<Part::Thickness*>(getObject())->Faces.getValue());
return child;
}
bool ViewProviderThickness::onDelete(const std::vector<std::string> &)
{
// get the support and Sketch
Part::Thickness* thickness = static_cast<Part::Thickness*>(getObject());
App::DocumentObject* source = thickness->Faces.getValue();
if (source){
Gui::Application::Instance->getViewProvider(source)->show();
}
return true;
}

View File

@ -158,6 +158,26 @@ protected:
virtual void unsetEdit(int ModNum);
};
class ViewProviderThickness : public ViewProviderPart
{
PROPERTY_HEADER(PartGui::ViewProviderThickness);
public:
/// constructor
ViewProviderThickness();
/// destructor
virtual ~ViewProviderThickness();
/// grouping handling
std::vector<App::DocumentObject*> claimChildren(void)const;
void setupContextMenu(QMenu*, QObject*, const char*);
bool onDelete(const std::vector<std::string> &);
protected:
virtual bool setEdit(int ModNum);
virtual void unsetEdit(int ModNum);
};
} // namespace PartGui

View File

@ -72,7 +72,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" << "Separator"
<< "Part_Boolean" << "Part_CrossSections" << "Part_Extrude"
<< "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer"
<< "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" << "Part_Offset";
<< "Part_RuledSurface" << "Part_Loft" << "Part_Sweep"
<< "Part_Offset" << "Part_Thickness";
return root;
}
@ -90,7 +91,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
tool->setCommand("Part tools");
*tool << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet"
<< "Part_Chamfer" << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep"
<< "Part_Offset";
<< "Part_Offset" << "Part_Thickness";
Gui::ToolBarItem* boolop = new Gui::ToolBarItem(root);
boolop->setCommand("Boolean");

View File

@ -231,6 +231,8 @@ bool SketchBased::isInside(const TopoDS_Wire& wire1, const TopoDS_Wire& wire2) c
double prec = Precision::Confusion();
BRepBuilderAPI_MakeFace mkFace(wire1);
if (!mkFace.IsDone())
Standard_Failure::Raise("Failed to create a face from wire in sketch");
TopoDS_Face face = validateFace(mkFace.Face());
BRepAdaptor_Surface adapt(face);
IntTools_FClass2d class2d(face, prec);

View File

@ -29,3 +29,29 @@ INSTALL(
Mod/PartDesign/Scripts
)
SET(WizardShaft_SRCS
WizardShaft/__init__.py
WizardShaft/WizardShaft.svg
WizardShaft/WizardShaft.py
WizardShaft/WizardShaftTable.py
WizardShaft/Shaft.py
WizardShaft/ShaftFeature.py
WizardShaft/ShaftDiagram.py
WizardShaft/SegmentFunction.py
)
SOURCE_GROUP("wizardshaft" FILES ${WizardShaft_SRCS})
SET(all_files ${WizardShaft_SRCS})
ADD_CUSTOM_TARGET(WizardShaft ALL
SOURCES ${all_files}
)
fc_copy_sources(Mod/PartDesign "${CMAKE_BINARY_DIR}/Mod/PartDesign" ${all_files})
INSTALL(
FILES
${WizardShaft_SRCS}
DESTINATION
Mod/PartDesign/WizardShaft
)

View File

@ -45,8 +45,8 @@ ViewProvider::~ViewProvider()
bool ViewProvider::doubleClicked(void)
{
std::string Msg("Change ");
Msg += this->pcObject->getNameInDocument();
std::string Msg("Edit ");
Msg += this->pcObject->Label.getValue();
Gui::Command::openCommand(Msg.c_str());
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument());
return true;

View File

@ -28,6 +28,8 @@
#endif
#include "Workbench.h"
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/MenuManager.h>
#include <Gui/ToolBarManager.h>
#include <Gui/Control.h>
@ -167,6 +169,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Separator"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
@ -176,22 +179,22 @@ Gui::MenuItem* Workbench::setupMenuBar() const
Gui::MenuItem* cons = new Gui::MenuItem();
cons->setCommand("Sketcher constraints");
*cons << "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainCoincident"
*cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainAngle"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric"
;
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainAngle";
Gui::MenuItem* part = new Gui::MenuItem;
root->insertItem(item, part);
@ -214,6 +217,12 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "PartDesign_PolarPattern"
// << "PartDesign_Scaled"
<< "PartDesign_MultiTransform";
// For 0.13 a couple of python packages like numpy, matplotlib and others
// are not deployed with the installer on Windows. Thus, the WizardShaft is
// not deployed either hence the check for the existence of the command.
if (Gui::Application::Instance->commandManager().getCommandByName("PartDesign_WizardShaft")) {
*part << "Separator" << "PartDesign_WizardShaft";
}
return root;
}
@ -238,14 +247,15 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
// << "PartDesign_Scaled"
<< "PartDesign_MultiTransform";
part = new Gui::ToolBarItem(root);
part->setCommand("Sketcher geometries");
*part << "Sketcher_CreatePoint"
Gui::ToolBarItem* geom = new Gui::ToolBarItem(root);
geom->setCommand("Sketcher geometries");
*geom << "Sketcher_CreatePoint"
<< "Sketcher_CreateArc"
<< "Sketcher_CreateCircle"
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Separator"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
@ -253,24 +263,24 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
/*<< "Sketcher_CreateText"*/
/*<< "Sketcher_CreateDraftLine"*/;
part = new Gui::ToolBarItem(root);
part->setCommand("Sketcher constraints");
*part << "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainCoincident"
Gui::ToolBarItem* cons = new Gui::ToolBarItem(root);
cons->setCommand("Sketcher constraints");
*cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainAngle"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric"
;
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainAngle";
return root;
}

View File

@ -1,4 +1,4 @@
# PartDesign gui init module
# PartDesign gui init module
# (c) 2003 Juergen Riegel
#
# Gathering all the information to start FreeCAD
@ -29,11 +29,9 @@
#* Juergen Riegel 2002 *
#***************************************************************************/
class PartDesignWorkbench ( Workbench ):
"PartDesign workbench object"
Icon = """
"PartDesign workbench object"
Icon = """
/* XPM */
static char * partdesign_xpm[] = {
"16 16 9 1",
@ -62,15 +60,19 @@ class PartDesignWorkbench ( Workbench ):
".+@@@####@.@.. ",
" ......+++.. ",
" ... "};
"""
"""
MenuText = "Part Design"
ToolTip = "Part Design workbench"
def Initialize(self):
# load the module
import PartDesignGui
import PartDesign
def GetClassName(self):
return "PartDesignGui::Workbench"
def Initialize(self):
# load the module
try:
from WizardShaft import WizardShaft
except:
print "Wizard shaft not installed"
import PartDesignGui
import PartDesign
def GetClassName(self):
return "PartDesignGui::Workbench"
Gui.addWorkbench(PartDesignWorkbench())

View File

@ -0,0 +1,76 @@
# PartDesign gui init module
# (c) 2003 Juergen Riegel
#
# Gathering all the information to start FreeCAD
# This is the second one of three init scripts, the third one
# runs when the gui is up
#***************************************************************************
#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 *
#* *
#* This file is part of the FreeCAD CAx development system. *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU General Public License (GPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* FreeCAD 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 FreeCAD; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#* Juergen Riegel 2002 *
#***************************************************************************/
class PartDesignWorkbench ( Workbench ):
"PartDesign workbench object"
from WizardShaft import WizardShaft
Icon = """
/* XPM */
static char * partdesign_xpm[] = {
"16 16 9 1",
" c None",
". c #040006",
"+ c #070F38",
"@ c #002196",
"# c #0030F3",
"$ c #5A4D20",
"% c #858EB2",
"& c #DEB715",
"* c #BFB99D",
" & ........ ",
"&&&$..@@@@@@+...",
"&&&&$@#####@..@.",
"&&&&&$......@#@.",
"&&&&&&@@@+.###@.",
"$&&&&&&@#@.###@.",
".$&&&&&%#@.###@.",
".@*&&&*%#@.###@.",
".@#*&**%#@.###@.",
".@#@%%%.@@.###@.",
".@@@@@@@#@.###@.",
".@#######@.###@.",
".@#######@.##+. ",
".+@@@####@.@.. ",
" ......+++.. ",
" ... "};
"""
MenuText = "Part Design"
ToolTip = "Part Design workbench"
def Initialize(self):
# load the module
import PartDesignGui
import PartDesign
def GetClassName(self):
return "PartDesignGui::Workbench"
Gui.addWorkbench(PartDesignWorkbench())

View File

@ -0,0 +1,158 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
import FreeCAD # just for debug printing to console...
class SegmentFunctionSegment:
"One segment of a segment function"
start = 0
variable = "x"
coefficient = 0
exponent = 0
def __init__(self, st, var, coeff, exp):
self.start = st
self.variable = var
self.coefficient = coeff
self.exponent = exp
def hasStart(self, xval):
"Return true if the start of this segment is xval"
#FIXME: 1E-9 is arbitrary here. But since units are in meters, 1E-9 is a nanometer...
return abs(self.start - xval) < 1E-9
def value(self, xval):
if xval < self.start:
return 0
else:
return self.coefficient * pow(xval - self.start, self.exponent)
def clone(self):
return SegmentFunctionSegment(self.start, self.variable, self.coefficient, self.exponent)
def negate(self):
self.coefficient *= -1
def integrate(self):
self.exponent = self.exponent + 1
self.coefficient = self.coefficient * 1 / self.exponent
def asString(self):
return "%f * {%s - %f}^%i" % (self.coefficient, self.variable, self.start, self.exponent)
class SegmentFunction:
"Function that is defined segment-wise"
variable = "x"
segments = []
name = "f(x)"
def __init__(self, name = "f(x)"):
self.variable = "x"
self.segments = []
self.name = name
def negate(self):
for s in self.segments:
s.negate()
return self
def index(self, xval):
"Find insert position for start value xval"
lastStart = 0.0
for i in range(len(self.segments)):
newStart = self.segments[i].start
if (xval >= lastStart) and (xval < newStart):
return i
lastStart = newStart
return len(self.segments)
def buildFromDict(self, var, dict):
self.variable = var
for key in sorted(dict.iterkeys()):
#if abs(dict[key]) > 1E-9:
self.segments.append(SegmentFunctionSegment(key, var, dict[key], 0))
def addSegments(self, dict):
for key in sorted(dict.iterkeys()):
if abs(dict[key]) > 1E-9:
self.segments.insert(self.index(key), SegmentFunctionSegment(key, self.variable, dict[key], 0))
def setMaxX(self, mx):
self.maxX = mx
def value(self, xval):
"Return the value of the function at the specified x value"
result = 0
for s in self.segments:
result = result + s.value(xval)
return result
def lowervalue(self, xval):
"Return the value of the previous segment at the specified x value"
result = 0
for s in self.segments:
result = result + s.value(xval - 1E-8)
return result
def clone(self):
result = SegmentFunction()
result.variable = self.variable
for s in self.segments:
result.segments.append(s.clone())
return result
def integrate(self):
"Integrate all segments with respect to the variable"
for s in self.segments:
s.integrate()
def integrated(self):
"Return a copy of self integrated with respect to the variable"
result = self.clone()
result.integrate()
return result
def evaluate(self, maxX, pointsX):
# Note: This usually creates a few more points than specified in pointsX
offset = (maxX - self.segments[0].start) / (pointsX - 1)
xvals = set([self.segments[0].start + s * offset for s in range(pointsX)])
starts = set([self.segments[i].start for i in range(len(self.segments))])
xvals = xvals.union(starts) # Make sure we have a point on each segment start
xresult = []
yresult = []
for xval in sorted(xvals):
if xval in starts:
# create double point at segment border
xresult.append(xval)
yresult.append(self.lowervalue(xval))
xresult.append(xval)
yresult.append(self.value(xval))
return (xresult, yresult)
def output(self):
FreeCAD.Console.PrintMessage(self.name + " = ")
for i in range(len(self.segments)):
FreeCAD.Console.PrintMessage(self.segments[i].asString())
if i < len(self.segments) - 1:
FreeCAD.Console.PrintMessage(" + ")
FreeCAD.Console.PrintMessage("\n")

View File

@ -0,0 +1,245 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui # FreeCAD just required for debug printing to the console...
from SegmentFunction import SegmentFunction
from ShaftFeature import ShaftFeature
from ShaftDiagram import Diagram
class ShaftSegment:
length = 0.0
diameter = 0.0
loadType = "None"
loadSize = 0.0
loadLocation = 0.0
def __init__(self, l, d):
self.length = l
self.diameter = d
class Shaft:
"The axis of the shaft is always assumed to correspond to the X-axis"
# List of shaft segments (each segment has a different diameter)
segments = []
# The sketch
sketch = 0
#featureWindow = None
# The diagrams
diagrams = {} # map of function name against Diagram object
# Calculation of shaft
Qy = 0 # force in direction of y axis
Qz = 0 # force in direction of z axis
Mbz = 0 # bending moment around z axis
Mby = 0 # bending moment around y axis
Mtz = 0 # torsion moment around z axis
def __init__(self, doc):
self.sketch = ShaftFeature(doc)
def getLengthTo(self, index):
"Get the total length of all segments up to the given one"
result = 0.0
for i in range(index):
result += self.segments[i].length
return result
def addSegment(self, l, d):
#print "Adding segment: ", l, " : ", d
self.segments.append(ShaftSegment(l,d))
self.sketch.addSegment(l, d)
# We don't call equilibrium() here because the new segment has no loads defined yet
def updateSegment(self, index, length = None, diameter = None):
oldLength = self.segments[index].length
#print "Old length of ", index, ": ", oldLength, ", new Length: ", length, " diameter: ", diameter
if length is not None:
self.segments[index].length = length
if diameter is not None:
self.segments[index].diameter = diameter
self.sketch.updateSegment(index, oldLength, self.segments[index].length, self.segments[index].diameter)
self.equilibrium()
self.updateDiagrams()
def updateLoad(self, index, loadType = None, loadSize = None, loadLocation = None):
if (loadType is not None):
self.segments[index].loadType = loadType
if (loadSize is not None):
self.segments[index].loadSize = loadSize
if (loadLocation is not None):
if (loadLocation >= 0) and (loadLocation <= self.segments[index].length):
self.segments[index].loadLocation = loadLocation
else:
# TODO: Show warning
FreeCAD.Console.PrintMessage("Load location must be inside segment\n")
#self.feature.updateForces() graphical representation of the forces
self.equilibrium()
self.updateDiagrams()
def updateEdge(self, column, start):
App.Console.PrintMessage("Not implemented yet - waiting for robust references...")
return
if self.sketchClosed is not True:
return
# Create a chamfer or fillet at the start or end edge of the segment
if start is True:
row = rowStartEdgeType
idx = 0
else:
row = rowEndEdgeType
idx = 1
edgeType = self.tableWidget.item(row, column).text().toAscii()[0].upper()
if not ((edgeType == "C") or (edgeType == "F")):
return # neither chamfer nor fillet defined
if edgeType == "C":
objName = self.doc.addObject("PartDesign::Chamfer","ChamferShaft%u" % (column * 2 + idx))
else:
objName = self.doc.addObject("PartDesign::Fillet","FilletShaft%u" % (column * 2 + idx))
if objName == "":
return
edgeName = "Edge%u" % self.getEdgeIndex(column, idx, edgeType)
self.doc.getObject(objName).Base = (self.doc.getObject("RevolutionShaft"),"[%s]" % edgeName)
# etc. etc.
def getEdgeIndex(self, column, startIdx):
# FIXME: This is impossible without robust references anchored in the sketch!!!
return
def updateDiagrams(self):
if (self.Qy == 0) or (self.Mbz == 0):
return
if self.Qy.name in self.diagrams:
# Update diagram
self.diagrams[self.Qy.name].update(self.Qy, self.getLengthTo(len(self.segments)) / 1000.0)
else:
# Create diagram
self.diagrams[self.Qy.name] = Diagram()
self.diagrams[self.Qy.name].create("Shear force", self.Qy, self.getLengthTo(len(self.segments)) / 1000.0, "x", "mm", 1000.0, "Q_y", "N", 1.0, 10)
if self.Mbz.name in self.diagrams:
# Update diagram
self.diagrams[self.Mbz.name].update(self.Mbz, self.getLengthTo(len(self.segments)) / 1000.0)
else:
# Create diagram
self.diagrams[self.Mbz.name] = Diagram()
self.diagrams[self.Mbz.name].create("Bending moment", self.Mbz, self.getLengthTo(len(self.segments)) / 1000.0, "x", "mm", 1000.0, "M_{b,z}", "Nm", 1.0, 10)
def equilibrium(self):
# Build equilibrium equations
forces = {0.0:0.0} # dictionary of (location : outer force)
moments = {0.0:0.0} # dictionary of (location : outer moment)
variableNames = [""] # names of all variables
locations = {} # dictionary of (variableName : location)
coefficientsFy = [0] # force equilibrium equation
coefficientsMbz = [0] # moment equilibrium equation
for i in range(len(self.segments)):
lType = self.segments[i].loadType
load = -1 # -1 means unknown (just for debug printing)
location = -1
if lType == "Fixed":
# Fixed segment
if i == 0:
location = 0
variableNames.append("Fy%u" % i)
coefficientsFy.append(1)
coefficientsMbz.append(0)
variableNames.append("Mz%u" % i)
coefficientsFy.append(0)
coefficientsMbz.append(1) # Force does not contribute because location is zero
elif i == len(self.segments) - 1:
location = self.getLengthTo(len(self.segments)) / 1000
variableNames.append("Fy%u" % i)
coefficientsFy.append(1)
coefficientsMbz.append(location)
variableNames.append("Mz%u" % i)
coefficientsFy.append(0)
coefficientsMbz.append(1)
else:
# TODO: Better error message
FreeCAD.Console.PrintMessage("Fixed constraint must be at beginning or end of shaft\n")
return
locations["Fy%u" % i] = location
locations["Mz%u" % i] = location
elif lType == "Static":
# Static load (currently force only)
load = self.segments[i].loadSize
location = (self.getLengthTo(i) + self.segments[i].loadLocation) / 1000 # convert to meters
coefficientsFy[0] = coefficientsFy[0] - load
forces[location] = load
coefficientsMbz[0] = coefficientsMbz[0] - load * location
moments[location] = 0
#elif lType == "None":
# # No loads on segment
FreeCAD.Console.PrintMessage("Segment: %u, type: %s, load: %f, location: %f\n" % (i, lType, load, location))
self.printEquilibrium(variableNames, coefficientsFy)
self.printEquilibrium(variableNames, coefficientsMbz)
# Build matrix and vector for linear algebra solving algorithm
try:
import numpy as np
except ImportError:
FreeCAD.Console.PrintMessage("numpy is not installed on your system\n")
raise ImportError("numpy not installed")
if (len(coefficientsFy) < 3) or (len(coefficientsMbz) < 3):
return
A = np.array([coefficientsFy[1:], coefficientsMbz[1:]])
b = np.array([coefficientsFy[0], coefficientsMbz[0]])
solution = np.linalg.solve(A, b)
# Complete dictionary of forces and moments
if variableNames[1][0] == "F":
forces[locations[variableNames[1]]] = solution[0]
else:
moments[locations[variableNames[1]]] = solution[0]
if variableNames[2][0] == "F":
forces[locations[variableNames[2]]] = solution[1]
else:
moments[locations[variableNames[2]]] = solution[1]
FreeCAD.Console.PrintMessage(forces)
FreeCAD.Console.PrintMessage(moments)
self.Qy = SegmentFunction("Qy")
self.Qy.buildFromDict("x", forces)
self.Qy.output()
self.Mbz = self.Qy.integrated().negate()
self.Mbz.addSegments(moments) # takes care of boundary conditions
self.Mbz.name = "Mbz"
self.Mbz.output()
def printEquilibrium(self, var, coeff):
# Auxiliary method for debugging purposes
for i in range(len(var)):
if i == 0:
FreeCAD.Console.PrintMessage("%f = " % coeff[i])
else:
FreeCAD.Console.PrintMessage("%f * %s" % (coeff[i], var[i]))
if (i < len(var) - 1) and (i != 0):
FreeCAD.Console.PrintMessage(" + ")
FreeCAD.Console.PrintMessage("\n")

View File

@ -0,0 +1,91 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
from PyQt4 import QtCore, QtGui
import FreeCAD, FreeCADGui
class Diagram:
function = 0 # This is assumed to be always a SegmentFunction
fname = "y(x)"
xlength = 0.0
xname = "x"
xunit = ""
xscale = 1.0
yname = "y"
yunit = ""
yscale = 1.0
numxpoints = 10
xpoints = []
ypoints = []
# Plot object
thePlot = None
def create(self, title, function, xlength, xname, xunit, xscale, yname, yunit, yscale, numxpoints):
# Initialize
import Plot
self.title = title
self.function = function
self.xlength = xlength
self.xname = xname
self.xunit = xunit
self.xscale = xscale
self.yname = yname
self.yunit = yunit
self.yscale = yscale
self.numxpoints = numxpoints
# Create a plot window
win = Plot.figure(title)
# Get the plot object from the window
self.thePlot = Plot.getPlot()
# Format the plot object
Plot.xlabel("$%s$ [%s]" % (xname, xunit))
Plot.ylabel("$%s$ [%s]" % (yname, yunit))
Plot.grid(True)
# Calculate points
(self.xpoints, self.ypoints) = self.function.evaluate(self.xlength, self.numxpoints)
# Create plot
self.plot()
def update(self, function = None, xlength = None):
if function is not None:
self.function = function
if xlength is not None:
self.xlength = xlength
# Calculate points
(self.xpoints, self.ypoints) = self.function.evaluate(self.xlength, self.numxpoints)
# Create plot
self.plot()
def plot(self):
plots = self.thePlot.series
if plots:
# Remove line from plot
axes = plots[0].axes
axes.lines.pop(plots[0].lid)
# Remove serie from list
del self.thePlot.series[0]
self.thePlot.update()
self.thePlot.plot(self.xpoints, self.ypoints)

View File

@ -0,0 +1,133 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui
import Part, Sketcher
class ShaftFeature:
"Creates and updates the feature of the shaft"
Doc = 0
App = FreeCAD
Gui = FreeCADGui
sketch = 0
feature = 0
segments = 0 # number of segments
totalLength = 0 # total length of all segments
lastRadius = 0 # radius of last segment (required for adding segments)
def __init__(self, doc):
"Create new feature"
self.Doc = doc
# TODO: Discover existing sketch and get data from it
self.sketch = self.Doc.addObject("Sketcher::SketchObject","SketchShaft")
self.sketch.Placement = self.App.Placement(self.App.Vector(0,0,0),self.App.Rotation(0,0,0,1))
def addSegment(self, length, diameter):
"Add a segment at the end of the shaft"
# Find constraint indices of vertical line constraint, horizontal line constraint
# FIXME: Should have a unique id instead of indices that might change with user editing
# 0-3 belong to the centerline
# 4-6 to the first vertical section
# 7-9 to the first horizontal section
# 10-12 to the second vertical section
# etc. etc.
constrRadius = 4 + self.segments * 6
constrLength = 7 + self.segments * 6
# Find line index of vertical segment, horizontal segment, last shaft segment
# FIXME: Should have a unique id instead of indices that might change with user editing
segRadius = 1 + self.segments * 2
segLength = 2 + self.segments * 2
prevSegLength = 0 + self.segments * 2
prevSegEnd = 3 + (self.segments - 1) * 2
segEnd = prevSegEnd + 2
radius = diameter / 2
oldLength = self.totalLength
self.totalLength += length
self.segments += 1
if oldLength == 0:
# First segment of shaft
# Create centerline
self.sketch.addGeometry(Part.Line(self.App.Vector(0,0,0), self.App.Vector(self.totalLength,0,0)))
self.sketch.addConstraint(Sketcher.Constraint('DistanceX',0, self.totalLength)) # Constraint1
self.sketch.addConstraint(Sketcher.Constraint('PointOnObject',0,1,-1)) # Constraint2
self.sketch.addConstraint(Sketcher.Constraint('PointOnObject',0,1,-2)) # Constraint3
self.sketch.addConstraint(Sketcher.Constraint('Horizontal', 0)) # Constraint4
# Create first segment
self.sketch.addGeometry(Part.Line(self.App.Vector(0,0,0), self.App.Vector(0,radius,0)))
self.sketch.addConstraint(Sketcher.Constraint('DistanceY',1,radius)) # Constraint5
self.sketch.addConstraint(Sketcher.Constraint('Coincident',0,1,1,1)) # Constraint6
self.sketch.addConstraint(Sketcher.Constraint('Vertical',1)) # Constraint7
self.sketch.addGeometry(Part.Line(self.App.Vector(0,radius,0), self.App.Vector(length,radius,0)))
self.sketch.addConstraint(Sketcher.Constraint('DistanceX',2,length)) # Constraint8
self.sketch.addConstraint(Sketcher.Constraint('Coincident',2,1,1,2)) # Constraint9
self.sketch.addConstraint(Sketcher.Constraint('Horizontal',2)) # Constraint10
else:
# remove line that closes the shaft
self.sketch.delGeometry(prevSegEnd)
# TODO: Delete the two constraints? Or will they disappear automatically?
# Adjust length of centerline
self.sketch.setDatum(0,self.totalLength)
# Add segment at the end
self.sketch.addGeometry(Part.Line(self.App.Vector(oldLength,self.lastRadius,0), self.App.Vector(oldLength,radius,0)))
self.sketch.addConstraint(Sketcher.Constraint('DistanceY', 0, 1, segRadius, 2, radius))
self.sketch.addConstraint(Sketcher.Constraint('Coincident',segRadius,1,prevSegLength,2))
self.sketch.addConstraint(Sketcher.Constraint('Vertical',segRadius))
self.sketch.addGeometry(Part.Line(self.App.Vector(oldLength,radius,0), self.App.Vector(oldLength+length,radius,0)))
self.sketch.addConstraint(Sketcher.Constraint('DistanceX',segLength,length))
self.sketch.addConstraint(Sketcher.Constraint('Coincident',segLength,1,segRadius,2))
self.sketch.addConstraint(Sketcher.Constraint('Horizontal',segLength))
# close the sketch
self.sketch.addGeometry(Part.Line(self.App.Vector(oldLength+length,radius,0), self.App.Vector(oldLength+length,0,0)))
self.sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,segEnd,2))
self.sketch.addConstraint(Sketcher.Constraint('Coincident',segEnd,1,segLength,2))
lastRadius = radius
if oldLength == 0:
# create feature
self.feature = self.Doc.addObject("PartDesign::Revolution","RevolutionShaft")
self.feature.Sketch = self.sketch
self.feature.ReferenceAxis = (self.sketch,['H_Axis'])
self.feature.Angle = 360.0
self.Doc.recompute()
self.Gui.hide("SketchShaft")
else:
self.Doc.recompute()
# FIXME: Will give a warning in the console if the active window is not the feature
self.Gui.SendMsgToActiveView("ViewFit")
def updateSegment(self, segment, oldLength, length, diameter):
constrRadius = 4 + segment * 6
constrLength = 7 + segment * 6
# update total length
self.totalLength = self.totalLength - oldLength + length
# Adjust length of centerline
self.sketch.setDatum(0,self.totalLength)
# Adjust segment length
self.sketch.setDatum(constrLength, length)
self.sketch.setDatum(constrRadius, diameter/2)
# Update feature
self.Doc.recompute()
self.Gui.SendMsgToActiveView("ViewFit")

View File

@ -0,0 +1,94 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
import FreeCAD, FreeCADGui
#import os
from PyQt4 import QtCore, QtGui
from WizardShaftTable import WizardShaftTable
from Shaft import Shaft
class TaskWizardShaft:
"Shaft Wizard"
# GUI
App = FreeCAD
Gui = FreeCADGui
doc = Gui.ActiveDocument
# Table and widget
table = 0
form = 0
# Shaft
shaft = 0
# Feature
featureWindow = 0
def __init__(self):
mw = QtGui.qApp.activeWindow()
cw = mw.centralWidget() # This is a qmdiarea widget
# Get active document or create a new one
# Important because when setting the default data in WizardShaftTable() the
# updateSketch() slot will be activated and it relies on finding a valid document
if self.doc == None:
self.Gui.activateWorkbench("PartDesignWorkbench")
self.doc = self.App.ActiveDocument
# Grab the newly created feature window
featureWindow = cw.subWindowList()[-1]
else:
featureWindow = cw.activeSubWindow()
# Create Shaft object
self.shaft = Shaft(self.doc)
# Assign a table widget to the dock window
self.table = WizardShaftTable(self, self.shaft)
self.form = self.table.widget
self.form.setWindowTitle("Shaft wizard")
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
def accept(self):
if self.table:
del self.table
if self.shaft:
del self.shaft
if self.form:
del self.form
return True
class WizardShaftGui:
def Activated(self):
FreeCADGui.Control.showDialog(TaskWizardShaft())
def GetResources(self):
IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/WizardShaft/WizardShaft.svg"
MenuText = 'Shaft design wizard...'
ToolTip = 'Start the shaft design wizard'
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
def IsActive(self):
return FreeCAD.ActiveDocument != None
FreeCADGui.addCommand('PartDesign_WizardShaft', WizardShaftGui())
#Note: Start wizard in Python Console with
# Gui.runCommand('PartDesign_WizardShaft')

View File

@ -0,0 +1,419 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2901"
sodipodi:version="0.32"
inkscape:version="0.48.0 r9654"
sodipodi:docname="PartDesign_Groove.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1"
inkscape:export-filename="/home/yorik/PartDesign_Groove.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs2903">
<linearGradient
id="linearGradient4237">
<stop
id="stop4239"
offset="0"
style="stop-color:#f82b39;stop-opacity:1;" />
<stop
id="stop4241"
offset="1"
style="stop-color:#520001;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4052">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4054" />
<stop
id="stop4060"
offset="0.5"
style="stop-color:#f0f1f1;stop-opacity:1;" />
<stop
style="stop-color:#0046ff;stop-opacity:1;"
offset="1"
id="stop4056" />
</linearGradient>
<linearGradient
id="linearGradient4044">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4046" />
<stop
style="stop-color:#061aff;stop-opacity:1;"
offset="1"
id="stop4048" />
</linearGradient>
<linearGradient
id="linearGradient3273">
<stop
id="stop3275"
offset="0"
style="stop-color:#c8e0f9;stop-opacity:1;" />
<stop
id="stop3277"
offset="1"
style="stop-color:#f7f9fa;stop-opacity:0.09649123;" />
</linearGradient>
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#c8e0f9;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2909" />
<inkscape:perspective
id="perspective3674"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4044"
id="linearGradient4050"
x1="44.858215"
y1="14.016123"
x2="33.928684"
y2="33.216251"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,1.4694319,0.12765765)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052"
id="linearGradient4058"
x1="42.373707"
y1="5.7974987"
x2="52.323219"
y2="22.675821"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,1.4694319,0.12765765)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052-1"
id="linearGradient4058-6"
x1="42.373707"
y1="5.7974987"
x2="52.323219"
y2="22.675821"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,1.4694319,0.12765765)" />
<linearGradient
id="linearGradient4052-1">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4054-5" />
<stop
id="stop4060-8"
offset="0.5"
style="stop-color:#f0f1f1;stop-opacity:1;" />
<stop
style="stop-color:#0046ff;stop-opacity:1;"
offset="1"
id="stop4056-4" />
</linearGradient>
<linearGradient
gradientTransform="translate(-30.295225,-2.9287147)"
y2="22.675821"
x2="52.323219"
y1="5.7974987"
x1="42.373707"
gradientUnits="userSpaceOnUse"
id="linearGradient4078"
xlink:href="#linearGradient4052-1"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4044"
id="linearGradient3885"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,107.10579,-22.235978)"
x1="44.858215"
y1="14.016123"
x2="33.928684"
y2="33.216251" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052-1"
id="linearGradient3890"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,107.10579,-22.235978)"
x1="42.373707"
y1="5.7974987"
x2="52.323219"
y2="22.675821" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052"
id="linearGradient3893"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,107.10579,-22.235978)"
x1="42.373707"
y1="5.7974987"
x2="52.323219"
y2="22.675821" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052-1-0"
id="linearGradient3890-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.55370638,0,0,0.55364331,74.680363,-24.12284)"
x1="42.373707"
y1="5.7974987"
x2="52.323219"
y2="22.675821" />
<linearGradient
id="linearGradient4052-1-0">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4054-5-5" />
<stop
id="stop4060-8-6"
offset="0.5"
style="stop-color:#f0f1f1;stop-opacity:1;" />
<stop
style="stop-color:#0046ff;stop-opacity:1;"
offset="1"
id="stop4056-4-6" />
</linearGradient>
<linearGradient
y2="22.675821"
x2="52.323219"
y1="5.7974987"
x1="42.373707"
gradientTransform="matrix(0.97680237,0,0,0.96003508,-3.3630199,-18.322982)"
gradientUnits="userSpaceOnUse"
id="linearGradient3912"
xlink:href="#linearGradient4052-1-0"
inkscape:collect="always" />
<linearGradient
id="linearGradient4052-1-0-0">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4054-5-5-9" />
<stop
id="stop4060-8-6-8"
offset="0.5"
style="stop-color:#f0f1f1;stop-opacity:1;" />
<stop
style="stop-color:#0046ff;stop-opacity:1;"
offset="1"
id="stop4056-4-6-4" />
</linearGradient>
<linearGradient
y2="22.675821"
x2="52.323219"
y1="5.7974987"
x1="42.373707"
gradientTransform="matrix(0.97680237,0,0,0.96003508,126.73769,-70.092683)"
gradientUnits="userSpaceOnUse"
id="linearGradient3985"
xlink:href="#linearGradient4052-1-0-0"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4044"
id="linearGradient3885-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.55370638,0,0,0.55364331,60.929239,37.280914)"
x1="44.858215"
y1="14.016123"
x2="33.928684"
y2="33.216251" />
<linearGradient
id="linearGradient4044-8">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4046-2" />
<stop
style="stop-color:#061aff;stop-opacity:1;"
offset="1"
id="stop4048-1" />
</linearGradient>
<linearGradient
y2="33.216251"
x2="33.928684"
y1="14.016123"
x1="44.858215"
gradientTransform="matrix(0.97680237,0,0,0.96003508,-26.24677,-8.4607595)"
gradientUnits="userSpaceOnUse"
id="linearGradient4072"
xlink:href="#linearGradient4044-8"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4044-8-4"
id="linearGradient3885-6-5"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.97680237,0,0,0.96003508,58.307367,54.671469)"
x1="44.858215"
y1="14.016123"
x2="33.928684"
y2="33.216251" />
<linearGradient
id="linearGradient4044-8-4">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4046-2-0" />
<stop
style="stop-color:#061aff;stop-opacity:1;"
offset="1"
id="stop4048-1-9" />
</linearGradient>
<linearGradient
y2="33.216251"
x2="33.928684"
y1="14.016123"
x1="44.858215"
gradientTransform="matrix(0.97680237,0,0,0.96003508,145.41299,94.782221)"
gradientUnits="userSpaceOnUse"
id="linearGradient4163"
xlink:href="#linearGradient4044-8-4"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052-1-0-9"
id="linearGradient3890-3-5"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.55370638,0,0,0.55364331,74.680363,-24.12284)"
x1="42.373707"
y1="5.7974987"
x2="52.323219"
y2="22.675821" />
<linearGradient
id="linearGradient4052-1-0-9">
<stop
style="stop-color:#0090ff;stop-opacity:1;"
offset="0"
id="stop4054-5-5-2" />
<stop
id="stop4060-8-6-5"
offset="0.5"
style="stop-color:#f0f1f1;stop-opacity:1;" />
<stop
style="stop-color:#0046ff;stop-opacity:1;"
offset="1"
id="stop4056-4-6-5" />
</linearGradient>
<linearGradient
y2="22.675821"
x2="52.323219"
y1="5.7974987"
x1="42.373707"
gradientTransform="matrix(0.97680237,0,0,0.96003508,126.73769,-70.092687)"
gradientUnits="userSpaceOnUse"
id="linearGradient4217"
xlink:href="#linearGradient4052-1-0-9"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.8890873"
inkscape:cx="38.625766"
inkscape:cy="12.657788"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1018"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:snap-nodes="true"
inkscape:object-paths="true"
inkscape:object-nodes="true"
inkscape:snap-intersection-paths="true" />
<metadata
id="metadata2906">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="color:#000000;fill:none;stroke:#ff0d00;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 60.033553,11.624146 2.9356835,49.895439"
id="path4129"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;fill:url(#linearGradient3885-6);fill-opacity:1.0;fill-rule:evenodd;stroke:#000137;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 33.589321,8.1499488 c 0.310719,0.4348594 0.568952,0.924885 0.761713,1.4417267 1.54209,4.1347065 -1.513953,9.1431885 -6.819987,11.1914025 -1.079148,0.416568 -2.160312,0.657262 -3.223995,0.774928 7.099799,4.804046 13.087612,12.269737 15.251972,21.806117 0.674062,-1.709016 1.803272,-3.374523 3.365708,-4.775719 2.394689,-2.147563 5.276855,-3.22083 7.847415,-3.153778 1.999324,0.05215 3.808695,0.783303 5.066276,2.234677 0.431584,0.49809 0.762456,1.065523 1.027427,1.657986 C 57.308292,21.656223 46.249275,12.722898 33.589321,8.1499488 z"
id="path3832-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssccssscc" />
<path
style="color:#000000;fill:none;stroke:#000137;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 33.595667,8.1588471 c 0.31072,0.4348652 0.568952,0.9248908 0.761713,1.4417268 1.542089,4.1347081 -1.513952,9.1431901 -6.819987,11.1914041 -1.079148,0.416568 -2.160311,0.657262 -3.223994,0.774928 m 15.251974,21.806118 c 0.67406,-1.709017 1.803271,-3.374523 3.365708,-4.77572 2.394689,-2.147563 5.276852,-3.22083 7.847414,-3.153778 1.999324,0.05215 3.808695,0.783303 5.066277,2.234677 0.431581,0.49809 0.762455,1.065523 1.027426,1.657986"
id="path3832-2-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssccsssc" />
<path
id="path3846-3"
style="color:#000000;fill:url(#linearGradient3890-3);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 3.536174,22.642207 c 18.022131,7.741361 26.381756,27.136035 26.236001,37.96079 L 40.42899,51.501192 C 40.591405,33.650608 27.82732,21.231698 15.136181,17.008914 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
id="path3842-6"
style="color:#000000;fill:url(#linearGradient3890-3-5);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 56.874841,39.325295 C 57.306666,21.656073 46.253772,12.727686 33.592842,8.1578264 L 39.537797,5.2929423 C 56.829323,9.1025668 61.692642,25.014757 61.692642,35.542943 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
id="path3852-7"
style="color:#000000;fill:#8bd2f7;fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 29.772175,60.602996 C 29.91793,49.77824 21.558305,30.383568 3.5361734,22.642207 L 3.97344,30.797845 c 7.619318,3.028308 17.782178,14.976717 18.219445,24.911767 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,334 @@
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
from PyQt4 import QtCore, QtGui
import FreeCAD # Just for debug printing...
class WizardShaftTable:
"The table widget that contains all the data of the shaft"
# Dictionary to access different parameters without using a numeric row index that might change
# as the code evolves
rowDict = {
"Length" : 0,
"Diameter" : 1,
"LoadType" : 2,
"LoadSize" : 3,
"LoadLocation" : 4,
"StartEdgeType" : 5,
"StartEdgeSize" : 6,
"EndEdgeType" : 7,
"EndEdgeSize" : 8
}
rowDictReverse = {}
headers = ["Length [mm]",
"Diameter [mm]",
"Load type",
"Load [N]",
"Location [mm]",
"Start edge type",
"Start edge size",
"End edge type",
"End edge size"
]
widget = 0
wizard = 0
shaft = 0
def __init__(self, w, s):
for key in self.rowDict.iterkeys():
self.rowDictReverse[self.rowDict[key]] = key
# Set parent wizard (for connecting slots)
self.wizard = w
self.shaft = s
# Create table widget
self.widget = QtGui.QTableWidget(len(self.rowDict), 0)
self.widget.resize(QtCore.QSize(300,100))
#self.widget.setFocusPolicy(QtCore.Qt.StrongFocus)
# Label rows and columns
self.widget.setVerticalHeaderLabels(self.headers)
self.widget.setHorizontalHeaderLabels(["Section 1", "Section 2"])
#self.widget.columnMoved.connect(column, oldIndex, newIndex)
# Create context menu
action = QtGui.QAction("Add column", self.widget)
action.triggered.connect(self.slotInsertColumn)
self.widget.addAction(action)
self.widget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
# Set some default data
# Section 1
self.addColumn()
self.setLength(0, 40.0)
self.setDiameter(0, 50.0)
self.setLoadType(0, "Static")
self.setLoadSize(0, 1000.0)
self.setLoadLocation(0, 25.0)
# Section 2
self.addColumn()
self.setLength(1, 80.0)
self.setDiameter(1, 60.0)
self.setLoadType(1, "Fixed")
def slotInsertColumn(self, point):
# FIXME: Allow inserting columns, not just adding at the end
# Note: need to re-name all the following column headers then
# if (column == self.tableWidget.columnCount()):
self.addColumn()
# else:
# self.insertColumn(index)
def addColumn(self):
"Add a new column, fill it with widgets, and connect the signals"
index = self.widget.columnCount()
# Make an intelligent guess at the length/dia of the next segment
if index > 0:
length = self.shaft.segments[index-1].length
diameter = self.shaft.segments[index-1].diameter
if index > 2:
diameter -= 5.0
else:
diameter += 5.0
else:
length = 20.0
diameter = 10.0
self.shaft.addSegment(length, diameter)
self.widget.insertColumn(index)
self.widget.setHorizontalHeaderItem(index + 1, QtGui.QTableWidgetItem("Section %s" % (index + 1)))
# Length
widget = QtGui.QDoubleSpinBox(self.widget)
widget.setMinimum(0)
widget.setMaximum(1E9)
self.widget.setCellWidget(self.rowDict["Length"], index, widget)
widget.setValue(length)
widget.valueChanged.connect(self.slotValueChanged)
widget.editingFinished.connect(self.slotEditingFinished)
# Diameter
widget = QtGui.QDoubleSpinBox(self.widget)
widget.setMinimum(0)
widget.setMaximum(1E9)
self.widget.setCellWidget(self.rowDict["Diameter"], index, widget)
widget.setValue(diameter)
widget.valueChanged.connect(self.slotValueChanged)
widget.editingFinished.connect(self.slotEditingFinished)
# Load type
widget = QtGui.QComboBox(self.widget)
widget.insertItem(0, "None")
widget.insertItem(1, "Fixed")
widget.insertItem(2, "Static")
widget.insertItem(3, "Bearing")
widget.insertItem(4, "Pulley")
self.widget.setCellWidget(self.rowDict["LoadType"], index, widget)
widget.setCurrentIndex(0)
self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType)
# Load size
widget = QtGui.QDoubleSpinBox(self.widget)
widget.setMinimum(-1E9)
widget.setMaximum(1E9)
self.widget.setCellWidget(self.rowDict["LoadSize"], index, widget)
widget.setValue(0)
widget.valueChanged.connect(self.slotValueChanged)
widget.editingFinished.connect(self.slotEditingFinished)
# Load location
widget = QtGui.QDoubleSpinBox(self.widget)
widget.setMinimum(0)
widget.setMaximum(1E9)
self.widget.setCellWidget(self.rowDict["LoadLocation"], index, widget)
widget.setValue(0)
widget.valueChanged.connect(self.slotValueChanged)
widget.editingFinished.connect(self.slotEditingFinished)
# Start edge type
widget = QtGui.QComboBox(self.widget)
widget.insertItem(0, "None",)
widget.insertItem(1, "Chamfer")
widget.insertItem(2, "Fillet")
self.widget.setCellWidget(self.rowDict["StartEdgeType"],index, widget)
widget.setCurrentIndex(0)
self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType)
# Start edge size
widget = QtGui.QDoubleSpinBox(self.widget)
widget.setMinimum(0)
widget.setMaximum(1E9)
self.widget.setCellWidget(self.rowDict["StartEdgeSize"],index, widget)
widget.setValue(1)
widget.valueChanged.connect(self.slotValueChanged)
widget.editingFinished.connect(self.slotEditingFinished)
# End edge type
widget = QtGui.QComboBox(self.widget)
widget.insertItem(0, "None",)
widget.insertItem(1, "Chamfer")
widget.insertItem(2, "Fillet")
self.widget.setCellWidget(self.rowDict["EndEdgeType"],index, widget)
widget.setCurrentIndex(0)
self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType)
# End edge size
widget = QtGui.QDoubleSpinBox(self.widget)
widget.setMinimum(0)
widget.setMaximum(1E9)
self.widget.setCellWidget(self.rowDict["EndEdgeSize"],index, widget)
widget.setValue(1)
widget.valueChanged.connect(self.slotValueChanged)
widget.editingFinished.connect(self.slotEditingFinished)
def slotValueChanged(self, value):
(self.editedRow, self.editedColumn) = self.getFocusedCell()
self.editedValue = value
def slotEditingFinished(self):
rowName = self.rowDictReverse[self.editedRow]
if rowName is None:
return
if rowName == "Length":
self.shaft.updateSegment(self.editedColumn, length = self.getDoubleValue(rowName, self.editedColumn))
elif rowName == "Diameter":
self.shaft.updateSegment(self.editedColumn, diameter = self.getDoubleValue(rowName, self.editedColumn))
elif rowName == "LoadType":
self.shaft.updateLoad(self.editedColumn, loadType = self.getListValue(rowName, self.editedColumn))
elif rowName == "LoadSize":
self.shaft.updateLoad(self.editedColumn, loadSize = self.getDoubleValue(rowName, self.editedColumn))
elif rowName == "LoadLocation":
self.shaft.updateLoad(self.editedColumn, loadLocation = self.getDoubleValue(rowName, self.editedColumn))
elif rowName == "StartEdgeType":
pass
elif rowName == "StartEdgeSize":
pass
elif rowName == "EndEdgeType":
pass
elif rowName == "EndEdgeSize":
pass
def setLength(self, column, l):
self.setDoubleValue("Length", column, l)
self.shaft.updateSegment(column, length = l)
def getLength(self, column):
return self.getDoubleValue("Length", column)
def setDiameter(self, column, d):
self.setDoubleValue("Diameter", column, d)
self.shaft.updateSegment(column, diameter = d)
def getDiameter(self, column):
return self.getDoubleValue("Diameter", column)
@QtCore.pyqtSlot('QString')
def slotLoadType(self, text):
if text != "Fixed":
if (self.getLoadSize is None) or (self.getLoadLocation is None):
return
self.shaft.updateLoad(self.getFocusedColumn(), loadType = text)
def setLoadType(self, column, t):
self.setListValue("LoadType", column, t)
self.shaft.updateLoad(column, loadType = t)
def getLoadType(self, column):
return self.getListValue("LoadType", column)
def setLoadSize(self, column, s):
self.setDoubleValue("LoadSize", column, s)
self.shaft.updateLoad(column, loadSize = s)
def getLoadSize(self, column):
return self.getDoubleValue("LoadSize", column)
def setLoadLocation(self, column, l):
self.setDoubleValue("LoadLocation", column, l)
self.shaft.updateLoad(column, loadLocation = l)
def getLoadLocation(self, column):
return self.getDoubleValue("LoadLocation", column)
def slotStartEdgeType(self, old, new):
pass
def setStartEdgeType(self, column, t):
self.setListValue("StartEdgeType", column, t)
def getStartEdgeType(self, column):
return self.getListValue("StartEdgeType", column)
def setStartEdgeSize(self, column, s):
self.setDoubleValue("StartEdgeSize", column, s)
def getStartEdgeSize(self, column):
return self.getDoubleValue("StartEdgeSize", column)
def slotEndEdgeType(self, old, new):
pass
def setEndEdgeType(self, column, t):
self.setListValue("EndEdgeType", column, t)
def getEndEdgeType(self, column):
return self.getListValue("EndEdgeType", column)
def setEndEdgeSize(self, column, s):
self.setDoubleValue("EndEdgeSize", column, s)
def getEndEdgeSize(self, column):
return self.getDoubleValue("EndEdgeSize", column)
def setDoubleValue(self, row, column, v):
widget = self.widget.cellWidget(self.rowDict[row], column)
# Avoid triggering a signal, because the slot will work on the focused cell, not the current one
widget.blockSignals(True)
widget.setValue(v)
widget.blockSignals(False)
def getDoubleValue(self, row, column):
widget = self.widget.cellWidget(self.rowDict[row], column)
if widget is not None:
return widget.value()
else:
return None
def setListValue(self, row, column, v):
widget = self.widget.cellWidget(self.rowDict[row], column)
widget.blockSignals(True)
widget.setCurrentIndex(widget.findText(v, QtCore.Qt.MatchExactly))
widget.blockSignals(False)
def getListValue(self, row, column):
widget = self.widget.cellWidget(self.rowDict[row], column)
if widget is not None:
return widget.currentText().toAscii()[0].upper()
else:
return None
def getFocusedColumn(self):
# Make the focused cell also the current one in the table
widget = QtGui.QApplication.focusWidget()
if widget is not None:
index = self.widget.indexAt(widget.pos())
self.widget.setCurrentCell(index.row(), index.column())
return self.widget.currentColumn()
def getFocusedCell(self):
# Make the focused cell also the current one in the table
widget = QtGui.QApplication.focusWidget()
if widget is not None:
index = self.widget.indexAt(widget.pos())
self.widget.setCurrentCell(index.row(), index.column())
return (self.widget.currentRow(), self.widget.currentColumn())

View File

@ -0,0 +1,27 @@
"""
Shaft Wizard
"""
#/******************************************************************************
# * Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ******************************************************************************/
# Empty file to treat the folder as a package

View File

@ -51,7 +51,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
int SecondIndex= Constraint::GeoUndef;
int SecondPos = none;
int ThirdIndex = Constraint::GeoUndef;
//int ThirdPos = none;
int ThirdPos = none;
double Value = 0;
// Note: In Python 2.x PyArg_ParseTuple prints a warning if a float is given but an integer is expected.
// This means we must use a PyObject and check afterwards if it's a float or integer.
@ -292,6 +292,21 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
}
}
}
PyErr_Clear();
if (PyArg_ParseTuple(args, "siiiiii", &ConstraintType, &FirstIndex, &FirstPos, &SecondIndex, &SecondPos, &ThirdIndex, &ThirdPos)) {
// ConstraintType, GeoIndex1, PosIndex1, GeoIndex2, PosIndex2, GeoIndex3, PosIndex3
if (strcmp("Symmetric",ConstraintType) == 0 ) {
this->getConstraintPtr()->Type = Symmetric;
this->getConstraintPtr()->First = FirstIndex;
this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos;
this->getConstraintPtr()->Second = SecondIndex;
this->getConstraintPtr()->SecondPos = (Sketcher::PointPos) SecondPos;
this->getConstraintPtr()->Third = ThirdIndex;
this->getConstraintPtr()->ThirdPos = (Sketcher::PointPos) ThirdPos;
return 0;
}
}
PyErr_SetString(PyExc_TypeError, "Constraint constructor accepts:\n"
"-- empty parameter list\n"

View File

@ -537,8 +537,13 @@ int Sketch::addConstraint(const Constraint *constraint)
rtn = addEqualConstraint(constraint->First,constraint->Second);
break;
case Symmetric:
rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos,
constraint->Second,constraint->SecondPos,constraint->Third);
if (constraint->ThirdPos != none)
rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos,
constraint->Second,constraint->SecondPos,
constraint->Third,constraint->ThirdPos);
else
rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos,
constraint->Second,constraint->SecondPos,constraint->Third);
break;
case None:
break;
@ -1522,6 +1527,30 @@ int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointP
return -1;
}
int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2,
int geoId3, PointPos pos3)
{
geoId1 = checkGeoId(geoId1);
geoId2 = checkGeoId(geoId2);
geoId3 = checkGeoId(geoId3);
int pointId1 = getPointId(geoId1, pos1);
int pointId2 = getPointId(geoId2, pos2);
int pointId3 = getPointId(geoId3, pos3);
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
pointId2 >= 0 && pointId2 < int(Points.size()) &&
pointId3 >= 0 && pointId3 < int(Points.size())) {
GCS::Point &p1 = Points[pointId1];
GCS::Point &p2 = Points[pointId2];
GCS::Point &p = Points[pointId3];
int tag = ++ConstraintsCounter;
GCSsys.addConstraintP2PSymmetric(p1, p2, p, tag);
return ConstraintsCounter;
}
return -1;
}
bool Sketch::updateGeometry()
{
int i=0;

View File

@ -172,6 +172,8 @@ public:
int addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2);
/// add a symmetric constraint between two points with respect to a line
int addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3);
/// add a symmetric constraint between three points, the last point is in the middle of the first two
int addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3, PointPos pos3);
//@}
enum GeoType {

View File

@ -1519,7 +1519,7 @@ void SketchObject::onFinishDuplicating()
onDocumentRestored();
}
void SketchObject::getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId)
void SketchObject::getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) const
{
if (VertexId < 0 || VertexId >= int(VertexId2GeoId.size())) {
GeoId = Constraint::GeoUndef;

View File

@ -124,7 +124,7 @@ public:
int trim(int geoId, const Base::Vector3d& point);
/// retrieves for a Vertex number the corresponding GeoId and PosId
void getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId);
void getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) const;
int getHighestVertexIndex(void) const { return VertexId2GeoId.size() - 1; }
int getHighestCurveIndex(void) const { return Geometry.getSize() - 1; }
void rebuildVertexIndex(void);

View File

@ -413,6 +413,18 @@ ConstraintPointOnLine::ConstraintPointOnLine(Point &p, Line &l)
rescale();
}
ConstraintPointOnLine::ConstraintPointOnLine(Point &p, Point &lp1, Point &lp2)
{
pvec.push_back(p.x);
pvec.push_back(p.y);
pvec.push_back(lp1.x);
pvec.push_back(lp1.y);
pvec.push_back(lp2.x);
pvec.push_back(lp2.y);
origpvec = pvec;
rescale();
}
ConstraintType ConstraintPointOnLine::getTypeId()
{
return PointOnLine;
@ -460,6 +472,74 @@ double ConstraintPointOnLine::grad(double *param)
return scale * deriv;
}
// PointOnPerpBisector
ConstraintPointOnPerpBisector::ConstraintPointOnPerpBisector(Point &p, Line &l)
{
pvec.push_back(p.x);
pvec.push_back(p.y);
pvec.push_back(l.p1.x);
pvec.push_back(l.p1.y);
pvec.push_back(l.p2.x);
pvec.push_back(l.p2.y);
origpvec = pvec;
rescale();
}
ConstraintPointOnPerpBisector::ConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2)
{
pvec.push_back(p.x);
pvec.push_back(p.y);
pvec.push_back(lp1.x);
pvec.push_back(lp1.y);
pvec.push_back(lp2.x);
pvec.push_back(lp2.y);
origpvec = pvec;
rescale();
}
ConstraintType ConstraintPointOnPerpBisector::getTypeId()
{
return PointOnPerpBisector;
}
void ConstraintPointOnPerpBisector::rescale(double coef)
{
scale = coef;
}
double ConstraintPointOnPerpBisector::error()
{
double dx1 = *p1x() - *p0x();
double dy1 = *p1y() - *p0y();
double dx2 = *p2x() - *p0x();
double dy2 = *p2y() - *p0y();
return scale * (sqrt(dx1*dx1+dy1*dy1) - sqrt(dx2*dx2+dy2*dy2));
}
double ConstraintPointOnPerpBisector::grad(double *param)
{
double deriv=0.;
if (param == p0x() || param == p0y() ||
param == p1x() || param == p1y()) {
double dx1 = *p1x() - *p0x();
double dy1 = *p1y() - *p0y();
if (param == p0x()) deriv -= dx1/sqrt(dx1*dx1+dy1*dy1);
if (param == p0y()) deriv -= dy1/sqrt(dx1*dx1+dy1*dy1);
if (param == p1x()) deriv += dx1/sqrt(dx1*dx1+dy1*dy1);
if (param == p1y()) deriv += dy1/sqrt(dx1*dx1+dy1*dy1);
}
if (param == p0x() || param == p0y() ||
param == p2x() || param == p2y()) {
double dx2 = *p2x() - *p0x();
double dy2 = *p2y() - *p0y();
if (param == p0x()) deriv += dx2/sqrt(dx2*dx2+dy2*dy2);
if (param == p0y()) deriv += dy2/sqrt(dx2*dx2+dy2*dy2);
if (param == p2x()) deriv -= dx2/sqrt(dx2*dx2+dy2*dy2);
if (param == p2y()) deriv -= dy2/sqrt(dx2*dx2+dy2*dy2);
}
return scale * deriv;
}
// Parallel
ConstraintParallel::ConstraintParallel(Line &l1, Line &l2)
{

View File

@ -41,11 +41,12 @@ namespace GCS
P2PAngle = 4,
P2LDistance = 5,
PointOnLine = 6,
Parallel = 7,
Perpendicular = 8,
L2LAngle = 9,
MidpointOnLine = 10,
TangentCircumf = 11
PointOnPerpBisector = 7,
Parallel = 8,
Perpendicular = 9,
L2LAngle = 10,
MidpointOnLine = 11,
TangentCircumf = 12
};
class Constraint
@ -171,6 +172,26 @@ namespace GCS
inline double* p2y() { return pvec[5]; }
public:
ConstraintPointOnLine(Point &p, Line &l);
ConstraintPointOnLine(Point &p, Point &lp1, Point &lp2);
virtual ConstraintType getTypeId();
virtual void rescale(double coef=1.);
virtual double error();
virtual double grad(double *);
};
// PointOnPerpBisector
class ConstraintPointOnPerpBisector : public Constraint
{
private:
inline double* p0x() { return pvec[0]; }
inline double* p0y() { return pvec[1]; }
inline double* p1x() { return pvec[2]; }
inline double* p1y() { return pvec[3]; }
inline double* p2x() { return pvec[4]; }
inline double* p2y() { return pvec[5]; }
public:
ConstraintPointOnPerpBisector(Point &p, Line &l);
ConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2);
virtual ConstraintType getTypeId();
virtual void rescale(double coef=1.);
virtual double error();

View File

@ -250,6 +250,27 @@ int System::addConstraintPointOnLine(Point &p, Line &l, int tagId)
return addConstraint(constr);
}
int System::addConstraintPointOnLine(Point &p, Point &lp1, Point &lp2, int tagId)
{
Constraint *constr = new ConstraintPointOnLine(p, lp1, lp2);
constr->setTag(tagId);
return addConstraint(constr);
}
int System::addConstraintPointOnPerpBisector(Point &p, Line &l, int tagId)
{
Constraint *constr = new ConstraintPointOnPerpBisector(p, l);
constr->setTag(tagId);
return addConstraint(constr);
}
int System::addConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2, int tagId)
{
Constraint *constr = new ConstraintPointOnPerpBisector(p, lp1, lp2);
constr->setTag(tagId);
return addConstraint(constr);
}
int System::addConstraintParallel(Line &l1, Line &l2, int tagId)
{
Constraint *constr = new ConstraintParallel(l1, l2);
@ -552,6 +573,12 @@ int System::addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId)
return addConstraintMidpointOnLine(p1, p2, l.p1, l.p2, tagId);
}
int System::addConstraintP2PSymmetric(Point &p1, Point &p2, Point &p, int tagId)
{
addConstraintPointOnPerpBisector(p, p1, p2, tagId);
return addConstraintPointOnLine(p, p1, p2, tagId);
}
void System::rescaleConstraint(int id, double coeff)
{
if (id >= clist.size() || id < 0)

View File

@ -99,6 +99,9 @@ namespace GCS
int addConstraintP2PAngle(Point &p1, Point &p2, double *angle, int tagId=0);
int addConstraintP2LDistance(Point &p, Line &l, double *distance, int tagId=0);
int addConstraintPointOnLine(Point &p, Line &l, int tagId=0);
int addConstraintPointOnLine(Point &p, Point &lp1, Point &lp2, int tagId=0);
int addConstraintPointOnPerpBisector(Point &p, Line &l, int tagId=0);
int addConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2, int tagId=0);
int addConstraintParallel(Line &l1, Line &l2, int tagId=0);
int addConstraintPerpendicular(Line &l1, Line &l2, int tagId=0);
int addConstraintPerpendicular(Point &l1p1, Point &l1p2,
@ -151,6 +154,7 @@ namespace GCS
int addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId=0);
int addConstraintEqualRadius(Arc &a1, Arc &a2, int tagId=0);
int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0);
int addConstraintP2PSymmetric(Point &p1, Point &p2, Point &p, int tagId=0);
void rescaleConstraint(int id, double coeff);
void declareUnknowns(VEC_pD &params);

View File

@ -79,22 +79,55 @@ bool checkBothExternal(int GeoId1, int GeoId2)
return false;
}
void getIdsFromName(const std::string &name, int &GeoId, int &VtId)
void getIdsFromName(const std::string &name, const Sketcher::SketchObject* Obj,
int &GeoId, PointPos &PosId)
{
GeoId = Constraint::GeoUndef;
VtId = -1;
if (name.size() > 4 && name.substr(0,4) == "Edge")
PosId = Sketcher::none;
if (name.size() > 4 && name.substr(0,4) == "Edge") {
GeoId = std::atoi(name.substr(4,4000).c_str());
}
else if (name.size() == 9 && name.substr(0,9) == "RootPoint") {
GeoId = -1;
PosId = Sketcher::start;
}
else if (name.size() == 6 && name.substr(0,6) == "H_Axis")
GeoId = -1;
else if (name.size() == 6 && name.substr(0,6) == "V_Axis")
GeoId = -2;
else if (name.size() > 12 && name.substr(0,12) == "ExternalEdge")
GeoId = -3 - std::atoi(name.substr(12,4000).c_str());
else if (name.size() > 6 && name.substr(0,6) == "Vertex")
VtId = std::atoi(name.substr(6,4000).c_str());
else if (name.size() > 6 && name.substr(0,6) == "Vertex") {
int VtId = std::atoi(name.substr(6,4000).c_str());
Obj->getGeoVertexIndex(VtId,GeoId,PosId);
}
}
bool inline isVertex(int GeoId, PointPos PosId)
{
return (GeoId != Constraint::GeoUndef && PosId != Sketcher::none);
}
bool inline isEdge(int GeoId, PointPos PosId)
{
return (GeoId != Constraint::GeoUndef && PosId == Sketcher::none);
}
bool isSimpleVertex(const Sketcher::SketchObject* Obj, int GeoId, PointPos PosId)
{
if (PosId == Sketcher::start && (GeoId == -1 || GeoId == -2))
return true;
const Part::Geometry *geo = Obj->getGeometry(GeoId);
if (geo->getTypeId() == Part::GeomPoint::getClassTypeId())
return true;
else if (PosId == Sketcher::mid &&
(geo->getTypeId() == Part::GeomCircle::getClassTypeId() ||
geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()))
return true;
else
return false;
}
namespace SketcherGui {
@ -405,16 +438,12 @@ void CmdSketcherConstrainLock::activated(int iMsg)
}
int GeoId;
Sketcher::PointPos PosId=Sketcher::none;
if (SubNames[0].size() > 6 && SubNames[0].substr(0,6) == "Vertex") {
int VtId = std::atoi(SubNames[0].substr(6,4000).c_str());
Obj->getGeoVertexIndex(VtId,GeoId,PosId);
}
else if (SubNames[0].size() > 4 && SubNames[0].substr(0,4) == "Edge")
GeoId = std::atoi(SubNames[0].substr(4,4000).c_str());
else {
Sketcher::PointPos PosId;
getIdsFromName(SubNames[0], Obj, GeoId, PosId);
if (isEdge(GeoId,PosId) || GeoId < 0) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select exactly one entity from the sketch."));
QObject::tr("Select one vertex from the sketch."));
return;
}
@ -481,34 +510,22 @@ void CmdSketcherConstrainCoincident::activated(int iMsg)
return;
}
int index1,index2;
// get first vertex index
if (SubNames[0].size() > 6 && SubNames[0].substr(0,6) == "Vertex")
index1 = std::atoi(SubNames[0].substr(6,4000).c_str());
else {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select exactly two vertexes from the sketch."));
return;
}
int GeoId1, GeoId2;
Sketcher::PointPos PosId1, PosId2;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
// get second vertex index
if (SubNames[1].size() > 6 && SubNames[1].substr(0,6) == "Vertex")
index2 = std::atoi(SubNames[1].substr(6,4000).c_str());
else {
if (isEdge(GeoId1,PosId1) || isEdge(GeoId2,PosId2)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select exactly two vertexes from the sketch."));
return;
}
int GeoId1,GeoId2;
Sketcher::PointPos Pt1,Pt2;
Obj->getGeoVertexIndex(index1,GeoId1,Pt1);
Obj->getGeoVertexIndex(index2,GeoId2,Pt2);
// undo command open
openCommand("add coincident constraint");
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ",
selection[0].getFeatName(),GeoId1,Pt1,GeoId2,Pt2);
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2);
// finish the transaction and update
commitCommand();
@ -562,44 +579,41 @@ void CmdSketcherConstrainDistance::activated(int iMsg)
return;
}
int GeoId1=Constraint::GeoUndef, VtId1=-1, GeoId2=Constraint::GeoUndef, VtId2=-1;
if (SubNames.size() >= 1) {
getIdsFromName(SubNames[0], GeoId1, VtId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], GeoId2, VtId2);
}
int GeoId1, GeoId2=Constraint::GeoUndef;
Sketcher::PointPos PosId1, PosId2=Sketcher::none;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
else if ((GeoId2 == -2 || GeoId2 == -1) && GeoId1 == Constraint::GeoUndef) {
else if (isVertex(GeoId1,PosId1) && (GeoId2 == -2 || GeoId2 == -1)) {
std::swap(GeoId1,GeoId2);
std::swap(VtId1,VtId2);
std::swap(PosId1,PosId2);
}
if ((GeoId1 == -2 || GeoId1 == -1 || VtId1 >= 0) && VtId2 >= 0) { // point to point distance
Sketcher::PointPos PosId1,PosId2;
if (GeoId1 == -2 || GeoId1 == -1)
PosId1 = Sketcher::start;
else
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
if ((isVertex(GeoId1,PosId1) || GeoId1 == -2 || GeoId1 == -1) &&
isVertex(GeoId2,PosId2)) { // point to point distance
Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2);
Base::Vector3d pnt1 = Obj->getPoint(GeoId1,PosId1);
Base::Vector3d pnt2 = Obj->getPoint(GeoId2,PosId2);
if (GeoId1 == -1) {
if (GeoId1 == -1 && PosId1 == Sketcher::none) {
PosId1 = Sketcher::start;
openCommand("add distance from horizontal axis constraint");
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f)) ",
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,pnt2.y);
}
else if (GeoId1 == -2) {
else if (GeoId1 == -2 && PosId1 == Sketcher::none) {
PosId1 = Sketcher::start;
openCommand("add distance from vertical axis constraint");
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f)) ",
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,pnt2.x);
}
else {
Base::Vector3d pnt1 = Obj->getPoint(GeoId1,PosId1);
openCommand("add point to point distance constraint");
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ",
@ -617,14 +631,12 @@ void CmdSketcherConstrainDistance::activated(int iMsg)
getSelection().clearSelection();
return;
}
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);
else if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) ||
(isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // point to line distance
if (isVertex(GeoId2,PosId2)) {
std::swap(GeoId1,GeoId2);
std::swap(PosId1,PosId2);
}
Sketcher::PointPos PosId1;
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
Base::Vector3d pnt = Obj->getPoint(GeoId1,PosId1);
const Part::Geometry *geom = Obj->getGeometry(GeoId2);
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
@ -652,10 +664,11 @@ void CmdSketcherConstrainDistance::activated(int iMsg)
return;
}
}
else if (GeoId1 != Constraint::GeoUndef) { // line length
else if (isEdge(GeoId1,PosId1)) { // line length
if (GeoId1 < 0) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a length constraint on an external geometry!"));
GeoId1 < 2 ? QObject::tr("Cannot add a length constraint on an external geometry!")
: QObject::tr("Cannot add a length constraint on an axis!"));
return;
}
@ -732,29 +745,22 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg)
return;
}
int GeoId1=Constraint::GeoUndef, VtId1=-1, GeoId2=Constraint::GeoUndef, VtId2=-1;
if (SubNames.size() >= 1) {
getIdsFromName(SubNames[0], GeoId1, VtId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], GeoId2, VtId2);
}
int GeoId1, GeoId2=Constraint::GeoUndef;
Sketcher::PointPos PosId1, PosId2=Sketcher::none;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) ||
(VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) {
if (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef) {
std::swap(VtId1,VtId2);
if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) ||
(isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) {
if (isVertex(GeoId2,PosId2)) {
std::swap(GeoId1,GeoId2);
std::swap(PosId1,PosId2);
}
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
@ -821,32 +827,28 @@ void CmdSketcherConstrainDistanceX::activated(int iMsg)
return;
}
int GeoId1=Constraint::GeoUndef, VtId1=-1, GeoId2=Constraint::GeoUndef, VtId2=-1;
if (SubNames.size() >= 1) {
getIdsFromName(SubNames[0], GeoId1, VtId1);
if (GeoId1 == -1) // reject horizontal axis from selection
GeoId1 = Constraint::GeoUndef;
if (SubNames.size() == 2) {
getIdsFromName(SubNames[1], GeoId2, VtId2);
if (GeoId2 == -1) // reject horizontal axis from selection
GeoId2 = Constraint::GeoUndef;
}
}
int GeoId1, GeoId2=Constraint::GeoUndef;
Sketcher::PointPos PosId1, PosId2=Sketcher::none;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
else if (GeoId2 == -2 && GeoId1 == Constraint::GeoUndef) {
else if (GeoId2 == -1 || GeoId2 == -2) {
std::swap(GeoId1,GeoId2);
std::swap(VtId1,VtId2);
std::swap(PosId1,PosId2);
}
if ((GeoId1 == -2 || VtId1 >= 0) && VtId2 >= 0) { // point to point horizontal distance
Sketcher::PointPos PosId1,PosId2;
if (GeoId1 == -2)
PosId1 = Sketcher::start;
else
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2);
if (GeoId1 == -1 && PosId1 == Sketcher::none) // reject horizontal axis from selection
GeoId1 = Constraint::GeoUndef;
else if (GeoId1 == -2 && PosId1 == Sketcher::none) {
GeoId1 = -1;
PosId1 = Sketcher::start;
}
if (isVertex(GeoId1,PosId1) && isVertex(GeoId2,PosId2)) { // point to point horizontal distance
Base::Vector3d pnt1 = Obj->getPoint(GeoId1,PosId1);
Base::Vector3d pnt2 = Obj->getPoint(GeoId2,PosId2);
double ActLength = pnt2.x-pnt1.x;
@ -867,12 +869,12 @@ void CmdSketcherConstrainDistanceX::activated(int iMsg)
getSelection().clearSelection();
return;
}
else if (GeoId1 != Constraint::GeoUndef &&
GeoId2 == Constraint::GeoUndef && VtId2 < 0) { // horizontal length of a line
else if (isEdge(GeoId1,PosId1) && GeoId2 == Constraint::GeoUndef) { // 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!"));
GeoId1 < -2 ? QObject::tr("Cannot add a horizontal length constraint on an external geometry!")
: QObject::tr("Cannot add a horizontal length constraint on an axis!"));
return;
}
@ -899,9 +901,15 @@ void CmdSketcherConstrainDistanceX::activated(int iMsg)
return;
}
}
else if (VtId1 >= 0) { // point on fixed x-coordinate
Sketcher::PointPos PosId1;
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
else if (isVertex(GeoId1,PosId1) && GeoId2 == Constraint::GeoUndef) { // point on fixed x-coordinate
if (GeoId1 < 0) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
GeoId1 < -2 ? QObject::tr("Cannot add a fixed x-cootdinate constraint on an external geometry!")
: QObject::tr("Cannot add a fixed x-cootdinate constraint on the root point!"));
return;
}
Base::Vector3d pnt = Obj->getPoint(GeoId1,PosId1);
double ActX = pnt.x;
@ -971,32 +979,26 @@ void CmdSketcherConstrainDistanceY::activated(int iMsg)
return;
}
int GeoId1=Constraint::GeoUndef, VtId1=-1, GeoId2=Constraint::GeoUndef, VtId2=-1;
if (SubNames.size() >= 1) {
getIdsFromName(SubNames[0], GeoId1, VtId1);
if (GeoId1 == -2) // reject vertical axis from selection
GeoId1 = Constraint::GeoUndef;
if (SubNames.size() == 2) {
getIdsFromName(SubNames[1], GeoId2, VtId2);
if (GeoId2 == -2) // reject vertical axis from selection
GeoId2 = Constraint::GeoUndef;
}
}
int GeoId1, GeoId2=Constraint::GeoUndef;
Sketcher::PointPos PosId1, PosId2=Sketcher::none;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
else if (GeoId2 == -1 && GeoId1 == Constraint::GeoUndef) {
else if (GeoId2 == -1 || GeoId2 == -2) {
std::swap(GeoId1,GeoId2);
std::swap(VtId1,VtId2);
std::swap(PosId1,PosId2);
}
if ((GeoId1 == -1 || VtId1 >= 0) && VtId2 >= 0) { // point to point horizontal distance
Sketcher::PointPos PosId1,PosId2;
if (GeoId1 == -1)
PosId1 = Sketcher::start;
else
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2);
if (GeoId1 == -2 && PosId1 == Sketcher::none) // reject vertical axis from selection
GeoId1 = Constraint::GeoUndef;
else if (GeoId1 == -1 && PosId1 == Sketcher::none)
PosId1 = Sketcher::start;
if (isVertex(GeoId1,PosId1) && isVertex(GeoId2,PosId2)) { // point to point vertical distance
Base::Vector3d pnt1 = Obj->getPoint(GeoId1,PosId1);
Base::Vector3d pnt2 = Obj->getPoint(GeoId2,PosId2);
double ActLength = pnt2.y-pnt1.y;
@ -1017,12 +1019,12 @@ void CmdSketcherConstrainDistanceY::activated(int iMsg)
getSelection().clearSelection();
return;
}
else if (GeoId1 != Constraint::GeoUndef &&
GeoId2 == Constraint::GeoUndef && VtId2 < 0) { // vertical length of a line
else if (isEdge(GeoId1,PosId1) && GeoId2 == Constraint::GeoUndef) { // 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!"));
GeoId1 < -2 ? QObject::tr("Cannot add a vertical length constraint on an external geometry!")
: QObject::tr("Cannot add a vertical length constraint on an axis!"));
return;
}
@ -1049,9 +1051,15 @@ void CmdSketcherConstrainDistanceY::activated(int iMsg)
return;
}
}
else if (VtId1 >= 0) { // point on fixed y-coordinate
Sketcher::PointPos PosId1;
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
else if (isVertex(GeoId1,PosId1) && GeoId2 == Constraint::GeoUndef) { // point on fixed y-coordinate
if (GeoId1 < 0) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
GeoId1 < -2 ? QObject::tr("Cannot add a fixed y-cootdinate constraint on an external geometry!")
: QObject::tr("Cannot add a fixed y-cootdinate constraint on the root point!"));
return;
}
Base::Vector3d pnt = Obj->getPoint(GeoId1,PosId1);
double ActY = pnt.y;
@ -1126,10 +1134,12 @@ void CmdSketcherConstrainParallel::activated(int iMsg)
std::vector<int> ids;
bool hasAlreadyExternal=false;
for (std::vector<std::string>::const_iterator it=SubNames.begin();it!=SubNames.end();++it) {
int GeoId, VtId;
getIdsFromName(*it, GeoId, VtId);
if (GeoId == Constraint::GeoUndef) {
int GeoId;
Sketcher::PointPos PosId;
getIdsFromName(*it, Obj, GeoId, PosId);
if (!isEdge(GeoId,PosId)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select a valid line"));
return;
@ -1212,17 +1222,22 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
return;
}
int GeoId1, VtId1, GeoId2, VtId2;
getIdsFromName(SubNames[0], GeoId1, VtId1);
getIdsFromName(SubNames[1], GeoId2, VtId2);
int GeoId1, GeoId2;
Sketcher::PointPos PosId1, PosId2;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
Sketcher::PointPos PosId1,PosId2;
if (VtId1 >= 0 && VtId2 >= 0) { // perpendicularity at common point
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
if (checkBothExternal(GeoId1, GeoId2))
if (isVertex(GeoId1,PosId1) && isVertex(GeoId2,PosId2)) { // perpendicularity at common point
if (isSimpleVertex(Obj, GeoId1, PosId1) ||
isSimpleVertex(Obj, GeoId2, PosId2)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a perpendicularity constraint at an unconnected point!"));
return;
}
const Part::Geometry *geo1 = Obj->getGeometry(GeoId1);
const Part::Geometry *geo2 = Obj->getGeometry(GeoId2);
@ -1247,18 +1262,18 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
getSelection().clearSelection();
return;
}
else if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) ||
(VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) { // VtId1 is a connecting point
if (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef) {
VtId1 = VtId2;
VtId2 = -1;
GeoId2 = GeoId1;
GeoId1 = -1;
else if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) ||
(isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // connecting point
if (isVertex(GeoId2,PosId2)) {
std::swap(GeoId1,GeoId2);
std::swap(PosId1,PosId2);
}
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
if (checkBothExternal(GeoId1, GeoId2))
if (isSimpleVertex(Obj, GeoId1, PosId1)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a perpendicularity constraint at an unconnected point!"));
return;
}
const Part::Geometry *geo1 = Obj->getGeometry(GeoId1);
const Part::Geometry *geo2 = Obj->getGeometry(GeoId2);
@ -1286,10 +1301,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
getSelection().clearSelection();
return;
}
else if (GeoId1 != Constraint::GeoUndef && GeoId2 != Constraint::GeoUndef) { // simple perpendicularity between GeoId1 and GeoId2
if (checkBothExternal(GeoId1, GeoId2))
return;
else if (isEdge(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) { // simple perpendicularity between GeoId1 and GeoId2
const Part::Geometry *geo1 = Obj->getGeometry(GeoId1);
const Part::Geometry *geo2 = Obj->getGeometry(GeoId2);
@ -1358,17 +1370,22 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
return;
}
int GeoId1, VtId1, GeoId2, VtId2;
getIdsFromName(SubNames[0], GeoId1, VtId1);
getIdsFromName(SubNames[1], GeoId2, VtId2);
int GeoId1, GeoId2;
Sketcher::PointPos PosId1, PosId2;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
Sketcher::PointPos PosId1,PosId2;
if (VtId1 >= 0 && VtId2 >= 0) { // tangency at common point
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
if (checkBothExternal(GeoId1, GeoId2))
if (isVertex(GeoId1,PosId1) && isVertex(GeoId2,PosId2)) { // tangency at common point
if (isSimpleVertex(Obj, GeoId1, PosId1) ||
isSimpleVertex(Obj, GeoId2, PosId2)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a tangency constraint at an unconnected point!"));
return;
}
openCommand("add tangent constraint");
Gui::Command::doCommand(
@ -1379,18 +1396,18 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
getSelection().clearSelection();
return;
}
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;
else if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) ||
(isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // tangency point
if (isVertex(GeoId2,PosId2)) {
std::swap(GeoId1,GeoId2);
std::swap(PosId1,PosId2);
}
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
if (checkBothExternal(GeoId1, GeoId2))
if (isSimpleVertex(Obj, GeoId1, PosId1)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a tangency constraint at an unconnected point!"));
return;
}
openCommand("add tangent constraint");
Gui::Command::doCommand(
@ -1401,10 +1418,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
getSelection().clearSelection();
return;
}
else if (GeoId1 != Constraint::GeoUndef && GeoId2 != Constraint::GeoUndef) { // simple tangency between GeoId1 and GeoId2
if (checkBothExternal(GeoId1, GeoId2))
return;
else if (isEdge(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) { // simple tangency between GeoId1 and GeoId2
openCommand("add tangent constraint");
Gui::Command::doCommand(
@ -1545,19 +1559,21 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
return;
}
int GeoId1, VtId1, GeoId2=Constraint::GeoUndef, VtId2=-1;
getIdsFromName(SubNames[0], GeoId1, VtId1);
int GeoId1, GeoId2=Constraint::GeoUndef;
Sketcher::PointPos PosId1, PosId2=Sketcher::none;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
if (SubNames.size() == 2)
getIdsFromName(SubNames[1], GeoId2, VtId2);
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
if (checkBothExternal(GeoId1, GeoId2))
return;
else if (GeoId1 == Constraint::GeoUndef && GeoId2 != Constraint::GeoUndef) {
else if (isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) {
std::swap(GeoId1,GeoId2);
std::swap(VtId1,VtId2);
std::swap(PosId1,PosId2);
}
if (GeoId2 != Constraint::GeoUndef) { // line to line angle
if (isEdge(GeoId2,PosId2)) { // line to line angle
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
@ -1612,10 +1628,11 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
getSelection().clearSelection();
return;
}
} else if (GeoId1 != Constraint::GeoUndef) { // line angle
} else if (isEdge(GeoId1,PosId1)) { // line angle
if (GeoId1 < 0) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add an angle constraint on an external geometry!"));
GeoId1 < -2 ? QObject::tr("Cannot add an angle constraint on an external geometry!")
: QObject::tr("Cannot add an angle constraint on an axis!"));
return;
}
@ -1700,10 +1717,11 @@ void CmdSketcherConstrainEqual::activated(int iMsg)
for (std::vector<std::string>::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
int GeoId, VtId;
getIdsFromName(*it, GeoId, VtId);
int GeoId;
Sketcher::PointPos PosId;
getIdsFromName(*it, Obj, GeoId, PosId);
if (GeoId == Constraint::GeoUndef) {
if (isVertex(GeoId,PosId)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select two or more compatible edges"));
return;
@ -1802,38 +1820,60 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg)
return;
}
int GeoId1, VtId1, GeoId2, VtId2, GeoId3, VtId3;
getIdsFromName(SubNames[0], GeoId1, VtId1);
getIdsFromName(SubNames[1], GeoId2, VtId2);
getIdsFromName(SubNames[2], GeoId3, VtId3);
int GeoId1, GeoId2, GeoId3;
Sketcher::PointPos PosId1, PosId2, PosId3;
getIdsFromName(SubNames[0], Obj, GeoId1, PosId1);
getIdsFromName(SubNames[1], Obj, GeoId2, PosId2);
getIdsFromName(SubNames[2], Obj, GeoId3, PosId3);
if (GeoId1 != Constraint::GeoUndef && GeoId3 == Constraint::GeoUndef) {
if (isEdge(GeoId1,PosId1) && isVertex(GeoId3,PosId3)) {
std::swap(GeoId1,GeoId3);
std::swap(VtId1,VtId3);
std::swap(PosId1,PosId3);
}
else if (GeoId2 != Constraint::GeoUndef && GeoId3 == Constraint::GeoUndef) {
else if (isEdge(GeoId2,PosId2) && isVertex(GeoId3,PosId3)) {
std::swap(GeoId2,GeoId3);
std::swap(VtId2,VtId3);
std::swap(PosId2,PosId3);
}
if (VtId1 >= 0 && VtId2 >= 0 && GeoId3 != Constraint::GeoUndef) {
Sketcher::PointPos PosId1,PosId2;
Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1);
Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2);
if ((GeoId1 < 0 && GeoId2 < 0 && GeoId3 < 0)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a constraint between external geometries!"));
return;
}
if ((GeoId1 < 0 && GeoId2 < 0) || (GeoId1 < 0 && GeoId3 < 0) || (GeoId2 < 0 && GeoId3 < 0)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a constraint between external geometries!"));
return;
if (isVertex(GeoId1,PosId1) &&
isVertex(GeoId2,PosId2)) {
if (isEdge(GeoId3,PosId3)) {
const Part::Geometry *geom = Obj->getGeometry(GeoId3);
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
if (GeoId1 == GeoId2 && GeoId2 == GeoId3) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a symmetry constraint between a line and its end points!"));
return;
}
// undo command open
openCommand("add symmetric constraint");
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d)) ",
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,GeoId3);
// finish the transaction and update
commitCommand();
updateActive();
// clear the selection (convenience)
getSelection().clearSelection();
return;
}
}
const Part::Geometry *geom = Obj->getGeometry(GeoId3);
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
else if (isVertex(GeoId3,PosId3)) {
// undo command open
openCommand("add symmetric constraint");
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d)) ",
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,GeoId3);
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d,%d)) ",
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,GeoId3,PosId3);
// finish the transaction and update
commitCommand();

View File

@ -1444,6 +1444,7 @@ public:
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr);
return;
}
applyCursor();
}

View File

@ -141,31 +141,42 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
// Get Preselection
int preSelPnt = sketchgui->getPreselectPoint();
int preSelCrv = sketchgui->getPreselectCurve();
int preSelCrs = sketchgui->getPreselectCross();
int GeoId = Constraint::GeoUndef;
Sketcher::PointPos PosId = Sketcher::none;
if (preSelPnt != -1)
sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId);
else if (preSelCrv != -1)
GeoId = preSelCrv;
else if (preSelCrs == 0) { // root point
GeoId = -1;
PosId = Sketcher::start;
}
else if (preSelCrs == 1) // x axis
GeoId = -1;
else if (preSelCrs == 2) // y axis
GeoId = -2;
// Currently only considers objects in current Sketcher
AutoConstraint constr;
constr.Type = Sketcher::None;
constr.GeoId = GeoId;
constr.PosId = PosId;
if (type == AutoConstraint::VERTEX && preSelPnt != -1)
constr.Type = Sketcher::Coincident;
else if (type == AutoConstraint::CURVE && preSelPnt != -1)
constr.Type = Sketcher::PointOnObject;
else if (type == AutoConstraint::VERTEX && preSelCrv != -1)
constr.Type = Sketcher::PointOnObject;
else if (type == AutoConstraint::CURVE && preSelCrv != -1)
constr.Type = Sketcher::Tangent;
if (GeoId != Constraint::GeoUndef) {
// Currently only considers objects in current Sketcher
AutoConstraint constr;
constr.Type = Sketcher::None;
constr.GeoId = GeoId;
constr.PosId = PosId;
if (type == AutoConstraint::VERTEX && PosId != Sketcher::none)
constr.Type = Sketcher::Coincident;
else if (type == AutoConstraint::CURVE && PosId != Sketcher::none)
constr.Type = Sketcher::PointOnObject;
else if (type == AutoConstraint::VERTEX && PosId == Sketcher::none)
constr.Type = Sketcher::PointOnObject;
else if (type == AutoConstraint::CURVE && PosId == Sketcher::none)
constr.Type = Sketcher::Tangent;
if (constr.Type != Sketcher::None)
suggestedConstraints.push_back(constr);
if (constr.Type != Sketcher::None)
suggestedConstraints.push_back(constr);
}
if (Dir.Length() < 1)
if (Dir.Length() < 1e-8)
// Direction not set so return;
return suggestedConstraints.size();
@ -175,6 +186,7 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
const double angleDev = 2;
const double angleDevRad = angleDev * M_PI / 180.;
AutoConstraint constr;
constr.Type = Sketcher::None;
constr.GeoId = Constraint::GeoUndef;
constr.PosId = Sketcher::none;

View File

@ -107,8 +107,8 @@ SbColor ViewProviderSketch::VertexColor (1.0f,0.149f,0.0f); // #FF26
SbColor ViewProviderSketch::CurveColor (1.0f,1.0f,1.0f); // #FFFFFF -> (255,255,255)
SbColor ViewProviderSketch::CurveDraftColor (0.0f,0.0f,0.86f); // #0000DC -> ( 0, 0,220)
SbColor ViewProviderSketch::CurveExternalColor (0.8f,0.2f,0.6f); // #CC3399 -> (204, 51,153)
SbColor ViewProviderSketch::CrossColorV (0.8f,0.4f,0.4f); // #CC6666 -> (204,102,102)
SbColor ViewProviderSketch::CrossColorH (0.4f,0.8f,0.4f); // #66CC66 -> (102,204,102)
SbColor ViewProviderSketch::CrossColorH (0.8f,0.4f,0.4f); // #CC6666 -> (204,102,102)
SbColor ViewProviderSketch::CrossColorV (0.4f,0.8f,0.4f); // #66CC66 -> (102,204,102)
SbColor ViewProviderSketch::FullyConstrainedColor (0.0f,1.0f,0.0f); // #00FF00 -> ( 0,255, 0)
SbColor ViewProviderSketch::ConstrDimColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
SbColor ViewProviderSketch::ConstrIcoColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
@ -1294,6 +1294,9 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI
if (point_detail && point_detail->getTypeId() == SoPointDetail::getClassTypeId()) {
// get the index
PtIndex = static_cast<const SoPointDetail *>(point_detail)->getCoordinateIndex();
PtIndex -= 1; // shift corresponding to RootPoint
if (PtIndex == -1)
CrossIndex = 0; // RootPoint was hit
}
} else {
// checking for a hit in the curves
@ -1382,7 +1385,10 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtI
,Point->getPoint()[2]);
edit->blockedPreselection = !accepted;
if (accepted) {
resetPreselectPoint();
if (CrossIndex == 0)
setPreselectPoint(-1);
else
resetPreselectPoint();
edit->PreselectCurve = -1;
edit->PreselectCross = CrossIndex;
edit->PreselectConstraint = -1;
@ -1661,16 +1667,21 @@ void ViewProviderSketch::updateColor(void)
SbColor *crosscolor = edit->RootCrossMaterials->diffuseColor.startEditing();
// colors of the point set
for (int i=0; i < PtNum; i++) {
if (edit->SelPointSet.find(i) != edit->SelPointSet.end())
pcolor[i] = SelectColor;
else if (edit->PreselectPoint == i)
pcolor[i] = PreselectColor;
else if (edit->FullyConstrained)
if (edit->FullyConstrained)
for (int i=0; i < PtNum; i++)
pcolor[i] = FullyConstrainedColor;
else
else
for (int i=0; i < PtNum; i++)
pcolor[i] = VertexColor;
}
if (edit->PreselectCross == 0)
pcolor[0] = PreselectColor;
else if (edit->PreselectPoint != -1)
pcolor[edit->PreselectPoint + 1] = PreselectColor;
for (std::set<int>::iterator it=edit->SelPointSet.begin();
it != edit->SelPointSet.end(); it++)
pcolor[*it] = SelectColor;
// colors of the curves
int intGeoCount = getSketchObject()->getHighestCurveIndex() + 1;
@ -1933,6 +1944,10 @@ void ViewProviderSketch::draw(bool temp)
edit->CurvIdToGeoId.clear();
int GeoId = 0;
// RootPoint
Points.push_back(Base::Vector3d(0.,0.,0.));
for (std::vector<Part::Geometry *>::const_iterator it = geomlist->begin(); it != geomlist->end()-2; ++it, GeoId++) {
if (GeoId >= intGeoCount)
GeoId = -extGeoCount;
@ -3182,17 +3197,23 @@ void ViewProviderSketch::resetPositionText(void)
void ViewProviderSketch::setPreselectPoint(int PreselectPoint)
{
if (edit) {
int oldPtId = -1;
if (edit->PreselectPoint != -1)
oldPtId = edit->PreselectPoint + 1;
else if (edit->PreselectCross == 0)
oldPtId = 0;
int newPtId = PreselectPoint + 1;
SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
float x,y,z;
if (edit->PreselectPoint != -1 &&
edit->SelPointSet.find(edit->PreselectPoint) == edit->SelPointSet.end()) {
if (oldPtId != -1 &&
edit->SelPointSet.find(oldPtId) == edit->SelPointSet.end()) {
// send to background
pverts[edit->PreselectPoint].getValue(x,y,z);
pverts[edit->PreselectPoint].setValue(x,y,zPoints);
pverts[oldPtId].getValue(x,y,z);
pverts[oldPtId].setValue(x,y,zPoints);
}
// bring to foreground
pverts[PreselectPoint].getValue(x,y,z);
pverts[PreselectPoint].setValue(x,y,zHighlight);
pverts[newPtId].getValue(x,y,z);
pverts[newPtId].setValue(x,y,zHighlight);
edit->PreselectPoint = PreselectPoint;
edit->PointsCoordinate->point.finishEditing();
}
@ -3201,13 +3222,18 @@ void ViewProviderSketch::setPreselectPoint(int PreselectPoint)
void ViewProviderSketch::resetPreselectPoint(void)
{
if (edit) {
if (edit->PreselectPoint != -1 &&
edit->SelPointSet.find(edit->PreselectPoint) == edit->SelPointSet.end()) {
int oldPtId = -1;
if (edit->PreselectPoint != -1)
oldPtId = edit->PreselectPoint + 1;
else if (edit->PreselectCross == 0)
oldPtId = 0;
if (oldPtId != -1 &&
edit->SelPointSet.find(oldPtId) == edit->SelPointSet.end()) {
// send to background
SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
float x,y,z;
pverts[edit->PreselectPoint].getValue(x,y,z);
pverts[edit->PreselectPoint].setValue(x,y,zPoints);
pverts[oldPtId].getValue(x,y,z);
pverts[oldPtId].setValue(x,y,zPoints);
edit->PointsCoordinate->point.finishEditing();
}
edit->PreselectPoint = -1;
@ -3217,12 +3243,13 @@ void ViewProviderSketch::resetPreselectPoint(void)
void ViewProviderSketch::addSelectPoint(int SelectPoint)
{
if (edit) {
int PtId = SelectPoint + 1;
SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
// bring to foreground
float x,y,z;
pverts[SelectPoint].getValue(x,y,z);
pverts[SelectPoint].setValue(x,y,zHighlight);
edit->SelPointSet.insert(SelectPoint);
pverts[PtId].getValue(x,y,z);
pverts[PtId].setValue(x,y,zHighlight);
edit->SelPointSet.insert(PtId);
edit->PointsCoordinate->point.finishEditing();
}
}
@ -3230,12 +3257,13 @@ void ViewProviderSketch::addSelectPoint(int SelectPoint)
void ViewProviderSketch::removeSelectPoint(int SelectPoint)
{
if (edit) {
int PtId = SelectPoint + 1;
SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
// send to background
float x,y,z;
pverts[SelectPoint].getValue(x,y,z);
pverts[SelectPoint].setValue(x,y,zPoints);
edit->SelPointSet.erase(SelectPoint);
pverts[PtId].getValue(x,y,z);
pverts[PtId].setValue(x,y,zPoints);
edit->SelPointSet.erase(PtId);
edit->PointsCoordinate->point.finishEditing();
}
}
@ -3270,6 +3298,13 @@ int ViewProviderSketch::getPreselectCurve(void) const
return -1;
}
int ViewProviderSketch::getPreselectCross(void) const
{
if (edit)
return edit->PreselectCross;
return -1;
}
int ViewProviderSketch::getPreselectConstraint(void) const
{
if (edit)

View File

@ -164,6 +164,7 @@ public:
float getScaleFactor();
int getPreselectPoint(void) const;
int getPreselectCurve(void) const;
int getPreselectCross(void) const;
int getPreselectConstraint(void) const;
//@}

View File

@ -66,29 +66,33 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Separator"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
<< "Sketcher_ToggleConstruction"
/*<< "Sketcher_CreateText"*/
/*<< "Sketcher_CreateDraftLine"*/;
Gui::MenuItem* cons = new Gui::MenuItem();
cons->setCommand("Sketcher constraints");
*cons << "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainCoincident"
*cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainAngle"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric";
<< "Sketcher_ConstrainSymmetric"
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainAngle";
*sketch
<< "Sketcher_NewSketch"
<< "Sketcher_LeaveSketch"
@ -96,7 +100,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Sketcher_MapSketch"
<< geom
<< cons
<< "Separator"
;
return root;
@ -110,14 +113,15 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
part->setCommand("Sketcher");
*part << "Sketcher_NewSketch"<< "Sketcher_LeaveSketch";
part = new Gui::ToolBarItem(root);
part->setCommand("Sketcher geometries");
*part << "Sketcher_CreatePoint"
Gui::ToolBarItem* geom = new Gui::ToolBarItem(root);
geom->setCommand("Sketcher geometries");
*geom << "Sketcher_CreatePoint"
<< "Sketcher_CreateArc"
<< "Sketcher_CreateCircle"
<< "Sketcher_CreateLine"
<< "Sketcher_CreatePolyline"
<< "Sketcher_CreateRectangle"
<< "Separator"
<< "Sketcher_CreateFillet"
<< "Sketcher_Trimming"
<< "Sketcher_External"
@ -125,23 +129,24 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
/*<< "Sketcher_CreateText"*/
/*<< "Sketcher_CreateDraftLine"*/;
part = new Gui::ToolBarItem(root);
part->setCommand("Sketcher constraints");
*part << "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainCoincident"
Gui::ToolBarItem* cons = new Gui::ToolBarItem(root);
cons->setCommand("Sketcher constraints");
*cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainAngle"
<< "Sketcher_ConstrainTangent"
<< "Sketcher_ConstrainEqual"
<< "Sketcher_ConstrainSymmetric";
<< "Sketcher_ConstrainSymmetric"
<< "Separator"
<< "Sketcher_ConstrainLock"
<< "Sketcher_ConstrainDistanceX"
<< "Sketcher_ConstrainDistanceY"
<< "Sketcher_ConstrainDistance"
<< "Sketcher_ConstrainRadius"
<< "Sketcher_ConstrainAngle";
return root;
}