Merge pull request #9594 from wwmayer/issue_9549_new
Part: fixes #9549: Part Fuse not working inside Part container
This commit is contained in:
@@ -182,6 +182,15 @@ Return -1 if element visibility is not supported or element not found, 0 if invi
|
||||
in a single group, hence only a single return value.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParent">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the group the object is in or None if it is not part of a group.
|
||||
Note that an object can only be in a single group, hence only a single return
|
||||
value.
|
||||
The parent can be a simple group as with getParentGroup() or a
|
||||
GeoFeature group as with getParentGeoFeatureGroup().</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPathsByOutList">
|
||||
<Documentation>
|
||||
<UserDocu>Get all paths from this object to another object following the OutList.</UserDocu>
|
||||
|
||||
@@ -673,6 +673,24 @@ PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getParent(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
auto grp = getDocumentObjectPtr()->getFirstParent();
|
||||
if(!grp) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
return grp->getPyObject();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
throw Py::RuntimeError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
Py::Boolean DocumentObjectPy::getMustExecute() const
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -291,6 +291,30 @@ std::string Base::Tools::escapeEncodeFilename(const std::string& s)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Base::Tools::quoted(const char* name)
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "\"" << name << "\"";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
std::string Base::Tools::quoted(const std::string& name)
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "\"" << name << "\"";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
std::string Base::Tools::joinList(const std::vector<std::string>& vec,
|
||||
const std::string& sep)
|
||||
{
|
||||
std::stringstream str;
|
||||
for (const auto& it : vec) {
|
||||
str << it << sep;
|
||||
}
|
||||
return str.str();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace Base;
|
||||
|
||||
@@ -274,6 +274,29 @@ struct BaseExport Tools
|
||||
static inline QString fromStdString(const std::string & s) {
|
||||
return QString::fromUtf8(s.c_str(), static_cast<int>(s.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief quoted Creates a quoted string.
|
||||
* @param String to be quoted.
|
||||
* @return A quoted std::string.
|
||||
*/
|
||||
static std::string quoted(const char*);
|
||||
/**
|
||||
* @brief quoted Creates a quoted string.
|
||||
* @param String to be quoted.
|
||||
* @return A quoted std::string.
|
||||
*/
|
||||
static std::string quoted(const std::string&);
|
||||
|
||||
/**
|
||||
* @brief joinList
|
||||
* Join the vector of strings \a vec using the separator \a sep
|
||||
* @param vec
|
||||
* @param sep
|
||||
* @return
|
||||
*/
|
||||
static std::string joinList(const std::vector<std::string>& vec,
|
||||
const std::string& sep = ", ");
|
||||
};
|
||||
|
||||
|
||||
|
||||
107
src/Mod/Part/BOPTools/BOPFeatures.py
Normal file
107
src/Mod/Part/BOPTools/BOPFeatures.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "BOPTools.BOPFeatures module"
|
||||
__author__ = "Werner Mayer"
|
||||
__url__ = "http://www.freecad.org"
|
||||
__doc__ = "Helper class to create the features for Boolean operations."
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
|
||||
class BOPFeatures:
|
||||
def __init__(self, doc):
|
||||
self.doc = doc
|
||||
|
||||
def make_section(self, inputNames):
|
||||
obj = self.doc.addObject("Part::Section", "Section")
|
||||
obj.Base = self.doc.getObject(inputNames[0])
|
||||
obj.Tool = self.doc.getObject(inputNames[1])
|
||||
self.copy_visual_attributes(obj, obj.Base)
|
||||
target = self.move_input_objects([obj.Base, obj.Tool])
|
||||
if target:
|
||||
target.addObject(obj)
|
||||
return obj
|
||||
|
||||
def make_cut(self, inputNames):
|
||||
obj = self.doc.addObject("Part::Cut", "Cut")
|
||||
obj.Base = self.doc.getObject(inputNames[0])
|
||||
obj.Tool = self.doc.getObject(inputNames[1])
|
||||
self.copy_visual_attributes(obj, obj.Base)
|
||||
target = self.move_input_objects([obj.Base, obj.Tool])
|
||||
if target:
|
||||
target.addObject(obj)
|
||||
return obj
|
||||
|
||||
def make_common(self, inputNames):
|
||||
obj = self.doc.addObject("Part::Common", "Common")
|
||||
obj.Base = self.doc.getObject(inputNames[0])
|
||||
obj.Tool = self.doc.getObject(inputNames[1])
|
||||
self.copy_visual_attributes(obj, obj.Base)
|
||||
target = self.move_input_objects([obj.Base, obj.Tool])
|
||||
if target:
|
||||
target.addObject(obj)
|
||||
return obj
|
||||
|
||||
def make_multi_common(self, inputNames):
|
||||
obj = self.doc.addObject("Part::MultiCommon", "Common")
|
||||
obj.Shapes = [self.doc.getObject(name) for name in inputNames]
|
||||
self.copy_visual_attributes(obj, obj.Shapes[0])
|
||||
target = self.move_input_objects(obj.Shapes)
|
||||
if target:
|
||||
target.addObject(obj)
|
||||
return obj
|
||||
|
||||
def make_fuse(self, inputNames):
|
||||
obj = self.doc.addObject("Part::Fuse", "Fusion")
|
||||
obj.Base = self.doc.getObject(inputNames[0])
|
||||
obj.Tool = self.doc.getObject(inputNames[1])
|
||||
self.copy_visual_attributes(obj, obj.Base)
|
||||
target = self.move_input_objects([obj.Base, obj.Tool])
|
||||
if target:
|
||||
target.addObject(obj)
|
||||
return obj
|
||||
|
||||
def make_multi_fuse(self, inputNames):
|
||||
obj = self.doc.addObject("Part::MultiFuse", "Fusion")
|
||||
obj.Shapes = [self.doc.getObject(name) for name in inputNames]
|
||||
self.copy_visual_attributes(obj, obj.Shapes[0])
|
||||
target = self.move_input_objects(obj.Shapes)
|
||||
if target:
|
||||
target.addObject(obj)
|
||||
return obj
|
||||
|
||||
def move_input_objects(self, objects):
|
||||
targetGroup = None
|
||||
for obj in objects:
|
||||
obj.Visibility = False
|
||||
parent = obj.getParent()
|
||||
if parent:
|
||||
parent.removeObject(obj)
|
||||
targetGroup = parent
|
||||
return targetGroup
|
||||
|
||||
def copy_visual_attributes(self, target, source):
|
||||
if target.ViewObject:
|
||||
target.ViewObject.ShapeColor = source.ViewObject.ShapeColor
|
||||
target.ViewObject.DisplayMode = source.ViewObject.DisplayMode
|
||||
@@ -44,6 +44,7 @@ endif(BUILD_GUI)
|
||||
|
||||
set(BOPTools_Scripts
|
||||
BOPTools/__init__.py
|
||||
BOPTools/BOPFeatures.py
|
||||
BOPTools/GeneralFuseResult.py
|
||||
BOPTools/JoinAPI.py
|
||||
BOPTools/JoinFeatures.py
|
||||
|
||||
@@ -316,6 +316,7 @@ void CmdPartCut::activated(int iMsg)
|
||||
}
|
||||
|
||||
bool askUser = false;
|
||||
std::vector<std::string> names;
|
||||
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
|
||||
App::DocumentObject* obj = it->getObject();
|
||||
const TopoDS_Shape& shape = Part::Feature::getShape(obj);
|
||||
@@ -327,34 +328,14 @@ void CmdPartCut::activated(int iMsg)
|
||||
return;
|
||||
askUser = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string FeatName = getUniqueObjectName("Cut");
|
||||
names.push_back(Base::Tools::quoted(it->getFeatName()));
|
||||
}
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Part Cut"));
|
||||
doCommand(Doc,"App.activeDocument().addObject(\"Part::Cut\",\"%s\")",FeatName.c_str());
|
||||
doCommand(Doc,"App.activeDocument().%s.Base = App.activeDocument().%s",FeatName.c_str(),Sel[0].getFeatName());
|
||||
doCommand(Doc,"App.activeDocument().%s.Tool = App.activeDocument().%s",FeatName.c_str(),Sel[1].getFeatName());
|
||||
|
||||
// hide the input objects and remove them from the parent group
|
||||
App::DocumentObjectGroup* targetGroup = nullptr;
|
||||
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
|
||||
doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->getFeatName());
|
||||
App::DocumentObjectGroup* group = it->getObject()->getGroup();
|
||||
if (group) {
|
||||
targetGroup = group;
|
||||
doCommand(Doc, "App.activeDocument().%s.removeObject(App.activeDocument().%s)",
|
||||
group->getNameInDocument(), it->getFeatName());
|
||||
}
|
||||
}
|
||||
|
||||
if (targetGroup) {
|
||||
doCommand(Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)",
|
||||
targetGroup->getNameInDocument(), FeatName.c_str());
|
||||
}
|
||||
|
||||
copyVisual(FeatName.c_str(), "ShapeColor", Sel[0].getFeatName());
|
||||
copyVisual(FeatName.c_str(), "DisplayMode", Sel[0].getFeatName());
|
||||
doCommand(Doc, "from BOPTools import BOPFeatures");
|
||||
doCommand(Doc, "bp = BOPFeatures.BOPFeatures(App.activeDocument())");
|
||||
doCommand(Doc, "bp.make_cut([%s])", Base::Tools::joinList(names).c_str());
|
||||
updateActive();
|
||||
commitCommand();
|
||||
}
|
||||
@@ -411,11 +392,7 @@ void CmdPartCommon::activated(int iMsg)
|
||||
}
|
||||
|
||||
bool askUser = false;
|
||||
std::string FeatName = getUniqueObjectName("Common");
|
||||
std::stringstream str;
|
||||
std::vector<Gui::SelectionObject> partObjects;
|
||||
|
||||
str << "App.activeDocument()." << FeatName << ".Shapes = [";
|
||||
std::vector<std::string> names;
|
||||
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
|
||||
App::DocumentObject* obj = it->getObject();
|
||||
const TopoDS_Shape& shape = Part::Feature::getShape(obj);
|
||||
@@ -427,34 +404,14 @@ void CmdPartCommon::activated(int iMsg)
|
||||
return;
|
||||
askUser = true;
|
||||
}
|
||||
str << "App.activeDocument()." << it->getFeatName() << ",";
|
||||
partObjects.push_back(*it);
|
||||
|
||||
names.push_back(Base::Tools::quoted(it->getFeatName()));
|
||||
}
|
||||
str << "]";
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Common"));
|
||||
doCommand(Doc,"App.activeDocument().addObject(\"Part::MultiCommon\",\"%s\")",FeatName.c_str());
|
||||
runCommand(Doc,str.str().c_str());
|
||||
|
||||
// hide the input objects and remove them from the parent group
|
||||
App::DocumentObjectGroup* targetGroup = nullptr;
|
||||
for (std::vector<Gui::SelectionObject>::iterator it = partObjects.begin(); it != partObjects.end(); ++it) {
|
||||
doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->getFeatName());
|
||||
App::DocumentObjectGroup* group = it->getObject()->getGroup();
|
||||
if (group) {
|
||||
targetGroup = group;
|
||||
doCommand(Doc, "App.activeDocument().%s.removeObject(App.activeDocument().%s)",
|
||||
group->getNameInDocument(), it->getFeatName());
|
||||
}
|
||||
}
|
||||
|
||||
if (targetGroup) {
|
||||
doCommand(Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)",
|
||||
targetGroup->getNameInDocument(), FeatName.c_str());
|
||||
}
|
||||
|
||||
copyVisual(FeatName.c_str(), "ShapeColor", partObjects.front().getFeatName());
|
||||
copyVisual(FeatName.c_str(), "DisplayMode", partObjects.front().getFeatName());
|
||||
doCommand(Doc, "from BOPTools import BOPFeatures");
|
||||
doCommand(Doc, "bp = BOPFeatures.BOPFeatures(App.activeDocument())");
|
||||
doCommand(Doc, "bp.make_multi_common([%s])", Base::Tools::joinList(names).c_str());
|
||||
updateActive();
|
||||
commitCommand();
|
||||
}
|
||||
@@ -511,11 +468,7 @@ void CmdPartFuse::activated(int iMsg)
|
||||
}
|
||||
|
||||
bool askUser = false;
|
||||
std::string FeatName = getUniqueObjectName("Fusion");
|
||||
std::stringstream str;
|
||||
std::vector<Gui::SelectionObject> partObjects;
|
||||
|
||||
str << "App.activeDocument()." << FeatName << ".Shapes = [";
|
||||
std::vector<std::string> names;
|
||||
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
|
||||
App::DocumentObject* obj = it->getObject();
|
||||
const TopoDS_Shape& shape = Part::Feature::getShape(obj);
|
||||
@@ -527,34 +480,14 @@ void CmdPartFuse::activated(int iMsg)
|
||||
return;
|
||||
askUser = true;
|
||||
}
|
||||
str << "App.activeDocument()." << it->getFeatName() << ",";
|
||||
partObjects.push_back(*it);
|
||||
|
||||
names.push_back(Base::Tools::quoted(it->getFeatName()));
|
||||
}
|
||||
str << "]";
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Fusion"));
|
||||
doCommand(Doc,"App.activeDocument().addObject(\"Part::MultiFuse\",\"%s\")",FeatName.c_str());
|
||||
runCommand(Doc,str.str().c_str());
|
||||
|
||||
// hide the input objects and remove them from the parent group
|
||||
App::DocumentObjectGroup* targetGroup = nullptr;
|
||||
for (std::vector<Gui::SelectionObject>::iterator it = partObjects.begin(); it != partObjects.end(); ++it) {
|
||||
doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->getFeatName());
|
||||
App::DocumentObjectGroup* group = it->getObject()->getGroup();
|
||||
if (group) {
|
||||
targetGroup = group;
|
||||
doCommand(Doc, "App.activeDocument().%s.removeObject(App.activeDocument().%s)",
|
||||
group->getNameInDocument(), it->getFeatName());
|
||||
}
|
||||
}
|
||||
|
||||
if (targetGroup) {
|
||||
doCommand(Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)",
|
||||
targetGroup->getNameInDocument(), FeatName.c_str());
|
||||
}
|
||||
|
||||
copyVisual(FeatName.c_str(), "ShapeColor", partObjects.front().getFeatName());
|
||||
copyVisual(FeatName.c_str(), "DisplayMode", partObjects.front().getFeatName());
|
||||
doCommand(Doc, "from BOPTools import BOPFeatures");
|
||||
doCommand(Doc, "bp = BOPFeatures.BOPFeatures(App.activeDocument())");
|
||||
doCommand(Doc, "bp.make_multi_fuse([%s])", Base::Tools::joinList(names).c_str());
|
||||
updateActive();
|
||||
commitCommand();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
@@ -405,7 +406,7 @@ void DlgBooleanOperation::accept()
|
||||
return;
|
||||
}
|
||||
|
||||
std::string type, objName;
|
||||
std::string method;
|
||||
App::DocumentObject* obj1 = activeDoc->getObject(shapeOne.c_str());
|
||||
App::DocumentObject* obj2 = activeDoc->getObject(shapeTwo.c_str());
|
||||
if (!obj1 || !obj2) {
|
||||
@@ -421,8 +422,7 @@ void DlgBooleanOperation::accept()
|
||||
tr("Performing union on non-solids is not possible"));
|
||||
return;
|
||||
}
|
||||
type = "Part::Fuse";
|
||||
objName = activeDoc->getUniqueObjectName("Fusion");
|
||||
method = "make_fuse";
|
||||
}
|
||||
else if (ui->interButton->isChecked()) {
|
||||
if (!hasSolids(obj1) || !hasSolids(obj2)) {
|
||||
@@ -430,8 +430,7 @@ void DlgBooleanOperation::accept()
|
||||
tr("Performing intersection on non-solids is not possible"));
|
||||
return;
|
||||
}
|
||||
type = "Part::Common";
|
||||
objName = activeDoc->getUniqueObjectName("Common");
|
||||
method = "make_common";
|
||||
}
|
||||
else if (ui->diffButton->isChecked()) {
|
||||
if (!hasSolids(obj1) || !hasSolids(obj2)) {
|
||||
@@ -439,55 +438,24 @@ void DlgBooleanOperation::accept()
|
||||
tr("Performing difference on non-solids is not possible"));
|
||||
return;
|
||||
}
|
||||
type = "Part::Cut";
|
||||
objName = activeDoc->getUniqueObjectName("Cut");
|
||||
method = "make_cut";
|
||||
}
|
||||
else if (ui->sectionButton->isChecked()) {
|
||||
type = "Part::Section";
|
||||
objName = activeDoc->getUniqueObjectName("Section");
|
||||
method = "make_section";
|
||||
}
|
||||
|
||||
try {
|
||||
Gui::WaitCursor wc;
|
||||
activeDoc->openTransaction("Boolean operation");
|
||||
std::vector<std::string> names;
|
||||
names.push_back(Base::Tools::quoted(shapeOne.c_str()));
|
||||
names.push_back(Base::Tools::quoted(shapeTwo.c_str()));
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
"App.activeDocument().addObject(\"%s\",\"%s\")",
|
||||
type.c_str(), objName.c_str());
|
||||
"from BOPTools import BOPFeatures");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
"App.activeDocument().%s.Base = App.activeDocument().%s",
|
||||
objName.c_str(),shapeOne.c_str());
|
||||
"bp = BOPFeatures.BOPFeatures(App.activeDocument())");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
"App.activeDocument().%s.Tool = App.activeDocument().%s",
|
||||
objName.c_str(),shapeTwo.c_str());
|
||||
Gui::Command::doCommand(Gui::Command::Gui,
|
||||
"Gui.activeDocument().hide(\"%s\")",shapeOne.c_str());
|
||||
Gui::Command::doCommand(Gui::Command::Gui,
|
||||
"Gui.activeDocument().hide(\"%s\")",shapeTwo.c_str());
|
||||
|
||||
// add/remove fromgroup if needed
|
||||
App::DocumentObjectGroup* targetGroup = nullptr;
|
||||
|
||||
App::DocumentObjectGroup* group1 = obj1->getGroup();
|
||||
if (group1) {
|
||||
targetGroup = group1;
|
||||
Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.removeObject(App.activeDocument().%s)",
|
||||
group1->getNameInDocument(), obj1->getNameInDocument());
|
||||
}
|
||||
|
||||
App::DocumentObjectGroup* group2 = obj2->getGroup();
|
||||
if (group2) {
|
||||
targetGroup = group2;
|
||||
Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.removeObject(App.activeDocument().%s)",
|
||||
group2->getNameInDocument(), obj2->getNameInDocument());
|
||||
}
|
||||
|
||||
if (targetGroup) {
|
||||
Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.addObject(App.activeDocument().%s)",
|
||||
targetGroup->getNameInDocument(), objName.c_str());
|
||||
}
|
||||
|
||||
Gui::Command::copyVisual(objName.c_str(), "ShapeColor", shapeOne.c_str());
|
||||
Gui::Command::copyVisual(objName.c_str(), "DisplayMode", shapeOne.c_str());
|
||||
"bp.%s([%s])", method.c_str(), Base::Tools::joinList(names).c_str());
|
||||
activeDoc->commitTransaction();
|
||||
activeDoc->recompute();
|
||||
}
|
||||
|
||||
@@ -831,3 +831,43 @@ class PartTestShapeFix(unittest.TestCase):
|
||||
fix.fixGap3d(1, False)
|
||||
fix.fixGap2d(1, False)
|
||||
fix.fixTails()
|
||||
|
||||
class PartBOPTestContainer(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.Doc = FreeCAD.newDocument()
|
||||
|
||||
def testMakeFuse(self):
|
||||
box = self.Doc.addObject("Part::Box", "Box")
|
||||
cyl = self.Doc.addObject("Part::Cylinder", "Cylinder")
|
||||
part = self.Doc.addObject("App::Part", "Part")
|
||||
part.addObject(box)
|
||||
part.addObject(cyl)
|
||||
from BOPTools import BOPFeatures
|
||||
bp = BOPFeatures.BOPFeatures(self.Doc)
|
||||
fuse = bp.make_multi_fuse([cyl.Name, box.Name])
|
||||
self.assertEqual(part, fuse.getParent())
|
||||
|
||||
def testMakeCut(self):
|
||||
box = self.Doc.addObject("Part::Box", "Box")
|
||||
cyl = self.Doc.addObject("Part::Cylinder", "Cylinder")
|
||||
part = self.Doc.addObject("App::Part", "Part")
|
||||
part.addObject(box)
|
||||
part.addObject(cyl)
|
||||
from BOPTools import BOPFeatures
|
||||
bp = BOPFeatures.BOPFeatures(self.Doc)
|
||||
fuse = bp.make_cut([cyl.Name, box.Name])
|
||||
self.assertEqual(part, fuse.getParent())
|
||||
|
||||
def testMakeCommon(self):
|
||||
box = self.Doc.addObject("Part::Box", "Box")
|
||||
cyl = self.Doc.addObject("Part::Cylinder", "Cylinder")
|
||||
part = self.Doc.addObject("App::Part", "Part")
|
||||
part.addObject(box)
|
||||
part.addObject(cyl)
|
||||
from BOPTools import BOPFeatures
|
||||
bp = BOPFeatures.BOPFeatures(self.Doc)
|
||||
fuse = bp.make_multi_common([cyl.Name, box.Name])
|
||||
self.assertEqual(part, fuse.getParent())
|
||||
|
||||
def tearDown(self):
|
||||
FreeCAD.closeDocument(self.Doc.Name)
|
||||
|
||||
@@ -40,3 +40,13 @@ TEST(BaseToolsSuite, TestUniqueName8)
|
||||
{
|
||||
EXPECT_EQ(Base::Tools::getUniqueName("Body12345", {"Body"}, 3), "Body12346");
|
||||
}
|
||||
|
||||
TEST(BaseToolsSuite, TestQuote)
|
||||
{
|
||||
EXPECT_EQ(Base::Tools::quoted("Test"), "\"Test\"");
|
||||
}
|
||||
|
||||
TEST(BaseToolsSuite, TestJoinList)
|
||||
{
|
||||
EXPECT_EQ(Base::Tools::joinList({"AB", "CD"}), "AB, CD, ");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user