diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp
index d7a166ba5..7c054f8de 100644
--- a/src/Mod/PartDesign/Gui/Workbench.cpp
+++ b/src/Mod/PartDesign/Gui/Workbench.cpp
@@ -105,8 +105,215 @@ PartDesign::Body *Workbench::setUpPart(const App::Part *part)
return NULL;
}
+void Workbench::_doMigration(const App::Document* doc)
+{
-void switchToDocument(const App::Document* doc)
+ if(doc->countObjects() != 0) {
+ // show a warning about the convertion
+ Gui::Dialog::DlgCheckableMessageBox::showMessage(
+ QString::fromLatin1("PartDesign conversion warning"),
+ QString::fromLatin1(
+ "
Converting PartDesign features to new Body centric schema
"
+ "If you are unsure what that mean save the document under a new name.
"
+ "You will not be able to load your work in an older Version of FreeCAD,
"
+ "After the translation took place...
"
+ "More information you will find here:
"
+ " http://www.freecadweb.org/wiki/index.php?title=Assembly_project
"
+ "Or the Assembly dedicated portion of our forum:
"
+ " http://forum.freecadweb.org/
"
+ ),
+ false,
+ QString::fromLatin1("Don't tell me again, I know!")
+ );
+ }
+
+ Gui::Command::openCommand("Migrate part to Body feature");
+
+ // Get the objects now, before adding the Body and the base planes
+ std::vector features = doc->getObjects();
+
+ // Assign all non-PartDesign features to a new group
+ for (std::vector::iterator f = features.begin(); f != features.end(); ) {
+ if ((*f)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) ||
+ (*f)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) {
+ ++f;
+ } else {
+ if (!groupCreated) {
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','NonBodyFeatures')");
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'",
+ QObject::tr("NonBodyFeatures").toStdString().c_str());
+ groupCreated = true;
+ }
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().NonBodyFeatures.addObject(App.activeDocument().getObject('%s'))",
+ (*f)->getNameInDocument());
+ f = features.erase(f);
+ }
+ }
+ // TODO: Fold the group (is that possible through the Python interface?)
+
+ // Try to find the root(s) of the model tree (the features that depend on no other feature)
+ // Note: We assume a linear graph, except for MultiTransform features
+ std::vector roots;
+ for (std::vector::iterator f = features.begin(); f != features.end(); f++) {
+ // Note: The dependency list always contains at least the object itself
+ std::vector ftemp;
+ ftemp.push_back(*f);
+ if (doc->getDependencyList(ftemp).size() == 1)
+ roots.push_back(*f);
+ }
+
+ // Always create at least the first body, even if the document is empty
+ // This adds both the base planes and the body
+ Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')");
+ activeBody = PartDesignGui::ActivePartObject;
+
+
+ // Create one Body for every root and put the appropriate features into it
+ for (std::vector::iterator r = roots.begin(); r != roots.end(); r++) {
+ if (r != roots.begin()) {
+ Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')");
+ activeBody = PartDesignGui::ActivePartObject;
+ }
+
+ std::set inList;
+ inList.insert(*r); // start with the root feature
+ std::vector bodyFeatures;
+ std::string modelString = "";
+ do {
+ for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) {
+ std::vector::iterator feat = std::find(features.begin(), features.end(), *o);
+ if (feat != features.end()) {
+ bodyFeatures.push_back(*o);
+ modelString += std::string(modelString.empty() ? "" : ",") + "App.ActiveDocument." + (*o)->getNameInDocument();
+ features.erase(feat);
+ } else {
+ QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Non-linear tree"),
+ QObject::tr("Please look at '") + QString::fromAscii((*o)->getNameInDocument()) +
+ QObject::tr("' and make sure that the migration result is what you would expect."));
+ }
+ }
+ std::set newInList;
+ for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) {
+ // Omit members of a MultiTransform from the inList, to avoid migration errors
+ if (PartDesign::Body::isMemberOfMultiTransform(*o))
+ continue;
+ std::vector iL = doc->getInList(*o);
+ newInList.insert(iL.begin(), iL.end());
+ }
+ inList = newInList; // TODO: Memory leak? Unnecessary copying?
+ } while (!inList.empty());
+
+ if (!modelString.empty()) {
+ modelString = std::string("[") + modelString + "]";
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Model = %s", activeBody->getNameInDocument(), modelString.c_str());
+ // Set the Tip, but not to a member of a MultiTransform!
+ for (std::vector::const_reverse_iterator f = bodyFeatures.rbegin(); f != bodyFeatures.rend(); f++) {
+ if (PartDesign::Body::isMemberOfMultiTransform(*f))
+ continue;
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",
+ activeBody->getNameInDocument(), (*f)->getNameInDocument());
+ break;
+ }
+ }
+
+ // Initialize the BaseFeature property of all PartDesign solid features
+ App::DocumentObject* baseFeature = NULL;
+ for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) {
+ if (PartDesign::Body::isSolidFeature(*f)) {
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = %s",
+ (*f)->getNameInDocument(),
+ baseFeature == NULL ?
+ "None" :
+ (std::string("App.activeDocument().") + baseFeature->getNameInDocument()).c_str());
+
+ baseFeature = *f;
+ }
+ }
+
+ // Re-route all sketches without support to the base planes
+ std::vector::const_iterator prevf;
+
+ for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) {
+ if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) {
+ Sketcher::SketchObject* sketch = static_cast(*f);
+ App::DocumentObject* support = sketch->Support.getValue();
+ if (support != NULL)
+ continue; // Sketch is on a face of a solid
+ Base::Placement plm = sketch->Placement.getValue();
+ Base::Vector3d pnt = plm.getPosition();
+
+ // Currently we only handle positions that are parallel to the base planes
+ Base::Rotation rot = plm.getRotation();
+ Base::Vector3d SketchVector(0,0,1);
+ rot.multVec(SketchVector, SketchVector);
+ std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front";
+ if (side == "back") SketchVector *= -1.0;
+ int index;
+
+ if (SketchVector == Base::Vector3d(0,0,1))
+ index = 0;
+ else if (SketchVector == Base::Vector3d(0,1,0))
+ index = 1;
+ else if (SketchVector == Base::Vector3d(1,0,0))
+ index = 2;
+ else {
+ QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"),
+ QObject::tr("Please edit '") + QString::fromAscii(sketch->getNameInDocument()) +
+ QObject::tr("' and redefine it to use a Base or Datum plane as the sketch plane."));
+ continue;
+ }
+
+ // Find the normal distance from origin to the sketch plane
+ gp_Pln pln(gp_Pnt (pnt.x, pnt.y, pnt.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z));
+ double offset = pln.Distance(gp_Pnt(0,0,0));
+
+ if (fabs(offset) < Precision::Confusion()) {
+ // One of the base planes
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])",
+ sketch->getNameInDocument(), BaseplaneNames[index], side.c_str());
+ } else {
+ // Offset to base plane
+ // Find out which direction we need to offset
+ double a = SketchVector.GetAngle(pnt);
+ if ((a < -M_PI_2) || (a > M_PI_2))
+ offset *= -1.0;
+
+ // Insert a new datum plane before the sketch
+ App::DocumentObject* oldTip = activeBody->Tip.getValue();
+ Gui::Selection().clearSelection();
+ if (f != bodyFeatures.begin())
+ Gui::Selection().addSelection(doc->getName(), (*prevf)->getNameInDocument());
+ Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')");
+
+ std::string Datum = doc->getUniqueObjectName("DatumPlane");
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",Datum.c_str());
+ QString refStr = QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(BaseplaneNames[index]) +
+ QString::fromAscii(",'')]");
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.References = %s",Datum.c_str(), refStr.toStdString().c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Offset = %f",Datum.c_str(), offset);
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)",
+ activeBody->getNameInDocument(), Datum.c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])",
+ sketch->getNameInDocument(), Datum.c_str(), side.c_str());
+ Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references
+
+ Gui::Selection().clearSelection();
+ if (oldTip != NULL) {
+ Gui::Selection().addSelection(doc->getName(), oldTip->getNameInDocument());
+ Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')");
+ Gui::Selection().clearSelection();
+ }
+ }
+ }
+
+ prevf = f;
+ }
+ }
+
+}
+
+void Workbench::_switchToDocument(const App::Document* doc)
{
bool groupCreated = false;
@@ -117,211 +324,12 @@ void switchToDocument(const App::Document* doc)
std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId());
// Is there a body feature in this document?
- if (bodies.empty()) {
-
- if(doc->countObjects() != 0) {
- // show a warning about the convertion
- Gui::Dialog::DlgCheckableMessageBox::showMessage(
- QString::fromLatin1("PartDesign conversion warning"),
- QString::fromLatin1(
- "Converting PartDesign features to new Body centric schema
"
- "If you are unsure what that mean save the document under a new name.
"
- "You will not be able to load your work in an older Version of FreeCAD,
"
- "After the translation took place...
"
- "More information you will find here:
"
- " http://www.freecadweb.org/wiki/index.php?title=Assembly_project
"
- "Or the Assembly dedicated portion of our forum:
"
- " http://forum.freecadweb.org/
"
- ),
- false,
- QString::fromLatin1("Don't tell me again, I know!")
- );
- }
-
- Gui::Command::openCommand("Migrate part to Body feature");
-
- // Get the objects now, before adding the Body and the base planes
- std::vector features = doc->getObjects();
-
- // Assign all non-PartDesign features to a new group
- for (std::vector::iterator f = features.begin(); f != features.end(); ) {
- if ((*f)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) ||
- (*f)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) {
- ++f;
- } else {
- if (!groupCreated) {
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','NonBodyFeatures')");
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'",
- QObject::tr("NonBodyFeatures").toStdString().c_str());
- groupCreated = true;
- }
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().NonBodyFeatures.addObject(App.activeDocument().getObject('%s'))",
- (*f)->getNameInDocument());
- f = features.erase(f);
- }
- }
- // TODO: Fold the group (is that possible through the Python interface?)
-
- // Try to find the root(s) of the model tree (the features that depend on no other feature)
- // Note: We assume a linear graph, except for MultiTransform features
- std::vector roots;
- for (std::vector::iterator f = features.begin(); f != features.end(); f++) {
- // Note: The dependency list always contains at least the object itself
- std::vector ftemp;
- ftemp.push_back(*f);
- if (doc->getDependencyList(ftemp).size() == 1)
- roots.push_back(*f);
- }
-
- // Always create at least the first body, even if the document is empty
- // This adds both the base planes and the body
- Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')");
- activeBody = PartDesignGui::ActivePartObject;
-
-
- // Create one Body for every root and put the appropriate features into it
- for (std::vector::iterator r = roots.begin(); r != roots.end(); r++) {
- if (r != roots.begin()) {
- Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')");
- activeBody = PartDesignGui::ActivePartObject;
- }
-
- std::set inList;
- inList.insert(*r); // start with the root feature
- std::vector bodyFeatures;
- std::string modelString = "";
- do {
- for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) {
- std::vector::iterator feat = std::find(features.begin(), features.end(), *o);
- if (feat != features.end()) {
- bodyFeatures.push_back(*o);
- modelString += std::string(modelString.empty() ? "" : ",") + "App.ActiveDocument." + (*o)->getNameInDocument();
- features.erase(feat);
- } else {
- QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Non-linear tree"),
- QObject::tr("Please look at '") + QString::fromAscii((*o)->getNameInDocument()) +
- QObject::tr("' and make sure that the migration result is what you would expect."));
- }
- }
- std::set newInList;
- for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) {
- // Omit members of a MultiTransform from the inList, to avoid migration errors
- if (PartDesign::Body::isMemberOfMultiTransform(*o))
- continue;
- std::vector iL = doc->getInList(*o);
- newInList.insert(iL.begin(), iL.end());
- }
- inList = newInList; // TODO: Memory leak? Unnecessary copying?
- } while (!inList.empty());
-
- if (!modelString.empty()) {
- modelString = std::string("[") + modelString + "]";
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Model = %s", activeBody->getNameInDocument(), modelString.c_str());
- // Set the Tip, but not to a member of a MultiTransform!
- for (std::vector::const_reverse_iterator f = bodyFeatures.rbegin(); f != bodyFeatures.rend(); f++) {
- if (PartDesign::Body::isMemberOfMultiTransform(*f))
- continue;
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",
- activeBody->getNameInDocument(), (*f)->getNameInDocument());
- break;
- }
- }
-
- // Initialize the BaseFeature property of all PartDesign solid features
- App::DocumentObject* baseFeature = NULL;
- for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) {
- if (PartDesign::Body::isSolidFeature(*f)) {
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = %s",
- (*f)->getNameInDocument(),
- baseFeature == NULL ?
- "None" :
- (std::string("App.activeDocument().") + baseFeature->getNameInDocument()).c_str());
-
- baseFeature = *f;
- }
- }
-
- // Re-route all sketches without support to the base planes
- std::vector::const_iterator prevf;
-
- for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) {
- if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) {
- Sketcher::SketchObject* sketch = static_cast(*f);
- App::DocumentObject* support = sketch->Support.getValue();
- if (support != NULL)
- continue; // Sketch is on a face of a solid
- Base::Placement plm = sketch->Placement.getValue();
- Base::Vector3d pnt = plm.getPosition();
-
- // Currently we only handle positions that are parallel to the base planes
- Base::Rotation rot = plm.getRotation();
- Base::Vector3d SketchVector(0,0,1);
- rot.multVec(SketchVector, SketchVector);
- std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front";
- if (side == "back") SketchVector *= -1.0;
- int index;
-
- if (SketchVector == Base::Vector3d(0,0,1))
- index = 0;
- else if (SketchVector == Base::Vector3d(0,1,0))
- index = 1;
- else if (SketchVector == Base::Vector3d(1,0,0))
- index = 2;
- else {
- QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"),
- QObject::tr("Please edit '") + QString::fromAscii(sketch->getNameInDocument()) +
- QObject::tr("' and redefine it to use a Base or Datum plane as the sketch plane."));
- continue;
- }
-
- // Find the normal distance from origin to the sketch plane
- gp_Pln pln(gp_Pnt (pnt.x, pnt.y, pnt.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z));
- double offset = pln.Distance(gp_Pnt(0,0,0));
-
- if (fabs(offset) < Precision::Confusion()) {
- // One of the base planes
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])",
- sketch->getNameInDocument(), BaseplaneNames[index], side.c_str());
- } else {
- // Offset to base plane
- // Find out which direction we need to offset
- double a = SketchVector.GetAngle(pnt);
- if ((a < -M_PI_2) || (a > M_PI_2))
- offset *= -1.0;
-
- // Insert a new datum plane before the sketch
- App::DocumentObject* oldTip = activeBody->Tip.getValue();
- Gui::Selection().clearSelection();
- if (f != bodyFeatures.begin())
- Gui::Selection().addSelection(doc->getName(), (*prevf)->getNameInDocument());
- Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')");
-
- std::string Datum = doc->getUniqueObjectName("DatumPlane");
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",Datum.c_str());
- QString refStr = QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(BaseplaneNames[index]) +
- QString::fromAscii(",'')]");
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.References = %s",Datum.c_str(), refStr.toStdString().c_str());
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Offset = %f",Datum.c_str(), offset);
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str());
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)",
- activeBody->getNameInDocument(), Datum.c_str());
- Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])",
- sketch->getNameInDocument(), Datum.c_str(), side.c_str());
- Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references
-
- Gui::Selection().clearSelection();
- if (oldTip != NULL) {
- Gui::Selection().addSelection(doc->getName(), oldTip->getNameInDocument());
- Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')");
- Gui::Selection().clearSelection();
- }
- }
- }
-
- prevf = f;
- }
- }
- } else {
+ if (bodies.empty())
+ {
+ _doMigration(doc);
+ }
+ else
+ {
// Find active body
for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) {
PartDesign::Body* body = static_cast(*b);
diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h
index 3e9cd2853..0de375b0d 100644
--- a/src/Mod/PartDesign/Gui/Workbench.h
+++ b/src/Mod/PartDesign/Gui/Workbench.h
@@ -100,6 +100,10 @@ private:
void slotDeleteDocument(const App::Document&);
// Add new objects to the body, if appropriate
//void slotNewObject(const App::DocumentObject& obj);
+
+ void _doMigration(const App::Document* doc);
+ void _switchToDocument(const App::Document* doc);
+
};
} // namespace PartDesignGui