boost::shared_ptr<Model_Document> aNew(new Model_Document(theDocID));
myDocs[theDocID] = aNew;
+ // load it if it must be loaded by demand
+ if (myLoadedByDemand.find(theDocID) != myLoadedByDemand.end() && !myPath.empty()) {
+ aNew->load(myPath.c_str());
+ myLoadedByDemand.erase(theDocID); // done, don't do it anymore
+ }
+
return myDocs[theDocID];
}
return myDocs.find(theDocID) != myDocs.end();
}
+//=======================================================================
+void Model_Application::setLoadPath(std::string thePath)
+{
+ myPath = thePath;
+}
+
+//=======================================================================
+void Model_Application::setLoadByDemand(std::string theID)
+{
+ myLoadedByDemand.insert(theID);
+}
+
//=======================================================================
Model_Application::Model_Application()
{
//! Deletes the document from the application
MODEL_EXPORT void deleteDocument(std::string theDocID);
+ //! Set path for the loaded by demand documents
+ void setLoadPath(std::string thePath);
+ //! Defines that specified document must be loaded by demand
+ void setLoadByDemand(std::string theID);
+
public:
// Redefined OCAF methods
//! Return name of resource (i.e. "Standard")
private:
/// Map from string identifiers to created documents of an application
std::map<std::string, boost::shared_ptr<Model_Document> > myDocs;
+ /// Path for the loaded by demand documents
+ std::string myPath;
+ /// Path for the loaded by demand documents
+ std::set<std::string> myLoadedByDemand;
};
#endif
if (!theLabel.FindAttribute(TDataStd_Comment::GetID(), myComment)) {
// create attribute: not initialized by value yet, just empty string
myComment = TDataStd_Comment::Set(theLabel, "");
+ } else { // document was already referenced: try to set it as loaded by demand
+ Handle(Model_Application) anApp = Model_Application::getApplication();
+ string anID(TCollection_AsciiString(myComment->Get()).ToCString());
+ if (!anApp->hasDocument(anID)) {
+ anApp->setLoadByDemand(anID);
+ }
}
}
myID->Set(aData->id(theAttr).c_str());
static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
- Model_FeatureUpdatedMessage aMsg(feature(), anEvent);
+ Model_FeatureUpdatedMessage aMsg(owner(), anEvent);
Events_Loop::loop()->send(aMsg);
}
#include <Model_PluginManager.h>
#include <Model_Events.h>
#include <Events_Loop.h>
+#include <Events_Error.h>
#include <TDataStd_Integer.hxx>
#include <TDataStd_Comment.hxx>
#include <climits>
+#ifdef WIN32
+# define _separator_ '\\'
+#else
+# define _separator_ '/'
+#endif
+
static const int UNDO_LIMIT = 10; // number of possible undo operations
static const int TAG_GENERAL = 1; // general properties tag
using namespace std;
+/// Returns the file name of this document by the nameof directory and identifuer of a document
+static TCollection_ExtendedString DocFileName(const char* theFileName, const string& theID)
+{
+ TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
+ aPath += _separator_;
+ aPath += theID.c_str();
+ aPath += ".cbf"; // standard binary file extension
+ return aPath;
+}
+
bool Model_Document::load(const char* theFileName)
{
- bool myIsError = Standard_False;
- /*
- TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
- PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
- try
- {
- Handle(TDocStd_Document) aDoc = this;
- aStatus = Model_Application::GetApplication()->Open(aPath, aDoc);
- }
- catch (Standard_Failure)
- {}
- myIsError = aStatus != PCDM_RS_OK;
- if (myIsError)
- {
- switch (aStatus)
- {
- case PCDM_RS_UnknownDocument: cout<<"OCAFApp_Appl_RUnknownDocument"<<endl; break;
- case PCDM_RS_AlreadyRetrieved: cout<<"OCAFApp_Appl_RAlreadyRetrieved"<<endl; break;
- case PCDM_RS_AlreadyRetrievedAndModified: cout<<"OCAFApp_Appl_RAlreadyRetrievedAndModified"<<endl; break;
- case PCDM_RS_NoDriver: cout<<"OCAFApp_Appl_RNoDriver"<<endl; break;
- case PCDM_RS_UnknownFileDriver: cout<<"OCAFApp_Appl_RNoDriver"<<endl; break;
- case PCDM_RS_OpenError: cout<<"OCAFApp_Appl_ROpenError"<<endl; break;
- case PCDM_RS_NoVersion: cout<<"OCAFApp_Appl_RNoVersion"<<endl; break;
- case PCDM_RS_NoModel: cout<<"OCAFApp_Appl_RNoModel"<<endl; break;
- case PCDM_RS_NoDocument: cout<<"OCAFApp_Appl_RNoDocument"<<endl; break;
- case PCDM_RS_FormatFailure: cout<<"OCAFApp_Appl_RFormatFailure"<<endl; break;
- case PCDM_RS_TypeNotFoundInSchema: cout<<"OCAFApp_Appl_RTypeNotFound"<<endl; break;
- case PCDM_RS_UnrecognizedFileFormat: cout<<"OCAFApp_Appl_RBadFileFormat"<<endl; break;
- case PCDM_RS_MakeFailure: cout<<"OCAFApp_Appl_RMakeFailure"<<endl; break;
- case PCDM_RS_PermissionDenied: cout<<"OCAFApp_Appl_RPermissionDenied"<<endl; break;
- case PCDM_RS_DriverFailure: cout<<"OCAFApp_Appl_RDriverFailure"<<endl; break;
- default: cout<<"OCAFApp_Appl_RUnknownFail"<<endl; break;
- }
- }
- SetUndoLimit(UNDO_LIMIT);
- */
- return !myIsError;
+ Handle(Model_Application) anApp = Model_Application::getApplication();
+ if (this == Model_PluginManager::get()->rootDocument().get()) {
+ anApp->setLoadPath(theFileName);
+ }
+ TCollection_ExtendedString aPath (DocFileName(theFileName, myID));
+ PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
+ try
+ {
+ aStatus = anApp->Open(aPath, myDoc);
+ }
+ catch (Standard_Failure)
+ {
+ Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+ Events_Error::send(string("Exception in opening of document: ") + aFail->GetMessageString());
+ return false;
+ }
+ bool isError = aStatus != PCDM_RS_OK;
+ if (isError)
+ {
+ switch (aStatus)
+ {
+ case PCDM_RS_UnknownDocument:
+ Events_Error::send(string("Can not open document: PCDM_RS_UnknownDocument")); break;
+ case PCDM_RS_AlreadyRetrieved:
+ Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrieved")); break;
+ case PCDM_RS_AlreadyRetrievedAndModified:
+ Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified")); break;
+ case PCDM_RS_NoDriver:
+ Events_Error::send(string("Can not open document: PCDM_RS_NoDriver")); break;
+ case PCDM_RS_UnknownFileDriver:
+ Events_Error::send(string("Can not open document: PCDM_RS_UnknownFileDriver")); break;
+ case PCDM_RS_OpenError:
+ Events_Error::send(string("Can not open document: PCDM_RS_OpenError")); break;
+ case PCDM_RS_NoVersion:
+ Events_Error::send(string("Can not open document: PCDM_RS_NoVersion")); break;
+ case PCDM_RS_NoModel:
+ Events_Error::send(string("Can not open document: PCDM_RS_NoModel")); break;
+ case PCDM_RS_NoDocument:
+ Events_Error::send(string("Can not open document: PCDM_RS_NoDocument")); break;
+ case PCDM_RS_FormatFailure:
+ Events_Error::send(string("Can not open document: PCDM_RS_FormatFailure")); break;
+ case PCDM_RS_TypeNotFoundInSchema:
+ Events_Error::send(string("Can not open document: PCDM_RS_TypeNotFoundInSchema")); break;
+ case PCDM_RS_UnrecognizedFileFormat:
+ Events_Error::send(string("Can not open document: PCDM_RS_UnrecognizedFileFormat")); break;
+ case PCDM_RS_MakeFailure:
+ Events_Error::send(string("Can not open document: PCDM_RS_MakeFailure")); break;
+ case PCDM_RS_PermissionDenied:
+ Events_Error::send(string("Can not open document: PCDM_RS_PermissionDenied")); break;
+ case PCDM_RS_DriverFailure:
+ Events_Error::send(string("Can not open document: PCDM_RS_DriverFailure")); break;
+ default:
+ Events_Error::send(string("Can not open document: unknown error")); break;
+ }
+ }
+ if (!isError) {
+ myDoc->SetUndoLimit(UNDO_LIMIT);
+ synchronizeFeatures();
+ }
+ return !isError;
}
bool Model_Document::save(const char* theFileName)
{
- bool myIsError = true;
- /*
- TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
- PCDM_StoreStatus aStatus;
- try {
- Handle(TDocStd_Document) aDoc = this;
- aStatus = Model_Application::GetApplication()->SaveAs (aDoc, aPath);
- }
- catch (Standard_Failure) {
- Handle(Standard_Failure) aFail = Standard_Failure::Caught();
- cout<<"OCAFApp_Engine:save Error: "<<aFail->GetMessageString()<<endl;
- return false;
- }
- myIsError = aStatus != PCDM_SS_OK;
- if (myIsError)
- {
- switch (aStatus)
- {
- case PCDM_SS_DriverFailure:
- cout<<"OCAFApp_Appl_SDriverFailure"<<endl;
- break;
- case PCDM_SS_WriteFailure:
- cout<<"OCAFApp_Appl_SWriteFailure"<<endl;
- break;
- case PCDM_SS_Failure:
- default:
- cout<<"OCAFApp_Appl_SUnknownFailure"<<endl;
- break;
- }
- }
- myTransactionsAfterSave = 0;
- Standard::Purge(); // Release free memory
- */
- return !myIsError;
+ // create a directory in the root document if it is not yet exist
+ if (this == Model_PluginManager::get()->rootDocument().get()) {
+#ifdef WIN32
+ CreateDirectory(theFileName, NULL);
+#else
+ mkdir(theFileName, 0x1ff);
+#endif
+ }
+ // filename in the dir is id of document inside of the given directory
+ TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
+ PCDM_StoreStatus aStatus;
+ try {
+ aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
+ }
+ catch (Standard_Failure) {
+ Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+ Events_Error::send(string("Exception in saving of document: ") + aFail->GetMessageString());
+ return false;
+ }
+ bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
+ if (!isDone)
+ {
+ switch (aStatus)
+ {
+ case PCDM_SS_DriverFailure:
+ Events_Error::send(string("Can not save document: PCDM_SS_DriverFailure"));
+ break;
+ case PCDM_SS_WriteFailure:
+ Events_Error::send(string("Can not save document: PCDM_SS_WriteFailure"));
+ break;
+ case PCDM_SS_Failure:
+ default:
+ Events_Error::send(string("Can not save document: PCDM_SS_Failure"));
+ break;
+ }
+ }
+ myTransactionsAfterSave = 0;
+ if (isDone) { // save also sub-documents if any
+ set<string>::iterator aSubIter = mySubs.begin();
+ for(; aSubIter != mySubs.end() && isDone; aSubIter++)
+ isDone = subDocument(*aSubIter)->save(theFileName);
+ }
+ return isDone;
}
void Model_Document::close()
void Model_Document::startOperation()
{
+ // check is it nested or not
+ if (myDoc->HasOpenCommand()) {
+ myIsNested = true;
+ }
// new command for this
myDoc->NewCommand();
// new command for all subs
// returns false if delta is empty and no transaction was made
myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand();
myTransactionsAfterSave++;
+ myIsNested = false;
// finish for all subs
set<string>::iterator aSubIter = mySubs.begin();
for(; aSubIter != mySubs.end(); aSubIter++)
{
myDoc->SetUndoLimit(UNDO_LIMIT);
myTransactionsAfterSave = 0;
+ myIsNested = false;
+ myDoc->SetNestedTransactionMode();
+ // to have something in the document and avoid empty doc open/save problem
+ TDataStd_Integer::Set(myDoc->Main().Father(), 0);
}
TDF_Label Model_Document::groupLabel(const string theGroup)
aFeature->setDoc(aThis);
aFeature->setData(aData);
aFeature->initAttributes();
- // event: model is updated
- static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED);
- Model_FeatureUpdatedMessage aMsg(aFeature, anEvent);
- Events_Loop::loop()->send(aMsg);
if (aFIter == aFeatures.end()) {
aFeatures.push_back(aFeature);
aFIter++;
aFeatures.insert(aFIter, aFeature);
}
+ // event: model is updated
+ static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED);
+ Model_FeatureUpdatedMessage aMsg(aFeature, anEvent);
+ Events_Loop::loop()->send(aMsg);
+
// feature for this label is added, so go to the next label
aFLabIter.Next();
} else { // nothing is changed, both iterators are incremented
std::set<std::string> mySubs; ///< set of identifiers of sub-documents of this document
/// transaction indexes (related to myTransactionsAfterSave) which were empty in this doc
std::map<int, bool> myIsEmptyTr;
+ /// true if the current operation is nested
+ bool myIsNested;
};
#endif
: myModule(theModule)
{
Events_Loop* aLoop = Events_Loop::loop();
- Events_ID aFeatureUpdatedId = aLoop->eventByName(EVENT_FEATURE_UPDATED);
- aLoop->registerListener(this, aFeatureUpdatedId);
+ aLoop->registerListener(this, aLoop->eventByName(EVENT_FEATURE_UPDATED));
+ aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+ aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
}
PartSet_Listener::~PartSet_Listener()
//******************************************************
void PartSet_Listener::processEvent(const Events_Message* theMessage)
{
- if (QString(theMessage->eventID().eventText()) == EVENT_FEATURE_UPDATED)
+ QString aType = QString(theMessage->eventID().eventText());
+ if (aType == EVENT_FEATURE_UPDATED ||
+ aType == EVENT_FEATURE_CREATED)
{
const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
- if (myModule->workshop()->displayer()->IsVisible(aFeature))
+ if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
+ aType == EVENT_FEATURE_CREATED)
myModule->visualizePreview(aFeature, true);
}
+ if (aType == EVENT_FEATURE_DELETED)
+ {
+ const Model_FeatureDeletedMessage* aDelMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
+ boost::shared_ptr<ModelAPI_Document> aDoc = aDelMsg->document();
+
+ std::string aGroup = aDelMsg->group();
+ if (aDelMsg->group().compare("Sketch") == 0) { // Update only Sketch group
+ myModule->updateCurrentPreview(aGroup);
+ }
+ }
}
aDisplayer->Erase(anOperation->feature());
}
}
+
+void PartSet_Module::updateCurrentPreview(const std::string& theCmdId)
+{
+ ModuleBase_Operation* anOperation = myWorkshop->operationMgr()->currentOperation();
+ if (!anOperation)
+ return;
+
+ PartSet_OperationSketchBase* aPreviewOp = dynamic_cast<PartSet_OperationSketchBase*>(anOperation);
+ if (!aPreviewOp)
+ return;
+
+ boost::shared_ptr<ModelAPI_Feature> aFeature = aPreviewOp->feature();
+ if (!aFeature || aFeature->getKind() != theCmdId)
+ return;
+
+ std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+ aList = aPreviewOp->preview();
+ XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+ std::list<int> aModes = aPreviewOp->getSelectionModes(aPreviewOp->feature());
+
+ std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >::const_iterator
+ anIt = aList.begin(), aLast = aList.end();
+ aDisplayer->EraseAll(false);
+ for (; anIt != aLast; anIt++) {
+ boost::shared_ptr<ModelAPI_Feature> aFeature = (*anIt).first;
+ boost::shared_ptr<GeomAPI_Shape> aPreview = (*anIt).second;
+ aDisplayer->RedisplayInLocalContext(aFeature,
+ aPreview ? aPreview->impl<TopoDS_Shape>() : TopoDS_Shape(),
+ aModes, false);
+ }
+ aDisplayer->UpdateViewer();
+}
+
/// \param isDisplay the state whether the presentation should be displayed or erased
void visualizePreview(boost::shared_ptr<ModelAPI_Feature> theFeature, bool isDisplay);
+ /// Updates current operation preview, if it has it.
+ /// \param theCmdId the operation name
+ void updateCurrentPreview(const std::string& theCmdId);
+
public slots:
void onFeatureTriggered();
/// SLOT, that is called after the operation is stopped. Switched off the modfications performed
#include <ModelAPI_Data.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
+
#include <GeomAlgoAPI_FaceBuilder.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Dir.h>
emit launchOperation(PartSet_OperationEditLine::Type(), aFeature);
}
+std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+ PartSet_OperationSketch::preview() const
+{
+ std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> > aPreviewMap;
+
+ boost::shared_ptr<SketchPlugin_Feature> aFeature;
+
+ boost::shared_ptr<ModelAPI_Data> aData = feature()->data();
+ boost::shared_ptr<ModelAPI_AttributeRefList> aRefList =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aData->attribute(SKETCH_ATTR_FEATURES));
+
+ std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aRefList->list();
+ std::list<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
+ aLast = aFeatures.end();
+ for (; anIt != aLast; anIt++) {
+ aFeature = boost::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
+ boost::shared_ptr<GeomAPI_Shape> aPreview = aFeature->preview();
+ if (aPreview)
+ aPreviewMap[aFeature] = aPreview;
+ }
+ return aPreviewMap;
+}
+
void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape)
{
if (theShape.IsNull())
virtual void mouseMoved(QMouseEvent* theEvent, Handle_V3d_View theView,
const std::list<XGUI_ViewerPrs>& theSelected);
+ /// Returns the map of the operation previews including the nested feature previews
+ /// \return the map of feature to the feature preview
+ virtual std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+ preview() const;
signals:
/// signal about the sketch plane is selected
/// \param theX the value in the X direction of the plane
return aFeature->preview();
}
+std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+ PartSet_OperationSketchBase::preview() const
+{
+ return std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >();
+}
+
boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature()
{
boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature();
#include <ModuleBase_Operation.h>
#include <QObject>
+#include <map>
+
class Handle_V3d_View;
class QMouseEvent;
class GeomAPI_Shape;
/// \param theFeature the feature object to obtain the preview
boost::shared_ptr<GeomAPI_Shape> preview(boost::shared_ptr<ModelAPI_Feature> theFeature) const;
+ /// Returns the map of the operation previews including the nested feature previews
+ /// \return the map of feature to the feature preview
+ virtual std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> > preview() const;
+
/// Returns the operation local selection mode
/// \param theFeature the feature object to get the selection mode
/// \return the selection mode
PARTSETPLUGIN_EXPORT virtual boost::shared_ptr<ModelAPI_Document> documentToAdd();
+ /// Returns true if this feature must be displayed in the history (top level of Part tree)
+ PARTSETPLUGIN_EXPORT virtual bool isInHistory() {return false;}
+
/// Use plugin manager for features creation
PartSetPlugin_Part();
/// Fourth entity for the constraint
const std::string CONSTRAINT_ATTR_ENTITY_D("ConstraintEntityD");
/// List of constraint attributes
-const std::string CONSTRAINT_ATTRIBUTES[4] =
+const unsigned int CONSTRAINT_ATTR_SIZE = 4;
+const std::string CONSTRAINT_ATTRIBUTES[CONSTRAINT_ATTR_SIZE] =
{CONSTRAINT_ATTR_ENTITY_A, CONSTRAINT_ATTR_ENTITY_B,
CONSTRAINT_ATTR_ENTITY_C, CONSTRAINT_ATTR_ENTITY_D};
SketchPlugin_Line::SketchPlugin_Line()
{
+ setSketch(0);
}
void SketchPlugin_Line::initAttributes()
const boost::shared_ptr<GeomAPI_Shape>& SketchPlugin_Line::preview()
{
SketchPlugin_Sketch* aSketch = sketch();
- // compute a start point in 3D view
- boost::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
- boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_START));
- boost::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
- // compute an end point in 3D view
- boost::shared_ptr<GeomDataAPI_Point2D> anEndAttr =
- boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_END));
- boost::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
- // make linear edge
- boost::shared_ptr<GeomAPI_Shape> anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd);
- setPreview(anEdge);
-
+ if (aSketch) {
+ // compute a start point in 3D view
+ boost::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_START));
+ boost::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
+ // compute an end point in 3D view
+ boost::shared_ptr<GeomDataAPI_Point2D> anEndAttr =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_END));
+ boost::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
+ // make linear edge
+ boost::shared_ptr<GeomAPI_Shape> anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd);
+ setPreview(anEdge);
+ }
return getPreview();
}
SET(PROJECT_LIBRARIES
${SLVS_LIBRARIES}
SketchPlugin
+ Events
)
INCLUDE_DIRECTORIES(
- ../SketchPlugin
- ../ModelAPI
- ../GeomAPI
+ ${PROJECT_SOURCE_DIR}/src/SketchPlugin
+ ${PROJECT_SOURCE_DIR}/src/ModelAPI
+ ${PROJECT_SOURCE_DIR}/src/Model
+ ${PROJECT_SOURCE_DIR}/src/GeomAPI
+ ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
+ ${PROJECT_SOURCE_DIR}/src/Events
)
ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS ${BOOST_DEFINITIONS})
#include "SketchSolver_ConstraintManager.h"
+#include <Events_Loop.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_Data.h>
+#include <Model_Events.h>
#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Sketch.h>
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
+
+/// Global constaint manager object
+SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
/// This value is used to give unique index to the groups
static Slvs_hGroup myGroupIndexer = 0;
+/** \brief Makes transformation from ModelAPI_Attribute to the list of parameters' values
+ * \remark Convertion of normal in 3D needs two attributes (coordinate axis of transversal plane)
+ * \param[in,out] theParams list of converted values which appended to incoming list
+ * \param[in] theAttr attribute to be converted
+ * \param[in] theNormExtraAttr additional attribute for conversion of a normal
+ */
+static void ConvertAttributeToParamList(
+ std::vector<double>& theParams,
+ boost::shared_ptr<ModelAPI_Attribute> theAttr,
+ boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr = boost::shared_ptr<ModelAPI_Attribute>());
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ * \param[in] theEntityID unique ID of the element
+ * \param[in] theEntities list of elements
+ * \return position of the found element or -1 if the element is not found
+ */
+template <typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+
// ========================================================
// ========= SketchSolver_ConstraintManager ===============
// ========================================================
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
+{
+ if (!_self)
+ _self = new SketchSolver_ConstraintManager();
+ return _self;
+}
+
SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
{
myGroups.clear();
+
+ // Register in event loop
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
}
SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
myGroups.clear();
}
+void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
+{
+ if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED))
+ {
+ const Model_FeatureUpdatedMessage* aCreateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+
+ // Only sketches and constraints can be added by Create event
+ boost::shared_ptr<SketchPlugin_Sketch> aSketch =
+ boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aCreateMsg->feature());
+ if (aSketch)
+ {
+ addWorkplane(aSketch);
+ return ;
+ }
+ boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+ boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aCreateMsg->feature());
+ if (aConstraint)
+ {
+ addConstraint(aConstraint);
+ return ;
+ }
+ }
+ else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
+ {
+ const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
+ /// \todo Implement deleting objects on event
+ }
+ else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+ {
+ const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+
+ boost::shared_ptr<SketchPlugin_Sketch> aSketch =
+ boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
+ if (aSketch)
+ {
+ updateWorkplane(aSketch);
+ return ;
+ }
+
+ boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+ boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
+ if (aConstraint)
+ {
+// updateConstraint(aConstraint);
+ return ;
+ }
+
+ boost::shared_ptr<SketchPlugin_Feature> aFeature =
+ boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
+// if (aFeature)
+// updateEntity(aFeature);
+ }
+}
+
+
+bool SketchSolver_ConstraintManager::addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+ // Check the specified workplane is already used
+ std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if (aGroupIter->isBaseWorkplane(theSketch))
+ return true;
+ // Create new group for workplane
+ SketchSolver_ConstraintGroup aNewGroup(theSketch);
+ // Verify that the group is created successfully
+ if (!aNewGroup.isBaseWorkplane(theSketch))
+ return false;
+ myGroups.push_back(aNewGroup);
+ return true;
+}
+
+bool SketchSolver_ConstraintManager::updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+ bool aResult = true; // changed when a workplane wrongly updated
+ bool isUpdated = false;
+ // Try to update specified workplane in all groups
+ std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if (aGroupIter->isBaseWorkplane(theSketch))
+ {
+ isUpdated = true;
+ if (!aGroupIter->updateWorkplane(theSketch))
+ aResult = false;
+ }
+ // If the workplane is not updates, so this is a new workplane
+ if (!isUpdated)
+ return addWorkplane(theSketch);
+ return aResult;
+}
+
+bool SketchSolver_ConstraintManager::addConstraint(
+ boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+ // Search the groups which this constraint touchs
+ std::vector<Slvs_hGroup> aGroups;
+ findGroups(theConstraint, aGroups);
+
+ // Process the groups list
+ if (aGroups.size() == 0)
+ { // There are no groups applicable for this constraint => create new one
+ boost::shared_ptr<SketchPlugin_Sketch> aWP = findWorkplaneForConstraint(theConstraint);
+ if (!aWP) return false;
+ SketchSolver_ConstraintGroup aGroup(aWP);
+ aGroup.addConstraint(theConstraint);
+ myGroups.push_back(aGroup);
+ return true;
+ }
+ else if (aGroups.size() == 1)
+ { // Only one group => add constraint into it
+ Slvs_hGroup aGroupId = *(aGroups.begin());
+ std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if (aGroupIter->getId() == aGroupId)
+ return aGroupIter->addConstraint(theConstraint);
+ }
+ else if (aGroups.size() > 1)
+ { // Several groups applicable for this constraint => need to merge them
+ /// \todo Implement merging of groups
+ }
+
+ // Something goes wrong
+ return false;
+}
+
+
void SketchSolver_ConstraintManager::findGroups(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
std::vector<Slvs_hGroup>& theGroupIDs) const
theGroupIDs.push_back(aGroupIter->getId());
}
+boost::shared_ptr<SketchPlugin_Sketch> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
+ boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
+{
+ std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ {
+ boost::shared_ptr<SketchPlugin_Sketch> aWP = aGroupIter->getWorkplane();
+ boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
+ std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
+ std::list< boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIter;
+ for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+ if (*anIter == theConstraint)
+ return aWP; // workplane is found
+ }
+
+ return boost::shared_ptr<SketchPlugin_Sketch>();
+}
+
+
// ========================================================
// ========= SketchSolver_ConstraintGroup ===============
// ========================================================
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup()
+SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
+ SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane)
: myID(++myGroupIndexer),
myParamMaxID(0),
myEntityMaxID(0),
myEntities.clear();
myConstraints.clear();
- // The workplane will be initialized on first constraint, so its handle is NULL meanwhile
- myWorkplane.h = 0;
-
// Nullify all elements of the set of equations
myConstrSet.param = 0;
myConstrSet.entity = 0;
myConstrSet.constraint = 0;
myConstrSet.failed = 0;
+
+ // Initialize workplane
+ myWorkplane.h = 0;
+ addWorkplane(theWorkplane);
}
SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
delete [] myConstrSet.failed;
}
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
+ boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const
+{
+ return theWorkplane == mySketch;
+}
+
bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
{
bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
{
+ // There is no workplane yet, something wrong
if (myWorkplane.h == 0)
- {
-// // Create workplane when first constraint is added
-// std::list< boost::shared_ptr<ModelAPI_Attribute> > aWPAttr;
-// theConstraint->getSketchParameters(aWPAttr);
-// if (!addWorkplane(aWPAttr))
-// return false;
- }
+ return false;
+
+ // Get constraint type and verify the constraint parameters are correct
+ int aConstrType = getConstraintType(theConstraint);
+ if (aConstrType == SLVS_C_UNKNOWN)
+ return false;
// Create constraint parameters
double aDistance = 0.0; // scalar value of the constraint
boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
- if (aDistAttr.get())
+ if (aDistAttr)
aDistance = aDistAttr->value();
- /// \todo Specify the entities
- Slvs_hEntity aPtA, aPtB, aEntityA, aEntityB; // parameters of the constraint
- boost::shared_ptr<ModelAPI_Attribute> aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
- aPtA = addEntity(aEntAttr);
- if (aPtA == 0) return false;
- aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
- aPtB = addEntity(aEntAttr);
- if (aPtB == 0) return false;
- aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_C);
- aEntityA = addEntity(aEntAttr);
- if (aEntityA == 0) return false;
- aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_D);
- aEntityB = addEntity(aEntAttr);
- if (aEntityB == 0) return false;
-
- // Constraint type
- int aConstrType = getConstraintType(theConstraint);
- if (aConstrType == 0) return false;
+ Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
+ for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+ {
+ boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
+ );
+ aConstrEnt[indAttr] = addEntity(aConstrAttr->attr());
+ }
// Create SolveSpace constraint structure
Slvs_Constraint aConstraint =
Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
- aDistance, aPtA, aPtB, aEntityA, aEntityB);
+ aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
myConstraints.push_back(aConstraint);
myConstraintMap[theConstraint] = *(myConstraints.rbegin());
Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
boost::shared_ptr<ModelAPI_Attribute> theEntity)
{
- /// \todo Should be implemented
+ // Look over supported types of entities
+
+ // Point in 3D
+ boost::shared_ptr<GeomDataAPI_Point> aPoint =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+ if (aPoint)
+ {
+ Slvs_hParam aX = addParameter(aPoint->x());
+ Slvs_hParam aY = addParameter(aPoint->y());
+ Slvs_hParam aZ = addParameter(aPoint->z());
+ Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
+ myEntities.push_back(aPtEntity);
+ return aPtEntity.h;
+ }
+
+ // Point in 2D
+ boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+ if (aPoint2D)
+ {
+ // The 2D points are created on workplane. So, if there is no workplane yet, then error
+ if (myWorkplane.h == 0)
+ return 0;
+ Slvs_hParam aU = addParameter(aPoint2D->x());
+ Slvs_hParam aV = addParameter(aPoint2D->y());
+ Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
+ myEntities.push_back(aPt2DEntity);
+ return aPt2DEntity.h;
+ }
+
+ /// \todo Other types of entities
+
+ // Unsupported or wrong entity type
return 0;
}
+Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addNormal(
+ boost::shared_ptr<ModelAPI_Attribute> theDirX,
+ boost::shared_ptr<ModelAPI_Attribute> theDirY)
+{
+ // Convert axes to the coordinates of normal
+ std::vector<double> aNormCoord;
+ ConvertAttributeToParamList(aNormCoord, theDirX, theDirY);
+
+ // Create a normal
+ Slvs_hParam aNormParams[4];
+ for (int i = 0; i < 4; i++)
+ aNormParams[i] = addParameter(aNormCoord[i]);
+ Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
+ aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
+ myEntities.push_back(aNormal);
+ return aNormal.h;
+}
+
+
bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
- std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams)
+ boost::shared_ptr<SketchPlugin_Sketch> theSketch)
{
- /// \todo Should be implemented
- return false;
+ if (myWorkplane.h)
+ return false; // the workplane already exists
+
+ // Get parameters of workplane
+ boost::shared_ptr<ModelAPI_Attribute> aDirX = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
+ boost::shared_ptr<ModelAPI_Attribute> aDirY = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
+ boost::shared_ptr<ModelAPI_Attribute> anOrigin = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
+ // Transform them into SolveSpace format
+ Slvs_hEntity aNormalWP = addNormal(aDirX, aDirY);
+ if (!aNormalWP) return false;
+ Slvs_hEntity anOriginWP = addEntity(anOrigin);
+ if (!anOriginWP) return false;
+ // Create workplane
+ myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
+ mySketch = theSketch;
+ // Workplane should be added to the list of entities
+ myEntities.push_back(myWorkplane);
+ return true;
+}
+
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane(
+ boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+ // Renew Sketch pointer
+ mySketch = theSketch;
+
+ // Get parameters of workplane
+ boost::shared_ptr<ModelAPI_Attribute> aDirX = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
+ boost::shared_ptr<ModelAPI_Attribute> aDirY = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
+ boost::shared_ptr<ModelAPI_Attribute> anOrig = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
+ // Transform them to lists of coordinates
+ std::vector<double> aNormal;
+ ConvertAttributeToParamList(aNormal, aDirX, aDirY);
+ std::vector<double> anOrigin;
+ ConvertAttributeToParamList(anOrigin, anOrig);
+
+ // Search the normal and the origin in the parameters list and update their values.
+ // Remark: entities are sorted in the vector, so the most probable position
+ // of the entity is equal to identifier the entity
+
+ // search normal
+ int aEntPos = Search(myWorkplane.normal, myEntities);
+ if (aEntPos < 0) return false;
+ // search first parameter of normal
+ int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+ if (aParamPos < 0) return false;
+ std::vector<Slvs_Param>::iterator aParamIter = myParams.begin() + aParamPos;
+ // change normal parameters
+ std::vector<double>::iterator anIter;
+ for (anIter = aNormal.begin(); anIter != aNormal.end(); anIter++, aParamIter++)
+ aParamIter->val = *anIter;
+
+ // search origin
+ aEntPos = Search(myWorkplane.point[0], myEntities);
+ if (aEntPos < 0) return false;
+ // search first parameter of origin
+ aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+ if (aParamPos < 0) return false;
+ aParamIter = myParams.begin() + aParamPos;
+ // change origin's parameters
+ for (anIter = anOrigin.begin(); anIter != anOrigin.end(); anIter++, aParamIter++)
+ aParamIter->val = *anIter;
+
+ return true;
+}
+
+
+Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addParameter(double theParam)
+{
+ Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
+ myParams.push_back(aParam);
+ return aParam.h;
}
int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
{
-// if (theConstraint->getKind() == SketchPlugin_ConstraintDistance().getKind())
-// {
-// boost::shared_ptr<ModelAPI_Attribute> aPtA = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_A);
-// boost::shared_ptr<ModelAPI_Attribute> aPtB = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_B);
-// boost::shared_ptr<ModelAPI_Attribute> aEntA = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-// boost::shared_ptr<ModelAPI_Attribute> aEntB = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-// boost::shared_ptr<ModelAPI_AttributeDouble> aDistance =
-// boost::shared_dynamic_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-// if (aPtA.get()) // ptA is an attribute of the constraint
-// {
-//// if (aEntA.get()) // entityA is an attribute of the constraint
-//// {
-//// if (aEntA->feature()->getKind() == SketchPlugin_Line().getKind()) // entityA is a line
-//// {
-//// if (aEntB.get() && aEntB->feature()->getKind() == SketchPlugin_Line().getKind()) // entityB is a line too
-//// return SLVS_C_ANGLE;
-//// else if (aPtB.get()) // ptB is also an attribute of the constraint
-//// return SLVS_C_PROJ_PT_DISTANCE;
-//// else
-//// return SLVS_C_PT_LINE_DISTANCE;
-//// }
-//// /// \todo Implement other point-entity distances
-//// }
-//// else
-// if (aPtB.get()) // ptB is an attribute of the constrtaint => point-point distance
-// {
-// if (aDistance->value() == 0.0)
-// return SLVS_C_POINTS_COINCIDENT;
-// else
-// return SLVS_C_PT_PT_DISTANCE;
-// }
-// }
-// else if (aEntA.get() && !aEntB.get() && !aPtB.get())
-// return SLVS_C_DIAMETER;
-// return SLVS_C_UNKNOWN;
-// }
+ // Constraint for coincidence of two points
+ boost::shared_ptr<SketchPlugin_ConstraintCoincidence> aPtEquiv =
+ boost::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidence>(theConstraint);
+ if (aPtEquiv)
+ {
+ // Verify the constraint has only two attributes and they are points
+ int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point
+ int aPt3d = 0; // bit-mapped field, the same information for 3D points
+ for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+ {
+ boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
+ );
+ // Verify the attribute is a 2D point
+ boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+ if (aPoint2D)
+ {
+ aPt2d |= (1 << indAttr);
+ continue;
+ }
+ // Verify the attribute is a 3D point
+ boost::shared_ptr<GeomDataAPI_Point> aPoint3D =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point>(anAttr->attr());
+ if (aPoint3D)
+ {
+ aPt3d |= (1 << indAttr);
+ continue;
+ }
+ // Attribute neither 2D nor 3D point is not supported by this type of constraint
+ return SLVS_C_UNKNOWN;
+ }
+ // The constrained points should be in first and second positions,
+ // so the expected value of aPt2d or aPt3d is 3
+ if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
+ return SLVS_C_POINTS_COINCIDENT;
+ // Constraint parameters are wrong
+ return SLVS_C_UNKNOWN;
+ }
+
/// \todo Implement other kind of constrtaints
return SLVS_C_UNKNOWN;
}
+
+
+
+// ========================================================
+// ========= Auxiliary functions ===============
+// ========================================================
+
+void ConvertAttributeToParamList(
+ std::vector<double>& theParams,
+ boost::shared_ptr<ModelAPI_Attribute> theAttr,
+ boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr)
+{
+ // Point in 3D
+ boost::shared_ptr<GeomDataAPI_Point> aPoint =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttr);
+ if (aPoint)
+ {
+ theParams.push_back(aPoint->x());
+ theParams.push_back(aPoint->y());
+ theParams.push_back(aPoint->z());
+ return ;
+ }
+
+ // Point in 2D
+ boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttr);
+ if (aPoint2D)
+ {
+ theParams.push_back(aPoint2D->x());
+ theParams.push_back(aPoint2D->y());
+ return ;
+ }
+
+ // Normal in 3D
+ boost::shared_ptr<GeomDataAPI_Dir> aDirX =
+ boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theAttr);
+ boost::shared_ptr<GeomDataAPI_Dir> aDirY =
+ boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormExtraAttr);
+ if (aDirX && aDirY)
+ {
+ // quaternion parameters of normal vector
+ double qw, qx, qy, qz;
+ Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(),
+ aDirY->x(), aDirY->y(), aDirY->z(),
+ &qw, &qx, &qy, &qz);
+ theParams.push_back(qw);
+ theParams.push_back(qx);
+ theParams.push_back(qy);
+ theParams.push_back(qz);
+ }
+
+ /// \todo Other types of entities
+}
+
+template <typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+ std::vector<T>::const_iterator aEntIter = theEntities.begin() + theEntityID - 1;
+ while (aEntIter != theEntities.end() && aEntIter->h > theEntityID)
+ aEntIter--;
+ while (aEntIter != theEntities.end() && aEntIter->h < theEntityID)
+ aEntIter++;
+ if (aEntIter == theEntities.end())
+ return -1;
+ return aEntIter - theEntities.begin();
+}
+
#include "SketchSolver.h"
+#include <Events_Listener.h>
#include <SketchPlugin_Constraint.h>
// Need to be defined before including SolveSpace to avoid additional dependances on Windows platform
/** \class SketchSolver_ConstraintManager
* \ingroup DataModel
- * \brief Transforms the Constraint feature into the format understandable by SolveSpace library.
+ * \brief Listens the changes of SketchPlugin features and transforms the Constraint
+ * feature into the format understandable by SolveSpace library.
*
- * Constraints created for SolveSpace library will be divided into the groups.
+ * Constraints created for SolveSpace library are divided into the groups.
* The division order based on connectedness of the features by the constraints.
* The groups may be fused or separated according to the new constraints.
+ *
+ * \remark This is a singleton.
*/
-class SketchSolver_ConstraintManager
+class SketchSolver_ConstraintManager : public Events_Listener
{
public:
+ /** \brief Main method to create constraint manager
+ * \return pointer to the singleton
+ */
+ static SketchSolver_ConstraintManager* Instance();
+
+ /** \brief Implementation of Event Listener method
+ * \param[in] theMessage the data of the event
+ */
+ virtual void processEvent(const Events_Message* theMessage);
+
+protected:
SketchSolver_ConstraintManager();
~SketchSolver_ConstraintManager();
* \param[in] theConstraint constraint to be added
* \return \c true if the constraint added successfully
*/
- SKETCHSOLVER_EXPORT bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+ bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
/** \brief Removes a constraint from the manager
* \param[in] theConstraint constraint to be removed
* \return \c true if the constraint removed successfully
*/
- SKETCHSOLVER_EXPORT bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+ bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+ /** \brief Updates a constraint
+ * \param[in] theConstraint constraint to be updated
+ * \return \c true if the constraint was updated
+ */
+ bool updateConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+ /** \brief Adds a workplane into the manager
+ * \param[in] theSketch the feature to create workplane
+ * \return \c true if the workplane added successfully
+ */
+ bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+ /** \brief Removes a workplane from the manager.
+ * All groups based on such workplane will be removed too.
+ * \param[in] theSketch the feature to be removed
+ * \return \c true if the workplane removed successfully
+ */
+ bool removeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+ /** \brief Updates a workplane
+ * \param[in] theSketch workplane to be updated
+ * \return \c true if the workplane was updated
+ */
+ bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+ /** \brief Updates entity which is neither workplane nor constraint
+ * \param[in] theFeature entity to be updated
+ * \return \c true if the entity updated successfully
+ */
+ bool updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature);
private:
class SketchSolver_ConstraintGroup;
void findGroups(boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
std::vector<Slvs_hGroup>& theGroupIDs) const;
+ /** \brief Searches in the list of groups the workplane which constains specified constraint
+ * \param[in] theConstraint constraint to be found
+ * \return workplane contains the constraint
+ */
+ boost::shared_ptr<SketchPlugin_Sketch> findWorkplaneForConstraint(
+ boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
+
private:
- std::vector<SketchSolver_ConstraintGroup> myGroups; ///< groups of constraints
+ static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality
+ std::vector<SketchSolver_ConstraintGroup> myGroups; ///< Groups of constraints
};
class SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup
{
public:
- SketchSolver_ConstraintGroup();
+ /** \brief New group based on specified workplane
+ */
+ SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane);
+
~SketchSolver_ConstraintGroup();
/// \brief Returns group's unique identifier
*/
bool isInteract(boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
-protected:
- /** \brief Creates a workplane from the sketch parameters
- * \param[in] theParams list of the basic parameters of the workplane
- * \return \c true if success
+ /** \brief Verifies the specified workplane is the same as a base workplane for this group
+ * \param[in] theWorkplane workplane to be compared
+ * \return \c true if workplanes are the same
+ */
+ bool isBaseWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const;
+
+ boost::shared_ptr<SketchPlugin_Sketch> getWorkplane() const
+ { return mySketch; }
+
+ /** \brief Update parameters of workplane. Should be called when Update event is coming
+ * \param[in] theWorkplane workplane to be updated
+ * \return \c true if workplane updated successfully
*/
- bool addWorkplane(std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams);
+ bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane);
+protected:
/** \brief Adds an entity into the group
+ *
+ * The parameters of entity will be parsed and added to the list of SolveSpace parameters.
+ * Parameters of certain entity will be placed sequentially in the list.
+ *
* \param[in] theEntity the object of constraint
* \return identifier of created entity or 0 if entity was not added
*/
Slvs_hEntity addEntity(boost::shared_ptr<ModelAPI_Attribute> theEntity);
+ /** \brief Adds a normal into the group
+ *
+ * Normal is a special entity in SolveSpace, which defines a direction in 3D and
+ * a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
+ *
+ * To define a normal there should be specified two coordinate axis
+ * on the plane transversed to created normal.
+ *
+ * \param[in] theDirX first coordinate axis of the plane
+ * \param[in] theDirY second coordinate axis of the plane
+ * \return identifier of created normal
+ */
+ Slvs_hEntity addNormal(boost::shared_ptr<ModelAPI_Attribute> theDirX,
+ boost::shared_ptr<ModelAPI_Attribute> theDirY);
+
/** \brief Adds a parameter into the group
* \param[in] theParam parameter to be added
* \return identifier of created parameter or 0 if it was not added
Slvs_hParam addParameter(double theParam);
/** \brief Compute constraint type according to SolveSpace identifiers
+ * and verify that constraint parameters are correct
* \param[in] theConstraint constraint which type should be determined
- * \return identifier of constraint type
+ * \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong
*/
int getConstraintType(const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const;
private:
+ /** \brief Creates a workplane from the sketch parameters
+ * \param[in] theSketch parameters of workplane are the attributes of this sketch
+ * \return \c true if success
+ */
+ bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+private:
+ // SolveSpace entities
Slvs_hGroup myID; ///< the index of the group
Slvs_Entity myWorkplane; ///< Workplane for the current group
std::vector<Slvs_Param> myParams; ///< List of parameters of the constraints
- Slvs_hParam myParamMaxID; ///< Actual maximal ID of parameters
+ Slvs_hParam myParamMaxID; ///< Actual maximal ID of parameters (not equal to myParams size)
std::vector<Slvs_Entity> myEntities; ///< List of entities of the constaints
- Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities
+ Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities (not equal to myEntities size)
std::vector<Slvs_Constraint> myConstraints; ///< List of constraints in SolveSpace format
- Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints
+ Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints (not equal to myConstraints size)
Slvs_System myConstrSet; ///< SolveSpace's set of equations obtained by constraints
+
+ // SketchPlugin entities
+ boost::shared_ptr<SketchPlugin_Sketch> mySketch; ///< Equivalent to workplane
std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_Constraint>
myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
};
aContext->UpdateCurrentViewer();
}
+void XGUI_Displayer::EraseAll(const bool isUpdateViewer)
+{
+ Handle(AIS_InteractiveContext) ic = AISContext();
+
+ AIS_ListOfInteractive aList;
+ ic->DisplayedObjects(aList);
+ AIS_ListIteratorOfListOfInteractive anIter(aList);
+ for (; anIter.More(); anIter.Next()) {
+ if ((anIter.Value()->DynamicType() == STANDARD_TYPE(AIS_Trihedron)))
+ continue;
+
+ // erase an object
+ Handle(AIS_InteractiveObject) anIO = anIter.Value();
+ ic->Erase(anIO, false);
+ }
+ myFeature2AISObjectMap.clear();
+ if (isUpdateViewer)
+ ic->UpdateCurrentViewer();
+}
+
void XGUI_Displayer::CloseLocalContexts(const bool isUpdateViewer)
{
closeAllContexts(true);
}
}
+void XGUI_Displayer::UpdateViewer()
+{
+ Handle(AIS_InteractiveContext) ic = AISContext();
+ if (!ic.IsNull())
+ ic->UpdateCurrentViewer();
+}
+
Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const
{
return myWorkshop->viewer()->AISContext();
/// \param isUpdateViewer the parameter whether the viewer should be update immediatelly
void Erase(boost::shared_ptr<ModelAPI_Feature> theFeature, const bool isUpdateViewer = true);
+ /// Erase all presentations
+ /// \param isUpdateViewer the parameter whether the viewer should be update immediatelly
+ void EraseAll(const bool isUpdateViewer = true);
+
/// Deactivates selection of sub-shapes
/// \param isUpdateViewer the parameter whether the viewer should be update immediatelly
void CloseLocalContexts(const bool isUpdateViewer = true);
+ /// Updates the viewer
+ void UpdateViewer();
+
protected:
/// Deactivate local selection
/// \param isUpdateViewer the state wether the viewer should be updated immediatelly
return true;
}
+bool XGUI_OperationMgr::abortOperation()
+{
+ ModuleBase_Operation* aCurrentOp = currentOperation();
+ if (!aCurrentOp || !canStopOperation())
+ return false;
+
+ aCurrentOp->abort();
+ return true;
+}
+
void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
{
connect(theOperation, SIGNAL(stopped()), this, SLOT(onOperationStopped()));
ModuleBase_Operation* aCurrentOp = currentOperation();
if (aCurrentOp && !theOperation->isGranted())
{
- int anAnswer = QMessageBox::question(0, tr("Operation launch"),
- tr("Previous operation is not finished and will be aborted"),
- QMessageBox::Ok, QMessageBox::Cancel);
- if (anAnswer == QMessageBox::Ok) {
+ if (canStopOperation()) {
aCurrentOp->abort();
} else {
aCanStart = false;
return aCanStart;
}
+bool XGUI_OperationMgr::canStopOperation()
+{
+ int anAnswer = QMessageBox::question(0, tr("Operation launch"),
+ tr("Previous operation is not finished and will be aborted"),
+ QMessageBox::Ok, QMessageBox::Cancel);
+ return anAnswer == QMessageBox::Ok;
+}
+
void XGUI_OperationMgr::onOperationStopped()
{
ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
/// \return the state whether the current operation is started
bool startOperation(ModuleBase_Operation* theOperation);
+ /// Abort the operation and append it to the stack of operations
+ /// \return the state whether the current operation is aborted
+ bool abortOperation();
+
signals:
/// Signal about an operation is started. It is emitted after the start() of operation is done.
void operationStarted();
/// \param theOperation an operation to check
bool canStartOperation(ModuleBase_Operation* theOperation);
+ /// Returns whether the operation can be stopped.
+ bool canStopOperation();
+
protected slots:
/// Slot that is called by an operation stop. Removes the stopped operation form the stack.
/// If there is a suspended operation, restart it.
}
//show file dialog, check if readable and open
- myCurrentFile = QFileDialog::getOpenFileName(mainWindow());
+ myCurrentFile = QFileDialog::getExistingDirectory(mainWindow());
if(myCurrentFile.isEmpty())
return;
QFileInfo aFileInfo(myCurrentFile);
objectBrowser()->setCurrentIndex(QModelIndex());
boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
+ if (!operationMgr()->abortOperation())
+ return;
aDoc->undo();
updateCommandStatus();
}