Make Body object on creation of Sketch/Primitive

This commit is contained in:
Ian Rees
2017-04-04 16:58:15 +12:00
committed by wmayer
parent e2b73e5bb1
commit ac2f9f8902
4 changed files with 130 additions and 51 deletions

View File

@@ -315,13 +315,26 @@ void CmdPartDesignNewSketch::activated(int iMsg)
{
Q_UNUSED(iMsg);
App::Document *doc = getDocument ();
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(
/*messageIfNot = */ PartDesignGui::assureModernWorkflow ( doc ) );
PartDesign::Body *pcActiveBody( nullptr );
auto shouldMakeBody( false );
// No PartDesign feature without Body past FreeCAD 0.13
if ( !pcActiveBody ) {
// Call normal sketch command for old workflow
if ( PartDesignGui::isLegacyWorkflow ( doc) ) {
if ( PartDesignGui::assureModernWorkflow( doc ) ) {
// We need either an active Body, or for there to be no Body
// objects (in which case, just make one) to make a new sketch.
pcActiveBody = PartDesignGui::getBody( /* messageIfNot = */ false );
if (pcActiveBody == nullptr) {
if ( doc->getObjectsOfType(PartDesign::Body::getClassTypeId()).empty() ) {
shouldMakeBody = true;
} else {
PartDesignGui::needActiveBodyError();
return;
}
}
} else {
// No PartDesign feature without Body past FreeCAD 0.13
if ( PartDesignGui::isLegacyWorkflow( doc ) ) {
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
rcCmdMgr.runCommandByName("Sketcher_NewSketch");
}
@@ -332,6 +345,7 @@ void CmdPartDesignNewSketch::activated(int iMsg)
Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1");
Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1");
Gui::SelectionFilter PlaneFilter2("SELECT PartDesign::Plane COUNT 1");
if (PlaneFilter2.match())
PlaneFilter = PlaneFilter2;
@@ -340,7 +354,14 @@ void CmdPartDesignNewSketch::activated(int iMsg)
openCommand("Edit Sketch");
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument());
}
else if (FaceFilter.match() || PlaneFilter.match()) {
else if ( FaceFilter.match() || PlaneFilter.match() ) {
if (!pcActiveBody) {
// We shouldn't make a new Body in this case, because that means
// the source shape of the face/plane would be outside the Body.
PartDesignGui::getBody( /* messageIfNot = */ true );
return;
}
// get the selected object
std::string supportString;
App::DocumentObject* obj;
@@ -385,6 +406,7 @@ void CmdPartDesignNewSketch::activated(int iMsg)
supportString = std::string("(App.activeDocument().") + obj->getNameInDocument() + ", '')";
}
if (!pcActiveBody->hasObject(obj)) {
if ( !obj->isDerivedFrom ( App::Plane::getClassTypeId() ) ) {
// TODO check here if the plane associated with right part/body (2015-09-01, Fat-Zer)
@@ -436,39 +458,49 @@ void CmdPartDesignNewSketch::activated(int iMsg)
doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
}
else {
// Get a valid plane from the user
unsigned validPlanes = 0;
auto group = App::GeoFeatureGroupExtension::getGroupOfObject ( pcActiveBody );
App::GeoFeatureGroupExtension* geoGroup = nullptr;
if(group)
geoGroup = group->getExtensionByType<App::GeoFeatureGroupExtension>();
App::GeoFeatureGroupExtension *geoGroup( nullptr );
if (pcActiveBody) {
auto group( App::GeoFeatureGroupExtension::getGroupOfObject(pcActiveBody) );
if (group) {
geoGroup = group->getExtensionByType<App::GeoFeatureGroupExtension>();
}
}
std::vector<App::DocumentObject*> planes;
std::vector<PartDesignGui::TaskFeaturePick::featureStatus> status;
// Baseplanes are preaprooved
if ( pcActiveBody ) {
try {
for ( auto plane: pcActiveBody->getOrigin ()->planes() ) {
planes.push_back (plane);
status.push_back(PartDesignGui::TaskFeaturePick::basePlane);
validPlanes++;
}
} catch (const Base::Exception &ex) {
Base::Console().Error ("%s\n", ex.what() );
// Start command early, so undo will undo any Body creation
Gui::Command::openCommand("Create a new Sketch");
if (shouldMakeBody) {
pcActiveBody = PartDesignGui::makeBody(doc);
if ( !pcActiveBody ) {
Base::Console().Error("Failed to create a Body object");
return;
}
}
std::vector<App::DocumentObject*> datumPlanes =
getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId());
// At this point, we have pcActiveBody
unsigned validPlaneCount = 0;
// Baseplanes are preaprooved
try {
for ( auto plane: pcActiveBody->getOrigin ()->planes() ) {
planes.push_back (plane);
status.push_back(PartDesignGui::TaskFeaturePick::basePlane);
validPlaneCount++;
}
} catch (const Base::Exception &ex) {
Base::Console().Error ("%s\n", ex.what() );
}
auto datumPlanes( getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId()) );
for (auto plane: datumPlanes) {
planes.push_back ( plane );
// Check whether this plane belongs to the active body
if ( pcActiveBody && pcActiveBody->hasObject(plane) ) {
if ( !pcActiveBody->isAfterInsertPoint ( plane ) ) {
validPlanes++;
validPlaneCount++;
status.push_back(PartDesignGui::TaskFeaturePick::validFeature);
} else {
status.push_back(PartDesignGui::TaskFeaturePick::afterTip);
@@ -489,34 +521,25 @@ void CmdPartDesignNewSketch::activated(int iMsg)
} else if (pcActiveBody) {
status.push_back ( PartDesignGui::TaskFeaturePick::notInBody );
} else { // if we are outside a body count it as valid
validPlanes++;
validPlaneCount++;
status.push_back(PartDesignGui::TaskFeaturePick::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;
}
auto accepter = [=](const std::vector<App::DocumentObject*>& features) -> bool {
if(features.empty())
return false;
return true;
// Determines if user made a valid selection in dialog
auto accepter = [](const std::vector<App::DocumentObject*>& features) -> bool {
return !features.empty();
};
// Called by dialog when user hits "OK" and accepter returns true
auto worker = [=](const std::vector<App::DocumentObject*>& features) {
App::Plane* plane = static_cast<App::Plane*>(features.front());
std::string FeatName = getUniqueObjectName("Sketch");
std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() +
", [''])";
Gui::Command::openCommand("Create a new Sketch");
Gui::Command::doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str());
Gui::Command::doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str());
Gui::Command::doCommand(Doc,"App.activeDocument().%s.MapMode = '%s'",FeatName.c_str(),Attacher::AttachEngine::getModeName(Attacher::mmFlatFace).c_str());
@@ -527,9 +550,20 @@ void CmdPartDesignNewSketch::activated(int iMsg)
Gui::Command::doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
};
// If there is more than one possibility, show dialog and let user pick plane
if (validPlanes > 1) {
// Called by dialog for "Cancel", or "OK" iff accepter returns false
auto quitter( Gui::Command::abortCommand );
if (validPlaneCount == 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"));
quitter();
return;
} else if (validPlaneCount == 1) {
worker(planes);
} else if (validPlaneCount > 1) {
// Show dialog and let user pick plane
Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
PartDesignGui::TaskDlgFeaturePick *pickDlg = qobject_cast<PartDesignGui::TaskDlgFeaturePick *>(dlg);
if (dlg && !pickDlg) {
@@ -541,18 +575,17 @@ void CmdPartDesignNewSketch::activated(int iMsg)
int ret = msgBox.exec();
if (ret == QMessageBox::Yes)
Gui::Control().closeDialog();
else
else {
quitter();
return;
}
}
if(dlg)
Gui::Control().closeDialog();
Gui::Selection().clearSelection();
Gui::Control().showDialog(new PartDesignGui::TaskDlgFeaturePick(planes, status, accepter, worker));
}
else {
worker(planes);
Gui::Control().showDialog(new PartDesignGui::TaskDlgFeaturePick(planes, status, accepter, worker, quitter));
}
}
}

View File

@@ -79,10 +79,20 @@ void CmdPrimtiveCompAdditive::activated(int iMsg)
if (!PartDesignGui::assureModernWorkflow(doc))
return;
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(true);
// We need either an active Body, or for there to be no Body objects
// (in which case, just make one) to make a new additive shape.
if (!pcActiveBody)
return;
PartDesign::Body *pcActiveBody = PartDesignGui::getBody( /* messageIfNot = */ false );
auto shouldMakeBody( false );
if (pcActiveBody == nullptr) {
if ( doc->getObjectsOfType(PartDesign::Body::getClassTypeId()).empty() ) {
shouldMakeBody = true;
} else {
PartDesignGui::needActiveBodyError();
return;
}
}
Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction);
pcAction->setIcon(pcAction->actions().at(iMsg)->icon());
@@ -91,6 +101,10 @@ void CmdPrimtiveCompAdditive::activated(int iMsg)
auto FeatName( getUniqueObjectName(shapeType) );
Gui::Command::openCommand( (std::string("Make additive ") + shapeType).c_str() );
if (shouldMakeBody) {
pcActiveBody = PartDesignGui::makeBody(doc);
}
Gui::Command::doCommand(
Gui::Command::Doc,
"App.ActiveDocument.addObject(\'PartDesign::Additive%s\',\'%s\')",

View File

@@ -82,6 +82,30 @@ PartDesign::Body *getBody(bool messageIfNot)
return activeBody;
}
void needActiveBodyError(void)
{
QMessageBox::warning( Gui::getMainWindow(),
QObject::tr("Active Body Required"),
QObject::tr("To create a new PartDesign object, there must be "
"an active Body object in the document. Please make "
"one active (double click) or create a new Body.") );
}
PartDesign::Body * makeBody(App::Document *doc)
{
// This is intended as a convenience when starting a new document.
auto bodyName( doc->getUniqueObjectName("Body") );
Gui::Command::doCommand( Gui::Command::Doc,
"App.activeDocument().addObject('PartDesign::Body','%s')",
bodyName.c_str() );
Gui::Command::doCommand( Gui::Command::Gui,
"Gui.activeView().setActiveObject('%s', App.activeDocument().%s)",
PDBODYKEY, bodyName.c_str() );
auto activeView( Gui::Application::Instance->activeView() );
return activeView->getActiveObject<PartDesign::Body*>(PDBODYKEY);
}
PartDesign::Body *getBodyFor(const App::DocumentObject* obj, bool messageIfNot)
{
if(!obj)

View File

@@ -32,6 +32,7 @@ namespace PartDesign {
}
namespace App {
class Document;
class DocumentObject;
class Part;
}
@@ -44,6 +45,13 @@ namespace PartDesignGui {
/// Return active body or show a warning message
PartDesign::Body *getBody(bool messageIfNot);
/// Display error when there are existing Body objects, but none are active
void needActiveBodyError(void);
/// Create a Body object in doc, set it active, and return pointer to it
PartDesign::Body * makeBody(App::Document *doc);
/**
* Finds a body for the given feature. And shows a message if not found
* Also unlike Body::findBodyFor it checks if the active body has the feature first.