| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <BRep_Tool.hxx> |
| | #include <BRepAdaptor_Curve.hxx> |
| | #include <BRepAdaptor_Surface.hxx> |
| | #include <BRepBuilderAPI_MakeEdge.hxx> |
| | #include <BRepBuilderAPI_MakeFace.hxx> |
| | #include <BRepBuilderAPI_MakeVertex.hxx> |
| | #include <BRepExtrema_DistShapeShape.hxx> |
| | #include <BRepGProp.hxx> |
| | #include <BRepIntCurveSurface_Inter.hxx> |
| | #include <BRepLProp_SLProps.hxx> |
| | #include <Geom_Line.hxx> |
| | #include <Geom_Plane.hxx> |
| | #include <GeomAdaptor.hxx> |
| | #include <GeomAPI.hxx> |
| | #include <GeomAPI_ProjectPointOnCurve.hxx> |
| | #include <GeomAPI_ProjectPointOnSurf.hxx> |
| | #include <GeomAPI_IntSS.hxx> |
| | #include <GeomLib_IsPlanarSurface.hxx> |
| | #include <gp_Ax1.hxx> |
| | #include <gp_Dir.hxx> |
| | #include <gp_Elips.hxx> |
| | #include <gp_Hypr.hxx> |
| | #include <gp_Parab.hxx> |
| | #include <gp_Pln.hxx> |
| | #include <gp_Pnt.hxx> |
| | #include <gp_Circ.hxx> |
| | #include <gp_Cylinder.hxx> |
| | #include <GProp_GProps.hxx> |
| | #include <GProp_PGProps.hxx> |
| | #include <GProp_PrincipalProps.hxx> |
| | #include <ShapeExtend_Explorer.hxx> |
| | #include <TopoDS.hxx> |
| | #include <TopoDS_Edge.hxx> |
| | #include <TopoDS_Face.hxx> |
| | #include <TopoDS_Iterator.hxx> |
| | #include <TopoDS_Shape.hxx> |
| | #include <TopoDS_Vertex.hxx> |
| | #include <TopTools_HSequenceOfShape.hxx> |
| | #include <GeomAbs_CurveType.hxx> |
| |
|
| | #include <App/Application.h> |
| | #include <App/Document.h> |
| | #include <App/Datums.h> |
| | #include <Base/Console.h> |
| |
|
| | #include "Attacher.h" |
| | #include "AttachExtension.h" |
| | #include "Tools.h" |
| |
|
| | #include <Geometry.h> |
| |
|
| |
|
| | using namespace Part; |
| | using namespace Attacher; |
| |
|
| | |
| | const char* AttachEngine::eMapModeStrings[] = { |
| | "Deactivated", |
| | "Translate", |
| | "ObjectXY", |
| | "ObjectXZ", |
| | "ObjectYZ", |
| | "FlatFace", |
| | "TangentPlane", |
| | "NormalToEdge", |
| | "FrenetNB", |
| | "FrenetTN", |
| | "FrenetTB", |
| | "Concentric", |
| | "SectionOfRevolution", |
| | "ThreePointsPlane", |
| | "ThreePointsNormal", |
| | "Folding", |
| |
|
| | "ObjectX", |
| | "ObjectY", |
| | "ObjectZ", |
| | "AxisOfCurvature", |
| | "Directrix1", |
| | "Directrix2", |
| | "Asymptote1", |
| | "Asymptote2", |
| | "Tangent", |
| | "Normal", |
| | "Binormal", |
| | "TangentU", |
| | "TangentV", |
| | "TwoPointLine", |
| | "IntersectionLine", |
| | "ProximityLine", |
| |
|
| | "ObjectOrigin", |
| | "Focus1", |
| | "Focus2", |
| | "OnEdge", |
| | "CenterOfCurvature", |
| | "CenterOfMass", |
| | "IntersectionPoint", |
| | "Vertex", |
| | "ProximityPoint1", |
| | "ProximityPoint2", |
| |
|
| | "AxisOfInertia1", |
| | "AxisOfInertia2", |
| | "AxisOfInertia3", |
| |
|
| | "InertialCS", |
| |
|
| | "FaceNormal", |
| |
|
| | "OZX", |
| | "OZY", |
| | "OXY", |
| | "OXZ", |
| | "OYZ", |
| | "OYX", |
| |
|
| | "ParallelPlane", |
| | "MidPoint", |
| |
|
| | nullptr |
| | }; |
| |
|
| | namespace |
| | { |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Base::Rotation rotationAlignedToNormal( |
| | const Base::Rotation& rotation, |
| | Base::Vector3d normal, |
| | const double eps = Precision::Confusion() |
| | ) |
| | { |
| | |
| | if (normal.Length() < eps) { |
| | return rotation; |
| | } |
| |
|
| | |
| | normal.Normalize(); |
| |
|
| | |
| | Base::Vector3d xOld = rotation.multVec(Base::Vector3d::UnitX); |
| | Base::Vector3d yOld = rotation.multVec(Base::Vector3d::UnitY); |
| |
|
| | |
| | Base::Vector3d xProj = xOld - normal * (xOld * normal); |
| |
|
| | if (xProj.Length() < eps) { |
| | xProj = yOld - normal * (yOld * normal); |
| | } |
| |
|
| | |
| | if (xProj.Length() < eps) { |
| | xProj = Base::Vector3d::UnitX; |
| |
|
| | if (std::fabs(xProj * normal) > 1.0 - eps) { |
| | xProj = Base::Vector3d::UnitY; |
| | } |
| | } |
| |
|
| | xProj.Normalize(); |
| |
|
| | |
| | Base::Vector3d yNew = normal.Cross(xProj); |
| | yNew.Normalize(); |
| |
|
| | |
| | Base::Matrix4D matrix; |
| | matrix.setCol(0, xProj); |
| | matrix.setCol(1, yNew); |
| | matrix.setCol(2, normal); |
| |
|
| | return {matrix}; |
| | } |
| |
|
| | } |
| |
|
| | |
| | |
| | |
| | const char* AttachEngine::eRefTypeStrings[] = {"Any", "Vertex", "Edge", "Face", |
| |
|
| | "Line", "Curve", "Circle", "Conic", |
| | "Ellipse", "Parabola", "Hyperbola", |
| |
|
| | "Plane", "Sphere", "Revolve", "Cylinder", |
| | "Torus", "Cone", |
| |
|
| | "Object", "Solid", "Wire", nullptr}; |
| |
|
| |
|
| | TYPESYSTEM_SOURCE_ABSTRACT(Attacher::AttachEngine, Base::BaseClass) |
| |
|
| | AttachEngine::AttachEngine() = default; |
| |
|
| | void AttachEngine::setReferences(const App::PropertyLinkSubList& references) |
| | { |
| | std::string docname; |
| | std::vector<std::string> names; |
| | for (auto obj : references.getValues()) { |
| | if (!obj->getNameInDocument()) { |
| | throw AttachEngineException("AttachEngine::invalid object"); |
| | } |
| | if (docname.empty()) { |
| | docname = obj->getDocument()->getName(); |
| | } |
| | else if (docname != obj->getDocument()->getName()) { |
| | throw AttachEngineException("AttachEngine::object from multiple document"); |
| | } |
| | names.emplace_back(obj->getNameInDocument()); |
| | } |
| | this->docName = docname; |
| | this->objNames = std::move(names); |
| | this->subnames.clear(); |
| | this->subnames.reserve(this->objNames.size()); |
| | this->shadowSubs.clear(); |
| | this->shadowSubs.reserve(this->objNames.size()); |
| | for (auto& shadow : references.getShadowSubs()) { |
| | this->shadowSubs.push_back(shadow.newName); |
| | this->subnames.push_back(shadow.oldName); |
| | } |
| | assert(this->objNames.size() == this->subnames.size()); |
| | } |
| |
|
| | void AttachEngine::setReferences(const std::vector<App::SubObjectT>& references) |
| | { |
| | std::string docname; |
| | std::vector<std::string> names; |
| | std::vector<std::string> subnames; |
| | std::vector<std::string> shadowSubs; |
| | for (auto& ref : references) { |
| | if (!ref.getSubObject()) { |
| | FC_THROWM( |
| | AttachEngineException, |
| | "AttachEngine::invalid object " << ref.getSubObjectFullName() |
| | ); |
| | } |
| | if (docname.empty()) { |
| | docname = ref.getDocumentName(); |
| | } |
| | else if (docname != ref.getDocumentName()) { |
| | throw AttachEngineException("AttachEngine::object from multiple document"); |
| | } |
| | names.push_back(ref.getObjectName()); |
| | subnames.push_back(ref.getSubNameNoElement() + ref.getOldElementName()); |
| | shadowSubs.push_back(ref.getSubNameNoElement() + ref.getNewElementName()); |
| | } |
| | this->docName = docname; |
| | this->objNames = std::move(names); |
| | this->subnames = std::move(subnames); |
| | this->shadowSubs = std::move(shadowSubs); |
| | } |
| |
|
| | void AttachEngine::setUp( |
| | const App::PropertyLinkSubList& references, |
| | eMapMode mapMode, |
| | bool mapReverse, |
| | double attachParameter, |
| | double surfU, |
| | double surfV, |
| | const Base::Placement& attachmentOffset |
| | ) |
| | { |
| | setReferences(references); |
| | this->mapMode = mapMode; |
| | this->mapReverse = mapReverse; |
| | this->attachParameter = attachParameter; |
| | this->surfU = surfU; |
| | this->surfV = surfV; |
| | this->attachmentOffset = attachmentOffset; |
| | } |
| |
|
| | void AttachEngine::setUp(const AttachEngine& another) |
| | { |
| | this->docName = another.docName; |
| | this->objNames = another.objNames; |
| | this->subnames = another.subnames; |
| | this->shadowSubs = another.shadowSubs; |
| | this->mapMode = another.mapMode; |
| | this->mapReverse = another.mapReverse; |
| | this->attachParameter = another.attachParameter; |
| | this->surfU = another.surfU; |
| | this->surfV = another.surfV; |
| | this->attachmentOffset = another.attachmentOffset; |
| | } |
| |
|
| | void AttachEngine::setOffset(const Base::Placement& offset) |
| | { |
| | this->attachmentOffset = offset; |
| | } |
| |
|
| | Base::Placement AttachEngine::placementFactory( |
| | const gp_Dir& ZAxis, |
| | gp_Vec XAxis, |
| | gp_Pnt Origin, |
| | gp_Pnt refOrg, |
| | bool useRefOrg_Line, |
| | bool useRefOrg_Plane, |
| | bool makeYVertical, |
| | bool makeLegacyFlatFaceOrientation, |
| | Base::Placement* placeOfRef |
| | ) const |
| | { |
| | if (useRefOrg_Line) { |
| | |
| | gp_Vec refOrgV = gp_Vec(refOrg.XYZ()); |
| | gp_Vec OriginV = gp_Vec(Origin.XYZ()); |
| | gp_Vec ZAxisV = gp_Vec(ZAxis); |
| | Origin = gp_Pnt((OriginV + ZAxisV * ZAxisV.Dot(refOrgV - OriginV)).XYZ()); |
| | } |
| | if (useRefOrg_Plane) { |
| | |
| | gp_Vec refOrgV = gp_Vec(refOrg.XYZ()); |
| | gp_Vec OriginV = gp_Vec(Origin.XYZ()); |
| | gp_Vec ZAxisV = gp_Vec(ZAxis); |
| | Origin = gp_Pnt((refOrgV + ZAxisV * ZAxisV.Dot(OriginV - refOrgV)).XYZ()); |
| | } |
| |
|
| | if (XAxis.Magnitude() < Precision::Confusion()) { |
| | makeYVertical = true; |
| | } |
| |
|
| | gp_Ax3 ax3; |
| | if (!makeYVertical) { |
| | ax3 = gp_Ax3(Origin, ZAxis, XAxis); |
| | } |
| | else if (!makeLegacyFlatFaceOrientation) { |
| | |
| | gp_Vec YAxis(0.0, 0.0, 1.0); |
| | XAxis = YAxis.Crossed(gp_Vec(ZAxis)); |
| | if (XAxis.Magnitude() < Precision::Confusion()) { |
| | |
| | XAxis = (gp_Vec(1, 0, 0) * ZAxis.Z()).Normalized(); |
| | } |
| | ax3 = gp_Ax3(Origin, ZAxis, XAxis); |
| | } |
| | else if (makeLegacyFlatFaceOrientation) { |
| | |
| | |
| | if (!placeOfRef) { |
| | throw AttachEngineException( |
| | "AttachEngine::placementFactory: for Legacy mode, placement of the reference must " |
| | "be supplied. Got null instead!" |
| | ); |
| | } |
| | Base::Placement& Place = *placeOfRef; |
| | Base::Vector3d dX, dY, dZ; |
| | Place.getRotation().multVec(Base::Vector3d(1, 0, 0), dX); |
| | Place.getRotation().multVec(Base::Vector3d(0, 1, 0), dY); |
| | Place.getRotation().multVec(Base::Vector3d(0, 0, 1), dZ); |
| | gp_Dir dirX(dX.x, dX.y, dX.z); |
| | gp_Dir dirY(dY.x, dY.y, dY.z); |
| | gp_Dir dirZ(dZ.x, dZ.y, dZ.z); |
| | double cosNX = ZAxis.Dot(dirX); |
| | double cosNY = ZAxis.Dot(dirY); |
| | double cosNZ = ZAxis.Dot(dirZ); |
| | std::vector<double> cosXYZ; |
| | cosXYZ.push_back(fabs(cosNX)); |
| | cosXYZ.push_back(fabs(cosNY)); |
| | cosXYZ.push_back(fabs(cosNZ)); |
| |
|
| | int pos = std::max_element(cosXYZ.begin(), cosXYZ.end()) - cosXYZ.begin(); |
| |
|
| | |
| | if (pos == 0) { |
| | if (cosNX > 0) { |
| | ax3 = gp_Ax3(Origin, ZAxis, dirY); |
| | } |
| | else { |
| | ax3 = gp_Ax3(Origin, ZAxis, -dirY); |
| | } |
| | } |
| | |
| | else if (pos == 1) { |
| | if (cosNY > 0) { |
| | ax3 = gp_Ax3(Origin, ZAxis, -dirX); |
| | } |
| | else { |
| | ax3 = gp_Ax3(Origin, ZAxis, dirX); |
| | } |
| | } |
| | |
| | else { |
| | ax3 = gp_Ax3(Origin, ZAxis, dirX); |
| | } |
| | } |
| |
|
| | if (this->mapReverse) { |
| | ax3.ZReverse(); |
| | ax3.XReverse(); |
| | } |
| |
|
| | |
| | gp_Trsf Trf; |
| | Trf.SetTransformation(ax3); |
| | Trf.Invert(); |
| | Trf.SetScaleFactor(Standard_Real(1.0)); |
| |
|
| | Base::Matrix4D mtrx; |
| | TopoShape::convertToMatrix(Trf, mtrx); |
| |
|
| | return Base::Placement(mtrx); |
| | } |
| |
|
| | void AttachEngine::suggestMapModes(SuggestResult& result) const |
| | { |
| | std::vector<eMapMode>& mlist = result.allApplicableModes; |
| | mlist.clear(); |
| | mlist.reserve(mmDummy_NumberOfModes); |
| |
|
| | std::set<eRefType>& hints = result.nextRefTypeHint; |
| | hints.clear(); |
| |
|
| | std::map<eMapMode, refTypeStringList>& mlist_reachable = result.reachableModes; |
| | mlist_reachable.clear(); |
| |
|
| | result.message = SuggestResult::srLinkBroken; |
| | result.bestFitMode = mmDeactivated; |
| |
|
| | std::vector<const TopoShape*> shapes; |
| | std::vector<TopoShape> shapeStorage; |
| | std::vector<eRefType> typeStr; |
| | try { |
| | readLinks(getRefObjects(), subnames, shapes, shapeStorage, typeStr); |
| | } |
| | catch (Base::Exception& err) { |
| | result.references_Types = typeStr; |
| | result.message = SuggestResult::srLinkBroken; |
| | result.error.Exception::operator=(err); |
| | return; |
| | } |
| |
|
| | result.references_Types = typeStr; |
| |
|
| | |
| | int bestMatchScore = -1; |
| | result.message = SuggestResult::srNoModesFit; |
| | for (std::size_t iMode = 0; iMode < this->modeRefTypes.size(); ++iMode) { |
| | if (!this->modeEnabled[iMode]) { |
| | continue; |
| | } |
| | const refTypeStringList& listStrings = modeRefTypes[iMode]; |
| | for (const auto& str : listStrings) { |
| | int score = 1; |
| | |
| | for (std::size_t iChr = 0; iChr < str.size() && iChr < typeStr.size(); ++iChr) { |
| | int match = AttachEngine::isShapeOfType(typeStr[iChr], str[iChr]); |
| | switch (match) { |
| | case -1: |
| | score = -1; |
| | break; |
| | case 0: |
| | score = 0; |
| | break; |
| | case 1: |
| | |
| | break; |
| | default: |
| | if (score > 0) { |
| | score += match; |
| | } |
| | break; |
| | } |
| | } |
| |
|
| | if (score > 0 && str.size() > typeStr.size()) { |
| | |
| | hints.insert(str[typeStr.size()]); |
| |
|
| | |
| | refTypeString extraRefs; |
| | extraRefs.resize(str.size() - typeStr.size()); |
| | for (std::size_t iChr = typeStr.size(); iChr < str.size(); iChr++) { |
| | extraRefs[iChr - typeStr.size()] = str[iChr]; |
| | } |
| |
|
| | |
| | auto it_r = mlist_reachable.find(eMapMode(iMode)); |
| | if (it_r == mlist_reachable.end()) { |
| | it_r = mlist_reachable |
| | .insert( |
| | std::pair<eMapMode, refTypeStringList>( |
| | eMapMode(iMode), |
| | refTypeStringList() |
| | ) |
| | ) |
| | .first; |
| | } |
| | refTypeStringList& list = it_r->second; |
| | list.push_back(extraRefs); |
| | } |
| |
|
| | |
| | if (str.size() != typeStr.size()) { |
| | score = -1; |
| | } |
| |
|
| | if (score > -1) { |
| | if (score > bestMatchScore) { |
| | bestMatchScore = score; |
| | result.bestFitMode = eMapMode(iMode); |
| | result.message = score > 0 ? SuggestResult::srOK |
| | : SuggestResult::srIncompatibleGeometry; |
| | } |
| | } |
| | if (score > 0) { |
| | if (mlist.empty()) { |
| | mlist.push_back(eMapMode(iMode)); |
| | } |
| | else if (mlist.back() != eMapMode(iMode)) { |
| | mlist.push_back(eMapMode(iMode)); |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void AttachEngine::EnableAllSupportedModes() |
| | { |
| | this->modeEnabled.resize(mmDummy_NumberOfModes, false); |
| | assert(modeRefTypes.size() > 0); |
| | for (std::size_t i = 0; i < this->modeEnabled.size(); i++) { |
| | modeEnabled[i] = !modeRefTypes[i].empty(); |
| | } |
| | } |
| |
|
| | eRefType AttachEngine::getShapeType(const TopoDS_Shape& sh) |
| | { |
| | if (sh.IsNull()) { |
| | return rtAnything; |
| | } |
| |
|
| | switch (sh.ShapeType()) { |
| | case TopAbs_SHAPE: |
| | return rtAnything; |
| | break; |
| | case TopAbs_SOLID: |
| | return rtSolid; |
| | break; |
| | case TopAbs_COMPOUND: { |
| | const TopoDS_Compound& cmpd = TopoDS::Compound(sh); |
| | TopoDS_Iterator it(cmpd, Standard_False, Standard_False); |
| | |
| | if (!it.More()) { |
| | return rtAnything; |
| | } |
| | const TopoDS_Shape& sh1 = it.Value(); |
| | it.Next(); |
| | if (it.More()) { |
| | |
| | return rtAnything; |
| | } |
| | else { |
| | |
| | return getShapeType(sh1); |
| | } |
| | } break; |
| | case TopAbs_COMPSOLID: |
| | case TopAbs_SHELL: |
| | return rtAnything; |
| | break; |
| | case TopAbs_FACE: { |
| | const TopoDS_Face& f = TopoDS::Face(sh); |
| | BRepAdaptor_Surface surf(f, Standard_False); |
| | switch (surf.GetType()) { |
| | case GeomAbs_Plane: |
| | return rtFlatFace; |
| | case GeomAbs_Cylinder: |
| | return rtCylindricalFace; |
| | case GeomAbs_Cone: |
| | return rtConicalFace; |
| | case GeomAbs_Sphere: |
| | return rtSphericalFace; |
| | case GeomAbs_Torus: |
| | return rtToroidalFace; |
| | case GeomAbs_BezierSurface: |
| | break; |
| | case GeomAbs_BSplineSurface: |
| | break; |
| | case GeomAbs_SurfaceOfRevolution: |
| | return rtSurfaceRev; |
| | case GeomAbs_SurfaceOfExtrusion: |
| | break; |
| | case GeomAbs_OffsetSurface: |
| | break; |
| | case GeomAbs_OtherSurface: |
| | break; |
| | } |
| | return rtFace; |
| | } break; |
| | case TopAbs_EDGE: { |
| | const TopoDS_Edge& e = TopoDS::Edge(sh); |
| | BRepAdaptor_Curve crv(e); |
| | switch (crv.GetType()) { |
| | case GeomAbs_Line: |
| | return rtLine; |
| | case GeomAbs_Circle: |
| | return rtCircle; |
| | case GeomAbs_Ellipse: |
| | return rtEllipse; |
| | case GeomAbs_Hyperbola: |
| | return rtHyperbola; |
| | case GeomAbs_Parabola: |
| | return rtParabola; |
| | case GeomAbs_BezierCurve: |
| | case GeomAbs_BSplineCurve: |
| | case GeomAbs_OtherCurve: |
| | case GeomAbs_OffsetCurve: |
| | return rtCurve; |
| | } |
| | } break; |
| | case TopAbs_WIRE: |
| | return rtWire; |
| | case TopAbs_VERTEX: |
| | return rtVertex; |
| | default: |
| | throw AttachEngineException( |
| | "AttachEngine::getShapeType: unexpected TopoDS_Shape::ShapeType" |
| | ); |
| | } |
| | return rtAnything; |
| | } |
| |
|
| | eRefType AttachEngine::getShapeType(const App::DocumentObject* obj, const std::string& subshape) |
| | { |
| | App::PropertyLinkSubList tmpLink; |
| | |
| | |
| | tmpLink.setValue(const_cast<App::DocumentObject*>(obj), subshape.c_str()); |
| |
|
| | std::vector<const TopoShape*> shapes; |
| | std::vector<TopoShape> copiedShapeStorage; |
| | std::vector<eRefType> types; |
| | readLinks(tmpLink.getValues(), tmpLink.getSubValues(), shapes, copiedShapeStorage, types); |
| |
|
| | assert(types.size() == 1); |
| | return types[0]; |
| | } |
| |
|
| | eRefType AttachEngine::downgradeType(eRefType type) |
| | { |
| | |
| | type = eRefType(type & (rtFlagHasPlacement - 1)); |
| | |
| |
|
| | switch (type) { |
| | case rtVertex: |
| | case rtEdge: |
| | case rtFace: |
| | return rtAnything; |
| | case rtAnything: |
| | return rtAnything; |
| | case rtLine: |
| | case rtCurve: |
| | return rtEdge; |
| | case rtConic: |
| | case rtCircle: |
| | return rtCurve; |
| | case rtEllipse: |
| | case rtParabola: |
| | case rtHyperbola: |
| | return rtConic; |
| | case rtFlatFace: |
| | case rtSphericalFace: |
| | case rtSurfaceRev: |
| | return rtFace; |
| | case rtCylindricalFace: |
| | case rtToroidalFace: |
| | case rtConicalFace: |
| | return rtSurfaceRev; |
| | case rtSolid: |
| | case rtWire: |
| | return rtPart; |
| | case rtPart: |
| | return rtAnything; |
| | default: |
| | throw AttachEngineException("AttachEngine::downgradeType: unknown type"); |
| | } |
| | } |
| |
|
| | int AttachEngine::getTypeRank(eRefType type) |
| | { |
| | |
| | type = eRefType(type & (rtFlagHasPlacement - 1)); |
| |
|
| | int rank = 0; |
| | while (type != rtAnything) { |
| | type = downgradeType(type); |
| | rank++; |
| | assert(rank < 8); |
| | } |
| | return rank; |
| | } |
| |
|
| | int AttachEngine::isShapeOfType(eRefType shapeType, eRefType requirement) |
| | { |
| | |
| | if (requirement & rtFlagHasPlacement) { |
| | if (!(shapeType & rtFlagHasPlacement)) { |
| | return -1; |
| | } |
| | } |
| |
|
| | |
| | shapeType = eRefType(shapeType & (rtFlagHasPlacement - 1)); |
| | requirement = eRefType(requirement & (rtFlagHasPlacement - 1)); |
| |
|
| | if (requirement == rtAnything) { |
| | return 1; |
| | } |
| |
|
| | int reqRank = getTypeRank(requirement); |
| |
|
| | |
| | eRefType shDeg = shapeType; |
| | while (shDeg != rtAnything) { |
| | if (shDeg == requirement) { |
| | return reqRank; |
| | } |
| | shDeg = downgradeType(shDeg); |
| | } |
| |
|
| | |
| | requirement = downgradeType(requirement); |
| | if (requirement != rtAnything) { |
| | eRefType shDeg = shapeType; |
| | while (shDeg != rtAnything) { |
| | if (shDeg == requirement) { |
| | return 0; |
| | } |
| | shDeg = downgradeType(shDeg); |
| | } |
| | } |
| |
|
| | |
| | return -1; |
| | } |
| |
|
| | std::string AttachEngine::getModeName(eMapMode mmode) |
| | { |
| | if (mmode < 0 || mmode >= mmDummy_NumberOfModes) { |
| | throw AttachEngineException("AttachEngine::getModeName: Attachment Mode index is out of range"); |
| | } |
| | return {AttachEngine::eMapModeStrings[mmode]}; |
| | } |
| |
|
| | eMapMode AttachEngine::getModeByName(const std::string& modeName) |
| | { |
| | for (int mmode = 0; mmode < mmDummy_NumberOfModes; mmode++) { |
| | if (strcmp(eMapModeStrings[mmode], modeName.c_str()) == 0) { |
| | return eMapMode(mmode); |
| | } |
| | } |
| | std::stringstream errMsg; |
| | errMsg << "AttachEngine::getModeByName: mode with this name doesn't exist: " << modeName; |
| | throw AttachEngineException(errMsg.str()); |
| | } |
| |
|
| | std::string AttachEngine::getRefTypeName(eRefType shapeType) |
| | { |
| | eRefType flagless = eRefType(shapeType & 0xFF); |
| | if (flagless < 0 || flagless >= rtDummy_numberOfShapeTypes) { |
| | throw AttachEngineException("eRefType value is out of range"); |
| | } |
| | std::string result = std::string(eRefTypeStrings[flagless]); |
| | if (shapeType & rtFlagHasPlacement) { |
| | result.append("|Placement"); |
| | } |
| | return result; |
| | } |
| |
|
| | eRefType AttachEngine::getRefTypeByName(const std::string& typeName) |
| | { |
| | std::string flagless; |
| | std::string flags; |
| | size_t seppos = typeName.find('|'); |
| | flagless = typeName.substr(0, seppos); |
| | if (seppos != std::string::npos) { |
| | flags = typeName.substr(seppos + 1); |
| | } |
| | for (int irt = 0; irt < rtDummy_numberOfShapeTypes; irt++) { |
| | if (strcmp(flagless.c_str(), eRefTypeStrings[irt]) == 0) { |
| | if (strcmp("Placement", flags.c_str()) == 0) { |
| | return eRefType(irt | rtFlagHasPlacement); |
| | } |
| | else if (flags.length() == 0) { |
| | return eRefType(irt); |
| | } |
| | else { |
| | std::stringstream errmsg; |
| | errmsg << "RefType flag not recognized: " << flags; |
| | throw AttachEngineException(errmsg.str()); |
| | } |
| | } |
| | } |
| | std::stringstream errmsg; |
| | errmsg << "RefType not recognized: " << typeName; |
| | throw AttachEngineException(errmsg.str()); |
| | } |
| |
|
| | GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector<const TopoShape*>& shapes) |
| | { |
| | |
| | TopTools_HSequenceOfShape totalSeq; |
| | for (auto tSh : shapes) { |
| | auto pSh = tSh->getShape(); |
| | ShapeExtend_Explorer xp; |
| | totalSeq.Append(xp.SeqFromCompound(pSh, true)); |
| | } |
| | if (totalSeq.Length() == 0) { |
| | throw AttachEngineException("AttachEngine::getInertialPropsOfShape: no geometry provided"); |
| | } |
| | const TopoDS_Shape& sh0 = totalSeq.Value(1); |
| | switch (sh0.ShapeType()) { |
| | case TopAbs_VERTEX: { |
| | GProp_PGProps gpr; |
| | for (int i = 0; i < totalSeq.Length(); i++) { |
| | const TopoDS_Shape& sh = totalSeq.Value(i + 1); |
| | if (sh.ShapeType() != TopAbs_VERTEX) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: provided shapes are incompatible " |
| | "(not only vertices)" |
| | ); |
| | } |
| | gpr.AddPoint(BRep_Tool::Pnt(TopoDS::Vertex(sh))); |
| | } |
| | return gpr; |
| | } break; |
| | case TopAbs_EDGE: |
| | case TopAbs_WIRE: { |
| | GProp_GProps gpr_acc; |
| | GProp_GProps gpr; |
| | for (int i = 0; i < totalSeq.Length(); i++) { |
| | const TopoDS_Shape& sh = totalSeq.Value(i + 1); |
| | if (sh.ShapeType() != TopAbs_EDGE && sh.ShapeType() != TopAbs_WIRE) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: provided shapes are incompatible " |
| | "(not only edges/wires)" |
| | ); |
| | } |
| | if (sh.Infinite()) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: infinite shape provided" |
| | ); |
| | } |
| | BRepGProp::LinearProperties(sh, gpr); |
| | gpr_acc.Add(gpr); |
| | } |
| | return gpr_acc; |
| | } break; |
| | case TopAbs_FACE: |
| | case TopAbs_SHELL: { |
| | GProp_GProps gpr_acc; |
| | GProp_GProps gpr; |
| | for (int i = 0; i < totalSeq.Length(); i++) { |
| | const TopoDS_Shape& sh = totalSeq.Value(i + 1); |
| | if (sh.ShapeType() != TopAbs_FACE && sh.ShapeType() != TopAbs_SHELL) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: provided shapes are incompatible " |
| | "(not only faces/shells)" |
| | ); |
| | } |
| | if (sh.Infinite()) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: infinite shape provided" |
| | ); |
| | } |
| | BRepGProp::SurfaceProperties(sh, gpr); |
| | gpr_acc.Add(gpr); |
| | } |
| | return gpr_acc; |
| | } break; |
| | case TopAbs_SOLID: |
| | case TopAbs_COMPSOLID: { |
| | GProp_GProps gpr_acc; |
| | GProp_GProps gpr; |
| | for (int i = 0; i < totalSeq.Length(); i++) { |
| | const TopoDS_Shape& sh = totalSeq.Value(i + 1); |
| | if (sh.ShapeType() != TopAbs_SOLID && sh.ShapeType() != TopAbs_COMPSOLID) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: provided shapes are incompatible " |
| | "(not only solids/compsolids)" |
| | ); |
| | } |
| | if (sh.Infinite()) { |
| | throw AttachEngineException( |
| | "AttachEngine::getInertialPropsOfShape: infinite shape provided" |
| | ); |
| | } |
| | BRepGProp::VolumeProperties(sh, gpr); |
| | gpr_acc.Add(gpr); |
| | } |
| | return gpr_acc; |
| | } break; |
| | default: |
| | throw AttachEngineException("AttachEngine::getInertialPropsOfShape: unexpected shape type"); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void AttachEngine::readLinks( |
| | const std::vector<App::DocumentObject*>& objs, |
| | const std::vector<std::string>& subs, |
| | 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 = extractGeoFeature(objs[i]); |
| | if (!geof) { |
| | FC_THROWM( |
| | AttachEngineException, |
| | "AttachEngine3D: attached to a non App::GeoFeature '" |
| | << objs[i]->getNameInDocument() << "'" |
| | ); |
| | } |
| |
|
| | auto shape = extractSubShape(objs[i], subs[i]); |
| | if (shape.isNull()) { |
| | if (subs[i].length() == 0) { |
| | storage.emplace_back(TopoShape()); |
| | shapes[i] = &storage.back(); |
| | types[i] = eRefType(rtPart | rtFlagHasPlacement); |
| | continue; |
| | } |
| | else { |
| | |
| | |
| | FC_THROWM( |
| | AttachEngineException, |
| | "AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.' << subs[i] |
| | ); |
| | } |
| | } |
| |
|
| | storage.emplace_back(shape); |
| | shapes[i] = &(storage.back()); |
| |
|
| | |
| | |
| | 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 { |
| | |
| | |
| | shape = Feature::getTopoShape( |
| | obj, |
| | ShapeOption::NeedSubElement | ShapeOption::ResolveLink | ShapeOption::Transform, |
| | subname.c_str() |
| | ); |
| |
|
| | for (;;) { |
| | if (shape.isNull()) { |
| | |
| | |
| | if (subname.empty()) { |
| | |
| | |
| | |
| | |
| | return TopoShape(); |
| | } |
| | else { |
| | |
| | |
| | FC_THROWM( |
| | AttachEngineException, |
| | "AttachEngine3D: subshape not found " << obj->getNameInDocument() << '.' |
| | << subname |
| | ); |
| | } |
| | } |
| |
|
| | if (shape.shapeType() != TopAbs_COMPOUND || shape.countSubShapes(TopAbs_SHAPE) != 1) { |
| | break; |
| | } |
| |
|
| | |
| | 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; |
| | if (mmode >= 0 && mmode < mmDummy_NumberOfModes) { |
| | if (AttachEngine::eMapModeStrings[mmode]) { |
| | errmsg << "Attachment mode " << AttachEngine::eMapModeStrings[mmode] |
| | << " is not implemented."; |
| | } |
| | else { |
| | errmsg << "Attachment mode " << int(mmode) << " is undefined."; |
| | } |
| | } |
| | else { |
| | errmsg << "Attachment mode index (" << int(mmode) << ") is out of range."; |
| | } |
| | throw Base::ValueError(errmsg.str().c_str()); |
| | } |
| |
|
| | void AttachEngine::verifyReferencesAreSafe(const App::PropertyLinkSubList& references) |
| | { |
| | const std::vector<App::DocumentObject*> links = references.getValues(); |
| | const std::vector<App::Document*> docs = App::GetApplication().getDocuments(); |
| | for (App::DocumentObject* lnk : links) { |
| | bool found = false; |
| | for (App::Document* doc : docs) { |
| | if (doc->isIn(lnk)) { |
| | found = true; |
| | } |
| | } |
| | if (!found) { |
| | throw AttachEngineException( |
| | "AttachEngine: verifyReferencesAreSafe: references point to deleted object." |
| | ); |
| | } |
| | } |
| | } |
| |
|
| | std::vector<App::DocumentObject*> AttachEngine::getRefObjects() const |
| | { |
| | std::vector<App::DocumentObject*> objs; |
| | if (objNames.empty()) { |
| | return objs; |
| | } |
| | auto doc = App::GetApplication().getDocument(docName.c_str()); |
| | if (!doc) { |
| | FC_THROWM(AttachEngineException, "AttachEngine: document '" << docName << "' not found"); |
| | } |
| | objs.reserve(objNames.size()); |
| | for (auto& name : objNames) { |
| | objs.push_back(doc->getObject(name.c_str())); |
| | if (!objs.back()) { |
| | FC_THROWM( |
| | AttachEngineException, |
| | "AttachEngine: object '" << docName << "#" << name << "' not found" |
| | ); |
| | } |
| | } |
| | return objs; |
| | } |
| |
|
| | Base::Placement AttachEngine::calculateAttachedPlacement( |
| | const Base::Placement& origPlacement, |
| | bool* subChanged |
| | ) |
| | { |
| | std::map<int, std::pair<std::string, std::string>> subChanges; |
| | int i = -1; |
| | auto objs = getRefObjects(); |
| | for (auto obj : objs) { |
| | ++i; |
| | auto& sub = subnames[i]; |
| | obj = obj->getSubObject(sub.c_str()); |
| | auto& shadow = shadowSubs[i]; |
| | if (shadow.empty() || !Data::hasMissingElement(sub.c_str())) { |
| | continue; |
| | } |
| | auto related = Part::Feature::getRelatedElements( |
| | obj, |
| | shadow.c_str(), |
| | Part::HistoryTraceType::followTypeChange, |
| | false |
| | ); |
| | if (!related.empty()) { |
| | auto& res = subChanges[i]; |
| | res.first = Data::ComplexGeoData::elementMapPrefix(); |
| | related.front().name.appendToBuffer(res.first); |
| | res.second.clear(); |
| | related.front().index.appendToStringBuffer(res.second); |
| | } |
| | else { |
| | std::string name = Data::oldElementName(shadow.c_str()); |
| | if (!name.empty()) { |
| | auto& res = subChanges[i]; |
| | res.first.clear(); |
| | res.second = name; |
| | } |
| | else { |
| | subnames[i] = shadow; |
| | } |
| | } |
| | } |
| | if (!subChanges.empty()) { |
| | |
| | |
| | |
| | |
| | auto subs = subnames; |
| | for (auto& change : subChanges) { |
| | auto [subkey, namechange] = change; |
| | auto [_oldname, newname] = namechange; |
| | subs[subkey] = newname; |
| | } |
| | auto pla = _calculateAttachedPlacement(objs, subs, origPlacement); |
| | |
| | if (pla.getPosition().IsEqual(origPlacement.getPosition(), Precision::Confusion()) |
| | && pla.getRotation().isSame(origPlacement.getRotation(), Precision::Angular())) { |
| | |
| | |
| | |
| | if (subChanged) { |
| | *subChanged = true; |
| | subnames = std::move(subs); |
| | for (auto& v : subChanges) { |
| | shadowSubs[v.first] = v.second.first; |
| | } |
| | } |
| | return pla; |
| | } |
| | } |
| | return _calculateAttachedPlacement(objs, subnames, origPlacement); |
| | } |
| |
|
| |
|
| | |
| |
|
| |
|
| | TYPESYSTEM_SOURCE(Attacher::AttachEngine3D, Attacher::AttachEngine) |
| |
|
| | AttachEngine3D::AttachEngine3D() |
| | { |
| | |
| | modeRefTypes.resize(mmDummy_NumberOfModes); |
| | refTypeString s; |
| | refTypeStringList ss; |
| |
|
| | modeRefTypes[mmTranslate].push_back(cat(rtVertex)); |
| |
|
| | ss.clear(); |
| | ss.push_back(cat(eRefType(rtAnything | rtFlagHasPlacement))); |
| | ss.push_back(cat(rtConic)); |
| | modeRefTypes[mmObjectXY] = ss; |
| | modeRefTypes[mmObjectXZ] = ss; |
| | modeRefTypes[mmObjectYZ] = ss; |
| |
|
| | modeRefTypes[mmParallelPlane].push_back(cat(eRefType(rtFlatFace | rtFlagHasPlacement), rtVertex)); |
| | modeRefTypes[mmParallelPlane].push_back(cat(eRefType(rtAnything | rtFlagHasPlacement), rtVertex)); |
| |
|
| | modeRefTypes[mmInertialCS].push_back(cat(rtAnything)); |
| | modeRefTypes[mmInertialCS].push_back(cat(rtAnything, rtAnything)); |
| | modeRefTypes[mmInertialCS].push_back(cat(rtAnything, rtAnything, rtAnything)); |
| | modeRefTypes[mmInertialCS].push_back(cat(rtAnything, rtAnything, rtAnything, rtAnything)); |
| |
|
| | modeRefTypes[mmFlatFace].push_back(cat(rtFlatFace)); |
| |
|
| | modeRefTypes[mmTangentPlane].push_back(cat(rtFace, rtVertex)); |
| | modeRefTypes[mmTangentPlane].push_back(cat(rtVertex, rtFace)); |
| |
|
| | |
| |
|
| | s = cat(rtEdge); |
| | modeRefTypes[mmNormalToPath].push_back(s); |
| |
|
| | s = cat(rtCurve); |
| | modeRefTypes[mmFrenetNB].push_back(s); |
| | modeRefTypes[mmFrenetTN].push_back(s); |
| | modeRefTypes[mmFrenetTB].push_back(s); |
| | modeRefTypes[mmRevolutionSection].push_back(s); |
| | modeRefTypes[mmConcentric].push_back(s); |
| | s = cat(rtCircle); |
| | modeRefTypes[mmRevolutionSection].push_back(s); |
| | modeRefTypes[mmConcentric].push_back(s); |
| |
|
| | |
| |
|
| | s = cat(rtEdge, rtVertex); |
| | modeRefTypes[mmNormalToPath].push_back(s); |
| | s = cat(rtVertex, rtEdge); |
| | modeRefTypes[mmNormalToPath].push_back(s); |
| |
|
| | s = cat(rtCurve, rtVertex); |
| | modeRefTypes[mmFrenetNB].push_back(s); |
| | modeRefTypes[mmFrenetTN].push_back(s); |
| | modeRefTypes[mmFrenetTB].push_back(s); |
| | modeRefTypes[mmRevolutionSection].push_back(s); |
| | modeRefTypes[mmConcentric].push_back(s); |
| | s = cat(rtCircle, rtVertex); |
| | modeRefTypes[mmRevolutionSection].push_back(s); |
| | modeRefTypes[mmConcentric].push_back(s); |
| |
|
| | s = cat(rtVertex, rtCurve); |
| | modeRefTypes[mmFrenetNB].push_back(s); |
| | modeRefTypes[mmFrenetTN].push_back(s); |
| | modeRefTypes[mmFrenetTB].push_back(s); |
| | modeRefTypes[mmRevolutionSection].push_back(s); |
| | modeRefTypes[mmConcentric].push_back(s); |
| | s = cat(rtVertex, rtCircle); |
| | modeRefTypes[mmRevolutionSection].push_back(s); |
| | modeRefTypes[mmConcentric].push_back(s); |
| |
|
| | |
| |
|
| | s = cat(rtVertex, rtVertex, rtVertex); |
| | modeRefTypes[mmThreePointsPlane].push_back(s); |
| | modeRefTypes[mmThreePointsNormal].push_back(s); |
| |
|
| | s = cat(rtLine, rtVertex); |
| | modeRefTypes[mmThreePointsPlane].push_back(s); |
| | modeRefTypes[mmThreePointsNormal].push_back(s); |
| |
|
| | s = cat(rtVertex, rtLine); |
| | modeRefTypes[mmThreePointsPlane].push_back(s); |
| | modeRefTypes[mmThreePointsNormal].push_back(s); |
| |
|
| | s = cat(rtLine, rtLine); |
| | modeRefTypes[mmThreePointsPlane].push_back(s); |
| | modeRefTypes[mmThreePointsNormal].push_back(s); |
| |
|
| | |
| | for (int mmode = mmOZX; mmode <= mmOYX; ++mmode) { |
| | modeRefTypes[mmode].push_back(cat(rtVertex, rtVertex, rtVertex)); |
| | modeRefTypes[mmode].push_back(cat(rtVertex, rtVertex, rtLine)); |
| | modeRefTypes[mmode].push_back(cat(rtVertex, rtLine, rtVertex)); |
| | modeRefTypes[mmode].push_back(cat(rtVertex, rtLine, rtLine)); |
| | modeRefTypes[mmode].push_back(cat(rtVertex, rtVertex)); |
| | modeRefTypes[mmode].push_back(cat(rtVertex, rtLine)); |
| | } |
| |
|
| |
|
| | modeRefTypes[mmFolding].push_back(cat(rtLine, rtLine, rtLine, rtLine)); |
| |
|
| | this->EnableAllSupportedModes(); |
| | } |
| |
|
| | AttachEngine3D* AttachEngine3D::copy() const |
| | { |
| | AttachEngine3D* p = new AttachEngine3D; |
| | p->setUp(*this); |
| | return p; |
| | } |
| |
|
| | Base::Placement AttachEngine3D::_calculateAttachedPlacement( |
| | const std::vector<App::DocumentObject*>& objs, |
| | const std::vector<std::string>& subs, |
| | const Base::Placement& origPlacement |
| | ) const |
| | { |
| | const eMapMode mmode = this->mapMode; |
| | if (mmode == mmDeactivated) { |
| | throw ExceptionCancel(); |
| | |
| | } |
| | std::vector<const TopoShape*> shapes; |
| | std::vector<TopoShape> copiedShapeStorage; |
| | std::vector<eRefType> types; |
| | readLinks(objs, subs, shapes, copiedShapeStorage, types); |
| |
|
| | if (shapes.empty()) { |
| | throw ExceptionCancel(); |
| | } |
| |
|
| | |
| | App::DocumentObject* subObj = objs[0]->getSubObject(subs[0].c_str()); |
| | Base::Placement Place = App::GeoFeature::getGlobalPlacement(subObj, objs[0], subs[0]); |
| | Base::Vector3d vec = Place.getPosition(); |
| | gp_Pnt refOrg = gp_Pnt(vec.x, vec.y, vec.z); |
| |
|
| | |
| | |
| | |
| | gp_Dir SketchNormal; |
| | gp_Vec SketchXAxis; |
| | gp_Pnt SketchBasePoint; |
| |
|
| |
|
| | switch (mmode) { |
| | case mmDeactivated: |
| | |
| | break; |
| | case mmTranslate: { |
| | if (shapes.empty()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: no subobjects " |
| | "specified (need one vertex)." |
| | ); |
| | } |
| | const TopoDS_Shape& sh = shapes[0]->getShape(); |
| | if (sh.IsNull()) { |
| | throw Base::ValueError("Null shape in AttachEngine3D::calculateAttachedPlacement()!"); |
| | } |
| | if (sh.ShapeType() != TopAbs_VERTEX) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: no subobjects " |
| | "specified (need one vertex)." |
| | ); |
| | } |
| | gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(sh)); |
| | Base::Placement plm = Base::Placement(); |
| | plm.setPosition(Base::Vector3d(p.X(), p.Y(), p.Z())); |
| | plm.setPosition(plm.getPosition() + this->attachmentOffset.getPosition()); |
| | plm.setRotation(origPlacement.getRotation()); |
| | return plm; |
| | } break; |
| | case mmObjectXY: |
| | case mmObjectXZ: |
| | case mmObjectYZ: |
| | case mmParallelPlane: { |
| | |
| | gp_Dir dirX, dirY, dirZ; |
| | if (types[0] & rtFlagHasPlacement) { |
| | Base::Vector3d dX, dY, |
| | dZ; |
| | Place.getRotation().multVec(Base::Vector3d(1, 0, 0), dX); |
| | Place.getRotation().multVec(Base::Vector3d(0, 1, 0), dY); |
| | Place.getRotation().multVec(Base::Vector3d(0, 0, 1), dZ); |
| | dirX = gp_Dir(dX.x, dX.y, dX.z); |
| | dirY = gp_Dir(dY.x, dY.y, dY.z); |
| | dirZ = gp_Dir(dZ.x, dZ.y, dZ.z); |
| | SketchBasePoint |
| | = 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]->getShape()); |
| | BRepAdaptor_Curve adapt(e); |
| | gp_Ax3 pos; |
| | switch (adapt.GetType()) { |
| | case GeomAbs_Ellipse: { |
| | gp_Elips cc = adapt.Ellipse(); |
| | pos = gp_Ax3(cc.Position()); |
| | } break; |
| | case GeomAbs_Hyperbola: { |
| | gp_Hypr cc = adapt.Hyperbola(); |
| | pos = gp_Ax3(cc.Position()); |
| | } break; |
| | case GeomAbs_Parabola: { |
| | gp_Parab cc = adapt.Parabola(); |
| | pos = gp_Ax3(cc.Position()); |
| | } break; |
| | default: |
| | assert(0); |
| | |
| | } |
| | dirX = pos.XDirection(); |
| | dirY = pos.YDirection(); |
| | dirZ = pos.Axis().Direction(); |
| | SketchBasePoint = pos.Location(); |
| | } |
| | else { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: need either a conic section edge, " |
| | "or a whole object for ObjectXY-like modes." |
| | ); |
| | } |
| |
|
| | switch (mmode) { |
| | case mmObjectXY: |
| | SketchNormal = dirZ; |
| | SketchXAxis = gp_Vec(dirX); |
| | break; |
| | case mmObjectXZ: |
| | SketchNormal = dirY.Reversed(); |
| | SketchXAxis = gp_Vec(dirX); |
| | break; |
| | case mmObjectYZ: |
| | SketchNormal = dirX; |
| | SketchXAxis = gp_Vec(dirY); |
| | break; |
| | case mmParallelPlane: { |
| | if (shapes.size() < 2) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: not " |
| | "enough subshapes (need one plane and one vertex)." |
| | ); |
| | } |
| |
|
| | TopoDS_Vertex vertex; |
| | try { |
| | vertex = TopoDS::Vertex(shapes[1]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (vertex.IsNull()) { |
| | throw Base::ValueError( |
| | "Null vertex in AttachEngine3D::calculateAttachedPlacement()!" |
| | ); |
| | } |
| |
|
| | SketchNormal = dirZ; |
| | SketchXAxis = gp_Vec(dirX); |
| |
|
| | |
| | Handle(Geom_Line) hCurve(new Geom_Line(SketchBasePoint, dirZ)); |
| | gp_Pnt p = BRep_Tool::Pnt(vertex); |
| | GeomAPI_ProjectPointOnCurve projector(p, hCurve); |
| | SketchBasePoint = projector.NearestPoint(); |
| | } break; |
| | default: |
| | break; |
| | } |
| |
|
| | } break; |
| | case mmInertialCS: { |
| | GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes); |
| | GProp_PrincipalProps pr = gpr.PrincipalProperties(); |
| | if (pr.HasSymmetryPoint()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement:InertialCS: " |
| | "inertia tensor is trivial, principal axes are undefined." |
| | ); |
| | } |
| | if (pr.HasSymmetryAxis()) { |
| | Base::Console().warning( |
| | "AttachEngine3D::calculateAttachedPlacement:InertialCS: inertia tensor has " |
| | "axis of symmetry. Second and third axes of inertia are undefined.\n" |
| | ); |
| | |
| | |
| | |
| | |
| | |
| | Standard_Real I1, I2, I3; |
| | pr.Moments(I1, I2, I3); |
| | Standard_Real d12, d23, d31; |
| | d12 = fabs(I1 - I2); |
| | d23 = fabs(I2 - I3); |
| | d31 = fabs(I3 - I1); |
| | if (d12 < d23 && d12 < d31) { |
| | SketchNormal = pr.ThirdAxisOfInertia(); |
| | } |
| | else if (d23 < d31 && d23 < d12) { |
| | SketchNormal = pr.FirstAxisOfInertia(); |
| | } |
| | else { |
| | SketchNormal = pr.SecondAxisOfInertia(); |
| | } |
| | } |
| | else { |
| | SketchNormal = pr.FirstAxisOfInertia(); |
| | SketchXAxis = pr.SecondAxisOfInertia(); |
| | } |
| | SketchBasePoint = gpr.CentreOfMass(); |
| | } break; |
| | case mmFlatFace: { |
| | if (shapes.empty()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: no subobjects " |
| | "specified (needed one planar face)." |
| | ); |
| | } |
| |
|
| | TopoDS_Face face; |
| | gp_Pln plane; |
| | bool Reverse = false; |
| | try { |
| | face = TopoDS::Face(shapes[0]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (face.IsNull()) { |
| | if (!TopoShape(*shapes[0]).findPlane(plane)) { |
| | throw Base::ValueError( |
| | "No planar face in AttachEngine3D::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | } |
| | else { |
| | BRepAdaptor_Surface adapt(face); |
| | if (adapt.GetType() == GeomAbs_Plane) { |
| | plane = adapt.Plane(); |
| | } |
| | else { |
| | TopLoc_Location loc; |
| | Handle(Geom_Surface) surf = BRep_Tool::Surface(face, loc); |
| | GeomLib_IsPlanarSurface check(surf, precision); |
| | if (check.IsPlanar()) { |
| | plane = check.Plan(); |
| | } |
| | else { |
| | throw Base::ValueError( |
| | "No planar face in AttachEngine3D::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | } |
| |
|
| | if (face.Orientation() == TopAbs_REVERSED) { |
| | Reverse = true; |
| | } |
| | } |
| |
|
| | Standard_Boolean ok = plane.Direct(); |
| | if (!ok) { |
| | |
| | plane.UReverse(); |
| | Reverse = !Reverse; |
| | } |
| | gp_Ax1 Normal = plane.Axis(); |
| | if (Reverse) { |
| | Normal.Reverse(); |
| | } |
| | SketchNormal = Normal.Direction(); |
| |
|
| | Handle(Geom_Plane) gPlane = new Geom_Plane(plane); |
| | GeomAPI_ProjectPointOnSurf projector(refOrg, gPlane); |
| | SketchBasePoint = projector.NearestPoint(); |
| |
|
| | } break; |
| | case mmTangentPlane: { |
| | if (shapes.size() < 2) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: not enough " |
| | "subshapes (need one face and one vertex)." |
| | ); |
| | } |
| |
|
| | bool bThruVertex = false; |
| | if (shapes[0]->shapeType() == TopAbs_VERTEX) { |
| | std::swap(shapes[0], shapes[1]); |
| | bThruVertex = true; |
| | } |
| |
|
| | TopoDS_Face face; |
| | try { |
| | face = TopoDS::Face(shapes[0]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (face.IsNull()) { |
| | throw Base::ValueError("Null face in AttachEngine3D::calculateAttachedPlacement()!"); |
| | } |
| |
|
| | TopoDS_Vertex vertex; |
| | try { |
| | vertex = TopoDS::Vertex(shapes[1]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (vertex.IsNull()) { |
| | throw Base::ValueError("Null vertex in AttachEngine3D::calculateAttachedPlacement()!"); |
| | } |
| |
|
| | Handle(Geom_Surface) hSurf = BRep_Tool::Surface(face); |
| | gp_Pnt p = BRep_Tool::Pnt(vertex); |
| |
|
| | GeomAPI_ProjectPointOnSurf projector(p, hSurf); |
| | double u, v; |
| | if (projector.NbPoints() == 0) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: projecting " |
| | "point onto surface failed." |
| | ); |
| | } |
| |
|
| | projector.LowerDistanceParameters(u, v); |
| | BRepAdaptor_Surface surf(face); |
| | BRepLProp_SLProps prop(surf, u, v, 1, Precision::Confusion()); |
| | gp_Dir dirX; |
| | Standard_Boolean done; |
| |
|
| | Tools::getNormal(face, u, v, Precision::Confusion(), SketchNormal, done); |
| |
|
| | if (!done) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: finding normal " |
| | "to surface at projected point failed." |
| | ); |
| | } |
| |
|
| | |
| | if (prop.IsTangentUDefined()) { |
| | prop.TangentU(dirX); |
| | if (face.Orientation() == TopAbs_REVERSED) { |
| | dirX.Reverse(); |
| | } |
| | } |
| | |
| | else { |
| | gp_Dir dirY; |
| | prop.TangentV(dirY); |
| | dirX = dirY.Crossed(SketchNormal); |
| | } |
| |
|
| | SketchXAxis = gp_Vec(dirX).Reversed(); |
| |
|
| | if (bThruVertex) { |
| | SketchBasePoint = p; |
| | } |
| | else { |
| | SketchBasePoint = projector.NearestPoint(); |
| | } |
| | } break; |
| | case mmNormalToPath: |
| | case mmFrenetNB: |
| | case mmFrenetTN: |
| | case mmFrenetTB: |
| | case mmRevolutionSection: |
| | case mmConcentric: { |
| | if (shapes.empty()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: no subshapes " |
| | "specified (need one edge, and an optional vertex)." |
| | ); |
| | } |
| |
|
| | bool bThruVertex = false; |
| | 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]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (path.IsNull()) { |
| | throw Base::ValueError("Null path in AttachEngine3D::calculateAttachedPlacement()!"); |
| | } |
| |
|
| | BRepAdaptor_Curve adapt(path); |
| |
|
| | double u = 0.0; |
| | double u1 = adapt.FirstParameter(); |
| | double u2 = adapt.LastParameter(); |
| | if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) { |
| | |
| | |
| | u1 = 0.0; |
| | u2 = 1.0; |
| | } |
| |
|
| | |
| | |
| | gp_Pnt p_in; |
| | if (shapes.size() >= 2) { |
| | TopoDS_Vertex vertex; |
| | try { |
| | vertex = TopoDS::Vertex(shapes[1]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (vertex.IsNull()) { |
| | throw Base::ValueError( |
| | "Null vertex in AttachEngine3D::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | p_in = BRep_Tool::Pnt(vertex); |
| |
|
| | Handle(Geom_Curve) hCurve = BRep_Tool::Curve(path, u1, u2); |
| |
|
| | GeomAPI_ProjectPointOnCurve projector(p_in, hCurve); |
| | u = projector.LowerDistanceParameter(); |
| | } |
| | else { |
| | u = u1 + this->attachParameter * (u2 - u1); |
| | } |
| | gp_Pnt p; |
| | gp_Vec d; |
| | adapt.D1(u, p, d); |
| |
|
| | if (d.Magnitude() < Precision::Confusion()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: path curve " |
| | "derivative is below 1e-7, too low, can't align" |
| | ); |
| | } |
| |
|
| | |
| | |
| | if (bThruVertex) { |
| | SketchBasePoint = p_in; |
| | } |
| | else { |
| | SketchBasePoint = p; |
| | } |
| |
|
| | if (mmode == mmRevolutionSection || mmode == mmConcentric || mmode == mmFrenetNB |
| | || mmode == mmFrenetTN || mmode == mmFrenetTB) { |
| | gp_Vec dd; |
| | try { |
| | adapt.D2(u, p, d, dd); |
| | } |
| | catch (Standard_Failure& e) { |
| | |
| | dd = gp_Vec(0., 0., 0.); |
| | Base::Console().warning( |
| | "AttachEngine3D::calculateAttachedPlacement: can't " |
| | "calculate second derivative of curve. OCC error: %s\n", |
| | e.GetMessageString() |
| | ); |
| | } |
| |
|
| | gp_Vec T, N, B; |
| | T = d.Normalized(); |
| | N = dd.Subtracted(T.Multiplied(dd.Dot(T))); |
| | |
| | if (N.Magnitude() > Precision::SquareConfusion()) { |
| | N.Normalize(); |
| | B = T.Crossed(N); |
| | } |
| | else { |
| | Base::Console().warning( |
| | "AttachEngine3D::calculateAttachedPlacement: path curve second derivative " |
| | "is below 1e-14, cannot align X-axis.\n" |
| | ); |
| | N = gp_Vec(0., 0., 0.); |
| | B = gp_Vec(0., 0., 0.); |
| | } |
| |
|
| |
|
| | switch (mmode) { |
| | case mmFrenetNB: |
| | case mmRevolutionSection: |
| | SketchNormal = T.Reversed(); |
| | |
| | SketchXAxis = N.Reversed(); |
| | break; |
| | case mmFrenetTN: |
| | case mmConcentric: |
| | if (N.Magnitude() == 0.0) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: Frenet-Serret normal " |
| | "is undefined. Can't align to TN plane." |
| | ); |
| | } |
| | SketchNormal = B; |
| | SketchXAxis = T; |
| | break; |
| | case mmFrenetTB: |
| | if (N.Magnitude() == 0.0) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: Frenet-Serret normal " |
| | "is undefined. Can't align to TB plane." |
| | ); |
| | } |
| | SketchNormal = N.Reversed(); |
| | |
| | SketchXAxis = T; |
| | break; |
| | default: |
| | assert(0); |
| | } |
| | if (mmode == mmRevolutionSection || mmode == mmConcentric) { |
| | |
| | if (N.Magnitude() == 0.0) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: path has infinite radius " |
| | "of curvature at the point. Can't align for revolving." |
| | ); |
| | } |
| | double curvature = dd.Dot(N) / pow(d.Magnitude(), 2); |
| | gp_Vec pv(p.XYZ()); |
| | pv.Add(N.Multiplied(1 / curvature)); |
| | |
| | SketchBasePoint = gp_Pnt(pv.XYZ()); |
| | |
| | |
| | } |
| | } |
| | else if (mmode == mmNormalToPath) { |
| | |
| | SketchNormal = gp_Dir(d.Reversed()); |
| | |
| | |
| | } |
| |
|
| | } break; |
| | case mmThreePointsPlane: |
| | case mmThreePointsNormal: { |
| |
|
| | std::vector<gp_Pnt> points; |
| |
|
| | for (const auto& shape : shapes) { |
| | const TopoDS_Shape& sh = shape->getShape(); |
| | if (sh.IsNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngine3D::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | if (sh.ShapeType() == TopAbs_VERTEX) { |
| | const TopoDS_Vertex& v = TopoDS::Vertex(sh); |
| | points.push_back(BRep_Tool::Pnt(v)); |
| | } |
| | else if (sh.ShapeType() == TopAbs_EDGE) { |
| | const TopoDS_Edge& e = TopoDS::Edge(sh); |
| | BRepAdaptor_Curve crv(e); |
| | double u1 = crv.FirstParameter(); |
| | double u2 = crv.LastParameter(); |
| | if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) { |
| | u1 = 0.0; |
| | u2 = 1.0; |
| | } |
| | points.push_back(crv.Value(u1)); |
| | points.push_back(crv.Value(u2)); |
| | } |
| | if (points.size() >= 3) { |
| | break; |
| | } |
| | } |
| |
|
| | if (points.size() < 3) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: less than 3 " |
| | "points are specified, cannot derive the plane." |
| | ); |
| | } |
| |
|
| | gp_Pnt p0 = points[0]; |
| | gp_Pnt p1 = points[1]; |
| | gp_Pnt p2 = points[2]; |
| |
|
| | gp_Vec vec01(p0, p1); |
| | gp_Vec vec02(p0, p2); |
| | if (vec01.Magnitude() < Precision::Confusion() |
| | || vec02.Magnitude() < Precision::Confusion()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: some of 3 " |
| | "points are coincident. Can't make a plane" |
| | ); |
| | } |
| | vec01.Normalize(); |
| | vec02.Normalize(); |
| |
|
| | gp_Vec norm; |
| | if (mmode == mmThreePointsPlane) { |
| | norm = vec01.Crossed(vec02); |
| | if (norm.Magnitude() < Precision::Confusion()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: points are " |
| | "collinear. Can't make a plane" |
| | ); |
| | } |
| | |
| | SketchBasePoint = gp_Pnt( |
| | gp_Vec(p0.XYZ()).Added(p1.XYZ()).Added(p2.XYZ()).Multiplied(1.0 / 3.0).XYZ() |
| | ); |
| | } |
| | else if (mmode == mmThreePointsNormal) { |
| | norm = vec02.Subtracted(vec01.Multiplied(vec02.Dot(vec01))) |
| | .Reversed(); |
| | if (norm.Magnitude() < Precision::Confusion()) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: points are " |
| | "collinear. Can't make a plane" |
| | ); |
| | } |
| | |
| |
|
| | Handle(Geom_Plane) gPlane = new Geom_Plane(p0, gp_Dir(norm)); |
| | GeomAPI_ProjectPointOnSurf projector(p2, gPlane); |
| | SketchBasePoint = projector.NearestPoint(); |
| | } |
| |
|
| | norm.Normalize(); |
| | SketchNormal = gp_Dir(norm); |
| |
|
| | } break; |
| | case mmFolding: { |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | if (shapes.size() < 4) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: not enough " |
| | "shapes (need 4 lines: edgeA, axisA, axisB, edgeB)." |
| | ); |
| | } |
| |
|
| | |
| | const TopoDS_Edge* edges[4]; |
| | BRepAdaptor_Curve adapts[4]; |
| | gp_Lin lines[4]; |
| | for (int i = 0; i < 4; i++) { |
| | try { |
| | edges[i] = &TopoDS::Edge(shapes[i]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (edges[i]->IsNull()) { |
| | throw Base::ValueError( |
| | "Null edge in AttachEngine3D::calculateAttachedPlacement()!" |
| | ); |
| | } |
| |
|
| | adapts[i] = BRepAdaptor_Curve(*(edges[i])); |
| | if (adapts[i].GetType() != GeomAbs_Line) { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: Folding - non-straight edge." |
| | ); |
| | } |
| | lines[i] = adapts[i].Line(); |
| | } |
| |
|
| | |
| | gp_Pnt p, p1, p2, p3, p4; |
| | double signs[4] = {0, 0, 0, 0}; |
| | |
| | p1 = adapts[0].Value(adapts[0].FirstParameter()); |
| | p2 = adapts[0].Value(adapts[0].LastParameter()); |
| | p3 = adapts[1].Value(adapts[1].FirstParameter()); |
| | p4 = adapts[1].Value(adapts[1].LastParameter()); |
| | p = p1; |
| | if (p1.Distance(p3) < Precision::Confusion()) { |
| | p = p3; |
| | signs[0] = +1.0; |
| | signs[1] = +1.0; |
| | } |
| | else if (p1.Distance(p4) < Precision::Confusion()) { |
| | p = p4; |
| | signs[0] = +1.0; |
| | signs[1] = -1.0; |
| | } |
| | else if (p2.Distance(p3) < Precision::Confusion()) { |
| | p = p3; |
| | signs[0] = -1.0; |
| | signs[1] = +1.0; |
| | } |
| | else if (p2.Distance(p4) < Precision::Confusion()) { |
| | p = p4; |
| | signs[0] = -1.0; |
| | signs[1] = -1.0; |
| | } |
| | else { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: Folding - " |
| | "edges to not share a vertex." |
| | ); |
| | } |
| | for (int i = 2; i < 4; i++) { |
| | p1 = adapts[i].Value(adapts[i].FirstParameter()); |
| | p2 = adapts[i].Value(adapts[i].LastParameter()); |
| | if (p.Distance(p1) < Precision::Confusion()) { |
| | signs[i] = +1.0; |
| | } |
| | else if (p.Distance(p2) < Precision::Confusion()) { |
| | signs[i] = -1.0; |
| | } |
| | else { |
| | throw Base::ValueError( |
| | "AttachEngine3D::calculateAttachedPlacement: Folding - " |
| | "edges to not share a vertex." |
| | ); |
| | } |
| | } |
| |
|
| | gp_Vec dirs[4]; |
| | for (int i = 0; i < 4; i++) { |
| | assert(fabs(signs[i]) == 1.0); |
| | dirs[i] = gp_Vec(lines[i].Direction()).Multiplied(signs[i]); |
| | } |
| |
|
| | double ang = this->calculateFoldAngle(dirs[1], dirs[2], dirs[0], dirs[3]); |
| |
|
| | gp_Vec norm = dirs[1].Crossed(dirs[2]); |
| | |
| | |
| | norm.Rotate(gp_Ax1(gp_Pnt(), gp_Dir(dirs[1])), -ang); |
| | SketchNormal = norm.Reversed(); |
| |
|
| | SketchXAxis = dirs[1]; |
| |
|
| | SketchBasePoint = p; |
| |
|
| | } break; |
| | case mmOZX: |
| | case mmOZY: |
| | case mmOXY: |
| | case mmOXZ: |
| | case mmOYZ: |
| | case mmOYX: { |
| | const char orderStrings[6][4] = { |
| | "ZXY", |
| | "ZYX", |
| | "XYZ", |
| | "XZY", |
| | "YZX", |
| | "YXZ", |
| | }; |
| | const char* orderString = orderStrings[mmode - mmOZX]; |
| |
|
| | enum dirIndex |
| | { |
| | X, |
| | Y, |
| | Z |
| | }; |
| | int order[3]; |
| | for (int i = 0; i < 3; ++i) { |
| | order[i] = orderString[i] - 'X'; |
| | } |
| |
|
| | if (shapes.size() < 2) { |
| | THROWM( |
| | Base::ValueError, |
| | "AttachEngine3D::calculateAttachedPlacement: not enough shapes linked (at " |
| | "least two are required)." |
| | ); |
| | } |
| |
|
| | gp_Vec dirs[3]; |
| |
|
| | |
| | if (shapes[0]->isNull()) { |
| | THROWM(Base::TypeError, "AttachEngine3D::calculateAttachedPlacement: null shape!") |
| | } |
| | 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]->getShape())); |
| |
|
| | |
| | for (size_t i = 1; i < 3 && i < shapes.size(); ++i) { |
| | 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]->getShape())); |
| | dirs[order[i - 1]] = gp_Vec(SketchBasePoint, p); |
| | } |
| | 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(); |
| | if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) { |
| | u1 = 0.0; |
| | u2 = 1.0; |
| | } |
| | gp_Pnt p1 = crv.Value(u1); |
| | gp_Pnt p2 = crv.Value(u2); |
| | dirs[order[i - 1]] = gp_Vec(p1, p2); |
| | } |
| | } |
| |
|
| | |
| | Base::Rotation rot = Base::Rotation::makeRotationByAxes( |
| | Base::Vector3d(dirs[0].X(), dirs[0].Y(), dirs[0].Z()), |
| | Base::Vector3d(dirs[1].X(), dirs[1].Y(), dirs[1].Z()), |
| | Base::Vector3d(dirs[2].X(), dirs[2].Y(), dirs[2].Z()), |
| | orderString |
| | ); |
| | if (this->mapReverse) { |
| | rot = rot * Base::Rotation(Base::Vector3d(0, 1, 0), std::numbers::pi); |
| | } |
| |
|
| | Base::Placement plm = Base::Placement( |
| | Base::Vector3d(SketchBasePoint.X(), SketchBasePoint.Y(), SketchBasePoint.Z()), |
| | rot |
| | ); |
| | plm *= this->attachmentOffset; |
| | return plm; |
| | } break; |
| | case mmMidpoint: { |
| | Base::Placement placement; |
| |
|
| | |
| | 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 = freecad_cast<GeomPoint*>(geom.get())) { |
| | placement.setPosition(point->getPoint()); |
| | } |
| | } break; |
| |
|
| | case TopAbs_EDGE: { |
| | if (auto conic = freecad_cast<GeomConic*>(geom.get())) { |
| | placement.setPosition(conic->getLocation()); |
| | placement.setRotation(conic->getRotation().value_or(Base::Rotation {})); |
| | } |
| | else if (auto line = freecad_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)); |
| | } |
| |
|
| | |
| | const TopoDS_Shape& sh = shape->getShape(); |
| | if (!sh.IsNull() && sh.ShapeType() == TopAbs_EDGE) { |
| | TopoDS_Edge ed = TopoDS::Edge(sh); |
| | BRepAdaptor_Curve adapt(ed); |
| | if (adapt.GetType() == GeomAbs_Circle) { |
| | |
| | const gp_Circ circ = adapt.Circle(); |
| | const gp_Pnt center = circ.Location(); |
| | const gp_Dir axisDir = circ.Axis().Direction(); |
| |
|
| | placement.setPosition(Base::convertTo<Base::Vector3d>(center)); |
| | placement.setRotation( |
| | Base::Rotation::fromNormalVector( |
| | Base::convertTo<Base::Vector3d>(axisDir) |
| | ) |
| | ); |
| | break; |
| | } |
| | } |
| | } break; |
| |
|
| | case TopAbs_FACE: { |
| | auto surface = freecad_cast<GeomSurface*>(geom.get()); |
| |
|
| | auto face = TopoDS::Face(shape->getShape()); |
| | auto adaptorSurface = BRepAdaptor_Surface(face, true); |
| |
|
| | auto u1 = adaptorSurface.FirstUParameter(); |
| | auto u2 = adaptorSurface.LastUParameter(); |
| | auto v1 = adaptorSurface.FirstVParameter(); |
| | auto v2 = adaptorSurface.LastVParameter(); |
| |
|
| | auto midU = (u1 + u2) / 2; |
| | auto midV = (v1 + v2) / 2; |
| |
|
| | |
| | if (adaptorSurface.GetType() == GeomAbs_Cylinder) { |
| | const gp_Cylinder cyl = adaptorSurface.Cylinder(); |
| | const gp_Ax1 axis = cyl.Axis(); |
| | const gp_Pnt origin = axis.Location(); |
| | const gp_Dir axisDir = axis.Direction(); |
| |
|
| | const gp_Pnt midPnt = adaptorSurface.Value(midU, midV); |
| |
|
| | |
| | const gp_Vec v(origin, midPnt); |
| | const Standard_Real t = v.Dot(gp_Vec(axisDir)); |
| | const gp_Pnt axisCenter = origin.Translated(gp_Vec(axisDir) * t); |
| |
|
| | placement.setPosition(Base::convertTo<Base::Vector3d>(axisCenter)); |
| | placement.setRotation( |
| | Base::Rotation::fromNormalVector(Base::convertTo<Base::Vector3d>(axisDir)) |
| | ); |
| | break; |
| | } |
| |
|
| | if (auto sphere = freecad_cast<GeomSphere*>(geom.get())) { |
| | placement.setPosition(sphere->getLocation()); |
| | } |
| | else if (auto cone = freecad_cast<GeomCone*>(geom.get())) { |
| | placement.setPosition(cone->getApex()); |
| | } |
| | else if (auto point = surface->point(midU, midV)) { |
| | placement.setPosition(*point); |
| | } |
| | else if (auto com = shape->centerOfGravity()) { |
| | placement.setPosition(*com); |
| | } |
| | else { |
| | placement.setPosition(shape->getBoundBox().GetCenter()); |
| | } |
| |
|
| | |
| | gp_Dir dir; |
| | surface->normal(midU, midV, dir); |
| |
|
| | if (face.Orientation() == TopAbs_REVERSED) { |
| | dir = -dir; |
| | } |
| |
|
| | placement.setRotation(rotationAlignedToNormal( |
| | placement.getRotation(), |
| | 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); |
| | } |
| |
|
| | |
| |
|
| | Base::Placement plm = this->placementFactory( |
| | SketchNormal, |
| | SketchXAxis, |
| | SketchBasePoint, |
| | gp_Pnt(), |
| | false, |
| | false, |
| | false, |
| | mmode == mmFlatFace, |
| | &Place |
| | ); |
| | plm *= this->attachmentOffset; |
| | return plm; |
| | } |
| |
|
| | double AttachEngine3D::calculateFoldAngle(gp_Vec axA, gp_Vec axB, gp_Vec edA, gp_Vec edB) const |
| | { |
| | |
| | |
| | |
| | |
| | axA.Normalize(); |
| | axB.Normalize(); |
| | edA.Normalize(); |
| | edB.Normalize(); |
| | gp_Vec norm = axA.Crossed(axB); |
| | if (norm.Magnitude() < Precision::Confusion()) { |
| | throw AttachEngineException( |
| | "calculateFoldAngle: Folding axes are parallel, folding angle cannot be computed." |
| | ); |
| | } |
| | norm.Normalize(); |
| | double a = edA.Dot(axA); |
| | double ra = edA.Crossed(axA).Magnitude(); |
| | if (fabs(ra) < Precision::Confusion()) { |
| | throw AttachEngineException( |
| | "calculateFoldAngle: axisA and edgeA are parallel, folding can't be computed." |
| | ); |
| | } |
| | double b = edB.Dot(axB); |
| | double costheta = axB.Dot(axA); |
| | double sintheta = axA.Crossed(axB).Dot(norm); |
| | double singama = -costheta; |
| | double cosgama = sintheta; |
| | double k = b * cosgama; |
| | double l = a + b * singama; |
| | double xa = k + l * singama / cosgama; |
| | double cos_unfold = -xa / ra; |
| | if (fabs(cos_unfold) > 0.999) { |
| | throw AttachEngineException( |
| | "calculateFoldAngle: cosine of folding angle is too close to or above 1." |
| | ); |
| | } |
| | return acos(cos_unfold); |
| | } |
| |
|
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE(Attacher::AttachEnginePlane, Attacher::AttachEngine) |
| |
|
| | AttachEnginePlane::AttachEnginePlane() |
| | { |
| | |
| | AttachEngine3D attacher3D; |
| | this->modeRefTypes = attacher3D.modeRefTypes; |
| | this->EnableAllSupportedModes(); |
| | } |
| |
|
| | AttachEnginePlane* AttachEnginePlane::copy() const |
| | { |
| | AttachEnginePlane* p = new AttachEnginePlane; |
| | p->setUp(*this); |
| | return p; |
| | } |
| |
|
| | Base::Placement AttachEnginePlane::_calculateAttachedPlacement( |
| | const std::vector<App::DocumentObject*>& objs, |
| | const std::vector<std::string>& subs, |
| | const Base::Placement& origPlacement |
| | ) const |
| | { |
| | |
| | Base::Placement plm; |
| | AttachEngine3D attacher3D; |
| | attacher3D.precision = precision; |
| | attacher3D.setUp(*this); |
| | plm = attacher3D._calculateAttachedPlacement(objs, subs, origPlacement); |
| | return plm; |
| | } |
| |
|
| | double AttachEnginePlane::planarPrecision() |
| | { |
| | return 2.0e-7; |
| | } |
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE(Attacher::AttachEngineLine, Attacher::AttachEngine) |
| |
|
| | AttachEngineLine::AttachEngineLine() |
| | { |
| | |
| | modeRefTypes.resize(mmDummy_NumberOfModes); |
| | refTypeString s; |
| |
|
| | |
| | AttachEngine3D attacher3D; |
| | modeRefTypes[mm1AxisX] = attacher3D.modeRefTypes[mmObjectYZ]; |
| | modeRefTypes[mm1AxisY] = attacher3D.modeRefTypes[mmObjectXZ]; |
| | modeRefTypes[mm1AxisZ] = attacher3D.modeRefTypes[mmObjectXY]; |
| | modeRefTypes[mm1AxisCurv] = attacher3D.modeRefTypes[mmRevolutionSection]; |
| | modeRefTypes[mm1Binormal] = attacher3D.modeRefTypes[mmFrenetTN]; |
| | modeRefTypes[mm1Normal] = attacher3D.modeRefTypes[mmFrenetTB]; |
| | modeRefTypes[mm1Tangent] = attacher3D.modeRefTypes[mmNormalToPath]; |
| |
|
| | modeRefTypes[mm1TwoPoints].push_back(cat(rtVertex, rtVertex)); |
| | modeRefTypes[mm1TwoPoints].push_back(cat(rtLine)); |
| |
|
| | modeRefTypes[mm1Asymptote1].push_back(cat(rtHyperbola)); |
| | modeRefTypes[mm1Asymptote2].push_back(cat(rtHyperbola)); |
| |
|
| | modeRefTypes[mm1Directrix1].push_back(cat(rtConic)); |
| |
|
| | modeRefTypes[mm1Directrix2].push_back(cat(rtEllipse)); |
| | modeRefTypes[mm1Directrix2].push_back(cat(rtHyperbola)); |
| |
|
| | modeRefTypes[mm1Proximity].push_back(cat(rtAnything, rtAnything)); |
| |
|
| | modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything)); |
| | modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything, rtAnything)); |
| | modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything, rtAnything, rtAnything)); |
| | modeRefTypes[mm1AxisInertia1].push_back(cat(rtAnything, rtAnything, rtAnything, rtAnything)); |
| | modeRefTypes[mm1AxisInertia2] = modeRefTypes[mm1AxisInertia1]; |
| | modeRefTypes[mm1AxisInertia3] = modeRefTypes[mm1AxisInertia1]; |
| |
|
| | modeRefTypes[mm1FaceNormal] = attacher3D.modeRefTypes[mmTangentPlane]; |
| |
|
| | modeRefTypes[mm1Intersection].push_back(cat(rtFace, rtFace)); |
| |
|
| | this->EnableAllSupportedModes(); |
| | } |
| |
|
| | AttachEngineLine* AttachEngineLine::copy() const |
| | { |
| | AttachEngineLine* p = new AttachEngineLine; |
| | p->setUp(*this); |
| | return p; |
| | } |
| |
|
| | Base::Placement AttachEngineLine::_calculateAttachedPlacement( |
| | const std::vector<App::DocumentObject*>& objs, |
| | const std::vector<std::string>& subs, |
| | const Base::Placement& origPlacement |
| | ) const |
| | { |
| | eMapMode mmode = this->mapMode; |
| |
|
| | |
| | bool bReUsed = true; |
| | Base::Placement presuperPlacement; |
| | switch (mmode) { |
| | case mmDeactivated: |
| | throw ExceptionCancel(); |
| | |
| | case mm1AxisX: |
| | mmode = mmObjectYZ; |
| | break; |
| | case mm1AxisY: |
| | mmode = mmObjectXZ; |
| | break; |
| | case mm1AxisZ: |
| | mmode = mmObjectXY; |
| | break; |
| | case mm1AxisCurv: |
| | mmode = mmRevolutionSection; |
| | |
| | presuperPlacement.setRotation( |
| | Base::Rotation(Base::Vector3d(0.0, 0.0, 1.0), Base::Vector3d(0.0, 1.0, 0.0)) |
| | ); |
| | break; |
| | case mm1Binormal: |
| | mmode = mmFrenetTN; |
| | break; |
| | case mm1Normal: |
| | mmode = mmFrenetTB; |
| | break; |
| | case mm1Tangent: |
| | mmode = mmNormalToPath; |
| | break; |
| | case mm1FaceNormal: |
| | mmode = mmTangentPlane; |
| | break; |
| | default: |
| | bReUsed = false; |
| | break; |
| | } |
| |
|
| | Base::Placement plm; |
| | if (!bReUsed) { |
| | std::vector<const TopoShape*> shapes; |
| | std::vector<TopoShape> copiedShapeStorage; |
| | std::vector<eRefType> types; |
| | readLinks(objs, subs, shapes, copiedShapeStorage, types); |
| |
|
| | if (shapes.empty()) { |
| | throw ExceptionCancel(); |
| | } |
| |
|
| |
|
| | |
| | App::DocumentObject* subObj = objs[0]->getSubObject(subs[0].c_str()); |
| | Base::Placement Place = App::GeoFeature::getGlobalPlacement(subObj, objs[0], subs[0]); |
| | Base::Vector3d vec = Place.getPosition(); |
| | gp_Pnt refOrg = gp_Pnt(vec.x, vec.y, vec.z); |
| |
|
| | |
| | |
| | gp_Dir LineDir; |
| | gp_Pnt LineBasePoint; |
| |
|
| |
|
| | switch (mmode) { |
| | case mm1AxisInertia1: |
| | case mm1AxisInertia2: |
| | case mm1AxisInertia3: { |
| | GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes); |
| | LineBasePoint = gpr.CentreOfMass(); |
| | GProp_PrincipalProps pr = gpr.PrincipalProperties(); |
| | if (pr.HasSymmetryPoint()) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia " |
| | "tensor is trivial, principal axes are undefined." |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | Standard_Real I1, I2, I3; |
| | pr.Moments(I1, I2, I3); |
| | Standard_Real d12, d23, d31; |
| | d12 = fabs(I1 - I2); |
| | d23 = fabs(I2 - I3); |
| | d31 = fabs(I3 - I1); |
| |
|
| | if (mmode == mm1AxisInertia1) { |
| | LineDir = pr.FirstAxisOfInertia(); |
| | if (pr.HasSymmetryAxis() && !(d23 < d31 && d23 < d12)) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia " |
| | "tensor has axis of symmetry; first axis of inertia is undefined." |
| | ); |
| | } |
| | } |
| | else if (mmode == mm1AxisInertia2) { |
| | LineDir = pr.SecondAxisOfInertia(); |
| | if (pr.HasSymmetryAxis() && !(d31 < d12 && d31 < d23)) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia " |
| | "tensor has axis of symmetry; second axis of inertia is undefined." |
| | ); |
| | } |
| | } |
| | else if (mmode == mm1AxisInertia3) { |
| | LineDir = pr.ThirdAxisOfInertia(); |
| | if (pr.HasSymmetryAxis() && !(d12 < d23 && d12 < d31)) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement:AxisOfInertia: inertia " |
| | "tensor has axis of symmetry; third axis of inertia is undefined." |
| | ); |
| | } |
| | } |
| | } break; |
| | case mm1TwoPoints: { |
| | std::vector<gp_Pnt> points; |
| |
|
| | for (const auto& shape : shapes) { |
| | const TopoDS_Shape& sh = shape->getShape(); |
| | if (sh.IsNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | if (sh.ShapeType() == TopAbs_VERTEX) { |
| | const TopoDS_Vertex& v = TopoDS::Vertex(sh); |
| | points.push_back(BRep_Tool::Pnt(v)); |
| | } |
| | else if (sh.ShapeType() == TopAbs_EDGE) { |
| | const TopoDS_Edge& e = TopoDS::Edge(sh); |
| | BRepAdaptor_Curve crv(e); |
| | double u1 = crv.FirstParameter(); |
| | double u2 = crv.LastParameter(); |
| | if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2)) { |
| | u1 = 0.0; |
| | u2 = 1.0; |
| | } |
| | points.push_back(crv.Value(u1)); |
| | points.push_back(crv.Value(u2)); |
| | } |
| | if (points.size() >= 2) { |
| | break; |
| | } |
| | } |
| |
|
| | if (points.size() < 2) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: less " |
| | "than 2 points are specified, cannot derive the line." |
| | ); |
| | } |
| |
|
| | gp_Pnt p0 = points[0]; |
| | gp_Pnt p1 = points[1]; |
| |
|
| | LineDir = gp_Dir(gp_Vec(p0, p1)); |
| | LineBasePoint = p0; |
| |
|
| | } break; |
| | case mm1Asymptote1: |
| | case mm1Asymptote2: { |
| | if (shapes[0]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | TopoDS_Edge e; |
| | try { |
| | e = TopoDS::Edge(shapes[0]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (e.IsNull()) { |
| | throw Base::ValueError( |
| | "Null edge in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | BRepAdaptor_Curve adapt(e); |
| | if (adapt.GetType() != GeomAbs_Hyperbola) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: Asymptotes are available " |
| | "only for hyperbola-shaped edges, the one supplied is not." |
| | ); |
| | } |
| | gp_Hypr hyp = adapt.Hyperbola(); |
| | if (mmode == mm1Asymptote1) { |
| | LineDir = hyp.Asymptote1().Direction(); |
| | } |
| | else { |
| | LineDir = hyp.Asymptote2().Direction(); |
| | } |
| | LineBasePoint = hyp.Location(); |
| | } break; |
| | case mm1Directrix1: |
| | case mm1Directrix2: { |
| | if (shapes[0]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | TopoDS_Edge e; |
| | try { |
| | e = TopoDS::Edge(shapes[0]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (e.IsNull()) { |
| | throw Base::ValueError( |
| | "Null edge in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | BRepAdaptor_Curve adapt(e); |
| | gp_Ax1 dx1, dx2; |
| | switch (adapt.GetType()) { |
| | case GeomAbs_Ellipse: { |
| | gp_Elips cc = adapt.Ellipse(); |
| | dx1 = cc.Directrix1(); |
| | dx2 = cc.Directrix2(); |
| | } break; |
| | case GeomAbs_Hyperbola: { |
| | gp_Hypr cc = adapt.Hyperbola(); |
| | dx1 = cc.Directrix1(); |
| | dx2 = cc.Directrix2(); |
| | } break; |
| | case GeomAbs_Parabola: { |
| | gp_Parab cc = adapt.Parabola(); |
| | dx1 = cc.Directrix(); |
| | if (mmode == mm1Directrix2) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: " |
| | "Parabola has no second directrix" |
| | ); |
| | } |
| | } break; |
| | default: |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: referenced edge is not " |
| | "a conic section with a directrix" |
| | ); |
| | } |
| | if (mmode == mm1Directrix1) { |
| | LineDir = dx1.Direction(); |
| | LineBasePoint = dx1.Location(); |
| | } |
| | else { |
| | LineDir = dx2.Direction(); |
| | LineBasePoint = dx2.Location(); |
| | } |
| | } break; |
| | case mm1Intersection: { |
| | if (shapes.size() < 2) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: Intersection mode requires " |
| | "two shapes; only one is supplied" |
| | ); |
| | } |
| | if (shapes[0]->isNull() || shapes[1]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| |
|
| | 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); |
| | GeomAPI_IntSS intersector(hSurf1, hSurf2, Precision::Confusion()); |
| | if (!intersector.IsDone()) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: Intersection failed" |
| | ); |
| | } |
| |
|
| | const Standard_Integer intLines = intersector.NbLines(); |
| | if (intLines == 0) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: The two " |
| | "shapes don't intersect" |
| | ); |
| | } |
| | if (intLines != 1) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: " |
| | "Intersection is not a single curve" |
| | ); |
| | } |
| |
|
| | GeomAdaptor_Curve adapt(intersector.Line(1)); |
| | if (adapt.GetType() != GeomAbs_Line) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: " |
| | "Intersection is not a straight line" |
| | ); |
| | } |
| |
|
| | LineBasePoint = adapt.Line().Location(); |
| | LineDir = adapt.Line().Direction(); |
| | } break; |
| | case mm1Proximity: { |
| | if (shapes.size() < 2) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: Proximity mode requires two " |
| | "shapes; only one is supplied" |
| | ); |
| | } |
| | if (shapes[0]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | if (shapes[1]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEngineLine::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | BRepExtrema_DistShapeShape distancer(shapes[0]->getShape(), shapes[1]->getShape()); |
| | if (!distancer.IsDone()) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: " |
| | "proximity calculation failed." |
| | ); |
| | } |
| | if (distancer.NbSolution() > 1) { |
| | Base::Console().warning( |
| | "AttachEngineLine::calculateAttachedPlacement: " |
| | "proximity calculation gave %i solutions, ambiguous.\n", |
| | int(distancer.NbSolution()) |
| | ); |
| | } |
| | gp_Pnt p1 = distancer.PointOnShape1(1); |
| | gp_Pnt p2 = distancer.PointOnShape2(1); |
| | LineBasePoint = p1; |
| | gp_Vec dist = gp_Vec(p1, p2); |
| | if (dist.Magnitude() < Precision::Confusion()) { |
| | throw Base::ValueError( |
| | "AttachEngineLine::calculateAttachedPlacement: can't make proximity line, " |
| | "because shapes touch or intersect" |
| | ); |
| | } |
| | LineDir = gp_Dir(dist); |
| | } break; |
| | default: |
| | throwWrongMode(mmode); |
| | } |
| |
|
| | plm = this->placementFactory( |
| | LineDir, |
| | gp_Vec(), |
| | LineBasePoint, |
| | refOrg, |
| | true |
| | ); |
| | } |
| | else { |
| | AttachEngine3D attacher3D; |
| | attacher3D.setUp(*this); |
| | attacher3D.mapMode = mmode; |
| | attacher3D.attachmentOffset |
| | = Base::Placement(); |
| | |
| | plm = attacher3D._calculateAttachedPlacement(objs, subs, origPlacement); |
| | plm *= presuperPlacement; |
| | } |
| | plm *= this->attachmentOffset; |
| | return plm; |
| | } |
| |
|
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE(Attacher::AttachEnginePoint, Attacher::AttachEngine) |
| |
|
| | AttachEnginePoint::AttachEnginePoint() |
| | { |
| | |
| | modeRefTypes.resize(mmDummy_NumberOfModes); |
| | refTypeString s; |
| |
|
| | |
| | AttachEngine3D attacher3D; |
| | modeRefTypes[mm0Origin] = attacher3D.modeRefTypes[mmObjectXY]; |
| | modeRefTypes[mm0CenterOfCurvature] = attacher3D.modeRefTypes[mmRevolutionSection]; |
| | modeRefTypes[mm0OnEdge] = attacher3D.modeRefTypes[mmNormalToPath]; |
| |
|
| | modeRefTypes[mm0Vertex].push_back(cat(rtVertex)); |
| | modeRefTypes[mm0Vertex].push_back(cat(rtLine)); |
| |
|
| | modeRefTypes[mm0Focus1].push_back(cat(rtConic)); |
| |
|
| | modeRefTypes[mm0Focus2].push_back(cat(rtEllipse)); |
| | modeRefTypes[mm0Focus2].push_back(cat(rtHyperbola)); |
| |
|
| | s = cat(rtAnything, rtAnything); |
| | modeRefTypes[mm0ProximityPoint1].push_back(s); |
| | modeRefTypes[mm0ProximityPoint2].push_back(s); |
| |
|
| | modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything)); |
| | modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything, rtAnything)); |
| | modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything, rtAnything, rtAnything)); |
| | modeRefTypes[mm0CenterOfMass].push_back(cat(rtAnything, rtAnything, rtAnything, rtAnything)); |
| |
|
| | this->EnableAllSupportedModes(); |
| | } |
| |
|
| | AttachEnginePoint* AttachEnginePoint::copy() const |
| | { |
| | AttachEnginePoint* p = new AttachEnginePoint; |
| | p->setUp(*this); |
| | return p; |
| | } |
| |
|
| | Base::Placement AttachEnginePoint::_calculateAttachedPlacement( |
| | const std::vector<App::DocumentObject*>& objs, |
| | const std::vector<std::string>& subs, |
| | const Base::Placement& origPlacement |
| | ) const |
| | { |
| | eMapMode mmode = this->mapMode; |
| |
|
| | |
| | bool bReUsed = true; |
| | switch (mmode) { |
| | case mmDeactivated: |
| | throw ExceptionCancel(); |
| | |
| | case mm0Origin: |
| | mmode = mmObjectXY; |
| | break; |
| | case mm0CenterOfCurvature: |
| | mmode = mmRevolutionSection; |
| | break; |
| | case mm0OnEdge: |
| | |
| | mmode = mmNormalToPath; |
| | break; |
| | default: |
| | bReUsed = false; |
| | } |
| |
|
| | Base::Placement plm; |
| | if (!bReUsed) { |
| | std::vector<const TopoShape*> shapes; |
| | std::vector<TopoShape> copiedShapeStorage; |
| | std::vector<eRefType> types; |
| | readLinks(objs, subs, shapes, copiedShapeStorage, types); |
| |
|
| | if (shapes.empty()) { |
| | throw ExceptionCancel(); |
| | } |
| |
|
| |
|
| | |
| | |
| | gp_Pnt BasePoint; |
| |
|
| |
|
| | switch (mmode) { |
| | case mm0Vertex: { |
| | std::vector<gp_Pnt> points; |
| | assert(!shapes.empty()); |
| |
|
| | const TopoDS_Shape& sh = shapes[0]->getShape(); |
| | if (sh.IsNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEnginePoint::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | if (sh.ShapeType() == TopAbs_VERTEX) { |
| | const TopoDS_Vertex& v = TopoDS::Vertex(sh); |
| | BasePoint = BRep_Tool::Pnt(v); |
| | } |
| | else if (sh.ShapeType() == TopAbs_EDGE) { |
| | const TopoDS_Edge& e = TopoDS::Edge(sh); |
| | BRepAdaptor_Curve crv(e); |
| | double u = crv.FirstParameter(); |
| | if (Precision::IsInfinite(u)) { |
| | throw Base::ValueError("Edge is infinite"); |
| | } |
| | BasePoint = crv.Value(u); |
| | } |
| |
|
| | } break; |
| | case mm0Focus1: |
| | case mm0Focus2: { |
| | if (shapes[0]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEnginePoint::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | TopoDS_Edge e; |
| | try { |
| | e = TopoDS::Edge(shapes[0]->getShape()); |
| | } |
| | catch (...) { |
| | } |
| | if (e.IsNull()) { |
| | throw Base::ValueError( |
| | "Null edge in AttachEnginePoint::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | BRepAdaptor_Curve adapt(e); |
| | gp_Pnt f1, f2; |
| | switch (adapt.GetType()) { |
| | case GeomAbs_Ellipse: { |
| | gp_Elips cc = adapt.Ellipse(); |
| | f1 = cc.Focus1(); |
| | f2 = cc.Focus2(); |
| | } break; |
| | case GeomAbs_Hyperbola: { |
| | gp_Hypr cc = adapt.Hyperbola(); |
| | f1 = cc.Focus1(); |
| | f2 = cc.Focus2(); |
| | } break; |
| | case GeomAbs_Parabola: { |
| | gp_Parab cc = adapt.Parabola(); |
| | f1 = cc.Focus(); |
| | if (mmode == mm0Focus2) { |
| | throw Base::ValueError( |
| | "AttachEnginePoint::calculateAttachedPlacement: " |
| | "Parabola has no second focus" |
| | ); |
| | } |
| | } break; |
| | default: |
| | throw Base::ValueError( |
| | "AttachEnginePoint::calculateAttachedPlacement: referenced edge is not " |
| | "a conic section with a directrix" |
| | ); |
| | } |
| | if (mmode == mm0Focus1) { |
| | BasePoint = f1; |
| | } |
| | else { |
| | BasePoint = f2; |
| | } |
| | } break; |
| | case mm0ProximityPoint1: |
| | case mm0ProximityPoint2: { |
| | if (shapes.size() < 2) { |
| | throw Base::ValueError( |
| | "AttachEnginePoint::calculateAttachedPlacement: Proximity mode requires " |
| | "two shapes; only one is supplied" |
| | ); |
| | } |
| | if (shapes[0]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEnginePoint::calculateAttachedPlacement()!" |
| | ); |
| | } |
| | if (shapes[1]->isNull()) { |
| | throw Base::ValueError( |
| | "Null shape in AttachEnginePoint::calculateAttachedPlacement()!" |
| | ); |
| | } |
| |
|
| | BasePoint = getProximityPoint(mmode, shapes[0]->getShape(), shapes[1]->getShape()); |
| | } break; |
| | case mm0CenterOfMass: { |
| | GProp_GProps gpr = AttachEngine::getInertialPropsOfShape(shapes); |
| | BasePoint = gpr.CentreOfMass(); |
| | } break; |
| | default: |
| | throwWrongMode(mmode); |
| | } |
| |
|
| | plm = this->placementFactory(gp_Vec(0.0, 0.0, 1.0), gp_Vec(1.0, 0.0, 0.0), BasePoint, gp_Pnt()); |
| | } |
| | else { |
| | AttachEngine3D attacher3D; |
| | attacher3D.setUp(*this); |
| | attacher3D.mapMode = mmode; |
| | attacher3D.attachmentOffset |
| | = Base::Placement(); |
| | |
| | plm = attacher3D._calculateAttachedPlacement(objs, subs, origPlacement); |
| | } |
| | plm *= this->attachmentOffset; |
| | return plm; |
| | } |
| |
|
| | gp_Pnt AttachEnginePoint::getProximityPoint( |
| | eMapMode mmode, |
| | const TopoDS_Shape& s1, |
| | const TopoDS_Shape& s2 |
| | ) const |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | try { |
| | TopoDS_Shape face, edge; |
| | if (s1.ShapeType() == TopAbs_FACE && s2.ShapeType() == TopAbs_EDGE) { |
| | face = s1; |
| | edge = s2; |
| | } |
| | else if (s1.ShapeType() == TopAbs_EDGE && s2.ShapeType() == TopAbs_FACE) { |
| | edge = s1; |
| | face = s2; |
| | } |
| |
|
| | |
| | if (!edge.IsNull() && !face.IsNull()) { |
| |
|
| | BRepAdaptor_Curve crv(TopoDS::Edge(edge)); |
| |
|
| | GeomAdaptor_Curve typedcrv; |
| | try { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | typedcrv.Load(GeomAdaptor::MakeCurve(crv)); |
| | } |
| | catch (const Standard_DomainError&) { |
| | Handle(Geom_Curve) curve = crv.Curve().Curve(); |
| | if (curve.IsNull()) { |
| | |
| | typedcrv = crv.Curve(); |
| | } |
| | else { |
| | curve = Handle(Geom_Curve)::DownCast(curve->Copy()); |
| | curve->Transform(crv.Trsf()); |
| | typedcrv.Load(curve); |
| | } |
| | } |
| |
|
| | BRepIntCurveSurface_Inter intCS; |
| | intCS.Init(face, typedcrv, Precision::Confusion()); |
| | std::vector<gp_Pnt> points; |
| | for (; intCS.More(); intCS.Next()) { |
| | gp_Pnt pnt = intCS.Pnt(); |
| | points.push_back(pnt); |
| | } |
| |
|
| | if (points.size() > 1) { |
| | Base::Console().warning( |
| | "AttachEnginePoint::calculateAttachedPlacement: proximity calculation gave %d " |
| | "solutions, ambiguous.\n", |
| | int(points.size()) |
| | ); |
| | } |
| |
|
| | |
| | |
| | if (!points.empty()) { |
| | return points.front(); |
| | } |
| | } |
| | } |
| | catch (const Standard_Failure&) { |
| | |
| | } |
| |
|
| | BRepExtrema_DistShapeShape distancer(s1, s2); |
| | if (!distancer.IsDone()) { |
| | throw Base::ValueError( |
| | "AttachEnginePoint::calculateAttachedPlacement: proximity calculation failed." |
| | ); |
| | } |
| | if (distancer.NbSolution() > 1) { |
| | Base::Console().warning( |
| | "AttachEnginePoint::calculateAttachedPlacement: proximity calculation gave %i " |
| | "solutions, ambiguous.\n", |
| | int(distancer.NbSolution()) |
| | ); |
| | } |
| |
|
| | gp_Pnt p1 = distancer.PointOnShape1(1); |
| | gp_Pnt p2 = distancer.PointOnShape2(1); |
| | if (mmode == mm0ProximityPoint1) { |
| | return p1; |
| | } |
| | else { |
| | return p2; |
| | } |
| | } |
| |
|