Show three base planes (XY, YZ, XZ) at the beginning of the feature tree and allow to create sketches on them
This commit is contained in:
parent
7dee0b7018
commit
417576d5eb
|
@ -45,6 +45,7 @@
|
|||
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include <App/Plane.h>
|
||||
#include "Part2DObject.h"
|
||||
#include "Geometry.h"
|
||||
|
||||
|
@ -74,42 +75,57 @@ App::DocumentObjectExecReturn *Part2DObject::execute(void)
|
|||
void Part2DObject::positionBySupport(void)
|
||||
{
|
||||
// recalculate support:
|
||||
Part::Feature *part = static_cast<Part::Feature*>(Support.getValue());
|
||||
if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
return;
|
||||
|
||||
Base::Placement Place = part->Placement.getValue();
|
||||
const std::vector<std::string> &sub = Support.getSubValues();
|
||||
assert(sub.size()==1);
|
||||
// get the selected sub shape (a Face)
|
||||
const Part::TopoShape &shape = part->Shape.getShape();
|
||||
if (shape._Shape.IsNull())
|
||||
throw Base::Exception("Support shape is empty!");
|
||||
Base::Placement Place;
|
||||
TopoDS_Shape sh;
|
||||
try {
|
||||
sh = shape.getSubShape(sub[0].c_str());
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
throw Base::Exception("Face in support shape doesn't exist!");
|
||||
}
|
||||
const TopoDS_Face &face = TopoDS::Face(sh);
|
||||
if (face.IsNull())
|
||||
throw Base::Exception("Null face in Part2DObject::positionBySupport()!");
|
||||
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if (adapt.GetType() != GeomAbs_Plane)
|
||||
throw Base::Exception("No planar face in Part2DObject::positionBySupport()!");
|
||||
|
||||
bool Reverse = false;
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
Reverse = true;
|
||||
gp_Pln plane;
|
||||
App::DocumentObject* support = Support.getValue();
|
||||
|
||||
gp_Pln plane = adapt.Plane();
|
||||
Standard_Boolean ok = plane.Direct();
|
||||
if (!ok) {
|
||||
// toggle if plane has a left-handed coordinate system
|
||||
plane.UReverse();
|
||||
Reverse = !Reverse;
|
||||
if (support->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) {
|
||||
Place = static_cast<App::Plane*>(support)->Placement.getValue();
|
||||
// TODO: How to handle the Reverse property???
|
||||
Base::Vector3d pos = Place.getPosition();
|
||||
Base::Vector3d dir;
|
||||
Place.getRotation().multVec(Base::Vector3d(0,0,1),dir);
|
||||
plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z));
|
||||
} else {
|
||||
Part::Feature *part = static_cast<Part::Feature*>(support);
|
||||
if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
return;
|
||||
|
||||
Place = part->Placement.getValue();
|
||||
const std::vector<std::string> &sub = Support.getSubValues();
|
||||
assert(sub.size()==1);
|
||||
// get the selected sub shape (a Face)
|
||||
const Part::TopoShape &shape = part->Shape.getShape();
|
||||
if (shape._Shape.IsNull())
|
||||
throw Base::Exception("Support shape is empty!");
|
||||
|
||||
try {
|
||||
sh = shape.getSubShape(sub[0].c_str());
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
throw Base::Exception("Face in support shape doesn't exist!");
|
||||
}
|
||||
|
||||
const TopoDS_Face &face = TopoDS::Face(sh);
|
||||
if (face.IsNull())
|
||||
throw Base::Exception("Null face in Part2DObject::positionBySupport()!");
|
||||
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if (adapt.GetType() != GeomAbs_Plane)
|
||||
throw Base::Exception("No planar face in Part2DObject::positionBySupport()!");
|
||||
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
Reverse = true;
|
||||
|
||||
plane = adapt.Plane();
|
||||
Standard_Boolean ok = plane.Direct();
|
||||
if (!ok) {
|
||||
// toggle if plane has a left-handed coordinate system
|
||||
plane.UReverse();
|
||||
Reverse = !Reverse;
|
||||
}
|
||||
}
|
||||
|
||||
gp_Ax1 Normal = plane.Axis();
|
||||
|
|
|
@ -82,6 +82,8 @@ PartDesign::Body *getBody(void)
|
|||
|
||||
}
|
||||
|
||||
const char* BasePlaneNames[3] = {"Body_PlaneXY", "Body_PlaneYZ", "Body_PlaneXZ"};
|
||||
|
||||
//===========================================================================
|
||||
// PartDesign_Body
|
||||
//===========================================================================
|
||||
|
@ -110,34 +112,35 @@ void CmdPartDesignBody::activated(int iMsg)
|
|||
bool found = false;
|
||||
std::vector<App::DocumentObject*> planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId());
|
||||
for (std::vector<App::DocumentObject*>::const_iterator p = planes.begin(); p != planes.end(); p++) {
|
||||
if ((strcmp("Body_PlaneXY", (*p)->getNameInDocument()) == 0) ||
|
||||
(strcmp("Body_PlaneYZ", (*p)->getNameInDocument()) == 0) ||
|
||||
(strcmp("Body_PlaneXZ", (*p)->getNameInDocument()) == 0)) {
|
||||
found = true;
|
||||
break;
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// Add the planes ...
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneXY')");
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[0]);
|
||||
doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'");
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneYZ')");
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[1]);
|
||||
doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))");
|
||||
doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'");
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneXZ')");
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[2]);
|
||||
doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))");
|
||||
doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'");
|
||||
// ... and put them in the 'Origin' group
|
||||
doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','Origin')");
|
||||
doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneXY'))");
|
||||
doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneYZ'))");
|
||||
doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneXZ'))");
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", BasePlaneNames[i]);
|
||||
// TODO: Fold the group (is that possible through the Python interface?)
|
||||
}
|
||||
|
||||
// add the Body feature itself, and make it active
|
||||
doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str());
|
||||
doCommand(Doc,"import PartDesignGui");
|
||||
doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)");
|
||||
// Make the "Create sketch" prompt appear in the task panel
|
||||
doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)");
|
||||
|
@ -179,42 +182,48 @@ void CmdPartDesignNewSketch::activated(int iMsg)
|
|||
|
||||
Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1");
|
||||
Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1");
|
||||
Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1");
|
||||
|
||||
if (SketchFilter.match()) {
|
||||
Sketcher::SketchObject *Sketch = static_cast<Sketcher::SketchObject*>(SketchFilter.Result[0][0].getObject());
|
||||
openCommand("Edit Sketch");
|
||||
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument());
|
||||
}
|
||||
else if (FaceFilter.match()) {
|
||||
else if (FaceFilter.match() || PlaneFilter.match()) {
|
||||
// get the selected object
|
||||
Part::Feature *part = static_cast<Part::Feature*>(FaceFilter.Result[0][0].getObject());
|
||||
Base::Placement ObjectPos = part->Placement.getValue();
|
||||
const std::vector<std::string> &sub = FaceFilter.Result[0][0].getSubNames();
|
||||
if (sub.size() > 1){
|
||||
// No assert for wrong user input!
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"),
|
||||
QObject::tr("You have to select a single face as support for a sketch!"));
|
||||
return;
|
||||
}
|
||||
// get the selected sub shape (a Face)
|
||||
const Part::TopoShape &shape = part->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(sub[0].c_str());
|
||||
const TopoDS_Face& face = TopoDS::Face(sh);
|
||||
if (face.IsNull()){
|
||||
// No assert for wrong user input!
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"),
|
||||
QObject::tr("You have to select a face as support for a sketch!"));
|
||||
return;
|
||||
}
|
||||
std::string supportString;
|
||||
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if (adapt.GetType() != GeomAbs_Plane){
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"),
|
||||
QObject::tr("You need a planar face as support for a sketch!"));
|
||||
return;
|
||||
}
|
||||
if (FaceFilter.match()) {
|
||||
Part::Feature *part = static_cast<Part::Feature*>(FaceFilter.Result[0][0].getObject());
|
||||
const std::vector<std::string> &sub = FaceFilter.Result[0][0].getSubNames();
|
||||
if (sub.size() > 1){
|
||||
// No assert for wrong user input!
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"),
|
||||
QObject::tr("You have to select a single face as support for a sketch!"));
|
||||
return;
|
||||
}
|
||||
// get the selected sub shape (a Face)
|
||||
const Part::TopoShape &shape = part->Shape.getValue();
|
||||
TopoDS_Shape sh = shape.getSubShape(sub[0].c_str());
|
||||
const TopoDS_Face& face = TopoDS::Face(sh);
|
||||
if (face.IsNull()){
|
||||
// No assert for wrong user input!
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"),
|
||||
QObject::tr("You have to select a face as support for a sketch!"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString();
|
||||
BRepAdaptor_Surface adapt(face);
|
||||
if (adapt.GetType() != GeomAbs_Plane){
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"),
|
||||
QObject::tr("You need a planar face as support for a sketch!"));
|
||||
return;
|
||||
}
|
||||
|
||||
supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString();
|
||||
} else {
|
||||
supportString = PlaneFilter.Result[0][0].getAsPropertyLinkSubString();
|
||||
}
|
||||
|
||||
// create Sketch on Face
|
||||
std::string FeatName = getUniqueObjectName("Sketch");
|
||||
|
@ -229,47 +238,71 @@ void CmdPartDesignNewSketch::activated(int iMsg)
|
|||
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
|
||||
}
|
||||
else {
|
||||
// ask user for orientation
|
||||
SketcherGui::SketchOrientationDialog Dlg;
|
||||
// Get a valid plane from the user
|
||||
std::vector<PartDesignGui::FeaturePickDialog::featureStatus> status;
|
||||
std::vector<App::DocumentObject*> planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId());
|
||||
|
||||
if (Dlg.exec() != QDialog::Accepted)
|
||||
return; // canceled
|
||||
Base::Vector3d p = Dlg.Pos.getPosition();
|
||||
Base::Rotation r = Dlg.Pos.getRotation();
|
||||
unsigned validPlanes = 0;
|
||||
std::vector<App::DocumentObject*>::const_iterator firstValidPlane = planes.end();
|
||||
|
||||
// do the right view direction
|
||||
std::string camstring;
|
||||
switch(Dlg.DirType){
|
||||
case 0:
|
||||
camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }";
|
||||
break;
|
||||
case 1:
|
||||
camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }";
|
||||
break;
|
||||
case 2:
|
||||
camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}";
|
||||
break;
|
||||
case 3:
|
||||
camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}";
|
||||
break;
|
||||
case 4:
|
||||
camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}";
|
||||
break;
|
||||
case 5:
|
||||
camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}";
|
||||
break;
|
||||
for (std::vector<App::DocumentObject*>::iterator p = planes.begin(); p != planes.end(); p++) {
|
||||
// Check whether this plane is a base plane
|
||||
bool base = false;
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) {
|
||||
status.push_back(PartDesignGui::FeaturePickDialog::basePlane);
|
||||
if (firstValidPlane == planes.end())
|
||||
firstValidPlane = p;
|
||||
validPlanes++;
|
||||
base = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (base) continue;
|
||||
|
||||
// Check whether this plane belongs to the active body
|
||||
PartDesign::Body* body = getBody();
|
||||
if (!body->hasFeature(*p)) {
|
||||
status.push_back(PartDesignGui::FeaturePickDialog::otherBody);
|
||||
continue;
|
||||
}
|
||||
|
||||
// All checks passed - found a valid plane
|
||||
if (firstValidPlane == planes.end())
|
||||
firstValidPlane = p;
|
||||
validPlanes++;
|
||||
status.push_back(PartDesignGui::FeaturePickDialog::validFeature);
|
||||
}
|
||||
|
||||
if (validPlanes == 0) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid planes in this document"),
|
||||
QObject::tr("Please create a plane first or select a face to sketch on"));
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is more than one possibility, show dialog and let user pick plane
|
||||
if (validPlanes > 1) {
|
||||
PartDesignGui::FeaturePickDialog Dlg(planes, status);
|
||||
if ((Dlg.exec() != QDialog::Accepted) || (planes = Dlg.getFeatures()).empty())
|
||||
return; // Cancelled or nothing selected
|
||||
firstValidPlane = planes.begin();
|
||||
}
|
||||
|
||||
App::Plane* plane = static_cast<App::Plane*>(*firstValidPlane);
|
||||
Base::Vector3d p = plane->Placement.getValue().getPosition();
|
||||
Base::Rotation r = plane->Placement.getValue().getRotation();
|
||||
|
||||
std::string FeatName = getUniqueObjectName("Sketch");
|
||||
std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])";
|
||||
|
||||
openCommand("Create a new Sketch");
|
||||
doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str());
|
||||
doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str());
|
||||
doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]);
|
||||
doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str());
|
||||
doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str());
|
||||
doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str());
|
||||
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CmdPartDesignNewSketch::isActive(void)
|
||||
|
@ -392,7 +425,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which,
|
|||
}
|
||||
|
||||
void finishSketchBased(const Gui::Command* cmd,
|
||||
const Part::Part2DObject* sketch, const std::string& FeatName, App::DocumentObject*& prevTip)
|
||||
const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevTip)
|
||||
{
|
||||
App::DocumentObjectGroup* grp = sketch->getGroup();
|
||||
if (grp) {
|
||||
|
|
|
@ -47,6 +47,7 @@ const QString FeaturePickDialog::getFeatureStatusString(const featureStatus st)
|
|||
case noWire: return tr("No wire in sketch");
|
||||
case isUsed: return tr("Sketch already used by other feature");
|
||||
case otherBody: return tr("Sketch belongs to another Body feature");
|
||||
case basePlane: return tr("Base plane");
|
||||
}
|
||||
|
||||
return tr("");
|
||||
|
@ -104,6 +105,7 @@ void FeaturePickDialog::updateList()
|
|||
case noWire: item->setFlags(Qt::NoItemFlags); break;
|
||||
case isUsed: item->setFlags(ui->checkOtherFeature->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break;
|
||||
case otherBody: item->setFlags(ui->checkOtherBody->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break;
|
||||
case basePlane: item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); break;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
|
|
@ -40,7 +40,8 @@ public:
|
|||
invalidShape,
|
||||
noWire,
|
||||
isUsed,
|
||||
otherBody
|
||||
otherBody,
|
||||
basePlane
|
||||
};
|
||||
|
||||
FeaturePickDialog(std::vector<App::DocumentObject*> &objects, const std::vector<featureStatus> &status);
|
||||
|
|
|
@ -102,6 +102,16 @@ void Workbench::activated()
|
|||
"Part_Box"
|
||||
));
|
||||
|
||||
const char* Plane[] = {
|
||||
"PartDesign_NewSketch",
|
||||
0};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT App::Plane COUNT 1",
|
||||
Plane,
|
||||
"Start Part",
|
||||
"Part_Box"
|
||||
));
|
||||
|
||||
const char* NoSel[] = {
|
||||
"PartDesign_Body",
|
||||
0};
|
||||
|
|
|
@ -25,3 +25,6 @@ import FreeCADGui
|
|||
FreeCADGui.activateWorkbench("PartDesignWorkbench")
|
||||
App.newDocument()
|
||||
FreeCADGui.runCommand('PartDesign_Body')
|
||||
# Make the planes properly visible
|
||||
FreeCADGui.activeDocument().activeView().viewAxometric()
|
||||
FreeCADGui.SendMsgToActiveView("ViewFit")
|
||||
|
|
Loading…
Reference in New Issue
Block a user