Draft: Accept datum lines and planes as references

This commit is contained in:
jrheinlaender 2013-05-16 18:09:11 +04:30 committed by Stefan Tröger
parent d8462d135b
commit 934c68faa5
9 changed files with 169 additions and 117 deletions

View File

@ -116,7 +116,7 @@ bool Feature::isDatum(const App::DocumentObject* feature)
feature->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId());
}
TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj)
gp_Pln Feature::makePlnFromPlane(const App::DocumentObject* obj)
{
const App::Plane* plane = static_cast<const App::Plane*>(obj);
if (plane == NULL)
@ -125,7 +125,12 @@ TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj)
Base::Rotation rot = plane->Placement.getValue().getRotation();
Base::Vector3d normal(0,0,1);
rot.multVec(normal, normal);
BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z)));
return gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z));
}
TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj)
{
BRepBuilderAPI_MakeFace builder(makePlnFromPlane(obj));
if (!builder.IsDone())
throw Base::Exception("Feature: Could not create shape from base plane");

View File

@ -28,6 +28,7 @@
#include <Mod/Part/App/PartFeature.h>
class gp_Pnt;
class gp_Pln;
/// Base class of all additive features in PartDesign
@ -67,6 +68,7 @@ protected:
/// Grab any point from the given face
static const gp_Pnt getPointFromFace(const TopoDS_Face& f);
/// Make a shape from a base plane (convenience method)
static gp_Pln makePlnFromPlane(const App::DocumentObject* obj);
static TopoDS_Shape makeShapeFromPlane(const App::DocumentObject* obj);
};

View File

@ -47,10 +47,13 @@
# include <BRepBuilderAPI_MakeEdge.hxx>
#endif
#include <App/Plane.h>
#include <Base/Tools.h>
#include <Mod/Part/App/TopoShape.h>
#include "FeatureDraft.h"
#include "DatumLine.h"
#include "DatumPlane.h"
#include <Base/Console.h>
@ -110,29 +113,35 @@ App::DocumentObjectExecReturn *Draft::execute(void)
// Pull direction
gp_Dir pullDirection;
App::DocumentObject* refDirection = PullDirection.getValue();
App::DocumentObject* refDirection = PullDirection.getValue();
if (refDirection != NULL) {
if (!refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
throw Base::Exception("Pull direction reference must be an edge of a feature");
std::vector<std::string> subStrings = PullDirection.getSubValues();
if (subStrings.empty() || subStrings[0].empty())
throw Base::Exception("No pull direction reference specified");
if (refDirection->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) {
PartDesign::Line* line = static_cast<PartDesign::Line*>(refDirection);
Base::Vector3d d = line->getDirection();
pullDirection = gp_Dir(d.x, d.y, d.z);
} else if (refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
std::vector<std::string> subStrings = PullDirection.getSubValues();
if (subStrings.empty() || subStrings[0].empty())
throw Base::Exception("No pull direction reference specified");
Part::Feature* refFeature = static_cast<Part::Feature*>(refDirection);
Part::TopoShape refShape = refFeature->Shape.getShape();
TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str());
Part::Feature* refFeature = static_cast<Part::Feature*>(refDirection);
Part::TopoShape refShape = refFeature->Shape.getShape();
TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str());
if (ref.ShapeType() == TopAbs_EDGE) {
TopoDS_Edge refEdge = TopoDS::Edge(ref);
if (refEdge.IsNull())
throw Base::Exception("Failed to extract pull direction reference edge");
BRepAdaptor_Curve adapt(refEdge);
if (adapt.GetType() != GeomAbs_Line)
throw Base::Exception("Pull direction reference edge must be linear");
if (ref.ShapeType() == TopAbs_EDGE) {
TopoDS_Edge refEdge = TopoDS::Edge(ref);
if (refEdge.IsNull())
throw Base::Exception("Failed to extract pull direction reference edge");
BRepAdaptor_Curve adapt(refEdge);
if (adapt.GetType() != GeomAbs_Line)
throw Base::Exception("Pull direction reference edge must be linear");
pullDirection = adapt.Line().Direction();
pullDirection = adapt.Line().Direction();
} else {
throw Base::Exception("Pull direction reference must be an edge or a datum line");
}
} else {
throw Base::Exception("Pull direction reference must be an edge");
throw Base::Exception("Pull direction reference must be an edge of a feature or a datum line");
}
TopLoc_Location invObjLoc = this->getLocation().Inverted();
@ -188,43 +197,52 @@ App::DocumentObjectExecReturn *Draft::execute(void)
if (!found)
throw Base::Exception("No neutral plane specified and none can be guessed");
} else {
if (!refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
throw Base::Exception("Neutral plane reference must be face of a feature");
std::vector<std::string> subStrings = NeutralPlane.getSubValues();
if (subStrings.empty() || subStrings[0].empty())
throw Base::Exception("No neutral plane reference specified");
if (refPlane->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) {
PartDesign::Plane* plane = static_cast<PartDesign::Plane*>(refPlane);
Base::Vector3d b = plane->getBasePoint();
Base::Vector3d n = plane->getNormal();
neutralPlane = gp_Pln(gp_Pnt(b.x, b.y, b.z), gp_Dir(n.x, n.y, n.z));
} else if (refPlane->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) {
neutralPlane = Feature::makePlnFromPlane(refPlane);
} else if (refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
std::vector<std::string> subStrings = NeutralPlane.getSubValues();
if (subStrings.empty() || subStrings[0].empty())
throw Base::Exception("No neutral plane reference specified");
Part::Feature* refFeature = static_cast<Part::Feature*>(refPlane);
Part::TopoShape refShape = refFeature->Shape.getShape();
TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str());
Part::Feature* refFeature = static_cast<Part::Feature*>(refPlane);
Part::TopoShape refShape = refFeature->Shape.getShape();
TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str());
if (ref.ShapeType() == TopAbs_FACE) {
TopoDS_Face refFace = TopoDS::Face(ref);
if (refFace.IsNull())
throw Base::Exception("Failed to extract neutral plane reference face");
BRepAdaptor_Surface adapt(refFace);
if (adapt.GetType() != GeomAbs_Plane)
throw Base::Exception("Neutral plane reference face must be planar");
if (ref.ShapeType() == TopAbs_FACE) {
TopoDS_Face refFace = TopoDS::Face(ref);
if (refFace.IsNull())
throw Base::Exception("Failed to extract neutral plane reference face");
BRepAdaptor_Surface adapt(refFace);
if (adapt.GetType() != GeomAbs_Plane)
throw Base::Exception("Neutral plane reference face must be planar");
neutralPlane = adapt.Plane();
} else if (ref.ShapeType() == TopAbs_EDGE) {
if (refDirection != NULL) {
// Create neutral plane through edge normal to pull direction
TopoDS_Edge refEdge = TopoDS::Edge(ref);
if (refEdge.IsNull())
throw Base::Exception("Failed to extract neutral plane reference edge");
BRepAdaptor_Curve c(refEdge);
neutralPlane = adapt.Plane();
} else if (ref.ShapeType() == TopAbs_EDGE) {
if (refDirection != NULL) {
// Create neutral plane through edge normal to pull direction
TopoDS_Edge refEdge = TopoDS::Edge(ref);
if (refEdge.IsNull())
throw Base::Exception("Failed to extract neutral plane reference edge");
BRepAdaptor_Curve c(refEdge);
if (c.GetType() != GeomAbs_Line)
throw Base::Exception("Neutral plane reference edge must be linear");
double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection));
if (std::fabs(a - M_PI_2) > Precision::Confusion())
throw Base::Exception("Neutral plane reference edge must be normal to pull direction");
neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection);
throw Base::Exception("Neutral plane reference edge must be linear");
double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection));
if (std::fabs(a - M_PI_2) > Precision::Confusion())
throw Base::Exception("Neutral plane reference edge must be normal to pull direction");
neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection);
} else {
throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined");
}
} else {
throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined");
throw Base::Exception("Neutral plane reference must be a face");
}
} else {
throw Base::Exception("Neutral plane reference must be a face");
throw Base::Exception("Neutral plane reference must be face of a feature or a datum plane");
}
TopLoc_Location invObjLoc = this->getLocation().Inverted();

View File

@ -33,6 +33,7 @@
#include <App/Plane.h>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/PartFeature.h>
#include <Mod/PartDesign/App/Feature.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/DatumPoint.h>
#include <Mod/PartDesign/App/DatumLine.h>
@ -111,3 +112,31 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c
}
return false;
}
namespace PartDesignGui
{
const QString getRefStr(const App::DocumentObject* obj, const std::vector<std::string>& sub)
{
if (obj == NULL)
return QString::fromAscii("");
if (PartDesign::Feature::isDatum(obj))
return QString::fromAscii(obj->getNameInDocument());
else
return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") +
QString::fromAscii(sub.front().c_str());
}
const std::string getPythonStr(const App::DocumentObject* obj, const std::vector<std::string>& sub)
{
if (obj == NULL)
return "";
if (PartDesign::Feature::isDatum(obj))
return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])";
else
return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])";
}
}

View File

@ -47,6 +47,12 @@ public:
bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName);
};
// Convenience methods
/// Return reference as string for UI elements (format <obj>:<subelement>
const QString getRefStr(const App::DocumentObject* obj, const std::vector<std::string>& sub);
/// Return reference as string for python (format (<obj>, ["<subelement>"]) )
const std::string getPythonStr(const App::DocumentObject* obj, const std::vector<std::string>& sub);
} //namespace PartDesignGui
#endif // GUI_ReferenceSelection_H

View File

@ -101,13 +101,30 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p
connect(action, SIGNAL(triggered()), this, SLOT(onFaceDeleted()));
ui->listWidgetFaces->setContextMenuPolicy(Qt::ActionsContextMenu);
App::DocumentObject* ref = pcDraft->NeutralPlane.getValue();
strings = pcDraft->NeutralPlane.getSubValues();
std::string neutralPlane = (strings.empty() ? "" : strings[0]);
ui->linePlane->setText(QString::fromStdString(neutralPlane));
ui->linePlane->setText(getRefStr(ref, strings));
ref = pcDraft->PullDirection.getValue();
strings = pcDraft->PullDirection.getSubValues();
std::string pullDirection = (strings.empty() ? "" : strings[0]);
ui->lineLine->setText(QString::fromStdString(pullDirection));
ui->lineLine->setText(getRefStr(ref, strings));
}
void TaskDraftParameters::getReferencedSelection(const Gui::SelectionChanges& msg,
App::DocumentObject*& selObj, std::vector<std::string>& selSub)
{
PartDesign::DressUp* pcDressup = static_cast<PartDesign::DressUp*>(DraftView->getObject());
selObj = pcDressup->getDocument()->getObject(msg.pObjectName);
if (selObj == pcDressup)
return;
std::string subname = msg.pSubName;
// Remove subname for planes and datum features
if (PartDesign::Feature::isDatum(selObj)) {
subname = "";
}
selSub = std::vector<std::string>(1,subname);
}
void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
@ -162,27 +179,22 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
ui->buttonFaceRemove->setChecked(false);
exitSelectionMode();
}
} else if ((selectionMode == plane) && (subName.size() > 4) &&
((subName.substr(0,4) == "Face") || (subName.substr(0,4) == "Edge"))) {
if (strcmp(msg.pObjectName, fname) != 0)
return;
std::vector<std::string> planes(1,subName);
pcDraft->NeutralPlane.setValue(base, planes);
ui->linePlane->setText(QString::fromStdString(subName));
} else if ((selectionMode == plane)) {
std::vector<std::string> planes;
App::DocumentObject* selObj;
getReferencedSelection(msg, selObj, planes);
pcDraft->NeutralPlane.setValue(selObj, planes);
ui->linePlane->setText(getRefStr(selObj, planes));
pcDraft->getDocument()->recomputeFeature(pcDraft);
ui->buttonPlane->setChecked(false);
exitSelectionMode();
} else if ((selectionMode == line) && (subName.size() > 4 && subName.substr(0,4) == "Edge")) {
if (strcmp(msg.pObjectName, fname) != 0)
return;
std::vector<std::string> edges(1,subName);
pcDraft->PullDirection.setValue(base, edges);
ui->lineLine->setText(QString::fromStdString(subName));
std::vector<std::string> edges;
App::DocumentObject* selObj;
getReferencedSelection(msg, selObj, edges);
pcDraft->PullDirection.setValue(selObj, edges);
ui->lineLine->setText(getRefStr(selObj, edges));
pcDraft->getDocument()->recomputeFeature(pcDraft);
ui->buttonLine->setChecked(false);
@ -258,14 +270,22 @@ void TaskDraftParameters::onFaceDeleted(void)
pcDraft->getDocument()->recomputeFeature(pcDraft);
}
const std::string TaskDraftParameters::getPlane(void) const
void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector<std::string>& sub) const
{
return ui->linePlane->text().toStdString();
sub = std::vector<std::string>(1,"");
QStringList parts = ui->linePlane->text().split(QChar::fromAscii(':'));
obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str());
if (parts.size() > 1)
sub[0] = parts[1].toStdString();
}
const std::string TaskDraftParameters::getLine(void) const
void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector<std::string>& sub) const
{
return ui->lineLine->text().toStdString();
sub = std::vector<std::string>(1,"");
QStringList parts = ui->lineLine->text().split(QChar::fromAscii(':'));
obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str());
if (parts.size() > 1)
sub[0] = parts[1].toStdString();
}
void TaskDraftParameters::hideObject()
@ -379,7 +399,11 @@ bool TaskDlgDraftParameters::accept()
parameter->showObject();
// Force the user to select a neutral plane
if (parameter->getPlane().empty()) {
std::vector<std::string> strings;
App::DocumentObject* obj;
parameter->getPlane(obj, strings);
std::string neutralPlane = getPythonStr(obj, strings);
if (neutralPlane.empty()) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"),
QObject::tr("Please select a plane or an edge plus a pull direction"));
return false;
@ -403,20 +427,14 @@ bool TaskDlgDraftParameters::accept()
QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what()));
return false;
}
std::string neutralPlane = parameter->getPlane();
if (!neutralPlane.empty()) {
QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])");
buf = buf.arg(QString::fromUtf8(parameter->getBase()->getNameInDocument()));
buf = buf.arg(QString::fromUtf8(neutralPlane.c_str()));
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), buf.toStdString().c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), neutralPlane.c_str());
} else
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = None", name.c_str());
std::string pullDirection = parameter->getLine();
parameter->getLine(obj, strings);
std::string pullDirection = getPythonStr(obj, strings);
if (!pullDirection.empty()) {
QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])");
buf = buf.arg(QString::fromUtf8(parameter->getBase()->getNameInDocument()));
buf = buf.arg(QString::fromUtf8(pullDirection.c_str()));
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), buf.toStdString().c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), pullDirection.c_str());
} else
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = None", name.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");

View File

@ -54,8 +54,8 @@ public:
const double getAngle(void) const;
const bool getReversed(void) const;
const std::vector<std::string> getFaces(void) const;
const std::string getPlane(void) const;
const std::string getLine(void) const;
void getPlane(App::DocumentObject*& obj, std::vector<std::string>& sub) const;
void getLine(App::DocumentObject*& obj, std::vector<std::string>& sub) const;
App::DocumentObject *getBase(void) const;
void hideObject();
@ -84,6 +84,9 @@ private:
enum selectionModes { none, faceAdd, faceRemove, plane, line };
selectionModes selectionMode;
void getReferencedSelection(const Gui::SelectionChanges& msg,
App::DocumentObject*& selObj, std::vector<std::string>& selSub);
};
/// simulation dialog for the TaskView

View File

@ -245,30 +245,6 @@ void TaskTransformedParameters::getReferencedSelection(const Gui::SelectionChang
selSub = std::vector<std::string>(1,subname);
}
const QString TaskTransformedParameters::getRefStr(const App::DocumentObject* obj, const std::vector<std::string>& sub)
{
if (obj == NULL)
return QString::fromAscii("");
if (PartDesign::Feature::isDatum(obj))
return QString::fromAscii(obj->getNameInDocument());
else
return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") +
QString::fromAscii(sub.front().c_str());
}
const std::string TaskTransformedParameters::getPythonStr(const App::DocumentObject* obj, const std::vector<std::string>& sub)
{
if (obj == NULL)
return "";
if (PartDesign::Feature::isDatum(obj))
return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])";
else
return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])";
}
//**************************************************************************
//**************************************************************************
// TaskDialog

View File

@ -62,10 +62,7 @@ public:
/// Get the support object either of the object associated with this feature or with the parent feature (MultiTransform mode)
App::DocumentObject* getSupportObject() const;
/// Get the sketch object of the first original either of the object associated with this feature or with the parent feature (MultiTransform mode)
App::DocumentObject* getSketchObject() const;
/// Return reference as string for python (format (<obj>, ["<subelement>"]) )
const std::string getPythonStr(const App::DocumentObject* selObj, const std::vector<std::string>& selSub);
App::DocumentObject* getSketchObject() const;
void exitSelectionMode();
@ -93,8 +90,6 @@ protected:
/// Extract reference from Selection (convenience method)
void getReferencedSelection(const Gui::SelectionChanges& msg,
App::DocumentObject*& selObj, std::vector<std::string>& selSub);
/// Return reference as string for UI elements (format <obj>:<subelement>
const QString getRefStr(const App::DocumentObject* selObj, const std::vector<std::string>& selSub);
bool isViewUpdated() const;
int getUpdateViewTimeout() const;