// SPDX-License-Identifier: LGPL-2.1-or-later /**************************************************************************** * * * Copyright (c) 2023 Ondsel * * * * This file is part of FreeCAD. * * * * FreeCAD is free software: you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 2.1 of the * * License, or (at your option) any later version. * * * * FreeCAD is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with FreeCAD. If not, see * * . * * * ***************************************************************************/ #ifndef ASSEMBLY_AssemblyObject_H #define ASSEMBLY_AssemblyObject_H #include #include #include #include #include #include namespace MbD { class ASMTPart; class ASMTAssembly; class ASMTJoint; class ASMTMarker; class ASMTPart; } // namespace MbD namespace App { class PropertyXLinkSub; } // namespace App namespace Base { class Placement; class Rotation; } // namespace Base namespace Assembly { class AssemblyLink; class JointGroup; class ViewGroup; enum class JointType; struct ObjRef { App::DocumentObject* obj; App::PropertyXLinkSub* ref; }; class AssemblyExport AssemblyObject: public App::Part { PROPERTY_HEADER_WITH_OVERRIDE(Assembly::AssemblyObject); public: AssemblyObject(); ~AssemblyObject() override; PyObject* getPyObject() override; /// returns the type name of the ViewProvider const char* getViewProviderName() const override { return "AssemblyGui::ViewProviderAssembly"; } App::DocumentObjectExecReturn* execute() override; /* Solve the assembly. It will update first the joints, solve, update placements of the parts and redraw the joints Args : enableRedo : This store initial positions to enable undo while being in an active transaction (joint creation).*/ int solve(bool enableRedo = false, bool updateJCS = true); int generateSimulation(App::DocumentObject* sim); int updateForFrame(size_t index, bool updateJCS = true); size_t numberOfFrames(); void preDrag(std::vector dragParts); void doDragStep(); void postDrag(); void savePlacementsForUndo(); void undoSolve(); void clearUndo(); void exportAsASMT(std::string fileName); Base::Placement getMbdPlacement(std::shared_ptr mbdPart); bool validateNewPlacements(); void setNewPlacements(); static void recomputeJointPlacements(std::vector joints); static void redrawJointPlacements(std::vector joints); static void redrawJointPlacement(App::DocumentObject* joint); // This makes sure that LinkGroups or sub-assemblies have identity placements. void ensureIdentityPlacements(); // Ondsel Solver interface std::shared_ptr makeMbdAssembly(); void create_mbdSimulationParameters(App::DocumentObject* sim); std::shared_ptr makeMbdPart( std::string& name, Base::Placement plc = Base::Placement(), double mass = 1.0 ); std::shared_ptr getMbDPart(App::DocumentObject* obj); // To help the solver, during dragging, we are bundling parts connected by a fixed joint. // So several assembly components are bundled in a single ASMTPart. // So we need to store the plc of each bundled object relative to the bundle origin (first obj // of objectPartMap). struct MbDPartData { std::shared_ptr part; Base::Placement offsetPlc; // This is the offset within the bundled parts }; MbDPartData getMbDData(App::DocumentObject* part); std::shared_ptr makeMbdMarker(std::string& name, Base::Placement& plc); std::vector> makeMbdJoint(App::DocumentObject* joint); std::shared_ptr makeMbdJointOfType(App::DocumentObject* joint, JointType jointType); std::shared_ptr makeMbdJointDistance(App::DocumentObject* joint); std::string handleOneSideOfJoint( App::DocumentObject* joint, const char* propRefName, const char* propPlcName ); void getRackPinionMarkers( App::DocumentObject* joint, std::string& markerNameI, std::string& markerNameJ ); int slidingPartIndex(App::DocumentObject* joint); void jointParts(std::vector joints); JointGroup* getJointGroup() const; ViewGroup* getExplodedViewGroup() const; template T* getGroup(); std::vector getJoints( bool updateJCS = true, bool delBadJoints = false, bool subJoints = true ); std::vector getGroundedJoints(); std::vector getJointsOfObj(App::DocumentObject* obj); std::vector getJointsOfPart(App::DocumentObject* part); App::DocumentObject* getJointOfPartConnectingToGround( App::DocumentObject* part, std::string& name, const std::vector& excludeJoints = {} ); std::unordered_set getGroundedParts(); std::unordered_set fixGroundedParts(); void fixGroundedPart(App::DocumentObject* obj, Base::Placement& plc, std::string& jointName); bool isJointConnectingPartToGround(App::DocumentObject* joint, const char* partPropName); bool isJointTypeConnecting(App::DocumentObject* joint); bool isObjInSetOfObjRefs(App::DocumentObject* obj, const std::vector& pairs); void removeUnconnectedJoints( std::vector& joints, std::unordered_set groundedObjs ); void traverseAndMarkConnectedParts( App::DocumentObject* currentPart, std::vector& connectedParts, const std::vector& joints ); std::vector getConnectedParts( App::DocumentObject* part, const std::vector& joints ); bool isPartGrounded(App::DocumentObject* part); bool isPartConnected(App::DocumentObject* part); std::vector getDownstreamParts( App::DocumentObject* part, App::DocumentObject* joint = nullptr ); App::DocumentObject* getUpstreamMovingPart( App::DocumentObject* part, App::DocumentObject*& joint, std::string& name, std::vector excludeJoints = {} ); double getObjMass(App::DocumentObject* obj); void setObjMasses(std::vector> objectMasses); std::vector getSubAssemblies(); std::vector getMotionsFromSimulation(App::DocumentObject* sim); bool isMbDJointValid(App::DocumentObject* joint); bool isEmpty() const; int numberOfComponents() const; inline int getLastDoF() const { return lastDoF; } inline bool getLastHasConflicts() const { return lastHasConflict; } inline bool getLastHasRedundancies() const { return lastHasRedundancies; } inline bool getLastHasPartialRedundancies() const { return lastHasPartialRedundancies; } inline bool getLastHasMalformedConstraints() const { return lastHasMalformedConstraints; } inline int getLastSolverStatus() const { return lastSolverStatus; } inline const std::vector& getLastConflicting() const { return lastConflicting; } inline const std::vector& getLastRedundant() const { return lastRedundant; } inline const std::vector& getLastPartiallyRedundant() const { return lastPartiallyRedundant; } inline const std::vector& getLastMalformedConstraints() const { return lastMalformedConstraints; } fastsignals::signal signalSolverUpdate; private: std::shared_ptr mbdAssembly; std::unordered_map objectPartMap; std::vector> objMasses; std::vector draggedParts; std::vector motions; std::vector> previousPositions; bool bundleFixed; int lastDoF; bool lastHasConflict; bool lastHasRedundancies; bool lastHasPartialRedundancies; bool lastHasMalformedConstraints; int lastSolverStatus; std::vector lastConflicting; std::vector lastRedundant; std::vector lastPartiallyRedundant; std::vector lastMalformedConstraints; }; } // namespace Assembly #endif // ASSEMBLY_AssemblyObject_H