FreeCAD/src/Mod/Part/App/Attacher.h
DeepSOIC 71f70eb855 AttachEngine: fix crash when referenced objects get deleted
... by verifying if the pointers equal to objects contained in all open
documents. Not terribly good, but I can't think of a situation where
doing this search might cause trouble.
2016-05-14 02:14:51 +03:00

465 lines
16 KiB
C++

/***************************************************************************
* Copyright (c) Victor Titov (DeepSOIC) *
* (vv.titov@gmail.com) 2015 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
/**
*Attacher.h, Attacher.cpp contain the functionality of deriving placement
*from a set of geometric subelements. Examples are: sketch attachment, datum
*plane placement.
*/
#ifndef PARTATTACHER_H
#define PARTATTACHER_H
#include <App/PropertyStandard.h>
#include <App/PropertyLinks.h>
#include <App/GeoFeature.h>
#include <Base/Vector3D.h>
#include <Base/Placement.h>
#include <Base/Exception.h>
#include "PartFeature.h"
#include <gp_Vec.hxx>
#include <GProp_GProps.hxx>
namespace Attacher
{
class AttachEngine;
//Attention! The numbers assiciated to the modes are permanent, because they are what get written into files.
enum eMapMode {
mmDeactivated,
mmTranslate,
mmObjectXY,
mmObjectXZ,
mmObjectYZ,
mmFlatFace,
mmTangentPlane,
mmNormalToPath,
mmFrenetNB,
mmFrenetTN,
mmFrenetTB,
mmConcentric,
mmRevolutionSection,
mmThreePointsPlane,
mmThreePointsNormal,
mmFolding,
mm1AxisX,
mm1AxisY,
mm1AxisZ,
mm1AxisCurv,
mm1Directrix1,
mm1Directrix2,
mm1Asymptote1,
mm1Asymptote2,
mm1Tangent,
mm1Normal,
mm1Binormal,
mm1TangentU,
mm1TangentV,
mm1TwoPoints,
mm1Intersection,
mm1Proximity,
mm0Origin,
mm0Focus1,
mm0Focus2,
mm0OnEdge,
mm0CenterOfCurvature,
mm0CenterOfMass,
mm0Intersection,
mm0Vertex,
mm0ProximityPoint1,
mm0ProximityPoint2,
mm1AxisInertia1,
mm1AxisInertia2,
mm1AxisInertia3,
mmInertialCS,
mmDummy_NumberOfModes//a value useful to check the validity of mode value
};//see also eMapModeStrings[] definition in .cpp
/**
* @brief The eRefType enum lists the types of references. If adding one, see
* also AttachEngine::eRefTypeStrings, AttachEngine::getShapeType(),
* AttachEngine::downgradeType(), AttacherTexts.cpp/getShTypeText()
*/
enum eRefType {
//topo //ranks: (number of times the type is downgradable)
rtAnything, //0
rtVertex, //1
rtEdge, //1
rtFace, //1
//edges:
rtLine, //2
rtCurve, //2
rtCircle, //3
rtConic, //3
rtEllipse, //4
rtParabola, //4
rtHyperbola, //4
//faces:
rtFlatFace, //2
rtSphericalFace, //2//flatface, shericalface are also surfaces of revolution, but the axis isn't defined.
rtSurfaceRev, //2
rtCylindricalFace, //3
rtToroidalFace, //3
rtConicalFace, //3
//shapes:
rtPart, //1
rtSolid, //2
rtWire, //2
rtDummy_numberOfShapeTypes,//a value useful to check the validity of value
rtFlagHasPlacement = 0x0100 //indicates that the linked shape is a whole FreeCAD object that has placement available.
};
typedef std::vector<eRefType> refTypeString; //a sequence of ref types, according to Support contents for example
typedef std::vector<refTypeString> refTypeStringList; //a set of type strings, defines which selection sets are supported by a certain mode
/**
* @brief The SuggestResult struct is a container for output information of AttachEngine mode suggesting routine.
*/
struct SuggestResult{
/**
* @brief message contains overall verdict of suggestor on current reference set
*/
enum eSuggestResult{
srOK, //references are valid for at least one mode
srLinkBroken, //failed to resolve out some of current references. Exception info is stored in SuggestResult::error.
srUnexpectedError,
srNoModesFit,//none of the avaliable mapping modes accepts the set of topological type
srIncompatibleGeometry,//there is a mode that could fit, but geometry is wrong (e.g. a line is required, but a curve was passed).
};
eSuggestResult message;
/**
* @brief allApplicableModes. Vector array that will recieve the list of
* all modes that are applicable to current set of references. It doesn't
* guarantee that all modes will work, it only checks that subelemnts are
* of right type.
*/
std::vector<eMapMode> allApplicableModes;
/**
* @brief bestFitMode is the mode that is the most specific to current
* references. Note that the mode may not be valid for current references;
* check if it's listed in allApplicableModes, or test if message == srOK.
*/
eMapMode bestFitMode;
/**
* @brief nextRefTypeHint: a hint of what can be added to references to
* achieve other modes.
*/
std::set<eRefType> nextRefTypeHint;
/**
* @brief reachableModes. List of modes that can be reached by selecing
* more references. Is a map, where key is the mode that can be reached,
* and value is a list of reference sequences that can be added to reach
* the mode (stuff already linked is omitted from these lists; only extra
* links needed are listed)
*/
std::map<eMapMode, refTypeStringList> reachableModes;
/**
* @brief references_Types: list of types of references, as queried when
* running suggesting routine.
*/
refTypeString references_Types;
Base::Exception error;
};
/**
* @brief The AttachEngine class is the placement calculation routine, modes,
* hints and so on. It can be used separately, without deriving from
* AttachableObject.
*/
class PartExport AttachEngine : public Base::BaseClass
{
TYPESYSTEM_HEADER();
public: //methods
AttachEngine();
virtual void setUp(const App::PropertyLinkSubList &references,
eMapMode mapMode = mmDeactivated,
bool mapReverse = false,
double attachParameter = 0.0,
double surfU = 0.0, double surfV = 0.0,
const Base::Placement &superPlacement = Base::Placement());
virtual void setUp(const AttachEngine &another);
virtual AttachEngine* copy() const = 0;
virtual Base::Placement calculateAttachedPlacement(Base::Placement origPlacement) const = 0;
/**
* @brief placementFactory calculates placement from Z axis direction,
* optional X axis direction, and origin point.
*
* @param ZAxis (input) mandatory. Z axis of the returned placement will
* strictly coincide with ZAxis.
*
* @param XAxis (input) optional (i.e., can be zero). Sets the preferred X
* axis orientation. If it is not perpendicular to ZAxis, it will be forced
* to be. If XAxis is zero, the effect is equivalent to setting
* makeYVertical to true.
*
* @param Origin (input) mandatory.
*
* @param refOrg (input). The point that will be used in case any of
* useRefOrg_XX parameters is true.
*
* @param useRefOrg_Line (input). If true, Origin will be moved along ZAxis
* to be as close as possible to refOrg.
*
* @param useRefOrg_Plane (input). If true, Origin will be moved in
* XAxis-YAxis plane to be as close as possible to refOrg.
*
* @param makeYVertical (input). If true, XAxis is ignored, and X and Y
* axes are defined in order to make Y axis go as upwards as possible. If
* ZAxis is strictly upwards, XY will match global XY. If ZAxis is strictly
* downwards, XAxis will be the reversed global X axis.
*
* @param makeLegacyFlatFaceOrientation (input). Modifies the behavior of
* makeYVertical to match the logic that was used in mapping of sketches to
* flat faces in FreeCAD prior to introduction of Attacher. Set
* makeYVertical to true if using this.
*
* @return the resulting placement. ReverseXY property of Attacher will be automatically applied.
*/
Base::Placement placementFactory(const gp_Dir &ZAxis,
gp_Vec XAxis,
gp_Pnt Origin,
gp_Pnt refOrg = gp_Pnt(),
bool useRefOrg_Line = false,
bool useRefOrg_Plane = false,
bool makeYVertical = false,
bool makeLegacyFlatFaceOrientation = false,
Base::Placement* placeOfRef = 0) const;
/**
* @brief suggestMapModes is the procedure that knows everything about
* mapping modes. It returns the most appropriate mapping mode, as well as
* list of all modes that will accept the set of references. In case no modes apply,
* extra information regarding reasons is returned in msg.
*
* @param result (output). Returns results of suggestion, such as best fit
* mode, list of all modes that apply, hints, etc.
*/
virtual void suggestMapModes(SuggestResult &result) const;
/**
* @brief EnableAllModes enables all modes that have shape type lists filled. The function acts on modeEnabled array.
*/
void EnableAllSupportedModes(void);
virtual ~AttachEngine(){};
public://helper functions that may be useful outside of the class
/**
* @brief getShapeType by shape. Will never set rtFlagHasPlacement.
* @param sh
* @return
*/
static eRefType getShapeType(const TopoDS_Shape &sh);
/**
* @brief getShapeType by link content. Will include rtFlagHasPlacement, if applies.
* @param obj
* @param subshape (input). Can be empty string (then, whole object will be used for shape type testing)
* @return
*/
static eRefType getShapeType(const App::DocumentObject* obj,
const std::string &subshape);
/**
* @brief downgradeType converts a more-specific type into a less-specific
* type (e.g. rtCircle->rtCurve, rtCurve->rtEdge, rtEdge->rtAnything)
* @param type
* @return the downgraded type.
*/
static eRefType downgradeType(eRefType type);
/**
* @brief getTypeRank determines, how specific is the supplied shape type.
* The ranks are outlined in definition of eRefType. The ranks are defined
* by implementation of downgradeType().
* @param type
* @return number of times the type can be downgradeType() before it
* becomes rtAnything
*/
static int getTypeRank(eRefType type);
/**
* @brief isShapeOfType tests if a shape fulfills the requirement of a mode, and returns a score of how spot on was the requirement.
* @param shapeType (use return value of AttachEngine::getShapeType)
* @param requirement
* @return : -1 - doesn't fulfill,
* 0 - compatible topology, but incompatible specific (e.g. rtLine, rtCircle);
* 1 - valid by generic type (e.g. rtCircle is rtEdge),
* 2 and up - more and more specific match (according to rank of requirement)
*/
static int isShapeOfType(eRefType shapeType, eRefType requirement);
/**
* @brief getModeName
* @param mmode
* @return returns a string that identifies the attachment mode in enum property.
*/
static std::string getModeName(eMapMode mmode);
static eMapMode getModeByName(const std::string &modeName);
static std::string getRefTypeName(eRefType shapeType);
static eRefType getRefTypeByName(const std::string &typeName);
static GProp_GProps getInertialPropsOfShape(const std::vector<const TopoDS_Shape*> &shapes);
/**
* @brief verifyReferencesAreSafe: checks if pointers in references still
* point to objects contained in open documents. This guarantees the links
* are valid. Throws Base::Exception if invalid links are found.
*/
static void verifyReferencesAreSafe(const App::PropertyLinkSubList& references);
public: //enums
static const char* eMapModeStrings[];
static const char* eRefTypeStrings[];
public: //members
App::PropertyLinkSubList references;
eMapMode mapMode;
bool mapReverse;
double attachParameter;
double surfU, surfV;
Base::Placement superPlacement;
/**
* @brief modeEnabled is an indicator, whether some mode is ever suggested
* or not. Set to false to suppress suggesting some mode, like so:
* modeEnabled[mmModeIDontLike] = false;
*/
std::vector<bool> modeEnabled;
std::vector<refTypeStringList> modeRefTypes; //a complete data structure, containing info on which modes support what selection
protected:
refTypeString cat(eRefType rt1){
refTypeString ret;
ret.push_back(rt1);
return ret;
}
refTypeString cat(eRefType rt1, eRefType rt2){
refTypeString ret;
ret.push_back(rt1);
ret.push_back(rt2);
return ret;
}
refTypeString cat(eRefType rt1, eRefType rt2, eRefType rt3){
refTypeString ret;
ret.push_back(rt1);
ret.push_back(rt2);
ret.push_back(rt3);
return ret;
}
refTypeString cat(eRefType rt1, eRefType rt2, eRefType rt3, eRefType rt4){
refTypeString ret;
ret.push_back(rt1);
ret.push_back(rt2);
ret.push_back(rt3);
ret.push_back(rt4);
return ret;
}
static void readLinks(const App::PropertyLinkSubList &references, std::vector<App::GeoFeature *> &geofs,
std::vector<const TopoDS_Shape*>& shapes, std::vector<TopoDS_Shape> &storage,
std::vector<eRefType> &types);
static void throwWrongMode(eMapMode mmode);
};
class PartExport AttachEngine3D : public AttachEngine
{
TYPESYSTEM_HEADER();
public:
AttachEngine3D();
virtual AttachEngine3D* copy() const;
virtual Base::Placement calculateAttachedPlacement(Base::Placement origPlacement) const;
private:
double calculateFoldAngle(gp_Vec axA, gp_Vec axB, gp_Vec edA, gp_Vec edB) const;
};
//attacher specialized for datum planes
class PartExport AttachEnginePlane : public AttachEngine
{
TYPESYSTEM_HEADER();
public:
AttachEnginePlane();
virtual AttachEnginePlane* copy() const;
virtual Base::Placement calculateAttachedPlacement(Base::Placement origPlacement) const;
};
//attacher specialized for datum lines
class PartExport AttachEngineLine : public AttachEngine
{
TYPESYSTEM_HEADER();
public:
AttachEngineLine();
virtual AttachEngineLine* copy() const;
virtual Base::Placement calculateAttachedPlacement(Base::Placement origPlacement) const;
};
//attacher specialized for datum points
class PartExport AttachEnginePoint : public AttachEngine
{
TYPESYSTEM_HEADER();
public:
AttachEnginePoint();
virtual AttachEnginePoint* copy() const;
virtual Base::Placement calculateAttachedPlacement(Base::Placement origPlacement) const;
};
//====================================================================
class ExceptionCancel : public Base::Exception
{
public:
ExceptionCancel(){}
ExceptionCancel(char* msg){this->setMessage(msg);}
~ExceptionCancel(){}
};
} // namespace Attacher
#endif // PARTATTACHER_H