Merge branch 'master' of ssh://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad into sanguinariojoe-ship

This commit is contained in:
Jose Luis Cercós pita 2012-06-09 17:38:14 +02:00
commit 8f8cac1734
61 changed files with 2814 additions and 207 deletions

BIN
data/tests/PadTest.fcstd Normal file

Binary file not shown.

BIN
data/tests/PocketTest.fcstd Normal file

Binary file not shown.

View File

@ -394,9 +394,6 @@ protected:
const Constraints* _ConstStruct;
};
class AppExport PropertyFloatList: public PropertyLists
{
TYPESYSTEM_HEADER();
@ -470,10 +467,11 @@ public:
*/
virtual ~PropertyString();
void setValue(const char* sString);
void setValue(const std::string &sString);
const char* getValue(void) const;
const std::string& getStrValue(void) const
{ return _cValue; }
bool isEmpty(void){return _cValue.empty();}
virtual const char* getEditorName(void) const { return "Gui::PropertyEditor::PropertyStringItem"; }

View File

@ -85,6 +85,7 @@ UnitsSchema *UnitsApi::UserPrefSystem = new UnitsSchemaInternal();
double UnitsApi::UserPrefFactor [50];
QString UnitsApi::UserPrefUnit [50];
int UnitsApi::UserPrefDecimals = 2;
UnitsApi::UnitsApi(const char* filter)
{
@ -196,6 +197,16 @@ const double UnitsApi::getPrefFactorOf(QuantityType t)
return UserPrefFactor[t];
}
void UnitsApi::setDecimals(int prec)
{
UserPrefDecimals = prec;
}
int UnitsApi::getDecimals()
{
return UserPrefDecimals;
}
void UnitsApi::setDefaults(void)
{
setPrefOf( Length ,"mm" );

View File

@ -101,6 +101,10 @@ public:
static const QString getQuantityName(QuantityType t);
/// get the translation factor for the default unit of a quantity
static const double getPrefFactorOf(QuantityType t);
// set the number of decimals
static void setDecimals(int);
// fet the number of decimals
static int getDecimals();
/// set the application defaults
static void setDefaults(void);
//@}
@ -119,6 +123,8 @@ protected:
static double UserPrefFactor [50] ;
/// name of the unit the user wants to use as quantities
static QString UserPrefUnit [50] ;
/// number of decimals for floats
static int UserPrefDecimals;
// do the real work
static double parse(const char*,bool &UsedUnit);

View File

@ -52,6 +52,7 @@
#include <Base/Factory.h>
#include <Base/FileInfo.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <App/Document.h>
#include <App/DocumentObjectPy.h>
@ -328,6 +329,10 @@ Application::Application(bool GUIenabled)
Translator::instance()->activateLanguage(hPGrp->GetASCII("Language", (const char*)lang.toAscii()).c_str());
GetWidgetFactorySupplier();
ParameterGrp::handle hUnits = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Units");
Base::UnitsApi::setDecimals(hUnits->GetInt("Decimals", Base::UnitsApi::getDecimals()));
// setting up Python binding
Base::PyGILStateLocker lock;
PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods,

View File

@ -55,11 +55,11 @@ public:
/// are there any SubNames selected
bool hasSubNames(void)const { return SubNames.size() != 0; }
/// get the name of the Document of this SelctionObject
inline const char* getDocName(void) { return DocName.c_str(); }
inline const char* getDocName(void) const { return DocName.c_str(); }
/// get the name of the Document Object of this SelectionObject
inline const char* getFeatName(void) { return FeatName.c_str(); }
inline const char* getFeatName(void) const { return FeatName.c_str(); }
/// get the Type of the selcted Object
inline const char* getTypeName(void) { return TypeName.c_str(); }
inline const char* getTypeName(void) const { return TypeName.c_str(); }
/// returns the selected DocumentObject or NULL if the object is already deleted
const App::DocumentObject *getObject(void) const;

View File

@ -57,6 +57,7 @@ TYPESYSTEM_SOURCE(Gui::PropertyEditor::PropertyItem, Base::BaseClass);
PropertyItem::PropertyItem() : parentItem(0), readonly(false)
{
precision = Base::UnitsApi::getDecimals();
}
PropertyItem::~PropertyItem()
@ -130,6 +131,16 @@ bool PropertyItem::isReadOnly() const
return readonly;
}
void PropertyItem::setDecimals(int prec)
{
precision = prec;
}
int PropertyItem::decimals() const
{
return precision;
}
QVariant PropertyItem::toolTip(const App::Property* prop) const
{
return QVariant(QString::fromUtf8(prop->getDocumentation()));
@ -574,7 +585,7 @@ void PropertyFloatItem::setValue(const QVariant& value)
if (!value.canConvert(QVariant::Double))
return;
double val = value.toDouble();
QString data = QString::fromAscii("%1").arg(val,0,'f',2);
QString data = QString::fromAscii("%1").arg(val,0,'f',decimals());
setPropertyValue(data);
}
@ -582,6 +593,7 @@ QWidget* PropertyFloatItem::createEditor(QWidget* parent, const QObject* receive
{
QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
sb->setFrame(false);
sb->setDecimals(decimals());
QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method);
return sb;
}
@ -703,13 +715,14 @@ void PropertyFloatConstraintItem::setValue(const QVariant& value)
if (!value.canConvert(QVariant::Double))
return;
double val = value.toDouble();
QString data = QString::fromAscii("%1").arg(val,0,'f',2);
QString data = QString::fromAscii("%1").arg(val,0,'f',decimals());
setPropertyValue(data);
}
QWidget* PropertyFloatConstraintItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const
{
QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
sb->setDecimals(decimals());
sb->setFrame(false);
QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method);
return sb;
@ -873,9 +886,9 @@ void PropertyVectorItem::setValue(const QVariant& value)
return;
const Base::Vector3f& val = value.value<Base::Vector3f>();
QString data = QString::fromAscii("(%1, %2, %3)")
.arg(val.x,0,'f',2)
.arg(val.y,0,'f',2)
.arg(val.z,0,'f',2);
.arg(val.x,0,'f',decimals())
.arg(val.y,0,'f',decimals())
.arg(val.z,0,'f',decimals());
setPropertyValue(data);
}
@ -976,9 +989,9 @@ void PropertyDoubleVectorItem::setValue(const QVariant& value)
return;
const Base::Vector3d& val = value.value<Base::Vector3d>();
QString data = QString::fromAscii("(%1, %2, %3)")
.arg(val.x,0,'f',2)
.arg(val.y,0,'f',2)
.arg(val.z,0,'f',2);
.arg(val.x,0,'f',decimals())
.arg(val.y,0,'f',decimals())
.arg(val.z,0,'f',decimals());
setPropertyValue(data);
}
@ -1503,9 +1516,9 @@ void PropertyColorItem::setValue(const QVariant& value)
val.g = (float)col.green()/255.0f;
val.b = (float)col.blue()/255.0f;
QString data = QString::fromAscii("(%1,%2,%3)")
.arg(val.r,0,'f',2)
.arg(val.g,0,'f',2)
.arg(val.b,0,'f',2);
.arg(val.r,0,'f',decimals())
.arg(val.g,0,'f',decimals())
.arg(val.b,0,'f',decimals());
setPropertyValue(data);
}

View File

@ -69,6 +69,8 @@ public:
void setReadOnly(bool);
bool isReadOnly() const;
void setDecimals(int);
int decimals() const;
PropertyItem *child(int row);
int childCount() const;
@ -99,6 +101,7 @@ private:
PropertyItem *parentItem;
QList<PropertyItem*> childItems;
bool readonly;
int precision;
};
/**

View File

@ -109,7 +109,8 @@ class _ViewProviderAxis:
vobj.LineColor = (0.13,0.15,0.37)
vobj.DrawStyle = "Dashdot"
def getIcon(self):
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Axis_Tree.svg"
def claimChildren(self):

View File

@ -86,6 +86,7 @@ class _ViewProviderBuilding(ArchFloor._ViewProviderFloor):
ArchFloor._ViewProviderFloor.__init__(self,vobj)
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Building_Tree.svg"
FreeCADGui.addCommand('Arch_Building',_CommandBuilding())

View File

@ -121,6 +121,7 @@ class _ViewProviderCell(ArchComponent.ViewProviderComponent):
self.Object = vobj.Object
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Cell_Tree.svg"
def updateData(self,obj,prop):

View File

@ -114,6 +114,7 @@ class _ViewProviderFloor:
vobj.Proxy = self
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Floor_Tree.svg"
def attach(self,vobj):

View File

@ -148,7 +148,8 @@ class _ViewProviderRoof(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
def getIcon(self):
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Roof_Tree.svg"
FreeCADGui.addCommand('Arch_Roof',_CommandRoof())

View File

@ -123,6 +123,7 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent):
self.Object = vobj.Object
def getIcon(self):
import Arch_rc
return ":/icons/Arch_SectionPlane_Tree.svg"
def claimChildren(self):

View File

@ -89,6 +89,7 @@ class _ViewProviderSite(ArchFloor._ViewProviderFloor):
ArchFloor._ViewProviderFloor.__init__(self,vobj)
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Site_Tree.svg"

View File

@ -193,7 +193,8 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
def getIcon(self):
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Structure_Tree.svg"
FreeCADGui.addCommand('Arch_Structure',_CommandStructure())

View File

@ -423,7 +423,8 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
def getIcon(self):
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Wall_Tree.svg"
def getDisplayModes(self,vobj):

View File

@ -179,7 +179,8 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
def getIcon(self):
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Window_Tree.svg"
def setEdit(self,vobj,mode):

View File

@ -179,6 +179,7 @@ void PartExport initPart()
Part::Part2DObjectPython ::init();
Part::RuledSurface ::init();
Part::Loft ::init();
Part::Sweep ::init();
// Geometry types
Part::Geometry ::init();

View File

@ -30,6 +30,10 @@
# include <TopTools_ListIteratorOfListOfShape.hxx>
# include <TopExp.hxx>
# include <TopTools_IndexedMapOfShape.hxx>
// includes for findAllFacesCutBy()
# include <TopoDS_Face.hxx>
# include <gp_Dir.hxx>
# include <gp_Pln.hxx> // for Precision::Confusion()
#endif
@ -139,22 +143,25 @@ ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_Sha
history.type = type;
TopTools_IndexedMapOfShape newM, oldM;
TopExp::MapShapes(newS, type, newM);
TopExp::MapShapes(oldS, type, oldM);
TopExp::MapShapes(newS, type, newM); // map containing all old objects of type "type"
TopExp::MapShapes(oldS, type, oldM); // map containing all new objects of type "type"
// Look at all objects in the old shape and try to find the modified object in the new shape
for (int i=1; i<=oldM.Extent(); i++) {
bool found = false;
TopTools_ListIteratorOfListOfShape it;
// Find all new objects that are a modification of the old object (e.g. a face was resized)
for (it.Initialize(mkShape.Modified(oldM(i))); it.More(); it.Next()) {
found = true;
for (int j=1; j<=newM.Extent(); j++) {
for (int j=1; j<=newM.Extent(); j++) { // one old object might create several new ones!
if (newM(j).IsPartner(it.Value())) {
history.shapeMap[i-1].push_back(j-1);
history.shapeMap[i-1].push_back(j-1); // adjust indices to start at zero
break;
}
}
}
// Find all new objects that were generated from an old object (e.g. a face generated from an edge)
for (it.Initialize(mkShape.Generated(oldM(i))); it.More(); it.Next()) {
found = true;
for (int j=1; j<=newM.Extent(); j++) {
@ -166,10 +173,12 @@ ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_Sha
}
if (!found) {
// Find all old objects that don't exist any more (e.g. a face was completely cut away)
if (mkShape.IsDeleted(oldM(i))) {
history.shapeMap[i-1] = std::vector<int>();
}
else {
// Mop up the rest (will this ever be reached?)
for (int j=1; j<=newM.Extent(); j++) {
if (newM(j).IsPartner(oldM(i))) {
history.shapeMap[i-1].push_back(j-1);
@ -204,6 +213,15 @@ ShapeHistory Feature::joinHistory(const ShapeHistory& oldH, const ShapeHistory&
return join;
}
const TopoDS_Shape Feature::findOriginOf(const TopoDS_Shape& reference) {
/* Base::Console().Error("Looking for origin of face in %s\n", this->getName());
if (reference.ShapeType() == TopAbs_FACE) {
// Find index of reference in the history
}
*/
return TopoDS_Shape();
}
/// returns the type name of the ViewProvider
const char* Feature::getViewProviderName(void) const {
return "PartGui::ViewProviderPart";
@ -253,3 +271,51 @@ template<> PyObject* Part::FeaturePython::getPyObject(void) {
template class PartExport FeaturePythonT<Part::Feature>;
}
// ----------------------------------------------------------------
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <gce_MakeLin.hxx>
#include <BRepIntCurveSurface_Inter.hxx>
#include <IntCurveSurface_IntersectionPoint.hxx>
#include <gce_MakeDir.hxx>
std::vector<Part::cutFaces> Part::findAllFacesCutBy(
const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir)
{
// Find the centre of gravity of the face
GProp_GProps props;
BRepGProp::SurfaceProperties(face,props);
gp_Pnt cog = props.CentreOfMass();
// create a line through the centre of gravity
gp_Lin line = gce_MakeLin(cog, dir);
// Find intersection of line with all faces of the shape
std::vector<cutFaces> result;
BRepIntCurveSurface_Inter mkSection;
// TODO: Less precision than Confusion() should be OK?
for (mkSection.Init(shape, line, Precision::Confusion()); mkSection.More(); mkSection.Next()) {
gp_Pnt iPnt = mkSection.Pnt();
double dsq = cog.SquareDistance(iPnt);
if (dsq < Precision::Confusion())
continue; // intersection with original face
// Find out which side of the original face the intersection is on
gce_MakeDir mkDir(cog, iPnt);
if (!mkDir.IsDone())
continue; // some error (appears highly unlikely to happen, though...)
if (mkDir.Value().IsOpposite(dir, Precision::Confusion()))
continue; // wrong side of face (opposite to extrusion direction)
cutFaces newF;
newF.face = mkSection.Face();
newF.distsq = dsq;
result.push_back(newF);
}
return result;
}

View File

@ -29,9 +29,16 @@
#include <App/GeoFeature.h>
#include <App/FeaturePython.h>
#include <App/PropertyGeo.h>
// includes for findAllFacesCutBy()
#include <TopoDS_Face.hxx>
class gp_Dir;
class BRepBuilderAPI_MakeShape;
// includes for findAllFacesCutBy()
#include <TopoDS_Face.hxx>
class gp_Dir;
namespace Part
{
@ -63,9 +70,22 @@ public:
virtual PyObject* getPyObject(void);
virtual std::vector<PyObject *> getPySubObjects(const std::vector<std::string>&) const;
/**
/* Find the origin of a reference, e.g. the vertex or edge in a sketch that
/* produced a face
*/
const TopoDS_Shape findOriginOf(const TopoDS_Shape& reference);
protected:
void onChanged(const App::Property* prop);
TopLoc_Location getLocation() const;
/**
/* Build a history of changes
/* MakeShape: The operation that created the changes, e.g. BRepAlgoAPI_Common
/* type: The type of object we are interested in, e.g. TopAbs_FACE
/* newS: The new shape that was created by the operation
/* oldS: The original shape prior to the operation
*/
ShapeHistory buildHistory(BRepBuilderAPI_MakeShape&, TopAbs_ShapeEnum type,
const TopoDS_Shape& newS, const TopoDS_Shape& oldS);
ShapeHistory joinHistory(const ShapeHistory&, const ShapeHistory&);
@ -99,6 +119,20 @@ public:
}
};
// Utility methods
/**
/* Find all faces cut by a line through the centre of gravity of a given face
/* Useful for the "up to face" options to pocket or pad
*/
struct cutFaces {
TopoDS_Face face;
double distsq;
};
PartExport
std::vector<cutFaces> findAllFacesCutBy(const TopoDS_Shape& shape,
const TopoDS_Shape& face, const gp_Dir& dir);
} //namespace Part

View File

@ -28,6 +28,8 @@
# include <TopoDS_Face.hxx>
# include <TopoDS_Shell.hxx>
# include <BRepBuilderAPI_MakeWire.hxx>
# include <BRepOffsetAPI_MakePipeShell.hxx>
# include <TopTools_ListIteratorOfListOfShape.hxx>
#endif
@ -196,3 +198,132 @@ App::DocumentObjectExecReturn *Loft::execute(void)
return new App::DocumentObjectExecReturn(e->GetMessageString());
}
}
// ----------------------------------------------------------------------------
const char* Part::Sweep::TransitionEnums[]= {"Transformed","Right corner", "Round corner",NULL};
PROPERTY_SOURCE(Part::Sweep, Part::Feature)
Sweep::Sweep()
{
ADD_PROPERTY_TYPE(Sections,(0),"Sweep",App::Prop_None,"List of sections");
Sections.setSize(0);
ADD_PROPERTY_TYPE(Spine,(0),"Sweep",App::Prop_None,"Path to sweep along");
ADD_PROPERTY_TYPE(Solid,(false),"Sweep",App::Prop_None,"Create solid");
ADD_PROPERTY_TYPE(Frenet,(false),"Sweep",App::Prop_None,"Frenet");
ADD_PROPERTY_TYPE(Transition,(long(0)),"Sweep",App::Prop_None,"Transition mode");
Transition.setEnums(TransitionEnums);
}
short Sweep::mustExecute() const
{
if (Sections.isTouched())
return 1;
if (Spine.isTouched())
return 1;
if (Solid.isTouched())
return 1;
if (Frenet.isTouched())
return 1;
if (Transition.isTouched())
return 1;
return 0;
}
void Sweep::onChanged(const App::Property* prop)
{
Part::Feature::onChanged(prop);
}
App::DocumentObjectExecReturn *Sweep::execute(void)
{
if (Sections.getSize() == 0)
return new App::DocumentObjectExecReturn("No sections linked.");
App::DocumentObject* spine = Spine.getValue();
if (!(spine && spine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
return new App::DocumentObjectExecReturn("No spine linked.");
const std::vector<std::string>& subedge = Spine.getSubValues();
if (subedge.size() != 1)
return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
TopoDS_Shape path;
const Part::TopoShape& shape = static_cast<Part::Feature*>(spine)->Shape.getValue();
if (!shape._Shape.IsNull()) {
if (!subedge[0].empty()) {
path = shape.getSubShape(subedge[0].c_str());
}
else {
if (shape._Shape.ShapeType() == TopAbs_EDGE)
path = shape._Shape;
else if (shape._Shape.ShapeType() == TopAbs_WIRE)
path = shape._Shape;
else
return new App::DocumentObjectExecReturn("Spine is neither an edge nor a wire.");
}
}
try {
TopTools_ListOfShape profiles;
const std::vector<App::DocumentObject*>& shapes = Sections.getValues();
std::vector<App::DocumentObject*>::const_iterator it;
for (it = shapes.begin(); it != shapes.end(); ++it) {
if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a shape.");
const TopoDS_Shape& shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Linked shape is invalid.");
if (shape.ShapeType() == TopAbs_WIRE) {
profiles.Append(shape);
}
else if (shape.ShapeType() == TopAbs_EDGE) {
BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(shape));
profiles.Append(mkWire.Wire());
}
else if (shape.ShapeType() == TopAbs_VERTEX) {
profiles.Append(shape);
}
else {
return new App::DocumentObjectExecReturn("Linked shape is not a vertex, edge nor wire.");
}
}
Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False;
Standard_Boolean isFrenet = Frenet.getValue() ? Standard_True : Standard_False;
BRepBuilderAPI_TransitionMode transMode;
switch (Transition.getValue()) {
case 1: transMode = BRepBuilderAPI_RightCorner;
break;
case 2: transMode = BRepBuilderAPI_RoundCorner;
break;
default: transMode = BRepBuilderAPI_Transformed;
break;
}
if (path.ShapeType() == TopAbs_EDGE) {
BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(path));
path = mkWire.Wire();
}
BRepOffsetAPI_MakePipeShell mkPipeShell(TopoDS::Wire(path));
mkPipeShell.SetMode(isFrenet);
mkPipeShell.SetTransitionMode(transMode);
TopTools_ListIteratorOfListOfShape iter;
for (iter.Initialize(profiles); iter.More(); iter.Next()) {
mkPipeShell.Add(TopoDS_Shape(iter.Value()));
}
if (!mkPipeShell.IsReady())
Standard_Failure::Raise("shape is not ready to build");
mkPipeShell.Build();
if (isSolid)
mkPipeShell.MakeSolid();
this->Shape.setValue(mkPipeShell.Shape());
return App::DocumentObject::StdReturn;
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
return new App::DocumentObjectExecReturn(e->GetMessageString());
}
}

View File

@ -73,6 +73,33 @@ protected:
void onChanged (const App::Property* prop);
};
class Sweep : public Part::Feature
{
PROPERTY_HEADER(Part::Sweep);
public:
Sweep();
App::PropertyLinkList Sections;
App::PropertyLinkSub Spine;
App::PropertyBool Solid;
App::PropertyBool Frenet;
App::PropertyEnumeration Transition;
/** @name methods override feature */
//@{
/// recalculate the feature
App::DocumentObjectExecReturn *execute(void);
short mustExecute() const;
//@}
protected:
void onChanged (const App::Property* prop);
private:
static const char* TransitionEnums[];
};
} //namespace Part

View File

@ -41,6 +41,7 @@ set(PartGui_MOC_HDRS
TaskFaceColors.h
TaskShapeBuilder.h
TaskLoft.h
TaskSweep.h
)
fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${PartGui_MOC_SRCS})
@ -65,6 +66,7 @@ set(PartGui_UIC_SRCS
TaskFaceColors.ui
TaskShapeBuilder.ui
TaskLoft.ui
TaskSweep.ui
)
qt4_wrap_ui(PartGui_UIC_HDRS ${PartGui_UIC_SRCS})
@ -155,6 +157,9 @@ SET(PartGui_SRCS
TaskLoft.cpp
TaskLoft.h
TaskLoft.ui
TaskSweep.cpp
TaskSweep.h
TaskSweep.ui
)
SET(PartGui_Scripts

View File

@ -61,6 +61,7 @@
#include "ViewProvider.h"
#include "TaskShapeBuilder.h"
#include "TaskLoft.h"
#include "TaskSweep.h"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@ -960,6 +961,31 @@ bool CmdPartLoft::isActive(void)
//--------------------------------------------------------------------------------------
DEF_STD_CMD_A(CmdPartSweep);
CmdPartSweep::CmdPartSweep()
: Command("Part_Sweep")
{
sAppModule = "Part";
sGroup = QT_TR_NOOP("Part");
sMenuText = QT_TR_NOOP("Sweep...");
sToolTipText = QT_TR_NOOP("Advanced utility to sweep");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
}
void CmdPartSweep::activated(int iMsg)
{
Gui::Control().showDialog(new PartGui::TaskSweep());
}
bool CmdPartSweep::isActive(void)
{
return (hasActiveDocument() && !Gui::Control().activeDialog());
}
//--------------------------------------------------------------------------------------
DEF_STD_CMD_A(CmdShapeInfo);
CmdShapeInfo::CmdShapeInfo()
@ -1194,5 +1220,6 @@ void CreatePartCommands(void)
rcCmdMgr.addCommand(new CmdPartRuledSurface());
rcCmdMgr.addCommand(new CmdPartBuilder());
rcCmdMgr.addCommand(new CmdPartLoft());
rcCmdMgr.addCommand(new CmdPartSweep());
}

View File

@ -0,0 +1,255 @@
/***************************************************************************
* Copyright (c) 2011 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 <QMessageBox>
# include <QTextStream>
#endif
#include "ui_TaskSweep.h"
#include "TaskSweep.h"
#include <Gui/Application.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/PartFeature.h>
using namespace PartGui;
class SweepWidget::Private
{
public:
Ui_TaskSweep ui;
std::string document;
Private()
{
}
~Private()
{
}
};
/* TRANSLATOR PartGui::SweepWidget */
SweepWidget::SweepWidget(QWidget* parent)
: d(new Private())
{
Gui::Application::Instance->runPythonCode("from FreeCAD import Base");
Gui::Application::Instance->runPythonCode("import Part");
d->ui.setupUi(this);
d->ui.selector->setAvailableLabel(tr("Vertex/Wire"));
d->ui.selector->setSelectedLabel(tr("Sweep"));
connect(d->ui.selector->availableTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
connect(d->ui.selector->selectedTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
findShapes();
}
SweepWidget::~SweepWidget()
{
delete d;
}
void SweepWidget::findShapes()
{
App::Document* activeDoc = App::GetApplication().getActiveDocument();
Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc);
if (!activeGui) return;
d->document = activeDoc->getName();
std::vector<Part::Feature*> objs = activeDoc->getObjectsOfType<Part::Feature>();
for (std::vector<Part::Feature*>::iterator it = objs.begin(); it!=objs.end(); ++it) {
const TopoDS_Shape& shape = (*it)->Shape.getValue();
if (shape.IsNull()) continue;
if (shape.ShapeType() == TopAbs_WIRE ||
shape.ShapeType() == TopAbs_EDGE ||
shape.ShapeType() == TopAbs_VERTEX) {
QString label = QString::fromUtf8((*it)->Label.getValue());
QString name = QString::fromAscii((*it)->getNameInDocument());
QTreeWidgetItem* child = new QTreeWidgetItem();
child->setText(0, label);
child->setToolTip(0, label);
child->setData(0, Qt::UserRole, name);
Gui::ViewProvider* vp = activeGui->getViewProvider(*it);
if (vp) child->setIcon(0, vp->getIcon());
d->ui.selector->availableTreeWidget()->addTopLevelItem(child);
}
}
}
bool SweepWidget::accept()
{
Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1");
Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 1");
bool matchEdge = edgeFilter.match();
bool matchPart = partFilter.match();
if (!matchEdge && !matchPart) {
QMessageBox::critical(this, tr("Sweep path"), tr("Select an edge or wire you want to sweep along."));
return false;
}
// get the selected object
std::string objectName, subShape;
if (matchEdge) {
const std::vector<Gui::SelectionObject>& result = edgeFilter.Result[0];
const std::vector<std::string>& edges = result[0].getSubNames();
objectName = result.front().getFeatName();
subShape = edges.front();
}
else {
const std::vector<Gui::SelectionObject>& result = partFilter.Result[0];
objectName = result.front().getFeatName();
}
QString list, solid, frenet;
if (d->ui.checkSolid->isChecked())
solid = QString::fromAscii("True");
else
solid = QString::fromAscii("False");
if (d->ui.checkFrenet->isChecked())
frenet = QString::fromAscii("True");
else
frenet = QString::fromAscii("False");
QTextStream str(&list);
int count = d->ui.selector->selectedTreeWidget()->topLevelItemCount();
if (count < 1) {
QMessageBox::critical(this, tr("Too few elements"), tr("At least one edge or wire is required."));
return false;
}
for (int i=0; i<count; i++) {
QTreeWidgetItem* child = d->ui.selector->selectedTreeWidget()->topLevelItem(i);
QString name = child->data(0, Qt::UserRole).toString();
str << "App.getDocument('" << d->document.c_str() << "')." << name << ", ";
}
try {
QString cmd;
cmd = QString::fromAscii(
"App.getDocument('%6').addObject('Part::Sweep','Sweep')\n"
"App.getDocument('%6').ActiveObject.Sections=[%1]\n"
"App.getDocument('%6').ActiveObject.Spine=(FreeCAD.ActiveDocument.%2,['%3'])\n"
"App.getDocument('%6').ActiveObject.Solid=%4\n"
"App.getDocument('%6').ActiveObject.Frenet=%5\n"
)
.arg(list).arg(QLatin1String(objectName.c_str()))
.arg(QLatin1String(subShape.c_str()))
.arg(solid).arg(frenet).arg(QString::fromAscii(d->document.c_str()));
Gui::Document* doc = Gui::Application::Instance->getDocument(d->document.c_str());
if (!doc) throw Base::Exception("Document doesn't exist anymore");
doc->openCommand("Sweep");
Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
doc->commitCommand();
doc->getDocument()->recompute();
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
return false;
}
return true;
}
bool SweepWidget::reject()
{
return true;
}
void SweepWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
{
if (previous) {
Gui::Selection().rmvSelection(d->document.c_str(),
(const char*)previous->data(0,Qt::UserRole).toByteArray());
}
if (current) {
Gui::Selection().addSelection(d->document.c_str(),
(const char*)current->data(0,Qt::UserRole).toByteArray());
}
}
void SweepWidget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
d->ui.retranslateUi(this);
d->ui.selector->setAvailableLabel(tr("Vertex/Wire"));
d->ui.selector->setSelectedLabel(tr("Sweep"));
}
}
/* TRANSLATOR PartGui::TaskSweep */
TaskSweep::TaskSweep()
{
widget = new SweepWidget();
taskbox = new Gui::TaskView::TaskBox(
QPixmap(), widget->windowTitle(), true, 0);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
}
TaskSweep::~TaskSweep()
{
}
void TaskSweep::open()
{
}
void TaskSweep::clicked(int)
{
}
bool TaskSweep::accept()
{
return widget->accept();
}
bool TaskSweep::reject()
{
return widget->reject();
}
#include "moc_TaskSweep.cpp"

View File

@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2011 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_TASKSWEEP_H
#define PARTGUI_TASKSWEEP_H
#include <Gui/TaskView/TaskView.h>
#include <Gui/TaskView/TaskDialog.h>
class QTreeWidgetItem;
namespace PartGui {
class SweepWidget : public QWidget
{
Q_OBJECT
public:
SweepWidget(QWidget* parent = 0);
~SweepWidget();
bool accept();
bool reject();
private Q_SLOTS:
void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*);
private:
void changeEvent(QEvent *e);
void findShapes();
private:
class Private;
Private* d;
};
class TaskSweep : public Gui::TaskView::TaskDialog
{
Q_OBJECT
public:
TaskSweep();
~TaskSweep();
public:
void open();
bool accept();
bool reject();
void clicked(int);
QDialogButtonBox::StandardButtons getStandardButtons() const
{ return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
private:
SweepWidget* widget;
Gui::TaskView::TaskBox* taskbox;
};
} //namespace PartGui
#endif // PARTGUI_TASKSWEEP_H

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PartGui::TaskSweep</class>
<widget class="QWidget" name="PartGui::TaskSweep">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>336</width>
<height>326</height>
</rect>
</property>
<property name="windowTitle">
<string>Sweep</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="3">
<widget class="Gui::ActionSelector" name="selector"/>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkSolid">
<property name="text">
<string>Create solid</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>130</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkFrenet">
<property name="text">
<string>Frenet</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Select one or more profiles and select an edge or wire
in the 3D view for the sweep path.</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::ActionSelector</class>
<extends>QWidget</extends>
<header>Gui/Widgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../Gui/Icons/resource.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -72,7 +72,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Part_RefineShape" << "Separator"
<< "Part_Boolean" << "Part_CrossSections" << "Part_Extrude"
<< "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer"
<< "Part_RuledSurface" << "Part_Loft"
<< "Part_RuledSurface" << "Part_Loft" << "Part_Sweep"
<< "Part_Builder";
//Gui::MenuItem* partSimple = new Gui::MenuItem;

View File

@ -34,6 +34,7 @@
#include "FeatureFillet.h"
#include "FeatureSketchBased.h"
#include "FeatureRevolution.h"
#include "FeatureGroove.h"
#include "Body.h"
#include "FeatureDressUp.h"
#include "FeatureChamfer.h"
@ -82,6 +83,7 @@ void PartDesignExport initPartDesign()
PartDesign::Pocket ::init();
PartDesign::Fillet ::init();
PartDesign::Revolution ::init();
PartDesign::Groove ::init();
PartDesign::Chamfer ::init();
PartDesign::Face ::init();
}

View File

@ -50,6 +50,8 @@ SET(FeaturesSketchBased_SRCS
FeaturePocket.h
FeatureRevolution.cpp
FeatureRevolution.h
FeatureGroove.cpp
FeatureGroove.h
FeatureAdditive.cpp
FeatureAdditive.h
FeatureSubtractive.h

View File

@ -0,0 +1,208 @@
/***************************************************************************
* Copyright (c) 2010 Juergen Riegel <FreeCAD@juergen-riegel.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 <BRep_Builder.hxx>
# include <BRepBndLib.hxx>
# include <BRepPrimAPI_MakeRevol.hxx>
# include <BRepBuilderAPI_Copy.hxx>
# include <BRepBuilderAPI_MakeFace.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Face.hxx>
# include <TopoDS_Wire.hxx>
# include <TopExp_Explorer.hxx>
# include <BRepAlgoAPI_Cut.hxx>
#endif
#include <Base/Axis.h>
#include <Base/Placement.h>
#include <Base/Tools.h>
#include <Mod/Part/App/Part2DObject.h>
#include "FeatureGroove.h"
using namespace PartDesign;
namespace PartDesign {
PROPERTY_SOURCE(PartDesign::Groove, PartDesign::SketchBased)
Groove::Groove()
{
ADD_PROPERTY_TYPE(Base,(Base::Vector3f(0.0f,0.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Base");
ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Axis");
ADD_PROPERTY_TYPE(Angle,(360.0),"Groove", App::Prop_None, "Angle");
ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Groove",(App::PropertyType)(App::Prop_None),"Reference axis of Groove");
ADD_PROPERTY_TYPE(Midplane,(0),"Groove", App::Prop_None, "Mid plane");
ADD_PROPERTY_TYPE(Reversed, (0),"Groove", App::Prop_None, "Reversed");
}
short Groove::mustExecute() const
{
if (Placement.isTouched() ||
Sketch.isTouched() ||
ReferenceAxis.isTouched() ||
Axis.isTouched() ||
Base.isTouched() ||
Angle.isTouched() ||
Midplane.isTouched() ||
Reversed.isTouched())
return 1;
return 0;
}
App::DocumentObjectExecReturn *Groove::execute(void)
{
App::DocumentObject* link = Sketch.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No sketch linked");
if (!link->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject");
Part::Part2DObject* pcSketch=static_cast<Part::Part2DObject*>(link);
TopoDS_Shape shape = pcSketch->Shape.getShape()._Shape;
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Linked shape object is empty");
// this is a workaround for an obscure OCC bug which leads to empty tessellations
// for some faces. Making an explicit copy of the linked shape seems to fix it.
// The error only happens when re-computing the shape.
if (!this->Shape.getValue().IsNull()) {
BRepBuilderAPI_Copy copy(shape);
shape = copy.Shape();
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Linked shape object is empty");
}
TopExp_Explorer ex;
std::vector<TopoDS_Wire> wires;
for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) {
wires.push_back(TopoDS::Wire(ex.Current()));
}
if (wires.empty()) // there can be several wires
return new App::DocumentObjectExecReturn("Linked shape object is not a wire");
// get the Sketch plane
Base::Placement SketchPlm = pcSketch->Placement.getValue();
// get reference axis
App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue();
const std::vector<std::string> &subReferenceAxis = ReferenceAxis.getSubValues();
if (pcReferenceAxis && pcReferenceAxis == pcSketch) {
bool hasValidAxis=false;
Base::Axis axis;
if (subReferenceAxis[0] == "V_Axis") {
hasValidAxis = true;
axis = pcSketch->getAxis(Part::Part2DObject::V_Axis);
}
else if (subReferenceAxis[0] == "H_Axis") {
hasValidAxis = true;
axis = pcSketch->getAxis(Part::Part2DObject::H_Axis);
}
else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") {
int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str());
if (AxId >= 0 && AxId < pcSketch->getAxisCount()) {
hasValidAxis = true;
axis = pcSketch->getAxis(AxId);
}
}
if (hasValidAxis) {
axis *= SketchPlm;
Base::Vector3d base=axis.getBase();
Base::Vector3d dir=axis.getDirection();
Base.setValue(base.x,base.y,base.z);
Axis.setValue(dir.x,dir.y,dir.z);
}
}
// get revolve axis
Base::Vector3f b = Base.getValue();
gp_Pnt pnt(b.x,b.y,b.z);
Base::Vector3f v = Axis.getValue();
gp_Dir dir(v.x,v.y,v.z);
// get the support of the Sketch if any
App::DocumentObject* pcSupport = pcSketch->Support.getValue();
Part::Feature *SupportObject = 0;
if (pcSupport && pcSupport->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
SupportObject = static_cast<Part::Feature*>(pcSupport);
TopoDS_Shape aFace = makeFace(wires);
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
// Rotate the face by half the angle to get Groove symmetric to sketch plane
if (Midplane.getValue()) {
gp_Trsf mov;
mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()) * (-1.0) / 2.0);
TopLoc_Location loc(mov);
aFace.Move(loc);
}
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
pnt.Transform(invObjLoc.Transformation());
dir.Transform(invObjLoc.Transformation());
// Reverse angle if selected
double angle = Base::toRadians<double>(Angle.getValue());
if (Reversed.getValue() && !Midplane.getValue())
angle *= (-1.0);
try {
// revolve the face to a solid
BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle);
if (RevolMaker.IsDone()) {
TopoDS_Shape result = RevolMaker.Shape();
// if the sketch has a support fuse them to get one result object (PAD!)
if (SupportObject) {
const TopoDS_Shape& support = SupportObject->Shape.getValue();
if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) {
// Let's call algorithm computing a fuse operation:
BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), result);
// Let's check if the fusion has been successful
if (!mkCut.IsDone())
throw Base::Exception("Cut out of support failed");
result = mkCut.Shape();
}
}
this->Shape.setValue(result);
}
else
return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
return App::DocumentObject::StdReturn;
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
return new App::DocumentObjectExecReturn(e->GetMessageString());
}
}
}

View File

@ -0,0 +1,66 @@
/***************************************************************************
* Copyright (c) 2010 Juergen Riegel <FreeCAD@juergen-riegel.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 PARTDESIGN_Groove_H
#define PARTDESIGN_Groove_H
#include <App/PropertyUnits.h>
#include "FeatureSketchBased.h"
namespace PartDesign
{
class Groove : public SketchBased
{
PROPERTY_HEADER(PartDesign::Groove);
public:
Groove();
App::PropertyVector Base;
App::PropertyVector Axis;
App::PropertyAngle Angle;
App::PropertyBool Midplane;
App::PropertyBool Reversed;
/** if this property is set to a valid link, both Axis and Base properties
* are calculated according to the linked line
*/
App::PropertyLinkSub ReferenceAxis;
/** @name methods override feature */
//@{
/// recalculate the feature
App::DocumentObjectExecReturn *execute(void);
short mustExecute() const;
/// returns the type name of the view provider
const char* getViewProviderName(void) const {
return "PartDesignGui::ViewProviderGroove";
}
//@}
};
} //namespace PartDesign
#endif // PART_Groove_H

View File

@ -23,14 +23,12 @@
#include "PreCompiled.h"
#ifndef _PreComp_
//# include <Bnd_Box.hxx>
//# include <gp_Pln.hxx>
# include <BRep_Builder.hxx>
# include <BRep_Tool.hxx>
# include <BRepBndLib.hxx>
# include <BRepPrimAPI_MakePrism.hxx>
# include <BRepBuilderAPI_Copy.hxx>
# include <BRepBuilderAPI_MakeFace.hxx>
//# include <Geom_Plane.hxx>
# include <Handle_Geom_Surface.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Solid.hxx>
@ -39,23 +37,32 @@
# include <TopExp_Explorer.hxx>
# include <BRepAlgoAPI_Fuse.hxx>
# include <Precision.hxx>
# include <BRepPrimAPI_MakeHalfSpace.hxx>
# include <BRepAlgoAPI_Common.hxx>
#endif
#include <Base/Placement.h>
#include <Mod/Part/App/Part2DObject.h>
#include <App/Document.h>
#include "FeaturePad.h"
using namespace PartDesign;
const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL};
PROPERTY_SOURCE(PartDesign::Pad, PartDesign::Additive)
Pad::Pad()
{
ADD_PROPERTY(Type,((long)0));
Type.setEnums(TypeEnums);
ADD_PROPERTY(Length,(100.0));
ADD_PROPERTY(Reversed,(0));
ADD_PROPERTY(MirroredExtent,(0));
ADD_PROPERTY(Midplane,(0));
ADD_PROPERTY(Length2,(100.0));
ADD_PROPERTY(FaceName,(""));
}
short Pad::mustExecute() const
@ -63,8 +70,10 @@ short Pad::mustExecute() const
if (Placement.isTouched() ||
Sketch.isTouched() ||
Length.isTouched() ||
MirroredExtent.isTouched() ||
Reversed.isTouched())
Midplane.isTouched() ||
Reversed.isTouched() ||
Length2.isTouched() ||
FaceName.isTouched())
return 1;
return 0;
}
@ -74,6 +83,10 @@ App::DocumentObjectExecReturn *Pad::execute(void)
double L = Length.getValue();
if (L < Precision::Confusion())
return new App::DocumentObjectExecReturn("Length of pad too small");
double L2 = Length2.getValue();
if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion()))
return new App::DocumentObjectExecReturn("Second length of pad too small");
App::DocumentObject* link = Sketch.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No sketch linked");
@ -103,10 +116,8 @@ App::DocumentObjectExecReturn *Pad::execute(void)
// get the Sketch plane
Base::Placement SketchPos = static_cast<Part::Part2DObject*>(link)->Placement.getValue();
Base::Rotation SketchOrientation = SketchPos.getRotation();
Base::Vector3d SketchOrientationVector(0,0,1);
if (Reversed.getValue()) // negative direction
SketchOrientationVector *= -1;
SketchOrientation.multVec(SketchOrientationVector,SketchOrientationVector);
Base::Vector3d SketchVector(0,0,1);
SketchOrientation.multVec(SketchVector,SketchVector);
// get the support of the Sketch if any
App::DocumentObject* SupportLink = static_cast<Part::Part2DObject*>(link)->Support.getValue();
@ -118,27 +129,159 @@ App::DocumentObjectExecReturn *Pad::execute(void)
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
// lengthen the vector
SketchOrientationVector *= L;
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
try {
// extrude the face to a solid
gp_Vec vec(SketchOrientationVector.x,SketchOrientationVector.y,SketchOrientationVector.z);
vec.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1);
if (PrismMaker.IsDone()) {
// if the sketch has a support fuse them to get one result object (PAD!)
if (SupportObject) {
// At this point the prism can be a compound
TopoDS_Shape result = PrismMaker.Shape();
// set the additive shape property for later usage in e.g. pattern
this->AddShape.setValue(result);
TopoDS_Shape prism;
bool isSolid = false; // support is a solid?
bool isSolidChecked = false; // not checked yet
if ((std::string(Type.getValueAsString()) == "UpToLast") ||
(std::string(Type.getValueAsString()) == "UpToFirst") ||
(std::string(Type.getValueAsString()) == "UpToFace"))
{
TopoDS_Face upToFace;
gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
if ((std::string(Type.getValueAsString()) == "UpToLast") ||
(std::string(Type.getValueAsString()) == "UpToFirst"))
{
// Check for valid support object
if (!SupportObject)
return new App::DocumentObjectExecReturn("Cannot extrude up to face: No support in Sketch!");
const TopoDS_Shape& support = SupportObject->Shape.getValue();
bool isSolid = false;
if (support.IsNull())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is invalid");
TopExp_Explorer xp (support, TopAbs_SOLID);
if (!xp.More())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is not a solid");
isSolid = true;
isSolidChecked = true;
TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit
std::vector<Part::cutFaces> cfaces = Part::findAllFacesCutBy(support, origFace, dir);
if (cfaces.empty())
return new App::DocumentObjectExecReturn("No faces found in this direction");
// Find nearest/furthest face
std::vector<Part::cutFaces>::const_iterator it, it_near, it_far;
it_near = it_far = cfaces.begin();
for (it = cfaces.begin(); it != cfaces.end(); it++)
if (it->distsq > it_far->distsq)
it_far = it;
else if (it->distsq < it_near->distsq)
it_near = it;
upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face);
} else {
if (FaceName.isEmpty())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected");
// Get active object, this is the object that the user referenced when he clicked on the face!
App::DocumentObject* baseLink = this->getDocument()->getActiveObject();
if (!baseLink)
return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked");
if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(baseLink);
const Part::TopoShape& baseShape = base->Shape.getShape();
if (baseShape._Shape.IsNull())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape");
TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue());
if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE)
upToFace = TopoDS::Face(sub);
else
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face");
// Validate face
// TODO: This would also exclude faces that are valid but not cut by the line
// So for now we trust to the intelligence of the user when picking the face
/*std::vector<cutFaces> cfaces = findAllFacesCutBy(upToFace, origFace, dir);
if (cfaces.empty())
return new App::DocumentObjectExecReturn("No faces found in this direction");*/
}
// Create semi-infinite prism from sketch in direction dir
// Hack, because the two lines commented out below do NOT work!!!
SketchVector *= 1E6;
gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
vec.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // very long, but finite prism
//dir.Transform(invObjLoc.Transformation());
//BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1);
if (!PrismMaker.IsDone())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!");
// Cut off the prism at the face we found
// Grab any point from the sketch
TopExp_Explorer exp;
exp.Init(aFace, TopAbs_VERTEX);
if (!exp.More())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?");
gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
// Create a halfspace from the face, extending in direction of sketch plane
BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt);
if (!mkHalfSpace.IsDone())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed");
// Find common material between halfspace and prism
BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc));
if (!mkCommon.IsDone())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed");
prism = this->getSolid(mkCommon.Shape());
if (prism.IsNull())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid");
} else if ((std::string(Type.getValueAsString()) == "Length") ||
(std::string(Type.getValueAsString()) == "TwoLengths")) {
if (std::string(Type.getValueAsString()) == "Length") {
if (Midplane.getValue()) {
// Move face by half the extrusion distance to get pad symmetric to sketch plane
gp_Trsf mov;
mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L/2.0);
TopLoc_Location loc(mov);
aFace.Move(loc);
} else if (Reversed.getValue()) { // negative direction
SketchVector *= -1.0;
}
// lengthen the vector
SketchVector *= L;
} else {
// Move face by the second length to get pad extending to both sides of sketch plane
gp_Trsf mov;
mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L2);
TopLoc_Location loc(mov);
aFace.Move(loc);
// lengthen the vector
SketchVector *= (L + L2);
}
// create the extrusion
gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
vec.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism
if (!PrismMaker.IsDone())
return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
prism = PrismMaker.Shape();
} else {
return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pad feature");
}
// if the sketch has a support fuse them to get one result object (PAD!)
if (SupportObject) {
// set the additive shape property for later usage in e.g. pattern
this->AddShape.setValue(prism);
const TopoDS_Shape& support = SupportObject->Shape.getValue();
if (!isSolidChecked) { // we haven't checked for solid, yet
if (!support.IsNull()) {
TopExp_Explorer xp;
xp.Init(support,TopAbs_SOLID);
@ -147,32 +290,30 @@ App::DocumentObjectExecReturn *Pad::execute(void)
break;
}
}
if (isSolid) {
// Let's call algorithm computing a fuse operation:
BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result);
// Let's check if the fusion has been successful
if (!mkFuse.IsDone())
return new App::DocumentObjectExecReturn("Fusion with support failed");
result = mkFuse.Shape();
// we have to get the solids (fuse create seldomly compounds)
TopoDS_Shape solRes = this->getSolid(result);
// lets check if the result is a solid
if (solRes.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
this->Shape.setValue(solRes);
}
else
if (!isSolid)
return new App::DocumentObjectExecReturn("Support is not a solid");
}
else {
TopoDS_Shape result = this->getSolid(PrismMaker.Shape());
// set the additive shape property for later usage in e.g. pattern
this->AddShape.setValue(result);
this->Shape.setValue(result);
}
// Let's call algorithm computing a fuse operation:
BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), prism);
// Let's check if the fusion has been successful
if (!mkFuse.IsDone())
return new App::DocumentObjectExecReturn("Fusion with support failed");
TopoDS_Shape result = mkFuse.Shape();
// we have to get the solids (fuse create seldomly compounds)
TopoDS_Shape solRes = this->getSolid(result);
// lets check if the result is a solid
if (solRes.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
this->Shape.setValue(solRes);
}
else {
TopoDS_Shape result = this->getSolid(prism);
// set the additive shape property for later usage in e.g. pattern
this->AddShape.setValue(result);
this->Shape.setValue(result);
}
else
return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
return App::DocumentObject::StdReturn;
}

View File

@ -38,10 +38,13 @@ class Pad : public Additive
public:
Pad();
App::PropertyLength Length;
App::PropertyEnumeration Type;
App::PropertyLength Length;
//App::PropertyEnumeration Side;
App::PropertyBool Reversed;
App::PropertyBool MirroredExtent;
App::PropertyBool Reversed;
App::PropertyBool Midplane;
App::PropertyLength Length2;
App::PropertyString FaceName;
/** @name methods override feature */
//@{
@ -54,7 +57,8 @@ public:
}
//@}
private:
static const char* SideEnums[];
static const char* TypeEnums[];
//static const char* SideEnums[];
};
} //namespace PartDesign

View File

@ -27,6 +27,7 @@
# include <gp_Dir.hxx>
# include <gp_Pln.hxx>
# include <BRep_Builder.hxx>
# include <BRep_Tool.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <BRepBndLib.hxx>
# include <BRepPrimAPI_MakePrism.hxx>
@ -40,17 +41,20 @@
# include <TopoDS_Solid.hxx>
# include <TopExp_Explorer.hxx>
# include <BRepAlgoAPI_Cut.hxx>
# include <BRepPrimAPI_MakeHalfSpace.hxx>
# include <BRepAlgoAPI_Common.hxx>
#endif
#include <Base/Placement.h>
#include <Mod/Part/App/Part2DObject.h>
#include <App/Document.h>
#include "FeaturePocket.h"
using namespace PartDesign;
const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst",NULL};
const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst","ThroughAll","UpToFace",NULL};
PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::SketchBased)
@ -59,13 +63,15 @@ Pocket::Pocket()
ADD_PROPERTY(Type,((long)0));
Type.setEnums(TypeEnums);
ADD_PROPERTY(Length,(100.0));
ADD_PROPERTY(FaceName,(""));
}
short Pocket::mustExecute() const
{
if (Placement.isTouched() ||
Sketch.isTouched() ||
Length.isTouched())
Length.isTouched() ||
FaceName.isTouched())
return 1;
return 0;
}
@ -113,13 +119,22 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
if (!SupportObject)
return new App::DocumentObjectExecReturn("No support in Sketch!");
const TopoDS_Shape& support = SupportObject->Shape.getValue();
if (support.IsNull())
return new App::DocumentObjectExecReturn("Support shape is invalid");
TopExp_Explorer xp (support, TopAbs_SOLID);
if (!xp.More())
return new App::DocumentObjectExecReturn("Support shape is not a solid");
TopoDS_Shape aFace = makeFace(wires);
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
// This is a trick to avoid problems with the cut operation. Sometimes a cut doesn't
// work as expected if faces or coincident. Thus, we move the face in normal direction
// work as expected if faces are coincident. Thus, we move the face in normal direction
// but make it longer by one unit in the opposite direction.
// TODO: Isn't one unit (one millimeter) a lot, assuming someone models a really tiny solid?
// What about using 2 * Precision::Confusion() ?
gp_Trsf mov;
mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z));
TopLoc_Location loc(mov);
@ -134,39 +149,133 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
// extrude the face to a solid
gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
vec.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1);
if (PrismMaker.IsDone()) {
// if the sketch has a support fuse them to get one result object (PAD!)
if (SupportObject) {
const TopoDS_Shape& support = SupportObject->Shape.getValue();
if (support.IsNull())
return new App::DocumentObjectExecReturn("Support shape is invalid");
TopExp_Explorer xp (support, TopAbs_SOLID);
if (!xp.More())
return new App::DocumentObjectExecReturn("Support shape is not a solid");
// Let's call algorithm computing a fuse operation:
BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), PrismMaker.Shape());
// Let's check if the fusion has been successful
if (!mkCut.IsDone())
return new App::DocumentObjectExecReturn("Cut with support failed");
try {
// extrude the face to a solid
TopoDS_Shape prism;
// we have to get the solids (fuse create seldomly compounds)
TopoDS_Shape solRes = this->getSolid(mkCut.Shape());
if (solRes.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
if ((std::string(Type.getValueAsString()) == "UpToLast") ||
(std::string(Type.getValueAsString()) == "UpToFirst") ||
(std::string(Type.getValueAsString()) == "UpToFace"))
{
TopoDS_Face upToFace;
gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
this->Shape.setValue(solRes);
}
else {
return new App::DocumentObjectExecReturn("Cannot create a tool out of sketch with no support");
if ((std::string(Type.getValueAsString()) == "UpToLast") ||
(std::string(Type.getValueAsString()) == "UpToFirst"))
{
TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit
std::vector<Part::cutFaces> cfaces = Part::findAllFacesCutBy(support, origFace, dir);
if (cfaces.empty())
return new App::DocumentObjectExecReturn("No faces found in this direction");
// Find nearest/furthest face
std::vector<Part::cutFaces>::const_iterator it, it_near, it_far;
it_near = it_far = cfaces.begin();
for (it = cfaces.begin(); it != cfaces.end(); it++)
if (it->distsq > it_far->distsq)
it_far = it;
else if (it->distsq < it_near->distsq)
it_near = it;
upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face);
} else {
if (FaceName.getValue() == "")
return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected");
// Get active object, this is the object that the user referenced when he clicked on the face!
App::DocumentObject* baseLink = this->getDocument()->getActiveObject();
if (!baseLink)
return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked");
if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(baseLink);
const Part::TopoShape& baseShape = base->Shape.getShape();
if (baseShape._Shape.IsNull())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape");
TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue());
if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE)
upToFace = TopoDS::Face(sub);
else
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face");
// Find the origin of this face (i.e. a vertex or a edge in a sketch)
TopoDS_Shape origin = base->findOriginOf(sub);
// Validate face
// TODO: This would also exclude faces that are valid but not cut by the line
// So for now we trust to the intelligence of the user when picking the face
/*std::vector<cutFaces> cfaces = findAllFacesCutBy(upToFace, origFace, dir);
if (cfaces.empty())
return new App::DocumentObjectExecReturn("No faces found in this direction");*/
}
// Create semi-infinite prism from sketch in direction dir
dir.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1);
if (!PrismMaker.IsDone())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!");
// Cut off the prism at the face we found
// Grab any point from the sketch
TopExp_Explorer exp;
exp.Init(aFace, TopAbs_VERTEX);
if (!exp.More())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?");
gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
// Create a halfspace from the face, extending in direction of sketch plane
BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt);
if (!mkHalfSpace.IsDone())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed");
// Find common material between halfspace and prism
BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc));
if (!mkCommon.IsDone())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed");
prism = this->getSolid(mkCommon.Shape());
if (prism.IsNull())
return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid");
} else if (std::string(Type.getValueAsString()) == "ThroughAll") {
gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
dir.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,1,0,1); // infinite prism (in both directions!)
if (!PrismMaker.IsDone())
return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
prism = PrismMaker.Shape();
} else if (std::string(Type.getValueAsString()) == "Length") {
gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
vec.Transform(invObjLoc.Transformation());
BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism
if (!PrismMaker.IsDone())
return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
prism = PrismMaker.Shape();
} else {
return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pocket feature");
}
// TODO: Set the subtractive shape property for later usage in e.g. pattern
//this->SubShape.setValue(prism); // This crashes with "Illegal storage access". Why?
// Cut out the pocket
BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), prism);
// Let's check if the fusion has been successful
if (!mkCut.IsDone())
return new App::DocumentObjectExecReturn("Cut with support failed");
// we have to get the solids (fuse sometimes creates compounds)
TopoDS_Shape solRes = this->getSolid(mkCut.Shape());
if (solRes.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
this->Shape.setValue(solRes);
return App::DocumentObject::StdReturn;
} catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
return new App::DocumentObjectExecReturn(e->GetMessageString());
}
else
return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
return App::DocumentObject::StdReturn;
}

View File

@ -39,6 +39,7 @@ public:
App::PropertyEnumeration Type;
App::PropertyLength Length;
App::PropertyString FaceName;
/** @name methods override feature */
//@{

View File

@ -52,10 +52,12 @@ PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::SketchBased)
Revolution::Revolution()
{
ADD_PROPERTY(Base,(Base::Vector3f(0.0f,0.0f,0.0f)));
ADD_PROPERTY(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)));
ADD_PROPERTY(Angle,(360.0));
ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Revolution",(App::PropertyType)(App::Prop_None),"Reference axis of revolution");
ADD_PROPERTY_TYPE(Base,(Base::Vector3f(0.0f,0.0f,0.0f)),"Revolution", App::Prop_ReadOnly, "Base");
ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)),"Revolution", App::Prop_ReadOnly, "Axis");
ADD_PROPERTY_TYPE(Angle,(360.0),"Revolution", App::Prop_None, "Angle");
ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Revolution",(App::Prop_None),"Reference axis of revolution");
ADD_PROPERTY_TYPE(Midplane,(0),"Revolution", App::Prop_None, "Mid plane");
ADD_PROPERTY_TYPE(Reversed, (0),"Revolution", App::Prop_None, "Reversed");
}
short Revolution::mustExecute() const
@ -65,7 +67,9 @@ short Revolution::mustExecute() const
ReferenceAxis.isTouched() ||
Axis.isTouched() ||
Base.isTouched() ||
Angle.isTouched())
Angle.isTouched() ||
Midplane.isTouched() ||
Reversed.isTouched())
return 1;
return 0;
}
@ -151,35 +155,54 @@ App::DocumentObjectExecReturn *Revolution::execute(void)
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
// Rotate the face by half the angle to get revolution symmetric to sketch plane
if (Midplane.getValue()) {
gp_Trsf mov;
mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()) * (-1.0) / 2.0);
TopLoc_Location loc(mov);
aFace.Move(loc);
}
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
pnt.Transform(invObjLoc.Transformation());
dir.Transform(invObjLoc.Transformation());
// revolve the face to a solid
BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()));
// Reverse angle if selected
double angle = Base::toRadians<double>(Angle.getValue());
if (Reversed.getValue() && !Midplane.getValue())
angle *= (-1.0);
if (RevolMaker.IsDone()) {
TopoDS_Shape result = RevolMaker.Shape();
// if the sketch has a support fuse them to get one result object (PAD!)
if (SupportObject) {
const TopoDS_Shape& support = SupportObject->Shape.getValue();
if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) {
// Let's call algorithm computing a fuse operation:
BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result);
// Let's check if the fusion has been successful
if (!mkFuse.IsDone())
throw Base::Exception("Fusion with support failed");
result = mkFuse.Shape();
try {
// revolve the face to a solid
BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle);
if (RevolMaker.IsDone()) {
TopoDS_Shape result = RevolMaker.Shape();
// if the sketch has a support fuse them to get one result object (PAD!)
if (SupportObject) {
const TopoDS_Shape& support = SupportObject->Shape.getValue();
if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) {
// Let's call algorithm computing a fuse operation:
BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result);
// Let's check if the fusion has been successful
if (!mkFuse.IsDone())
throw Base::Exception("Fusion with support failed");
result = mkFuse.Shape();
}
}
this->Shape.setValue(result);
}
else
return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
this->Shape.setValue(result);
return App::DocumentObject::StdReturn;
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
return new App::DocumentObjectExecReturn(e->GetMessageString());
}
else
return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
return App::DocumentObject::StdReturn;
}
}

View File

@ -39,7 +39,9 @@ public:
App::PropertyVector Base;
App::PropertyVector Axis;
App::PropertyAngle Angle;
App::PropertyAngle Angle;
App::PropertyBool Midplane;
App::PropertyBool Reversed;
/** if this property is set to a valid link, both Axis and Base properties
* are calculated according to the linked line

View File

@ -37,6 +37,7 @@
#include "ViewProviderChamfer.h"
#include "ViewProviderFillet.h"
#include "ViewProviderRevolution.h"
#include "ViewProviderGroove.h"
//#include "resources/qrc_PartDesign.cpp"
@ -83,6 +84,7 @@ void PartDesignGuiExport initPartDesignGui()
PartDesignGui::ViewProviderPocket ::init();
PartDesignGui::ViewProviderPad ::init();
PartDesignGui::ViewProviderRevolution::init();
PartDesignGui::ViewProviderGroove ::init();
PartDesignGui::ViewProviderChamfer ::init();
PartDesignGui::ViewProviderFillet ::init();

View File

@ -32,6 +32,7 @@ set(PartDesignGui_MOC_HDRS
TaskFilletParameters.h
TaskHoleParameters.h
TaskRevolutionParameters.h
TaskGrooveParameters.h
)
fc_wrap_cpp(PartDesignGui_MOC_SRCS ${PartDesignGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${PartDesignGui_MOC_SRCS})
@ -46,6 +47,7 @@ set(PartDesignGui_UIC_SRCS
TaskFilletParameters.ui
TaskHoleParameters.ui
TaskRevolutionParameters.ui
TaskGrooveParameters.ui
)
qt4_wrap_ui(PartDesignGui_UIC_HDRS ${PartDesignGui_UIC_SRCS})
@ -64,6 +66,8 @@ SET(PartDesignGuiViewProvider_SRCS
ViewProviderFillet.h
ViewProviderRevolution.cpp
ViewProviderRevolution.h
ViewProviderGroove.cpp
ViewProviderGroove.h
ViewProviderPatternRectangular.cpp
ViewProviderPatternRectangular.h
)
@ -88,6 +92,9 @@ SET(PartDesignGuiTaskDlgs_SRCS
TaskRevolutionParameters.ui
TaskRevolutionParameters.cpp
TaskRevolutionParameters.h
TaskGrooveParameters.ui
TaskGrooveParameters.cpp
TaskGrooveParameters.h
TaskHoleParameters.ui
TaskHoleParameters.cpp
TaskHoleParameters.h

View File

@ -327,6 +327,82 @@ bool CmdPartDesignRevolution::isActive(void)
return hasActiveDocument();
}
//===========================================================================
// PartDesign_Groove
//===========================================================================
DEF_STD_CMD_A(CmdPartDesignGroove);
CmdPartDesignGroove::CmdPartDesignGroove()
: Command("PartDesign_Groove")
{
sAppModule = "PartDesign";
sGroup = QT_TR_NOOP("PartDesign");
sMenuText = QT_TR_NOOP("Groove");
sToolTipText = QT_TR_NOOP("Groove a selected sketch");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "PartDesign_Groove";
}
void CmdPartDesignGroove::activated(int iMsg)
{
unsigned int n = getSelection().countObjectsOfType(Part::Part2DObject::getClassTypeId());
if (n != 1) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select a sketch or 2D object."));
return;
}
std::string FeatName = getUniqueObjectName("Groove");
std::vector<App::DocumentObject*> Sel = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId());
Part::Part2DObject* sketch = static_cast<Part::Part2DObject*>(Sel.front());
const TopoDS_Shape& shape = sketch->Shape.getValue();
if (shape.IsNull()) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("The shape of the selected object is empty."));
return;
}
// count free wires
int ctWires=0;
TopExp_Explorer ex;
for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) {
ctWires++;
}
if (ctWires == 0) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("The shape of the selected object is not a wire."));
return;
}
App::DocumentObject* support = sketch->Support.getValue();
openCommand("Make Groove");
doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str());
doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument());
doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])",
FeatName.c_str(), sketch->getNameInDocument());
doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str());
updateActive();
if (isActiveObjectValid()) {
doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument());
if (support)
doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument());
}
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
if (support) {
copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument());
copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument());
copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument());
}
}
bool CmdPartDesignGroove::isActive(void)
{
return hasActiveDocument();
}
//===========================================================================
// PartDesign_Fillet
//===========================================================================
@ -628,6 +704,7 @@ void CreatePartDesignCommands(void)
rcCmdMgr.addCommand(new CmdPartDesignPad());
rcCmdMgr.addCommand(new CmdPartDesignPocket());
rcCmdMgr.addCommand(new CmdPartDesignRevolution());
rcCmdMgr.addCommand(new CmdPartDesignGroove());
rcCmdMgr.addCommand(new CmdPartDesignFillet());
//rcCmdMgr.addCommand(new CmdPartDesignNewSketch());
rcCmdMgr.addCommand(new CmdPartDesignChamfer());

View File

@ -37,6 +37,7 @@ EXTRA_DIST = \
translations/PartDesign_uk.ts \
translations/PartDesign_zh.qm \
translations/PartDesign_zh.ts \
icons/PartDesign_Groove.svg \
icons/PartDesign_Pad.svg \
icons/PartDesign_Pocket.svg \
icons/PartDesign_Revolution.svg \

View File

@ -1,5 +1,6 @@
<RCC>
<qresource>
<file>icons/PartDesign_Groove.svg</file>
<file>icons/PartDesign_Pad.svg</file>
<file>icons/PartDesign_Pocket.svg</file>
<file>icons/PartDesign_Revolution.svg</file>

View File

@ -0,0 +1,144 @@
<?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.3.1 r9886"
sodipodi:docname="PartDesign_Groove.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2903">
<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" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient2828"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.17633158,1.0722433,-2.4668184,0.22034972,200.7515,-229.90841)"
cx="210.14677"
cy="90.154442"
fx="210.14677"
fy="90.154442"
r="19.467436" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3273"
id="radialGradient3603"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3995263,0.42685906,-0.16783602,0.65132941,-270.58184,-127.11943)"
cx="235.36554"
cy="100.66685"
fx="235.36554"
fy="100.66685"
r="12.369295" />
<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="#linearGradient3377"
id="linearGradient3623"
x1="29.883257"
y1="48.10252"
x2="14.402146"
y2="38.793137"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0525814,0,0,1.0539222,-2.4849957,-0.33904926)" />
</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="19.560465"
inkscape:cy="30.011334"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="777"
inkscape:window-height="671"
inkscape:window-x="477"
inkscape:window-y="11"
inkscape:window-maximized="0" />
<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="fill:url(#radialGradient2828);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:2.54254937;stroke-linecap:butt;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 16.219529,48.470519 5.519805,-10.603495 3.099728,-5.954548 c -2.538693,-1.004369 -7.359646,-5.057261 -6.367193,-7.486557 0.992442,-2.429306 8.213296,-1.410588 17.450246,2.659744 9.23696,4.070334 10.545281,7.72797 9.552828,10.157267 -0.992454,2.429299 -5.153506,1.062409 -10.492825,-0.44407 0,0 -2.909634,-0.135138 -4.957582,4.19395 -1.280609,2.707035 -1.900598,5.328711 -2.201937,7.848172 -0.302478,2.529002 1.410667,4.420093 1.410667,4.420093 11.236677,4.016835 26.220226,2.576595 30.921828,-8.93185 C 64.856692,32.820781 55.970471,17.888025 40.33209,10.996855 24.693722,4.1056906 8.1791437,7.8453977 3.4775422,19.35384 -1.2240589,30.862285 8.2362999,44.645309 16.219529,48.470519"
id="path3568"
sodipodi:nodetypes="cccssccszcscss"
inkscape:connector-curvature="0" />
<path
style="fill:url(#radialGradient3603);fill-opacity:1.0;fill-rule:evenodd;stroke:none"
d="m 43.385467,39.483241 -4.557458,-0.384821 -3.924569,-1.094677 -2.064721,0.95476 -1.422046,2.21889 0.339476,5.469855 c 0,0 12.46651,4.215168 14.232668,4.685459 1.76616,0.470289 11.715062,-5.022866 11.715062,-5.022866 L 59.37987,38.44684 45.133043,23.468457 l -0.622959,7.011971 2.041649,3.128647 0.405504,2.013354 -0.420224,2.075699 -1.281497,1.315064 -1.870049,0.470049 z"
id="path3580"
sodipodi:nodetypes="ccccccsccccccccc" />
<path
style="font-size:54.21519088999999525px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;color:#000000;fill:url(#linearGradient3623);fill-opacity:1;stroke:#000137;stroke-width:3.15975474999999983;stroke-linecap:butt;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;font-family:Arial;-inkscape-font-specification:Arial"
d="m 25.615879,42.810546 c -1.454882,3.867291 -4.596603,8.064603 -9.109549,6.003891 -4.512945,-2.06071 -2.23349,-15.445828 4.354416,-17.340156 6.587905,-1.894328 6.283764,6.354186 4.755133,11.336265 z"
id="path3736"
sodipodi:nodetypes="czzc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -0,0 +1,287 @@
/***************************************************************************
* Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.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_
#endif
#include "ui_TaskGrooveParameters.h"
#include "TaskGrooveParameters.h"
#include <App/Application.h>
#include <App/Document.h>
#include <Gui/Application.h>
#include <Gui/Document.h>
#include <Gui/BitmapFactory.h>
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>
#include <Base/Console.h>
#include <Gui/Selection.h>
#include <Gui/Command.h>
#include <Mod/PartDesign/App/FeatureGroove.h>
#include <Mod/Sketcher/App/SketchObject.h>
using namespace PartDesignGui;
using namespace Gui;
/* TRANSLATOR PartDesignGui::TaskGrooveParameters */
TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent)
: TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Groove"),tr("Groove parameters"),true, parent),GrooveView(GrooveView)
{
// we need a separate container widget to add all controls to
proxy = new QWidget(this);
ui = new Ui_TaskGrooveParameters();
ui->setupUi(proxy);
QMetaObject::connectSlotsByName(this);
connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(onAngleChanged(double)));
connect(ui->axis, SIGNAL(activated(int)),
this, SLOT(onAxisChanged(int)));
connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
this, SLOT(onMidplane(bool)));
connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
this, SLOT(onReversed(bool)));
this->groupLayout()->addWidget(proxy);
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
double l = pcGroove->Angle.getValue();
bool mirrored = pcGroove->Midplane.getValue();
bool reversed = pcGroove->Reversed.getValue();
ui->doubleSpinBox->setValue(l);
int count=pcGroove->getSketchAxisCount();
for (int i=ui->axis->count()-1; i >= count+2; i--)
ui->axis->removeItem(i);
for (int i=ui->axis->count(); i < count+2; i++)
ui->axis->addItem(QString::fromAscii("Sketch axis %1").arg(i-2));
int pos=-1;
App::DocumentObject *pcReferenceAxis = pcGroove->ReferenceAxis.getValue();
const std::vector<std::string> &subReferenceAxis = pcGroove->ReferenceAxis.getSubValues();
if (pcReferenceAxis && pcReferenceAxis == pcGroove->Sketch.getValue()) {
assert(subReferenceAxis.size()==1);
if (subReferenceAxis[0] == "V_Axis")
pos = 0;
else if (subReferenceAxis[0] == "H_Axis")
pos = 1;
else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis")
pos = 2 + std::atoi(subReferenceAxis[0].substr(4,4000).c_str());
}
if (pos < 0 || pos >= ui->axis->count()) {
ui->axis->addItem(QString::fromAscii("Undefined"));
pos = ui->axis->count()-1;
}
ui->axis->setCurrentIndex(pos);
ui->checkBoxMidplane->setChecked(mirrored);
ui->checkBoxReversed->setChecked(reversed);
setFocus ();
}
void TaskGrooveParameters::onAngleChanged(double len)
{
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
pcGroove->Angle.setValue((float)len);
pcGroove->getDocument()->recomputeFeature(pcGroove);
}
void TaskGrooveParameters::onAxisChanged(int num)
{
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
Sketcher::SketchObject *pcSketch = static_cast<Sketcher::SketchObject*>(pcGroove->Sketch.getValue());
if (pcSketch) {
int maxcount = pcSketch->getAxisCount()+2;
if (num == 0)
pcGroove->ReferenceAxis.setValue(pcSketch, std::vector<std::string>(1,"V_Axis"));
else if (num == 1)
pcGroove->ReferenceAxis.setValue(pcSketch, std::vector<std::string>(1,"H_Axis"));
else if (num >= 2 && num < maxcount) {
QString buf = QString::fromUtf8("Axis%1").arg(num-2);
std::string str = buf.toStdString();
pcGroove->ReferenceAxis.setValue(pcSketch, std::vector<std::string>(1,str));
}
if (num < maxcount && ui->axis->count() > maxcount)
ui->axis->setMaxCount(maxcount);
}
pcGroove->getDocument()->recomputeFeature(pcGroove);
}
void TaskGrooveParameters::onMidplane(bool on)
{
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
pcGroove->Midplane.setValue(on);
pcGroove->getDocument()->recomputeFeature(pcGroove);
}
void TaskGrooveParameters::onReversed(bool on)
{
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
pcGroove->Reversed.setValue(on);
pcGroove->getDocument()->recomputeFeature(pcGroove);
}
double TaskGrooveParameters::getAngle(void) const
{
return ui->doubleSpinBox->value();
}
QString TaskGrooveParameters::getReferenceAxis(void) const
{
// get the support and Sketch
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
Sketcher::SketchObject *pcSketch = static_cast<Sketcher::SketchObject*>(pcGroove->Sketch.getValue());
QString buf;
if (pcSketch) {
buf = QString::fromUtf8("(App.ActiveDocument.%1,[%2])");
buf = buf.arg(QString::fromUtf8(pcSketch->getNameInDocument()));
if (ui->axis->currentIndex() == 0)
buf = buf.arg(QString::fromUtf8("'V_Axis'"));
else if (ui->axis->currentIndex() == 1)
buf = buf.arg(QString::fromUtf8("'H_Axis'"));
else if (ui->axis->currentIndex() >= 2) {
buf = buf.arg(QString::fromUtf8("'Axis%1'"));
buf = buf.arg(ui->axis->currentIndex()-2);
}
}
else
buf = QString::fromUtf8("''");
return buf;
}
bool TaskGrooveParameters::getMidplane(void) const
{
return ui->checkBoxMidplane->isChecked();
}
bool TaskGrooveParameters::getReversed(void) const
{
return ui->checkBoxReversed->isChecked();
}
TaskGrooveParameters::~TaskGrooveParameters()
{
delete ui;
}
void TaskGrooveParameters::changeEvent(QEvent *e)
{
TaskBox::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
ui->retranslateUi(proxy);
}
}
//**************************************************************************
//**************************************************************************
// TaskDialog
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TaskDlgGrooveParameters::TaskDlgGrooveParameters(ViewProviderGroove *GrooveView)
: TaskDialog(),GrooveView(GrooveView)
{
assert(GrooveView);
parameter = new TaskGrooveParameters(GrooveView);
Content.push_back(parameter);
}
TaskDlgGrooveParameters::~TaskDlgGrooveParameters()
{
}
//==== calls from the TaskView ===============================================================
void TaskDlgGrooveParameters::open()
{
}
void TaskDlgGrooveParameters::clicked(int)
{
}
bool TaskDlgGrooveParameters::accept()
{
std::string name = GrooveView->getObject()->getNameInDocument();
//Gui::Command::openCommand("Groove changed");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle());
std::string axis = parameter->getReferenceAxis().toStdString();
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
Gui::Command::commitCommand();
return true;
}
bool TaskDlgGrooveParameters::reject()
{
// get the support and Sketch
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(GrooveView->getObject());
Sketcher::SketchObject *pcSketch;
App::DocumentObject *pcSupport;
if (pcGroove->Sketch.getValue()) {
pcSketch = static_cast<Sketcher::SketchObject*>(pcGroove->Sketch.getValue());
pcSupport = pcSketch->Support.getValue();
}
// role back the done things
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
// if abort command deleted the object the support is visible again
if (!Gui::Application::Instance->getViewProvider(pcGroove)) {
if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch))
Gui::Application::Instance->getViewProvider(pcSketch)->show();
if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport))
Gui::Application::Instance->getViewProvider(pcSupport)->show();
}
//Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
//Gui::Command::commitCommand();
return true;
}
#include "moc_TaskGrooveParameters.cpp"

View File

@ -0,0 +1,115 @@
/***************************************************************************
* Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.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 GUI_TASKVIEW_TaskGrooveParameters_H
#define GUI_TASKVIEW_TaskGrooveParameters_H
#include <Gui/TaskView/TaskView.h>
#include <Gui/Selection.h>
#include <Gui/TaskView/TaskDialog.h>
#include "ViewProviderGroove.h"
class Ui_TaskGrooveParameters;
namespace App {
class Property;
}
namespace Gui {
class ViewProvider;
}
namespace PartDesignGui {
class TaskGrooveParameters : public Gui::TaskView::TaskBox
{
Q_OBJECT
public:
TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent = 0);
~TaskGrooveParameters();
QString getReferenceAxis(void) const;
double getAngle(void) const;
bool getMidplane(void) const;
bool getReversed(void) const;
private Q_SLOTS:
void onAngleChanged(double);
void onAxisChanged(int);
void onMidplane(bool);
void onReversed(bool);
protected:
void changeEvent(QEvent *e);
private:
private:
QWidget* proxy;
Ui_TaskGrooveParameters* ui;
ViewProviderGroove *GrooveView;
};
/// simulation dialog for the TaskView
class TaskDlgGrooveParameters : public Gui::TaskView::TaskDialog
{
Q_OBJECT
public:
TaskDlgGrooveParameters(ViewProviderGroove *GrooveView);
~TaskDlgGrooveParameters();
ViewProviderGroove* getGrooveView() const
{ return GrooveView; }
public:
/// is called the TaskView when the dialog is opened
virtual void open();
/// is called by the framework if an button is clicked which has no accept or reject role
virtual void clicked(int);
/// is called by the framework if the dialog is accepted (Ok)
virtual bool accept();
/// is called by the framework if the dialog is rejected (Cancel)
virtual bool reject();
/// is called by the framework if the user presses the help button
virtual bool isAllowedAlterDocument(void) const
{ return false; }
/// returns for Close and Help button
virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const
{ return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
protected:
ViewProviderGroove *GrooveView;
TaskGrooveParameters *parameter;
};
} //namespace PartDesignGui
#endif // GUI_TASKVIEW_TASKAPPERANCE_H

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PartDesignGui::TaskGrooveParameters</class>
<widget class="QWidget" name="PartDesignGui::TaskGrooveParameters">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>278</width>
<height>158</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>Axis:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="axis">
<item>
<property name="text">
<string>Vertical sketch axis</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal sketch axis</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Angle:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>360.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxMidplane">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Symmetric to plane</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxReversed">
<property name="text">
<string>Reversed</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -59,30 +59,106 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,QWidget *parent)
connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(onLengthChanged(double)));
connect(ui->checkBoxMirrored, SIGNAL(toggled(bool)),
this, SLOT(onMirrored(bool)));
connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
this, SLOT(onMidplane(bool)));
connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
this, SLOT(onReversed(bool)));
connect(ui->doubleSpinBox2, SIGNAL(valueChanged(double)),
this, SLOT(onLength2Changed(double)));
connect(ui->changeMode, SIGNAL(currentIndexChanged(int)),
this, SLOT(onModeChanged(int)));
connect(ui->lineFaceName, SIGNAL(textEdited(QString)),
this, SLOT(onFaceName(QString)));
this->groupLayout()->addWidget(proxy);
// Get the feature data
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(PadView->getObject());
double l = pcPad->Length.getValue();
bool mirrored = pcPad->MirroredExtent.getValue();
bool midplane = pcPad->Midplane.getValue();
bool reversed = pcPad->Reversed.getValue();
double l2 = pcPad->Length2.getValue();
int index = pcPad->Type.getValue(); // must extract value here, clear() kills it!
const char* upToFace = pcPad->FaceName.getValue();
// Fill data into dialog elements
ui->doubleSpinBox->setMinimum(0);
ui->doubleSpinBox->setMaximum(INT_MAX);
ui->doubleSpinBox->setValue(l);
ui->doubleSpinBox->selectAll();
ui->checkBoxMirrored->setChecked(mirrored);
ui->doubleSpinBox2->setMinimum(0);
ui->doubleSpinBox2->setMaximum(INT_MAX);
ui->doubleSpinBox2->setValue(l2);
ui->checkBoxMidplane->setChecked(midplane);
// According to bug #0000521 the reversed option
// shouldn't be de-activated if the pad has a support face
ui->checkBoxReversed->setChecked(reversed);
ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace));
ui->changeMode->clear();
ui->changeMode->insertItem(0, tr("Dimension"));
ui->changeMode->insertItem(1, tr("To last"));
ui->changeMode->insertItem(2, tr("To first"));
ui->changeMode->insertItem(3, tr("Up to face"));
ui->changeMode->insertItem(4, tr("Two dimensions"));
ui->changeMode->setCurrentIndex(index);
// Make sure that the spin box has the focus to get key events
// Calling setFocus() directly doesn't work because the spin box is not
// yet visible.
QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
// activate and de-activate dialog elements as appropriate
updateUI(index);
}
void TaskPadParameters::updateUI(int index)
{
if (index == 0) { // dimension
ui->doubleSpinBox->setEnabled(true);
ui->doubleSpinBox->selectAll();
// Make sure that the spin box has the focus to get key events
// Calling setFocus() directly doesn't work because the spin box is not
// yet visible.
QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
ui->checkBoxMidplane->setEnabled(true);
ui->checkBoxReversed->setEnabled(true);
ui->doubleSpinBox2->setEnabled(false);
ui->lineFaceName->setEnabled(false);
} else if ((index == 1) || (index == 2)) { // up to first/last
ui->doubleSpinBox->setEnabled(false);
ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(false);
ui->doubleSpinBox2->setEnabled(false);
ui->lineFaceName->setEnabled(false);
} else if (index == 3) { // up to face
ui->doubleSpinBox->setEnabled(false);
ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(false);
ui->doubleSpinBox2->setEnabled(false);
ui->lineFaceName->setEnabled(true);
QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection);
} else { // two dimensions
ui->doubleSpinBox->setEnabled(true);
ui->doubleSpinBox->selectAll();
QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(false);
ui->doubleSpinBox2->setEnabled(true);
ui->lineFaceName->setEnabled(false);
}
}
void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
{
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(PadView->getObject());
if (pcPad->Type.getValue() != 3) // ignore user selections if mode is not upToFace
return;
if (!msg.pSubName || msg.pSubName[0] == '\0')
return;
std::string element(msg.pSubName);
if (element.substr(0,4) != "Face")
return;
if (msg.Type == Gui::SelectionChanges::AddSelection) {
pcPad->FaceName.setValue(element);
pcPad->getDocument()->recomputeFeature(pcPad);
ui->lineFaceName->setText(tr(element.c_str()));
}
}
void TaskPadParameters::onLengthChanged(double len)
@ -92,10 +168,10 @@ void TaskPadParameters::onLengthChanged(double len)
pcPad->getDocument()->recomputeFeature(pcPad);
}
void TaskPadParameters::onMirrored(bool on)
void TaskPadParameters::onMidplane(bool on)
{
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(PadView->getObject());
pcPad->MirroredExtent.setValue(on);
pcPad->Midplane.setValue(on);
pcPad->getDocument()->recomputeFeature(pcPad);
}
@ -106,6 +182,40 @@ void TaskPadParameters::onReversed(bool on)
pcPad->getDocument()->recomputeFeature(pcPad);
}
void TaskPadParameters::onLength2Changed(double len)
{
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(PadView->getObject());
pcPad->Length2.setValue((float)len);
pcPad->getDocument()->recomputeFeature(pcPad);
}
void TaskPadParameters::onModeChanged(int index)
{
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(PadView->getObject());
switch (index) {
case 0: pcPad->Type.setValue("Length"); break;
case 1: pcPad->Type.setValue("UpToLast"); break;
case 2: pcPad->Type.setValue("UpToFirst"); break;
case 3: pcPad->Type.setValue("UpToFace"); break;
default: pcPad->Type.setValue("TwoLengths");
}
updateUI(index);
pcPad->getDocument()->recomputeFeature(pcPad);
}
void TaskPadParameters::onFaceName(const QString& text)
{
if (text.left(4) != tr("Face"))
return;
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(PadView->getObject());
pcPad->FaceName.setValue(text.toUtf8());
pcPad->getDocument()->recomputeFeature(pcPad);
}
double TaskPadParameters::getLength(void) const
{
return ui->doubleSpinBox->value();
@ -116,9 +226,24 @@ bool TaskPadParameters::getReversed(void) const
return ui->checkBoxReversed->isChecked();
}
bool TaskPadParameters::getMirroredExtent(void) const
bool TaskPadParameters::getMidplane(void) const
{
return ui->checkBoxMirrored->isChecked();
return ui->checkBoxMidplane->isChecked();
}
double TaskPadParameters::getLength2(void) const
{
return ui->doubleSpinBox2->value();
}
int TaskPadParameters::getMode(void) const
{
return ui->changeMode->currentIndex();
}
const QString TaskPadParameters::getFaceName(void) const
{
return ui->lineFaceName->text();
}
TaskPadParameters::~TaskPadParameters()
@ -174,7 +299,10 @@ bool TaskDlgPadParameters::accept()
//Gui::Command::openCommand("Pad changed");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirroredExtent = %i",name.c_str(),parameter->getMirroredExtent()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length2 = %f",name.c_str(),parameter->getLength2());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!PadView->getObject()->isValid())
throw Base::Exception(PadView->getObject()->getStatusString());

View File

@ -44,7 +44,7 @@ namespace PartDesignGui {
class TaskPadParameters : public Gui::TaskView::TaskBox
class TaskPadParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
{
Q_OBJECT
@ -52,19 +52,27 @@ public:
TaskPadParameters(ViewProviderPad *PadView,QWidget *parent = 0);
~TaskPadParameters();
int getMode(void) const;
double getLength(void) const;
double getLength2(void) const;
bool getReversed(void) const;
bool getMirroredExtent(void) const;
bool getMidplane(void) const;
const QString getFaceName(void) const;
private Q_SLOTS:
void onLengthChanged(double);
void onMirrored(bool);
void onMidplane(bool);
void onReversed(bool);
void onLength2Changed(double);
void onModeChanged(int);
void onFaceName(const QString& text);
protected:
void changeEvent(QEvent *e);
private:
void onSelectionChanged(const Gui::SelectionChanges& msg);
void updateUI(int index);
private:
QWidget* proxy;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>158</width>
<height>116</height>
<width>272</width>
<height>238</height>
</rect>
</property>
<property name="windowTitle">
@ -19,7 +19,7 @@
<item>
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>Type:</string>
<string>Type</string>
</property>
</widget>
</item>
@ -39,7 +39,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Length:</string>
<string>Length</string>
</property>
</widget>
</item>
@ -55,19 +55,19 @@
<double>5.000000000000000</double>
</property>
<property name="value">
<double>20.000000000000000</double>
<double>10.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxMirrored">
<widget class="QCheckBox" name="checkBoxMidplane">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="text">
<string>Mirrored extent</string>
<string>Symmetric to plane</string>
</property>
</widget>
</item>
@ -78,6 +78,47 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>2nd length</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox2">
<property name="minimum">
<double>-999999999.000000000000000</double>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>5.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="textLabel1_2">
<property name="text">
<string>Face</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineFaceName"/>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

View File

@ -58,16 +58,39 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(onLengthChanged(double)));
connect(ui->changeMode, SIGNAL(currentIndexChanged(int)),
this, SLOT(onModeChanged(int)));
connect(ui->lineFaceName, SIGNAL(textEdited(QString)),
this, SLOT(onFaceName(QString)));
this->groupLayout()->addWidget(proxy);
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(PocketView->getObject());
double l = pcPocket->Length.getValue();
int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it!
const char* upToFace = pcPocket->FaceName.getValue();
ui->doubleSpinBox->setMaximum(INT_MAX);
ui->doubleSpinBox->setValue(l);
ui->doubleSpinBox->selectAll();
QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
ui->changeMode->clear();
ui->changeMode->insertItem(0, tr("Dimension"));
ui->changeMode->insertItem(1, tr("To last"));
ui->changeMode->insertItem(2, tr("To first"));
ui->changeMode->insertItem(3, tr("Through all"));
ui->changeMode->insertItem(4, tr("Up to face"));
ui->changeMode->setCurrentIndex(index);
if (index == 0) { // Only this option requires a numeric value
ui->doubleSpinBox->setMaximum(INT_MAX);
ui->doubleSpinBox->setValue(l);
ui->doubleSpinBox->selectAll();
QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
ui->lineFaceName->setEnabled(false);
} else if (index == 4) { // Only this option requires to select a face
ui->doubleSpinBox->setEnabled(false);
ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace));
} else { // Neither value nor face required
ui->doubleSpinBox->setEnabled(false);
ui->lineFaceName->setEnabled(false);
}
//// check if the sketch has support
//Sketcher::SketchObject *pcSketch;
@ -81,6 +104,25 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
//}
}
void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
{
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(PocketView->getObject());
if (pcPocket->Type.getValue() != 4) // ignore user selections if mode is not upToFace
return;
if (!msg.pSubName || msg.pSubName[0] == '\0')
return;
std::string element(msg.pSubName);
if (element.substr(0,4) != "Face")
return;
if (msg.Type == Gui::SelectionChanges::AddSelection) {
pcPocket->FaceName.setValue(element);
pcPocket->getDocument()->recomputeFeature(pcPocket);
ui->lineFaceName->setText(tr(element.c_str()));
}
}
void TaskPocketParameters::onLengthChanged(double len)
{
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(PocketView->getObject());
@ -88,11 +130,59 @@ void TaskPocketParameters::onLengthChanged(double len)
pcPocket->getDocument()->recomputeFeature(pcPocket);
}
void TaskPocketParameters::onModeChanged(int index)
{
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(PocketView->getObject());
switch (index) {
case 0: pcPocket->Type.setValue("Length"); break;
case 1: pcPocket->Type.setValue("UpToLast"); break;
case 2: pcPocket->Type.setValue("UpToFirst"); break;
case 3: pcPocket->Type.setValue("ThroughAll"); break;
case 4: pcPocket->Type.setValue("UpToFace"); break;
default: pcPocket->Type.setValue("Length");
}
if (index == 0) {
ui->doubleSpinBox->setEnabled(true);
ui->lineFaceName->setEnabled(false);
ui->doubleSpinBox->setValue(pcPocket->Length.getValue());
} else if (index == 4) {
ui->lineFaceName->setEnabled(true);
ui->doubleSpinBox->setEnabled(false);
ui->lineFaceName->setText(tr(pcPocket->FaceName.getValue()));
} else {
ui->doubleSpinBox->setEnabled(false);
ui->lineFaceName->setEnabled(false);
}
pcPocket->getDocument()->recomputeFeature(pcPocket);
}
void TaskPocketParameters::onFaceName(const QString& text)
{
if (text.left(4) != tr("Face"))
return;
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(PocketView->getObject());
pcPocket->FaceName.setValue(text.toUtf8());
pcPocket->getDocument()->recomputeFeature(pcPocket);
}
double TaskPocketParameters::getLength(void) const
{
return ui->doubleSpinBox->value();
}
int TaskPocketParameters::getMode(void) const
{
return ui->changeMode->currentIndex();
}
const QString TaskPocketParameters::getFaceName(void) const
{
return ui->lineFaceName->text();
}
TaskPocketParameters::~TaskPocketParameters()
{
@ -145,6 +235,8 @@ bool TaskDlgPocketParameters::accept()
//Gui::Command::openCommand("Pocket changed");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
Gui::Command::commitCommand();
@ -163,7 +255,7 @@ bool TaskDlgPocketParameters::reject()
pcSupport = pcSketch->Support.getValue();
}
// role back the done things
// roll back the done things
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");

View File

@ -44,7 +44,7 @@ namespace PartDesignGui {
class TaskPocketParameters : public Gui::TaskView::TaskBox
class TaskPocketParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
{
Q_OBJECT
@ -53,14 +53,19 @@ public:
~TaskPocketParameters();
double getLength(void) const;
int getMode(void) const;
const QString getFaceName(void) const;
private Q_SLOTS:
void onLengthChanged(double);
void onModeChanged(int);
void onFaceName(const QString& text);
protected:
void changeEvent(QEvent *e);
private:
void onSelectionChanged(const Gui::SelectionChanges& msg);
private:
QWidget* proxy;

View File

@ -6,49 +6,97 @@
<rect>
<x>0</x>
<y>0</y>
<width>137</width>
<height>68</height>
<width>241</width>
<height>134</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>233</width>
<height>134</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="textLabel1">
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>211</width>
<height>34</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="changeMode">
<item>
<property name="text">
<string>Type:</string>
<string>Dimension</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="changeMode">
<item>
<property name="text">
<string>Dimension</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox"/>
</item>
</layout>
</item>
</layout>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>211</width>
<height>34</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="textLabel1_2">
<property name="text">
<string>Face</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineFaceName"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>211</width>
<height>34</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>

View File

@ -60,11 +60,18 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol
this, SLOT(onAngleChanged(double)));
connect(ui->axis, SIGNAL(activated(int)),
this, SLOT(onAxisChanged(int)));
connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
this, SLOT(onMidplane(bool)));
connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
this, SLOT(onReversed(bool)));
this->groupLayout()->addWidget(proxy);
PartDesign::Revolution* pcRevolution = static_cast<PartDesign::Revolution*>(RevolutionView->getObject());
double l = pcRevolution->Angle.getValue();
bool mirrored = pcRevolution->Midplane.getValue();
bool reversed = pcRevolution->Reversed.getValue();
ui->doubleSpinBox->setValue(l);
int count=pcRevolution->getSketchAxisCount();
@ -95,6 +102,9 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol
ui->axis->setCurrentIndex(pos);
ui->checkBoxMidplane->setChecked(mirrored);
ui->checkBoxReversed->setChecked(reversed);
setFocus ();
}
@ -126,6 +136,19 @@ void TaskRevolutionParameters::onAxisChanged(int num)
pcRevolution->getDocument()->recomputeFeature(pcRevolution);
}
void TaskRevolutionParameters::onMidplane(bool on)
{
PartDesign::Revolution* pcRevolution = static_cast<PartDesign::Revolution*>(RevolutionView->getObject());
pcRevolution->Midplane.setValue(on);
pcRevolution->getDocument()->recomputeFeature(pcRevolution);
}
void TaskRevolutionParameters::onReversed(bool on)
{
PartDesign::Revolution* pcRevolution = static_cast<PartDesign::Revolution*>(RevolutionView->getObject());
pcRevolution->Reversed.setValue(on);
pcRevolution->getDocument()->recomputeFeature(pcRevolution);
}
double TaskRevolutionParameters::getAngle(void) const
{
@ -157,6 +180,16 @@ QString TaskRevolutionParameters::getReferenceAxis(void) const
return buf;
}
bool TaskRevolutionParameters::getMidplane(void) const
{
return ui->checkBoxMidplane->isChecked();
}
bool TaskRevolutionParameters::getReversed(void) const
{
return ui->checkBoxReversed->isChecked();
}
TaskRevolutionParameters::~TaskRevolutionParameters()
{
delete ui;
@ -210,6 +243,8 @@ bool TaskDlgRevolutionParameters::accept()
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle());
std::string axis = parameter->getReferenceAxis().toStdString();
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
Gui::Command::commitCommand();

View File

@ -54,10 +54,14 @@ public:
QString getReferenceAxis(void) const;
double getAngle(void) const;
bool getMidplane(void) const;
bool getReversed(void) const;
private Q_SLOTS:
void onAngleChanged(double);
void onAxisChanged(int);
void onMidplane(bool);
void onReversed(bool);
protected:
void changeEvent(QEvent *e);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>182</width>
<height>68</height>
<width>278</width>
<height>158</height>
</rect>
</property>
<property name="windowTitle">
@ -54,7 +54,7 @@
<number>1</number>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
@ -69,6 +69,23 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxMidplane">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Symmetric to plane</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxReversed">
<property name="text">
<string>Reversed</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -0,0 +1,141 @@
/***************************************************************************
* Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.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_
#endif
#include <Mod/PartDesign/App/FeatureGroove.h>
#include <Mod/Sketcher/App/SketchObject.h>
#include <Gui/Control.h>
#include <Gui/Command.h>
#include <Gui/Application.h>
#include "ViewProviderGroove.h"
#include "TaskGrooveParameters.h"
using namespace PartDesignGui;
PROPERTY_SOURCE(PartDesignGui::ViewProviderGroove,PartDesignGui::ViewProvider)
ViewProviderGroove::ViewProviderGroove()
{
}
ViewProviderGroove::~ViewProviderGroove()
{
}
std::vector<App::DocumentObject*> ViewProviderGroove::claimChildren(void)const
{
std::vector<App::DocumentObject*> temp;
temp.push_back(static_cast<PartDesign::Groove*>(getObject())->Sketch.getValue());
return temp;
}
void ViewProviderGroove::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
QAction* act;
act = menu->addAction(QObject::tr("Edit Groove"), receiver, member);
act->setData(QVariant((int)ViewProvider::Default));
PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member);
}
bool ViewProviderGroove::setEdit(int ModNum)
{
if (ModNum == ViewProvider::Default ) {
// When double-clicking on the item for this pad the
// object unsets and sets its edit mode without closing
// the task panel
Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
TaskDlgGrooveParameters *padDlg = qobject_cast<TaskDlgGrooveParameters *>(dlg);
if (padDlg && padDlg->getGrooveView() != this)
padDlg = 0; // another pad left open its task panel
if (dlg && !padDlg) {
QMessageBox msgBox;
msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
int ret = msgBox.exec();
if (ret == QMessageBox::Yes)
Gui::Control().closeDialog();
else
return false;
}
// clear the selection (convenience)
Gui::Selection().clearSelection();
//if (ModNum == 1)
// Gui::Command::openCommand("Change Groove parameters");
// start the edit dialog
if (padDlg)
Gui::Control().showDialog(padDlg);
else
Gui::Control().showDialog(new TaskDlgGrooveParameters(this));
return true;
}
else {
return PartGui::ViewProviderPart::setEdit(ModNum);
}
}
void ViewProviderGroove::unsetEdit(int ModNum)
{
if (ModNum == ViewProvider::Default) {
// and update the pad
//getSketchObject()->getDocument()->recompute();
// when pressing ESC make sure to close the dialog
Gui::Control().closeDialog();
}
else {
PartGui::ViewProviderPart::unsetEdit(ModNum);
}
}
bool ViewProviderGroove::onDelete(const std::vector<std::string> &)
{
// get the support and Sketch
PartDesign::Groove* pcGroove = static_cast<PartDesign::Groove*>(getObject());
Sketcher::SketchObject *pcSketch;
App::DocumentObject *pcSupport;
if (pcGroove->Sketch.getValue()){
pcSketch = static_cast<Sketcher::SketchObject*>(pcGroove->Sketch.getValue());
pcSupport = pcSketch->Support.getValue();
}
// if abort command deleted the object the support is visible again
if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch))
Gui::Application::Instance->getViewProvider(pcSketch)->show();
if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport))
Gui::Application::Instance->getViewProvider(pcSupport)->show();
return true;
}

View File

@ -0,0 +1,59 @@
/***************************************************************************
* Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.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_ViewProviderGroove_H
#define PARTGUI_ViewProviderGroove_H
#include "ViewProvider.h"
namespace PartDesignGui {
class PartDesignGuiExport ViewProviderGroove : public ViewProvider
{
PROPERTY_HEADER(PartGui::ViewProviderGroove);
public:
/// constructor
ViewProviderGroove();
/// destructor
virtual ~ViewProviderGroove();
/// grouping handling
std::vector<App::DocumentObject*> claimChildren(void)const;
void setupContextMenu(QMenu*, QObject*, const char*);
virtual bool onDelete(const std::vector<std::string> &);
protected:
virtual bool setEdit(int ModNum);
virtual void unsetEdit(int ModNum);
};
} // namespace PartDesignGui
#endif // PARTGUI_ViewProviderGroove_H

View File

@ -86,6 +86,7 @@ void Workbench::activated()
"PartDesign_Pad",
"PartDesign_Pocket",
"PartDesign_Revolution",
"PartDesign_Groove",
0};
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
"SELECT Sketcher::SketchObject COUNT 1",
@ -169,6 +170,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "PartDesign_Pad"
<< "PartDesign_Pocket"
<< "PartDesign_Revolution"
<< "PartDesign_Groove"
<< "PartDesign_Fillet"
<< "PartDesign_Chamfer";
@ -186,6 +188,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
<< "PartDesign_Pad"
<< "PartDesign_Pocket"
<< "PartDesign_Revolution"
<< "PartDesign_Groove"
<< "PartDesign_Fillet"
<< "PartDesign_Chamfer";