std::shared_ptr<ModelAPI_DocumentCreatedMessage> aMessage = std::dynamic_pointer_cast<
ModelAPI_DocumentCreatedMessage>(theMessage);
DocumentPtr aDoc = aMessage->document();
+
+ /// Issue 431: for the current moment create planes only in the module document,
+ /// Later if it is needed we may create special initial planes in Parts (may be different)
+ if (aDoc != ModelAPI_Session::get()->moduleDocument())
+ return;
+
std::list<FeaturePtr> aFeatures;
// the viewer update should be blocked in order to avoid the features blinking before they are
string anID = aData->id(theAttr);
if (myIsInitialized && object() == theAttr->owner() && myID->Get().IsEqual(anID.c_str()))
return; // nothing is changed
+ REMOVE_BACK_REF(theAttr->owner());
myRef->Set(aData->label().Father());
myID->Set(aData->id(theAttr).c_str());
+ ADD_BACK_REF(theAttr->owner());
owner()->data()->sendAttributeUpdated(this);
}
{
// the back reference from the previous object to the attribute should be removed
ObjectPtr anObject = object();
- if (anObject.get() && anObject != theObject) {
- FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
- if (anOwnerFeature.get()) {
- std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
- anObject->data());
- aData->removeBackReference(anOwnerFeature, id());
- }
- }
-
if (theObject && (!myIsInitialized || myID->Get().Length() != 0 || object() != theObject)) {
+ REMOVE_BACK_REF(anObject);
+
std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
theObject->data());
myRef->Set(aData->label().Father());
if (anOwnerFeature.get()) {
aData->addBackReference(anOwnerFeature, id(), false);
}
+ ADD_BACK_REF(theObject);
owner()->data()->sendAttributeUpdated(this);
} else if (theObject.get() == NULL) {
+ REMOVE_BACK_REF(anObject);
myRef->Set(myRef->Label()); // reference to itself means that object is null
myID->Set(""); // feature is identified by the empty ID
owner()->data()->sendAttributeUpdated(this);
myRef->Append(aData->label().Father()); // store label of the object
// do it before the transaction finish to make just created/removed objects know dependencies
// and reference from composite feature is removed automatically
- FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
- if (anOwnerFeature.get()) {
- aData->addBackReference(anOwnerFeature, id());
- }
+ ADD_BACK_REF(theObject);
owner()->data()->sendAttributeUpdated(this);
}
ObjectPtr anObj = aDoc->object(aLIter.Value());
if (anObj.get() == NULL) {
myRef->Remove(aLIter.Value());
+ REMOVE_BACK_REF(theObject);
break;
}
}
{
if(!theObject)
return;
- if (!myIsInitialized || value() != theObject) {
+ ObjectPtr aValue = value();
+ if (!myIsInitialized || aValue != theObject) {
+ REMOVE_BACK_REF(aValue);
+
std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
- theObject->data());
+ theObject->data());
TDF_Label anObjLab = aData->label().Father(); // object label
if (owner()->document() == theObject->document()) { // same document, use reference attribute
}
// do it before the transaction finish to make just created/removed objects know dependencies
// and reference from composite feature is removed automatically
- FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
- if (anOwnerFeature.get()) {
- aData->addBackReference(anOwnerFeature, id(), false);
- }
+ ADD_BACK_REF(theObject);
owner()->data()->sendAttributeUpdated(this);
}
if (theSubShape.get() && !theSubShape->isNull() && theSubShape->isEdge()) {
const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
if (aSubShape.ShapeType() == TopAbs_EDGE)
- isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape));
+ isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape)) == Standard_True;
}
if (!theContext.get() || isDegeneratedEdge) {
// to keep the reference attribute label
const bool theApplyConcealment = true);
};
+/// Generic method to register back reference, used in referencing attributes.
+/// Without concealment change, it will be done later, on synchronization.
+#define ADD_BACK_REF(TARGET) \
+ if (TARGET.get() != NULL) { \
+ FeaturePtr anAttributeOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner()); \
+ if (anAttributeOwnerFeature.get()) { \
+ std::shared_ptr<Model_Data> aTargetData = std::dynamic_pointer_cast<Model_Data>( \
+ (TARGET)->data()); \
+ aTargetData->addBackReference(anAttributeOwnerFeature, id(), false); \
+ } \
+ }
+
+/// Generic method to unregister back reference, used in referencing attributes.
+/// Without concealment change, it will be done later, on synchronization.
+#define REMOVE_BACK_REF(TARGET) \
+ if (TARGET.get() != NULL) { \
+ FeaturePtr anAttOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner()); \
+ if (anAttOwnerFeature.get()) { \
+ std::shared_ptr<Model_Data> aTargetData = std::dynamic_pointer_cast<Model_Data>( \
+ (TARGET)->data()); \
+ aTargetData->removeBackReference(anAttOwnerFeature, id()); \
+ } \
+ }
+
#endif
myDoc->Undo();
myDoc->ClearRedos();
}
- // references were not changed since transaction start
- synchronizeFeatures(true, false, isRoot());
+ // references may be changed because they are set in attributes on the fly
+ synchronizeFeatures(true, true, isRoot());
// abort for all subs
const std::set<std::string> aSubs = subDocuments(true);
std::set<std::string>::iterator aSubIter = aSubs.begin();
ModelAPI_ShapeValidator.cpp
ModelAPI_Tools.cpp
ModelAPI_ResultParameter.cpp
+ ModelAPI_AttributeValidator.cpp
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: ModelAPI_AttributeValidator.cpp
+// Created: 4 Sep 2014
+// Author: Mikhail PONIKAROV
+
+#include <ModelAPI_AttributeValidator.h>
+
+ModelAPI_AttributeValidator::~ModelAPI_AttributeValidator()
+{
+
+}
#ifndef ModelAPI_AttributeValidator_H
#define ModelAPI_AttributeValidator_H
+#include <ModelAPI.h>
#include <ModelAPI_Attribute.h>
#include <ModelAPI_Validator.h>
//! \param theArguments arguments of the attribute
virtual bool isValid(const AttributePtr& theAttribute,
const std::list<std::string>& theArguments) const = 0;
+
+ MODELAPI_EXPORT ~ModelAPI_AttributeValidator();
};
#endif
}
}
// 2. ignore not obligatory widgets
- for (; aWIt != aWidgets.constEnd(); ++aWIt) {
+ /*for (; aWIt != aWidgets.constEnd(); ++aWIt) {
aWgt = (*aWIt);
if (aWgt && aWgt->isObligatory())
continue;
aFilledWgt = aWgt;
- }
+ }*/
// 3. activate the next obligatory widget
myPropertyPanel->activateNextWidget(aFilledWgt);
result = new ModuleBase_WidgetShapeSelector(theParent, myWorkshop, myWidgetApi, myParentId);
} else if (theType == WDG_BOOLVALUE) {
result = new ModuleBase_WidgetBoolValue(theParent, myWidgetApi, myParentId);
- } else if (theType == WDG_DOUBLEVALUE_EDITOR) {
- result = new ModuleBase_WidgetEditor(theParent, myWidgetApi, myParentId);
+ //} else if (theType == WDG_DOUBLEVALUE_EDITOR) {
+ // result = new ModuleBase_WidgetEditor(theParent, myWidgetApi, myParentId);
} else if (theType == WDG_FILE_SELECTOR) {
result = new ModuleBase_WidgetFileSelector(theParent, myWidgetApi, myParentId);
} else if (theType == WDG_CHOICE) {
PartSet_Validators.h
PartSet_WidgetPoint2d.h
PartSet_WidgetConstraintShapeSelector.h
+ PartSet_WidgetEditor.h
PartSet_WidgetPoint2dDistance.h
PartSet_WidgetShapeSelector.h
PartSet_Filters.h
PartSet_FilterSketchEntity.h
PartSet_SketcherMgr.h
+ PartSet_MenuMgr.h
)
SET(PROJECT_SOURCES
PartSet_WidgetSketchLabel.cpp
PartSet_Validators.cpp
PartSet_WidgetConstraintShapeSelector.cpp
+ PartSet_WidgetEditor.cpp
PartSet_WidgetPoint2d.cpp
PartSet_WidgetPoint2dDistance.cpp
PartSet_WidgetShapeSelector.cpp
PartSet_Filters.cpp
PartSet_FilterSketchEntity.cpp
PartSet_SketcherMgr.cpp
+ PartSet_MenuMgr.cpp
)
SET(PROJECT_RESOURCES
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: PartSet_MenuMgr.cpp
+// Created: 03 April 2015
+// Author: Vitaly SMETANNIKOV
+
+#include "PartSet_MenuMgr.h"
+#include "PartSet_Module.h"
+#include "PartSet_SketcherMgr.h"
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Point.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_Operation.h>
+
+#include <XGUI_ModuleConnector.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <Events_Loop.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Session.h>
+
+#include <QAction>
+#include <QMenu>
+
+PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
+ : QObject(theModule), myModule(theModule), myPrevId(-1)
+{
+ createActions();
+}
+
+
+QAction* PartSet_MenuMgr::action(const QString& theId) const
+{
+ if (myActions.contains(theId))
+ return myActions[theId];
+ return 0;
+}
+
+void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
+{
+ if (myActions.contains(theId))
+ qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
+ theAction->setData(theId);
+ connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
+ myActions[theId] = theAction;
+}
+
+void PartSet_MenuMgr::createActions()
+{
+ QAction* anAction;
+
+ anAction = new QAction(tr("Auxiliary"), this);
+ anAction->setCheckable(true);
+ addAction("AUXILIARY_CMD", anAction);
+}
+
+
+void PartSet_MenuMgr::onAction(bool isChecked)
+{
+ QAction* aAction = static_cast<QAction*>(sender());
+ QString anId = aAction->data().toString();
+
+ if (anId == "AUXILIARY_CMD") {
+ setAuxiliary(isChecked);
+ }
+}
+
+/// Returns point of coincidence feature
+/// \param theFeature the coincidence feature
+/// \param theAttribute the attribute name
+std::shared_ptr<GeomAPI_Pnt2d> getPoint(std::shared_ptr<ModelAPI_Feature>& theFeature,
+ const std::string& theAttribute)
+{
+ std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
+
+ if (!theFeature->data())
+ return std::shared_ptr<GeomAPI_Pnt2d>();
+
+ FeaturePtr aFeature;
+ std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
+ ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
+ if (anAttr)
+ aFeature = ModelAPI_Feature::feature(anAttr->object());
+
+ if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
+ aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
+
+ else if (aFeature && aFeature->getKind() == SketchPlugin_Circle::ID())
+ aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
+
+ else if (anAttr->attr()) {
+ aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+ }
+ if (aPointAttr.get() != NULL)
+ return aPointAttr->pnt();
+ return std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
+/// Returns list of features connected in a councedence feature point
+/// \param theStartCoin the coincidence feature
+/// \param theList a list which collects lines features
+/// \param theAttr the attribute name
+void findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList, std::string theAttr)
+{
+ AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
+ FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
+ if (!theList.contains(aObj)) {
+ std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
+ theList.append(aObj);
+ const std::set<AttributePtr> aRefsList = aObj->data()->refsToMe();
+ std::set<AttributePtr>::const_iterator aIt;
+ for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
+ std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
+ FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+ if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
+ if (aOrig->isEqual(aPnt)) {
+ findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+ findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+ }
+ }
+ }
+ }
+}
+
+
+bool PartSet_MenuMgr::addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
+{
+ ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+ if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
+ !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+ return false;
+
+ myCoinsideLines.clear();
+ ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
+ QObjectPtrList aObjects = aSelection->selectedPresentations();
+ if (aObjects.size() > 0) {
+ bool hasFeature = false;
+ FeaturePtr aFeature;
+ foreach(ObjectPtr aObject, aObjects) {
+ aFeature = ModelAPI_Feature::feature(aObject);
+ if (aFeature.get() != NULL) {
+ hasFeature = true;
+ }
+ }
+ if (hasFeature) {
+ bool aIsDetach = false;
+ if (aObjects.size() == 1) {
+ if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ /// If the feature is coincident then we use Detach command instead Delete
+ mySelectedFeature = aFeature;
+ findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+ findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+ if (myCoinsideLines.size() > 0) {
+ aIsDetach = true;
+ QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
+ QAction* aAction;
+ int i = 0;
+ foreach (FeaturePtr aCoins, myCoinsideLines) {
+ aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
+ aAction->setData(QVariant(i));
+ i++;
+ }
+ connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
+ connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
+ connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
+ }
+ }
+ }
+ if (!aIsDetach)
+ theMenu->addAction(theStdActions["DELETE_CMD"]);
+ }
+ }
+ bool isAuxiliary;
+ if (canSetAuxiliary(isAuxiliary)) {
+ QAction* anAction = action("AUXILIARY_CMD");
+ theMenu->addAction(anAction);
+ anAction->setChecked(isAuxiliary);
+ }
+ return true;
+}
+
+void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
+{
+ if (myPrevId != -1) {
+ // Restore color for previous object
+ setLineColor(myPrevId, myColor, false);
+ }
+ myPrevId = theAction->data().toInt();
+ myColor = setLineColor(myPrevId, Qt::white, true);
+}
+
+QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
+{
+ XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+ XGUI_Workshop* aWorkshop = aConnector->workshop();
+ XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+
+ FeaturePtr aLine = myCoinsideLines.at(myPrevId);
+ std::list<ResultPtr>::const_iterator aIt;
+ const std::list<ResultPtr>& aResults = aLine->results();
+ QColor aColor;
+ for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
+ aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
+ }
+ if (theUpdate)
+ aDisplayer->updateViewer();
+ return aColor;
+}
+
+
+void PartSet_MenuMgr::onLineDetach(QAction* theAction)
+{
+ int aId = theAction->data().toInt();
+ FeaturePtr aLine = myCoinsideLines.at(aId);
+ std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+ gp_Pnt aOr = aOrig->impl<gp_Pnt>();
+ const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
+
+ QObjectPtrList aToDelFeatures;
+ std::set<AttributePtr>::const_iterator aIt;
+ // Find all coincedences corresponded to the selected line in the selected point
+ for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
+ std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
+ FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+ if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+ gp_Pnt aP = aPnt->impl<gp_Pnt>();
+ if (aOrig->isEqual(aPnt)) {
+ aToDelFeatures.append(aConstrFeature);
+ } else {
+ aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+ aP = aPnt->impl<gp_Pnt>();
+ if (aOrig->isEqual(aPnt)) {
+ aToDelFeatures.append(aConstrFeature);
+ break;
+ }
+ }
+ }
+ }
+ if (aToDelFeatures.size() > 0) {
+ XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+ XGUI_Workshop* aWorkshop = aConnector->workshop();
+ ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+ if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+ anOperation->abort();
+
+ SessionPtr aMgr = ModelAPI_Session::get();
+ std::set<FeaturePtr> anIgnoredFeatures;
+ anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
+
+ QString aName = tr("Detach %1").arg(aLine->data()->name().c_str());
+ aMgr->startOperation(aName.toStdString());
+ aWorkshop->deleteFeatures(aToDelFeatures, anIgnoredFeatures);
+ aMgr->finishOperation();
+ }
+ myCoinsideLines.clear();
+}
+
+
+void PartSet_MenuMgr::onDetachMenuHide()
+{
+ if (myPrevId != -1) {
+ // Restore color for previous object
+ setLineColor(myPrevId, myColor, false);
+ }
+ // Clear previous definitions
+ myPrevId = -1;
+}
+
+
+void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
+{
+ ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+
+ bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
+ PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
+ if (!isActiveSketch)
+ return;
+
+ QObjectPtrList anObjects;
+ bool isUseTransaction = false;
+ // 1. change auxiliary type of a created feature
+ if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
+ PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
+ anObjects.append(anOperation->feature());
+ }
+ else {
+ isUseTransaction = true;
+ // 2. change auxiliary type of selected sketch entities
+ ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
+ anObjects = aSelection->selectedPresentations();
+ }
+
+ QAction* anAction = action("AUXILIARY_CMD");
+ SessionPtr aMgr = ModelAPI_Session::get();
+ if (isUseTransaction) {
+ if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+ anOperation->abort();
+ aMgr->startOperation(anAction->text().toStdString());
+ }
+ myModule->sketchMgr()->storeSelection();
+
+ if (anObjects.size() > 0) {
+ QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
+ for (; anIt != aLast; anIt++) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature.get() != NULL) {
+ std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+ if (aSketchFeature.get() != NULL) {
+ std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
+
+ std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
+ if (anAuxiliaryAttr)
+ anAuxiliaryAttr->setValue(isChecked);
+ }
+ }
+ }
+ }
+ if (isUseTransaction) {
+ aMgr->finishOperation();
+ }
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ myModule->sketchMgr()->restoreSelection();
+}
+
+bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
+{
+ bool anEnabled = false;
+ ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+
+ bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
+ PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
+ if (!isActiveSketch)
+ return anEnabled;
+
+ QObjectPtrList anObjects;
+ // 1. change auxiliary type of a created feature
+ if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
+ PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
+ anObjects.append(anOperation->feature());
+ }
+ else {
+ /// The operation should not be aborted here, because the method does not changed
+ /// the auxilliary state, but checks the possibility to perform this
+ ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+ /// anOperation->abort();
+ // 2. change auxiliary type of selected sketch entities
+ ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
+ anObjects = aSelection->selectedPresentations();
+ }
+ anEnabled = anObjects.size() > 0;
+
+ bool isNotAuxiliaryFound = false;
+ if (anObjects.size() > 0) {
+ QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
+ for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature.get() != NULL) {
+ std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+ if (aSketchFeature.get() != NULL) {
+ std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
+
+ std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
+ if (anAuxiliaryAttr)
+ isNotAuxiliaryFound = !anAuxiliaryAttr->value();
+ }
+ }
+ }
+ }
+ theValue = anObjects.size() && !isNotAuxiliaryFound;
+ return anEnabled;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: PartSet_MenuMgr.h
+// Created: 03 April 2015
+// Author: Vitaly SMETANNIKOV
+
+#ifndef PartSet_MenuMgr_H
+#define PartSet_MenuMgr_H
+
+#include <ModelAPI_Feature.h>
+
+#include <QObject>
+#include <QMap>
+#include <QString>
+#include <QList>
+#include <QColor>
+
+class PartSet_Module;
+class QAction;
+class QMenu;
+
+/**
+* \ingroup Modules
+* A class for management of module specific menu
+*/
+class PartSet_MenuMgr: public QObject
+{
+ Q_OBJECT
+public:
+ /// Constructor
+ /// \param theModule a parent module
+ PartSet_MenuMgr(PartSet_Module* theModule);
+
+
+ /// Returns action according to the given ID
+ /// \param theId an action identifier, it should be uniqued in the bounds of the module
+ QAction* action(const QString& theId) const;
+
+ /// Add menu atems for viewer into the given menu
+ /// \param theMenu a popup menu to be shown in the viewer
+ /// \param theStdActions a map of standard actions
+ /// \return true if items are added and there is no necessity to provide standard menu
+ bool addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const;
+
+public slots:
+ /// Processes the context menu action click
+ /// \param isChecked a state of toggle if the action is checkable
+ void onAction(bool isChecked);
+
+private slots:
+
+ /// A slot which is called on selection of menu item coresponding to line with coincedence
+ /// \param theAction an action of the selected item
+ void onLineHighlighted(QAction* theAction);
+
+ /// A slot which is called on hiding Detach menu
+ void onDetachMenuHide();
+
+ /// A slot which is called on selection an Item in Detach menu
+ /// \param theAction an action of the selected item
+ void onLineDetach(QAction* theAction);
+
+private:
+ /// Returns true if the current operation is sketch entity create operation
+ /// \param theValue the current auxiliary value
+ /// \return the boolean result
+ bool canSetAuxiliary(bool& theValue) const;
+
+ /// Changes the sketcher entity construction argument value
+ /// \param isChecked if true, the feature is a construction
+ void setAuxiliary(const bool isChecked);
+
+ /// Create all actions for context menus. It is called on creation of module
+ /// Put the created actions into an internal map
+ void createActions();
+
+ /// Add action to the internal map
+ /// \param theId - string ID of the item
+ /// \param theAction - action to add
+ void addAction(const QString& theId, QAction* theAction);
+
+ /// Set color on presentation of result listed in myCoinsideLines
+ /// \param theId object Id in myCoinsideLines list
+ /// \param theColor a color which has to be set
+ /// \param theUpdate update viewer flag
+ /// \return previously defined color on the object
+ QColor setLineColor(int theId, const QColor theColor, bool theUpdate);
+
+ /// Reference to a parent module
+ PartSet_Module* myModule;
+
+ /// the popup menu actions
+ QMap<QString, QAction*> myActions;
+
+ /// List of lines coincided in a one point
+ mutable QList<FeaturePtr> myCoinsideLines;
+
+ /// A Coincedence feature selected by user for detaching
+ mutable FeaturePtr mySelectedFeature;
+
+ /// Id of menu item in Detach menu previously selected
+ int myPrevId;
+
+ /// Original color of highlighted line
+ QColor myColor;
+};
+
+#endif
\ No newline at end of file
#include <PartSet_WidgetPoint2dDistance.h>
#include <PartSet_WidgetShapeSelector.h>
#include <PartSet_WidgetConstraintShapeSelector.h>
-#include <PartSet_SketcherMgr.h>
+#include <PartSet_WidgetEditor.h>
+#include "PartSet_SketcherMgr.h"
+#include "PartSet_MenuMgr.h"
#include <ModuleBase_Operation.h>
#include <ModuleBase_IViewer.h>
#include <SketchPlugin_Feature.h>
#include <SketchPlugin_Sketch.h>
#include <SketchPlugin_Line.h>
-//#include <SketchPlugin_Arc.h>
-//#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Point.h>
#include <SketchPlugin_ConstraintLength.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintParallel.h>
#include <Events_Loop.h>
#include <Config_PropManager.h>
+#include <Config_Keywords.h>
#include <StdSelect_TypeOfFace.hxx>
#include <TopoDS_Vertex.hxx>
connect(aViewer, SIGNAL(viewTransformed(int)),
SLOT(onViewTransformed(int)));
- createActions();
+ myMenuMgr = new PartSet_MenuMgr(this);
}
PartSet_Module::~PartSet_Module()
bool PartSet_Module::canDisplayObject(const ObjectPtr& theObject) const
{
- // the display should be possible almost always, with exception of some specific cases
-
- bool aCanDisplay = true;
-
- if (mySketchMgr->activeSketch()) {
- aCanDisplay = mySketchMgr->canDisplayObject(theObject);
- }
- return aCanDisplay;
+ // the sketch manager put the restriction to the objects display
+ return mySketchMgr->canDisplayObject(theObject);
}
+
bool PartSet_Module::addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
{
- ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
- if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
- !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
- return false;
+ return myMenuMgr->addViewerItems(theMenu, theStdActions);
+}
- ModuleBase_ISelection* aSelection = myWorkshop->selection();
- QObjectPtrList aObjects = aSelection->selectedPresentations();
- if (aObjects.size() > 0) {
- bool hasFeature = false;
- foreach(ObjectPtr aObject, aObjects)
- {
- FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
- if (aFeature.get() != NULL) {
- hasFeature = true;
- }
- }
- if (hasFeature) {
- theMenu->addAction(theStdActions["DELETE_CMD"]);
- }
- }
- bool isAuxiliary;
- if (mySketchMgr->canSetAuxiliary(isAuxiliary)) {
- QAction* anAction = action("AUXILIARY_CMD");
- theMenu->addAction(anAction);
- anAction->setChecked(isAuxiliary);
- }
- return true;
+bool PartSet_Module::isMouseOverWindow()
+{
+ return mySketchMgr->isMouseOverWindow();
}
void PartSet_Module::propertyPanelDefined(ModuleBase_Operation* theOperation)
new PartSet_WidgetConstraintShapeSelector(theParent, workshop(), theWidgetApi, theParentId);
aConstraintShapeSelectorWgt->setSketcher(mySketchMgr->activeSketch());
aWgt = aConstraintShapeSelectorWgt;
- }
+ } if (theType == WDG_DOUBLEVALUE_EDITOR) {
+ aWgt = new PartSet_WidgetEditor(theParent, workshop(), theWidgetApi, theParentId);
+ }
return aWgt;
}
-void PartSet_Module::createActions()
-{
- QAction* anAction;
-
- anAction = new QAction(tr("Auxiliary"), this);
- anAction->setCheckable(true);
- addAction("AUXILIARY_CMD", anAction);
-}
-
-QAction* PartSet_Module::action(const QString& theId) const
-{
- if (myActions.contains(theId))
- return myActions[theId];
- return 0;
-}
-
-void PartSet_Module::addAction(const QString& theId, QAction* theAction)
-{
- if (myActions.contains(theId))
- qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
- theAction->setData(theId);
- connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
- myActions[theId] = theAction;
-}
-
-void PartSet_Module::onAction(bool isChecked)
-{
- QAction* aAction = static_cast<QAction*>(sender());
- QString anId = aAction->data().toString();
-
- if (anId == "AUXILIARY_CMD") {
- mySketchMgr->setAuxiliary(isChecked);
- }
-}
bool PartSet_Module::deleteObjects()
{
// the abort leads to selection lost on constraint objects. It can be corrected after #386 issue
XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
XGUI_Workshop* aWorkshop = aConnector->workshop();
- ModuleBase_ISelection* aSel = aConnector->selection();
+ ModuleBase_ISelection* aSel = workshop()->selection();
QObjectPtrList aSelectedObj = aSel->selectedPresentations();
// if there are no selected objects in the viewer, that means that the selection in another
// place cased this method. It is necessary to return the false value to understande in above
#include "PartSet.h"
#include "PartSet_Filters.h"
-#include "PartSet_SketcherMgr.h"
#include <ModuleBase_IModule.h>
#include <ModuleBase_Definitions.h>
class ModuleBase_Operation;
class ModuleBase_IViewWindow;
+class PartSet_MenuMgr;
+class PartSet_SketcherMgr;
class QAction;
/// \param theOperation a started operation
virtual ModuleBase_Operation* currentOperation() const;
- /// Returns action according to the given ID
- /// \param theId an action identifier, it should be uniqued in the bounds of the module
- QAction* action(const QString& theId) const;
-
/// Returns True if there are available Undos and the sketch manager allows undo
/// \return the boolean result
virtual bool canUndo() const;
/// \return true if items are added and there is no necessity to provide standard menu
virtual bool addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const;
+ /// Returns whether the mouse enter the viewer's window
+ /// \return true if items are added and there is no necessity to provide standard menu
+ bool isMouseOverWindow();
+
+ PartSet_SketcherMgr* sketchMgr() const { return mySketchMgr; }
+
public slots:
/// SLOT, that is called by no more widget signal emitted by property panel
/// Set a specific flag to restart the sketcher operation
void onNoMoreWidgets();
- /// Processes the context menu action click
- /// \param isChecked a state of toggle if the action is checkable
- void onAction(bool isChecked);
-
/// Slolt called on object display
/// \param theObject a data object
/// \param theAIS a presentation object
/// Breaks sequense of automatically resterted operations
void breakOperationSequence();
- /// Create all actions for context menus. It is called on creation of module
- /// Put the created actions into an internal map
- void createActions();
-
- /// Add action to the internal map
- /// \param theId - string ID of the item
- /// \param theAction - action to add
- void addAction(const QString& theId, QAction* theAction);
-
//! Delete features
virtual bool deleteObjects();
PartSet_SketcherMgr* mySketchMgr;
- QMap<QString, QAction*> myActions; // the popup menu actions
+ PartSet_MenuMgr* myMenuMgr;
int myVisualLayerId;
};
bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
{
bool aCanDisplay = true;
- // 1. the sketch feature should not be displayed during the sketch active operation
- // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch
- // nested features can be visualized
- CompositeFeaturePtr aSketchFeature = activeSketch();
- if (aSketchFeature.get() != NULL) {
+
+ bool aHasActiveSketch = activeSketch().get() != NULL;
+ if (aHasActiveSketch) {
+ // 1. the sketch feature should not be displayed during the sketch active operation
+ // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch
+ // nested features can be visualized
FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
- if (aFeature.get() != NULL && aFeature == aSketchFeature)
+ if (aFeature.get() != NULL && aFeature == activeSketch())
aCanDisplay = false;
}
- // 2. For created nested feature operation do not display the created feature if
+ else { // there are no an active sketch
+ // 2. sketch sub-features should not visualized if the sketch operatio is not active
+ FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+ if (aFeature.get() != NULL) {
+ std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+ if (aSketchFeature.get())
+ aCanDisplay = false;
+ }
+ }
+
+ // 3. For created nested feature operation do not display the created feature if
// the mouse curstor leaves the OCC window.
// The correction cases, which ignores this condition:
// a. the property panel values modification
// b. the popup menu activated
// c. widget editor control
- if (aCanDisplay) {
- if (!isNestedCreateOperation(getCurrentOperation()))
- return aCanDisplay;
-
+ if (aCanDisplay && isNestedCreateOperation(getCurrentOperation())) {
ModuleBase_Operation* aOperation = getCurrentOperation();
ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
ModuleBase_ModelWidget* anActiveWdg = aPanel ? aPanel->activeWidget() : 0;
+ ModuleBase_WidgetEditor* anEditorWdg = anActiveWdg ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWdg) : 0;
// the active widget editor should not influence here. The presentation should be visible always
// when this widget is active.
- if (anActiveWdg) {
- ModuleBase_WidgetEditor* anEditorWdg = dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWdg);
- if (anEditorWdg) {
- return aCanDisplay;
- }
+ if (!anEditorWdg && !myIsPopupMenuActive) {
+ // during a nested create operation, the feature is redisplayed only if the mouse over view
+ // of there was a value modified in the property panel after the mouse left the view
+ aCanDisplay = myIsPropertyPanelValueChanged || myIsMouseOverWindow;
}
- if (myIsPopupMenuActive)
- return aCanDisplay;
-
- // during a nested create operation, the feature is redisplayed only if the mouse over view
- // of there was a value modified in the property panel after the mouse left the view
- aCanDisplay = myIsPropertyPanelValueChanged || myIsMouseOverWindow;
}
return aCanDisplay;
}
-bool PartSet_SketcherMgr::canSetAuxiliary(bool& theValue) const
-{
- bool anEnabled = false;
- ModuleBase_Operation* anOperation = getCurrentOperation();
-
- bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
- PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
- if (!isActiveSketch)
- return anEnabled;
-
- QObjectPtrList anObjects;
- // 1. change auxiliary type of a created feature
- if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
- PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
- anObjects.append(anOperation->feature());
- }
- else {
- /// The operation should not be aborted here, because the method does not changed
- /// the auxilliary state, but checks the possibility to perform this
- ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
- /// anOperation->abort();
- // 2. change auxiliary type of selected sketch entities
- ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
- anObjects = aSelection->selectedPresentations();
- }
- anEnabled = anObjects.size() > 0;
-
- bool isNotAuxiliaryFound = false;
- if (anObjects.size() > 0) {
- QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
- for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
- if (aFeature.get() != NULL) {
- std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
- if (aSketchFeature.get() != NULL) {
- std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
-
- std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
- if (anAuxiliaryAttr)
- isNotAuxiliaryFound = !anAuxiliaryAttr->value();
- }
- }
- }
- }
- theValue = anObjects.size() && !isNotAuxiliaryFound;
- return anEnabled;
-}
-
-void PartSet_SketcherMgr::setAuxiliary(const bool isChecked)
-{
- ModuleBase_Operation* anOperation = getCurrentOperation();
-
- bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
- PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
- if (!isActiveSketch)
- return;
-
- QObjectPtrList anObjects;
- bool isUseTransaction = false;
- // 1. change auxiliary type of a created feature
- if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
- PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
- anObjects.append(anOperation->feature());
- }
- else {
- isUseTransaction = true;
- // 2. change auxiliary type of selected sketch entities
- ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
- anObjects = aSelection->selectedPresentations();
- }
-
- QAction* anAction = myModule->action("AUXILIARY_CMD");
- SessionPtr aMgr = ModelAPI_Session::get();
- if (isUseTransaction) {
- if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
- anOperation->abort();
- aMgr->startOperation(anAction->text().toStdString());
- }
- storeSelection();
-
- if (anObjects.size() > 0) {
- QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
- for (; anIt != aLast; anIt++) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
- if (aFeature.get() != NULL) {
- std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
- if (aSketchFeature.get() != NULL) {
- std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
-
- std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
- if (anAuxiliaryAttr)
- anAuxiliaryAttr->setValue(isChecked);
- }
- }
- }
- }
- if (isUseTransaction) {
- aMgr->finishOperation();
- }
- Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
- restoreSelection();
-}
void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
{
/// \return a boolean value
static bool isDistanceOperation(ModuleBase_Operation* theOperation);
+ bool isMouseOverWindow() { return myIsMouseOverWindow; }
+
/// Returns current Sketch feature/ Returns NULL if there is no launched sketch operation
CompositeFeaturePtr activeSketch() const { return myCurrentSketch; }
/// \param theObject a model object
bool canDisplayObject(const ObjectPtr& theObject) const;
- /// Returns true if the current operation is sketch entity create operation
- /// \param theValue the current auxiliary value
- /// \return the boolean result
- bool canSetAuxiliary(bool& theValue) const;
-
- /// Changes the sketcher entity construction argument value
- /// \param isChecked if true, the feature is a construction
- void setAuxiliary(const bool isChecked);
-
-
+ /// Returns state of constraints showing flag
bool isConstraintsShown() const { return myIsConstraintsShown; }
+ /// Saves the current selection in the viewer into an internal container
+ /// It obtains the selected attributes. The highlighted objects can be processes as the selected ones
+ /// \param theHighlightedUse a boolean flag
+ void storeSelection(const bool theHighlightedOnly = false);
+ void restoreSelection();
/// Returns list of strings which contains id's of sketch operations
static const QStringList& sketchOperationIdList();
/// \param isToDisplay a flag about the display or erase the feature
void visualizeFeature(ModuleBase_Operation* theOperation, const bool isToDisplay);
- /// Saves the current selection in the viewer into an internal container
- /// It obtains the selected attributes. The highlighted objects can be processes as the selected ones
- /// \param theHighlightedUse a boolean flag
- void storeSelection(const bool theHighlightedOnly = false);
- void restoreSelection();
-
private:
PartSet_Module* myModule;
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: PartSet_WidgetShapeSelector.cpp
+// Created: 27 Nov 2014
+// Author: Vitaly Smetannikov
+
+#include "PartSet_WidgetEditor.h"
+#include "PartSet_Module.h"
+
+#include <ModuleBase_IWorkshop.h>
+
+#include <Config_WidgetAPI.h>
+
+#include <QWidget>
+
+PartSet_WidgetEditor::PartSet_WidgetEditor(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData,
+ const std::string& theParentId)
+ : ModuleBase_WidgetEditor(theParent, theData, theParentId), myWorkshop(theWorkshop)
+{
+}
+
+bool PartSet_WidgetEditor::focusTo()
+{
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+ if (aModule->isMouseOverWindow())
+ return ModuleBase_WidgetDoubleValue::focusTo();
+ else {
+ ModuleBase_WidgetEditor::focusTo();
+ }
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: PartSet_WidgetShapeSelector.h
+// Created: 27 Nov 2014
+// Author: Vitaly Smetannikov
+
+
+#ifndef PartSet_WidgetEditor_H
+#define PartSet_WidgetEditor_H
+
+#include "PartSet.h"
+
+#include <ModuleBase_WidgetEditor.h>
+
+class ModuleBase_IWorkshop;
+
+/**
+* \ingroup Modules
+* Customosation of ModuleBase_WidgetEditor in order to do not show the editor value if the mouse
+* cursor is not over the OCC window
+*/
+class PARTSET_EXPORT PartSet_WidgetEditor : public ModuleBase_WidgetEditor
+{
+Q_OBJECT
+ public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theWorkshop instance of workshop interface
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ /// \param theParentId is Id of a parent of the current attribute
+ PartSet_WidgetEditor(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData, const std::string& theParentId);
+
+ virtual ~PartSet_WidgetEditor() {}
+
+ /// Activates the editor control only in case if the mouse over the OCC window, otherwise
+ /// set focus to the usual double value control
+ /// \return the state whether the widget can accept the focus
+ virtual bool focusTo();
+
+private:
+ ModuleBase_IWorkshop* myWorkshop; // the current workshop
+};
+
+#endif
\ No newline at end of file
#include <GeomAPI_XYZ.h>
#include <SketchPlugin_Sketch.h>
+#include <SketcherPrs_Tools.h>
#include <Precision.hxx>
#include <gp_Pln.hxx>
// Get default selection modes
QIntList aModes;
- aModes.append(AIS_DSM_Text);
- aModes.append(AIS_DSM_Line);
+ aModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
+ aModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
+ aModes.append(SketcherPrs_Tools::Sel_Constraint);
aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum) TopAbs_VERTEX));
aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum) TopAbs_EDGE));
}
};
+typedef std::shared_ptr<SketchPlugin_Constraint> ConstraintPtr;
+
#endif
AISObjectPtr anAIS = thePrevious;
if (!anAIS) {
anAIS = SketcherPrs_Factory::coincidentConstraint(this, sketch()->coordinatePlane());
- anAIS->setColor(0, 0, 255);
+ std::vector<int> aRGB = Config_PropManager::color("Visualization", "sketch_constraint_color",
+ SKETCH_DIMENSION_COLOR);
+ anAIS->setColor(aRGB[0], aRGB[1], aRGB[2]);
}
return anAIS;
}
aPnt_A = aPoint_A->pnt();
aPnt_B = aPoint_B->pnt();
} else if (!aPoint_A && aPoint_B) {
- std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
- aData, SketchPlugin_Constraint::ENTITY_A());
- if (aLine) {
- aPnt_B = aPoint_B->pnt();
- aPnt_A = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_B);
- }
+ //std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+ // aData, SketchPlugin_Constraint::ENTITY_A());
+ //if (aLine) {
+ // aPnt_B = aPoint_B->pnt();
+ // aPnt_A = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_B);
+ //}
} else if (aPoint_A && !aPoint_B) {
- std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
- aData, SketchPlugin_Constraint::ENTITY_B());
- if (aLine) {
- aPnt_A = aPoint_A->pnt();
- aPnt_B = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_A);
- }
+ //std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+ // aData, SketchPlugin_Constraint::ENTITY_B());
+ //if (aLine) {
+ // aPnt_A = aPoint_A->pnt();
+ // aPnt_B = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_A);
+ //}
}
if (!aPnt_A || !aPnt_B)
return false;
if (aPointA && aPointB) { // both points
aDistance = aPointA->pnt()->distance(aPointB->pnt());
} else {
- if (!aPointA && aPointB) { //Line and point
- std::shared_ptr<SketchPlugin_Line> aLine =
- SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
- if (aLine) {
- aDistance = aLine->distanceToPoint(aPointB->pnt());
- }
- } else if (aPointA && !aPointB) { // Point and line
- std::shared_ptr<SketchPlugin_Line> aLine =
- SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
- if (aLine) {
- aDistance = aLine->distanceToPoint(aPointA->pnt());
- }
- }
+// if (!aPointA && aPointB) { //Line and point
+// std::shared_ptr<SketchPlugin_Line> aLine =
+// SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
+// if (aLine) {
+// aDistance = aLine->distanceToPoint(aPointB->pnt());
+// }
+// } else if (aPointA && !aPointB) { // Point and line
+// std::shared_ptr<SketchPlugin_Line> aLine =
+// SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
+// if (aLine) {
+// aDistance = aLine->distanceToPoint(aPointA->pnt());
+// }
+// }
}
return aDistance;
}
#include <Config_PropManager.h>
#include <Events_Loop.h>
+static const std::string PREVIOUS_VALUE("FilletPreviousRadius");
+
/// \brief Attract specified point on theNewArc to the attribute of theFeature
static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
FeaturePtr theFeature, const std::string& theFeatureAttribute);
data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
+ data()->addAttribute(PREVIOUS_VALUE, ModelAPI_AttributeDouble::typeId());
// initialize attribute not applicable for user
data()->attribute(SketchPlugin_Constraint::ENTITY_C())->setInitialized();
+ data()->attribute(PREVIOUS_VALUE)->setInitialized();
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(data()->attribute(PREVIOUS_VALUE))->setValue(0.0);
}
void SketchPlugin_ConstraintFillet::execute()
FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
if (aFeature == aFilletArcFeature) {
- AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
- aRadius->setValue(aFilletRadius);
+ // Update radius constraint only if the value is changed in fillet's attribute
+ double aPrevRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aData->attribute(PREVIOUS_VALUE))->value();
+ if (aFilletRadius != aPrevRadius) {
+ AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
+ aRadius->setValue(aFilletRadius);
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aData->attribute(PREVIOUS_VALUE))->setValue(aFilletRadius);
+ }
+ break;
}
}
return;
FeaturePtr aNewFeatureA = sketch()->addFeature(aFeatureA->getKind());
aFeatureA->data()->copyTo(aNewFeatureA->data());
aNewFeatureA->execute();
- aRefListOfFillet->append(aNewFeatureA);
+ aRefListOfFillet->append(aNewFeatureA->firstResult());
// copy aFeatureB
FeaturePtr aNewFeatureB = sketch()->addFeature(aFeatureB->getKind());
aFeatureB->data()->copyTo(aNewFeatureB->data());
aNewFeatureB->execute();
- aRefListOfFillet->append(aNewFeatureB);
- // create filleting arc
+ aRefListOfFillet->append(aNewFeatureB->firstResult());
+ // create filleting arc (it will be attached to the list later)
FeaturePtr aNewArc = sketch()->addFeature(SketchPlugin_Arc::ID());
- aRefListOfFillet->append(aNewArc);
- aRefListOfFillet->setInitialized();
// Wait all constraints being created, then send update events
static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
aCenter->x(), aCenter->y());
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
aNewArc->attribute(SketchPlugin_Arc::START_ID()))->setValue(
- aCenter->x() - aStep->y(), aCenter->y() + aStep->x());
+ aSharedPoint->x() - 1.e-5 * aStep->y(), aSharedPoint->y() + 1.e-5 * aStep->x());
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
aNewArc->attribute(SketchPlugin_Arc::END_ID()))->setValue(
- aCenter->x() + aStep->y(), aCenter->y() - aStep->x());
+ aSharedPoint->x() + 1.e-5 * aStep->y(), aSharedPoint->y() - 1.e-5 * aStep->x());
aNewArc->execute();
+ // attach new arc to the list
+ aRefListOfFillet->append(aNewArc->lastResult());
+ aRefListOfFillet->setInitialized();
// Create list of additional constraints:
// 1. Coincidence of boundary points of features and fillet arc
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Events.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
aMirrorIter++;
}
+ static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
+
// Check consistency of initial list and mirrored list
anInitialList = aRefListOfShapes->list();
anInitIter = anInitialList.begin();
FeaturePtr aNewFeature = sketch()->addFeature(aFeatureIn->getKind());
aFeatureIn->data()->copyTo(aNewFeature->data());
aNewFeature->execute();
+ ModelAPI_EventCreator::get()->sendUpdated(aNewFeature, aRedisplayEvent);
std::shared_ptr<GeomAPI_Shape> aShapeIn = aRCIn->shape();
const std::list<ResultPtr>& aResults = aNewFeature->results();
#include "SketchPlugin_ConstraintRigid.h"
#include "SketchPlugin_ConstraintParallel.h"
+#include "SketchPlugin_Feature.h"
#include <SketcherPrs_Factory.h>
return thePrevious;
AISObjectPtr anAIS = thePrevious;
- if (!anAIS) {
- anAIS = SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane());
+ if (anAIS.get() == NULL) {
+ std::shared_ptr<ModelAPI_Data> aData = data();
+ std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ ObjectPtr aObj = anAttr->object();
+ if (aObj.get() != NULL) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
+ std::shared_ptr<SketchPlugin_Feature> aSkFea =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+ if (!aSkFea->isExternal())
+ anAIS = SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane());
+ }
}
return anAIS;
return aDelta;
}
+const std::string& SketchPlugin_Line::getKind()
+{
+ static std::string MY_KIND = SketchPlugin_Line::ID();
+ return MY_KIND;
+}
+
bool SketchPlugin_Line::isFixed() {
return data()->selection(EXTERNAL_ID())->context().get() != NULL;
}
}
/// Returns the kind of a feature
- SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
- {
- static std::string MY_KIND = SketchPlugin_Line::ID();
- return MY_KIND;
- }
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind();
/// Returns true is sketch element is under the rigid constraint
SKETCHPLUGIN_EXPORT virtual bool isFixed();
label="Last object" tooltip="Select line or arc" shape_types="edge">
</sketch_constraint_shape_selector>
- <doublevalue_editor label="Value" tooltip="Fillet radius" id="ConstraintValue" default="1" min="0" obligatory="0">
+ <doublevalue_editor label="Value" tooltip="Fillet radius" id="ConstraintValue" min="0">
<validator id="GeomValidators_Positive"/>
</doublevalue_editor>
</feature>
SET(PROJECT_HEADERS
SketchSolver.h
+ SketchSolver_Error.h
SketchSolver_Solver.h
SketchSolver_Constraint.h
- SketchSolver_ConstraintGroup.h
+ SketchSolver_ConstraintCoincidence.h
+ SketchSolver_ConstraintDistance.h
+ SketchSolver_ConstraintEqual.h
+ SketchSolver_ConstraintFillet.h
+ SketchSolver_ConstraintLength.h
+ SketchSolver_ConstraintMirror.h
+ SketchSolver_ConstraintRigid.h
+ SketchSolver_ConstraintTangent.h
+ SketchSolver_Builder.h
+ SketchSolver_Group.h
SketchSolver_ConstraintManager.h
+ SketchSolver_Storage.h
+ SketchSolver_FeatureStorage.h
)
SET(PROJECT_SOURCES
SketchSolver_Solver.cpp
SketchSolver_Constraint.cpp
- SketchSolver_ConstraintGroup.cpp
+ SketchSolver_ConstraintCoincidence.cpp
+ SketchSolver_ConstraintDistance.cpp
+ SketchSolver_ConstraintEqual.cpp
+ SketchSolver_ConstraintFillet.cpp
+ SketchSolver_ConstraintLength.cpp
+ SketchSolver_ConstraintMirror.cpp
+ SketchSolver_ConstraintRigid.cpp
+ SketchSolver_ConstraintTangent.cpp
+ SketchSolver_Builder.cpp
+ SketchSolver_Group.cpp
SketchSolver_ConstraintManager.cpp
+ SketchSolver_Storage.cpp
+ SketchSolver_FeatureStorage.cpp
)
SET(PROJECT_LIBRARIES
#endif
#endif
+/// Tolerance for value of parameters
+const double tolerance = 1.e-10;
+
#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Builder.cpp
+// Created: 25 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include "SketchSolver_Builder.h"
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_ConstraintDistance.h>
+#include <SketchSolver_ConstraintEqual.h>
+#include <SketchSolver_ConstraintFillet.h>
+#include <SketchSolver_ConstraintLength.h>
+#include <SketchSolver_ConstraintMirror.h>
+#include <SketchSolver_ConstraintRigid.h>
+#include <SketchSolver_ConstraintTangent.h>
+#include <SketchSolver_Error.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <Events_Error.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+
+#include <math.h>
+
+// Initialization of constraint builder self pointer
+SketchSolver_Builder* SketchSolver_Builder::mySelf = 0;
+
+SketchSolver_Builder* SketchSolver_Builder::getInstance()
+{
+ if (!mySelf)
+ mySelf = new SketchSolver_Builder();
+ return mySelf;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint)
+{
+ SolverConstraintPtr aResult;
+ DataPtr aData = theConstraint->data();
+ if (!aData || !aData->isValid())
+ return aResult;
+
+#ifdef _DEBUG
+ // Verify attributes of constraint and generate errors
+ std::list<AttributePtr> anAttrList = aData->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttrList.begin();
+ for (; anIter != anAttrList.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (aRefAttr->isObject() && aRefAttr->object()) {
+ ResultConstructionPtr aRC =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aRefAttr->object());
+ if (!aRC)
+ Events_Error::send(SketchSolver_Error::NEED_OBJECT_NOT_FEATURE(), this);
+ }
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aListIter);
+ if (*aListIter && !aRC)
+ Events_Error::send(SketchSolver_Error::NEED_OBJECT_NOT_FEATURE(), this);
+ }
+ }
+ }
+#endif
+
+ if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint));
+ }
+ return aResult;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature)
+{
+ DataPtr aData = theFixedFeature->data();
+ if (!aData || !aData->isValid())
+ return SolverConstraintPtr();
+ return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature));
+}
+
+
+
+bool SketchSolver_Builder::createWorkplane(
+ CompositeFeaturePtr theSketch,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ DataPtr aSketchData = theSketch->data();
+ if (!aSketchData || !aSketchData->isValid())
+ return false; // the sketch is incorrect
+
+ // Get parameters of workplane
+ std::shared_ptr<ModelAPI_Attribute> aDirX = aSketchData->attribute(
+ SketchPlugin_Sketch::DIRX_ID());
+ std::shared_ptr<ModelAPI_Attribute> aNorm = aSketchData->attribute(
+ SketchPlugin_Sketch::NORM_ID());
+ std::shared_ptr<ModelAPI_Attribute> anOrigin = aSketchData->attribute(
+ SketchPlugin_Sketch::ORIGIN_ID());
+ // Create SolveSpace entity corresponding to the sketch origin
+ if (!createEntity(anOrigin, theEntities, theParameters))
+ return false;
+ Slvs_hEntity anOriginID = theEntities.back().h;
+ // Create SolveSpace entity corresponding the the sketch normal
+ if (!createNormal(aNorm, aDirX, theEntities, theParameters))
+ return false;
+ Slvs_hEntity aNormalID = theEntities.back().h;
+
+ // Create workplane
+ Slvs_hEntity aWorkplaneID = theEntities.back().h + 1;
+ Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID);
+ theEntities.push_back(aWorkplane);
+ return true;
+}
+
+bool SketchSolver_Builder::createEntity(
+ AttributePtr theAttribute,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h;
+ Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h;
+
+ // Point in 3D
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+ if (aPoint) {
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x()));
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y()));
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z()));
+ theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN,
+ aParamID-2, aParamID-1, aParamID));
+ return true;
+ }
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ if (aPoint2D) {
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x()));
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y()));
+ theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+ aParamID-1, aParamID));
+ return true;
+ }
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aScalar) {
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value()));
+ theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN,
+ SLVS_E_UNKNOWN, aParamID));
+ return true;
+ }
+ // unknown attribute type
+ return false;
+}
+
+bool SketchSolver_Builder::createEntity(
+ FeaturePtr theFeature,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ if (!theFeature->data()->isValid())
+ return false;
+
+ // SketchPlugin features
+ std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+ SketchPlugin_Feature>(theFeature);
+ if (!aFeature)
+ return false;
+
+ // Verify the feature by its kind
+ const std::string& aFeatureKind = aFeature->getKind();
+ DataPtr aData = aFeature->data();
+ // Line
+ if (aFeatureKind == SketchPlugin_Line::ID()) {
+ AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID());
+ AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID());
+ if (!aStart->isInitialized() || !aEnd->isInitialized())
+ return false;
+ if (!createEntity(aStart, theEntities, theParameters) ||
+ !createEntity(aEnd, theEntities, theParameters))
+ return false;
+ Slvs_hEntity aLineID = theEntities.back().h + 1;
+ theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+ aLineID-2, aLineID-1));
+ }
+ // Circle
+ else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+ AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+ AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+ if (!aCenter->isInitialized() || !aRadius->isInitialized())
+ return false;
+ if (!createEntity(aCenter, theEntities, theParameters) ||
+ !createEntity(aRadius, theEntities, theParameters))
+ return false;
+ Slvs_hEntity aCircID = theEntities.back().h;
+ theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2,
+ SLVS_E_UNKNOWN, aCircID-1));
+ }
+ // Arc
+ else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+ AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+ AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID());
+ AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID());
+ if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
+ return false;
+ if (!createEntity(aCenter, theEntities, theParameters) ||
+ !createEntity(aStart, theEntities, theParameters) ||
+ !createEntity(aEnd, theEntities, theParameters))
+ return false;
+ Slvs_hEntity anArcID = theEntities.back().h;
+ theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+ SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1));
+ }
+ // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+ else if (aFeatureKind == SketchPlugin_Point::ID()) {
+ AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID());
+ if (!aPoint->isInitialized() ||
+ !createEntity(aPoint, theEntities, theParameters))
+ return false;
+ // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier.
+ // No need to add another entity.
+ }
+ return true;
+}
+
+bool SketchSolver_Builder::createNormal(
+ AttributePtr theNormal,
+ AttributePtr theDirX,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
+ std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+ if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
+ return false;
+ // calculate Y direction
+ std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
+
+ // 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);
+ double aNormCoord[4] = { qw, qx, qy, qz };
+
+ // Create parameters of the normal
+ Slvs_hParam aCurParam = theParameters.back().h;
+ for (int i = 0; i < 4; i++)
+ theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i]));
+
+ // Create a normal
+ Slvs_hEntity aCurEntity = theEntities.back().h + 1;
+ Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN,
+ aCurParam-3, aCurParam-2, aCurParam-1, aCurParam);
+ theEntities.push_back(aNormal);
+ return true;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Builder.h
+// Created: 25 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Builder_H_
+#define SketchSolver_Builder_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class SketchSolver_Builder
+ * \ingroup Plugins
+ * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints
+ */
+class SketchSolver_Builder
+{
+private:
+ /// Default constructor
+ SketchSolver_Builder() {}
+
+public:
+ /// \brief Returns single instance of builder
+ static SketchSolver_Builder* getInstance();
+
+ /// \brief Creates a solver's constraint using given SketchPlugin constraint
+ /// or returns empty pointer if not all attributes are correct
+ SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
+
+ /// \brief Creates temporary constraint to fix the placement of the feature
+ SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature);
+
+ /// \brief Converts sketch parameters to the list of SolveSpace entities.
+ /// Identifiers of entities and parameters are local. They should be changed while adding into storage.
+ /// The sketch entity goes last.
+ /// \param[in] theSketch the element to be converted
+ /// \param[out] theEntities created list of entities
+ /// \param[out] theParameters created list of parameters of the entities
+ /// \return \c true if workplane created
+ bool createWorkplane(CompositeFeaturePtr theSketch,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+
+ /// \brief Converts attribute to the list of entities.
+ /// Identifiers are local (see createWorkplane).
+ /// The main entity goes last.
+ bool createEntity(AttributePtr theAttribute,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+ /// \brief Converts feature to the list of entities.
+ /// Identifiers are local (see createWorkplane).
+ /// The main entity goes last.
+ bool createEntity(FeaturePtr theFeature,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+
+ /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace.
+ /// Identifiers are local (see createWorkplane).
+ /// The main entity goes last.
+ bool createNormal(AttributePtr theNormal,
+ AttributePtr theDirX,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+
+private:
+ static SketchSolver_Builder* mySelf;
+};
+
+#endif
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_Constraint.cpp
-// Created: 27 May 2014
-// Author: Artem ZHIDKOV
-
-#include "SketchSolver_Constraint.h"
-#include <SketchSolver_Solver.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintDistance.h>
-#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintHorizontal.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintParallel.h>
-#include <SketchPlugin_ConstraintPerpendicular.h>
-#include <SketchPlugin_ConstraintRadius.h>
-#include <SketchPlugin_ConstraintRigid.h>
-#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintVertical.h>
-
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Object.h>
-#include <ModelAPI_ResultConstruction.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
-#include <GeomAPI_Edge.h>
-#include <GeomAPI_Shape.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
-/// Possible types of attributes (used to determine constraint type)
-enum AttrType
+#include <math.h>
+
+SketchSolver_Constraint::SketchSolver_Constraint(
+ ConstraintPtr theConstraint)
+ : myBaseConstraint(theConstraint),
+ myGroup(0)
{
- UNKNOWN, // Something wrong during type determination
- POINT2D,
- POINT3D,
- LINE,
- CIRCLE,
- ARC
-};
-
-/// Calculate type of the attribute
-static AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute);
-
-SketchSolver_Constraint::SketchSolver_Constraint()
- : myConstraint(std::shared_ptr<SketchPlugin_Constraint>()),
- myType(SLVS_C_UNKNOWN),
- myAttributesList()
+}
+
+SketchSolver_Constraint::~SketchSolver_Constraint()
{
+ std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
+ for (; anIt1 != myValueMap.end(); anIt1++)
+ myStorage->removeParameter(anIt1->second);
+ myValueMap.clear();
+
+ std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
+ for (; anIt2 != myAttributeMap.end(); anIt2++)
+ myStorage->removeEntity(anIt2->second);
+ myAttributeMap.clear();
+
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator anIt3 = myFeatureMap.begin();
+ for (; anIt3 != myFeatureMap.end(); anIt3++)
+ myStorage->removeEntity(anIt3->second);
+ myFeatureMap.clear();
+
+ std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
+ for (; anIt4 != mySlvsConstraints.end(); anIt4++)
+ myStorage->removeConstraint(*anIt4);
+ mySlvsConstraints.clear();
}
-SketchSolver_Constraint::SketchSolver_Constraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
- : myConstraint(theConstraint),
- myAttributesList()
+void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
+{
+ myStorage = theStorage;
+ process();
+}
+
+void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
+{
+ myGroup = theGroup;
+ process();
+}
+
+
+void SketchSolver_Constraint::process()
{
- myType = getType(myConstraint);
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ int aConstrType = getType();
+ double aValue = 0.0;
+ std::vector<Slvs_hEntity> anAttributes;
+ getAttributes(aValue, anAttributes);
+ if (!myErrorMsg.empty())
+ return;
+
+ Slvs_hGroup aGroupID = myGroup->getId();
+ Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+ Slvs_Constraint aConstraint;
+ if (mySlvsConstraints.empty())
+ aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
+ aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+ else {
+ aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
+ aConstraint.valA = aValue;
+ static const int aNbAttrs = 6;
+ Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
+ &aConstraint.ptA, &aConstraint.ptB,
+ &aConstraint.entityA, &aConstraint.entityB,
+ &aConstraint.entityC, &aConstraint.entityD};
+ std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
+ for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
+ *(aConstrAttrs[i]) = *anIter;
+ }
+
+ Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
+ if (mySlvsConstraints.empty())
+ mySlvsConstraints.push_back(anID);
+ else
+ mySlvsConstraints[0] = anID;
+ adjustConstraint();
}
-const int& SketchSolver_Constraint::getType(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
{
- myType = SLVS_C_UNKNOWN;
- if (!theConstraint)
- return getType();
-
- DataPtr aConstrData = theConstraint->data();
- if (!aConstrData || !aConstrData->isValid())
- return getType();
-
- // Assign empty names of attributes
- myAttributesList.clear();
- for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
- myAttributesList.push_back(std::string());
-
- const std::string& aConstraintKind = theConstraint->getKind();
- // Constraint for coincidence of two points
- if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) {
- int anAttrPos = 0;
- // 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++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (!anAttr)
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint) {
+ if (theConstraint->getKind() != myBaseConstraint->getKind())
+ return;
+ remove(myBaseConstraint);
+ myBaseConstraint = theConstraint;
+ process();
+ }
+
+ // Update all attributes
+ int aType;
+ std::map<Slvs_hEntity, Slvs_hEntity> aRelocationMap;
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
+ for (; aFeatIter != myFeatureMap.end(); aFeatIter++) {
+ Slvs_hEntity aPrevID = aFeatIter->second;
+ aFeatIter->second = changeEntity(aFeatIter->first, aType);
+ if (aFeatIter->second != aPrevID)
+ aRelocationMap[aPrevID] = aFeatIter->second;
+ }
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+ for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+ Slvs_hEntity aPrevID = anAttrIter->second;
+ anAttrIter->second = changeEntity(anAttrIter->first, aType);
+ if (anAttrIter->second != aPrevID)
+ aRelocationMap[aPrevID] = anAttrIter->second;
+ }
+
+ // Value if exists
+ DataPtr aData = myBaseConstraint->data();
+ if (!aData) return;
+ AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
+ double aValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+ // Update constraint
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++) {
+ Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
+ aConstraint.valA = aValue;
+ Slvs_hEntity* aCoeffs[6] = {
+ &aConstraint.ptA, &aConstraint.ptB,
+ &aConstraint.entityA, &aConstraint.entityB,
+ &aConstraint.entityC, &aConstraint.entityD};
+ for (int i = 0; i < 6; i++) {
+ if (*(aCoeffs[i]) == SLVS_E_UNKNOWN)
continue;
- switch (typeOfAttribute(anAttr)) {
- case POINT2D: // the attribute is a 2D point
- aPt2d |= (1 << indAttr);
- myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- break;
- case POINT3D: // the attribute is a 3D point
- aPt3d |= (1 << indAttr);
- myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- break;
- default:
- // Attribute neither 2D nor 3D point is not supported by this type of constraint
- return getType();
- }
+ std::map<Slvs_hEntity, Slvs_hEntity>::iterator aFound = aRelocationMap.find(*(aCoeffs[i]));
+ if (aFound != aRelocationMap.end())
+ *(aCoeffs[i]) = aFound->second;
}
- // 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))
- myType = SLVS_C_POINTS_COINCIDENT;
- // Constraint parameters are wrong
- return getType();
+ *aCIter = myStorage->addConstraint(aConstraint);
}
+ adjustConstraint();
+}
- // Constraint for distance between point and another entity
- if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) {
- int aNbPoints = 0;
- int aNbEntities = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- switch (typeOfAttribute(anAttr)) {
- case POINT2D:
- case POINT3D:
- myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- break;
- case LINE:
- // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute
- myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- myType = SLVS_C_PT_LINE_DISTANCE;
- break;
- }
+bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint)
+ return false;
+ if (mySlvsConstraints.empty())
+ return true;
+ bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
+ if (isFullyRemoved) {
+ myFeatureMap.clear();
+ myAttributeMap.clear();
+ myValueMap.clear();
+ } else
+ cleanRemovedEntities();
+ mySlvsConstraints.clear();
+ return true;
+}
+
+void SketchSolver_Constraint::cleanRemovedEntities()
+{
+ std::set<Slvs_hParam> aRemovedParams;
+ std::set<Slvs_hEntity> aRemovedEntities;
+ std::set<Slvs_hConstraint> aRemovedConstraints;
+ myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
+ while (aFeatIt != myFeatureMap.end()) {
+ if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
+ aFeatIt++;
+ continue;
+ }
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
+ myFeatureMap.erase(aTmpIter);
+ }
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
+ while (anAttrIt != myAttributeMap.end()) {
+ if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
+ anAttrIt++;
+ continue;
+ }
+ std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
+ myAttributeMap.erase(aTmpIter);
+ }
+ std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
+ while (aValIt != myValueMap.end()) {
+ if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
+ aValIt++;
+ continue;
+ }
+ std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
+ myValueMap.erase(aTmpIter);
+ }
+}
+
+void SketchSolver_Constraint::getAttributes(
+ double& theValue,
+ std::vector<Slvs_hEntity>& theAttributes)
+{
+ static const int anInitNbOfAttr = 4;
+ theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
+
+ DataPtr aData = myBaseConstraint->data();
+
+ AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aData->attribute(SketchPlugin_Constraint::VALUE()));
+ theValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+ int aPtInd = 0; // index of first point in the list of attributes
+ int aEntInd = 2; // index of first antity in the list of attributes
+ std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
+ std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
+ for (; anIter != aConstrAttrs.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (!aRefAttr || !aRefAttr->isInitialized()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+
+ int aType = SLVS_E_UNKNOWN; // type of created entity
+ Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
+ if (anEntity == SLVS_E_UNKNOWN)
+ anEntity = changeEntity(aRefAttr, aType);
+ else {
+ Slvs_Entity anEnt = myStorage->getEntity(anEntity);
+ aType = anEnt.type;
+ }
+
+ if (aType == SLVS_E_UNKNOWN)
+ continue;
+ else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
+ theAttributes[aPtInd++] = anEntity; // the point is created
+ else { // another entity (not a point) is created
+ if (aEntInd < anInitNbOfAttr)
+ theAttributes[aEntInd] = anEntity;
+ else
+ theAttributes.push_back(anEntity);
+ aEntInd++;
}
- // Verify the correctness of constraint arguments
- if (aNbPoints == 2 && aNbEntities == 0)
- myType = SLVS_C_PT_PT_DISTANCE;
- else if (aNbPoints != 1 || aNbEntities != 1)
- myType = SLVS_C_UNKNOWN;
- return getType();
}
+}
- // Constraint for the given length of a line
- if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) {
- int aNbLines = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE)
- myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
+{
+ // Convert the object of the attribute to the feature
+ FeaturePtr aFeature;
+ if (theAttribute->isObject() && theAttribute->object()) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ theAttribute->object());
+ if (!aRC) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return SLVS_E_UNKNOWN;
}
- if (aNbLines == 1)
- myType = SLVS_C_PT_PT_DISTANCE;
- return getType();
+ std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+ aFeature = aDoc->feature(aRC);
+
+ return changeEntity(aFeature, theType);
}
- // Constraint for two parallel/perpendicular lines
- bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0);
- bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0);
- if (isParallel || isPerpendicular) {
- int aNbEntities = 2; // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ return changeEntity(theAttribute->attr(), theType);
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
+{
+ Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+ if (!isInitialized(theEntity))
+ return SLVS_E_UNKNOWN;
+
+ // If the entity is already in the group, try to find it
+ std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
+ myAttributeMap.find(theEntity);
+ Slvs_Entity aCurrentEntity;
+ aCurrentEntity.h = SLVS_E_UNKNOWN;
+ if (anEntIter != myAttributeMap.end())
+ aCurrentEntity = myStorage->getEntity(anEntIter->second);
+ else {
+ aResult = myGroup->getAttributeId(theEntity);
+ if (aResult != SLVS_E_UNKNOWN) {
+ Slvs_Entity anEnt = myStorage->getEntity(aResult);
+ theType = anEnt.type;
+ myAttributeMap[theEntity] = aResult;
+ return aResult;
}
- if (aNbEntities == 4)
- myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
- return getType();
}
- // Constraint for radius of a circle or an arc of circle
- if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) {
- int aNbEntities = 2; // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == CIRCLE || aType == ARC)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ Slvs_hGroup aGroupID = myGroup->getId();
+ // Point in 3D
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+ if (aPoint) {
+ double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
+ Slvs_hParam aParams[3];
+ for (int i = 0; i < 3; i++) {
+ Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+ myStorage->getParameter(aCurrentEntity.param[i]) :
+ Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+ aPar.val = aXYZ[i];
+ aParams[i] = myStorage->addParameter(aPar);
+ }
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
+ else { // update entity data
+ for (int i = 0; i < 3; i++)
+ aCurrentEntity.param[i] = aParams[i];
+ }
+ aResult = myStorage->addEntity(aCurrentEntity);
+ } else {
+ // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
+ Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+ if (aWorkplaneID == SLVS_E_UNKNOWN)
+ return SLVS_E_UNKNOWN;
+
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+ if (aPoint2D) {
+ double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
+ Slvs_hParam aParams[2];
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+ myStorage->getParameter(aCurrentEntity.param[i]) :
+ Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+ aPar.val = aXY[i];
+ aParams[i] = myStorage->addParameter(aPar);
+ }
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
+ else { // update entity data
+ for (int i = 0; i < 2; i++)
+ aCurrentEntity.param[i] = aParams[i];
+ }
+ aResult = myStorage->addEntity(aCurrentEntity);
+ } else {
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+ if (aScalar) {
+ Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+ myStorage->getParameter(aCurrentEntity.param[0]) :
+ Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+ aParam.val = aScalar->value();
+ Slvs_hParam aValue = myStorage->addParameter(aParam);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
+ else
+ aCurrentEntity.param[0] = aValue;
+ aResult = myStorage->addEntity(aCurrentEntity);
+ }
}
- if (aNbEntities == 3)
- myType = SLVS_C_DIAMETER;
- return getType();
}
- // Constraint for fixed entity
- if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) {
- // Verify that only one entity is filled
- int aNbAttrs = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType != UNKNOWN)
- myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ myAttributeMap[theEntity] = aResult;
+ theType = aCurrentEntity.type;
+ return aResult;
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
+{
+ Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+ if (!theEntity->data() || !theEntity->data()->isValid())
+ return SLVS_E_UNKNOWN;
+ // If the entity is already in the group, try to find it
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
+ Slvs_Entity aCurrentEntity;
+ aCurrentEntity.h = SLVS_E_UNKNOWN;
+ if (anEntIter != myFeatureMap.end())
+ aCurrentEntity = myStorage->getEntity(anEntIter->second);
+ else {
+ aResult = myGroup->getFeatureId(theEntity);
+ if (aResult != SLVS_E_UNKNOWN) {
+ Slvs_Entity anEnt = myStorage->getEntity(aResult);
+ theType = anEnt.type;
+ myFeatureMap[theEntity] = aResult;
+ return aResult;
}
- if (aNbAttrs == 1)
- myType = SLVS_C_WHERE_DRAGGED;
- return getType();
}
- // Constraint for horizontal/vertical line
- bool isHorizontal = (aConstraintKind.compare(SketchPlugin_ConstraintHorizontal::ID()) == 0);
- bool isVertical = (aConstraintKind.compare(SketchPlugin_ConstraintVertical::ID()) == 0);
- if (isHorizontal || isVertical) {
- int aNbEntities = 2; // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ Slvs_hGroup aGroupID = myGroup->getId();
+ Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+ DataPtr aData = theEntity->data();
+
+ // SketchPlugin features
+ const std::string& aFeatureKind = theEntity->getKind();
+ AttributePtr anAttribute;
+ int anAttrType;
+ // Line
+ if (aFeatureKind == SketchPlugin_Line::ID()) {
+ anAttribute = aData->attribute(SketchPlugin_Line::START_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+ anAttribute = aData->attribute(SketchPlugin_Line::END_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
+ else {
+ aCurrentEntity.point[0] = aStart;
+ aCurrentEntity.point[1] = aEnd;
}
- if (aNbEntities == 3)
- myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL;
- return getType();
+ aResult = myStorage->addEntity(aCurrentEntity);
}
+ // Circle
+ else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+ anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
- if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) {
- static const int aConstrType[3] = {
- SLVS_C_EQUAL_RADIUS,
- SLVS_C_EQUAL_LINE_ARC_LEN,
- SLVS_C_EQUAL_LENGTH_LINES
- };
- int aNbLines = 0;
- int aNbEntities = 2; // lines and circles in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == LINE) {
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- aNbLines++;
- }
- else if (aType == CIRCLE || aType == ARC)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+ Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+ aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+ aCenter, aWorkplane.normal, aRadius);
+ } else {
+ aCurrentEntity.point[0] = aCenter;
+ aCurrentEntity.distance = aRadius;
}
- if (aNbEntities == 4)
- myType = aConstrType[aNbLines];
- return getType();
+ aResult = myStorage->addEntity(aCurrentEntity);
}
+ // Arc
+ else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+ anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
- if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) {
- static const int anArcPosDefault = 2;
- static const int aLinePosDefault = 3;
- int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line
- int aLinePos = aLinePosDefault;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE)
- myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- else if (aType == ARC)
- myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ anAttribute = aData->attribute(SketchPlugin_Arc::START_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+ anAttribute = aData->attribute(SketchPlugin_Arc::END_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+ Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+ aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+ aWorkplane.normal, aCenter, aStart, aEnd);
+ } else {
+ aCurrentEntity.point[0] = aCenter;
+ aCurrentEntity.point[1] = aStart;
+ aCurrentEntity.point[2] = aEnd;
}
- if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2)
- myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT;
- return getType();
+ aResult = myStorage->addEntity(aCurrentEntity);
+ }
+ // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+ else if (aFeatureKind == SketchPlugin_Point::ID()) {
+ anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID());
+ if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+ // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+ aResult = changeEntity(anAttribute, anAttrType);
+ aCurrentEntity.type = SLVS_E_POINT_IN_3D;
}
- if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) {
- int aNbAttrs = 0;
- bool hasMirrorLine = false;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
- if (anAttrRefList) {
- aNbAttrs++;
- myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ if (aResult != SLVS_E_UNKNOWN) {
+ myFeatureMap[theEntity] = aResult;
+ theType = aCurrentEntity.type;
+ }
+ return aResult;
+}
+
+std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
+{
+ std::list<ConstraintPtr> aConstraints;
+ aConstraints.push_back(myBaseConstraint);
+ return aConstraints;
+}
+
+void SketchSolver_Constraint::refresh()
+{
+ cleanErrorMsg();
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+ for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
+ if (aPoint) {
+ Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+ double aXYZ[3];
+ for (int i = 0; i < 3; i++) {
+ Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+ aXYZ[i] = aPar.val;
}
- else {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE) {
- hasMirrorLine = !hasMirrorLine;
- myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ if (fabs(aPoint->x() - aXYZ[0]) > tolerance ||
+ fabs(aPoint->y() - aXYZ[1]) > tolerance ||
+ fabs(aPoint->z() - aXYZ[2]) > tolerance)
+ aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
+ } else {
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
+ if (aPoint2D) {
+ Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+ double aXY[2];
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+ aXY[i] = aPar.val;
+ }
+ if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
+ fabs(aPoint2D->y() - aXY[1]) > tolerance)
+ aPoint2D->setValue(aXY[0], aXY[1]);
+ } else {
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+ if (aScalar) {
+ Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+ Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
+ if (fabs(aScalar->value() - aPar.val) > tolerance)
+ aScalar->setValue(aPar.val);
}
}
}
- if (aNbAttrs == 2 && hasMirrorLine)
- myType = SLVS_C_SYMMETRIC_LINE;
- return getType();
}
- if (aConstraintKind.compare(SketchPlugin_ConstraintFillet::ID()) == 0) {
- int aNbAttrs = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
- if (anAttrRefList)
- myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- else {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == LINE || aType == ARC)
- myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- }
+ std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
+ for (; aValIter != myValueMap.end(); aValIter++) {
+ AttributeDoublePtr aScalar =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+ if (aScalar) {
+ Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
+ aScalar->setValue(aPar.val);
}
- if (aNbAttrs == 3)
- myType = SLVS_C_FILLET;
- return getType();
}
+}
- /// \todo Implement other kind of constraints
+Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
+{
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
+ if (aFIter == myFeatureMap.end())
+ return SLVS_E_UNKNOWN;
+ return aFIter->second;
+}
+
+Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
+{
+ std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
+ if (anAttrIter == myAttributeMap.end())
+ return SLVS_E_UNKNOWN;
+ return anAttrIter->second;
+}
- return getType();
+bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute)
+{
+ if (theAttribute->isInitialized())
+ return true;
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return false;
}
-// ================= Auxiliary functions ==============================
-AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute)
+
+void SketchSolver_Constraint::calculateMiddlePoint(
+ const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const
{
- std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(theAttribute);
- if (!anAttrRef)
- return UNKNOWN;
+ if (theEntity.type == SLVS_E_LINE_SEGMENT) {
+ double aStartEndXY[2][2];
+ Slvs_Entity aPoint;
+ for (int i = 0; i < 2; i++) {
+ aPoint = myStorage->getEntity(theEntity.point[i]);
+ for (int j = 0; j < 2; j++)
+ aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val;
+ }
+ theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0];
+ theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1];
+ } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) {
+ double anArcPoint[3][2];
+ Slvs_Entity aPoint;
+ for (int i = 0; i < 3; i++) {
+ aPoint = myStorage->getEntity(theEntity.point[i]);
+ for (int j = 0; j < 2; j++)
+ anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val;
+ }
+ // project last point of arc on the arc
+ double x = anArcPoint[1][0] - anArcPoint[0][0];
+ double y = anArcPoint[1][1] - anArcPoint[0][1];
+ double aRad = sqrt(x*x + y*y);
+ x = anArcPoint[2][0] - anArcPoint[0][0];
+ y = anArcPoint[2][1] - anArcPoint[0][1];
+ double aNorm = sqrt(x*x + y*y);
+ if (aNorm >= tolerance) {
+ anArcPoint[2][0] = x * aRad / aNorm;
+ anArcPoint[2][1] = y * aRad / aNorm;
+ }
+ anArcPoint[1][0] -= anArcPoint[0][0];
+ anArcPoint[1][1] -= anArcPoint[0][1];
+ if (theCoeff < tolerance) {
+ theX = anArcPoint[0][0] + anArcPoint[1][0];
+ theY = anArcPoint[0][1] + anArcPoint[1][1];
+ return;
+ } else if (1 - theCoeff < tolerance) {
+ theX = anArcPoint[0][0] + anArcPoint[2][0];
+ theY = anArcPoint[0][1] + anArcPoint[2][1];
+ return;
+ }
- if (anAttrRef->isObject()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- anAttrRef->object());
- if (!aRC || !aRC->shape())
- return UNKNOWN;
-
- if (aRC->shape()->isVertex())
- return POINT3D;
- else if (aRC->shape()->isEdge()) {
- std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
- aRC->shape());
- if (anEdge->isLine())
- return LINE;
- else if (anEdge->isCircle())
- return CIRCLE;
- else if (anEdge->isArc())
- return ARC;
+ double xStart = anArcPoint[1][0] / aRad, xEnd = anArcPoint[2][0] / aRad;
+ double yStart = anArcPoint[1][1] / aRad, yEnd = anArcPoint[2][1] / aRad;
+ if (anArcPoint[1][0] * anArcPoint[2][0] < 0.0) {
+ if (anArcPoint[1][0] > 0.0)
+ yEnd = 2.0 - yEnd;
+ else
+ yStart = -2.0 - yStart;
+ } else {
+ if (yStart > yEnd) {
+ yStart = 2.0 - yStart;
+ yEnd = -2.0 - yEnd;
+ } else {
+ yStart = -2.0 - yStart;
+ yEnd = 2.0 - yEnd;
+ }
}
- } else {
- if (anAttrRef->attr().get() != NULL) {
- const std::string aType = anAttrRef->attr()->attributeType();
- if (aType == GeomDataAPI_Point2D::typeId())
- return POINT2D;
- if (aType == GeomDataAPI_Point2D::typeId())
- return POINT2D;
+ if (anArcPoint[1][1] * anArcPoint[2][1] < 0.0) {
+ if (anArcPoint[1][1] > 0.0)
+ xEnd = 2.0 - xEnd;
+ else
+ xStart = -2.0 - xStart;
+ } else {
+ if (xStart > xEnd) {
+ xStart = 2.0 - xStart;
+ xEnd = -2.0 - xEnd;
+ } else {
+ xStart = -2.0 - xStart;
+ xEnd = 2.0 - xEnd;
+ }
}
- }
+ x = (1.0 - theCoeff) * xStart + theCoeff * xEnd;
+ y = (1.0 - theCoeff) * yStart + theCoeff * yEnd;
+ if (x > 1.0) x = 2.0 - x;
+ if (x < -1.0) x = -2.0 - x;
+ if (y > 1.0) y = 2.0 - y;
+ if (y < -1.0) y = -2.0 - y;
- return UNKNOWN;
+ aNorm = sqrt(x*x + y*y);
+ if (aNorm >= tolerance) {
+ x *= aRad / aNorm;
+ y *= aRad / aNorm;
+ } else {
+ x = -0.5 * (anArcPoint[2][1] + anArcPoint[1][1]);
+ y = -0.5 * (anArcPoint[2][0] + anArcPoint[1][0]);
+ }
+ theX = anArcPoint[0][0] + x;
+ theY = anArcPoint[0][1] + y;
+ }
}
#define SketchSolver_Constraint_H_
#include "SketchSolver.h"
+#include <SketchSolver_Storage.h>
#include <SketchPlugin_Constraint.h>
+#include <ModelAPI_AttributeRefAttr.h>
+
#include <string>
#include <vector>
+class SketchSolver_Group;
+
/** \class SketchSolver_Constraint
* \ingroup Plugins
- * \brief Obtain information about SketchPlugin's constraint
+ * \brief Stores mapping between SketchPlugin and SolveSpace constraints data
*/
class SketchSolver_Constraint
{
-public:
+protected:
/// Default constructor
- SketchSolver_Constraint();
- /// Creates constraint to manage the given constraint from plugin
- SketchSolver_Constraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \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 or SLVS_C_UNKNOWN if the type is wrong
- */
- const int& getType(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /// \brief Returns the type of myConstraint member
- inline const int& getType() const
- {
- return myType;
- }
+ SketchSolver_Constraint() {}
+ SketchSolver_Constraint(ConstraintPtr theConstraint);
+
+public:
+ virtual ~SketchSolver_Constraint();
+
+ /// \brief Initializes the storage of SolveSpace constraints
+ void setStorage(StoragePtr theStorage);
+ /// \brief Initializes group ID for this constraint
+ void setGroup(SketchSolver_Group* theGroup);
+
+ /// \brief Update constraint
+ virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
+ void refresh();
+
+ /// \brief Returns the type of constraint
+ virtual int getType() const = 0;
+
+ /// \brief Checks the constraint is used by current object
+ virtual bool hasConstraint(ConstraintPtr theConstraint) const
+ { return theConstraint == myBaseConstraint; }
+
+ /// \brief Return list of SketchPlugin constraints attached to this object
+ virtual std::list<ConstraintPtr> constraints() const;
+
+ /// \brief Return identifier of SolveSpace entity relating to the feature
+ Slvs_hEntity getId(FeaturePtr theFeature) const;
+ /// \brief Return identifier of SolveSpace entity relating to the attribute
+ Slvs_hEntity getId(AttributePtr theAttribute) const;
+
+ /// \brief Shows error message
+ const std::string& error() const
+ { return myErrorMsg; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+ /// \brief This method is used in derived objects to check consistence of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint()
+ {}
+
+ /// \brief Create or change SlveSpace entity according to the given attribute
+ /// \param[in] theAttribute reference to the entity to be changed
+ /// \param[out] theType type of created entity
+ /// \return identifier of created/updated entity
+ Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType);
+ /// \brief Create or change SlveSpace entity according to the given attribute
+ Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType);
+ /// \brief Create or change SlveSpace entity according to the given feature
+ Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType);
+
+ /// \brief Calculate middle point on the specified entity
+ /// \param[in] theEntity arc or line
+ /// \param[in] theCoeff is a value in [0.0, 1.0] which shows the position of the point on the entity (0.0 - start point, 1.0 - end point)
+ /// \param[out] theX X coordinate of middle point
+ /// \param[out] theY Y coordinate of middle point
+ void calculateMiddlePoint(const Slvs_Entity& theEntity, double theCoeff,
+ double& theX, double& theY) const;
+
+ /// \brief Removes the links to unused entities
+ void cleanRemovedEntities();
+
+ /// \brief Removes last error
+ void cleanErrorMsg()
+ { myErrorMsg.clear(); }
+
+private:
+ /// \brief Sets error, if the attribute is not initialized
+ bool isInitialized(AttributePtr theAttribute);
+
+protected:
+ SketchSolver_Group* myGroup; ///< the group which contains current constraint
+ ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint
+ std::vector<Slvs_hConstraint> mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint
+ std::map<FeaturePtr, Slvs_hEntity> myFeatureMap; ///< map feature to the entity it represents
+ std::map<AttributePtr, Slvs_hEntity> myAttributeMap; ///< map attribute to the corresponding entity
+ std::map<AttributePtr, Slvs_hParam> myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint
+ StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group
+
+ std::string myErrorMsg; ///< error message
+};
+
+typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
+
+
+
+/** \class SketchSolver_ConstraintParallel
+ * \ingroup Plugins
+ * \brief Convert Parallel constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintParallel : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
- /// \brief Returns list of attributes names in the correct order required by SolveSpace
- inline const std::vector<std::string>& getAttributes() const
+ virtual int getType() const
+ { return SLVS_C_PARALLEL; }
+};
+
+
+/** \class SketchSolver_ConstraintPerpendicular
+ * \ingroup Plugins
+ * \brief Convert Perpendicular constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_PERPENDICULAR; }
+};
+
+
+/** \class SketchSolver_ConstraintHorizontal
+ * \ingroup Plugins
+ * \brief Convert Horizontal constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_HORIZONTAL; }
+};
+
+
+/** \class SketchSolver_ConstraintVertical
+ * \ingroup Plugins
+ * \brief Convert Vertical constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintVertical : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_VERTICAL; }
+};
+
+
+/** \class SketchSolver_ConstraintRadius
+ * \ingroup Plugins
+ * \brief Convert Radius constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintRadius : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintRadius(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_DIAMETER; }
+
+ virtual void adjustConstraint()
{
- return myAttributesList;
+ Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
+ aConstraint.valA *= 2.0;
+ myStorage->updateConstraint(aConstraint);
}
-
- private:
- std::shared_ptr<SketchPlugin_Constraint> myConstraint;
- int myType;
- std::vector<std::string> myAttributesList;
};
#endif
--- /dev/null
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <map>
+
+bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
+{
+ if (myBaseConstraint == theConstraint)
+ return true;
+ std::map<Slvs_hConstraint, ConstraintPtr>::const_iterator anIt = myExtraCoincidence.begin();
+ for (; anIt != myExtraCoincidence.end(); anIt++)
+ if (anIt->second == theConstraint)
+ return true;
+ return false;
+}
+
+std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
+{
+ std::list<ConstraintPtr> aConstraints;
+ aConstraints.push_back(myBaseConstraint);
+ std::map<Slvs_hConstraint, ConstraintPtr>::const_iterator anIt = myExtraCoincidence.begin();
+ for (; anIt != myExtraCoincidence.end(); anIt++)
+ aConstraints.push_back(anIt->second);
+ return aConstraints;
+}
+
+bool SketchSolver_ConstraintCoincidence::isCoincide(
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
+{
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatIter = myFeatureMap.begin();
+ for (; aFeatIter != myFeatureMap.end(); aFeatIter++)
+ if (theConstraint->myFeatureMap.find(aFeatIter->first) != theConstraint->myFeatureMap.end())
+ return true;
+ std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.begin();
+ for (; anAttrIter != myAttributeMap.end(); anAttrIter++)
+ if (theConstraint->myAttributeMap.find(anAttrIter->first) != theConstraint->myAttributeMap.end())
+ return true;
+ return false;
+}
+
+void SketchSolver_ConstraintCoincidence::attach(
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
+{
+ cleanErrorMsg();
+ Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+ // Remove constraints from theConstraint
+ std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
+ for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
+ theConstraint->myStorage->removeConstraint(*aCIter);
+
+ if (myStorage == theConstraint->myStorage) {
+ // Clean removed items
+ std::set<Slvs_hParam> aRemParams;
+ std::set<Slvs_hEntity> aRemEnts;
+ std::set<Slvs_hConstraint> aRemConstr;
+ theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
+ }
+
+ // Copy data.
+ addConstraint(theConstraint->myBaseConstraint);
+ std::map<Slvs_hConstraint, ConstraintPtr>::iterator aConstrIter =
+ theConstraint->myExtraCoincidence.begin();
+ for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
+ addConstraint(aConstrIter->second);
+ // Clear the lists to not remove the entities on destruction
+ theConstraint->mySlvsConstraints.clear();
+ theConstraint->myFeatureMap.clear();
+ theConstraint->myAttributeMap.clear();
+}
+
+Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
+ Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
+{
+ Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
+ SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2,
+ SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
+ mySlvsConstraints.push_back(aNewID);
+ return aNewID;
+}
+
+void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
+{
+ std::list<AttributePtr> anAttrList =
+ theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+ std::list<AttributePtr>::iterator anIter = anAttrList.begin();
+ std::vector<Slvs_hEntity> anEntities;
+ for (; anIter != anAttrList.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (!aRefAttr || aRefAttr->isObject() ||
+ myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end())
+ continue;
+ int aType;
+ Slvs_hEntity anEntityID = myGroup->getAttributeId(aRefAttr->attr());
+ if (anEntityID == SLVS_E_UNKNOWN)
+ anEntityID = changeEntity(aRefAttr->attr(), aType);
+ anEntities.push_back(anEntityID);
+ }
+
+ Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+ Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
+ std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++)
+ aNewConstr = addConstraint(aBaseCoincidence.ptA, *anEntIter);
+ myExtraCoincidence[aNewConstr] = theConstraint;
+}
+
+bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (mySlvsConstraints.empty())
+ return true;
+ ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
+ int aPos = -1; // position of constraint in the list (-1 for base constraint)
+ std::map<Slvs_hConstraint, ConstraintPtr>::iterator anExtraIt;
+ if (aConstraint != myBaseConstraint) {
+ anExtraIt = myExtraCoincidence.begin();
+ for (aPos = 0; anExtraIt != myExtraCoincidence.end(); anExtraIt++, aPos++)
+ if (anExtraIt->second == aConstraint)
+ break;
+ if (aPos >= (int)myExtraCoincidence.size())
+ return false; // there is no constraint, which is specified to remove
+ else {
+ bool isEmpty = anExtraIt->first == SLVS_E_UNKNOWN;
+ myExtraCoincidence.erase(anExtraIt);
+ if (isEmpty)
+ return false;
+ }
+ }
+
+ bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
+ mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
+ if (aPos < 0 && !myExtraCoincidence.empty()) {
+ anExtraIt = myExtraCoincidence.begin();
+ // Remove invalid constraints
+ while (anExtraIt != myExtraCoincidence.end()) {
+ if (!anExtraIt->second->data() || !anExtraIt->second->data()->isValid()) {
+ std::map<Slvs_hConstraint, ConstraintPtr>::iterator aTempIt = anExtraIt++;
+ if (aTempIt->first != SLVS_E_UNKNOWN) {
+ myStorage->removeConstraint(aTempIt->first);
+ std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
+ for (; anIt != mySlvsConstraints.end(); anIt++)
+ if (*anIt == aTempIt->first) {
+ mySlvsConstraints.erase(anIt);
+ break;
+ }
+ }
+ myExtraCoincidence.erase(aTempIt);
+ continue;
+ }
+ anExtraIt++;
+ }
+ // Find first non-extra conststraint
+ while (anExtraIt != myExtraCoincidence.end() && anExtraIt->first == SLVS_E_UNKNOWN)
+ anExtraIt++;
+ if (anExtraIt != myExtraCoincidence.end()) {
+ // Need to specify another base coincidence constraint
+ myBaseConstraint = anExtraIt->second;
+ myExtraCoincidence.erase(anExtraIt);
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
+ for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
+ Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
+ aConstr.ptA = aBase.ptA;
+ myStorage->updateConstraint(aConstr);
+ }
+ }
+ }
+ // Clear removed attributes
+ std::set<Slvs_hParam> aParamRemoved;
+ std::set<Slvs_hEntity> anEntRemoved;
+ std::set<Slvs_hConstraint> aConstrRemoved;
+ myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+ while (anAttrIter != myAttributeMap.end()) {
+ if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
+ std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
+ myAttributeMap.erase(aTempIt);
+ continue;
+ }
+ anAttrIter++;
+ }
+
+ // Go through remaining extra coincidence and try to add or remove them
+ anExtraIt = myExtraCoincidence.begin();
+ while (anExtraIt != myExtraCoincidence.end()) {
+ if (anExtraIt->first == SLVS_E_UNKNOWN) {
+ if (!anExtraIt->second->data() || !anExtraIt->second->data()->isValid()) {
+ std::map<Slvs_hConstraint, ConstraintPtr>::iterator aTempIt = anExtraIt++;
+ myExtraCoincidence.erase(aTempIt);
+ continue;
+ }
+ if (mySlvsConstraints.empty()) {
+ myBaseConstraint = anExtraIt->second;
+ std::map<Slvs_hConstraint, ConstraintPtr>::iterator aTempIt = anExtraIt++;
+ myExtraCoincidence.erase(aTempIt);
+ process();
+ continue;
+ } else
+ addConstraint(anExtraIt->second);
+ }
+ anExtraIt++;
+ }
+ return isFullyRemoved;
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintCoincidence.h
+// Created: 29 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintCoincidence_H_
+#define SketchSolver_ConstraintCoincidence_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+
+/** \class SketchSolver_ConstraintCoincidence
+ * \ingroup Plugins
+ * \brief Convert coincidence constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_POINTS_COINCIDENT; }
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Checks the constraint is used by current object
+ virtual bool hasConstraint(ConstraintPtr theConstraint) const;
+
+ /// \brief Return list of SketchPlugin constraints attached to this object
+ virtual std::list<ConstraintPtr> constraints() const;
+
+ /// \brief Verifies the two Coincidence constraints are intersects (have shared point)
+ bool isCoincide(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const;
+
+ /// \brief Append all data of coincidence constaint to the current
+ void attach(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint);
+
+private:
+ /// \brief Creates new coincidence constraint
+ Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2);
+
+ /// \brief Create full SolveSpace structure according to given constraint
+ void addConstraint(ConstraintPtr theConstraint);
+
+private:
+ std::map<Slvs_hConstraint, ConstraintPtr> myExtraCoincidence; ///< multiple coincidence of points
+};
+
+#endif
--- /dev/null
+#include <SketchSolver_ConstraintDistance.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+#include <GeomAPI_XY.h>
+
+
+void SketchSolver_ConstraintDistance::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntities;
+ getAttributes(aValue, anEntities);
+ if (!myErrorMsg.empty())
+ return;
+
+ // Obtain entities to identify the type of distance
+ static const int aNbPoints = 2;
+ Slvs_hEntity aPoint[aNbPoints] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
+ Slvs_hEntity aLine = SLVS_E_UNKNOWN;
+ myType = SLVS_C_PT_PT_DISTANCE;
+ int aPtPos = 0;
+ std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++) {
+ if (*anEntIter == SLVS_E_UNKNOWN)
+ continue;
+ Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
+ if (anEnt.type == SLVS_E_POINT_IN_2D || anEnt.type == SLVS_E_POINT_IN_3D) {
+ if (aPtPos >= aNbPoints) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
+ }
+ aPoint[aPtPos++] = *anEntIter;
+ }
+ else if (anEnt.type == SLVS_E_LINE_SEGMENT) {
+ if (myType == SLVS_C_PT_LINE_DISTANCE) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
+ }
+ aLine = *anEntIter;
+ myType = SLVS_C_PT_LINE_DISTANCE;
+ }
+ }
+
+ Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+ getType(), myGroup->getWorkplaneId(), aValue, aPoint[0], aPoint[1], aLine, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ adjustConstraint();
+}
+
+void SketchSolver_ConstraintDistance::adjustConstraint()
+{
+ if (getType() != SLVS_C_PT_LINE_DISTANCE)
+ return;
+
+ // Get constraint parameters and check the sign of constraint value
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++) {
+ Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
+ Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA);
+ // Obtain point and line coordinates
+ Slvs_hEntity aPointID[3] = {aConstraint.ptA, aLine.point[0], aLine.point[1]};
+ std::shared_ptr<GeomAPI_XY> aPoints[3];
+ for (int i = 0; i < 3; i++) {
+ Slvs_Entity aPoint = myStorage->getEntity(aPointID[i]);
+ Slvs_Param aParams[2] = {
+ myStorage->getParameter(aPoint.param[0]),
+ myStorage->getParameter(aPoint.param[1])};
+ aPoints[i] = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aParams[0].val, aParams[1].val));
+ }
+ std::shared_ptr<GeomAPI_XY> aLineVec = aPoints[2]->decreased(aPoints[1]);
+ std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoints[0]->decreased(aPoints[1]);
+ if (aPtLineVec->cross(aLineVec) * aConstraint.valA < 0.0) {
+ aConstraint.valA *= -1.0;
+ myStorage->updateConstraint(aConstraint);
+ }
+ }
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintDistance.h
+// Created: 31 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintDistance_H_
+#define SketchSolver_ConstraintDistance_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintDistance
+ * \ingroup Plugins
+ * \brief Convert distance constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintDistance : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint), myType(SLVS_C_UNKNOWN)
+ {}
+
+ virtual int getType() const
+ {return myType; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Verifies the sign of the distance between line and point and change it if necessary
+ virtual void adjustConstraint();
+
+private:
+ int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE)
+};
+
+#endif
--- /dev/null
+#include <SketchSolver_ConstraintEqual.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+
+void SketchSolver_ConstraintEqual::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntities;
+ getAttributes(aValue, anEntities);
+ if (!myErrorMsg.empty())
+ return;
+
+ // Check the quantity of entities of each type
+ int aNbLines = 0;
+ int aNbArcs = 0;
+ int aNbCircs = 0;
+ bool isArcFirst = false; // in line-arc equivalence, the line should be first
+ std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++) {
+ Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
+ if (anEnt.type == SLVS_E_LINE_SEGMENT)
+ aNbLines++;
+ else if (anEnt.type == SLVS_E_CIRCLE)
+ aNbCircs++;
+ else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
+ aNbArcs++;
+ isArcFirst = (aNbLines == 0);
+ }
+ }
+
+ if (aNbLines + aNbArcs + aNbCircs != 2 ||
+ (aNbLines == aNbCircs && aNbArcs == 0)) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
+ }
+
+ switch (aNbLines) {
+ case 0:
+ myType = SLVS_C_EQUAL_RADIUS;
+ break;
+ case 1:
+ myType = SLVS_C_EQUAL_LINE_ARC_LEN;
+ if (isArcFirst) { // change the order of arc and line
+ Slvs_hEntity aTmp = anEntities[2];
+ anEntities[2] = anEntities[3];
+ anEntities[3] = aTmp;
+ }
+ break;
+ default:
+ myType = SLVS_C_EQUAL_LENGTH_LINES;
+ break;
+ }
+
+ Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+ getType(), myGroup->getWorkplaneId(), aValue,
+ anEntities[0], anEntities[1], anEntities[2], anEntities[3]);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ adjustConstraint();
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintEqual.h
+// Created: 1 Apr 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintEqual_H_
+#define SketchSolver_ConstraintEqual_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintEqual
+ * \ingroup Plugins
+ * \brief Convert equality constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintEqual : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintEqual(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return myType; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+private:
+ int myType; ///< type of constraint (applicable: SLVS_C_EQUAL_LENGTH_LINES, SLVS_C_EQUAL_RADIUS, SLVS_C_EQUAL_LINE_ARC_LEN)
+};
+
+#endif
--- /dev/null
+#include <SketchSolver_ConstraintFillet.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+
+void SketchSolver_ConstraintFillet::getAttributes(
+ double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+{
+ theAttributes.clear();
+
+ DataPtr aData = myBaseConstraint->data();
+ AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aData->attribute(SketchPlugin_Constraint::VALUE()));
+ theValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+ std::list<AttributePtr> aBaseAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
+ std::list<AttributePtr>::iterator anIter = aBaseAttrs.begin();
+ for (; anIter != aBaseAttrs.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (!aRefAttr || !aRefAttr->isInitialized()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+
+ int aType = SLVS_E_UNKNOWN; // type of created entity
+ Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
+ if (anEntity == SLVS_E_UNKNOWN)
+ anEntity = changeEntity(aRefAttr, aType);
+
+ if (aType == SLVS_E_UNKNOWN)
+ continue;
+ theAttributes.push_back(anEntity);
+ }
+
+ // Fillet objects
+ AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
+ if (!aFilletRefList || !aFilletRefList->isInitialized()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ std::list<ObjectPtr> aFilletList = aFilletRefList->list();
+ if (aFilletList.size() < theAttributes.size() + 1) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ FeaturePtr aFilletFeature;
+ ResultConstructionPtr aRC;
+ int aType;
+ std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
+ for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
+ aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
+ aFilletFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
+ if (!aFilletFeature) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ Slvs_hEntity anEntity = changeEntity(aFilletFeature, aType);
+ theAttributes.push_back(anEntity);
+ }
+}
+
+void SketchSolver_ConstraintFillet::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntID;
+ getAttributes(aValue, anEntID);
+ if (!myErrorMsg.empty())
+ return;
+
+ // Obtain the entities itself:
+ // First two are base entities
+ // Second two are trimmed them
+ // Last one is a fillet arc
+ std::vector<Slvs_Entity> anEntities;
+ std::vector<Slvs_hEntity>::iterator anIt = anEntID.begin();
+ for (; anIt != anEntID.end(); anIt++)
+ anEntities.push_back(myStorage->getEntity(*anIt));
+
+ // Check the base entities have a coincident point
+ Slvs_hEntity aPointsToFind[4];
+ for (int i = 0; i < 2; i++) {
+ int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+ aPointsToFind[2*i] = anEntities[i].point[aShift];
+ aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
+ }
+ // Search coincident points
+ int aCoincInd[2]; // indices of coincident points on each entity (0 - first, 1 - last)
+ bool isPointFound = false;
+ for (int i = 0; i < 2 && !isPointFound; i++)
+ for (int j = 2; j < 4 && !isPointFound; j++)
+ if (myStorage->isCoincident(aPointsToFind[i], aPointsToFind[j])) {
+ aCoincInd[0] = i;
+ aCoincInd[1] = j - 2;
+ isPointFound = true;
+ }
+ if (!isPointFound) {
+ // There is no coincident points between tangential objects. Generate error message
+ myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+ return;
+ }
+
+ // For correct result, move floating points of fillet on the middle points of base objects
+ Slvs_Entity aPoint;
+ Slvs_Param aParam;
+ double anArcPoints[3][2];
+ for (int i = 0; i < 2; i++) {
+ calculateMiddlePoint(anEntities[i], 0.1 + 0.8 * aCoincInd[i], anArcPoints[i+1][0], anArcPoints[i+1][1]);
+ aPoint = myStorage->getEntity(anEntities[i+2].point[aCoincInd[i]]);
+ for (int j = 0; j < 2; j++) {
+ aParam = myStorage->getParameter(aPoint.param[j]);
+ aParam.val = anArcPoints[i+1][j];
+ aPoint.param[j] = myStorage->updateParameter(aParam);
+ }
+ }
+ anArcPoints[0][0] = 0.5 * (anArcPoints[1][0] + anArcPoints[2][0]);
+ anArcPoints[0][1] = 0.5 * (anArcPoints[1][1] + anArcPoints[2][1]);
+ // Check the arc is need to be reversed
+ double aSharedPoint[2];
+ aPoint = myStorage->getEntity(aPointsToFind[aCoincInd[0]]);
+ for (int j = 0; j < 2; j++)
+ aSharedPoint[j] = myStorage->getParameter(aPoint.param[j]).val;
+ double aCross = (anArcPoints[1][0] - anArcPoints[0][0]) * (aSharedPoint[1] - anArcPoints[0][1]) -
+ (anArcPoints[1][1] - anArcPoints[0][1]) * (aSharedPoint[0] - anArcPoints[0][0]);
+ if (aCross < 0.0) { // reverse fillet arc
+ double aTmp;
+ for (int j = 0; j < 2; j++) {
+ aTmp = anArcPoints[1][j];
+ anArcPoints[1][j] = anArcPoints[2][j];
+ anArcPoints[2][j] = aTmp;
+ }
+ }
+ // update fillet arc coordinates
+ for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
+ aPoint = myStorage->getEntity(anEntities.back().point[indArcPt]);
+ for (int j = 0; j < 2; j++) {
+ aParam = myStorage->getParameter(aPoint.param[j]);
+ aParam.val = anArcPoints[indArcPt][j];
+ aPoint.param[j] = myStorage->updateParameter(aParam);
+ }
+ }
+
+ for (int indEnt = 0; indEnt < 2; indEnt++) {
+ int aShift = anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+ // one point of fillet object should be coincident with the point on base, non-coincident with another base object
+ Slvs_hEntity aBaseID = anEntities[indEnt].point[1 - aCoincInd[indEnt] + aShift];
+ Slvs_hEntity aFilletID = anEntities[2 + indEnt].point[1 - aCoincInd[indEnt] + aShift];
+ Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
+ 0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aCoincConstr.h = myStorage->addConstraint(aCoincConstr);
+ mySlvsConstraints.push_back(aCoincConstr.h);
+
+ // another point of fillet object should be placed on the base object
+ Slvs_Constraint aPonCurveConstr;
+ if (anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE) {
+ // centers of arcs should be coincident
+ aBaseID = anEntities[indEnt].point[0];
+ aFilletID = anEntities[2 + indEnt].point[0];
+ aPonCurveConstr = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
+ 0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ } else {
+ aFilletID = anEntities[2 + indEnt].point[aCoincInd[indEnt]];
+ aPonCurveConstr = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(),
+ 0.0, aFilletID, SLVS_E_UNKNOWN, anEntities[indEnt].h, SLVS_E_UNKNOWN);
+ }
+ aPonCurveConstr.h = myStorage->addConstraint(aPonCurveConstr);
+ mySlvsConstraints.push_back(aPonCurveConstr.h);
+ }
+}
+
+bool SketchSolver_ConstraintFillet::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint)
+ return false;
+ bool isFullyRemoved = true;
+ std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++)
+ isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+ mySlvsConstraints.clear();
+
+ if (isFullyRemoved) {
+ myFeatureMap.clear();
+ myAttributeMap.clear();
+ myValueMap.clear();
+ } else
+ cleanRemovedEntities();
+ return true;
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintFillet.h
+// Created: 1 Apr 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintFillet_H_
+#define SketchSolver_ConstraintFillet_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintFillet
+ * \ingroup Plugins
+ * \brief Convert fillet constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintFillet : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintFillet(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_FILLET; }
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ ///
+ /// Parameter theAttributes contains 5 elements:
+ /// Two first entities in theAttributes list correspond to base features of fillet,
+ /// the next two entities represent trimmed base features and the last one is a fillet arc.
+ virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+};
+
+#endif
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintGroup.cpp
-// Created: 27 May 2014
-// Author: Artem ZHIDKOV
-
-#include "SketchSolver_ConstraintGroup.h"
-
-#include <SketchSolver_Constraint.h>
-
-#include <Events_Error.h>
-#include <Events_Loop.h>
-#include <GeomAPI_XY.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintRigid.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-
-#include <math.h>
-#include <assert.h>
-
-/// Tolerance for value of parameters
-const double tolerance = 1.e-10;
-
-/**
- * Collects all sketch solver error' codes
- * as inline static functions
- */
- // TODO: Move this class into a separate file
-class SketchSolver_Error
-{
- public:
- /// The value parameter for the constraint
- inline static const std::string& CONSTRAINTS()
- {
- static const std::string MY_ERROR_VALUE("Conflicting constraints");
- return MY_ERROR_VALUE;
- }
- /// The entities need to have shared point, but they have not
- inline static const std::string& NO_COINCIDENT_POINTS()
- {
- static const std::string MY_ERROR_VALUE("Objects should have coincident point");
- return MY_ERROR_VALUE;
- }
-};
-
-/// This value is used to give unique index to the groups
-static Slvs_hGroup myGroupIndexer = 0;
-
-/** \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_ConstraintGroup ===============
-// ========================================================
-
-SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
- std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
- : myID(++myGroupIndexer),
- myParamMaxID(0),
- myEntityMaxID(0),
- myConstrMaxID(0),
- myConstraintMap(),
- myNeedToSolve(false),
- myConstrSolver()
-{
- myParams.clear();
- myEntities.clear();
- myEntOfConstr.clear();
- myConstraints.clear();
-
- myTempConstraints.clear();
- myTempPointWhereDragged.clear();
- myTempPointWDrgdID = 0;
-
- // Initialize workplane
- myWorkplane.h = SLVS_E_UNKNOWN;
-#ifndef NDEBUG
- assert(addWorkplane(theWorkplane));
-#else
- addWorkplane(theWorkplane);
-#endif
-}
-
-SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
-{
- myParams.clear();
- myEntities.clear();
- myEntOfConstr.clear();
- myConstraints.clear();
- myConstraintMap.clear();
- myTempConstraints.clear();
- myTempPointWhereDragged.clear();
-
- // If the group with maximal identifier is deleted, decrease the indexer
- if (myID == myGroupIndexer)
- myGroupIndexer--;
-}
-
-// ============================================================================
-// Function: isBaseWorkplane
-// Class: SketchSolver_ConstraintGroup
-// Purpose: verify the group is based on the given workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isBaseWorkplane(
- std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
-{
- return theWorkplane == mySketch;
-}
-
-// ============================================================================
-// Function: isInteract
-// Class: SketchSolver_ConstraintGroup
-// Purpose: verify are there any entities in the group used by given constraint
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isInteract(
- std::shared_ptr<SketchPlugin_Feature> theFeature) const
-{
- // Check the group is empty
- if (isEmpty())
- return true;
-
- // Check if the feature is already in the group
- if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
- return true;
- std::shared_ptr<SketchPlugin_Constraint> aConstr =
- std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
- if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
- return true;
-
- // Go through the attributes and verify if some of them already in the group
- std::list<std::shared_ptr<ModelAPI_Attribute>>
- anAttrList = theFeature->data()->attributes(std::string());
- std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
- anAttrIter = anAttrList.begin();
- for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
- AttributeRefListPtr aCAttrRefList =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
- if (aCAttrRefList) {
- std::list<ObjectPtr> anObjList = aCAttrRefList->list();
- std::list<ObjectPtr>::iterator anIt = anObjList.begin();
- for ( ; anIt != anObjList.end(); anIt++) {
- FeaturePtr aFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
- if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
- return true;
- }
- continue;
- }
- AttributeRefAttrPtr aCAttrRef =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
- if (!aCAttrRef || !aCAttrRef->isObject()) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
- if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
- return true;
- } else {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aCAttrRef->object());
- if (!aRC)
- continue;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- FeaturePtr aFeature = aDoc->feature(aRC);
- if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
- return true;
- // search attributes of a feature to be parameters of constraint
- std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
- aFeature->data()->attributes(std::string());
- std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
- .begin();
- for (; aFAIter != aFeatAttrList.end(); aFAIter++)
- if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
- return true;
- }
- }
-
- // Entities did not found
- return false;
-}
-
-// ============================================================================
-// Function: checkConstraintConsistence
-// Class: SketchSolver_ConstraintGroup
-// Purpose: verifies and changes parameters of the constraint
-// ============================================================================
-void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
-{
- if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
- // Get constraint parameters and check the sign of constraint value
-
- // point coordinates
- int aPtPos = Search(theConstraint.ptA, myEntities);
- int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aPoint(
- new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
- // line coordinates
- int aLnPos = Search(theConstraint.entityA, myEntities);
- aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
- aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aStart(
- new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
- aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
- aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aEnd(
- new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
- aEnd = aEnd->added(aStart);
- aPoint = aPoint->added(aStart);
- if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
- theConstraint.valA *= -1.0;
- }
-}
-
-// ============================================================================
-// Function: changeConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- // There is no workplane yet, something wrong
- if (myWorkplane.h == SLVS_E_UNKNOWN)
- return false;
-
- if (theConstraint) {
- if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
- return changeRigidConstraint(theConstraint);
- if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
- return changeMirrorConstraint(theConstraint);
- if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
- return changeFilletConstraint(theConstraint);
- }
-
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN
- || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- // Create constraint parameters
- double aDistance = 0.0; // scalar value of the constraint
- AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
- if (aDistAttr) {
- aDistance = aDistAttr->value();
- // Issue #196: checking the positivity of the distance constraint
- if (aDistance < tolerance &&
- (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
- return false;
- // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
- if (aConstrType == SLVS_C_DIAMETER)
- aDistance *= 2.0;
- if (aConstrMapIter != myConstraintMap.end()
- && fabs(aConstrIter->valA - aDistance) > tolerance) {
- myNeedToSolve = true;
- aConstrIter->valA = aDistance;
- }
- }
-
- size_t aNbTmpConstraints = myTempConstraints.size();
- Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
- std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(
- theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
- if (!aConstrAttr)
- continue;
-
- // Convert the object of the attribute to the feature
- FeaturePtr aFeature;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- continue;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aFeature = aDoc->feature(aRC);
- }
-
- // For the length constraint the start and end points of the line should be added to the entities list instead of line
- if (aConstrType == SLVS_C_PT_PT_DISTANCE
- && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
- Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
- int aEntPos = Search(aLineEnt, myEntities);
- aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
- aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
- while (indAttr < CONSTRAINT_ATTR_SIZE)
- aConstrEnt[indAttr++] = 0;
- break; // there should be no other entities
- } else if (aConstrAttr->isObject())
- aConstrEnt[indAttr] = changeEntityFeature(aFeature);
- else
- aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
- }
-
- if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
- // Several points may be coincident, it is not necessary to store all constraints between them.
- // Try to find sequence of coincident points which connects the points of new constraint
- if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
- if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
- return false;
- if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
- myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
- return false;
- }
- if (aNbTmpConstraints < myTempConstraints.size()) {
- // There was added temporary constraint. Check that there is no coincident points which already rigid.
-
- // Get list of already fixed points
- std::set<Slvs_hEntity> anAlreadyFixed;
- std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
- std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
- for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
- if (*aTmpIt == aCIter->h)
- break;
- if (aTmpIt == myTempConstraints.end())
- anAlreadyFixed.insert(aCIter->ptA);
- }
-
- std::set<Slvs_hConstraint> aTmpConstrToDelete;
- std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
- size_t aCurSize = myTempConstraints.size();
- for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
- aTmpIter++, aCurSize--) {
- int aConstrPos = Search(*aTmpIter, myConstraints);
- std::vector<std::set<Slvs_hEntity> >::const_iterator
- aCoincIter = myCoincidentPoints.begin();
- for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
- if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
- std::set<Slvs_hEntity>::const_iterator anIt;
- for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
- if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
- aTmpConstrToDelete.insert(*aTmpIter);
- break;
- }
- break;
- }
- }
- if (!aTmpConstrToDelete.empty())
- removeTemporaryConstraints(aTmpConstrToDelete);
- }
- }
- // For the tangency constraints it is necessary to identify which points of entities are coincident
- int aSlvsOtherFlag = 0;
- int aSlvsOther2Flag = 0;
- if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
- // Search entities used by constraint
- int anEnt1Pos = Search(aConstrEnt[2], myEntities);
- int anEnt2Pos = Search(aConstrEnt[3], myEntities);
- // Obtain start and end points of entities
- Slvs_hEntity aPointsToFind[4];
- aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
- aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
- bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
- aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
- aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
- // Search coincident points
- bool isPointFound[4];
- std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
- for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
- for (int i = 0; i < 4; i++)
- isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
- if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
- // the arc is tangent by end point
- if (isPointFound[1]) aSlvsOtherFlag = 1;
- // the second item is an arc and it is tangent by end point too
- if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
- break;
- }
- }
- if (aCPIter == myCoincidentPoints.end()) {
- // There is no coincident points between tangential objects. Generate error message
- Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
- return false;
- }
- }
-
- // Create SolveSpace constraint structure
- Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
- myWorkplane.h, aDistance, aConstrEnt[0],
- aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
- if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
- if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
- myConstraints.push_back(aSlvsConstr);
- myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
- int aConstrPos = Search(aSlvsConstr.h, myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- myNeedToSolve = true;
- } else { // Attributes of constraint may be changed => update constraint
- Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
- &aConstrIter->entityA, &aConstrIter->entityB,
- &aConstrIter->entityC, &aConstrIter->entityD};
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
- {
- *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
- myNeedToSolve = true;
- }
- }
- }
-
- // Update flags of entities to be used by constraints
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
- if (aConstrEnt[indAttr] != 0) {
- int aPos = Search(aConstrEnt[indAttr], myEntities);
- myEntOfConstr[aPos] = true;
- // Sub-entities should be used implcitly
- Slvs_hEntity* aEntPtr = myEntities[aPos].point;
- while (*aEntPtr != 0) {
- aPos = Search(*aEntPtr, myEntities);
- myEntOfConstr[aPos] = true;
- aEntPtr++;
- }
- }
-
- checkConstraintConsistence(*aConstrIter);
- return true;
-}
-
-// ============================================================================
-// Function: changeRigidConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the "Rigid" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeRigidConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN
- || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
- std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(
- theConstraint->data()->attribute(aConstraintAttributes[0]));
- if (!aConstrAttr)
- return false;
-
- // Convert the object of the attribute to the feature
- FeaturePtr aFeature;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- return false;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aFeature = aDoc->feature(aRC);
- }
-
- aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
-
- if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
- // Check the fixed entity is not a point.
- std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
- std::shared_ptr<GeomDataAPI_Point> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
- std::shared_ptr<SketchPlugin_Point> aSketchPoint =
- std::dynamic_pointer_cast<SketchPlugin_Point>(aFeature);
- if (aPoint || aPoint2D || aSketchPoint) {
- // Create SolveSpace constraint structure
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
- aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
- int aConstrPos = Search(aConstraint.h, myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- myNeedToSolve = true;
- } else {
- myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
-
- // To avoid SolveSpace problems:
- // * if the circle is rigid, we will fix its center and radius;
- // * if the arc is rigid, we will fix its start and end points and radius.
- double aRadius = 0.0;
- bool isArc = false;
- bool isCircle = false;
- if (aFeature) {
- if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
- std::shared_ptr<GeomDataAPI_Point2D> aCenter =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStart =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
- aRadius = aStart->pnt()->distance(aCenter->pnt());
- isArc = true;
- } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
- aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
- isCircle = true;
- }
- }
-
- // Get list of already fixed points
- std::set<Slvs_hEntity> anAlreadyFixed;
- std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if (aCIter->type == SLVS_C_WHERE_DRAGGED)
- anAlreadyFixed.insert(aCIter->ptA);
-
- // Create constraints to fix the parameters of the entity
- int aEntPos = Search(aConstrEnt, myEntities);
- Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
- if (isArc) aPointsPtr++; // avoid to fix center of arc
- while (*aPointsPtr != 0) {
- // Avoid to create additional "Rigid" constraints for coincident points
- bool isCoincAlreadyFixed = false;
- if (!anAlreadyFixed.empty()) {
- if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
- isCoincAlreadyFixed = true;
-
- std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
- myCoincidentPoints.begin();
- for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
- if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
- continue;
- std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
- for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
- if (aCoincIter->find(*anIter) != aCoincIter->end())
- isCoincAlreadyFixed = true;
- }
- }
-
- if (!isCoincAlreadyFixed) {
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
- *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint].push_back(aConstraint.h);
- }
- aPointsPtr++;
- }
-
- if (isArc || isCircle) { // add radius constraint
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint].push_back(aConstraint.h);
- }
-
- // The object is already rigid, so there is no constraints added
- if (myConstraintMap[theConstraint].empty()) {
- myConstraintMap.erase(theConstraint);
- myNeedToSolve = false;
- }
- else
- myNeedToSolve = true;
- }
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeMirrorConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the "Mirror" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- DataPtr aConstrData = theConstraint->data();
-
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- bool isExists = false;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- isExists = true;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN
- || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
- AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrData->attribute(aConstraintAttributes[0]));
- if (!aConstrAttr)
- return false;
-
- // Convert the object of the attribute to the feature
- FeaturePtr aMirrorLineFeat;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- return false;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aMirrorLineFeat = aDoc->feature(aRC);
- }
- aMirrorLineEnt = aConstrAttr->isObject() ?
- changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
-
- // Append symmetric constraint for each point of mirroring features
- AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(aConstraintAttributes[1]));
- AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(aConstraintAttributes[2]));
- if (!aBaseRefList || !aMirroredRefList)
- return false;
-
- std::list<ObjectPtr> aBaseList = aBaseRefList->list();
- std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
- // remove all empty items
- std::list<ObjectPtr>::iterator anIt = aBaseList.begin();
- std::list<ObjectPtr>::iterator aTmpIt;
- while (anIt != aBaseList.end()) {
- aTmpIt = anIt;
- anIt++;
- if (!(*aTmpIt))
- aBaseList.erase(aTmpIt);
- }
- anIt = aMirroredList.begin();
- while (anIt != aMirroredList.end()) {
- aTmpIt = anIt;
- anIt++;
- if (!(*aTmpIt))
- aMirroredList.erase(aTmpIt);
- }
- if (aBaseList.empty() || aBaseList.size() != aMirroredList.size())
- return false;
-
- std::vector<Slvs_hConstraint> aNewConstraints;
- // Fill the list of already mirrored points
- std::vector<Slvs_Constraint> anOldConstraints;
- std::map<Slvs_hEntity, Slvs_hEntity> aMirroredPoints;
- if (isExists) {
- std::vector<Slvs_hConstraint>::const_iterator aCIter = aConstrMapIter->second.begin();
- for (; aCIter != aConstrMapIter->second.end(); aCIter++) {
- int anInd = Search(*aCIter, myConstraints);
- if (myConstraints[anInd].type != aConstrType)
- continue;
- aMirroredPoints[myConstraints[anInd].ptA] = myConstraints[anInd].ptB;
- anOldConstraints.push_back(myConstraints[anInd]);
- }
- }
-
- FeaturePtr aBaseFeature, aMirrorFeature;
- ResultConstructionPtr aRC;
- std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
- std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
- for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
- aBaseFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
- aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aMirIter);
-
- if (!aBaseFeature || !aMirrorFeature ||
- aBaseFeature->getKind() != aMirrorFeature->getKind())
- return false;
- Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
- Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
- // Make aMirrorEnt parameters to be symmetric with aBaseEnt
- makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
-
- if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
- Slvs_hConstraint anID = changeMirrorPoints(aBaseEnt, aMirrorEnt,
- aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- } else {
- int aBasePos = Search(aBaseEnt, myEntities);
- int aMirrorPos = Search(aMirrorEnt, myEntities);
- if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
- for (int ind = 0; ind < 2; ind++) {
- Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[ind],
- myEntities[aMirrorPos].point[ind], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- }
- } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
- Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[0],
- myEntities[aMirrorPos].point[0], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- // Additional constraint for equal radii
- Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
- myConstraints.push_back(anEqRadConstr);
- myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
- } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
- // Workaround to avoid problems in SolveSpace.
- // The symmetry of two arcs will be done using symmetry of three points on these arcs:
- // start point, end point, and any other point on the arc
- Slvs_hEntity aBaseArcPoints[3] = {
- myEntities[aBasePos].point[1],
- myEntities[aBasePos].point[2],
- SLVS_E_UNKNOWN};
- Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
- myEntities[aMirrorPos].point[2],
- myEntities[aMirrorPos].point[1],
- SLVS_E_UNKNOWN};
- Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
- Slvs_hEntity aBothMiddlePoints[2];
- for (int i = 0; i < 2; i++) {
- double x, y;
- calculateMiddlePoint(aBothArcs[i], x, y);
- std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
- Slvs_hParam u = changeParameter(x, aParamIter);
- Slvs_hParam v = changeParameter(y, aParamIter);
- Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
- myEntities.push_back(aPoint);
- myEntOfConstr.push_back(true);
- aBothMiddlePoints[i] = aPoint.h;
- // additional constraint point-on-curve
- Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
- aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
- myConstraints.push_back(aPonCircConstr);
- myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
- aNewConstraints.push_back(aPonCircConstr.h);
- }
-
- aBaseArcPoints[2] = aBothMiddlePoints[0];
- aMirrorArcPoints[2] = aBothMiddlePoints[1];
- for (int ind = 0; ind < 3; ind++) {
- Slvs_hConstraint anID = changeMirrorPoints(aBaseArcPoints[ind], aMirrorArcPoints[ind],
- aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- }
- }
- }
- }
-
- // Remove unused constraints
- std::vector<Slvs_Constraint>::const_iterator anOldCIter = anOldConstraints.begin();
- for (; anOldCIter != anOldConstraints.end(); anOldCIter++) {
- int anInd = Search(anOldCIter->h, myConstraints);
- myConstraints.erase(myConstraints.begin() + anInd);
- }
- myConstraintMap[theConstraint] = aNewConstraints;
-
- if (!isExists) {
- // Set the mirror line unchanged during constraint recalculation
- int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
- // firstly check the line is not fixed yet
- bool isFixed[2] = {false, false};
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end() && !(isFixed[0] && isFixed[1]); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) {
- if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[0])
- isFixed[0] = true;
- else if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[1])
- isFixed[1] = true;
- }
- // add new rigid constraints
- if (!isFixed[0]) {
- Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
- myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aRigidStart);
- myConstraintMap[theConstraint].push_back(aRigidStart.h);
- }
- if (!isFixed[1]) {
- Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
- myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aRigidEnd);
- myConstraintMap[theConstraint].push_back(aRigidEnd.h);
- }
-
- // Add temporary constraints for initial objects to be unchanged
- for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
- aBaseFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
- if (!aBaseFeature) continue;
- std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
- if (aBaseFeature->getKind() != SketchPlugin_Arc::ID()) {
- std::list<AttributePtr>::iterator anIt = aPoints.begin();
- for ( ; anIt != aPoints.end(); anIt++) {
- addTemporaryConstraintWhereDragged(*anIt);
- }
- } else {
- // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
- AttributePtr aCenterAttr = aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID());
- std::map<AttributePtr, Slvs_hEntity>::iterator aFound = myEntityAttrMap.find(aCenterAttr);
- Slvs_hEntity anArcPoints[3] = {aFound->second, 0, 0};
- AttributePtr aStartAttr = aBaseFeature->attribute(SketchPlugin_Arc::START_ID());
- aFound = myEntityAttrMap.find(aStartAttr);
- anArcPoints[1] = aFound->second;
- AttributePtr aEndAttr = aBaseFeature->attribute(SketchPlugin_Arc::END_ID());
- aFound = myEntityAttrMap.find(aEndAttr);
- anArcPoints[2] = aFound->second;
-
- bool isFixed[3] = {false, false, false};
- int aNbFixed = 0; // number of already fixed points on the arc
- for (int i = 0; i < 3; i++) {
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- for (; aCoPtIter != myCoincidentPoints.end() && !isFixed[i]; aCoPtIter++) {
- if (aCoPtIter->find(anArcPoints[i]) == aCoPtIter->end())
- continue; // the entity was not found in current set
-
- // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
- std::vector<Slvs_Constraint>::iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCoPtIter->find(aConstrIter->ptA) != aCoPtIter->end()) {
- isFixed[i] = true;
- aNbFixed++;
- break; // the SLVS_C_WHERE_DRAGGED constraint already exists
- }
- }
- }
- if (aNbFixed < 2) { // append constraints
- if (!isFixed[0])
- addTemporaryConstraintWhereDragged(aCenterAttr);
- if (!isFixed[1] && (isFixed[0] || aNbFixed == 0))
- addTemporaryConstraintWhereDragged(aStartAttr);
- }
- }
- }
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeFilletConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the "Fillet" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeFilletConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- DataPtr aConstrData = theConstraint->data();
-
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN)
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- // Obtain hEntity for basic objects of fillet
- Slvs_hEntity aBaseObject[2];
- FeaturePtr aBaseFeature[2];
- for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
- AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrData->attribute(aConstraintAttributes[indAttr]));
- if (!aConstrAttr)
- return false;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- return false;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aBaseFeature[indAttr] = aDoc->feature(aRC);
- }
- aBaseObject[indAttr] = aConstrAttr->isObject() ?
- changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
- }
- // Check the base entities have a coincident point
- int aBaseObjInd[2] = {
- Search(aBaseObject[0], myEntities),
- Search(aBaseObject[1], myEntities)
- };
- int aShift[2] = { // shift for calculating correct start and end points for different types of objects
- myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
- myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
- };
- Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
- myEntities[aBaseObjInd[0]].point[aShift[0]],
- myEntities[aBaseObjInd[0]].point[1+aShift[0]]
- };
- Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
- myEntities[aBaseObjInd[1]].point[aShift[1]],
- myEntities[aBaseObjInd[1]].point[1+aShift[1]]
- };
- bool isCoincidentFound = false;
- int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
- std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
- for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
- for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
- for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
- if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
- aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
- aBaseCoincInd[0] = ind1;
- aBaseCoincInd[1] = ind2;
- isCoincidentFound = true;
- }
- if (!isCoincidentFound) {
- // There is no coincident points between objects. Generate error message
- Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
- return false;
- }
-
- // Create fillet entities
- // - first object is placed on the first base
- // - second object is on the second base
- // - third object is a filleting arc
- static const int aNbFilletEnt = 3;
- Slvs_hEntity aFilletEnt[aNbFilletEnt];
- int aFilletObjInd[aNbFilletEnt];
- AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(aConstraintAttributes[2]));
- if (!aFilletRefList)
- return false;
- std::list<ObjectPtr> aFilletList = aFilletRefList->list();
- if (aFilletList.size() < aNbFilletEnt)
- return false;
- FeaturePtr aFilletFeature;
- ResultConstructionPtr aRC;
- std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
- for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
- aFilletFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
- if (!aFilletFeature)
- return false;
- aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
- if (aFilletEnt[indEnt] == SLVS_E_UNKNOWN)
- return false; // not all attributes are initialized yet
- aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
- }
- // At first time, for correct result, move floating points of fillet on the middle points of base objects
- if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
- double anArcPoints[6];
- for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
- int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
- int aPointsPos[2] = {
- Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
- Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
- };
- int aParamPos[2] = {
- Search(myEntities[aPointsPos[0]].param[0], myParams),
- Search(myEntities[aPointsPos[1]].param[0], myParams)
- };
- int anIndex = aParamPos[aBaseCoincInd[indEnt]];
- if (anIndShift == 0) {
- myParams[anIndex].val =
- 0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
- myParams[1 + anIndex].val =
- 0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
- } else { // place the changed point on the arc
- double x = 0, y = 0;
- calculateMiddlePoint(aFilletEnt[indEnt], x, y);
- myParams[anIndex].val = x;
- myParams[1 + anIndex].val = y;
- }
- anArcPoints[indEnt*2+2] = myParams[anIndex].val;
- anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
- }
- anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
- anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
- for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
- int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
- int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
- myParams[aParamPos].val = anArcPoints[indArcPt * 2];
- myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
- }
- }
-
- // Create list of constraints to generate fillet
- int aPtInd;
- std::vector<Slvs_hConstraint> aConstrList;
- bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
- std::vector<Slvs_hConstraint>::iterator aCMapIter =
- isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
- std::vector<Slvs_hConstraint>::iterator aCMapEnd =
- isExists ? myConstraintMap[theConstraint].end() : aConstrList.end();
- int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
- for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
- // one point of fillet object should be coincident with the point on base, non-coincident with another base object
- aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
- Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
- Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
- if (isExists) {
- myConstraints[aCurConstrPos].ptA = aPtBase;
- myConstraints[aCurConstrPos].ptB = aPtFillet;
- aCMapIter++;
- aCurConstrPos = Search(*aCMapIter, myConstraints);
- } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
- Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
- 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aCoincConstr);
- aConstrList.push_back(aCoincConstr.h);
- }
-
- // another point of fillet object should be placed on the base object
- Slvs_Constraint aPonCurveConstr;
- int aTangentType;
- if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
- // centers of arcs should be coincident
- aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
- aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
- if (isExists) {
- myConstraints[aCurConstrPos].ptA = aPtBase;
- myConstraints[aCurConstrPos].ptB = aPtFillet;
- aCMapIter++;
- if (aCMapIter != aCMapEnd)
- aCurConstrPos = Search(*aCMapIter, myConstraints);
- } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
- aPonCurveConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
- 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- }
- aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
- aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
- } else {
- aPtInd = aBaseCoincInd[indEnt];
- aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
- if (isExists) {
- myConstraints[aCurConstrPos].ptA = aPtFillet;
- aCMapIter++;
- if (aCMapIter != aCMapEnd)
- aCurConstrPos = Search(*aCMapIter, myConstraints);
- } else {
- aPonCurveConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
- 0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
- }
- aTangentType = SLVS_C_ARC_LINE_TANGENT;
- }
- if (!isExists) {
- myConstraints.push_back(aPonCurveConstr);
- aConstrList.push_back(aPonCurveConstr.h);
- }
- }
-
- if (!isExists)
- myConstraintMap[theConstraint] = aConstrList;
-
- // Additional temporary constraints for base objects to be fixed
- int aNbArcs = 0;
- for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
- if (!aBaseFeature[indAttr]) {
- AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrData->attribute(aConstraintAttributes[indAttr]));
- addTemporaryConstraintWhereDragged(aConstrAttr->attr());
- continue;
- }
- if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Line::ID()) {
- addTemporaryConstraintWhereDragged(
- aBaseFeature[indAttr]->attribute(SketchPlugin_Line::START_ID()));
- addTemporaryConstraintWhereDragged(
- aBaseFeature[indAttr]->attribute(SketchPlugin_Line::END_ID()));
- } else if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID()) {
- // Arc should be fixed by its center only (to avoid "conflicting constraints" message)
- // If the fillet is made on two arc, the shared point should be fixed too
- aNbArcs++;
- addTemporaryConstraintWhereDragged(
- aBaseFeature[indAttr]->attribute(SketchPlugin_Arc::CENTER_ID()));
- }
- }
- if (aNbArcs == 2) {
- addTemporaryConstraintWhereDragged(aBaseCoincInd[0] == 0 ?
- aBaseFeature[0]->attribute(SketchPlugin_Arc::START_ID()) :
- aBaseFeature[0]->attribute(SketchPlugin_Arc::END_ID()));
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeEntity
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the element affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
- std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
- // If the entity is already in the group, try to find it
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
- myEntityAttrMap.find(theEntity);
- int aEntPos;
- std::vector<Slvs_Param>::iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
- if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
- aParamIter = myParams.end();
- else { // the entity already exists
- aEntPos = Search(aEntIter->second, myEntities);
- int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
- aParamIter = myParams.begin() + aParamPos;
- }
- const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
- const bool isNeedToSolve = myNeedToSolve;
- myNeedToSolve = false;
-
- if (isEntExists) {
- // Verify that the entity is not used by "Rigid" constraint.
- // If it is used, the object should not move.
- std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
- for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
- if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
- break;
- std::set<Slvs_hEntity> aCoincident;
- if (aCoincIter != myCoincidentPoints.end()) {
- aCoincident = *aCoincIter;
- aCoincident.erase(aEntIter->second);
-
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
- myNeedToSolve = true;
- return aEntIter->second;
- }
- }
- }
-
- // Look over supported types of entities
- Slvs_Entity aNewEntity;
- aNewEntity.h = SLVS_E_UNKNOWN;
-
- // Point in 3D
- std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- theEntity);
- if (aPoint) {
- Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
- Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
- Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
- } else {
- // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
- if (myWorkplane.h == SLVS_E_UNKNOWN)
- return SLVS_E_UNKNOWN;
-
- // Point in 2D
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
- if (aPoint2D) {
- Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
- Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
- } else {
- // Scalar value (used for the distance entities)
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
- if (aScalar) {
- Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
- }
- }
- }
- /// \todo Other types of entities
-
- Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
-
- if (isEntExists) {
- myNeedToSolve = myNeedToSolve || isNeedToSolve;
- aResult = aEntIter->second;
- } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
- myEntities.push_back(aNewEntity);
- myEntOfConstr.push_back(false);
- myEntityAttrMap[theEntity] = aNewEntity.h;
- aResult = aNewEntity.h;
- }
-
- // If the attribute was changed by the user, we need to fix it before solving
- if (myNeedToSolve && theEntity->isImmutable())
- addTemporaryConstraintWhereDragged(theEntity, false);
-
- return aResult;
-}
-
-// ============================================================================
-// Function: changeEntity
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the element defined by the feature affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
-{
- if (!theEntity->data()->isValid())
- return SLVS_E_UNKNOWN;
- // If the entity is already in the group, try to find it
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
- // defines that the entity already exists
- const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
-
- Slvs_Entity aNewEntity;
- aNewEntity.h = SLVS_E_UNKNOWN;
-
- // SketchPlugin features
- std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
- SketchPlugin_Feature>(theEntity);
- if (aFeature) { // Verify the feature by its kind
- const std::string& aFeatureKind = aFeature->getKind();
- AttributePtr anAttribute;
-
- // Line
- if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aStart = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aEnd = changeEntity(anAttribute);
-
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
- }
- // Circle
- else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aCenter = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aRadius = changeEntity(anAttribute);
-
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
- myWorkplane.normal, aRadius);
- }
- // Arc
- else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aCenter = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aStart = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aEnd = changeEntity(anAttribute);
-
- if (!isEntExists)
- aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
- myWorkplane.normal, aCenter, aStart, aEnd);
- }
- // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
- else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aPoint = changeEntity(anAttribute);
-
- if (isEntExists)
- return aEntIter->second;
-
- // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
- myEntityFeatMap[theEntity] = aPoint;
- myNeedToSolve = true;
- return aPoint;
- }
- }
- /// \todo Other types of features
-
- if (isEntExists)
- return aEntIter->second;
-
- if (aNewEntity.h != SLVS_E_UNKNOWN) {
- myEntities.push_back(aNewEntity);
- myEntOfConstr.push_back(false);
- myEntityFeatMap[theEntity] = aNewEntity.h;
- myNeedToSolve = true;
- return aNewEntity.h;
- }
-
- // Unsupported or wrong entity type
- return SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-// Function: changeNormal
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the normal of workplane
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
- std::shared_ptr<ModelAPI_Attribute> theDirX,
- std::shared_ptr<ModelAPI_Attribute> theNorm)
-{
- std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNorm);
- std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
- if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
- return SLVS_E_UNKNOWN;
- // calculate Y direction
- std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
-
- // 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);
- double aNormCoord[4] = { qw, qx, qy, qz };
-
- // Try to find existent normal
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
- myEntityAttrMap.find(theNorm);
- std::vector<Slvs_Param>::iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
- if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
- aParamIter = myParams.end();
- else { // the entity already exists, update it
- int aEntPos = Search(aEntIter->second, myEntities);
- int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
- aParamIter = myParams.begin() + aParamPos;
- }
-
- // Change parameters of the normal
- Slvs_hParam aNormParams[4];
- for (int i = 0; i < 4; i++)
- aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
-
- if (aEntIter != myEntityAttrMap.end()) // the entity already exists
- return aEntIter->second;
-
- // Create a normal
- Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
- aNormParams[2], aNormParams[3]);
- myEntities.push_back(aNormal);
- myEntOfConstr.push_back(false);
- myEntityAttrMap[theNorm] = aNormal.h;
- return aNormal.h;
-}
-
-// ============================================================================
-// Function: addWorkplane
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create workplane for the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
-{
- if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
- return false; // the workplane already exists or the function parameter is not Sketch
-
- mySketch = theSketch;
- updateWorkplane();
- return true;
-}
-
-// ============================================================================
-// Function: updateWorkplane
-// Class: SketchSolver_ConstraintGroup
-// Purpose: update parameters of workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateWorkplane()
-{
- if (!mySketch->data())
- return false; // case sketch is deleted
- // Get parameters of workplane
- std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
- SketchPlugin_Sketch::DIRX_ID());
- std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
- SketchPlugin_Sketch::NORM_ID());
- std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
- SketchPlugin_Sketch::ORIGIN_ID());
- // Transform them into SolveSpace format
- Slvs_hEntity aNormalWP = changeNormal(aDirX, aNorm);
- if (!aNormalWP)
- return false;
- Slvs_hEntity anOriginWP = changeEntity(anOrigin);
- if (!anOriginWP)
- return false;
-
- if (!myWorkplane.h) {
- // Create workplane
- myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
- // Workplane should be added to the list of entities
- myEntities.push_back(myWorkplane);
- myEntOfConstr.push_back(false);
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeParameter
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update value of parameter
-// ============================================================================
-Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
- double theParam, std::vector<Slvs_Param>::iterator& thePrmIter)
-{
- if (thePrmIter != myParams.end()) { // Parameter should be updated
- int aParamPos = thePrmIter - myParams.begin();
- if (fabs(thePrmIter->val - theParam) > tolerance) {
- myNeedToSolve = true; // parameter is changed, need to resolve constraints
- myParams[aParamPos].val = theParam;
- }
- thePrmIter++;
- return myParams[aParamPos].h;
- }
-
- // Newly created parameter
- Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
- myParams.push_back(aParam);
- myNeedToSolve = true;
- // The list of parameters is changed, move iterator to the end of the list to avoid problems
- thePrmIter = myParams.end();
- return aParam.h;
-}
-
-// ============================================================================
-// Function: resolveConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: solve the set of constraints for the current group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::resolveConstraints()
-{
- if (!myNeedToSolve)
- return false;
-
- myConstrSolver.setGroupID(myID);
- myConstrSolver.setParameters(myParams);
- myConstrSolver.setEntities(myEntities);
- myConstrSolver.setConstraints(myConstraints);
- myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
-
- int aResult = myConstrSolver.solve();
- if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
- // Obtain result into the same list of parameters
- if (!myConstrSolver.getResult(myParams))
- return true;
-
- // We should go through the attributes map, because only attributes have valued parameters
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
- myEntityAttrMap.begin();
- for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
- if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
- anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
- if (updateAttribute(anEntIter->first, anEntIter->second))
- updateRelatedConstraints(anEntIter->first);
- }
- updateFilletConstraints();
- // unblock all features then
- for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
- if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
- anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
- }
- } else if (!myConstraints.empty())
- Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
-
- removeTemporaryConstraints();
- myNeedToSolve = false;
- return true;
-}
-
-// ============================================================================
-// Function: mergeGroups
-// Class: SketchSolver_ConstraintGroup
-// Purpose: append specified group to the current group
-// ============================================================================
-void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
-{
- // If specified group is empty, no need to merge
- if (theGroup.myConstraintMap.empty())
- return;
-
- // Map between old and new indexes of SolveSpace constraints
- std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
-
- // Add all constraints from theGroup to the current group
- ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
- for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
- if (changeConstraint(aConstrIter->first))
- aConstrMap[aConstrIter->second.back()] = myConstrMaxID; // the constraint was added => store its ID
-
- // Add temporary constraints from theGroup
- std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
- for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
- std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
- *aTempConstrIter);
- if (aFind != aConstrMap.end())
- myTempConstraints.push_back(aFind->second);
- }
-
- if (myTempPointWhereDragged.empty())
- myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
- else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
- theGroup.myEntityAttrMap.begin();
- for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
- if (aFeatureIter->second == myTempPointWDrgdID) {
- addTemporaryConstraintWhereDragged(aFeatureIter->first);
- break;
- }
- }
-
- myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
-}
-
-// ============================================================================
-// Function: splitGroup
-// Class: SketchSolver_ConstraintGroup
-// Purpose: divide the group into several subgroups
-// ============================================================================
-void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
-{
- // Divide constraints and entities into several groups
- std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
- std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
- int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++) {
- Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
- aConstrIter->entityB };
- std::vector<int> anIndexes;
- // Go through the groupped entities and find even one of entities of current constraint
- std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
- for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
- bool isFound = false;
- for (int i = 0; i < 4 && !isFound; i++)
- if (aConstrEnt[i] != 0) {
- isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
- // Also we need to check sub-entities
- int aEntPos = Search(aConstrEnt[i], myEntities);
- if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
- Slvs_hEntity* aSub = myEntities[aEntPos].point;
- for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
- isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
- }
- }
- if (isFound)
- anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
- }
- // Add new group if no one is found
- if (anIndexes.empty()) {
- std::set<Slvs_hEntity> aNewGrEnt;
- for (int i = 0; i < 4; i++)
- if (aConstrEnt[i] != 0) {
- aNewGrEnt.insert(aConstrEnt[i]);
- int aEntPos = Search(aConstrEnt[i], myEntities);
- if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
- Slvs_hEntity* aSub = myEntities[aEntPos].point;
- for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
- aNewGrEnt.insert(*aSub);
- }
- }
- std::set<Slvs_hConstraint> aNewGrConstr;
- aNewGrConstr.insert(aConstrIter->h);
-
- aGroupsEntities.push_back(aNewGrEnt);
- aGroupsConstr.push_back(aNewGrConstr);
- if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
- aMaxNbEntities = aGroupsEntities.size() - 1;
- } else { // Add entities indexes into the found group
- aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
- for (int i = 0; i < 4; i++)
- if (aConstrEnt[i] != 0) {
- aGrEntIter->insert(aConstrEnt[i]);
- int aEntPos = Search(aConstrEnt[i], myEntities);
- if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
- Slvs_hEntity* aSub = myEntities[aEntPos].point;
- for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
- aGrEntIter->insert(*aSub);
- }
- }
- aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
- if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
- aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
- if (anIndexes.size() > 1) { // There are found several connected groups, merge them
- std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
- + anIndexes.front();
- std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
- + anIndexes.front();
- std::vector<int>::iterator anInd = anIndexes.begin();
- for (++anInd; anInd != anIndexes.end(); anInd++) {
- aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
- aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
- }
- if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
- aMaxNbEntities = anIndexes.front();
- // Remove merged groups
- for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
- aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
- aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
- }
- }
- }
- }
-
- if (aGroupsEntities.size() <= 1)
- return;
-
- // Remove the group with maximum elements as it will be left in the current group
- aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
- aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
-
- // Add new groups of constraints and divide current group
- std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
- for (int i = aGroupsEntities.size(); i > 0; i--) {
- SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
- aNewGroups.push_back(aG);
- }
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
- int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
- while (aConstrMapIter != myConstraintMap.end()) {
- std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
- for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
- if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
- (*aGroup)->changeConstraint(aConstrMapIter->first);
- removeConstraint(aConstrMapIter->first);
- // restore iterator
- aConstrMapIter = myConstraintMap.begin();
- for (int i = 0; i < aConstrMapPos; i++)
- aConstrMapIter++;
- break;
- }
- if (aGIter == aGroupsConstr.end()) {
- aConstrMapIter++;
- aConstrMapPos++;
- }
- }
-
- theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
-}
-
-// ============================================================================
-// Function: updateGroup
-// Class: SketchSolver_ConstraintGroup
-// Purpose: search removed entities and constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateGroup()
-{
- ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
- bool isAllValid = true;
- bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
- int aConstrIndex = 0;
- while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
- if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
- if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
- isCCRemoved = true;
- removeConstraint(aConstrIter->first);
- isAllValid = false;
- // Get back the correct position of iterator after the "remove" operation
- aConstrIter = myConstraintMap.rbegin();
- for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
- aConstrIter++;
- } else {
- aConstrIter++;
- aConstrIndex++;
- }
- }
-
- // Check if some entities are invalid too
- std::set<Slvs_hEntity> anEntToRemove;
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
- anAttrIter = myEntityAttrMap.begin();
- while (anAttrIter != myEntityAttrMap.end()) {
- if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
- !anAttrIter->first->owner()->data()->isValid()) {
- anEntToRemove.insert(anAttrIter->second);
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
- aRemovedIter = anAttrIter;
- anAttrIter++;
- myEntityAttrMap.erase(aRemovedIter);
- } else
- anAttrIter++;
- }
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
- while (aFeatIter != myEntityFeatMap.end()) {
- if (!aFeatIter->first || !aFeatIter->first->data() ||
- !aFeatIter->first->data()->isValid()) {
- anEntToRemove.insert(aFeatIter->second);
- std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
- aFeatIter++;
- myEntityFeatMap.erase(aRemovedIter);
- } else
- aFeatIter++;
- }
- removeEntitiesById(anEntToRemove);
-
- // Probably, need to update coincidence constraints
- if (isCCRemoved && !myExtraCoincidence.empty()) {
- // Make a copy, because the new list of unused constrtaints will be generated
- std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
- myExtraCoincidence.clear();
-
- std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
- for (; aCIter != anExtraCopy.end(); aCIter++)
- if ((*aCIter)->data() && (*aCIter)->data()->isValid())
- changeConstraint(*aCIter);
- }
-
- return !isAllValid;
-}
-
-// ============================================================================
-// Function: updateAttribute
-// Class: SketchSolver_ConstraintGroup
-// Purpose: update features of sketch after resolving constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateAttribute(
- std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
-{
- // Search the position of the first parameter of the entity
- int anEntPos = Search(theEntityID, myEntities);
- int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
-
- // Look over supported types of entities
-
- // Point in 3D
- std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- theAttribute);
- if (aPoint) {
- if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
- || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
- || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
- aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
- myParams[aFirstParamPos + 2].val);
- return true;
- }
- return false;
- }
-
- // Point in 2D
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
- if (aPoint2D) {
- if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
- || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
- aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
- return true;
- }
- return false;
- }
-
- // Scalar value
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (aScalar) {
- if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
- aScalar->setValue(myParams[aFirstParamPos].val);
- return true;
- }
- return false;
- }
-
- /// \todo Support other types of entities
- return false;
-}
-
-// ============================================================================
-// Function: updateEntityIfPossible
-// Class: SketchSolver_ConstraintGroup
-// Purpose: search the entity in this group and update it
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateEntityIfPossible(
- std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
- if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
- // If the attribute is a point and it is changed (the group needs to rebuild),
- // probably user has dragged this point into this position,
- // so it is necessary to add constraint which will guarantee the point will not change
-
- // Store myNeedToSolve flag to verify the entity is really changed
- bool aNeedToSolveCopy = myNeedToSolve;
- myNeedToSolve = false;
-
- changeEntity(theEntity);
-
- if (myNeedToSolve) // the entity is changed
- {
- // Verify the entity is a point and add temporary constraint of permanency
- std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- theEntity);
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
- GeomDataAPI_Point2D>(theEntity);
- if (aPoint || aPoint2D)
- addTemporaryConstraintWhereDragged(theEntity);
- }
-
- // Restore flag of changes
- myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
-
- if (myNeedToSolve)
- updateRelatedConstraints(theEntity);
- }
-}
-
-// ============================================================================
-// Function: addTemporaryConstraintWhereDragged
-// Class: SketchSolver_ConstraintGroup
-// Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
-// which was moved by user
-// ============================================================================
-void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
- std::shared_ptr<ModelAPI_Attribute> theEntity,
- bool theAllowToFit)
-{
- // Find identifier of the entity
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
- myEntityAttrMap.find(theEntity);
- if (anEntIter == myEntityAttrMap.end())
- return;
-
- // Get identifiers of all dragged points
- std::set<Slvs_hEntity> aDraggedPntID;
- aDraggedPntID.insert(myTempPointWDrgdID);
- std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
- for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
- unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
- if (aConstrPos < myConstraints.size())
- aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
- }
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
- aDraggedPntID.insert(aConstrIter->ptA);
- // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
- if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
- continue; // the entity was not found in current set
-
- // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
- std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
- for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
- if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
- return; // the SLVS_C_WHERE_DRAGGED constraint already exists
- }
- if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
- return;
-
- // If this is a first dragged point, its parameters should be placed
- // into Slvs_System::dragged field to avoid system inconsistense
- if (myTempPointWhereDragged.empty() && theAllowToFit) {
- int anEntPos = Search(anEntIter->second, myEntities);
- Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
- for (int i = 0; i < 4; i++, aDraggedParam++)
- if (*aDraggedParam != 0)
- myTempPointWhereDragged.push_back(*aDraggedParam);
- myTempPointWDrgdID = myEntities[anEntPos].h;
- return;
- }
-
- // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
- Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
- myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
- myConstraints.push_back(aWDConstr);
- myTempConstraints.push_back(aWDConstr.h);
-}
-
-// ============================================================================
-// Function: removeTemporaryConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
-// resolving the set of constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
- const std::set<Slvs_hConstraint>& theRemoved)
-{
- std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
- for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
- aTmpConstrIter++) {
- if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
- continue;
- unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
- if (aConstrPos >= myConstraints.size())
- continue;
- myConstraints.erase(myConstraints.begin() + aConstrPos);
-
- // If the removing constraint has higher index, decrease the indexer
- if (*aTmpConstrIter == myConstrMaxID)
- myConstrMaxID--;
- }
- myTempConstraints.clear();
-
- // Clear basic dragged point
- myTempPointWhereDragged.clear();
- myTempPointWDrgdID = SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-// Function: removeConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: remove constraint and all unused entities
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
- if (anIterToRemove == myConstraintMap.end())
- return;
-
- std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
- // Remove constraint from the map
- myConstraintMap.erase(anIterToRemove);
-
- std::set<Slvs_hEntity> anEntToRemove;
-
- // Find unused entities
- std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
- for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
- int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
- Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
- myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
- for (int i = 0; i < 4; i++)
- if (aCnstEnt[i] != 0)
- anEntToRemove.insert(aCnstEnt[i]);
- myConstraints.erase(myConstraints.begin() + aConstrPos);
- if (*aCnstrToRemoveIter == myConstrMaxID)
- myConstrMaxID--;
- }
-
- // Find all entities which are based on these unused
- std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
- for ( ; anEntIter != myEntities.end(); anEntIter++)
- if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
- anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
- for (int i = 0; i < 4; i++)
- if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
- anEntToRemove.insert(anEntIter->h);
- for (int j = 0; j < 4; j++)
- if (anEntIter->point[j] != 0)
- anEntToRemove.insert(anEntIter->point[j]);
- break;
- }
- }
-
- // Find entities used by remaining constraints and remove them from the list to delete
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++) {
- Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
- ->entityB };
- for (int i = 0; i < 4; i++)
- if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) {
- anEntToRemove.erase(aEnts[i]);
- // remove from the list all points of current entity
- int aEntPos = Search(aEnts[i], myEntities);
- for (int j = 0; j < 4; j++)
- if (myEntities[aEntPos].point[j] != 0)
- anEntToRemove.erase(myEntities[aEntPos].point[j]);
- }
- }
-
- if (anEntToRemove.empty())
- return;
-
- // Remove unused entities
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
- myEntityAttrMap.begin();
- while (anEntAttrIter != myEntityAttrMap.end()) {
- if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
- anEntAttrIter;
- anEntAttrIter++;
- myEntityAttrMap.erase(aRemovedIter);
- } else
- anEntAttrIter++;
- }
- std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
- while (anEntFeatIter != myEntityFeatMap.end()) {
- if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
- std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
- anEntFeatIter++;
- myEntityFeatMap.erase(aRemovedIter);
- } else
- anEntFeatIter++;
- }
-
- removeEntitiesById(anEntToRemove);
-
- if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
- myCoincidentPoints.clear();
-}
-
-// ============================================================================
-// Function: removeEntitiesById
-// Class: SketchSolver_ConstraintGroup
-// Purpose: Removes specified entities and their parameters
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
-{
- std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
- for (; aRemIter != theEntities.rend(); aRemIter++) {
- unsigned int anEntPos = Search(*aRemIter, myEntities);
- if (anEntPos >= myEntities.size())
- continue;
- if (myEntities[anEntPos].param[0] != 0) {
- unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
- if (aParamPos >= myParams.size())
- continue;
- int aNbParams = 0;
- while (myEntities[anEntPos].param[aNbParams] != 0)
- aNbParams++;
- if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
- myParamMaxID -= aNbParams;
- myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
- if (*aRemIter == myEntityMaxID)
- myEntityMaxID--;
- }
- myEntities.erase(myEntities.begin() + anEntPos);
- myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
-
- // Remove entity's ID from the lists of conincident points
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
- aCoPtIter->erase(*aRemIter);
- }
-}
-
-// ============================================================================
-// Function: addCoincidentPoints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: add coincident point the appropriate list of such points
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
- const Slvs_hEntity& thePoint2)
-{
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
- while (aCoPtIter != myCoincidentPoints.end()) {
- bool isFound[2] = { // indicate which point ID was already in coincidence constraint
- aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
- != aCoPtIter->end(), };
- if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
- return false;
- if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
- if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them
- int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
- int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
- aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
- myCoincidentPoints.erase(aCoPtIter);
- aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
- aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
- continue;
- } else {
- aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
- aFirstFound = aCoPtIter;
- }
- }
- aCoPtIter++;
- }
- // No points were found, need to create new set
- if (aFirstFound == myCoincidentPoints.end()) {
- std::set<Slvs_hEntity> aNewSet;
- aNewSet.insert(thePoint1);
- aNewSet.insert(thePoint2);
- myCoincidentPoints.push_back(aNewSet);
- }
-
- return true;
-}
-
-// ============================================================================
-// Function: updateRelatedConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: emit the signal to update constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateRelatedConstraints(
- std::shared_ptr<ModelAPI_Attribute> theEntity) const
-{
- ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
- for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
- std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
- ->attributes(std::string());
-
- std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
- for (; anAttrIter != anAttributes.end(); anAttrIter++) {
- bool isUpd = (*anAttrIter == theEntity);
- std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(*anAttrIter);
- if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
- isUpd = true;
-
- if (isUpd) {
- static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
- ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
- break;
- }
- }
- }
-}
-
-void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature(
- std::shared_ptr<ModelAPI_Feature> theFeature) const
-{
- ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
- for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
- std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
- ->attributes(std::string());
-
- std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
- for (; anAttrIter != anAttributes.end(); anAttrIter++) {
- std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(*anAttrIter);
- if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
- static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
- ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
- break;
- }
- }
- }
-}
-
-// ============================================================================
-// Function: updateFilletConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: change fillet arc to be less than 180 degree
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateFilletConstraints()
-{
- ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
- for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
- if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
- AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
- if (!aFilletRefList)
- return;
- ObjectPtr anArcObj = aFilletRefList->object(2);
- std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
- double aCosA = aStart->x() - aCenter->x();
- double aSinA = aStart->y() - aCenter->y();
- double aCosB = aEnd->x() - aCenter->x();
- double aSinB = aEnd->y() - aCenter->y();
- if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
- anArcObj->data()->blockSendAttributeUpdated(true);
- double x = aStart->x();
- double y = aStart->y();
- aStart->setValue(aEnd->x(), aEnd->y());
- aEnd->setValue(x, y);
- // Update constraint data
- changeFilletConstraint(aConstrIter->first);
- anArcObj->data()->blockSendAttributeUpdated(false);
- }
- }
-}
-
-// ============================================================================
-// Function: makeMirrorEntity
-// Class: SketchSolver_ConstraintGroup
-// Purpose: change entities parameters to make them symmetric relating to the mirror line
-// ============================================================================
-void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase,
- const Slvs_hEntity& theMirror,
- const Slvs_hEntity& theMirrorLine)
-{
- Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
- Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
- int i = 0;
- if (aBase.type != SLVS_E_ARC_OF_CIRCLE) {
- while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
- makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
- i++;
- }
- } else {
- // swap mirroring first and last points of an arc
- makeMirrorEntity(aBase.point[0], aMirror.point[0], theMirrorLine);
- makeMirrorEntity(aBase.point[1], aMirror.point[2], theMirrorLine);
- makeMirrorEntity(aBase.point[2], aMirror.point[1], theMirrorLine);
- }
- if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
- Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
- std::shared_ptr<GeomAPI_XY> aLinePoints[2];
- for (i = 0; i < 2; i++) {
- Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
- int aParamPos = Search(aPoint.param[0], myParams);
- aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
- }
- int aBaseParamPos = Search(aBase.param[0], myParams);
- int aMirrorParamPos = Search(aMirror.param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
-
- // direction of a mirror line
- std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
- // orthogonal direction
- aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-
- std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
- double aDist = aVec->dot(aDir->xy());
- std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-
- myParams[aMirrorParamPos].val = aMirrorPoint->x();
- myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
- }
-}
-
-// ============================================================================
-// Function: changeMirrorPoints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: creates/updates mirror constraint for two points
-// ============================================================================
-Slvs_hConstraint SketchSolver_ConstraintGroup::changeMirrorPoints(
- const Slvs_hEntity& theBasePoint,
- const Slvs_hEntity& theMirrorPoint,
- const Slvs_hEntity& theMirrorLine,
- std::vector<Slvs_Constraint>& thePrevConstr,
- std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror)
-{
- std::map<Slvs_hEntity, Slvs_hEntity>::iterator aMapIter = thePrevMirror.find(theBasePoint);
- if (aMapIter != thePrevMirror.end()) {
- thePrevMirror.erase(aMapIter);
- std::vector<Slvs_Constraint>::iterator anIter = thePrevConstr.begin();
- for (; anIter != thePrevConstr.end(); anIter++)
- if (anIter->ptA == theBasePoint) {
- if (anIter->ptB != theMirrorPoint) {
- int aConstrInd = Search(anIter->h, myConstraints);
- myConstraints[aConstrInd].ptB = theMirrorPoint;
- myConstraints[aConstrInd].entityA = theMirrorLine;
- }
- Slvs_hConstraint aResult = anIter->h;
- thePrevConstr.erase(anIter);
- return aResult;
- }
- }
-
- // Newly created constraint
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_SYMMETRIC_LINE, myWorkplane.h, 0.0,
- theBasePoint, theMirrorPoint, theMirrorLine, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- return aConstraint.h;
-}
-
-
-// ============================================================================
-// Function: calculateMiddlePoint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: calculates middle point on line or arc
-// ============================================================================
-void SketchSolver_ConstraintGroup::calculateMiddlePoint(
- const Slvs_hEntity& theEntity,
- double& theX,
- double& theY) const
-{
- int anInd = Search(theEntity, myEntities);
- if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
- int aLineParams[2];
- for (int i = 0; i < 2; i++) {
- int aPtPos = Search(myEntities[anInd].point[i], myEntities);
- aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
- }
- theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
- theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
- } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
- double anArcPoint[3][2];
- for (int i = 0; i < 3; i++) {
- int aPtPos = Search(myEntities[anInd].point[i], myEntities);
- int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
- anArcPoint[i][0] = myParams[anArcParam].val;
- anArcPoint[i][1] = myParams[1 + anArcParam].val;
- }
- // project last point of arc on the arc
- double x = anArcPoint[1][0] - anArcPoint[0][0];
- double y = anArcPoint[1][1] - anArcPoint[0][1];
- double aRad = sqrt(x*x + y*y);
- x = anArcPoint[2][0] - anArcPoint[0][0];
- y = anArcPoint[2][1] - anArcPoint[0][1];
- double aNorm = sqrt(x*x + y*y);
- if (aNorm >= tolerance) {
- anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
- anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
- }
-
- x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
- y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
- aNorm = sqrt(x*x + y*y);
- if (aNorm >= tolerance) {
- x *= aRad / aNorm;
- y *= aRad / aNorm;
- } else { // obtain orthogonal direction
- x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
- y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
- }
- theX = anArcPoint[0][0] + x;
- theY = anArcPoint[0][1] + y;
- }
-}
-
-
-// ========================================================
-// ========= Auxiliary functions ===============
-// ========================================================
-
-template<typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
-{
- int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
- int aVecSize = theEntities.size();
- while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
- aResIndex--;
- while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
- aResIndex++;
- if (aResIndex == -1)
- aResIndex = aVecSize;
- return aResIndex;
-}
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintGroup.h
-// Created: 27 May 2014
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintGroup_H_
-#define SketchSolver_ConstraintGroup_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Feature.h>
-
-
-#include <memory>
-#include <list>
-#include <map>
-#include <vector>
-#include <set>
-
-typedef std::map< std::shared_ptr<SketchPlugin_Constraint>, std::vector<Slvs_hConstraint> >
- ConstraintMap;
-
-/** \class SketchSolver_ConstraintGroup
- * \ingroup Plugins
- * \brief Keeps the group of constraints which based on the same entities
- */
-class SketchSolver_ConstraintGroup
-{
- public:
- /** \brief New group based on specified workplane.
- * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
- * \remark Type of theSketch is not verified inside
- */
- SketchSolver_ConstraintGroup(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
-
- ~SketchSolver_ConstraintGroup();
-
- /// \brief Returns group's unique identifier
- inline const Slvs_hGroup& getId() const
- {
- return myID;
- }
-
- /// \brief Returns true if the group has no constraints yet
- inline bool isEmpty() const
- {
- return myConstraints.empty();
- }
-
- /// \brief Check for valid sketch data
- inline bool isWorkplaneValid() const
- {
- return mySketch->data() && mySketch->data()->isValid();
- }
-
- /** \brief Adds or updates a constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Adds or updates a rigid constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Adds or updates a mirror constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Adds or updates a fillet constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeFilletConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Verifies the feature attributes are used in this group
- * \param[in] theFeature constraint or any other object for verification of interaction
- * \return \c true if some of attributes are used in current group
- */
- bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
-
- /** \brief Verifies the specified feature is equal to the base workplane for this group
- * \param[in] theWorkplane the feature to be compared with base workplane
- * \return \c true if workplanes are the same
- */
- bool isBaseWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const;
-
- /// Returns the current workplane
- std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
- {
- return mySketch;
- }
-
- /** \brief Update parameters of workplane. Should be called when Update event is coming.
- * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
- */
- bool updateWorkplane();
-
- /** \brief If the entity is in this group it will updated
- * \param[in] theEntity attribute, which values should update SolveSpace entity
- */
- void updateEntityIfPossible(std::shared_ptr<ModelAPI_Attribute> theEntity);
-
- /** \brief Searches invalid features and constraints in the group and avoids them
- * \return \c true if the group several constraints were removed
- */
- bool updateGroup();
-
- /** \brief Add specified group to this one
- * \param[in] theGroup group of constraint to be added
- */
- void mergeGroups(const SketchSolver_ConstraintGroup& theGroup);
-
- /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
- * \param[out] theCuts enlarge this list by newly created groups
- */
- void splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts);
-
- /** \brief Start solution procedure if necessary and update attributes of features
- * \return \c false when no need to solve constraints
- */
- bool resolveConstraints();
-
- /** \brief Searches the constraints built on the entity and emit the signal to update them
- * \param[in] theEntity attribute of the constraint
- */
- void updateRelatedConstraints(std::shared_ptr<ModelAPI_Attribute> theEntity) const;
- /** \brief Searches the constraints built on the entity and emit the signal to update them
- * \param[in] theFeature feature of the constraint
- */
- void updateRelatedConstraintsFeature(std::shared_ptr<ModelAPI_Feature> theFeature) const;
-
- /** \brief Adds or updates an entity in 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 changed entity or 0 if entity could not be changed
- */
- Slvs_hEntity changeEntity(std::shared_ptr<ModelAPI_Attribute> theEntity);
- Slvs_hEntity changeEntityFeature(std::shared_ptr<ModelAPI_Feature> theEntity);
-
-protected:
- /** \brief Adds or updates a normal in 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] theNorm attribute for the normal (used to identify newly created entity)
- * \return identifier of created or updated normal
- */
- Slvs_hEntity changeNormal(std::shared_ptr<ModelAPI_Attribute> theDirX,
- std::shared_ptr<ModelAPI_Attribute> theNorm);
-
- /** \brief Adds or updates a parameter in the group
- * \param[in] theParam the value of parameter
- * \param[in] thePrmIter the cell in the list of parameters which should be changed
- * (the iterator will be increased if it does not reach the end of the list)
- * \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
- */
- Slvs_hParam changeParameter(double theParam,
- std::vector<Slvs_Param>::iterator& thePrmIter);
-
- /** \brief Removes specified entities and their parameters
- * \param[in] theEntities list of IDs of the entities to be removed
- */
- void removeEntitiesById(const std::set<Slvs_hEntity>& theEntities);
-
- /** \brief Removes constraints from the group
- * \param[in] theConstraint constraint to be removed
- */
- void removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Change values of attribute by parameters received from SolveSpace solver
- * \param[in,out] theAttribute pointer to the attribute to be changed
- * \param[in] theEntityID identifier of SolveSpace entity, which contains updated data
- * \return \c true if the attribute's value has changed
- */
- bool updateAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
- const Slvs_hEntity& theEntityID);
-
- /// \brief Update arc of fillet to be less than 180 degree
- void updateFilletConstraints();
-
- /** \brief Adds a constraint for a point which should not be changed during computations
- * \param[in] theEntity the base for the constraint
- * \param[in] theAllowToFit this flag shows that the entity may be placed into
- * the 'dragged' field of SolveSpace solver, so this entity
- * may be changed a little during solution
- */
- void addTemporaryConstraintWhereDragged(std::shared_ptr<ModelAPI_Attribute> theEntity,
- bool theAllowToFit = true);
-
- /** \brief Remove all temporary constraint after computation finished
- * \param[in] theRemoved indexes of constraints to be removed. If empty, all temporary constraints should be deleted
- */
- void removeTemporaryConstraints(const std::set<Slvs_hConstraint>& theRemoved =
- std::set<Slvs_hConstraint>());
-
- 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, \c false if workplane parameters are not consistent
- */
- bool addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
-
- /** \brief Add the entities of constraint for points coincidence into the appropriate list
- * \param[in] thePoint1 identifier of the first point
- * \param[in] thePoint2 identifier of the second point
- * \return \c true if the points are added successfully, and
- * \c false if the constraint is the extra one (should not be created in SolveSpace)
- */
- bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
-
- /** \brief Verifies and changes parameters of constriant,
- * e.g. sign of the distance between line and point
- * \param[in,out] theConstraint SolveSpace constraint to be verified
- */
- void checkConstraintConsistence(Slvs_Constraint& theConstraint);
-
- /** \brief Change entities parameters to make them symmetric relating to the mirror line
- * \param[in] theBase entity to be mirrored
- * \param[in] theMirror a mirrored object
- * \param[in] theMirrorLine a mirror line
- */
- void makeMirrorEntity(const Slvs_hEntity& theBase,
- const Slvs_hEntity& theMirror,
- const Slvs_hEntity& theMirrorLine);
-
- /** \brief Creates/updates mirror constraint for two points
- * \param[in] theBasePoint ID of initial point
- * \param[in] theMirrorPoint ID of the mirroring point
- * \param[in] theMirrorLine ID of the mirror line
- * \param[in] thePrevConstr list of previous constraints (the items will be deleted from the list if they are updated)
- * \param[in,out] thePrevMirror list of previously mirrored points (the items will be deleted from the list if they are updated)
- * \return ID of created/updated constraint
- */
- Slvs_hConstraint changeMirrorPoints(const Slvs_hEntity& theBasePoint,
- const Slvs_hEntity& theMirrorPoint,
- const Slvs_hEntity& theMirrorLine,
- std::vector<Slvs_Constraint>& thePrevConstr,
- std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror);
-
- /** \brief Calculates middle point on line or arc
- * \param[in] theEntity identifier of line or arc
- * \param[out] theX X value of middle point
- * \param[out] theY Y value of middle point
- */
- void calculateMiddlePoint(const Slvs_hEntity& theEntity,
- double& theX, double& theY) const;
-
- 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 (not equal to myParams size)
- std::vector<Slvs_Entity> myEntities; ///< List of entities of the constaints
- std::vector<bool> myEntOfConstr; ///< Flags show that certain entity used in constraints
- 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 (not equal to myConstraints size)
- bool myNeedToSolve; ///< Indicator that something changed in the group and constraint system need to be rebuilt
-
- SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
-
- std::vector<Slvs_hParam> myTempPointWhereDragged; ///< Parameters of one of the points which is moved by user
- Slvs_hEntity myTempPointWDrgdID; ///< Identifier of such point
- std::list<Slvs_hConstraint> myTempConstraints; ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
-
- // SketchPlugin entities
- std::shared_ptr<ModelAPI_CompositeFeature> mySketch; ///< Equivalent to workplane
- ConstraintMap myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity> myEntityAttrMap; ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities
- std::map<FeaturePtr, Slvs_hEntity> myEntityFeatMap; ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities
-
- // Conincident items
- std::vector<std::set<Slvs_hEntity> > myCoincidentPoints; ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
- std::set<std::shared_ptr<SketchPlugin_Constraint> > myExtraCoincidence; ///< Additional coincidence constraints which are not necessary (coincidence between points already done
- ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed
-};
-
-#endif
--- /dev/null
+#include <SketchSolver_ConstraintLength.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+
+void SketchSolver_ConstraintLength::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntities;
+ getAttributes(aValue, anEntities);
+ if (!myErrorMsg.empty())
+ return;
+
+ // Check the entity is a line
+ Slvs_Entity aLine = myStorage->getEntity(anEntities[2]);
+ if (aLine.type != SLVS_E_LINE_SEGMENT){
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
+ }
+
+ Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+ getType(), myGroup->getWorkplaneId(), aValue,
+ aLine.point[0], aLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ adjustConstraint();
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintLength.h
+// Created: 31 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintLength_H_
+#define SketchSolver_ConstraintLength_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintLength
+ * \ingroup Plugins
+ * \brief Convert length constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintLength : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintLength(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_PT_PT_DISTANCE; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+};
+
+#endif
// Author: Artem ZHIDKOV
#include "SketchSolver_ConstraintManager.h"
-#include <SketchSolver_ConstraintGroup.h>
#include <Events_Loop.h>
#include <ModelAPI_AttributeDouble.h>
#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
std::shared_ptr<SketchPlugin_Feature> aSFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
if (aSFeature)
- updateEntity(aSFeature);
+ moveEntity(aSFeature);
}
} else {
std::set<ObjectPtr>::iterator aFeatIter;
}
}
// then get anything but not the sketch
- // at first, add coincidence constraints, because they may be used by other constraints
+ std::set<ObjectPtr> aComplexConstraints;
+ // fillet and mirror an tangency constraints will be processed later
for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
std::shared_ptr<SketchPlugin_Feature> aFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
- if (!aFeature || aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
+ if (!aFeature)
+ continue;
+ if (aFeature->getKind() == SketchPlugin_ConstraintFillet::ID() ||
+ aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() ||
+ aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+ aComplexConstraints.insert(aFeature);
continue;
+ }
changeConstraintOrEntity(aFeature);
}
- // after that, add all features except coincidence
- for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+ // processing remain constraints
+ aFeatIter = aComplexConstraints.begin();
+ for (; aFeatIter != aComplexConstraints.end(); aFeatIter++) {
std::shared_ptr<SketchPlugin_Feature> aFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
- if (!aFeature /*|| aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()*/)
+ if (!aFeature)
continue;
changeConstraintOrEntity(aFeature);
}
break;
if (aFGrIter != aFeatureGroups.end()) {
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
- std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+ std::vector<SketchSolver_Group*> aSeparatedGroups;
while (aGroupIter != myGroups.end()) {
if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
delete *aGroupIter;
aGroupIter = myGroups.begin() + aShift;
continue;
}
- if ((*aGroupIter)->updateGroup()) { // some constraints were removed, try to split the group
+ if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
(*aGroupIter)->splitGroup(aSeparatedGroups);
}
aGroupIter++;
// Class: SketchSolver_Session
// Purpose: update workplane by given parameters of the sketch
// ============================================================================
-bool SketchSolver_ConstraintManager::changeWorkplane(
- std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
+bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr 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;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
isUpdated = true;
}
// If the workplane is not updated, so this is a new workplane
if (!isUpdated) {
- SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
+ SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
// Verify that the group is created successfully
if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
delete aNewGroup;
std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
if (!aWP)
return false;
- SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
+ SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
if (!aGroup->changeConstraint(aConstraint)) {
delete aGroup;
return false;
return true;
} else if (aGroups.size() == 1) { // Only one group => add feature into it
Slvs_hGroup aGroupId = *(aGroups.begin());
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->getId() == aGroupId) {
// If the group is empty, the feature is not added (the constraint only)
if (!aConstraint && !(*aGroupIter)->isEmpty())
- return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+ return (*aGroupIter)->updateFeature(theFeature);
return (*aGroupIter)->changeConstraint(aConstraint);
}
} else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
// Search first group
- std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
if ((*aFirstGroupIter)->getId() == *aGroupsIter)
break;
return false;
// Append other groups to the first one
- std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+ std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
if ((*anOtherGroupIter)->getId() == *aGroupsIter)
if (aConstraint)
return (*aFirstGroupIter)->changeConstraint(aConstraint);
- return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+ return (*aFirstGroupIter)->updateFeature(theFeature);
}
// Something goes wrong
}
// ============================================================================
-// Function: updateEntity
+// Function: moveEntity
// Class: SketchSolver_Session
-// Purpose: update any element on the sketch, which is used by constraints
+// Purpose: update element moved on the sketch, which is used by constraints
// ============================================================================
-void SketchSolver_ConstraintManager::updateEntity(
+void SketchSolver_ConstraintManager::moveEntity(
std::shared_ptr<SketchPlugin_Feature> theFeature)
{
- // Create list of attributes depending on type of the feature
- std::vector<std::string> anAttrList;
- const std::string& aFeatureKind = theFeature->getKind();
- // Point
- if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
- anAttrList.push_back(SketchPlugin_Point::COORD_ID());
- // Line
- else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
- anAttrList.push_back(SketchPlugin_Line::START_ID());
- anAttrList.push_back(SketchPlugin_Line::END_ID());
- }
- // Circle
- else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
- anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
- anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
- }
- // Arc
- else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
- anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
- anAttrList.push_back(SketchPlugin_Arc::START_ID());
- anAttrList.push_back(SketchPlugin_Arc::END_ID());
- }
- /// \todo Other types of features should be implemented
-
- // Check changing of feature's attributes (go through the groups and search usage of the attributes)
- std::vector<std::string>::const_iterator anAttrIter;
- for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
- if ((*aGroupIter)->isEmpty())
- continue;
- std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
- ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
- (*aGroupIter)->updateEntityIfPossible(anAttribute);
- }
- }
-
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (!(*aGroupIter)->isEmpty())
- (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
+ std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+ for (; aGroupIt != myGroups.end(); aGroupIt++)
+ if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+ (*aGroupIt)->moveFeature(theFeature);
}
// ============================================================================
{
std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
- SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
- std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+ SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
+ std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
if (!(*aGroupIter)->isEmpty())
// Already verified workplanes
std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
- std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
if (aVerified.find(aWP) != aVerified.end())
Events_Loop::loop()->setFlushed(anUpdateEvent, false);
}
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->resolveConstraints())
needToUpdate = true;
#include "SketchSolver.h"
#include <SketchSolver_Solver.h>
-#include <SketchSolver_ConstraintGroup.h>
+#include <SketchSolver_Group.h>
#include <Events_Listener.h>
#include <SketchPlugin_Constraint.h>
* \return \c true if the workplane changed successfully
* \remark Type of theSketch is not verified inside
*/
- bool changeWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
+ bool changeWorkplane(CompositeFeaturePtr theSketch);
/** \brief Removes a workplane from the manager.
* All groups based on such workplane will be removed too.
*/
bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
- /** \brief Updates entity which is neither workplane nor constraint
+ /** \brief Updates entity which is moved in GUI
* \param[in] theFeature entity to be updated
*/
- void updateEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
+ void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
/** \brief Goes through the list of groups and solve the constraints
* \param theForceUpdate flushes the update event in any case: something changed or not
private:
static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality
- std::vector<SketchSolver_ConstraintGroup*> myGroups; ///< Groups of constraints
+ std::vector<SketchSolver_Group*> myGroups; ///< Groups of constraints
/// true if computation is performed and all "updates" are generated by this algo
/// and needs no recomputation
bool myIsComputed;
--- /dev/null
+#include <SketchSolver_ConstraintMirror.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+
+
+void SketchSolver_ConstraintMirror::getAttributes(
+ Slvs_Entity& theMirrorLine,
+ std::vector<Slvs_Entity>& theBaseEntities,
+ std::vector<Slvs_Entity>& theMirrorEntities)
+{
+ DataPtr aData = myBaseConstraint->data();
+ AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ int aType = SLVS_E_UNKNOWN; // type of created entity
+ Slvs_hEntity anEntity = myGroup->getAttributeId(aMirLineAttr);
+ if (anEntity == SLVS_E_UNKNOWN)
+ anEntity = changeEntity(aMirLineAttr, aType);
+ theMirrorLine = myStorage->getEntity(anEntity);
+
+ // Create SolveSpace entity for all features
+ AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
+ myNumberOfObjects = aMirroredRefList->size();
+ if (!aBaseRefList || !aMirroredRefList) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
+ return;
+ }
+
+ std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+ std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+
+ FeaturePtr aFeature;
+ ResultConstructionPtr aRC;
+ for (int i = 0; i < 2; i++) {
+ std::list<ObjectPtr>::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin();
+ std::list<ObjectPtr>::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end();
+ std::vector<Slvs_Entity>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
+ for ( ; anIter != aEndIter; anIter++) {
+ aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIter);
+ aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*anIter);
+ if (!aFeature)
+ continue;
+
+ anEntity = changeEntity(aFeature, aType);
+ aList->push_back(myStorage->getEntity(anEntity));
+ }
+ }
+
+ if (theBaseEntities.size() > theMirrorEntities.size())
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+}
+
+void SketchSolver_ConstraintMirror::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ Slvs_Entity aMirrorLine;
+ std::vector<Slvs_Entity> aBaseList;
+ std::vector<Slvs_Entity> aMirrorList;
+ getAttributes(aMirrorLine, aBaseList, aMirrorList);
+ if (!myErrorMsg.empty())
+ return;
+
+ if (aBaseList.size() != aMirrorList.size()) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
+ return;
+ }
+
+ Slvs_Constraint aConstraint;
+ // Get coordinates of mirror line points for speed up
+ double aStartEnd[4];
+ for (int i = 0; i < 2; i++) {
+ Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
+ for (int j = 0; j < 2; j++)
+ aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
+ }
+
+ std::vector<Slvs_Entity>::iterator aBaseIter = aBaseList.begin();
+ std::vector<Slvs_Entity>::iterator aMirrorIter = aMirrorList.begin();
+ for (; aBaseIter != aBaseList.end(); aBaseIter++, aMirrorIter++) {
+ // Make aMirrorEnt parameters to be symmetric with aBaseEnt
+ makeMirrorEntity(*aBaseIter, *aMirrorIter, aStartEnd);
+
+ if (aBaseIter->type == SLVS_E_POINT_IN_2D) {
+ aConstraint = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+ 0.0, aBaseIter->h, aMirrorIter->h, aMirrorLine.h, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ } else if (aBaseIter->type == SLVS_E_LINE_SEGMENT) {
+ for (int i = 0; i < 2; i++) {
+ aConstraint = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
+ aBaseIter->point[i], aMirrorIter->point[i], aMirrorLine.h, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ }
+ } else if (aBaseIter->type == SLVS_E_CIRCLE) {
+ aConstraint = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
+ aBaseIter->point[0], aMirrorIter->point[0], aMirrorLine.h, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ // Additional constraint for equal radii
+ Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(),
+ 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseIter->h, aMirrorIter->h);
+ anEqRadConstr.h = myStorage->addConstraint(anEqRadConstr);
+ mySlvsConstraints.push_back(anEqRadConstr.h);
+ } else if (aBaseIter->type == SLVS_E_ARC_OF_CIRCLE) {
+ // Workaround to avoid problems in SolveSpace.
+ // The symmetry of two arcs will be done using symmetry of three points on these arcs:
+ // start point, end point, and any other point on the arc
+ Slvs_hEntity aBaseArcPoints[3] = {
+ aBaseIter->point[1],
+ aBaseIter->point[2],
+ SLVS_E_UNKNOWN};
+ Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
+ aMirrorIter->point[2],
+ aMirrorIter->point[1],
+ SLVS_E_UNKNOWN};
+
+ Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter};
+ Slvs_hEntity aBothMiddlePoints[2];
+ for (int i = 0; i < 2; i++) {
+ double x, y;
+ calculateMiddlePoint(aBothArcs[i], 0.5, x, y);
+ Slvs_Param aParamX = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), x);
+ Slvs_Param aParamY = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), y);
+ aParamX.h = myStorage->addParameter(aParamX);
+ aParamY.h = myStorage->addParameter(aParamY);
+ Slvs_Entity aPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, myGroup->getId(),
+ myGroup->getWorkplaneId(), aParamX.h, aParamY.h);
+ aBothMiddlePoints[i] = myStorage->addEntity(aPoint);
+ // additional constraint point-on-curve
+ Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_CIRCLE, myGroup->getWorkplaneId(),
+ 0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN);
+ aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr);
+ mySlvsConstraints.push_back(aPonCircConstr.h);
+ }
+
+ aBaseArcPoints[2] = aBothMiddlePoints[0];
+ aMirrorArcPoints[2] = aBothMiddlePoints[1];
+ for (int ind = 0; ind < 3; ind++) {
+ Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
+ aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLine.h, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ }
+ }
+ }
+
+ // Set the mirror line unchanged during constraint recalculation
+ for (int i = 0; i < 2; i++) {
+ aConstraint = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
+ aMirrorLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ }
+}
+
+
+void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (!theConstraint || theConstraint == myBaseConstraint) {
+ AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
+ if (aMirroredRefList->size() != myNumberOfObjects) {
+ remove(myBaseConstraint);
+ process();
+ }
+ }
+ SketchSolver_Constraint::update();
+}
+
+bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint)
+ return false;
+ bool isFullyRemoved = true;
+ std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++)
+ isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+ mySlvsConstraints.clear();
+
+ if (isFullyRemoved) {
+ myFeatureMap.clear();
+ myAttributeMap.clear();
+ myValueMap.clear();
+ } else
+ cleanRemovedEntities();
+ return true;
+}
+
+void SketchSolver_ConstraintMirror::makeMirrorEntity(
+ const Slvs_Entity& theBase,
+ const Slvs_Entity& theMirror,
+ const double theMirrorLine[]) const
+{
+ Slvs_hEntity aBasePoint[4];
+ Slvs_hEntity aMirrorPoint[4];
+ for (int i = 0; i < 4; i++) {
+ aBasePoint[i] = theBase.point[i];
+ aMirrorPoint[i] = theMirror.point[i];
+ }
+ if (theBase.type == SLVS_E_ARC_OF_CIRCLE) {
+ Slvs_hEntity aTmp = aMirrorPoint[2];
+ aMirrorPoint[2] = aMirrorPoint[1];
+ aMirrorPoint[1] = aTmp;
+ }
+ if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) {
+ aBasePoint[0] = theBase.h;
+ aMirrorPoint[0] = theMirror.h;
+ }
+
+ // Mirror line parameters
+ std::shared_ptr<GeomAPI_XY> aLinePoints[2];
+ for (int i = 0; i < 2; i++)
+ aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
+ new GeomAPI_XY(theMirrorLine[2*i], theMirrorLine[2*i+1]));
+ // direction of a mirror line
+ std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
+ new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
+ // orthogonal direction
+ aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
+
+ for (int i = 0; i < 4; i++) {
+ if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN)
+ continue;
+ Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]);
+ double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val;
+ double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val;
+ std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aBaseX, aBaseY));
+
+ std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
+ new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
+ double aDist = aVec->dot(aDir->xy());
+ aPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
+
+ Slvs_Entity aMirrorEnt = myStorage->getEntity(aMirrorPoint[i]);
+ Slvs_Param aParam = Slvs_MakeParam(aMirrorEnt.param[0], myGroup->getId(), aPoint->x());
+ myStorage->updateParameter(aParam);
+ aParam = Slvs_MakeParam(aMirrorEnt.param[1], myGroup->getId(), aPoint->y());
+ myStorage->updateParameter(aParam);
+ }
+}
+
+void SketchSolver_ConstraintMirror::adjustConstraint()
+{
+ // Search mirror between middle points on the arcs and recompute their coordinates
+ std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
+ if (aPonCirc.empty())
+ return;
+
+ AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ ResultConstructionPtr aRC =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aMirLineAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aMirLineAttr->object());
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aMirLineIter = myFeatureMap.find(aFeature);
+ if (aMirLineIter == myFeatureMap.end())
+ return;
+ Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second);
+
+ double aStartEnd[4];
+ for (int i = 0; i < 2; i++) {
+ Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
+ for (int j = 0; j < 2; j++)
+ aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
+ }
+
+ Slvs_Constraint aMirror;
+ std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
+ for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
+ aMirror = myStorage->getConstraint(*aConstrIter);
+ if (aMirror.type != SLVS_C_SYMMETRIC_LINE)
+ continue;
+ Slvs_Constraint aPonCircA, aPonCircB;
+ aPonCircA.h = SLVS_E_UNKNOWN;
+ aPonCircB.h = SLVS_E_UNKNOWN;
+ std::list<Slvs_Constraint>::iterator aPtIter = aPonCirc.begin();
+ for (; aPtIter != aPonCirc.end(); aPtIter++) {
+ if (aMirror.ptA == aPtIter->ptA)
+ aPonCircA = *aPtIter;
+ if (aMirror.ptB == aPtIter->ptA)
+ aPonCircB = *aPtIter;
+ }
+ if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN)
+ continue;
+
+ // Calculate middle point for base arc and mirrored point on mirror arc
+ Slvs_Entity aBaseArc = myStorage->getEntity(aPonCircA.entityA);
+ Slvs_Entity aBasePoint = myStorage->getEntity(aPonCircA.ptA);
+ Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]);
+ Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]);
+ calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val);
+ myStorage->updateParameter(aParamX);
+ myStorage->updateParameter(aParamY);
+ Slvs_Entity aMirrorPoint = myStorage->getEntity(aPonCircB.ptA);
+ makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd);
+ }
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintMirror.h
+// Created: 1 Apr 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintMirror_H_
+#define SketchSolver_ConstraintMirror_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintMirror
+ * \ingroup Plugins
+ * \brief Convert fillet constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintMirror : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintMirror(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint),
+ myNumberOfObjects(0)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_SYMMETRIC_LINE; }
+
+ /// \brief Update constraint
+ virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+ { /* do nothing here */ }
+
+ /// \brief Generate list of entities of mirror constraint
+ /// \param[out] theMirrorLine entity corresponding to mirror line
+ /// \param[out] theBaseEntities list of entities to mirror
+ /// \param[out] theMirrorEntities list of mirrored entities
+ void getAttributes(Slvs_Entity& theMirrorLine,
+ std::vector<Slvs_Entity>& theBaseEntities,
+ std::vector<Slvs_Entity>& theMirrorEntities);
+
+ /// \brief This method is used in derived objects to check consistence of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint();
+
+private:
+ /// \brief Change parameters of entities to be symmetric relative a line,
+ /// given by array of parameters (coordinates of first and last points)
+ void makeMirrorEntity(const Slvs_Entity& theBase,
+ const Slvs_Entity& theMirror,
+ const double theMirrorLine[]) const;
+
+private:
+ size_t myNumberOfObjects; ///< number of previously mirrored objects
+};
+
+#endif
--- /dev/null
+#include <SketchSolver_ConstraintRigid.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_ConstraintRigid.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+
+SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
+ : SketchSolver_Constraint(),
+ myBaseFeature(theFeature)
+{
+ process();
+}
+
+void SketchSolver_ConstraintRigid::process()
+{
+ cleanErrorMsg();
+ if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntities;
+ getAttributes(aValue, anEntities);
+ if (!myErrorMsg.empty())
+ return;
+
+ Slvs_Constraint aConstraint;
+ std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
+ bool isEmpty = aConstrIter == mySlvsConstraints.end();
+
+ // Check the fixed entity is an arc
+ if (isEmpty) {
+ if (!myFeatureMap.empty() && myFeatureMap.begin()->first->getKind() == SketchPlugin_Arc::ID()) {
+ Slvs_Entity anArc = myStorage->getEntity(myFeatureMap.begin()->second);
+ fixArc(anArc);
+ return;
+ }
+ }
+
+ std::vector<Slvs_hEntity>::const_iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++) {
+ if (*anEntIter == SLVS_E_UNKNOWN)
+ continue;
+ Slvs_hConstraint aConstrID = myStorage->isPointFixed(*anEntIter);
+ bool isForceUpdate = (aConstrID != SLVS_E_UNKNOWN && !myBaseConstraint);
+ if (isEmpty && !isForceUpdate) { // create new constraint
+ if (aConstrID != SLVS_E_UNKNOWN)
+ continue; // the coincident point is already fixed
+ aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+ aValue, *anEntIter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ if (!myBaseConstraint)
+ myStorage->addTemporaryConstraint(aConstraint.h);
+ } else { // update already existent constraint
+ if (aConstrID == SLVS_E_UNKNOWN || myBaseConstraint)
+ aConstrID = *aConstrIter;
+ aConstraint = myStorage->getConstraint(aConstrID);
+ aConstraint.ptA = *anEntIter;
+ myStorage->addConstraint(aConstraint);
+ if (!myBaseConstraint)
+ myStorage->addTemporaryConstraint(aConstraint.h);
+ if (!isEmpty) {
+ aConstrIter++;
+ isEmpty = aConstrIter == mySlvsConstraints.end();
+ }
+ }
+ }
+
+ if (!myFeatureMap.empty() && myFeatureMap.begin()->first->getKind() == SketchPlugin_Circle::ID()) {
+ // Fix radius of a circle
+ AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID()));
+ aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER, myGroup->getWorkplaneId(),
+ aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ if (!myBaseConstraint)
+ myStorage->addTemporaryConstraint(aConstraint.h);
+ }
+}
+
+
+void SketchSolver_ConstraintRigid::getAttributes(
+ double& theValue,
+ std::vector<Slvs_hEntity>& theAttributes)
+{
+ theValue = 0.0;
+ int aType = SLVS_E_UNKNOWN; // type of created entity
+ Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
+ if (myBaseConstraint) {
+ // Get the attribute of constraint
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
+ if (!aRefAttr || !aRefAttr->isInitialized()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ anEntityID = myGroup->getAttributeId(aRefAttr);
+ if (anEntityID == SLVS_E_UNKNOWN)
+ anEntityID = changeEntity(aRefAttr, aType);
+ } else {
+ anEntityID = myGroup->getFeatureId(myBaseFeature);
+ if (anEntityID == SLVS_E_UNKNOWN)
+ anEntityID = changeEntity(myBaseFeature, aType);
+ else
+ myFeatureMap[myBaseFeature] = anEntityID;
+ }
+
+ // Check the entity is complex
+ Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
+ if (anEntity.point[0] != SLVS_E_UNKNOWN) {
+ for (int i = 0; i < 4 && anEntity.point[i]; i++)
+ theAttributes.push_back(anEntity.point[i]);
+ } else // simple entity
+ theAttributes.push_back(anEntityID);
+}
+
+void SketchSolver_ConstraintRigid::adjustConstraint()
+{
+ if (myFeatureMap.empty() || (
+ myFeatureMap.begin()->first->getKind() != SketchPlugin_Arc::ID() &&
+ myFeatureMap.begin()->first->getKind() != SketchPlugin_Circle::ID()))
+ return;
+ FeaturePtr aFeature = myFeatureMap.begin()->first;
+
+ // Search radius constraints and update them
+ Slvs_Constraint aConstraint;
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++) {
+ aConstraint = myStorage->getConstraint(*aCIter);
+ if (aConstraint.type != SLVS_C_DIAMETER)
+ continue;
+ double aRadius = 0.0;
+ if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+ aRadius = aCenter->distance(aStart);
+ } else {
+ aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aFeature->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
+ }
+
+ aConstraint.valA = aRadius * 2.0;
+ *aCIter = myStorage->updateConstraint(aConstraint);
+ }
+}
+
+
+bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint)
+ return false;
+ bool isFullyRemoved = true;
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++)
+ isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+
+ if (isFullyRemoved) {
+ myFeatureMap.clear();
+ myAttributeMap.clear();
+ myValueMap.clear();
+ } else
+ cleanRemovedEntities();
+ return true;
+}
+
+
+void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc)
+{
+ Slvs_Constraint aConstraint;
+ Slvs_hConstraint aConstrID = myStorage->isPointFixed(theArc.point[0]);
+ int aPointsToFix = 2; // number of fixed points for the arc
+ if (aConstrID != SLVS_E_UNKNOWN)
+ aPointsToFix--;
+
+ // Radius of the arc
+ FeaturePtr aFeature = myFeatureMap.begin()->first;
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+ double aRadius = aCenter->distance(aStart);
+
+ // Update end point of the arc to be on a curve
+ std::shared_ptr<GeomAPI_Pnt2d> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+ double aDistance = anEnd->distance(aCenter);
+ std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
+ if (aDistance < tolerance)
+ aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
+ else
+ aDir = aDir->multiplied(aRadius / aDistance);
+ double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
+ Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]);
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]);
+ aParam.val = xy[i];
+ myStorage->updateParameter(aParam);
+ }
+
+ for (int i = 1; aPointsToFix > 0; i++, aPointsToFix--) {
+ aConstrID = myStorage->isPointFixed(theArc.point[i]);
+ if (aConstrID != SLVS_E_UNKNOWN)
+ continue; // the coincident point is already fixed
+ aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+ 0.0, theArc.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ if (!myBaseConstraint)
+ myStorage->addTemporaryConstraint(aConstraint.h);
+ }
+
+ // Fix radius of the arc
+ bool isExists = false;
+ std::list<Slvs_Constraint> aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
+ std::list<Slvs_Constraint>::iterator anIt = aDiamConstraints.begin();
+ for (; anIt != aDiamConstraints.end() && !isExists; anIt)
+ if (anIt->entityA == myFeatureMap.begin()->second)
+ isExists = true;
+ if (!isExists) {
+ aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER, myGroup->getWorkplaneId(),
+ aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ if (!myBaseConstraint)
+ myStorage->addTemporaryConstraint(aConstraint.h);
+ }
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintRigid.h
+// Created: 30 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintRigid_H_
+#define SketchSolver_ConstraintRigid_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintRigid
+ * \ingroup Plugins
+ * \brief Stores data of Rigid (Fixed) constraint
+ *
+ * Rigid constraint may have NULL basic SketchPlugin constraint,
+ * because the Rigid constraint may be temporary for correct moving of objects
+ */
+class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
+{
+public:
+ /// Creates constraint to manage the given constraint from plugin
+ SketchSolver_ConstraintRigid(ConstraintPtr theConstraint)
+ : SketchSolver_Constraint(theConstraint)
+ {}
+ /// Creates temporary constraint based on feature
+ SketchSolver_ConstraintRigid(FeaturePtr theFeature);
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Returns the type of constraint
+ virtual int getType() const
+ { return SLVS_C_WHERE_DRAGGED; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+ /// \brief This method is used in derived objects to check consistence of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint();
+
+private:
+ /// \brief The arc is fixed differently to avoid SolveSpace problems (overconstraint)
+ ///
+ /// There will be fixed start and end points and the radius of the arc.
+ void fixArc(const Slvs_Entity& theArc);
+
+protected:
+ FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
+};
+
+#endif
--- /dev/null
+#include <SketchSolver_ConstraintTangent.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+
+void SketchSolver_ConstraintTangent::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntID;
+ getAttributes(aValue, anEntID);
+ if (!myErrorMsg.empty())
+ return;
+ // Check the quantity of entities of each type and their order (arcs first)
+ int aNbLines = 0;
+ int aNbArcs = 0;
+ Slvs_Entity anEntities[2];
+ myType = SLVS_C_CURVE_CURVE_TANGENT;
+ std::vector<Slvs_hEntity>::iterator anEntIter = anEntID.begin();
+ for (; anEntIter != anEntID.end(); anEntIter++) {
+ Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
+ if (anEnt.type == SLVS_E_LINE_SEGMENT) {
+ if (aNbLines == 0)
+ anEntities[1 + aNbLines] = anEnt;
+ aNbLines++;
+ myType = SLVS_C_ARC_LINE_TANGENT;
+ }
+ else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
+ if (aNbArcs < 2)
+ anEntities[aNbArcs] = anEnt;
+ aNbArcs++;
+ }
+ }
+
+ if (aNbLines + aNbArcs != 2) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
+ } else if (aNbArcs < 1) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
+ return;
+ }
+
+ // It is necessary to identify which points of entities are coincident
+ int aSlvsOtherFlag = 0;
+ int aSlvsOther2Flag = 0;
+ // Obtain start and end points of entities
+ Slvs_hEntity aPointsToFind[4];
+ for (int i = 0; i < 2; i++) {
+ int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+ aPointsToFind[2*i] = anEntities[i].point[aShift];
+ aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
+ }
+ // Search coincident points
+ bool isPointFound = false;
+ for (int i = 0; i < 2 && !isPointFound; i++)
+ for (int j = 2; j < 4 && !isPointFound; j++)
+ if (myStorage->isCoincident(aPointsToFind[i], aPointsToFind[j])) {
+ aSlvsOtherFlag = i;
+ aSlvsOther2Flag = j - 2;
+ isPointFound = true;
+ }
+ if (!isPointFound) {
+ // There is no coincident points between tangential objects. Generate error message
+ myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+ return;
+ }
+
+ Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+ getType(), myGroup->getWorkplaneId(), aValue,
+ SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, anEntities[0].h, anEntities[1].h);
+ aConstraint.other = aSlvsOtherFlag;
+ aConstraint.other2 = aSlvsOther2Flag;
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ adjustConstraint();
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintTangent.h
+// Created: 1 Apr 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintTangent_H_
+#define SketchSolver_ConstraintTangent_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintTangent
+ * \ingroup Plugins
+ * \brief Convert tangency constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintTangent : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintTangent(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return myType; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+private:
+ int myType; ///< type of constraint (applicable: SLVS_C_ARC_LINE_TANGENT, SLVS_C_CURVE_CURVE_TANGENT)
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Error.h
+// Created: 29 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Error_H_
+#define SketchSolver_Error_H_
+
+#include <string>
+
+/** \class SketchSolver_Error
+ * \ingroup Plugins
+ * \brief Collects all sketch solver error' codes
+ * as inline static functions
+ */
+class SketchSolver_Error
+{
+ public:
+ /// The value parameter for the constraint
+ inline static const std::string& CONSTRAINTS()
+ {
+ static const std::string MY_ERROR_VALUE("Conflicting constraints");
+ return MY_ERROR_VALUE;
+ }
+ /// Constraints should use objects instead of features as attributes
+ inline static const std::string& NEED_OBJECT_NOT_FEATURE()
+ {
+ static const std::string MY_ERROR_VALUE("Constraint should be based on object instead of feature");
+ return MY_ERROR_VALUE;
+ }
+ /// The entities need to have shared point, but they have not
+ inline static const std::string& NO_COINCIDENT_POINTS()
+ {
+ static const std::string MY_ERROR_VALUE("Objects should have coincident point");
+ return MY_ERROR_VALUE;
+ }
+ /// Attribute of a feature is not initialized
+ inline static const std::string& NOT_INITIALIZED()
+ {
+ static const std::string MY_ERROR_VALUE("Attribute is not initialized");
+ return MY_ERROR_VALUE;
+ }
+ /// Constraint has wrong attributes
+ inline static const std::string& INCORRECT_ATTRIBUTE()
+ {
+ static const std::string MY_ERROR_VALUE("Incorrect attribute");
+ return MY_ERROR_VALUE;
+ }
+ /// Tangency constraint has wrong attributes
+ inline static const std::string& INCORRECT_TANGENCY_ATTRIBUTE()
+ {
+ static const std::string MY_ERROR_VALUE("An arc should be an attribute of tangency constraint");
+ return MY_ERROR_VALUE;
+ }
+ /// Mirror constraint has wrong attributes
+ inline static const std::string& INCORRECT_MIRROR_ATTRIBUTE()
+ {
+ static const std::string MY_ERROR_VALUE("Mirror constraint has wrong attributes");
+ return MY_ERROR_VALUE;
+ }
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_FeatureStorage.cpp
+// Created: 23 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include <SketchSolver_FeatureStorage.h>
+
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint)
+{
+ std::list<AttributePtr> anAttributes = theConstraint->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject()) {
+ changeAttribute(aRefAttr->attr(), theConstraint);
+ continue;
+ }
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ aRefAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+ if (aFeature)
+ changeFeature(aFeature, theConstraint);
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ *aListIter);
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+ if (aFeature)
+ changeFeature(aFeature, theConstraint);
+ }
+ continue;
+ }
+ changeAttribute(*anIter, theConstraint);
+ }
+ myConstraints.insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint)
+{
+ DataPtr aData = theConstraint->data();
+ if (aData) { // Constraint has data. Iterate through its attributes and remove them
+ std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject()) {
+ removeAttribute(aRefAttr->attr(), theConstraint);
+ continue;
+ }
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ aRefAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+ if (aFeature)
+ removeFeature(aFeature, theConstraint);
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ *aListIter);
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+ if (aFeature)
+ removeFeature(aFeature, theConstraint);
+ }
+ continue;
+ }
+ removeAttribute(*anIter, theConstraint);
+ }
+ } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes
+ std::set<ConstraintPtr>::iterator aCIter;
+ MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
+ while (aFeatIter != myFeatures.end()) {
+ aCIter = aFeatIter->second.find(theConstraint);
+ if (aCIter != aFeatIter->second.end()) {
+ aFeatIter->second.erase(aCIter);
+ if (aFeatIter->second.empty()) {
+ MapFeatureConstraint::iterator aTmpIter = aFeatIter; // stores iterator for the next element, while the current is deleting
+ aTmpIter++;
+ myFeatures.erase(aFeatIter);
+ aFeatIter = aTmpIter;
+ continue;
+ }
+ }
+ aFeatIter++;
+ }
+ std::set<FeaturePtr>::iterator aFIter;
+ MapAttributeFeature::iterator anAttrIter = myAttributes.begin();
+ while (anAttrIter != myAttributes.end()) {
+ aFIter = anAttrIter->second.find(theConstraint);
+ if (aFIter != anAttrIter->second.end()) {
+ anAttrIter->second.erase(aFIter);
+ if (anAttrIter->second.empty()) {
+ MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting
+ aTmpIter++;
+ myAttributes.erase(anAttrIter);
+ anAttrIter = aTmpIter;
+ continue;
+ }
+ }
+ anAttrIter++;
+ }
+ }
+ myConstraints.erase(theConstraint);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const
+{
+ if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end())
+ return true;
+
+ DataPtr aData = theConstraint->data();
+ if (!aData)
+ return false;
+
+ std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject()) {
+ if (isInteract(aRefAttr->attr()))
+ return true;
+ continue;
+ }
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ aRefAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+ if (aFeature)
+ if (isInteract(aFeature))
+ return true;
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ *aListIter);
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+ if (aFeature)
+ if (isInteract(aFeature))
+ return true;
+ }
+ continue;
+ }
+ if (isInteract(*anIter))
+ return true;
+ }
+ return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature)
+{
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject())
+ changeAttribute(aRefAttr->attr(), theFeature);
+ continue;
+ }
+ changeAttribute(*anIter, theFeature);
+ }
+ if (myFeatures.find(theFeature) == myFeatures.end())
+ myFeatures[theFeature] = std::set<ConstraintPtr>();
+}
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+ // Change all attributes of the feature
+ changeFeature(theFeature);
+ // Add back reference feature to constraint
+ myFeatures[theFeature].insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature)
+{
+ MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+ if (aFeatIter != myFeatures.end())
+ return; // no such feature
+
+ std::set<ConstraintPtr> aConstraints = aFeatIter->second;
+ std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+ for (; aCIter != aConstraints.end(); aCIter++)
+ removeFeature(theFeature, *aCIter);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+ MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+ if (aFeatIter != myFeatures.end())
+ return; // no such feature
+
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject())
+ removeAttribute(aRefAttr->attr(), theFeature);
+ continue;
+ }
+ removeAttribute(*anIter, theFeature);
+ }
+
+ aFeatIter->second.erase(theConstraint);
+ if (aFeatIter->second.empty())
+ myFeatures.erase(aFeatIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const
+{
+ if (myFeatures.find(theFeature) != myFeatures.end())
+ return true;
+
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject())
+ if (isInteract(aRefAttr->attr()))
+ return true;
+ continue;
+ }
+ if (isInteract(*anIter))
+ return true;
+ }
+ return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute)
+{
+ if (myAttributes.find(theAttribute) == myAttributes.end())
+ myAttributes[theAttribute] = std::set<FeaturePtr>();
+}
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+ MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+ if (anAttrIter == myAttributes.end()) {
+ std::set<FeaturePtr> aFeatures;
+ aFeatures.insert(theFeature);
+ myAttributes[theAttribute] = aFeatures;
+ return;
+ }
+ anAttrIter->second.insert(theFeature);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute)
+{
+ MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+ if (anAttrIter == myAttributes.end())
+ return;
+
+ std::set<FeaturePtr> aFeatures = anAttrIter->second;
+ std::set<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
+ for (; aFeatIter != aFeatures.end(); aFeatIter++)
+ removeAttribute(theAttribute, *aFeatIter);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+ MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+ if (anAttrIter != myAttributes.end())
+ return; // no such attribute
+
+ anAttrIter->second.erase(theFeature);
+ if (anAttrIter->second.empty())
+ myAttributes.erase(anAttrIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const
+{
+ return myAttributes.find(theAttribute) != myAttributes.end();
+}
+
+
+bool SketchSolver_FeatureStorage::isConsistent() const
+{
+ // Check the constraints are valid
+ std::set<ConstraintPtr>::const_iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (!(*aCIter)->data() || !(*aCIter)->data()->isValid())
+ return false;
+ // Check the features are valid
+ MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
+ for (; aFIter != myFeatures.end(); aFIter++)
+ if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+ return false;
+ return true;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const
+{
+ std::set<ConstraintPtr> aResult;
+ MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature);
+ if (aFeatIter != myFeatures.end())
+ aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::const_iterator anAttrIter = anAttributes.begin();
+ for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+ MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter);
+ if (anIt == myAttributes.end())
+ continue;
+ std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+ for (; aFIter != anIt->second.end(); aFIter++) {
+ aFeatIter = myFeatures.find(*aFIter);
+ if (aFeatIter != myFeatures.end())
+ aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+ else {
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+ if (aConstraint)
+ aResult.insert(aConstraint);
+ }
+ }
+ }
+ return aResult;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const
+{
+ std::set<ConstraintPtr> aResult;
+ MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute);
+ if (anIt == myAttributes.end())
+ return aResult;
+ std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+ MapFeatureConstraint::const_iterator aFeatIter;
+ for (; aFIter != anIt->second.end(); aFIter++) {
+ aFeatIter = myFeatures.find(*aFIter);
+ if (aFeatIter != myFeatures.end())
+ aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+ else {
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+ if (aConstraint)
+ aResult.insert(aConstraint);
+ }
+ }
+ return aResult;
+}
+
+void SketchSolver_FeatureStorage::blockEvents(bool isBlocked) const
+{
+ std::set<ConstraintPtr>::iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if ((*aCIter)->data() && (*aCIter)->data()->isValid())
+ (*aCIter)->data()->blockSendAttributeUpdated(isBlocked);
+
+ MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
+ for (; aFIter != myFeatures.end(); aFIter++)
+ if (aFIter->first->data() && aFIter->first->data()->isValid())
+ aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
+
+ MapAttributeFeature::const_iterator anAtIter = myAttributes.begin();
+ for (; anAtIter != myAttributes.end(); anAtIter++)
+ if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
+ anAtIter->first->owner()->data()->isValid())
+ anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_FeatureStorage.h
+// Created: 23 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_FeatureStorage_H_
+#define SketchSolver_FeatureStorage_H_
+
+#include <SketchSolver.h>
+#include <SketchPlugin_Feature.h>
+#include <SketchPlugin_Constraint.h>
+
+#include <set>
+#include <map>
+
+typedef std::map<FeaturePtr, std::set<ConstraintPtr> > MapFeatureConstraint;
+typedef std::map<AttributePtr, std::set<FeaturePtr> > MapAttributeFeature;
+
+/** \class SketchSolver_FeatureStorage
+ * \ingroup Plugins
+ * \brief Collects information about SketchPlugin constraints used in specific group
+ */
+class SketchSolver_FeatureStorage
+{
+public:
+ SketchSolver_FeatureStorage() {}
+
+ /// \brief Adds or changes a constraint and all features it uses in the storage
+ void changeConstraint(ConstraintPtr theConstraint);
+ /// \brief Removes a constraint and all its features not used by other constraints
+ void removeConstraint(ConstraintPtr theConstraint);
+ /// \brief Verifies a constraint is used in the current storage
+ bool isInteract(ConstraintPtr theConstraint) const;
+
+ /// \brief Adds or changes a feature in the storage
+ void changeFeature(FeaturePtr theFeature);
+ /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint
+ void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+ /// \brief Removes a feature
+ void removeFeature(FeaturePtr theFeature);
+ /// \brief Removes a feature according to a given constraint
+ void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+ /// \brief Verifies a feature is used in the current storage
+ bool isInteract(FeaturePtr theFeature) const;
+
+ /// \brief Adds or changes an attribute in the storage
+ void changeAttribute(AttributePtr theAttribute);
+ /// \brief Adds or changes a attribute in the storage.
+ /// The attribute is used in specified feature or constraint (theFeature)
+ void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+ /// \brief Removes an attribute
+ void removeAttribute(AttributePtr theAttribute);
+ /// \brief Removes an attribute according to a given feature
+ void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+ /// \brief Verifies an attribute is used in the current storage
+ bool isInteract(AttributePtr theAttribute) const;
+
+ /// \brief Check the features is not removed
+ bool isConsistent() const;
+
+ /// \brief Prepares list of constraints, which using specified feature or its attributes
+ std::set<ConstraintPtr> getConstraints(FeaturePtr theFeature) const;
+ /// \brief Prepares list of constraints, which using specified attribute
+ std::set<ConstraintPtr> getConstraints(AttributePtr theAttribute) const;
+
+ /// \brief Block/unblock events of changing attributes of the features
+ void blockEvents(bool isBlocked) const;
+
+private:
+ std::set<ConstraintPtr> myConstraints; ///< list of SketchPlugin constraints used in the current group
+ MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature
+ MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute
+};
+
+typedef std::shared_ptr<SketchSolver_FeatureStorage> FeatureStoragePtr;
+
+#endif // SketchSolver_FeatureStorage_H_
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Group.cpp
+// Created: 27 May 2014
+// Author: Artem ZHIDKOV
+
+#include "SketchSolver_Group.h"
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+
+#include <Events_Error.h>
+#include <Events_Loop.h>
+#include <GeomAPI_XY.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_Feature.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <math.h>
+#include <assert.h>
+
+
+/// \brief This class is used to give unique index to the groups
+class GroupIndexer
+{
+public:
+ /// \brief Return vacant index
+ static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
+ /// \brief Removes the index
+ static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
+ if (myGroupIndex == theIndex)
+ myGroupIndex--;
+ }
+
+private:
+ GroupIndexer() {};
+
+ static Slvs_hGroup myGroupIndex; ///< index of the group
+};
+
+Slvs_hGroup GroupIndexer::myGroupIndex = 0;
+
+
+
+// ========================================================
+// ========= SketchSolver_Group ===============
+// ========================================================
+
+SketchSolver_Group::SketchSolver_Group(
+ std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
+ : myID(GroupIndexer::NEW_GROUP())
+{
+ // Initialize workplane
+ myWorkplaneID = SLVS_E_UNKNOWN;
+#ifndef NDEBUG
+ assert(addWorkplane(theWorkplane));
+#else
+ addWorkplane(theWorkplane);
+#endif
+}
+
+SketchSolver_Group::~SketchSolver_Group()
+{
+ myConstraints.clear();
+ GroupIndexer::REMOVE_GROUP(myID);
+}
+
+// ============================================================================
+// Function: isBaseWorkplane
+// Class: SketchSolver_Group
+// Purpose: verify the group is based on the given workplane
+// ============================================================================
+bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
+{
+ return theWorkplane == mySketch;
+}
+
+// ============================================================================
+// Function: isInteract
+// Class: SketchSolver_Group
+// Purpose: verify are there any entities in the group used by given constraint
+// ============================================================================
+bool SketchSolver_Group::isInteract(
+ std::shared_ptr<SketchPlugin_Feature> theFeature) const
+{
+ // Empty group interacts with everything
+ if (isEmpty()) return true;
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+ if (aConstraint)
+ return myFeatureStorage->isInteract(aConstraint);
+ return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
+}
+
+// ============================================================================
+// Function: getFeatureId
+// Class: SketchSolver_Group
+// Purpose: Find the identifier of the feature, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
+{
+ Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+ if (!myFeatureStorage)
+ return aResult;
+ std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+ if (aConstraints.empty())
+ return aResult;
+ std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
+ for (; aConstrIter != aConstraints.end(); aConstrIter++) {
+ ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
+ if (aCIter == myConstraints.end())
+ continue;
+ aResult = aCIter->second->getId(theFeature);
+ if (aResult != SLVS_E_UNKNOWN)
+ return aResult;
+ }
+ return SLVS_E_UNKNOWN;
+}
+
+// ============================================================================
+// Function: getAttributeId
+// Class: SketchSolver_Group
+// Purpose: Find the identifier of the attribute, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
+{
+ Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+ if (!myFeatureStorage)
+ return aResult;
+ std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
+ if (aConstraints.empty())
+ return aResult;
+ std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
+ for (; aConstrIter != aConstraints.end(); aConstrIter++) {
+ ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
+ if (aCIter == myConstraints.end())
+ continue;
+ aResult = aCIter->second->getId(theAttribute);
+ if (aResult != SLVS_E_UNKNOWN)
+ return aResult;
+ }
+ return SLVS_E_UNKNOWN;
+}
+
+// ============================================================================
+// Function: changeConstraint
+// Class: SketchSolver_Group
+// Purpose: create/update the constraint in the group
+// ============================================================================
+bool SketchSolver_Group::changeConstraint(
+ std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+ // There is no workplane yet, something wrong
+ if (myWorkplaneID == SLVS_E_UNKNOWN)
+ return false;
+
+ if (!theConstraint)
+ return false;
+
+ if (myConstraints.find(theConstraint) == myConstraints.end()) {
+ // Add constraint to the current group
+ SolverConstraintPtr aConstraint =
+ SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
+ if (!aConstraint)
+ return false;
+ aConstraint->setGroup(this);
+ aConstraint->setStorage(myStorage);
+ if (!aConstraint->error().empty()) {
+ if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
+ return false; // some attribute are not initialized yet, don't show message
+ Events_Error::send(aConstraint->error(), this);
+ }
+
+ // Additional verification of coincidence of several points
+ if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++) {
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
+ std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
+ if (!aCoincidence)
+ continue;
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
+ std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
+ if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
+ aCoincidence->attach(aCoinc2);
+ aConstraint = aCoincidence;
+ }
+ }
+ }
+ myConstraints[theConstraint] = aConstraint;
+ }
+ else
+ myConstraints[theConstraint]->update();
+
+ // Fix base features for fillet
+ if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+ std::list<AttributePtr> anAttrList =
+ theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+ std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
+ for (; anAttrIter != anAttrList.end(); anAttrIter++) {
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+ if (!aRefAttr || !aRefAttr->isObject())
+ continue;
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ SolverConstraintPtr aConstraint =
+ SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+ if (!aConstraint)
+ continue;
+ aConstraint->setGroup(this);
+ aConstraint->setStorage(myStorage);
+ myTempConstraints.insert(aConstraint);
+ }
+ }
+ // Fix base features for mirror
+ if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_B()));
+ fixFeaturesList(aRefList);
+ }
+
+ if (!myFeatureStorage)
+ myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+ myFeatureStorage->changeConstraint(theConstraint);
+
+ return true;
+}
+
+
+bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+ std::set<ConstraintPtr> aConstraints =
+ myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
+ if (aConstraints.empty())
+ return false;
+ std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+ for (; aCIter != aConstraints.end(); aCIter++) {
+ ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
+ aSolConIter->second->update();
+ }
+ return true;
+}
+
+void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+ updateFeature(theFeature);
+ // Temporary rigid constraint
+ SolverConstraintPtr aConstraint =
+ SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature);
+ if (!aConstraint)
+ return;
+ aConstraint->setGroup(this);
+ aConstraint->setStorage(myStorage);
+ myTempConstraints.insert(aConstraint);
+}
+
+// ============================================================================
+// Function: fixFeaturesList
+// Class: SketchSolver_Group
+// Purpose: Apply temporary rigid constraints for the list of features
+// ============================================================================
+void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
+{
+ std::list<ObjectPtr> aList = theList->list();
+ std::list<ObjectPtr>::iterator anIt = aList.begin();
+ for (; anIt != aList.end(); anIt++) {
+ if (!(*anIt))
+ continue;
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ SolverConstraintPtr aConstraint =
+ SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+ if (!aConstraint)
+ continue;
+ aConstraint->setGroup(this);
+ aConstraint->setStorage(myStorage);
+ myTempConstraints.insert(aConstraint);
+ }
+}
+
+// ============================================================================
+// Function: addWorkplane
+// Class: SketchSolver_Group
+// Purpose: create workplane for the group
+// ============================================================================
+bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
+{
+ if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
+ return false; // the workplane already exists or the function parameter is not Sketch
+
+ mySketch = theSketch;
+ updateWorkplane();
+ return true;
+}
+
+// ============================================================================
+// Function: updateWorkplane
+// Class: SketchSolver_Group
+// Purpose: update parameters of workplane
+// ============================================================================
+bool SketchSolver_Group::updateWorkplane()
+{
+ if (!myStorage) // Create storage if not exists
+ myStorage = StoragePtr(new SketchSolver_Storage);
+ SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
+
+ std::vector<Slvs_Entity> anEntities;
+ std::vector<Slvs_Param> aParams;
+ if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
+ return false;
+
+ if (myWorkplaneID == SLVS_E_UNKNOWN) {
+ myWorkplaneID = anEntities.back().h;
+ // Add new workplane elements
+ std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+ for (; aParIter != aParams.end(); aParIter++) {
+ aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+ aParIter->group = myID;
+ aParIter->h = myStorage->addParameter(*aParIter);
+ }
+ std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++) {
+ anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+ anEntIter->group = myID;
+ anEntIter->wrkpl = myWorkplaneID;
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->param[i] != SLVS_E_UNKNOWN)
+ anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->point[i] != SLVS_E_UNKNOWN)
+ anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
+ anEntIter->h = myStorage->addEntity(*anEntIter);
+ }
+ } else {
+ // Update existent workplane
+ const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
+ const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
+ const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
+ // Get parameters and update them
+ Slvs_hParam aWPParams[7] = {
+ anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
+ aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
+ };
+ std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+ for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
+ Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
+ aParam.val = aParIter->val;
+ myStorage->updateParameter(aParam);
+ }
+ }
+ return myWorkplaneID > 0;
+}
+
+// ============================================================================
+// Function: resolveConstraints
+// Class: SketchSolver_Group
+// Purpose: solve the set of constraints for the current group
+// ============================================================================
+bool SketchSolver_Group::resolveConstraints()
+{
+ bool aResolved = false;
+ if (myStorage->isNeedToResolve() && !isEmpty()) {
+ myConstrSolver.setGroupID(myID);
+ myStorage->initializeSolver(myConstrSolver);
+
+ int aResult = myConstrSolver.solve();
+ if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
+ myFeatureStorage->blockEvents(true);
+ ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ aConstrIter->second->refresh();
+ myFeatureStorage->blockEvents(false);
+ } else if (!myConstraints.empty())
+ Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+
+ aResolved = true;
+ }
+ removeTemporaryConstraints();
+ myStorage->setNeedToResolve(false);
+ return aResolved;
+}
+
+// ============================================================================
+// Function: mergeGroups
+// Class: SketchSolver_Group
+// Purpose: append specified group to the current group
+// ============================================================================
+void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
+{
+ // If specified group is empty, no need to merge
+ if (theGroup.isEmpty())
+ return;
+ if (!myFeatureStorage)
+ myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+
+ ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
+ for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
+ changeConstraint(aConstrIter->first);
+}
+
+// ============================================================================
+// Function: splitGroup
+// Class: SketchSolver_Group
+// Purpose: divide the group into several subgroups
+// ============================================================================
+void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
+{
+ // Obtain constraints, which should be separated
+ FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
+ std::vector<ConstraintPtr> anUnusedConstraints;
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for ( ; aCIter != myConstraints.end(); aCIter++) {
+ std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
+ std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
+ for (; anIter != aBaseConstraints.end(); anIter++)
+ if (aNewFeatStorage->isInteract(*anIter)) {
+ aNewFeatStorage->changeConstraint(*anIter);
+ } else
+ anUnusedConstraints.push_back(*anIter);
+ }
+
+ std::vector<SketchSolver_Group*>::iterator aCutsIter;
+ std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+ for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
+ // Remove unused constraints
+ removeConstraint(*aUnuseIt);
+ // Try to append constraint to already existent group
+ for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
+ if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+ (*aCutsIter)->changeConstraint(*aUnuseIt);
+ break;
+ }
+ if (aCutsIter == theCuts.end()) {
+ // Add new group
+ SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
+ aGroup->changeConstraint(*aUnuseIt);
+ theCuts.push_back(aGroup);
+ }
+ }
+}
+
+// ============================================================================
+// Function: isConsistent
+// Class: SketchSolver_Group
+// Purpose: search removed entities and constraints
+// ============================================================================
+bool SketchSolver_Group::isConsistent()
+{
+ if (!myFeatureStorage) // no one constraint is initialized yet
+ return true;
+
+ bool aResult = myFeatureStorage->isConsistent();
+ if (!aResult) {
+ // remove invalid entities
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ while (aCIter != myConstraints.end()) {
+ std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
+ std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
+ for (; anIt != aConstraints.end(); anIt++)
+ if (!(*anIt)->data() || !(*anIt)->data()->isValid())
+ if (aCIter->second->remove(*anIt)) {
+ // the constraint is fully removed, detach it from the list
+ ConstraintConstraintMap::iterator aTmpIt = aCIter++;
+ myFeatureStorage->removeConstraint(aTmpIt->first);
+ myConstraints.erase(aTmpIt);
+ break;
+ }
+ if (anIt == aConstraints.end())
+ aCIter++;
+ }
+ }
+ return aResult;
+}
+
+// ============================================================================
+// Function: removeTemporaryConstraints
+// Class: SketchSolver_Group
+// Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
+// resolving the set of constraints
+// ============================================================================
+void SketchSolver_Group::removeTemporaryConstraints()
+{
+ myTempConstraints.clear();
+ // Clean lists of removed entities in the storage
+ std::set<Slvs_hParam> aRemPar;
+ std::set<Slvs_hEntity> aRemEnt;
+ std::set<Slvs_hConstraint> aRemCon;
+ myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+ myStorage->setNeedToResolve(false);
+}
+
+// ============================================================================
+// Function: removeConstraint
+// Class: SketchSolver_Group
+// Purpose: remove constraint and all unused entities
+// ============================================================================
+void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
+{
+ myFeatureStorage->removeConstraint(theConstraint);
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (aCIter->second->hasConstraint(theConstraint)) {
+ if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
+ aCIter = myConstraints.end();
+ break;
+ }
+ if (aCIter != myConstraints.end())
+ myConstraints.erase(aCIter);
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Group.h
+// Created: 27 May 2014
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Group_H_
+#define SketchSolver_Group_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+#include <SketchSolver_FeatureStorage.h>
+#include <SketchSolver_Solver.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_AttributeRefList.h>
+
+#include <memory>
+#include <list>
+#include <map>
+#include <vector>
+#include <set>
+
+typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
+
+/** \class SketchSolver_Group
+ * \ingroup Plugins
+ * \brief Keeps the group of constraints which based on the same entities
+ */
+class SketchSolver_Group
+{
+ public:
+ /** \brief New group based on specified workplane.
+ * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
+ * \remark Type of theSketch is not verified inside
+ */
+ SketchSolver_Group(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
+
+ ~SketchSolver_Group();
+
+ /// \brief Returns group's unique identifier
+ inline const Slvs_hGroup& getId() const
+ {
+ return myID;
+ }
+
+ /// \brief Returns identifier of the workplane
+ inline const Slvs_hEntity& getWorkplaneId() const
+ {
+ return myWorkplaneID;
+ }
+
+ /// \brief Find the identifier of the feature, if it already exists in the group
+ Slvs_hEntity getFeatureId(FeaturePtr theFeature) const;
+ /// \brief Find the identifier of the attribute, if it already exists in the group
+ Slvs_hEntity getAttributeId(AttributePtr theAttribute) const;
+
+ /// \brief Returns true if the group has no constraints yet
+ inline bool isEmpty() const
+ {
+ return myConstraints.empty();
+ }
+
+ /// \brief Check for valid sketch data
+ inline bool isWorkplaneValid() const
+ {
+ return mySketch->data() && mySketch->data()->isValid();
+ }
+
+ /** \brief Adds or updates a constraint in the group
+ * \param[in] theConstraint constraint to be changed
+ * \return \c true if the constraint added or updated successfully
+ */
+ bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+ /** \brief Updates the data corresponding the specified feature
+ * \param[in] theFeature the feature to be updated
+ */
+ bool updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+ /** \brief Updates the data corresponding the specified feature moved in GUI.
+ * Additional Fixed constraints are created.
+ * \param[in] theFeature the feature to be updated
+ */
+ void moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+ /** \brief Verifies the feature attributes are used in this group
+ * \param[in] theFeature constraint or any other object for verification of interaction
+ * \return \c true if some of attributes are used in current group
+ */
+ bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+
+ /** \brief Verifies the specified feature is equal to the base workplane for this group
+ * \param[in] theWorkplane the feature to be compared with base workplane
+ * \return \c true if workplanes are the same
+ */
+ bool isBaseWorkplane(CompositeFeaturePtr theWorkplane) const;
+
+ /// Returns the current workplane
+ std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
+ {
+ return mySketch;
+ }
+
+ /** \brief Update parameters of workplane. Should be called when Update event is coming.
+ * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
+ */
+ bool updateWorkplane();
+
+ /** \brief Searches invalid features and constraints in the group and removes them
+ * \return \c false if the group several constraints were removed
+ */
+ bool isConsistent();
+
+ /** \brief Add specified group to this one
+ * \param[in] theGroup group of constraint to be added
+ */
+ void mergeGroups(const SketchSolver_Group& theGroup);
+
+ /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
+ * \param[out] theCuts enlarge this list by newly created groups
+ */
+ void splitGroup(std::vector<SketchSolver_Group*>& theCuts);
+
+ /** \brief Start solution procedure if necessary and update attributes of features
+ * \return \c false when no need to solve constraints
+ */
+ bool resolveConstraints();
+
+protected:
+ /** \brief Removes constraints from the group
+ * \param[in] theConstraint constraint to be removed
+ */
+ void removeConstraint(ConstraintPtr theConstraint);
+
+ /** \brief Remove all temporary constraint after computation finished
+ * \param[in] theRemoved indexes of constraints to be removed. If empty, all temporary constraints should be deleted
+ */
+ void removeTemporaryConstraints();
+
+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, \c false if workplane parameters are not consistent
+ */
+ bool addWorkplane(CompositeFeaturePtr theSketch);
+
+ /// \brief Apply temporary rigid constraints for the list of features
+ void fixFeaturesList(AttributeRefListPtr theList);
+
+private:
+ Slvs_hGroup myID; ///< Index of the group
+ Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on
+ CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane
+ ConstraintConstraintMap myConstraints; ///< List of constraints
+ std::set<SolverConstraintPtr> myTempConstraints; ///< List of temporary constraints
+
+ StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities
+ FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies
+
+ SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
+};
+
+#endif
SketchSolver_Solver::~SketchSolver_Solver()
{
- if (myEquationsSystem.param)
- delete[] myEquationsSystem.param;
- if (myEquationsSystem.entity)
- delete[] myEquationsSystem.entity;
if (myEquationsSystem.constraint)
delete[] myEquationsSystem.constraint;
if (myEquationsSystem.failed)
delete[] myEquationsSystem.failed;
}
-void SketchSolver_Solver::setParameters(const std::vector<Slvs_Param>& theParameters)
+void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
{
- if (theParameters.size() != myEquationsSystem.params) // number of parameters was changed => reallocate the memory
- {
- if (myEquationsSystem.param)
- delete[] myEquationsSystem.param;
- myEquationsSystem.params = theParameters.size();
- myEquationsSystem.param = new Slvs_Param[theParameters.size()];
- }
-
- // Copy data
- std::vector<Slvs_Param>::const_iterator aParamIter = theParameters.begin();
- for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++)
- myEquationsSystem.param[i] = *aParamIter;
+ myEquationsSystem.param = theParameters;
+ myEquationsSystem.params = theSize;
}
-void SketchSolver_Solver::setDraggedParameters(const std::vector<Slvs_hParam>& theDragged)
+
+void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
{
- if (theDragged.size() == 0) {
- myEquationsSystem.dragged[0] = 0;
- myEquationsSystem.dragged[1] = 0;
- myEquationsSystem.dragged[2] = 0;
- myEquationsSystem.dragged[3] = 0;
- return;
- }
- for (unsigned int i = 0; i < theDragged.size(); i++)
+ for (unsigned int i = 0; i < 4; i++)
myEquationsSystem.dragged[i] = theDragged[i];
}
-void SketchSolver_Solver::setEntities(const std::vector<Slvs_Entity>& theEntities)
+void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
{
- if (theEntities.size() != myEquationsSystem.entities) // number of entities was changed => reallocate the memory
- {
- if (myEquationsSystem.entity)
- delete[] myEquationsSystem.entity;
- myEquationsSystem.entities = theEntities.size();
- myEquationsSystem.entity = new Slvs_Entity[theEntities.size()];
- }
-
- // Copy data
- std::vector<Slvs_Entity>::const_iterator aEntIter = theEntities.begin();
- for (int i = 0; i < myEquationsSystem.entities; i++, aEntIter++)
- myEquationsSystem.entity[i] = *aEntIter;
+ myEquationsSystem.entity = theEntities;
+ myEquationsSystem.entities = theSize;
}
-void SketchSolver_Solver::setConstraints(const std::vector<Slvs_Constraint>& theConstraints)
+void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
{
- if (theConstraints.size() != myEquationsSystem.constraints) // number of constraints was changed => reallocate the memory
- {
- if (myEquationsSystem.constraint)
- delete[] myEquationsSystem.constraint;
- myEquationsSystem.constraints = theConstraints.size();
- myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()];
-
- // Assign the memory for the failed constraints
- if (myEquationsSystem.failed)
- delete[] myEquationsSystem.failed;
- myEquationsSystem.failed = new Slvs_hConstraint[theConstraints.size()];
- myEquationsSystem.faileds = theConstraints.size();
+ if (!myEquationsSystem.constraint) {
+ myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+ myEquationsSystem.constraints = theSize;
}
-
- // Copy data
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = theConstraints.begin();
- for (int i = 0; i < myEquationsSystem.constraints; i++, aConstrIter++)
- myEquationsSystem.constraint[i] = *aConstrIter;
+ else if (myEquationsSystem.constraints != theSize) {
+ delete[] myEquationsSystem.constraint;
+ myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+ myEquationsSystem.constraints = theSize;
+ }
+ memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint));
}
+
int SketchSolver_Solver::solve()
{
if (myEquationsSystem.constraints <= 0)
#define SLVS_C_FILLET 100100
// Unknown entity
#define SLVS_E_UNKNOWN 0
+// Unknown group
+#define SLVS_G_UNKNOWN 0
/**
* The main class that performs the high-level operations for connection to the SolveSpace.
}
/** \brief Change array of parameters
- * \param[in] theParameters vector of parameters
+ * \param[in] theParameters pointer to the array of parameters
+ * \param[in] theSize size of this array
*/
- void setParameters(const std::vector<Slvs_Param>& theParameters);
+ void setParameters(Slvs_Param* theParameters, int theSize);
/** \brief Change array of entities
- * \param[in] theEntities vector of entities
+ * \param[in] theEntities pointer to the array of entities
+ * \param[in] theSize size of this array
*/
- void setEntities(const std::vector<Slvs_Entity>& theEntities);
+ void setEntities(Slvs_Entity* theEntities, int theSize);
/** \brief Change array of constraints
- * \param[in] theConstraints vector of constraints
+ * \param[in] theConstraints pointer to the array of constraints
+ * \param[in] theSize size of this array
*/
- void setConstraints(const std::vector<Slvs_Constraint>& theConstraints);
+ void setConstraints(Slvs_Constraint* theConstraints, int theSize);
/** \brief Store the parameters of the point which was moved by user.
* The solver will watch this items to be constant
* \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
*/
- void setDraggedParameters(const std::vector<Slvs_hParam>& theDragged);
+ void setDraggedParameters(const Slvs_hParam* theDragged);
/** \brief Solve the set of equations
* \return identifier whether solution succeeded
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Storage.cpp
+// Created: 18 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include <SketchSolver_Storage.h>
+
+#include <math.h>
+
+/** \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);
+
+/// \brief Compare two parameters to be different
+static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
+/// \brief Compare two entities to be different
+static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
+/// \brief Compare two constriants to be different
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+
+
+SketchSolver_Storage::SketchSolver_Storage()
+ : myParamMaxID(SLVS_E_UNKNOWN),
+ myEntityMaxID(SLVS_E_UNKNOWN),
+ myConstrMaxID(SLVS_C_UNKNOWN),
+ myFixed(SLVS_E_UNKNOWN),
+ myNeedToResolve(false)
+{
+}
+
+Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
+{
+ if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+ // parameter is already used, rewrite it
+ return updateParameter(theParam);
+ }
+
+ Slvs_Param aParam = theParam;
+ if (aParam.h > myParamMaxID)
+ myParamMaxID = aParam.h;
+ else
+ aParam.h = ++myParamMaxID;
+ myParameters.push_back(aParam);
+ myNeedToResolve = true;
+ return aParam.h;
+}
+
+Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
+{
+ if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+ // parameter already used, rewrite it
+ int aPos = Search(theParam.h, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam);
+ myParameters[aPos] = theParam;
+ return theParam.h;
+ }
+ }
+
+ // Parameter is not found, add new one
+ Slvs_Param aParam = theParam;
+ aParam.h = 0;
+ return addParameter(aParam);
+}
+
+bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+{
+ int aPos = Search(theParamID, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ // Firstly, search the parametes is not used elsewhere
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->param[i] == theParamID)
+ return false;
+ }
+ // Remove parameter
+ myParameters.erase(myParameters.begin() + aPos);
+ myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
+ myNeedToResolve = true;
+ myRemovedParameters.insert(theParamID);
+ return true;
+ }
+ return false;
+}
+
+const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
+{
+ int aPos = Search(theParamID, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size())
+ return myParameters[aPos];
+
+ // Parameter is not found, return empty object
+ static Slvs_Param aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+
+Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+{
+ if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+ // Entity is already used, rewrite it
+ return updateEntity(theEntity);
+ }
+
+ Slvs_Entity aEntity = theEntity;
+ if (aEntity.h > myEntityMaxID)
+ myEntityMaxID = aEntity.h;
+ else
+ aEntity.h = ++myEntityMaxID;
+ myEntities.push_back(aEntity);
+ myNeedToResolve = true;
+ return aEntity.h;
+}
+
+Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
+{
+ if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+ // Entity already used, rewrite it
+ int aPos = Search(theEntity.h, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
+ myEntities[aPos] = theEntity;
+ return theEntity.h;
+ }
+ }
+
+ // Entity is not found, add new one
+ Slvs_Entity aEntity = theEntity;
+ aEntity.h = 0;
+ return addEntity(aEntity);
+}
+
+bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
+{
+ bool aResult = true;
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ // Firstly, check the entity is not used elsewhere
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->point[i] == theEntityID)
+ return false;
+ if (anEntIter->distance == theEntityID)
+ return false;
+ }
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++) {
+ Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
+ aConstrIter->entityA, aConstrIter->entityB,
+ aConstrIter->entityC, aConstrIter->entityD};
+ for (int i = 0; i < 6; i++)
+ if (anEntIDs[i] == theEntityID)
+ return false;
+ }
+ // The entity is not used, remove it and its parameters
+ Slvs_Entity anEntity = myEntities[aPos];
+ myEntities.erase(myEntities.begin() + aPos);
+ myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
+ if (anEntity.distance != SLVS_E_UNKNOWN)
+ aResult = aResult && removeParameter(anEntity.distance);
+ for (int i = 0; i < 4; i++)
+ if (anEntity.param[i] != SLVS_E_UNKNOWN)
+ aResult = removeParameter(anEntity.param[i]) && aResult;
+ for (int i = 0; i < 4; i++)
+ if (anEntity.point[i] != SLVS_E_UNKNOWN)
+ aResult = removeEntity(anEntity.point[i]) && aResult;
+ myNeedToResolve = true;
+ myRemovedEntities.insert(theEntityID);
+ if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
+ removeCoincidentPoint(theEntityID);
+ }
+ return aResult;
+}
+
+const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
+{
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size())
+ return myEntities[aPos];
+
+ // Entity is not found, return empty object
+ static Slvs_Entity aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const
+{
+ // Search the set of coincident points
+ std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
+ for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
+ if (aCPIter->find(thePointID) != aCPIter->end())
+ break;
+ if (aCPIter == myCoincidentPoints.end()) {
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+ aConstrIter->ptA == thePointID)
+ return aConstrIter->h;
+ return SLVS_E_UNKNOWN;
+ }
+
+ // Search the Rigid constraint
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+ aCPIter->find(aConstrIter->ptA) != aCPIter->end())
+ return aConstrIter->h;
+ return SLVS_E_UNKNOWN;
+}
+
+
+Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
+{
+ if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+ // Constraint is already used, rewrite it
+ return updateConstraint(theConstraint);
+ }
+
+ Slvs_Constraint aConstraint = theConstraint;
+
+ // Find a constraint with same type uses same arguments
+ std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
+ for (; aCIt != myConstraints.end(); aCIt++) {
+ if (aConstraint.type != aCIt->type)
+ continue;
+ if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
+ aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
+ aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD) {
+ aConstraint.h = aCIt->h;
+ return updateConstraint(aConstraint);
+ }
+ }
+
+ if (aConstraint.h > myConstrMaxID)
+ myConstrMaxID = aConstraint.h;
+ else
+ aConstraint.h = ++myConstrMaxID;
+ myConstraints.push_back(aConstraint);
+ myNeedToResolve = true;
+ if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
+ addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
+ return aConstraint.h;
+}
+
+Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+{
+ if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+ // Constraint already used, rewrite it
+ int aPos = Search(theConstraint.h, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
+ myConstraints[aPos] = theConstraint;
+ if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
+ addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
+ return theConstraint.h;
+ }
+ }
+
+ // Constraint is not found, add new one
+ Slvs_Constraint aConstraint = theConstraint;
+ aConstraint.h = 0;
+ return addConstraint(aConstraint);
+}
+
+bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ bool aResult = true;
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+ Slvs_Constraint aConstraint = myConstraints[aPos];
+ myConstraints.erase(myConstraints.begin() + aPos);
+ myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
+ myNeedToResolve = true;
+ myRemovedConstraints.insert(theConstraintID);
+ // Remove all entities
+ Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
+ aConstraint.entityA, aConstraint.entityB,
+ aConstraint.entityC, aConstraint.entityD};
+ for (int i = 0; i < 6; i++)
+ if (anEntities[i] != SLVS_E_UNKNOWN)
+ aResult = removeEntity(anEntities[i]) && aResult;
+ // remove temporary fixed point, if available
+ if (myFixed == theConstraintID)
+ myFixed = SLVS_E_UNKNOWN;
+ }
+ return aResult;
+}
+
+const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+{
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ return myConstraints[aPos];
+
+ // Constraint is not found, return empty object
+ static Slvs_Constraint aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+std::list<Slvs_Constraint> SketchSolver_Storage::getConstraintsByType(int theConstraintType) const
+{
+ std::list<Slvs_Constraint> aResult;
+ std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (aCIter->type == theConstraintType)
+ aResult.push_back(*aCIter);
+ return aResult;
+}
+
+
+void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ if (myFixed != SLVS_E_UNKNOWN)
+ return; // the point is already fixed
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ myFixed = theConstraintID;
+}
+
+void SketchSolver_Storage::getRemoved(
+ std::set<Slvs_hParam>& theParameters,
+ std::set<Slvs_hEntity>& theEntities,
+ std::set<Slvs_hConstraint>& theConstraints)
+{
+ theParameters = myRemovedParameters;
+ theEntities = myRemovedEntities;
+ theConstraints = myRemovedConstraints;
+
+ myRemovedParameters.clear();
+ myRemovedEntities.clear();
+ myRemovedConstraints.clear();
+}
+
+void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
+{
+ theSolver.setParameters(myParameters.data(), (int)myParameters.size());
+ theSolver.setEntities(myEntities.data(), (int)myEntities.size());
+
+ // Copy constraints excluding the fixed one
+ std::vector<Slvs_Constraint> aConstraints = myConstraints;
+ if (myFixed != SLVS_E_UNKNOWN) {
+ Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
+ std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
+ for (; anIt != aConstraints.end(); anIt++)
+ if (anIt->h == myFixed) {
+ aFixedPoint = anIt->ptA;
+ aConstraints.erase(anIt);
+ break;
+ }
+ // set dragged parameters
+ int aPos = Search(aFixedPoint, myEntities);
+ theSolver.setDraggedParameters(myEntities[aPos].param);
+ }
+ theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
+}
+
+void SketchSolver_Storage::addCoincidentPoints(
+ const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
+{
+ std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
+ std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
+ bool isFound = false;
+ for (; aCIter != myCoincidentPoints.end(); aCIter++) {
+ bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
+ bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
+ isFound = isFound || isFirstFound || isSecondFound;
+ if (isFirstFound && isSecondFound)
+ break; // already coincident
+ else if (isFirstFound || isSecondFound) {
+ if (aFoundIter != myCoincidentPoints.end()) {
+ // merge two sets
+ aFoundIter->insert(aCIter->begin(), aCIter->end());
+ myCoincidentPoints.erase(aCIter);
+ break;
+ }
+ aCIter->insert(thePoint1);
+ aCIter->insert(thePoint2);
+ }
+ }
+ // coincident points not found
+ if (!isFound) {
+ std::set<Slvs_hEntity> aNewSet;
+ aNewSet.insert(thePoint1);
+ aNewSet.insert(thePoint2);
+ myCoincidentPoints.push_back(aNewSet);
+ }
+}
+
+void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
+{
+ std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
+ for (; aCIter != myCoincidentPoints.end(); aCIter++)
+ if (aCIter->find(thePoint) != aCIter->end()) {
+ aCIter->erase(thePoint);
+ if (aCIter->size() <= 1)
+ myCoincidentPoints.erase(aCIter);
+ break;
+ }
+}
+
+bool SketchSolver_Storage::isCoincident(
+ const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
+{
+ std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
+ for (; aCIter != myCoincidentPoints.end(); aCIter++)
+ if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
+ return true;
+ return false;
+}
+
+
+
+
+// ========================================================
+// ========= Auxiliary functions ===============
+// ========================================================
+
+template<typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+ int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+ int aVecSize = theEntities.size();
+ if (theEntities.empty())
+ return 1;
+ while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+ aResIndex--;
+ while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+ aResIndex++;
+ if (aResIndex == -1)
+ aResIndex = aVecSize;
+ return aResIndex;
+}
+
+bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
+{
+ return fabs(theParam1.val - theParam2.val) > tolerance;
+}
+
+bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
+{
+ int i = 0;
+ for (; theEntity1.param[i] != 0 && i < 4; i++)
+ if (theEntity1.param[i] != theEntity2.param[i])
+ return true;
+ i = 0;
+ for (; theEntity1.point[i] != 0 && i < 4; i++)
+ if (theEntity1.point[i] != theEntity2.point[i])
+ return true;
+ return false;
+}
+
+bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
+{
+ return theConstraint1.ptA != theConstraint2.ptA ||
+ theConstraint1.ptB != theConstraint2.ptB ||
+ theConstraint1.entityA != theConstraint2.entityA ||
+ theConstraint1.entityB != theConstraint2.entityB ||
+ theConstraint1.entityC != theConstraint2.entityC ||
+ theConstraint1.entityD != theConstraint2.entityD ||
+ fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Storage.h
+// Created: 18 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Storage_H_
+#define SketchSolver_Storage_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Solver.h>
+
+#include <list>
+#include <memory>
+#include <set>
+#include <vector>
+
+/** \class SketchSolver_Storage
+ * \ingroup Plugins
+ * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints
+ */
+class SketchSolver_Storage
+{
+public:
+ SketchSolver_Storage();
+
+ /** \brief Add new parameter to the current group
+ * \param[in] theParam SolveSpace parameter
+ * \return the ID of added parameter
+ */
+ Slvs_hParam addParameter(const Slvs_Param& theParam);
+ /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added
+ * \param[in] theParam SolveSpace parameter
+ * \return the ID of updated/added parameter
+ */
+ Slvs_hParam updateParameter(const Slvs_Param& theParam);
+ /** \brief Removes the parameter by its ID
+ * \param[in] theParamID index of parameter to be removed
+ * \return \c true if the parameter was successfully removed
+ */
+ bool removeParameter(const Slvs_hParam& theParamID);
+ /// \brief Returns the parameter by its ID
+ const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const;
+
+ /** \brief Add new entity to the current group
+ * \param[in] theEntity SolveSpace entity
+ * \return the ID of added entity
+ */
+ Slvs_hEntity addEntity(const Slvs_Entity& theEntity);
+ /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added
+ * \param[in] theEntity SolveSpace entity
+ * \return the ID of updated/added entity
+ */
+ Slvs_hEntity updateEntity(const Slvs_Entity& theEntity);
+ /** \brief Removes the entity by its ID. All parameters used in this entity,
+ * and not used in other constraints, will be removed too.
+ * \param[in] theEntityID index of entity to be removed
+ * \return \c true if the entity was successfully removed
+ */
+ bool removeEntity(const Slvs_hEntity& theEntityID);
+ /// \brief Returns the entity by its ID
+ const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const;
+
+ /// \brief Verifies the current point or another coincident one is fixed
+ /// \return the ID of the Fixed constraint or SLVS_E_UNKNOWN
+ Slvs_hConstraint isPointFixed(const Slvs_hEntity& thePointID) const;
+
+ /** \brief Add new constraint to the current group
+ * \param[in] theConstraint SolveSpace's constraint
+ * \return the ID of added constraint
+ */
+ Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint);
+ /** \brief Updates constraint in the current group.
+ * If the ID of constraint is zero, the new item will be added
+ * \param[in] theConstraint SolveSpace constraint
+ * \return the ID of updated/added constraint
+ */
+ Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint);
+ /** \brief Removes the constraint by its ID. All entities and parameters depending on this
+ * constraint, which are not used in other constraints, will be removed too.
+ * \param[in] theConstraintID index of constraint to be removed
+ * \return \c true if the constraint was successfully removed
+ */
+ bool removeConstraint(const Slvs_hConstraint& theConstraintID);
+ /// \brief Returns the constraint by its ID
+ const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const;
+ /// \brief Returns list of constraints of specified type
+ std::list<Slvs_Constraint> getConstraintsByType(int theConstraintType) const;
+
+ /// \brief Attach temporary constraint to this storage. It need to make precise calculations
+ void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID);
+
+ /// \brief Shows the sketch should be resolved
+ bool isNeedToResolve() const
+ { return myNeedToResolve; }
+
+ /// \brief Changes the flag of group to be resolved
+ void setNeedToResolve(bool theFlag)
+ { myNeedToResolve = theFlag; }
+
+ /// \brief Returns lists of removed elements
+ void getRemoved(std::set<Slvs_hParam>& theParameters,
+ std::set<Slvs_hEntity>& theEntities,
+ std::set<Slvs_hConstraint>& theConstraints);
+
+ /// \brief Initialize constraint solver by the entities collected by current storage
+ void initializeSolver(SketchSolver_Solver& theSolver);
+
+private:
+ /// \brief Store coincident points
+ void addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
+ /// \brief Remove point from lists of coincidence
+ void removeCoincidentPoint(const Slvs_hEntity& thePoint);
+
+public:
+ /// \brief Check two points are coincident
+ bool isCoincident(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const;
+
+private:
+ Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
+ std::vector<Slvs_Param> myParameters; ///< list of parameters used in the current group of constraints (sorted by the identifier)
+ Slvs_hEntity myEntityMaxID; ///< current entity index (may differs with the number of entities)
+ std::vector<Slvs_Entity> myEntities; ///< list of entities used in the current group of constraints (sorted by the identifier)
+ Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints)
+ std::vector<Slvs_Constraint> myConstraints; ///< list of constraints used in the current group (sorted by the identifier)
+
+ std::vector< std::set<Slvs_hEntity> > myCoincidentPoints; ///< lists of coincident points
+ Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+
+ bool myNeedToResolve; ///< parameters are changed and group needs to be resolved
+
+ std::set<Slvs_hParam> myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant)
+ std::set<Slvs_hEntity> myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant)
+ std::set<Slvs_hConstraint> myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant)
+};
+
+typedef std::shared_ptr<SketchSolver_Storage> StoragePtr;
+
+#endif
#include <GeomAPI_Dir.h>
#include <GeomAPI_Pnt2d.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Constraint.h>
#include <AIS_Drawer.hxx>
IMPLEMENT_STANDARD_HANDLE(SketcherPrs_Coincident, AIS_InteractiveObject);
IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Coincident, AIS_InteractiveObject);
-SketcherPrs_Coincident::SketcherPrs_Coincident(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Coincident::SketcherPrs_Coincident(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: AIS_InteractiveObject(), myConstraint(theConstraint), myPlane(thePlane)
{
void SketcherPrs_Coincident::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
const Standard_Integer aMode)
{
- Handle(SelectMgr_EntityOwner) aOwn = new SelectMgr_EntityOwner(this, 10);
- Handle(Select3D_SensitivePoint) aSp = new Select3D_SensitivePoint(aOwn, myPoint);
- aSelection->Add(aSp);
+ if ((aMode == 0) || (aMode == SketcherPrs_Tools::Sel_Constraint)) {
+ Handle(SelectMgr_EntityOwner) aOwn = new SelectMgr_EntityOwner(this, 10);
+ Handle(Select3D_SensitivePoint) aSp = new Select3D_SensitivePoint(aOwn, myPoint);
+ aSelection->Add(aSp);
+ }
}
void SketcherPrs_Coincident::SetColor(const Quantity_NameOfColor aCol)
#define SketcherPrs_Coincident_H
#include <GeomAPI_Ax3.h>
+#include <ModelAPI_Feature.h>
#include <AIS_InteractiveObject.hxx>
#include <Standard_DefineHandle.hxx>
-class SketchPlugin_Constraint;
-
DEFINE_STANDARD_HANDLE(SketcherPrs_Coincident, AIS_InteractiveObject)
public:
/// Constructor
/// \param theResult a result object
- Standard_EXPORT SketcherPrs_Coincident(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Coincident(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
Standard_EXPORT virtual void SetColor(const Quantity_Color& aColor);
const Standard_Integer aMode) ;
private:
- SketchPlugin_Constraint* myConstraint;
+ ModelAPI_Feature* myConstraint;
std::shared_ptr<GeomAPI_Ax3> myPlane;
gp_Pnt myPoint;
};
static Handle(Image_AlienPixMap) MyPixMap;
-SketcherPrs_Equal::SketcherPrs_Equal(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Equal::SketcherPrs_Equal(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: SketcherPrs_SymbolPrs(theConstraint, thePlane)
{
#include "SketcherPrs_SymbolPrs.h"
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
-
DEFINE_STANDARD_HANDLE(SketcherPrs_Equal, SketcherPrs_SymbolPrs)
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_Equal(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Equal(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
DEFINE_STANDARD_RTTI(SketcherPrs_Equal)
protected:
#include "SketcherPrs_LengthDimension.h"
#define CONSTRAINT_PRS_IMPL(NAME, CLASS) \
-AISObjectPtr SketcherPrs_Factory::NAME(SketchPlugin_Constraint* theConstraint, \
+AISObjectPtr SketcherPrs_Factory::NAME(ModelAPI_Feature* theConstraint, \
const std::shared_ptr<GeomAPI_Ax3>& thePlane) \
{ \
std::shared_ptr<GeomAPI_AISObject> aAISObj = AISObjectPtr(new GeomAPI_AISObject()); \
CONSTRAINT_PRS_IMPL(lengthDimensionConstraint, SketcherPrs_LengthDimension);
-AISObjectPtr SketcherPrs_Factory::horisontalConstraint(SketchPlugin_Constraint* theConstraint,
+AISObjectPtr SketcherPrs_Factory::horisontalConstraint(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
{
std::shared_ptr<GeomAPI_AISObject> aAISObj = AISObjectPtr(new GeomAPI_AISObject());
return aAISObj;
}
-AISObjectPtr SketcherPrs_Factory::verticalConstraint(SketchPlugin_Constraint* theConstraint,
+AISObjectPtr SketcherPrs_Factory::verticalConstraint(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
{
std::shared_ptr<GeomAPI_AISObject> aAISObj = AISObjectPtr(new GeomAPI_AISObject());
#include "SketcherPrs.h"
+#include <ModelAPI_Feature.h>
+
#include <GeomAPI_Ax3.h>
#include <GeomAPI_AISObject.h>
-class SketchPlugin_Constraint;
-
#define GET_CONSTRAINT_PRS(NAME) \
- static AISObjectPtr NAME(SketchPlugin_Constraint* theConstraint, \
+ static AISObjectPtr NAME(ModelAPI_Feature* theConstraint, \
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
static Handle(Image_AlienPixMap) MyPixMap;
-SketcherPrs_HVDirection::SketcherPrs_HVDirection(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_HVDirection::SketcherPrs_HVDirection(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane,
bool isHorisontal)
: SketcherPrs_SymbolPrs(theConstraint, thePlane), myIsHorisontal(isHorisontal)
#define SketcherPrs_HVDirection_H
#include "SketcherPrs_SymbolPrs.h"
-
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
+#include <ModelAPI_Feature.h>
DEFINE_STANDARD_HANDLE(SketcherPrs_HVDirection, SketcherPrs_SymbolPrs)
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_HVDirection(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_HVDirection(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane,
bool isHorisontal);
IMPLEMENT_STANDARD_HANDLE(SketcherPrs_LengthDimension, AIS_LengthDimension);
IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_LengthDimension, AIS_LengthDimension);
-SketcherPrs_LengthDimension::SketcherPrs_LengthDimension(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_LengthDimension::SketcherPrs_LengthDimension(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: AIS_LengthDimension(MyDefStart, MyDefEnd, MyDefPln),
myConstraint(theConstraint), myPlane(thePlane)
aPnt_A = aPoint_A->pnt();
aPnt_B = aPoint_B->pnt();
} else if (!aPoint_A && aPoint_B) {
- std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+ FeaturePtr aLine = SketcherPrs_Tools::getFeatureLine(
aData, SketchPlugin_Constraint::ENTITY_A());
if (aLine) {
aPnt_B = aPoint_B->pnt();
aPnt_A = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_B);
}
} else if (aPoint_A && !aPoint_B) {
- std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+ FeaturePtr aLine = SketcherPrs_Tools::getFeatureLine(
aData, SketchPlugin_Constraint::ENTITY_B());
if (aLine) {
aPnt_A = aPoint_A->pnt();
}
return false;
}
+
+
+
+void SketcherPrs_LengthDimension::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+ const Standard_Integer theMode)
+{
+ Standard_Integer aMode;
+ switch (theMode) {
+ case SketcherPrs_Tools::Sel_Dimension_All:
+ aMode = 0;
+ break;
+ case SketcherPrs_Tools::Sel_Dimension_Line:
+ aMode = 1;
+ break;
+ case SketcherPrs_Tools::Sel_Dimension_Text:
+ aMode = 2;
+ break;
+ default:
+ aMode = theMode;
+ }
+ AIS_LengthDimension::ComputeSelection(aSelection, aMode);
+}
#define SketcherPrs_LinearDimension_H
#include <GeomAPI_Ax3.h>
+#include <ModelAPI_Feature.h>
#include <AIS_LengthDimension.hxx>
#include <Standard_DefineHandle.hxx>
-class SketchPlugin_Constraint;
-
DEFINE_STANDARD_HANDLE(SketcherPrs_LengthDimension, AIS_LengthDimension)
/**
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_LengthDimension(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_LengthDimension(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
std::string constraintType() const;
Standard_EXPORT virtual void Compute(const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
const Handle(Prs3d_Presentation)& thePresentation, const Standard_Integer theMode = 0);
+ /// Redefinition of virtual function
+ Standard_EXPORT virtual void ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+ const Standard_Integer aMode);
+
private:
bool getPoints(gp_Pnt& thePnt1, gp_Pnt& thePnt2) const;
/// Constraint feature
- SketchPlugin_Constraint* myConstraint;
+ ModelAPI_Feature* myConstraint;
/// Plane of the current sketcher
std::shared_ptr<GeomAPI_Ax3> myPlane;
static Handle(Image_AlienPixMap) MyPixMap;
-SketcherPrs_Parallel::SketcherPrs_Parallel(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Parallel::SketcherPrs_Parallel(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: SketcherPrs_SymbolPrs(theConstraint, thePlane)
{
#include "SketcherPrs_SymbolPrs.h"
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
-
DEFINE_STANDARD_HANDLE(SketcherPrs_Parallel, SketcherPrs_SymbolPrs)
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_Parallel(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Parallel(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
DEFINE_STANDARD_RTTI(SketcherPrs_Parallel)
protected:
static Handle(Image_AlienPixMap) MyPixMap;
-SketcherPrs_Perpendicular::SketcherPrs_Perpendicular(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Perpendicular::SketcherPrs_Perpendicular(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: SketcherPrs_SymbolPrs(theConstraint, thePlane)
{
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_Perpendicular(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Perpendicular(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
DEFINE_STANDARD_RTTI(SketcherPrs_Perpendicular)
IMPLEMENT_STANDARD_HANDLE(SketcherPrs_Radius, AIS_RadiusDimension);
IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Radius, AIS_RadiusDimension);
-SketcherPrs_Radius::SketcherPrs_Radius(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Radius::SketcherPrs_Radius(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: AIS_RadiusDimension(MyDefCirc), myConstraint(theConstraint), myPlane(thePlane)
{
AIS_RadiusDimension::Compute(thePresentationManager, thePresentation, theMode);
}
+
+void SketcherPrs_Radius::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+ const Standard_Integer theMode)
+{
+ Standard_Integer aMode;
+ switch (theMode) {
+ case SketcherPrs_Tools::Sel_Dimension_All:
+ aMode = 0;
+ break;
+ case SketcherPrs_Tools::Sel_Dimension_Line:
+ aMode = 1;
+ break;
+ case SketcherPrs_Tools::Sel_Dimension_Text:
+ aMode = 2;
+ break;
+ default:
+ aMode = theMode;
+ }
+ AIS_RadiusDimension::ComputeSelection(aSelection, aMode);
+}
#define SketcherPrs_Radius_H
#include <GeomAPI_Ax3.h>
+#include <ModelAPI_Feature.h>
#include <AIS_RadiusDimension.hxx>
#include <Standard_DefineHandle.hxx>
-class SketchPlugin_Constraint;
-
DEFINE_STANDARD_HANDLE(SketcherPrs_Radius, AIS_RadiusDimension)
/**
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_Radius(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Radius(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
DEFINE_STANDARD_RTTI(SketcherPrs_Radius)
Standard_EXPORT virtual void Compute(const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
const Handle(Prs3d_Presentation)& thePresentation, const Standard_Integer theMode = 0);
+ /// Redefinition of virtual function
+ Standard_EXPORT virtual void ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+ const Standard_Integer aMode);
+
private:
/// Constraint feature
- SketchPlugin_Constraint* myConstraint;
+ ModelAPI_Feature* myConstraint;
/// Plane of the current sketcher
std::shared_ptr<GeomAPI_Ax3> myPlane;
-SketcherPrs_Rigid::SketcherPrs_Rigid(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Rigid::SketcherPrs_Rigid(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: SketcherPrs_SymbolPrs(theConstraint, thePlane)
{
#include "SketcherPrs_SymbolPrs.h"
#include <ModelAPI_Object.h>
-
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
+#include <ModelAPI_Feature.h>
DEFINE_STANDARD_HANDLE(SketcherPrs_Rigid, SketcherPrs_SymbolPrs)
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_Rigid(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Rigid(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
#include <Graphic3d_BndBox4f.hxx>
#include <SelectMgr_Selection.hxx>
+#include <SelectMgr_SelectionManager.hxx>
#include <Select3D_SensitivePoint.hxx>
#include <TopLoc_Location.hxx>
#include <AIS_InteractiveContext.hxx>
std::map<const char*, Handle(Image_AlienPixMap)> SketcherPrs_SymbolPrs::myIconsMap;
-SketcherPrs_SymbolPrs::SketcherPrs_SymbolPrs(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_SymbolPrs::SketcherPrs_SymbolPrs(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: AIS_InteractiveObject(), myConstraint(theConstraint), myPlane(thePlane)
{
const Standard_Integer aMode)
{
ClearSelected();
- for (int i = 1; i <= mySPoints.Length(); i++)
- aSelection->Add(mySPoints.Value(i));
+ if ((aMode == 0) || (aMode == SketcherPrs_Tools::Sel_Constraint)) {
+ for (int i = 1; i <= mySPoints.Length(); i++)
+ aSelection->Add(mySPoints.Value(i));
+ }
}
theWorkspace->EnableTexture (aTextureBack);
aCtx->BindProgram (NULL);
- // Update selection position
- GetContext()->RecomputeSelectionOnly(this);
+ // Update selection position only if there is no selected object
+ // because it can corrupt selection of other objects
+ if ((GetContext()->NbCurrents() == 0) && (GetContext()->NbSelected() == 0))
+ GetContext()->RecomputeSelectionOnly(this);
}
#define SketcherPrs_SymbolPrs_H
#include "SketcherPrs_SensitivePoint.h"
+#include <ModelAPI_Feature.h>
#include <AIS_InteractiveObject.hxx>
#include <GeomAPI_Ax3.h>
#include <OpenGl_Workspace.hxx>
-class SketchPlugin_Constraint;
class OpenGl_Context;
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_SymbolPrs(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_SymbolPrs(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
virtual ~SketcherPrs_SymbolPrs();
Standard_EXPORT std::shared_ptr<GeomAPI_Ax3> plane() const { return myPlane; }
- Standard_EXPORT SketchPlugin_Constraint* feature() const { return myConstraint; }
+ Standard_EXPORT ModelAPI_Feature* feature() const { return myConstraint; }
Handle(Graphic3d_ArrayOfPoints) pointsArray() const { return myPntArray; }
protected:
/// Constraint feature
- SketchPlugin_Constraint* myConstraint;
+ ModelAPI_Feature* myConstraint;
/// Plane of the current sketcher
std::shared_ptr<GeomAPI_Ax3> myPlane;
static Handle(Image_AlienPixMap) MyPixMap;
-SketcherPrs_Tangent::SketcherPrs_Tangent(SketchPlugin_Constraint* theConstraint,
+SketcherPrs_Tangent::SketcherPrs_Tangent(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane)
: SketcherPrs_SymbolPrs(theConstraint, thePlane)
{
#define SketcherPrs_Tangent_H
#include "SketcherPrs_SymbolPrs.h"
-
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
+#include <ModelAPI_Feature.h>
DEFINE_STANDARD_HANDLE(SketcherPrs_Tangent, SketcherPrs_SymbolPrs)
/// Constructor
/// \param theConstraint a constraint feature
/// \param thePlane a coordinate plane of current sketch
- Standard_EXPORT SketcherPrs_Tangent(SketchPlugin_Constraint* theConstraint,
+ Standard_EXPORT SketcherPrs_Tangent(ModelAPI_Feature* theConstraint,
const std::shared_ptr<GeomAPI_Ax3>& thePlane);
DEFINE_STANDARD_RTTI(SketcherPrs_Tangent)
namespace SketcherPrs_Tools {
-ObjectPtr getResult(SketchPlugin_Constraint* theFeature, const std::string& theAttrName)
+ObjectPtr getResult(ModelAPI_Feature* theFeature, const std::string& theAttrName)
{
std::shared_ptr<ModelAPI_Data> aData = theFeature->data();
std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
}
-std::shared_ptr<GeomAPI_Pnt2d> getPoint(SketchPlugin_Constraint* theFeature,
- const std::string& theAttribute)
+std::shared_ptr<GeomAPI_Pnt2d> getPoint(ModelAPI_Feature* theFeature,
+ const std::string& theAttribute)
{
std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
}
//*************************************************************************************
-std::shared_ptr<SketchPlugin_Line> getFeatureLine(DataPtr theData,
- const std::string& theAttribute)
+FeaturePtr getFeatureLine(DataPtr theData,
+ const std::string& theAttribute)
{
- std::shared_ptr<SketchPlugin_Line> aLine;
+ FeaturePtr aLine;
if (!theData)
return aLine;
- std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(theData->attribute(theAttribute));
+ std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theData->attribute(theAttribute));
if (anAttr) {
FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->object());
if (aFeature && aFeature->getKind() == SketchPlugin_Line::ID()) {
- aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aFeature);
+ return aFeature;
}
}
return aLine;
}
//*************************************************************************************
-std::shared_ptr<GeomAPI_Pnt2d> getProjectionPoint(
- const std::shared_ptr<SketchPlugin_Line>& theLine,
- const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+std::shared_ptr<GeomAPI_Pnt2d> getProjectionPoint(const FeaturePtr theLine,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
{
- std::shared_ptr<ModelAPI_Data> aData = theLine->data();
+ DataPtr aData = theLine->data();
std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
aData->attribute(SketchPlugin_Line::START_ID()));
std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
MyArrowSize = theSize;
}
-};
\ No newline at end of file
+};
#include <GeomAPI_Shape.h>
#include <GeomAPI_Pnt2d.h>
#include <ModelAPI_Object.h>
+#include <ModelAPI_Feature.h>
#include <string>
-class SketchPlugin_Constraint;
-class SketchPlugin_Line;
class GeomDataAPI_Point2D;
#define MyTextHeight 20
namespace SketcherPrs_Tools {
- SKETCHERPRS_EXPORT ObjectPtr getResult(SketchPlugin_Constraint* theFeature,
- const std::string& theAttrName);
+/// Enumeration with modes for activation of selection custom presentations
+enum SelectionModes {
+ /// Start of enumeration
+ Sel_Mode_First = 100,
+
+ /// Selection mode for all constraints exclude dimensions
+ Sel_Constraint,
+
+ /// Selection mode for whole dimension
+ Sel_Dimension_All,
+
+ /// Selection mode for line of dimension
+ Sel_Dimension_Line,
+
+ /// Selection mode foe text of dimension
+ Sel_Dimension_Text
+};
+
+ SKETCHERPRS_EXPORT ObjectPtr getResult(ModelAPI_Feature* theFeature,
+ const std::string& theAttrName);
SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Shape> getShape(ObjectPtr theObject);
- SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Pnt2d> getPoint(SketchPlugin_Constraint* theFeature,
+ SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Pnt2d> getPoint(ModelAPI_Feature* theFeature,
const std::string& theAttrName);
SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Pnt2d> getProjectionPoint(
- const std::shared_ptr<SketchPlugin_Line>& theLine,
+ const FeaturePtr theLine,
const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
- SKETCHERPRS_EXPORT std::shared_ptr<SketchPlugin_Line> getFeatureLine(DataPtr theData,
- const std::string& theAttribute);
+ SKETCHERPRS_EXPORT FeaturePtr getFeatureLine(DataPtr theData,
+ const std::string& theAttribute);
/// Obtain the point object from specified constraint parameter
SKETCHERPRS_EXPORT std::shared_ptr<GeomDataAPI_Point2D> getFeaturePoint(DataPtr theData,
SKETCHERPRS_EXPORT void setArrowSize(double theSize);
};
-#endif
\ No newline at end of file
+#endif
void XGUI_ActionsMgr::updateOnViewSelection()
{
- XGUI_Selection* aSelection = myWorkshop->selector()->selection();
- if (aSelection->getSelected().size() == 0 || !myOperationMgr->hasOperation())
+ if (!myOperationMgr->hasOperation())
return;
+
ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
FeaturePtr anActiveFeature = anOperation->feature();
if(!anActiveFeature.get())
return;
- QString aFeatureId = QString::fromStdString(anActiveFeature->getKind());
- SessionPtr aMgr = ModelAPI_Session::get();
- ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
- foreach(QString aId, nestedCommands(aFeatureId)) {
- std::list<ModelAPI_Validator*> aValidators;
- std::list<std::list<std::string> > anArguments;
- aFactory->validators(aId.toStdString(), aValidators, anArguments);
- std::list<ModelAPI_Validator*>::iterator aValidator = aValidators.begin();
- std::list<std::list<std::string> >::iterator aValidatorArgs = anArguments.begin();
- for (; aValidator != aValidators.end(); aValidator++, aValidatorArgs++) {
- if (!(*aValidator))
- continue;
- const ModuleBase_SelectionValidator* aSelValidator =
- dynamic_cast<const ModuleBase_SelectionValidator*>(*aValidator);
- if (!aSelValidator)
- continue;
- setActionEnabled(aId, aSelValidator->isValid(aSelection, *aValidatorArgs));
+ QString aFeatureId = QString::fromStdString(anActiveFeature->getKind());
+ XGUI_Selection* aSelection = myWorkshop->selector()->selection();
+ if (aSelection->getSelected().size() == 0) {
+ foreach(QString aId, nestedCommands(aFeatureId)) {
+ setActionEnabled(aId, true);
+ }
+ } else {
+ SessionPtr aMgr = ModelAPI_Session::get();
+ ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+ foreach(QString aId, nestedCommands(aFeatureId)) {
+ std::list<ModelAPI_Validator*> aValidators;
+ std::list<std::list<std::string> > anArguments;
+ aFactory->validators(aId.toStdString(), aValidators, anArguments);
+ std::list<ModelAPI_Validator*>::iterator aValidator = aValidators.begin();
+ std::list<std::list<std::string> >::iterator aValidatorArgs = anArguments.begin();
+ for (; aValidator != aValidators.end(); aValidator++, aValidatorArgs++) {
+ if (!(*aValidator))
+ continue;
+ const ModuleBase_SelectionValidator* aSelValidator =
+ dynamic_cast<const ModuleBase_SelectionValidator*>(*aValidator);
+ if (!aSelValidator)
+ continue;
+ setActionEnabled(aId, aSelValidator->isValid(aSelection, *aValidatorArgs));
+ }
}
}
}
GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
bool isShading = false;
if (aPrs.get() != NULL) {
- anAIS = aPrs->getAISObject(AISObjectPtr());
+ anAIS = aPrs->getAISObject(anAIS);
} else {
ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
if (aResult.get() != NULL) {
}
aContext->Display(anAISIO, false);
aContext->SetDisplayMode(anAISIO, isShading? Shading : Wireframe, false);
+ if (isShading)
+ anAISIO->Attributes()->SetFaceBoundaryDraw( Standard_True );
emit objectDisplayed(theObject, theAIS);
bool isCustomized = customizeObject(theObject);
}
return aCustomPrs->customisePresentation(aResult, anAISObj, myCustomPrs);
}
+
+
+QColor XGUI_Displayer::setObjectColor(ObjectPtr theObject, const QColor& theColor, bool toUpdate)
+{
+ if (!isVisible(theObject))
+ return Qt::black;
+
+ AISObjectPtr anAISObj = getAISObject(theObject);
+ int aR, aG, aB;
+ anAISObj->getColor(aR, aG, aB);
+ anAISObj->setColor(theColor.red(), theColor.green(), theColor.blue());
+ if (toUpdate)
+ updateViewer();
+ return QColor(aR, aG, aB);
+}
#include <QString>
#include <QMap>
#include <QObject>
+#include <QColor>
class ModelAPI_Feature;
class XGUI_Workshop;
/// \param theObject object to check
bool canBeShaded(ObjectPtr theObject) const;
+ /// Set color on presentation of an object if it is displayed
+ /// \param theObject an object
+ /// \param theColor a color which has to be set
+ /// \param theUpdate update viewer flag
+ /// \return previously defined color on the object
+ QColor setObjectColor(ObjectPtr theObject, const QColor& theColor, bool toUpdate = true);
signals:
/// Signal on object display
// Convert shape types to selection types
QIntList aModes;
foreach(int aType, theTypes) {
- aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum)aType));
+ if (aType > TopAbs_SHAPE)
+ aModes.append(aType);
+ else
+ aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum)aType));
}
aDisp->activateObjects(aModes);
//TODO: We have to open Local context because at neutral point filters don't work (bug 25340)
//******************************************************
void XGUI_Workshop::onRedo(int theTimes)
{
+ // the viewer update should be blocked in order to avoid the features blinking. For the created
+ // feature a results are created, the flush of the created signal caused the viewer redisplay for
+ // each created result. After a redisplay signal is flushed. So, the viewer update is blocked until
+ // redo of all possible objects happens
+ bool isUpdateEnabled = myDisplayer->enableUpdateViewer(false);
+
objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
SessionPtr aMgr = ModelAPI_Session::get();
if (aMgr->isOperation())
aMgr->redo();
}
updateCommandStatus();
+
+ // unblock the viewer update functionality and make update on purpose
+ myDisplayer->enableUpdateViewer(isUpdateEnabled);
+ myDisplayer->updateViewer();
}
//******************************************************