+// Copyright (C) 2014-2023 CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
#include <SketchSolver_ConstraintMirror.h>
#include <SketchSolver_Error.h>
-#include <SketchSolver_Manager.h>
+#include <PlaneGCSSolver_Tools.h>
+#include <PlaneGCSSolver_UpdateFeature.h>
+
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeRefList.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_EllipticArc.h>
+
+
+static void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
+ const AttributePoint2DPtr& theOriginal,
+ const AttributePoint2DPtr& theMirrored);
+
+static void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
+ const FeaturePtr& theOriginal,
+ const FeaturePtr& theMirrored);
+
+
void SketchSolver_ConstraintMirror::getAttributes(
- EntityWrapperPtr& theMirrorLine,
- std::vector<EntityWrapperPtr>& theBaseEntities,
- std::vector<EntityWrapperPtr>& theMirrorEntities)
+ EntityWrapperPtr&,
+ std::vector<EntityWrapperPtr>&)
{
- AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A());
AttributeRefAttrPtr aMirLineRefAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aMirLineAttr);
+ myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) {
myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
return;
}
+ FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aMirLineRefAttr->object());
+ myFeatures.insert(aMirrorLine);
+
myType = TYPE(myBaseConstraint);
- myStorage->update(aMirLineAttr/*, myGroupID*/);
- theMirrorLine = myStorage->entity(aMirLineAttr);
-
- // 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()));
+ myStorage->update(aMirrorLine);
+
+
+ AttributeRefListPtr aBaseRefList =
+ myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
+ AttributeRefListPtr aMirroredRefList =
+ myBaseConstraint->reflist(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;
- 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<EntityWrapperPtr>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
- for ( ; anIter != aEndIter; anIter++) {
- aFeature = ModelAPI_Feature::feature(*anIter);
- if (!aFeature)
- continue;
-
- myStorage->update(aFeature/*, myGroupID*/);
- aList->push_back(myStorage->entity(aFeature));
+ // store only original entities because mirrored ones
+ // will be updated separately in adjustConstraint
+ std::list<ObjectPtr> aList = aBaseRefList->list();
+ std::list<ObjectPtr>::iterator anIt = aList.begin();
+ for (; anIt != aList.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature) {
+ myStorage->update(aFeature);
+ myFeatures.insert(aFeature);
}
}
-
- // Mirrored entities are placed out-of-group by default, due to they are copies.
- // Place them into current group manually.
- std::vector<EntityWrapperPtr>::iterator aMirIt = theMirrorEntities.begin();
- for (; aMirIt != theMirrorEntities.end(); ++aMirIt)
- (*aMirIt)->setGroup(myGroupID);
-
- if (theBaseEntities.size() > theMirrorEntities.size())
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ // add mirrored features to the list
+ aList = aMirroredRefList->list();
+ for (anIt = aList.begin(); anIt != aList.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature)
+ myFeatures.insert(aFeature);
+ }
}
void SketchSolver_ConstraintMirror::process()
{
cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
+ if (!myBaseConstraint || !myStorage) {
// Not enough parameters are assigned
return;
}
EntityWrapperPtr aMirrorLine;
std::vector<EntityWrapperPtr> aBaseList;
- std::vector<EntityWrapperPtr> aMirrorList;
- getAttributes(aMirrorLine, aBaseList, aMirrorList);
+ getAttributes(aMirrorLine, aBaseList);
if (!myErrorMsg.empty())
return;
- if (aBaseList.size() != aMirrorList.size()) {
- myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
- return;
- }
-
- std::list<ConstraintWrapperPtr> aNewConstraints;
- SketchSolver_ConstraintType aConstrType = getType();
- BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
- std::list<ConstraintWrapperPtr> aMirConstrList;
-
- std::vector<EntityWrapperPtr>::iterator aBIt = aBaseList.begin();
- std::vector<EntityWrapperPtr>::iterator aMIt = aMirrorList.begin();
- for (; aBIt != aBaseList.end(); ++aBIt, ++aMIt) {
- if ((*aBIt)->type() == ENTITY_ARC) {
- // add new points on arcs and mirror them
- EntityWrapperPtr aBasePnt = myStorage->calculateMiddlePoint(*aBIt, 0.5);
- EntityWrapperPtr aMirrPnt = myStorage->calculateMiddlePoint(*aMIt, 0.5);
- // point on base arc
- aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
- CONSTRAINT_PT_ON_CIRCLE, 0.0, aBasePnt, EntityWrapperPtr(), *aBIt);
- aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
- // point on mirrored arc
- aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
- CONSTRAINT_PT_ON_CIRCLE, 0.0, aMirrPnt, EntityWrapperPtr(), *aMIt);
- aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
- // mirror these points
- aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
- aConstrType, 0.0, aBasePnt, aMirrPnt, aMirrorLine);
- aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
- }
- aNewConstraints = aBuilder->createConstraint(
- myBaseConstraint, myGroupID, mySketchID, aConstrType,
- 0.0, *aBIt, *aMIt, aMirrorLine);
- aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
- }
-
- // update mirrored features to be in the current group
- for (aMIt = aMirrorList.begin(); aMIt != aMirrorList.end(); ++aMIt)
- myStorage->update((*aMIt)->baseFeature(), myGroupID);
- myStorage->addConstraint(myBaseConstraint, aMirConstrList);
+ adjustConstraint();
+ myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
}
void SketchSolver_ConstraintMirror::adjustConstraint()
{
- BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ AttributeRefAttrPtr aMirrLineRefAttr =
+ myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+ std::shared_ptr<GeomAPI_Lin2d> aMirrorLine =
+ PlaneGCSSolver_Tools::line(ModelAPI_Feature::feature(aMirrLineRefAttr->object()));
- const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
- std::list<ConstraintWrapperPtr>::const_iterator aCIt = aConstraints.begin();
- for (; aCIt != aConstraints.end(); ++aCIt)
- if ((*aCIt)->type() == CONSTRAINT_SYMMETRIC)
- aBuilder->adjustConstraint(*aCIt);
+ AttributeRefListPtr aBaseRefList =
+ myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
+ AttributeRefListPtr aMirroredRefList =
+ myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
+
+ std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+ std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+ std::list<ObjectPtr>::iterator aBIt, aMIt;
+ for (aBIt = aBaseList.begin(), aMIt = aMirroredList.begin();
+ aBIt != aBaseList.end() && aMIt != aMirroredList.end();
+ ++aBIt, ++aMIt) {
+ FeaturePtr aBase = ModelAPI_Feature::feature(*aBIt);
+ FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt);
+ mirrorEntities(aMirrorLine, aBase, aMirrored);
+
+ // update mirrored entity if it exists in the storage
+ if (myStorage->entity(aMirrored))
+ myStorage->update(aMirrored);
+ }
+}
+
+void SketchSolver_ConstraintMirror::notify(const FeaturePtr& theFeature,
+ PlaneGCSSolver_Update*)
+{
+ if (myFeatures.find(theFeature) == myFeatures.end())
+ return; // the feature is not used by constraint => nothing to update
+ adjustConstraint();
+}
+
+void SketchSolver_ConstraintMirror::blockEvents(bool isBlocked)
+{
+ std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
+ for (; anIt != myFeatures.end(); ++anIt)
+ (*anIt)->data()->blockSendAttributeUpdated(isBlocked);
+
+ SketchSolver_Constraint::blockEvents(isBlocked);
+}
+
+
+
+
+// ================= Auxiliary functions ==================================
+void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
+ const AttributePoint2DPtr& theOriginal,
+ const AttributePoint2DPtr& theMirrored)
+{
+ std::shared_ptr<GeomAPI_Pnt2d> anOriginal = theOriginal->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aPtOnLine = theMirrorLine->project(anOriginal);
+ std::shared_ptr<GeomAPI_XY> aPerp = aPtOnLine->xy()->decreased(anOriginal->xy());
+ theMirrored->setValue(anOriginal->x() + aPerp->x() * 2.0, anOriginal->y() + aPerp->y() * 2.0);
+}
+
+void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
+ const FeaturePtr& theOriginal,
+ const FeaturePtr& theMirrored)
+{
+ std::list<AttributePtr> aPoints0 =
+ theOriginal->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr> aPoints1 =
+ theMirrored->data()->attributes(GeomDataAPI_Point2D::typeId());
+
+ // process specific features
+ if (theOriginal->getKind() == SketchPlugin_Arc::ID()) {
+ // orientation of arc
+ theMirrored->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(
+ !theOriginal->boolean(SketchPlugin_Arc::REVERSED_ID())->value());
+ } else if (theOriginal->getKind() == SketchPlugin_Circle::ID()) {
+ // radius of the circle
+ theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
+ theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
+ }
+ else if (theOriginal->getKind() == SketchPlugin_EllipticArc::ID()) {
+ // orientation of arc
+ theMirrored->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(
+ !theOriginal->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->value());
+ }
+
+ // mirror all initialized points of features
+ std::list<AttributePtr>::iterator anIt0, anIt1;
+ for (anIt0 = aPoints0.begin(), anIt1 = aPoints1.begin();
+ anIt0 != aPoints0.end() && anIt1 != aPoints1.end(); ++anIt0, ++anIt1) {
+ AttributePoint2DPtr aPt0 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt0);
+ AttributePoint2DPtr aPt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt1);
+ if (aPt0->isInitialized() && aPt1->isInitialized())
+ mirrorPoints(theMirrorLine, aPt0, aPt1);
+ }
}