Merge pull request #17564 from kadet1090/new-transform-dialog

Gui: New transform dialog
This commit is contained in:
Chris Hennes
2025-01-13 11:18:26 -06:00
committed by GitHub
42 changed files with 2559 additions and 750 deletions

View File

@@ -34,6 +34,7 @@
#include <Base/ExceptionFactory.h>
#include <Base/Interpreter.h>
#include <Base/Parameter.h>
#include <Base/ServiceProvider.h>
#include <Base/PrecisionPy.h>
#include "ArcOfCirclePy.h"
@@ -187,8 +188,12 @@
#include <OCAF/ImportExportSettings.h>
#include "MeasureClient.h"
#include <FuzzyHelper.h>
#include <App/Services.h>
#include <Services.h>
namespace Part {
extern PyObject* initModule();
}
@@ -572,7 +577,10 @@ PyMOD_INIT_FUNC(Part)
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean");
Part::FuzzyHelper::setBooleanFuzzy(hGrp->GetFloat("BooleanFuzzy",10.0));
Base::registerServiceImplementation<App::SubObjectPlacementProvider>(new AttacherSubObjectPlacement);
Base::registerServiceImplementation<App::CenterOfMassProvider>(new PartCenterOfMass);
PyMOD_Return(partModule);
}
// clang-format on

View File

@@ -69,6 +69,8 @@
#include "AttachExtension.h"
#include "Tools.h"
#include <Geometry.h>
using namespace Part;
using namespace Attacher;
@@ -136,6 +138,7 @@ const char* AttachEngine::eMapModeStrings[]= {
"OYX",
"ParallelPlane",
"MidPoint",
nullptr};
@@ -388,8 +391,8 @@ void AttachEngine::suggestMapModes(SuggestResult &result) const
result.message = SuggestResult::srLinkBroken;
result.bestFitMode = mmDeactivated;
std::vector<const TopoDS_Shape*> shapes;
std::vector<TopoDS_Shape> shapeStorage;
std::vector<const TopoShape*> shapes;
std::vector<TopoShape> shapeStorage;
std::vector<eRefType> typeStr;
try{
readLinks(getRefObjects(),subnames, shapes, shapeStorage, typeStr);
@@ -578,8 +581,8 @@ eRefType AttachEngine::getShapeType(const App::DocumentObject *obj, const std::s
//const_cast is worth here, to keep obj argument const. We are not going to write anything to obj through this temporary link.
tmpLink.setValue(const_cast<App::DocumentObject*>(obj), subshape.c_str());
std::vector<const TopoDS_Shape*> shapes;
std::vector<TopoDS_Shape> copiedShapeStorage;
std::vector<const TopoShape*> shapes;
std::vector<TopoShape> copiedShapeStorage;
std::vector<eRefType> types;
readLinks(tmpLink.getValues(), tmpLink.getSubValues(), shapes, copiedShapeStorage, types);
@@ -740,13 +743,14 @@ eRefType AttachEngine::getRefTypeByName(const std::string& typeName)
throw AttachEngineException(errmsg.str());
}
GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector<const TopoDS_Shape*> &shapes)
GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector<const TopoShape*> &shapes)
{
//explode compounds
TopTools_HSequenceOfShape totalSeq;
for (const TopoDS_Shape* pSh : shapes) {
for (auto tSh : shapes) {
auto pSh = tSh->getShape();
ShapeExtend_Explorer xp;
totalSeq.Append( xp.SeqFromCompound(*pSh, /*recursive=*/true));
totalSeq.Append( xp.SeqFromCompound(pSh, /*recursive=*/true));
}
if (totalSeq.Length() == 0)
throw AttachEngineException("AttachEngine::getInertialPropsOfShape: no geometry provided");
@@ -820,75 +824,96 @@ GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector<const TopoD
*/
void AttachEngine::readLinks(const std::vector<App::DocumentObject*>& objs,
const std::vector<std::string> &subs,
std::vector<const TopoDS_Shape*> &shapes,
std::vector<TopoDS_Shape> &storage,
std::vector<const TopoShape*> &shapes,
std::vector<TopoShape> &storage,
std::vector<eRefType> &types)
{
storage.reserve(objs.size());
shapes.resize(objs.size());
types.resize(objs.size());
for (std::size_t i = 0; i < objs.size(); i++) {
auto* geof = dynamic_cast<App::GeoFeature*>(objs[i]);
auto geof = extractGeoFeature(objs[i]);
if (!geof) {
// Accept App::Links to GeoFeatures
geof = dynamic_cast<App::GeoFeature*>(objs[i]->getLinkedObject());
if (!geof) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: attached to a non App::GeoFeature '" << objs[i]->getNameInDocument() << "'");
}
}
TopoDS_Shape myShape;
try {
// getTopoShape support fully qualified subnames and should return shape with correct
// global placement.
Part::TopoShape shape = Part::Feature::getTopoShape(objs[i], subs[i].c_str(), true);
for (;;) {
if (shape.isNull()) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: subshape not found "
<< objs[i]->getNameInDocument() << '.' << subs[i]);
}
if (shape.shapeType() != TopAbs_COMPOUND
|| shape.countSubShapes(TopAbs_SHAPE) != 1) {
break;
}
// auto extract the single sub-shape from a compound
shape = shape.getSubTopoShape(TopAbs_SHAPE, 1);
}
myShape = shape.getShape();
}
catch (Standard_Failure& e) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
<< '.' << subs[i] << std::endl
<< e.GetMessageString());
}
catch (Base::CADKernelError& e) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
<< '.' << subs[i] << std::endl
<< e.what());
}
if (myShape.IsNull()) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.'
<< subs[i]);
"AttachEngine3D: attached to a non App::GeoFeature '"
<< objs[i]->getNameInDocument() << "'");
}
storage.emplace_back(myShape);
auto shape = extractSubShape(objs[i], subs[i]);
if (shape.isNull()) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.'
<< subs[i]);
}
storage.emplace_back(shape);
shapes[i] = &(storage.back());
// FIXME: unpack single-child compounds here? Compounds are not used so far, so it should be
// considered later, when the need arises.
types[i] = getShapeType(*(shapes[i]));
types[i] = getShapeType(shapes[i]->getShape());
if (subs[i].length() == 0) {
types[i] = eRefType(types[i] | rtFlagHasPlacement);
}
}
}
App::GeoFeature* AttachEngine::extractGeoFeature(App::DocumentObject *obj)
{
if (auto geof = dynamic_cast<App::GeoFeature*>(obj)) {
return geof;
}
auto linkedObject = obj->getLinkedObject();
if (auto linkedGeof = dynamic_cast<App::GeoFeature*>(linkedObject)) {
return linkedGeof;
}
return nullptr;
}
TopoShape AttachEngine::extractSubShape(App::DocumentObject* obj, const std::string& subname)
{
TopoShape shape;
try {
// getTopoShape support fully qualified subnames and should return shape with correct
// global placement.
shape = Feature::getTopoShape(obj, subname.c_str(), true);
for (;;) {
if (shape.isNull()) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: subshape not found " << obj->getNameInDocument() << '.'
<< subname);
}
if (shape.shapeType() != TopAbs_COMPOUND || shape.countSubShapes(TopAbs_SHAPE) != 1) {
break;
}
// auto extract the single sub-shape from a compound
shape = shape.getSubTopoShape(TopAbs_SHAPE, 1);
}
}
catch (Standard_Failure& e) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: subshape not found " << obj->getNameInDocument() << '.'
<< subname << std::endl
<< e.GetMessageString());
}
catch (Base::CADKernelError& e) {
FC_THROWM(AttachEngineException,
"AttachEngine3D: subshape not found " << obj->getNameInDocument() << '.'
<< subname << std::endl
<< e.what());
}
return shape;
}
void AttachEngine::throwWrongMode(eMapMode mmode)
{
std::stringstream errmsg;
@@ -1140,8 +1165,8 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
throw ExceptionCancel(); // to be handled in positionBySupport, to not do anything if
// disabled
}
std::vector<const TopoDS_Shape*> shapes;
std::vector<TopoDS_Shape> copiedShapeStorage;
std::vector<const TopoShape*> shapes;
std::vector<TopoShape> copiedShapeStorage;
std::vector<eRefType> types;
readLinks(objs, subs, shapes, copiedShapeStorage, types);
@@ -1172,7 +1197,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: no subobjects "
"specified (need one vertex).");
}
const TopoDS_Shape& sh = *shapes[0];
const TopoDS_Shape& sh = shapes[0]->getShape();
if (sh.IsNull()) {
throw Base::ValueError(
"Null shape in AttachEngine3D::calculateAttachedPlacement()!");
@@ -1207,7 +1232,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
gp_Pnt(Place.getPosition().x, Place.getPosition().y, Place.getPosition().z);
}
else if (isShapeOfType(types[0], rtConic) > 0) {
const TopoDS_Edge& e = TopoDS::Edge(*shapes[0]);
const TopoDS_Edge& e = TopoDS::Edge(shapes[0]->getShape());
BRepAdaptor_Curve adapt(e);
gp_Ax3 pos;
switch (adapt.GetType()) {
@@ -1259,7 +1284,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
TopoDS_Vertex vertex;
try {
vertex = TopoDS::Vertex(*(shapes[1]));
vertex = TopoDS::Vertex(shapes[1]->getShape());
}
catch (...) {
}
@@ -1330,7 +1355,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
gp_Pln plane;
bool Reverse = false;
try {
face = TopoDS::Face(*(shapes[0]));
face = TopoDS::Face(shapes[0]->getShape());
}
catch (...) {
}
@@ -1387,14 +1412,14 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
}
bool bThruVertex = false;
if (shapes[0]->ShapeType() == TopAbs_VERTEX) {
if (shapes[0]->shapeType() == TopAbs_VERTEX) {
std::swap(shapes[0], shapes[1]);
bThruVertex = true;
}
TopoDS_Face face;
try {
face = TopoDS::Face(*(shapes[0]));
face = TopoDS::Face(shapes[0]->getShape());
}
catch (...) {
}
@@ -1405,7 +1430,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
TopoDS_Vertex vertex;
try {
vertex = TopoDS::Vertex(*(shapes[1]));
vertex = TopoDS::Vertex(shapes[1]->getShape());
}
catch (...) {
}
@@ -1472,14 +1497,14 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
}
bool bThruVertex = false;
if (shapes[0]->ShapeType() == TopAbs_VERTEX && shapes.size() >= 2) {
if (shapes[0]->shapeType() == TopAbs_VERTEX && shapes.size() >= 2) {
std::swap(shapes[0], shapes[1]);
bThruVertex = true;
}
TopoDS_Edge path;
try {
path = TopoDS::Edge(*(shapes[0]));
path = TopoDS::Edge(shapes[0]->getShape());
}
catch (...) {
}
@@ -1506,7 +1531,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
if (shapes.size() >= 2) {
TopoDS_Vertex vertex;
try {
vertex = TopoDS::Vertex(*(shapes[1]));
vertex = TopoDS::Vertex(shapes[1]->getShape());
}
catch (...) {
}
@@ -1633,7 +1658,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
std::vector<gp_Pnt> points;
for (const auto & shape : shapes) {
const TopoDS_Shape &sh = *shape;
const TopoDS_Shape &sh = shape->getShape();
if (sh.IsNull()) {
throw Base::ValueError(
"Null shape in AttachEngine3D::calculateAttachedPlacement()!");
@@ -1725,7 +1750,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
gp_Lin lines[4];
for (int i = 0; i < 4; i++) {
try {
edges[i] = &TopoDS::Edge(*(shapes[i]));
edges[i] = &TopoDS::Edge(shapes[i]->getShape());
}
catch (...) {
}
@@ -1845,28 +1870,28 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
gp_Vec dirs[3];
// read out origin
if (shapes[0]->IsNull()) {
if (shapes[0]->isNull()) {
THROWM(Base::TypeError, "AttachEngine3D::calculateAttachedPlacement: null shape!")
}
if (shapes[0]->ShapeType() != TopAbs_VERTEX) {
if (shapes[0]->shapeType() != TopAbs_VERTEX) {
THROWM(Base::TypeError,
"AttachEngine3D::calculateAttachedPlacement: first reference must be a "
"vertex, it's not")
}
SketchBasePoint = BRep_Tool::Pnt(TopoDS::Vertex(*(shapes[0])));
SketchBasePoint = BRep_Tool::Pnt(TopoDS::Vertex(shapes[0]->getShape()));
// read out axes directions
for (size_t i = 1; i < 3 && i < shapes.size(); ++i) {
if (shapes[i]->IsNull()) {
if (shapes[i]->isNull()) {
THROWM(Base::TypeError,
"AttachEngine3D::calculateAttachedPlacement: null shape!")
}
if (shapes[i]->ShapeType() == TopAbs_VERTEX) {
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(*(shapes[i])));
if (shapes[i]->shapeType() == TopAbs_VERTEX) {
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(shapes[i]->getShape()));
dirs[order[i - 1]] = gp_Vec(SketchBasePoint, p);
}
else if (shapes[i]->ShapeType() == TopAbs_EDGE) {
const TopoDS_Edge& e = TopoDS::Edge(*(shapes[i]));
else if (shapes[i]->shapeType() == TopAbs_EDGE) {
const TopoDS_Edge& e = TopoDS::Edge(shapes[i]->getShape());
BRepAdaptor_Curve crv(e);
double u1 = crv.FirstParameter();
double u2 = crv.LastParameter();
@@ -1896,6 +1921,90 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
plm *= this->attachmentOffset;
return plm;
} break;
case mmMidpoint: {
Base::Placement placement;
// special case for planes
if (auto plane = dynamic_cast<App::Plane*>(objs[0])) {
return plane->Placement.getValue() * attachmentOffset;
}
auto shape = shapes.front();
auto geom = Geometry::fromShape(shape->getShape());
switch (shape->shapeType()) {
case TopAbs_VERTEX: {
if (auto point = dynamic_cast<GeomPoint*>(geom.get())) {
placement.setPosition(point->getPoint());
}
}
break;
case TopAbs_EDGE: {
if (auto conic = dynamic_cast<GeomConic*>(geom.get())) {
placement.setPosition(conic->getLocation());
placement.setRotation(conic->getRotation().value_or(Base::Rotation {}));
} else if (auto line = dynamic_cast<GeomCurve*>(geom.get())) {
auto u1 = line->getFirstParameter();
auto u2 = line->getLastParameter();
auto middle = (u1 + u2) / 2;
placement.setPosition(line->pointAtParameter(middle));
Base::Vector3d direction;
if (!line->normalAt(middle, direction)) {
line->tangent(middle, direction);
}
placement.setRotation(Base::Rotation::fromNormalVector(direction));
}
}
break;
case TopAbs_FACE: {
auto surface = dynamic_cast<GeomSurface*>(geom.get());
if (auto sphere = dynamic_cast<GeomSphere*>(geom.get())) {
placement.setPosition(sphere->getLocation());
} else if (auto cone = dynamic_cast<GeomCone*>(geom.get())) {
placement.setPosition(cone->getApex());
} else if (auto com = shape->centerOfGravity()) {
placement.setPosition(*com);
} else {
placement.setPosition(shape->getBoundBox().GetCenter());
}
if (auto rotation = surface->getRotation()) {
placement.setRotation(*rotation);
} else {
auto adaptorSurface = BRepAdaptor_Surface(TopoDS::Face(shape->getShape()), true);
auto u1 = adaptorSurface.FirstUParameter();
auto u2 = adaptorSurface.LastUParameter();
auto v1 = adaptorSurface.FirstVParameter();
auto v2 = adaptorSurface.LastVParameter();
// calculate the normal at midpoint of the surface and use it as Z axis
gp_Dir dir;
surface->normal((u1 + u2) / 2, (v1 + v2) / 2, dir);
placement.setRotation(Base::Rotation::fromNormalVector(Base::convertTo<Base::Vector3d>(-dir)));
}
}
break;
default:
THROWM(Base::TypeError,
"AttachEngine3D::calculateAttachedPlacement: Unsupported shape type, "
"must be one of: Vertex, Edge, Face");
break;
}
return placement * attachmentOffset;
break;
}
default:
throwWrongMode(mmode);
} // switch (MapMode)
@@ -2083,8 +2192,8 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
Base::Placement plm;
if (!bReUsed) {
std::vector<const TopoDS_Shape*> shapes;
std::vector<TopoDS_Shape> copiedShapeStorage;
std::vector<const TopoShape*> shapes;
std::vector<TopoShape> copiedShapeStorage;
std::vector<eRefType> types;
readLinks(objs, subs, shapes, copiedShapeStorage, types);
@@ -2157,7 +2266,7 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
std::vector<gp_Pnt> points;
for (const auto & shape : shapes) {
const TopoDS_Shape &sh = *shape;
const TopoDS_Shape &sh = shape->getShape();
if (sh.IsNull()) {
throw Base::ValueError(
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
@@ -2197,13 +2306,13 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
} break;
case mm1Asymptote1:
case mm1Asymptote2: {
if (shapes[0]->IsNull()) {
if (shapes[0]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
}
TopoDS_Edge e;
try {
e = TopoDS::Edge(*(shapes[0]));
e = TopoDS::Edge(shapes[0]->getShape());
}
catch (...) {
}
@@ -2228,13 +2337,13 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
} break;
case mm1Directrix1:
case mm1Directrix2: {
if (shapes[0]->IsNull()) {
if (shapes[0]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
}
TopoDS_Edge e;
try {
e = TopoDS::Edge(*(shapes[0]));
e = TopoDS::Edge(shapes[0]->getShape());
}
catch (...) {
}
@@ -2283,13 +2392,13 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
"AttachEngineLine::calculateAttachedPlacement: Intersection mode requires "
"two shapes; only one is supplied");
}
if (shapes[0]->IsNull() || shapes[1]->IsNull()) {
if (shapes[0]->isNull() || shapes[1]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
}
const TopoDS_Face& face1 = TopoDS::Face(*(shapes[0]));
const TopoDS_Face& face2 = TopoDS::Face(*(shapes[1]));
const TopoDS_Face& face1 = TopoDS::Face(shapes[0]->getShape());
const TopoDS_Face& face2 = TopoDS::Face(shapes[1]->getShape());
Handle(Geom_Surface) hSurf1 = BRep_Tool::Surface(face1);
Handle(Geom_Surface) hSurf2 = BRep_Tool::Surface(face2);
@@ -2324,15 +2433,15 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
"AttachEngineLine::calculateAttachedPlacement: Proximity mode requires two "
"shapes; only one is supplied");
}
if (shapes[0]->IsNull()) {
if (shapes[0]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
}
if (shapes[1]->IsNull()) {
if (shapes[1]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEngineLine::calculateAttachedPlacement()!");
}
BRepExtrema_DistShapeShape distancer(*(shapes[0]), *(shapes[1]));
BRepExtrema_DistShapeShape distancer(shapes[0]->getShape(), shapes[1]->getShape());
if (!distancer.IsDone()) {
throw Base::ValueError("AttachEngineLine::calculateAttachedPlacement: "
"proximity calculation failed.");
@@ -2450,8 +2559,8 @@ AttachEnginePoint::_calculateAttachedPlacement(const std::vector<App::DocumentOb
Base::Placement plm;
if (!bReUsed) {
std::vector<const TopoDS_Shape*> shapes;
std::vector<TopoDS_Shape> copiedShapeStorage;
std::vector<const TopoShape*> shapes;
std::vector<TopoShape> copiedShapeStorage;
std::vector<eRefType> types;
readLinks(objs, subs, shapes, copiedShapeStorage, types);
@@ -2470,7 +2579,7 @@ AttachEnginePoint::_calculateAttachedPlacement(const std::vector<App::DocumentOb
std::vector<gp_Pnt> points;
assert(!shapes.empty());
const TopoDS_Shape& sh = *shapes[0];
const TopoDS_Shape& sh = shapes[0]->getShape();
if (sh.IsNull()) {
throw Base::ValueError(
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
@@ -2492,13 +2601,13 @@ AttachEnginePoint::_calculateAttachedPlacement(const std::vector<App::DocumentOb
} break;
case mm0Focus1:
case mm0Focus2: {
if (shapes[0]->IsNull()) {
if (shapes[0]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
}
TopoDS_Edge e;
try {
e = TopoDS::Edge(*(shapes[0]));
e = TopoDS::Edge(shapes[0]->getShape());
}
catch (...) {
}
@@ -2546,16 +2655,16 @@ AttachEnginePoint::_calculateAttachedPlacement(const std::vector<App::DocumentOb
"AttachEnginePoint::calculateAttachedPlacement: Proximity mode requires "
"two shapes; only one is supplied");
}
if (shapes[0]->IsNull()) {
if (shapes[0]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
}
if (shapes[1]->IsNull()) {
if (shapes[1]->isNull()) {
throw Base::ValueError(
"Null shape in AttachEnginePoint::calculateAttachedPlacement()!");
}
BasePoint = getProximityPoint(mmode, *(shapes[0]), *(shapes[1]));
BasePoint = getProximityPoint(mmode, shapes[0]->getShape(), shapes[1]->getShape());
} break;
case mm0CenterOfMass: {
GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes);

View File

@@ -108,6 +108,7 @@ enum eMapMode {
mmOYX,
mmParallelPlane,
mmMidpoint,
mmDummy_NumberOfModes//a value useful to check the validity of mode value
};//see also eMapModeStrings[] definition in .cpp
@@ -363,7 +364,7 @@ public://helper functions that may be useful outside of the class
static eRefType getRefTypeByName(const std::string &typeName);
static GProp_GProps getInertialPropsOfShape(const std::vector<const TopoDS_Shape*> &shapes);
static GProp_GProps getInertialPropsOfShape(const std::vector<const Part::TopoShape*> &shapes);
std::vector<App::DocumentObject*> getRefObjects() const;
const std::vector<std::string> &getSubValues() const {return subnames;}
@@ -430,11 +431,36 @@ protected:
}
static void readLinks(const std::vector<App::DocumentObject*> &objs,
const std::vector<std::string> &subs,
std::vector<const TopoDS_Shape*>& shapes, std::vector<TopoDS_Shape> &storage,
std::vector<const Part::TopoShape*>& shapes,
std::vector<Part::TopoShape> &storage,
std::vector<eRefType> &types);
static void throwWrongMode(eMapMode mmode);
/**
* Extracts GeoFeature instance from given DocumentObject.
*
* In case of object itself being GeoFeature it returns itself, in other cases (like links)
* the method should return pointer to associated GeoFeature or nullptr if none is available.
*
* @param obj The document object to extract the GeoFeature.
*
* @return App::GeoFeature pointer associated with this document object
*/
static App::GeoFeature* extractGeoFeature(App::DocumentObject* obj);
/**
* Tries to extract sub shape from document object with given subname.
*
* @param obj DocumentObject containing the sub shape
* @param subname Name of the sub shape to extract
*
* @return Extracted sub shape. Can be null.
*
* @throws AttachEngineException If given sub shape does not exist or is impossible to obtain.
*/
static Part::TopoShape extractSubShape(App::DocumentObject* obj, const std::string& subname);
};

View File

@@ -553,6 +553,8 @@ SET(Part_SRCS
PreCompiled.h
ProgressIndicator.cpp
ProgressIndicator.h
Services.cpp
Services.h
TopoShape.cpp
TopoShape.h
TopoShapeCache.cpp

View File

@@ -149,6 +149,8 @@
#include "ToroidPy.h"
#include "TopoShape.h"
#include <gp_Quaternion.hxx>
#if OCC_VERSION_HEX >= 0x070600
using GeomAdaptor_HCurve = GeomAdaptor_Curve;
@@ -2127,10 +2129,25 @@ void GeomConic::setLocation(const Base::Vector3d& Center)
Base::Vector3d GeomConic::getCenter() const
{
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(handle());
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(handle());
gp_Ax1 axis = conic->Axis();
const gp_Pnt& loc = axis.Location();
return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
return Base::Vector3d(loc.X(), loc.Y(), loc.Z());
}
std::optional<Base::Rotation> GeomConic::getRotation() const
{
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(handle());
if (!conic) {
return {};
}
gp_Trsf trsf;
trsf.SetTransformation(conic->Position(), gp_Ax3());
auto q = trsf.GetRotation();
return Base::Rotation(q.X(), q.Y(), q.Z(), q.W());
}
void GeomConic::setCenter(const Base::Vector3d& Center)
@@ -2142,7 +2159,6 @@ void GeomConic::setCenter(const Base::Vector3d& Center)
conic->SetLocation(p1);
}
catch (Standard_Failure& e) {
THROWM(Base::CADKernelError,e.GetMessageString())
}
}
@@ -4803,28 +4819,36 @@ GeomPlane* GeomSurface::toPlane(bool clone, double tol) const
if (isDerivedFrom(GeomPlane::getClassTypeId())) {
if (clone) {
return dynamic_cast<GeomPlane*>(this->clone());
} else {
}
else {
return dynamic_cast<GeomPlane*>(this->copy());
}
}
gp_Pln pln;
if (!isPlanar(&pln, tol))
if (!isPlanar(&pln, tol)) {
return nullptr;
}
auto res = new GeomPlane(pln);
res->copyNonTag(this);
if (clone)
if (clone) {
res->tag = this->tag;
}
return res;
}
std::optional<Base::Rotation> GeomSurface::getRotation() const
{
return {};
}
TopoDS_Shape GeomSurface::toShape() const
{
Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
Standard_Real u1,u2,v1,v2;
s->Bounds(u1,u2,v1,v2);
BRepBuilderAPI_MakeFace mkBuilder(s, u1, u2, v1, v2, Precision::Confusion() );
Standard_Real u1, u2, v1, v2;
s->Bounds(u1, u2, v1, v2);
BRepBuilderAPI_MakeFace mkBuilder(s, u1, u2, v1, v2, Precision::Confusion());
return mkBuilder.Shape();
}
@@ -5180,9 +5204,24 @@ GeomElementarySurface::~GeomElementarySurface()
Base::Vector3d GeomElementarySurface::getLocation(void) const
{
Handle(Geom_ElementarySurface) surf = Handle(Geom_ElementarySurface)::DownCast(handle());
Handle(Geom_ElementarySurface) surf = Handle(Geom_ElementarySurface)::DownCast(handle());
gp_Pnt loc = surf->Location();
return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
return Base::Vector3d(loc.X(), loc.Y(), loc.Z());
}
std::optional<Base::Rotation> GeomPlane::getRotation() const
{
Handle(Geom_ElementarySurface) s = Handle(Geom_ElementarySurface)::DownCast(handle());
if (!s) {
return {};
}
gp_Trsf trsf;
trsf.SetTransformation(s->Position().Ax2(),gp_Ax3());
auto q = trsf.GetRotation();
return Base::Rotation(q.X(),q.Y(),q.Z(),q.W());
}
Base::Vector3d GeomElementarySurface::getDir(void) const
@@ -5411,6 +5450,12 @@ double GeomCone::getSemiAngle() const
return mySurface->SemiAngle();
}
Base::Vector3d GeomCone::getApex() const
{
Handle(Geom_ConicalSurface) s = Handle(Geom_ConicalSurface)::DownCast(handle());
return Base::convertTo<Base::Vector3d>(s->Apex());
}
bool GeomCone::isSame(const Geometry &_other, double tol, double atol) const
{
if(_other.getTypeId() != getTypeId())

View File

@@ -58,6 +58,7 @@
#include <list>
#include <memory>
#include <vector>
#include <optional>
#include <boost/uuid/uuid_generators.hpp>
@@ -409,6 +410,7 @@ public:
*/
Base::Vector3d getCenter() const;
Base::Vector3d getLocation() const;
std::optional<Base::Rotation> getRotation() const;
void setLocation(const Base::Vector3d& Center);
/*!
* \deprecated use setLocation
@@ -882,6 +884,8 @@ public:
GeomPlane *toPlane(bool clone=true, double tol=1e-7) const;
virtual std::optional<Base::Rotation> getRotation() const;
bool tangentU(double u, double v, gp_Dir& dirU) const;
bool tangentV(double u, double v, gp_Dir& dirV) const;
bool normal(double u, double v, gp_Dir& dir) const;
@@ -961,6 +965,7 @@ public:
~GeomElementarySurface() override;
Base::Vector3d getLocation() const;
Base::Vector3d getDir() const;
Base::Vector3d getXDir() const;
Base::Vector3d getYDir() const;
@@ -1014,6 +1019,8 @@ public:
double getRadius() const;
double getSemiAngle() const;
Base::Vector3d getApex() const;
bool isSame(const Geometry &other, double tol, double atol) const override;
void setHandle(const Handle(Geom_ConicalSurface)&);
@@ -1091,6 +1098,8 @@ public:
~GeomPlane() override;
Geometry *copy() const override;
std::optional<Base::Rotation> getRotation() const override;
// Persistence implementer ---------------------
unsigned int getMemSize() const override;
void Save(Base::Writer &/*writer*/) const override;

View File

@@ -0,0 +1,55 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2024 Kacper Donat <kacper@kadet.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/>. *
* *
***************************************************************************/
#include "Services.h"
AttacherSubObjectPlacement::AttacherSubObjectPlacement()
: attacher(std::make_unique<Attacher::AttachEngine3D>())
{
attacher->setUp({}, Attacher::mmMidpoint);
}
Base::Placement AttacherSubObjectPlacement::calculate(App::SubObjectT object,
Base::Placement basePlacement) const
{
attacher->setReferences({object});
auto calculatedAttachment = attacher->calculateAttachedPlacement(basePlacement);
return basePlacement.inverse() * calculatedAttachment;
}
std::optional<Base::Vector3d> PartCenterOfMass::ofDocumentObject(App::DocumentObject* object) const
{
if (const auto feature = dynamic_cast<Part::Feature*>(object)) {
const auto shape = feature->Shape.getShape();
if (const auto cog = shape.centerOfGravity()) {
const Base::Placement comPlacement { *cog, Base::Rotation { } };
return (feature->Placement.getValue().inverse() * comPlacement).getPosition();
}
}
return {};
}

View File

@@ -0,0 +1,47 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2024 Kacper Donat <kacper@kadet.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/>. *
* *
***************************************************************************/
#ifndef PART_SERVICES_H
#define PART_SERVICES_H
#include <Attacher.h>
#include <App/Services.h>
class AttacherSubObjectPlacement final: public App::SubObjectPlacementProvider
{
public:
AttacherSubObjectPlacement();
Base::Placement calculate(App::SubObjectT object, Base::Placement basePlacement) const override;
private:
std::unique_ptr<Attacher::AttachEngine3D> attacher;
};
class PartCenterOfMass final: public App::CenterOfMassProvider
{
public:
std::optional<Base::Vector3d> ofDocumentObject(App::DocumentObject* object) const override;
};
#endif // PART_SERVICES_H

View File

@@ -81,7 +81,16 @@ void ViewProvider::setupContextMenu(QMenu* menu, QObject* receiver, const char*
bool ViewProvider::setEdit(int ModNum)
{
if (ModNum == ViewProvider::Default ) {
if (ModNum == ViewProvider::Transform) {
if (forwardToLink()) {
return true;
}
// this is feature so we need to forward the transform to the body
forwardedViewProvider = getBodyViewProvider();
return forwardedViewProvider->startEditing(ModNum);
}
else if (ModNum == ViewProvider::Default) {
// When double-clicking on the item for this feature the
// object unsets and sets its edit mode without closing
// the task panel
@@ -194,6 +203,22 @@ void ViewProvider::onChanged(const App::Property* prop) {
PartGui::ViewProviderPartExt::onChanged(prop);
}
Gui::ViewProvider* ViewProvider::startEditing(int ModNum)
{
// in case of transform we forward the request to body
if (ModNum == Transform) {
forwardedViewProvider = nullptr;
if (!ViewProviderPart::startEditing(ModNum)) {
return nullptr;
}
return forwardedViewProvider;
}
return ViewProviderPart::startEditing(ModNum);
}
void ViewProvider::setTipIcon(bool onoff) {
isSetTipIcon = onoff;

View File

@@ -55,6 +55,8 @@ public:
void updateData(const App::Property*) override;
void onChanged(const App::Property* prop) override;
Gui::ViewProvider* startEditing(int ModNum) override;
void setTipIcon(bool onoff);
//body mode means that the object is part of a body and that the body is used to set the