Make Body object on creation of Sketch/Primitive
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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\')",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user