Merge branch 'main' into bgbsww-toponamingMakeElementSolid

This commit is contained in:
bgbsww
2024-02-22 20:06:51 -05:00
committed by GitHub
23 changed files with 776 additions and 191 deletions

View File

@@ -20,7 +20,11 @@
* *
****************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <iostream>
#endif
#include "VarSet.h"
#include "DocumentObject.h"

View File

@@ -145,8 +145,8 @@
#include "UiLoader.h"
#include "MetaTypes.h"
#ifdef HAVE_SHIBOKEN
#ifdef HAVE_SHIBOKEN2
// NOLINTBEGIN
#if defined(HAVE_SHIBOKEN2)
PyTypeObject** SbkPySide2_QtCoreTypes = nullptr;
PyTypeObject** SbkPySide2_QtGuiTypes = nullptr;
PyTypeObject** SbkPySide2_QtWidgetsTypes = nullptr;
@@ -157,8 +157,11 @@ constexpr auto &SbkPySide_QtGuiTypes = SbkPySide2_QtGuiTypes;
constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide2_QtWidgetsTypes;
constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide2_QtPrintSupportTypes;
constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide2_QtUiToolsTypes;
#if !defined(HAVE_PYSIDE2)
constexpr const char* ModuleShiboken = "shiboken2";
#endif
constexpr const char* ModulePySide = "PySide2";
#else
#elif defined(HAVE_SHIBOKEN6)
PyTypeObject** SbkPySide6_QtCoreTypes = nullptr;
PyTypeObject** SbkPySide6_QtGuiTypes = nullptr;
PyTypeObject** SbkPySide6_QtWidgetsTypes = nullptr;
@@ -169,8 +172,10 @@ constexpr auto &SbkPySide_QtGuiTypes = SbkPySide6_QtGuiTypes;
constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide6_QtWidgetsTypes;
constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide6_QtPrintSupportTypes;
constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide6_QtUiToolsTypes;
constexpr const char* ModulePySide = "PySide6";
#if !defined(HAVE_PYSIDE6)
constexpr const char* ModuleShiboken = "shiboken6";
#endif
constexpr const char* ModulePySide = "PySide6";
#else
static PyTypeObject** SbkPySide_DummyTypes;
constexpr auto &SbkPySide_QtCoreTypes = SbkPySide_DummyTypes;
@@ -186,6 +191,7 @@ constexpr const char* ModuleShiboken = "shiboken6";
constexpr const char* ModulePySide = "PySide6";
# endif
#endif
// NOLINTEND
using namespace Gui;
@@ -201,7 +207,8 @@ using namespace Gui;
\endcode
*/
PyObject* toPythonFuncQuantityTyped(Base::Quantity cpx) {
PyObject* toPythonFuncQuantityTyped(Base::Quantity cpx)
{
return new Base::QuantityPy(new Base::Quantity(cpx));
}
@@ -212,13 +219,14 @@ PyObject* toPythonFuncQuantity(const void* cpp)
void toCppPointerConvFuncQuantity(PyObject* pyobj,void* cpp)
{
*((Base::Quantity*)cpp) = *static_cast<Base::QuantityPy*>(pyobj)->getQuantityPtr();
*static_cast<Base::Quantity*>(cpp) = *static_cast<Base::QuantityPy*>(pyobj)->getQuantityPtr();
}
PythonToCppFunc toCppPointerCheckFuncQuantity(PyObject* obj)
{
if (PyObject_TypeCheck(obj, &(Base::QuantityPy::Type)))
if (PyObject_TypeCheck(obj, &(Base::QuantityPy::Type))) {
return toCppPointerConvFuncQuantity;
}
return nullptr;
}
@@ -230,8 +238,9 @@ void BaseQuantity_PythonToCpp_QVariant(PyObject* pyIn, void* cppOut)
PythonToCppFunc isBaseQuantity_PythonToCpp_QVariantConvertible(PyObject* obj)
{
if (PyObject_TypeCheck(obj, &(Base::QuantityPy::Type)))
if (PyObject_TypeCheck(obj, &(Base::QuantityPy::Type))) {
return BaseQuantity_PythonToCpp_QVariant;
}
return nullptr;
}
@@ -289,8 +298,9 @@ static bool loadPySideModule(const std::string& moduleName, PyTypeObject**& type
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
if (!types) {
Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(getPySideModuleName(moduleName).c_str()));
if (requiredModule.isNull())
if (requiredModule.isNull()) {
return false;
}
types = Shiboken::Module::getTypes(requiredModule);
}
#else
@@ -312,8 +322,9 @@ getPyTypeObjectForTypeName()
#if defined (HAVE_SHIBOKEN_TYPE_FOR_TYPENAME)
# if defined (HAVE_SHIBOKEN2)
auto sbkType = Shiboken::ObjectType::typeForTypeName(typeid(qttype).name());
if (sbkType)
if (sbkType) {
return reinterpret_cast<SbkObjectType*>&(sbkType->type);
}
# else
return Shiboken::ObjectType::typeForTypeName(typeid(qttype).name());
# endif
@@ -379,16 +390,20 @@ public:
PyW_invalidator->setObjectName(PyW_unique_name);
Py_INCREF (pyobj);
} else
}
else {
PyW_invalidator->disconnect();
}
auto destroyedFun = [pyobj](){
Base::PyGILStateLocker lock;
auto sbk_ptr = reinterpret_cast <SbkObject *> (pyobj);
if (sbk_ptr != nullptr)
if (sbk_ptr != nullptr) {
Shiboken::Object::setValidCpp(sbk_ptr, false);
else
}
else {
Base::Console().DeveloperError("WrapperManager", "A QObject has just been destroyed after its Pythonic wrapper.\n");
}
Py_DECREF (pyobj);
};
@@ -484,8 +499,9 @@ const char* qt_identifyType(QObject* ptr, const std::string& moduleName)
const QMetaObject* metaObject = ptr->metaObject();
while (metaObject) {
const char* className = metaObject->className();
if (qtmod.getDict().hasKey(className))
if (qtmod.getDict().hasKey(className)) {
return className;
}
metaObject = metaObject->superClass();
}
@@ -583,8 +599,9 @@ Py::Object PythonWrapper::fromQIcon(const QIcon* icon)
const char* typeName = typeid(*const_cast<QIcon*>(icon)).name();
PyObject* pyobj = Shiboken::Object::newObject(getPyTypeObjectForTypeName<QIcon>(),
const_cast<QIcon*>(icon), true, false, typeName);
if (pyobj)
if (pyobj) {
return Py::asObject(pyobj);
}
throw Py::RuntimeError("Failed to wrap icon");
#else
@@ -604,8 +621,9 @@ Py::Object PythonWrapper::fromQDir(const QDir& dir)
const char* typeName = typeid(dir).name();
PyObject* pyobj = Shiboken::Object::newObject(getPyTypeObjectForTypeName<QDir>(),
const_cast<QDir*>(&dir), false, false, typeName);
if (pyobj)
if (pyobj) {
return Py::asObject(pyobj);
}
#else
Q_UNUSED(dir)
#endif
@@ -619,8 +637,9 @@ QDir* PythonWrapper::toQDir(PyObject* pyobj)
Py::Object PythonWrapper::fromQPrinter(QPrinter* printer)
{
if (!printer)
if (!printer) {
return Py::None();
}
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
// Access shiboken/PySide via C++
auto type = getPyTypeObjectForTypeName<QPrinter>();
@@ -646,17 +665,21 @@ Py::Object PythonWrapper::fromQPrinter(QPrinter* printer)
Py::Object PythonWrapper::fromQObject(QObject* object, const char* className)
{
if (!object)
if (!object) {
return Py::None();
}
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
// Access shiboken/PySide via C++
auto type = getPyTypeObjectForTypeName<QObject>();
if (type) {
std::string typeName;
if (className)
if (className) {
typeName = className;
else
}
else {
typeName = object->metaObject()->className();
}
PyObject* pyobj = Shiboken::Object::newObject(type, object, false, false, typeName.c_str());
WrapperManager::instance().addQObject(object, pyobj);
return Py::asObject(pyobj);
@@ -665,10 +688,13 @@ Py::Object PythonWrapper::fromQObject(QObject* object, const char* className)
#else
// Access shiboken/PySide via Python
std::string typeName;
if (className)
if (className) {
typeName = className;
else
}
else {
typeName = object->metaObject()->className();
}
return qt_wrapInstance<QObject*>(object, typeName, "QtCore");
#endif
}
@@ -680,10 +706,13 @@ Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
auto type = getPyTypeObjectForTypeName<QWidget>();
if (type) {
std::string typeName;
if (className)
if (className) {
typeName = className;
else
}
else {
typeName = widget->metaObject()->className();
}
PyObject* pyobj = Shiboken::Object::newObject(type, widget, false, false, typeName.c_str());
WrapperManager::instance().addQObject(widget, pyobj);
return Py::asObject(pyobj);
@@ -692,10 +721,13 @@ Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
#else
// Access shiboken/PySide via Python
std::string typeName;
if (className)
if (className) {
typeName = className;
else
}
else {
typeName = widget->metaObject()->className();
}
return qt_wrapInstance<QWidget*>(widget, typeName, "QtWidgets");
#endif
}
@@ -707,8 +739,9 @@ const char* PythonWrapper::getWrapperName(QObject* obj) const
while (meta) {
const char* typeName = meta->className();
PyTypeObject* exactType = Shiboken::Conversions::getPythonTypeObject(typeName);
if (exactType)
if (exactType) {
return typeName;
}
meta = meta->superClass();
}
#else
@@ -717,8 +750,9 @@ const char* PythonWrapper::getWrapperName(QObject* obj) const
const QMetaObject* meta = obj->metaObject();
while (meta) {
const char* typeName = meta->className();
if (names.indexOf(QLatin1String(typeName)) >= 0)
if (names.indexOf(QLatin1String(typeName)) >= 0) {
return typeName;
}
meta = meta->superClass();
}
#endif
@@ -764,10 +798,12 @@ void PythonWrapper::createChildrenNameAttributes(PyObject* root, QObject* object
#else
const char* className = qt_identifyType(child, "QtWidgets");
if (!className) {
if (qobject_cast<QWidget*>(child))
if (qobject_cast<QWidget*>(child)) {
className = "QWidget";
else
}
else {
className = "QObject";
}
}
Py::Object pyChild(qt_wrapInstance<QObject*>(child, className, "QtWidgets"));

View File

@@ -112,7 +112,7 @@ installed addons will be checked for available updates
<string>Hide Addons with non-FSF Free/Libre license</string>
</property>
<property name="checked">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>HideNonFSFFreeLibre</cstring>

View File

@@ -502,7 +502,6 @@ if HAVE_QTNETWORK:
current_index = index
break
sender.abort()
if current_index != -1:
self.__launch_request(current_index, self.__create_get_request(url, timeout_ms))
@@ -579,7 +578,7 @@ if HAVE_QTNETWORK:
return
response_code = reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute)
if response_code == 301: # Permanently moved -- this is a redirect, bail out
if response_code == 301 or response_code == 302: # This is a redirect, bail out
return
if reply.error() != QtNetwork.QNetworkReply.NetworkError.OperationCanceledError:
# It this was not a timeout, make sure we mark the queue task done

View File

@@ -93,9 +93,9 @@ class PackageList(QtWidgets.QWidget):
self.set_view_style(style)
self.ui.view_bar.view_selector.set_current_view(style)
self.item_filter.setHidePy2(pref.GetBool("HidePy2", True))
self.item_filter.setHideObsolete(pref.GetBool("HideObsolete", True))
self.item_filter.setHideNonOSIApproved(pref.GetBool("HideNonOSIApproved", True))
self.item_filter.setHidePy2(pref.GetBool("HidePy2", False))
self.item_filter.setHideObsolete(pref.GetBool("HideObsolete", False))
self.item_filter.setHideNonOSIApproved(pref.GetBool("HideNonOSIApproved", False))
self.item_filter.setHideNonFSFLibre(pref.GetBool("HideNonFSFFreeLibre", False))
self.item_filter.setHideNewerFreeCADRequired(
pref.GetBool("HideNewerFreeCADRequired", False)

View File

@@ -2508,4 +2508,21 @@ def compact_mesh(
# may be return another value if the mesh was compacted, just check last map entries
return (new_mesh, node_map, elem_map)
# ************************************************************************************************
def beam_reduced_integration(
fileName
):
# replace B3x elements with B3xR elements
f = open(fileName, "r+")
lines = f.readlines()
f.seek(0)
for line in lines:
if line.find("B32") != -1:
line = line.replace("B32", "B32R")
if line.find("B31") != -1:
line = line.replace("B31", "B31R")
f.write(line)
f.truncate()
f.close()
## @}

View File

@@ -372,6 +372,15 @@ def add_attributes(obj, ccx_prefs):
obj.BeamShellResultOutput3D = dimout
if not hasattr(obj, "BeamReducedIntegration"):
obj.addProperty(
"App::PropertyBool",
"BeamReducedIntegration",
"Fem",
"Set to True to use beam elements with reduced integration"
)
obj.BeamReducedIntegration = True
"""
Should there be some equation object for Calculix too?

View File

@@ -77,7 +77,7 @@ def write_femelement_geometry(f, ccxwriter):
thickness = beamsec_obj.PipeThickness.getValueAs("mm").Value
section_type = ", SECTION=PIPE"
section_geo = "{:.13G},{:.13G}\n".format(radius, thickness)
section_def = "*BEAM GENERAL SECTION, {}{}{}\n".format(
section_def = "*BEAM SECTION, {}{}{}\n".format(
elsetdef,
material,
section_type

View File

@@ -51,6 +51,10 @@ def write_mesh(ccxwriter):
if ccxwriter.member.geos_fluidsection:
meshtools.write_D_network_element_to_inputfile(ccxwriter.femmesh_file)
# Use reduced integration beam elements if this option is enabled in ccx solver settings
if ccxwriter.solver_obj.BeamReducedIntegration:
meshtools.beam_reduced_integration(ccxwriter.femmesh_file)
inpfile = codecs.open(ccxwriter.file_name, "w", encoding="utf-8")
inpfile.write("{}\n".format(59 * "*"))
inpfile.write("** {}\n".format(write_name))
@@ -69,6 +73,10 @@ def write_mesh(ccxwriter):
# inpfile is closed
meshtools.write_D_network_element_to_inputfile(ccxwriter.femmesh_file)
# Use reduced integration beam elements if this option is enabled in ccx solver settings
if ccxwriter.solver_obj.BeamReducedIntegration:
meshtools.beam_reduced_integration(ccxwriter.femmesh_file)
# reopen file with "append" to add all the rest
inpfile = codecs.open(ccxwriter.femmesh_file, "a", encoding="utf-8")
inpfile.write("\n\n")

View File

@@ -17,7 +17,7 @@
** Edge elements
*Element, TYPE=B32, ELSET=Eedges
*Element, TYPE=B32R, ELSET=Eedges
1, 1, 7, 3
2, 3, 8, 4
3, 4, 9, 5

View File

@@ -17,7 +17,7 @@
** Edge elements
*Element, TYPE=B32, ELSET=Eedges
*Element, TYPE=B32R, ELSET=Eedges
1, 1, 7, 3
2, 3, 8, 4
3, 4, 9, 5
@@ -56,7 +56,7 @@ Eedges
***********************************************************
** Sections
*BEAM GENERAL SECTION, ELSET=M0B0RstdD0, MATERIAL=MechanicalMaterial, SECTION=PIPE
*BEAM SECTION, ELSET=M0B0RstdD0, MATERIAL=MechanicalMaterial, SECTION=PIPE
500,100
-0, 1, 0

View File

@@ -17,7 +17,7 @@
** Edge elements
*Element, TYPE=B32, ELSET=Eedges
*Element, TYPE=B32R, ELSET=Eedges
1, 1, 7, 3
2, 3, 8, 4
3, 4, 9, 5

View File

@@ -61,7 +61,7 @@
** Edge elements
*Element, TYPE=B31, ELSET=Eedges
*Element, TYPE=B31R, ELSET=Eedges
1, 1, 3
2, 3, 4
3, 4, 5

View File

@@ -17,7 +17,7 @@
** Edge elements
*Element, TYPE=B32, ELSET=Eedges
*Element, TYPE=B32R, ELSET=Eedges
1, 1, 7, 3
2, 3, 8, 4
3, 4, 9, 5

View File

@@ -593,14 +593,6 @@ void TopoShape::setPyObject(PyObject* obj)
}
}
void TopoShape::operator = (const TopoShape& sh)
{
if (this != &sh) {
this->Tag = sh.Tag;
this->_Shape = sh._Shape;
}
}
void TopoShape::convertTogpTrsf(const Base::Matrix4D& mtrx, gp_Trsf& trsf)
{
trsf.SetValues(mtrx[0][0],mtrx[0][1],mtrx[0][2],mtrx[0][3],

View File

@@ -197,9 +197,33 @@ enum class MapElement
/// Defines how to fill the holes that may appear after offset two adjacent faces
enum class JoinType
{
Arc,
Tangent,
Intersection,
arc,
tangent,
intersection,
};
enum class Flip
{
none,
flip
};
enum class AsAngle
{
no,
yes
};
enum class CheckScale
{
noScaleCheck,
checkScale
};
enum class Copy
{
noCopy,
copy
};
enum class CheckScale
@@ -820,7 +844,7 @@ public:
*/
TopoShape &makeElementThickSolid(const TopoShape &shape, const std::vector<TopoShape> &faces,
double offset, double tol, bool intersection = false, bool selfInter = false,
short offsetMode = 0, JoinType join = JoinType::Arc, const char *op=nullptr);
short offsetMode = 0, JoinType join = JoinType::arc, const char *op=nullptr);
/** Make a hollowed solid by removing some faces from a given solid
*
@@ -841,7 +865,7 @@ public:
*/
TopoShape makeElementThickSolid(const std::vector<TopoShape> &faces,
double offset, double tol, bool intersection = false, bool selfInter = false,
short offsetMode = 0, JoinType join = JoinType::Arc, const char *op=nullptr) const {
short offsetMode = 0, JoinType join = JoinType::arc, const char *op=nullptr) const {
return TopoShape(0,Hasher).makeElementThickSolid(*this,faces,offset,tol,intersection,selfInter,
offsetMode,join,op);
}
@@ -1015,6 +1039,10 @@ public:
void mapSubElementsTo(std::vector<TopoShape>& shapes, const char* op = nullptr) const;
bool hasPendingElementMap() const;
void flushElementMap() const override;
virtual Data::ElementMapPtr resetElementMap(
Data::ElementMapPtr elementMap=Data::ElementMapPtr());
/** Helper class to return the generated and modified shape given an input shape
*
@@ -1362,6 +1390,87 @@ public:
return TopoShape(0, Hasher).makeElementBoolean(maker, *this, op, tol);
}
/* Make fillet shape
*
* @param source: the source shape
* @param edges: the edges of the source shape where to make fillets
* @param radius1: the radius of the beginning of the fillet
* @param radius2: the radius of the ending of the fillet
* @param op: optional string to be encoded into topo naming for indicating
* the operation
*
* @return The original content of this TopoShape is discarded and replaced
* with the new shape. The function returns the TopoShape itself as
* a self reference so that multiple operations can be carried out
* for the same shape in the same line of code.
*/
TopoShape& makeElementFillet(const TopoShape& source,
const std::vector<TopoShape>& edges,
double radius1,
double radius2,
const char* op = nullptr);
/* Make fillet shape
*
* @param source: the source shape
* @param edges: the edges of the source shape where to make fillets
* @param radius1: the radius of the beginning of the fillet
* @param radius2: the radius of the ending of the fillet
* @param op: optional string to be encoded into topo naming for indicating
* the operation
*
* @return Return the new shape. The TopoShape itself is not modified.
*/
TopoShape makeElementFillet(const std::vector<TopoShape>& edges,
double radius1,
double radius2,
const char* op = nullptr) const
{
return TopoShape(0, Hasher).makeElementFillet(*this, edges, radius1, radius2, op);
}
/* Make chamfer shape
*
* @param source: the source shape
* @param edges: the edges of the source shape where to make chamfers
* @param radius1: the radius of the beginning of the chamfer
* @param radius2: the radius of the ending of the chamfer
* @param op: optional string to be encoded into topo naming for indicating
* the operation
*
* @return The original content of this TopoShape is discarded and replaced
* with the new shape. The function returns the TopoShape itself as
* a self reference so that multiple operations can be carried out
* for the same shape in the same line of code.
*/
TopoShape& makeElementChamfer(const TopoShape& source,
const std::vector<TopoShape>& edges,
double radius1,
double radius2,
const char* op = nullptr,
Flip flipDirection = Flip::none,
AsAngle asAngle = AsAngle::no);
/* Make chamfer shape
*
* @param source: the source shape
* @param edges: the edges of the source shape where to make chamfers
* @param radius1: the radius of the beginning of the chamfer
* @param radius2: the radius of the ending of the chamfer
* @param op: optional string to be encoded into topo naming for indicating
* the operation
*
* @return Return the new shape. The TopoShape itself is not modified.
*/
TopoShape makeElementChamfer(const std::vector<TopoShape>& edges,
double radius1,
double radius2,
const char* op = nullptr,
Flip flipDirection = Flip::none,
AsAngle asAngle = AsAngle::no) const
{
return TopoShape(0, Hasher)
.makeElementChamfer(*this, edges, radius1, radius2, op, flipDirection, asAngle);
}
/** Make a new shape with transformation
*
* @param source: input shape
@@ -1430,7 +1539,7 @@ public:
TopoShape makeElementTransform(const Base::Matrix4D& mat,
const char* op = nullptr,
CheckScale checkScale = CheckScale::noScaleCheck,
Copy copy = Copy::noCopy)
Copy copy = Copy::noCopy) const
{
return TopoShape(Tag, Hasher).makeElementTransform(*this, mat, op, checkScale, copy);
}

View File

@@ -51,6 +51,8 @@
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepFilletAPI_MakeChamfer.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepLib.hxx>
#include <BRepOffsetAPI_DraftAngle.hxx>
@@ -121,6 +123,48 @@ void TopoShape::initCache(int reset) const
}
}
Data::ElementMapPtr TopoShape::resetElementMap(Data::ElementMapPtr elementMap)
{
if (_cache && elementMap != this->elementMap(false)) {
for (auto& info : _cache->shapeAncestryCache) {
info.clear();
}
}
else {
initCache();
}
if (elementMap) {
_cache->cachedElementMap = elementMap;
_cache->subLocation.Identity();
_subLocation.Identity();
_parentCache.reset();
}
return Data::ComplexGeoData::resetElementMap(elementMap);
}
void TopoShape::flushElementMap() const
{
initCache();
if (!elementMap(false) && this->_cache) {
if (this->_cache->cachedElementMap) {
const_cast<TopoShape*>(this)->resetElementMap(this->_cache->cachedElementMap);
}
else if (this->_parentCache) {
TopoShape parent(this->Tag, this->Hasher, this->_parentCache->shape);
parent._cache = _parentCache;
parent.flushElementMap();
TopoShape self(this->Tag,
this->Hasher,
this->_Shape.Located(this->_subLocation * this->_cache->subLocation));
self._cache = _cache;
self.mapSubElement(parent);
this->_parentCache.reset();
this->_subLocation.Identity();
const_cast<TopoShape*>(this)->resetElementMap(self.elementMap());
}
}
}
void TopoShape::setShape(const TopoDS_Shape& shape, bool resetElementMap)
{
if (resetElementMap) {
@@ -208,6 +252,18 @@ TopoDS_Shape TopoShape::located(const TopoDS_Shape& tds, const gp_Trsf& transfer
return moved(sCopy, transfer);
}
void TopoShape::operator = (const TopoShape& sh)
{
if (this != &sh) {
this->setShape(sh._Shape, true);
this->Tag = sh.Tag;
this->Hasher = sh.Hasher;
this->_cache = sh._cache;
this->_parentCache = sh._parentCache;
this->_subLocation = sh._subLocation;
resetElementMap(sh.elementMap(false));
}
}
int TopoShape::findShape(const TopoDS_Shape& subshape) const
{
@@ -2090,11 +2146,11 @@ TopoShape& TopoShape::makeElementThickSolid(const TopoShape& shape,
// we do not offer tangent join type
switch (join) {
case JoinType::Arc:
case JoinType::Intersection:
case JoinType::arc:
case JoinType::intersection:
break;
default:
join = JoinType::Intersection;
join = JoinType::intersection;
}
if (shape.isNull()) {
@@ -2452,19 +2508,19 @@ TopoShape& TopoShape::makeElementOrderedWires(const std::vector<TopoShape>& shap
}
bool TopoShape::_makeElementTransform(const TopoShape& shape,
const Base::Matrix4D& rclTrf,
const Base::Matrix4D& mat,
const char* op,
CheckScale checkScale,
Copy copy)
{
if (checkScale == CheckScale::checkScale) {
auto scaleType = rclTrf.hasScale();
auto scaleType = mat.hasScale();
if (scaleType != Base::ScaleType::NoScaling && scaleType != Base::ScaleType::Uniform) {
makeElementGTransform(shape, rclTrf, op, copy);
makeElementGTransform(shape, mat, op, copy);
return true;
}
}
makeElementTransform(shape, convert(rclTrf), op, copy);
makeElementTransform(shape, convert(mat), op, copy);
return false;
}
@@ -2475,8 +2531,11 @@ TopoShape& TopoShape::makeElementTransform(const TopoShape& shape,
{
if (copy == Copy::noCopy) {
// OCCT checks the ScaleFactor against gp::Resolution() which is DBL_MIN!!!
copy = trsf.ScaleFactor() * trsf.HVectorialPart().Determinant() < 0.
|| Abs(Abs(trsf.ScaleFactor()) - 1) > Precision::Confusion() ? Copy::copy : Copy::noCopy;
// No scaling is 1 as in 1:1
const bool scaling = Abs(Abs(trsf.ScaleFactor()) - 1) > Precision::Confusion();
const bool negative_scaling =
trsf.ScaleFactor() * trsf.HVectorialPart().Determinant() < 0.0;
copy = negative_scaling || scaling ? Copy::copy : Copy::noCopy;
}
TopoShape tmp(shape);
if (copy == Copy::copy) {
@@ -2512,7 +2571,7 @@ TopoShape& TopoShape::makeElementTransform(const TopoShape& shape,
}
TopoShape& TopoShape::makeElementGTransform(const TopoShape& shape,
const Base::Matrix4D& rclTrf,
const Base::Matrix4D& mat,
const char* op,
Copy copy)
{
@@ -2521,23 +2580,23 @@ TopoShape& TopoShape::makeElementGTransform(const TopoShape& shape,
}
// if(!op) op = Part::OpCodes::Gtransform;
gp_GTrsf mat;
mat.SetValue(1, 1, rclTrf[0][0]);
mat.SetValue(2, 1, rclTrf[1][0]);
mat.SetValue(3, 1, rclTrf[2][0]);
mat.SetValue(1, 2, rclTrf[0][1]);
mat.SetValue(2, 2, rclTrf[1][1]);
mat.SetValue(3, 2, rclTrf[2][1]);
mat.SetValue(1, 3, rclTrf[0][2]);
mat.SetValue(2, 3, rclTrf[1][2]);
mat.SetValue(3, 3, rclTrf[2][2]);
mat.SetValue(1, 4, rclTrf[0][3]);
mat.SetValue(2, 4, rclTrf[1][3]);
mat.SetValue(3, 4, rclTrf[2][3]);
gp_GTrsf matrix;
matrix.SetValue(1, 1, mat[0][0]);
matrix.SetValue(2, 1, mat[1][0]);
matrix.SetValue(3, 1, mat[2][0]);
matrix.SetValue(1, 2, mat[0][1]);
matrix.SetValue(2, 2, mat[1][1]);
matrix.SetValue(3, 2, mat[2][1]);
matrix.SetValue(1, 3, mat[0][2]);
matrix.SetValue(2, 3, mat[1][2]);
matrix.SetValue(3, 3, mat[2][2]);
matrix.SetValue(1, 4, mat[0][3]);
matrix.SetValue(2, 4, mat[1][3]);
matrix.SetValue(3, 4, mat[2][3]);
// geometric transformation
TopoShape tmp(shape);
BRepBuilderAPI_GTransform mkTrf(shape.getShape(), mat, copy == Copy::copy);
BRepBuilderAPI_GTransform mkTrf(shape.getShape(), matrix, copy == Copy::copy);
tmp.setShape(mkTrf.Shape(), false);
if (op || (shape.Tag && shape.Tag != Tag)) {
setShape(tmp._Shape);
@@ -2700,6 +2759,80 @@ TopoShape& TopoShape::makeElementSolid(const TopoShape& shape, const char* op)
}
return *this;
}
TopoShape& TopoShape::makeElementFillet(const TopoShape& shape,
const std::vector<TopoShape>& edges,
double radius1,
double radius2,
const char* op)
{
if (!op) {
op = Part::OpCodes::Fillet;
}
if (shape.isNull()) {
FC_THROWM(NullShapeException, "Null shape");
}
if (edges.empty()) {
FC_THROWM(NullShapeException, "Null input shape");
}
BRepFilletAPI_MakeFillet mkFillet(shape.getShape());
for (auto& e : edges) {
if (e.isNull()) {
FC_THROWM(NullShapeException, "Null input shape");
}
const auto& edge = e.getShape();
if (!shape.findShape(edge)) {
FC_THROWM(Base::CADKernelError, "edge does not belong to the shape");
}
mkFillet.Add(radius1, radius2, TopoDS::Edge(edge));
}
return makeElementShape(mkFillet, shape, op);
}
TopoShape& TopoShape::makeElementChamfer(const TopoShape& shape,
const std::vector<TopoShape>& edges,
double radius1,
double radius2,
const char* op,
Flip flipDirection,
AsAngle asAngle)
{
if (!op) {
op = Part::OpCodes::Chamfer;
}
if (shape.isNull()) {
FC_THROWM(NullShapeException, "Null shape");
}
if (edges.empty()) {
FC_THROWM(NullShapeException, "Null input shape");
}
BRepFilletAPI_MakeChamfer mkChamfer(shape.getShape());
for (auto& e : edges) {
const auto& edge = e.getShape();
if (e.isNull()) {
FC_THROWM(NullShapeException, "Null input shape");
}
if (!shape.findShape(edge)) {
FC_THROWM(Base::CADKernelError, "edge does not belong to the shape");
}
// Add edge to fillet algorithm
TopoDS_Shape face;
if (flipDirection == Flip::flip) {
face = shape.findAncestorsShapes(edge, TopAbs_FACE).back();
}
else {
face = shape.findAncestorShape(edge, TopAbs_FACE);
}
if (asAngle == AsAngle::yes) {
mkChamfer.AddDA(radius1, radius2, TopoDS::Edge(edge), TopoDS::Face(face));
}
else {
mkChamfer.Add(radius1, radius2, TopoDS::Edge(edge), TopoDS::Face(face));
}
}
return makeElementShape(mkChamfer, shape, op);
}
TopoShape& TopoShape::makeElementGeneralFuse(const std::vector<TopoShape>& _shapes,
std::vector<std::vector<TopoShape>>& modifies,