From 88141d6dce04ef5c2ca3f496dd30dfae2cdb3fb6 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Mon, 11 Nov 2024 17:59:07 +0100 Subject: [PATCH] Part: Add midpoint attachement mode This adds midpoint attachement mode to Attacher. It works just like method for finding placement of JCS in Assembly. --- src/Base/Rotation.cpp | 6 +++ src/Base/Rotation.h | 3 ++ src/Mod/Part/App/Attacher.cpp | 80 +++++++++++++++++++++++++++++++++++ src/Mod/Part/App/Attacher.h | 1 + src/Mod/Part/App/Geometry.cpp | 67 ++++++++++++++++++++++++----- src/Mod/Part/App/Geometry.h | 9 ++++ 6 files changed, 155 insertions(+), 11 deletions(-) diff --git a/src/Base/Rotation.cpp b/src/Base/Rotation.cpp index e1c871e0f7..9947d0cd0b 100644 --- a/src/Base/Rotation.cpp +++ b/src/Base/Rotation.cpp @@ -81,6 +81,12 @@ Rotation::Rotation(const Vector3d& rotateFrom, const Vector3d& rotateTo) this->setValue(rotateFrom, rotateTo); } +Rotation Rotation::fromNormalVector(const Vector3d& normal) +{ + // We rotate Z axis to be aligned with the supplied normal vector + return Rotation(Vector3d(0, 0, 1), normal); +} + const double* Rotation::getValue() const { return &this->quat[0]; diff --git a/src/Base/Rotation.h b/src/Base/Rotation.h index f663c81510..03b82d62ad 100644 --- a/src/Base/Rotation.h +++ b/src/Base/Rotation.h @@ -49,6 +49,9 @@ public: Rotation(const Rotation& rot) = default; Rotation(Rotation&& rot) = default; ~Rotation() = default; + + /// Utility function to create Rotation based on direction / normal vector + static Rotation fromNormalVector(const Vector3d& normal); //@} /** Methods to get or set rotations. */ diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index 77f389bc7c..8b9e594f57 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -69,6 +69,8 @@ #include "AttachExtension.h" #include "Tools.h" +#include + using namespace Part; using namespace Attacher; @@ -136,6 +138,7 @@ const char* AttachEngine::eMapModeStrings[]= { "OYX", "ParallelPlane", + "MidPoint", nullptr}; @@ -1895,6 +1898,83 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vectorattachmentOffset; return plm; } break; + case mmMidpoint: { + Base::Placement placement; + + auto shape = shapes.front(); + auto geom = Geometry::fromShape(shape->getShape()); + + switch (shape->shapeType()) { + case TopAbs_VERTEX: { + if (auto point = dynamic_cast(geom.get())) { + placement.setPosition(point->getPoint()); + } + } + break; + + case TopAbs_EDGE: { + if (auto conic = dynamic_cast(geom.get())) { + placement.setPosition(conic->getLocation()); + placement.setRotation(conic->getRotation().value_or(Base::Rotation {})); + } else if (auto line = dynamic_cast(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(geom.get()); + + if (auto sphere = dynamic_cast(geom.get())) { + placement.setPosition(sphere->getLocation()); + } else if (auto cone = dynamic_cast(geom.get())) { + placement.setPosition(cone->getApex()); + } else { + placement.setPosition(shape->centerOfGravity().value()); + } + + 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(-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) diff --git a/src/Mod/Part/App/Attacher.h b/src/Mod/Part/App/Attacher.h index 1a11bc220f..9b617d7547 100644 --- a/src/Mod/Part/App/Attacher.h +++ b/src/Mod/Part/App/Attacher.h @@ -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 diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 9a47464e2b..f786c75c68 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -149,6 +149,8 @@ #include "ToroidPy.h" #include "TopoShape.h" +#include + #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 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(this->clone()); - } else { + } + else { return dynamic_cast(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 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 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(s->Apex()); +} + bool GeomCone::isSame(const Geometry &_other, double tol, double atol) const { if(_other.getTypeId() != getTypeId()) diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index 4af1809128..376b16b99a 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -58,6 +58,7 @@ #include #include #include +#include #include @@ -409,6 +410,7 @@ public: */ Base::Vector3d getCenter() const; Base::Vector3d getLocation() const; + std::optional 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 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 getRotation() const override; + // Persistence implementer --------------------- unsigned int getMemSize() const override; void Save(Base::Writer &/*writer*/) const override;