| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| |
|
| | #include <boost_regex.hpp> |
| |
|
| | #include <BRep_Builder.hxx> |
| | #include <BRepTools.hxx> |
| | #include <TopoDS.hxx> |
| | #include <TopoDS_Iterator.hxx> |
| | #include <BRepBuilderAPI_Copy.hxx> |
| | #include <TopLoc_Location.hxx> |
| |
|
| | #include <App/Document.h> |
| | #include <App/DocumentObjectGroup.h> |
| | #include <App/Link.h> |
| | #include <App/GeoFeature.h> |
| | #include <App/GeoFeatureGroupExtension.h> |
| | #include <App/Part.h> |
| | #include <Base/Tools.h> |
| |
|
| | #include <Mod/Part/App/PartFeature.h> |
| | #include <Mod/Part/App/AttachExtension.h> |
| | #include <Mod/Part/App/Attacher.h> |
| |
|
| | #include "ShapeFinder.h" |
| |
|
| |
|
| | using namespace Measure; |
| |
|
| | |
| | |
| |
|
| | ResolveResult::ResolveResult( |
| | const App::DocumentObject* realTarget, |
| | const std::string& shortSubName, |
| | const App::DocumentObject* targetParent |
| | ) |
| | : m_target(App::SubObjectT(realTarget, shortSubName.c_str())) |
| | , m_targetParent(App::DocumentObjectT(targetParent)) |
| | {} |
| |
|
| | App::DocumentObject& ResolveResult::getTarget() const |
| | { |
| | return *(m_target.getObject()); |
| | } |
| |
|
| | std::string ResolveResult::getShortSub() const |
| | { |
| | return m_target.getSubName(); |
| | } |
| |
|
| | App::DocumentObject& ResolveResult::getTargetParent() const |
| | { |
| | return *(m_targetParent.getObject()); |
| | } |
| |
|
| |
|
| | |
| | |
| | ResolveResult ShapeFinder::resolveSelection( |
| | const App::DocumentObject& selectObj, |
| | const std::string& selectLongSub |
| | ) |
| | { |
| | App::DocumentObject* targetParent {nullptr}; |
| | std::string childName {}; |
| | const char* subElement {nullptr}; |
| | App::DocumentObject* realTarget |
| | = selectObj.resolve(selectLongSub.c_str(), &targetParent, &childName, &subElement); |
| | auto shortSub = getLastTerm(selectLongSub); |
| | return {realTarget, shortSub, targetParent}; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | TopoDS_Shape ShapeFinder::getLocatedShape(const App::DocumentObject& rootObject, const std::string& leafSub) |
| | { |
| | auto resolved = resolveSelection(rootObject, leafSub); |
| | auto target = &resolved.getTarget(); |
| | auto shortSub = resolved.getShortSub(); |
| | if (!target) { |
| | return {}; |
| | } |
| |
|
| | TopoDS_Shape shape = Part::Feature::getShape( |
| | target, |
| | Part::ShapeOption::ResolveLink | Part::ShapeOption::Transform |
| | ); |
| | if (isShapeReallyNull(shape)) { |
| | return {}; |
| | } |
| |
|
| | auto cleanSub = removeTnpInfo(leafSub); |
| | auto transform = getGlobalTransform(rootObject, cleanSub); |
| |
|
| | shape = transformShape(shape, transform.first, transform.second); |
| | Part::TopoShape tShape {shape}; |
| | if (!shortSub.empty()) { |
| | return tShape.getSubTopoShape(shortSub.c_str()).getShape(); |
| | } |
| |
|
| | return tShape.getShape(); |
| | } |
| |
|
| |
|
| | |
| | Part::TopoShape ShapeFinder::getLocatedTopoShape( |
| | const App::DocumentObject& rootObject, |
| | const std::string& leafSub |
| | ) |
| | { |
| | return {getLocatedShape(rootObject, leafSub)}; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | void ShapeFinder::crawlPlacementChain( |
| | std::vector<Base::Placement>& plmStack, |
| | std::vector<Base::Matrix4D>& scaleStack, |
| | const App::DocumentObject& rootObject, |
| | const std::string& leafSub |
| | ) |
| | { |
| | auto currentSub = leafSub; |
| | std::string previousSub {}; |
| | while (!currentSub.empty() && currentSub != previousSub) { |
| | auto resolved = resolveSelection(rootObject, currentSub); |
| | auto target = &resolved.getTarget(); |
| | if (!target) { |
| | return; |
| | } |
| | auto currentPlacement = getPlacement(target); |
| | auto currentScale = getScale(target); |
| | if (!currentPlacement.isIdentity() || !currentScale.isUnity()) { |
| | plmStack.push_back(currentPlacement); |
| | scaleStack.push_back(currentScale); |
| | } |
| | previousSub = currentSub; |
| | currentSub = pruneLastTerm(currentSub); |
| | } |
| | } |
| |
|
| |
|
| | |
| | |
| | TopoDS_Shape ShapeFinder::transformShape( |
| | TopoDS_Shape& inShape, |
| | const Base::Placement& placement, |
| | const Base::Matrix4D& scaler |
| | ) |
| | { |
| | if (isShapeReallyNull(inShape)) { |
| | return {}; |
| | } |
| | |
| | |
| | Part::TopoShape tshape {inShape}; |
| | if (tshape.isInfinite()) { |
| | inShape = stripInfiniteShapes(inShape); |
| | } |
| |
|
| | |
| | |
| | |
| | BRepBuilderAPI_Copy copier(inShape); |
| | tshape = Part::TopoShape(copier.Shape()); |
| | if (tshape.isNull()) { |
| | return {}; |
| | } |
| |
|
| | tshape.transformShape(scaler, true, true); |
| | tshape.setPlacement(placement); |
| |
|
| | return tshape.getShape(); |
| | } |
| |
|
| |
|
| | |
| | Base::Placement ShapeFinder::getPlacement(const App::DocumentObject* root) |
| | { |
| | auto namedProperty = root->getPropertyByName("Placement"); |
| | auto placementProperty = dynamic_cast<App::PropertyPlacement*>(namedProperty); |
| | if (namedProperty && placementProperty) { |
| | return placementProperty->getValue(); |
| | } |
| | return {}; |
| | } |
| |
|
| |
|
| | |
| | |
| | Base::Matrix4D ShapeFinder::getScale(const App::DocumentObject* root) |
| | { |
| | if (!isLinkLike(root)) { |
| | return {}; |
| | } |
| |
|
| | Base::Matrix4D linkScale; |
| | auto namedProperty = root->getPropertyByName("ScaleVector"); |
| | auto scaleVectorProperty = dynamic_cast<App::PropertyVector*>(namedProperty); |
| | if (scaleVectorProperty) { |
| | linkScale.scale(scaleVectorProperty->getValue()); |
| | } |
| | return linkScale; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | bool ShapeFinder::isLinkLike(const App::DocumentObject* obj) |
| | { |
| | if (!obj) { |
| | return false; |
| | } |
| |
|
| | if (obj->isDerivedFrom<App::Link>() || obj->isDerivedFrom<App::LinkElement>() |
| | || obj->isDerivedFrom<App::LinkGroup>()) { |
| | return true; |
| | } |
| |
|
| | auto namedProperty = obj->getPropertyByName("LinkedObject"); |
| | auto linkedObjectProperty = dynamic_cast<App::PropertyLink*>(namedProperty); |
| | if (linkedObjectProperty) { |
| | return true; |
| | } |
| |
|
| | namedProperty = obj->getPropertyByName("ElementList"); |
| | auto elementListProperty = dynamic_cast<App::PropertyLinkList*>(namedProperty); |
| | return elementListProperty != nullptr; |
| | } |
| |
|
| |
|
| | |
| | |
| | TopoDS_Shape ShapeFinder::stripInfiniteShapes(const TopoDS_Shape& inShape) |
| | { |
| | BRep_Builder builder; |
| | TopoDS_Compound comp; |
| | builder.MakeCompound(comp); |
| |
|
| | TopoDS_Iterator it(inShape); |
| | for (; it.More(); it.Next()) { |
| | TopoDS_Shape shape = it.Value(); |
| | if (shape.ShapeType() < TopAbs_SOLID) { |
| | |
| | shape = stripInfiniteShapes(shape); |
| | } |
| | else if (Part::TopoShape(shape).isInfinite()) { |
| | continue; |
| | } |
| | |
| | builder.Add(comp, shape); |
| | } |
| |
|
| | return {std::move(comp)}; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | bool ShapeFinder::isShapeReallyNull(const TopoDS_Shape& shape) |
| | { |
| | |
| | return shape.IsNull() || !TopoDS_Iterator(shape).More(); |
| | } |
| |
|
| |
|
| | |
| | |
| | std::pair<Base::Placement, Base::Matrix4D> ShapeFinder::getGlobalTransform( |
| | const App::DocumentObject& rootObject, |
| | const std::string& leafSub |
| | ) |
| | { |
| | |
| | std::string newSub = removeGeometryTerm(leafSub); |
| |
|
| | std::vector<Base::Placement> plmStack; |
| | std::vector<Base::Matrix4D> scaleStack; |
| | |
| | |
| | crawlPlacementChain(plmStack, scaleStack, rootObject, newSub); |
| |
|
| | auto pathTransform = sumTransforms(plmStack, scaleStack); |
| |
|
| | |
| | |
| | auto rootTransform = getGlobalTransform(&rootObject); |
| |
|
| | auto netPlm = rootTransform.first * pathTransform.first; |
| | auto netScale = rootTransform.second * pathTransform.second; |
| |
|
| | return {netPlm, netScale}; |
| | } |
| |
|
| |
|
| | |
| | |
| | std::pair<Base::Placement, Base::Matrix4D> ShapeFinder::getGlobalTransform( |
| | const App::DocumentObject* cursorObject |
| | ) |
| | { |
| | if (!cursorObject) { |
| | return {}; |
| | } |
| |
|
| | Base::Placement netPlm; |
| | Base::Matrix4D netScale = getScale(cursorObject); |
| |
|
| | Base::Placement geoPlm; |
| | auto geoCursor = dynamic_cast<const App::GeoFeature*>(cursorObject); |
| | if (!isLinkLike(cursorObject) && geoCursor) { |
| | netPlm = geoCursor->globalPlacement(); |
| | return {netPlm, netScale}; |
| | } |
| |
|
| | netPlm = getPlacement(cursorObject); |
| |
|
| | return {netPlm, netScale}; |
| | } |
| |
|
| |
|
| | |
| | |
| | std::pair<Base::Placement, Base::Matrix4D> ShapeFinder::sumTransforms( |
| | const std::vector<Base::Placement>& plmStack, |
| | const std::vector<Base::Matrix4D>& scaleStack |
| | ) |
| | { |
| | Base::Placement netPlm; |
| | Base::Matrix4D netScale; |
| |
|
| | auto itRevPlm = plmStack.rbegin(); |
| | for (; itRevPlm != plmStack.rend(); itRevPlm++) { |
| | netPlm *= *itRevPlm; |
| | } |
| | auto itRevScale = scaleStack.rbegin(); |
| | for (; itRevScale != scaleStack.rend(); itRevScale++) { |
| | netScale *= *itRevScale; |
| | } |
| |
|
| | return {netPlm, netScale}; |
| | } |
| |
|
| |
|
| | |
| | |
| | App::DocumentObject* ShapeFinder::getLinkAttachParent(const App::DocumentObject* attachedObject) |
| | { |
| | auto namedProperty = attachedObject->getPropertyByName("a1AttParent"); |
| | auto attachProperty = dynamic_cast<App::PropertyLink*>(namedProperty); |
| | if (namedProperty && attachProperty) { |
| | return attachProperty->getValue(); |
| | } |
| | return {}; |
| | } |
| |
|
| |
|
| | |
| | |
| | std::string ShapeFinder::PlacementAsString(const Base::Placement& inPlacement) |
| | { |
| | auto position = inPlacement.getPosition(); |
| | auto rotation = inPlacement.getRotation(); |
| | Base::Vector3d axis; |
| | double angle {0.0}; |
| | rotation.getValue(axis, angle); |
| | std::stringstream ss; |
| | ss << "pos: (" << position.x << ", " << position.y << ", " << position.z << ") axis: (" |
| | << axis.x << ", " << axis.y << ", " << axis.z << ") angle: " << Base::toDegrees(angle); |
| | return ss.str(); |
| | } |
| |
|
| |
|
| | |
| | std::string ShapeFinder::LocationAsString(const TopLoc_Location& location) |
| | { |
| | auto position = Base::Vector3d { |
| | location.Transformation().TranslationPart().X(), |
| | location.Transformation().TranslationPart().Y(), |
| | location.Transformation().TranslationPart().Z() |
| | }; |
| | gp_XYZ axisDir; |
| | double angle {0}; |
| | auto isRotation = location.Transformation().GetRotation(axisDir, angle); |
| | Base::Vector3d axis {axisDir.X(), axisDir.Y(), axisDir.Z()}; |
| |
|
| | std::stringstream ss; |
| | ss << "isRotation: " << isRotation << " pos: (" << position.x << ", " << position.y << ", " |
| | << position.z << ") axis: (" << axisDir.X() << ", " << axisDir.Y() << ", " << axisDir.Z() |
| | << ") angle: " << Base::toDegrees(angle); |
| | return ss.str(); |
| | } |
| |
|