1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: PlaneGCSSolver_Storage.cpp
4 // Created: 14 Dec 2015
5 // Author: Artem ZHIDKOV
7 #include <PlaneGCSSolver_Storage.h>
8 #include <PlaneGCSSolver_Builder.h>
9 #include <PlaneGCSSolver_Solver.h>
10 #include <PlaneGCSSolver_ConstraintWrapper.h>
11 #include <PlaneGCSSolver_EntityWrapper.h>
12 #include <PlaneGCSSolver_PointWrapper.h>
13 #include <PlaneGCSSolver_ScalarWrapper.h>
14 #include <PlaneGCSSolver_ParameterWrapper.h>
16 #include <GeomAPI_Edge.h>
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_XY.h>
20 #include <GeomDataAPI_Point2D.h>
21 #include <SketchPlugin_Arc.h>
22 #include <SketchPlugin_ConstraintTangent.h>
27 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup)
28 : SketchSolver_Storage(theGroup),
29 myEntityLastID(EID_SKETCH),
30 myConstraintLastID(CID_UNKNOWN)
34 void PlaneGCSSolver_Storage::addConstraint(
35 ConstraintPtr theConstraint,
36 std::list<ConstraintWrapperPtr> theSolverConstraints)
38 SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraints);
40 // update point-point coincidence
41 if (!theSolverConstraints.empty() &&
42 theSolverConstraints.front()->type() == CONSTRAINT_PT_PT_COINCIDENT) {
43 std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
44 for (; aCIt != theSolverConstraints.end(); ++aCIt)
50 bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr theConstraint)
52 bool isUpdated = false;
53 std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
54 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
56 // point-Line distance should be positive
57 if (aConstraint->type() == CONSTRAINT_PT_LINE_DISTANCE && aConstraint->value() < 0.0)
58 aConstraint->setValue(-aConstraint->value());
60 // make value of constraint unchangeable
61 ParameterWrapperPtr aValue = aConstraint->valueParameter();
63 isUpdated = update(aValue) || isUpdated;
65 // update constrained entities
66 std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
67 std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
68 for (; anIt != anEntities.end(); ++anIt)
69 isUpdated = update(*anIt) || isUpdated;
71 if (aConstraint->id() == CID_UNKNOWN) {
72 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
73 // check middle-point constraint conflicts with point-on-line
74 if (aConstraint->type() == CONSTRAINT_MIDDLE_POINT) {
75 std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
76 anIt = myConstraintMap.begin();
77 for (; anIt != myConstraintMap.end(); ++anIt) {
78 EntityWrapperPtr aPoint, aLine;
79 if (anIt->second.empty())
81 ConstraintWrapperPtr aCurrentConstr = anIt->second.front();
82 if (aCurrentConstr->type() != CONSTRAINT_PT_ON_LINE)
84 const std::list<EntityWrapperPtr>& aCurSubs = aCurrentConstr->entities();
85 std::list<EntityWrapperPtr>::const_iterator aSIt1, aSIt2;
86 for (aSIt1 = aSubs.begin(); aSIt1 != aSubs.end(); ++aSIt1) {
87 if ((*aSIt1)->type() == ENTITY_POINT)
89 else if((*aSIt1)->type() == ENTITY_LINE)
93 for (aSIt2 = aCurSubs.begin(); aSIt2 != aCurSubs.end(); ++aSIt2)
94 if ((*aSIt1)->id() == (*aSIt2)->id())
96 if (aSIt2 == aCurSubs.end())
99 // point-on-line found, change it to bisector
100 if (aSIt1 == aSubs.end()) {
101 std::list<GCSConstraintPtr> aConstrList = aConstraint->constraints();
102 aConstrList.pop_front();
103 aConstraint->setConstraints(aConstrList);
109 // Change ID of constraints
110 aConstraint->setId(++myConstraintLastID);
116 /// \brief Update coordinates of the point or scalar using its base attribute
117 static bool updateValues(EntityWrapperPtr& theEntity)
119 const double aTol = 1000. * tolerance;
120 bool isUpdated = false;
121 AttributePtr anAttr = theEntity->baseAttribute();
122 const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
126 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
127 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
129 aCoord[0] = aPoint2D->x();
130 aCoord[1] = aPoint2D->y();
132 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
134 aCoord[0] = aScalar->value();
137 std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
138 for (int i = 0; anIt != aParams.end(); ++anIt, ++i)
139 if (fabs((*anIt)->value() - aCoord[i]) > aTol) {
140 (*anIt)->setValue(aCoord[i]);
146 bool PlaneGCSSolver_Storage::update(EntityWrapperPtr theEntity)
148 if (theEntity->type() == ENTITY_SKETCH)
149 return true; // sketch is not necessary for PlaneGCS, so it is always says true
151 bool isUpdated = false;
153 if (theEntity->baseAttribute()) {
154 isUpdated = updateValues(theEntity);
156 setNeedToResolve(true);
157 if (theEntity->type() == ENTITY_POINT && theEntity->group() != myGroupID)
158 updateCoincident(theEntity);
163 std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
164 std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
165 for (; aPIt != aParams.end(); ++aPIt)
166 isUpdated = update(*aPIt) || isUpdated;
168 // update sub-entities
169 std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
170 std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
171 for (; aSIt != aSubEntities.end(); ++aSIt)
172 isUpdated = update(*aSIt) || isUpdated;
174 // additional constraints for the arc processing
175 if (theEntity->type() == ENTITY_ARC)
176 processArc(theEntity);
178 // Change entity's ID, if necessary
179 if (theEntity->id() == EID_UNKNOWN) {
180 if (theEntity->type() == ENTITY_POINT) {
181 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
182 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
184 aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
185 theEntity->subEntities().front());
187 aPoint->setId(++myEntityLastID);
188 } else if (theEntity->type() == ENTITY_SCALAR) {
189 std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aScalar =
190 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
191 aScalar->setId(++myEntityLastID);
193 std::shared_ptr<PlaneGCSSolver_EntityWrapper> aGCSEnt =
194 std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity);
195 aGCSEnt->setId(++myEntityLastID);
201 bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter)
203 std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
204 std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
205 if (aParam->isProcessed())
207 if (theParameter->group() != myGroupID || theParameter->isParametric())
208 myConst.push_back(aParam->parameter());
210 myParameters.push_back(aParam->parameter());
211 aParam->setProcessed(true);
216 bool PlaneGCSSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
218 std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
219 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
221 bool isFullyRemoved = true;
222 // remove point-point coincidence
223 if (aConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT)
224 isFullyRemoved = removeCoincidence(theConstraint) && isFullyRemoved;
225 // remove sub-entities
226 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
227 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
228 for (; aSIt != aSubs.end(); ++ aSIt)
229 isFullyRemoved = remove(*aSIt) && isFullyRemoved;
231 if (aConstraint->valueParameter())
232 isFullyRemoved = remove(aConstraint->valueParameter()) && isFullyRemoved;
233 if (!isFullyRemoved && aConstraint->baseConstraint() &&
234 (!aConstraint->baseConstraint()->data() || !aConstraint->baseConstraint()->data()->isValid()))
235 isFullyRemoved = true;
236 setNeedToResolve(true);
237 myRemovedConstraints.insert(myRemovedConstraints.end(),
238 aConstraint->constraints().begin(), aConstraint->constraints().end());
240 if (isFullyRemoved && theConstraint->id() == myConstraintLastID)
241 --myConstraintLastID;
243 return isFullyRemoved;
246 bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity)
248 // do not remove entity, if it is used by constraints or other entities
249 if ((theEntity->baseFeature() && isUsed(theEntity->baseFeature())) ||
250 (theEntity->baseAttribute() && isUsed(theEntity->baseAttribute())))
253 bool isFullyRemoved = SketchSolver_Storage::remove(theEntity);
254 if (isFullyRemoved) {
255 if (theEntity->type() == ENTITY_ARC) {
256 // remove arc additional constraints
257 std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::iterator
258 aFound = myArcConstraintMap.find(theEntity);
259 if (aFound != myArcConstraintMap.end()) {
260 myRemovedConstraints.insert(myRemovedConstraints.end(),
261 aFound->second.begin(), aFound->second.end());
262 myArcConstraintMap.erase(aFound);
265 if (theEntity->id() == myEntityLastID)
268 return isFullyRemoved;
271 bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter)
273 std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
274 std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
275 if (aParam->isProcessed()) {
276 double* aValPtr = aParam->parameter();
277 GCS::VEC_pD::iterator anIt = myParameters.begin();
278 for (; anIt != myParameters.end(); ++anIt)
279 if (*anIt == aValPtr)
281 if (anIt != myParameters.end()) {
282 myParameters.erase(anIt);
283 setNeedToResolve(true);
284 aParam->setProcessed(false);
287 for (anIt = myConst.begin(); anIt != myConst.end(); ++anIt)
288 if (*anIt == aValPtr)
290 if (anIt != myConst.end()) {
292 setNeedToResolve(true);
293 aParam->setProcessed(false);
301 void PlaneGCSSolver_Storage::addCoincidentPoints(
302 EntityWrapperPtr theMaster, EntityWrapperPtr theSlave)
304 if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
307 std::shared_ptr<PlaneGCSSolver_PointWrapper> aMaster =
308 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theMaster);
310 aMaster = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
311 std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theMaster)->subEntities().front());
312 std::shared_ptr<PlaneGCSSolver_PointWrapper> aSlave =
313 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSlave);
315 aSlave = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
316 std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theSlave)->subEntities().front());
318 // Search available coincidence
319 CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(aMaster);
320 CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(aSlave);
321 if (aMasterFound == myCoincidentPoints.end() && aSlaveFound == myCoincidentPoints.end()) {
322 // try to find master and slave points in the lists of slaves of already existent coincidences
323 CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
324 for (; anIt != myCoincidentPoints.end(); ++anIt) {
325 if (anIt->second.find(aMaster) != anIt->second.end())
327 else if (anIt->second.find(aSlave) != anIt->second.end())
330 if (aMasterFound != myCoincidentPoints.end() && aSlaveFound != myCoincidentPoints.end())
335 if (aMasterFound == myCoincidentPoints.end()) {
337 myCoincidentPoints[aMaster] = std::set<EntityWrapperPtr>();
338 aMasterFound = myCoincidentPoints.find(aMaster);
339 } else if (aMasterFound == aSlaveFound)
340 return; // already coincident
342 if (aSlaveFound != myCoincidentPoints.end()) {
343 // A slave has been found, we need to attach all points coincident with it to the new master
344 std::set<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
345 aNewSlaves.insert(aSlaveFound->first);
346 myCoincidentPoints.erase(aSlaveFound);
348 std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
349 for (; aSlIt != aNewSlaves.end(); ++aSlIt)
350 addCoincidentPoints(aMaster, *aSlIt);
352 //std::list<ParameterWrapperPtr> aSlaveParams = aSlave->parameters();
353 //aSlave->setParameters(aMaster->parameters());
355 //// Remove slave's parameters
356 //std::list<ParameterWrapperPtr>::iterator aParIt = aSlaveParams.begin();
357 //for (; aParIt != aSlaveParams.end(); ++aParIt)
360 aMasterFound->second.insert(aSlave);
365 void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
367 theEntity->setGroup(theGroup);
368 if (theGroup == myGroupID)
369 makeVariable(theEntity);
371 if (theEntity->type() == ENTITY_POINT)
373 makeConstant(theEntity);
377 void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
382 void PlaneGCSSolver_Storage::verifyFixed()
387 void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc)
389 // Calculate additional parameters necessary for PlaneGCS
390 const std::list<EntityWrapperPtr>& aSubs = theArc->subEntities();
391 std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
392 bool isFixed[3] = {false, false, false};
393 for (int i = 0; (*aSubIt)->type() == ENTITY_POINT; ++i) { // search scalar entities
394 isFixed[i] = (*aSubIt)->group() == GID_OUTOFGROUP;
397 double* aStartAngle =
398 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
400 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
401 double* aRadius = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt)->scalar();
403 std::shared_ptr<SketchPlugin_Feature> anArcFeature =
404 std::dynamic_pointer_cast<SketchPlugin_Feature>(theArc->baseFeature());
405 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
406 anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
407 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
408 anArcFeature->attribute(SketchPlugin_Arc::START_ID()));
409 std::shared_ptr<GeomDataAPI_Point2D> aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
410 anArcFeature->attribute(SketchPlugin_Arc::END_ID()));
411 if (!aCenterAttr || !aStartAttr || !aEndAttr)
413 std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = aCenterAttr->pnt();
414 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aStartAttr->pnt();
415 std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aEndAttr->pnt();
417 if (isFixed[2] && !isFixed[1])
418 *aRadius = aCenterPnt->distance(aEndPnt);
420 *aRadius = aCenterPnt->distance(aStartPnt);
421 if (!anArcFeature->lastResult())
423 static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
424 std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(
425 aStartPnt->xy()->decreased(aCenterPnt->xy())));
426 *aStartAngle = OX->angle(aDir);
427 aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
428 aEndPnt->xy()->decreased(aCenterPnt->xy())));
429 *aEndAngle = OX->angle(aDir);
431 // no need to constraint a fixed or a copied arc
432 if (theArc->group() == GID_OUTOFGROUP || anArcFeature->isCopy())
434 // No need to add constraints if they are already exist
435 std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
436 aFound = myArcConstraintMap.find(theArc);
437 // if (aFound != myArcConstraintMap.end())
440 // Prepare additional constraints to produce the arc
441 std::vector<GCSConstraintPtr> anArcConstraints;
442 std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt =
443 std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theArc);
444 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt->entity());
445 // Distances from center till start and end points are equal to radius
446 GCSConstraintPtr aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance(
447 anArc->center, anArc->start, anArc->rad));
448 // aNew->setTag((int)(++myConstraintLastID));
449 anArcConstraints.push_back(aNew);
450 aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance(
451 anArc->center, anArc->end, anArc->rad));
452 // aNew->setTag((int)myConstraintLastID);
453 anArcConstraints.push_back(aNew);
454 // Angles of start and end points should be equal to given angles
455 aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle(
456 anArc->center, anArc->start, anArc->startAngle));
457 // aNew->setTag((int)myConstraintLastID);
458 anArcConstraints.push_back(aNew);
459 aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle(
460 anArc->center, anArc->end, anArc->endAngle));
461 // aNew->setTag((int)myConstraintLastID);
462 anArcConstraints.push_back(aNew);
464 myArcConstraintMap[theArc] = anArcConstraints;
468 void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity)
470 toggleEntity(theEntity, myParameters, myConst);
471 if (theEntity->type() == ENTITY_POINT)
472 updateCoincident(theEntity);
475 void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity)
477 toggleEntity(theEntity, myConst, myParameters);
480 static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set<double*>& theParamList)
482 const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
483 std::list<ParameterWrapperPtr>::const_iterator aPIt = aParams.begin();
484 for (; aPIt != aParams.end(); ++aPIt)
486 std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*aPIt)->parameter());
488 const std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
489 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
491 if (theEntity->type() == ENTITY_ARC) {
492 // workaround for the arc processing, because the arc is fixed by a set of constraints,
493 // which will conflict with all parameters fixed:
495 getParametersToMove(*aSIt++, theParamList);
496 // 2. skip start and end points
498 // 3. take radius, start angle and end angle parameters
499 getParametersToMove(*(++aSIt), theParamList);
500 getParametersToMove(*(++aSIt), theParamList);
501 getParametersToMove(*(++aSIt), theParamList);
503 for (; aSIt != aSubs.end(); ++aSIt)
504 getParametersToMove(*aSIt, theParamList);
508 void PlaneGCSSolver_Storage::toggleEntity(
509 const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo)
511 std::set<double*> aParamsToMove;
512 getParametersToMove(theEntity, aParamsToMove);
514 GCS::VEC_pD::iterator anIt = theFrom.begin();
515 while (anIt != theFrom.end()) {
516 if (aParamsToMove.find(*anIt) == aParamsToMove.end()) {
521 theTo.push_back(*anIt);
522 int aShift = int(anIt - theFrom.begin());
524 anIt = theFrom.begin() + aShift;
528 void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint)
530 CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
531 for (; anIt != myCoincidentPoints.end(); ++anIt) {
532 if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) {
533 std::set<EntityWrapperPtr> aCoincident = anIt->second;
534 aCoincident.insert(anIt->first);
536 const std::list<ParameterWrapperPtr>& aBaseParams = thePoint->parameters();
537 std::list<ParameterWrapperPtr> aParams;
538 std::list<ParameterWrapperPtr>::const_iterator aBaseIt, anUpdIt;
540 std::set<EntityWrapperPtr>::const_iterator aCoincIt = aCoincident.begin();
541 for (; aCoincIt != aCoincident.end(); ++aCoincIt)
542 if (*aCoincIt != thePoint && (*aCoincIt)->group() != GID_OUTOFGROUP) {
543 aParams = (*aCoincIt)->parameters();
544 aBaseIt = aBaseParams.begin();
545 for (anUpdIt = aParams.begin(); anUpdIt != aParams.end(); ++anUpdIt, ++aBaseIt)
546 (*anUpdIt)->setValue((*aBaseIt)->value());
555 bool PlaneGCSSolver_Storage::isRedundant(
556 GCSConstraintPtr theCheckedConstraint,
557 ConstraintWrapperPtr theParentConstraint,
558 std::list<std::set<double*> >& theCoincidentPoints) const
560 if (theParentConstraint->type() == CONSTRAINT_SYMMETRIC) {
561 if (theCheckedConstraint->getTypeId() == GCS::Perpendicular) {
562 BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
563 // check the initial point is placed on the mirror line
564 std::list<EntityWrapperPtr> aSubs = theParentConstraint->entities();
565 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(aSubs.front());
566 std::shared_ptr<GeomAPI_Lin2d> aLine = aBuilder->line(aSubs.back());
567 return aLine->distance(aPoint) < tolerance;
570 else if (theParentConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT) {
571 // Verify that the coincidence between points is already added
572 GCS::VEC_pD aParams = theCheckedConstraint->params();
574 std::list<std::set<double*> >::iterator aCoincIt, aFound1, aFound2;
575 aFound1 = aFound2 = theCoincidentPoints.end();
576 for (aCoincIt = theCoincidentPoints.begin();
577 aCoincIt != theCoincidentPoints.end(); ++aCoincIt) {
578 if (aFound1 == theCoincidentPoints.end() && aCoincIt->find(aParams[0]) != aCoincIt->end())
580 if (aFound2 == theCoincidentPoints.end() && aCoincIt->find(aParams[1]) != aCoincIt->end())
582 if (aFound1 != theCoincidentPoints.end() && aFound2 != theCoincidentPoints.end())
585 if (aCoincIt != theCoincidentPoints.end()) { // both point are found
586 if (aFound1 == aFound2)
588 // merge two groups of coincidence
589 aFound1->insert(aFound2->begin(), aFound2->end());
590 theCoincidentPoints.erase(aFound2);
592 if (aFound1 != theCoincidentPoints.end())
593 aFound1->insert(aParams[1]);
594 else if (aFound2 != theCoincidentPoints.end())
595 aFound2->insert(aParams[0]);
597 std::set<double*> aNewCoincidence;
598 aNewCoincidence.insert(aParams[0]);
599 aNewCoincidence.insert(aParams[1]);
600 theCoincidentPoints.push_back(aNewCoincidence);
608 void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver)
610 std::shared_ptr<PlaneGCSSolver_Solver> aSolver =
611 std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(theSolver);
619 // initialize constraints
620 std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
621 aCIt = myConstraintMap.begin();
622 GCS::SET_I aTangentIDs;
623 std::list<std::set<double*> > aCoincidentPoints;
624 for (; aCIt != myConstraintMap.end(); ++aCIt) {
625 std::list<ConstraintWrapperPtr>::const_iterator aCWIt = aCIt->second.begin();
626 for (; aCWIt != aCIt->second.end(); ++ aCWIt) {
627 std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aGCS =
628 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(*aCWIt);
629 std::list<GCSConstraintPtr>::const_iterator anIt = aGCS->constraints().begin();
630 for (; anIt != aGCS->constraints().end(); ++anIt)
631 if (!isRedundant(*anIt, aGCS, aCoincidentPoints))
632 aSolver->addConstraint(*anIt, aGCS->type());
634 // store IDs of tangent constraints to avoid incorrect report of redundant constraints
635 if (aCIt->first && aCIt->first->getKind() == SketchPlugin_ConstraintTangent::ID())
636 for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++ aCWIt)
637 aTangentIDs.insert((int)(*aCWIt)->id());
639 // additional constraints for arcs
640 std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
641 anArcIt = myArcConstraintMap.begin();
642 for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) {
643 std::vector<GCSConstraintPtr>::const_iterator anIt = anArcIt->second.begin();
644 for (; anIt != anArcIt->second.end(); ++anIt)
645 aSolver->addConstraint(*anIt, CONSTRAINT_UNKNOWN);
647 // removed waste constraints
648 std::list<GCSConstraintPtr>::const_iterator aRemIt = myRemovedConstraints.begin();
649 for (; aRemIt != myRemovedConstraints.end(); ++aRemIt)
650 aSolver->removeConstraint(*aRemIt);
651 myRemovedConstraints.clear();
652 // set list of tangent constraints
653 aSolver->setTangent(aTangentIDs);
654 // initialize unknowns
655 aSolver->setParameters(myParameters);
658 // indicates attribute containing in the external feature
659 bool isExternalAttribute(const AttributePtr& theAttribute)
663 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
664 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
665 return aSketchFeature.get() && aSketchFeature->isExternal();
668 void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const
672 const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
674 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
675 std::list<ParameterWrapperPtr> aParams;
676 std::list<ParameterWrapperPtr>::const_iterator aParIt;
677 for (; anIt != myAttributeMap.end(); ++anIt) {
678 // the external feature always should keep the up to date values, so,
679 // refresh from the solver is never needed
680 bool isExternal = isExternalAttribute(anIt->first);
682 // update parameter wrappers and obtain values of attributes
683 aParams = anIt->second->parameters();
685 bool isUpd[3] = {false};
687 for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
688 if (!theFixedOnly || isExternal ||
689 (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) {
690 aCoords[i] = (*aParIt)->value();
694 if (!isUpd[0] && !isUpd[1] && !isUpd[2])
695 continue; // nothing is updated
697 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
698 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
700 if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > aTol) ||
701 (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > aTol) || isExternal) {
702 // Find points coincident with this one (probably not in GID_OUTOFGROUP)
703 CoincidentPointsMap::const_iterator aCoincIt = myCoincidentPoints.begin();
704 for (; aCoincIt != myCoincidentPoints.end(); ++aCoincIt)
705 if (aCoincIt->first == anIt->second ||
706 aCoincIt->second.find(anIt->second) != aCoincIt->second.end())
708 // get coordinates of "master"-point
709 std::shared_ptr<GeomDataAPI_Point2D> aMaster = aCoincIt != myCoincidentPoints.end() ?
710 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCoincIt->first->baseAttribute()) :
712 if (!isUpd[0] || isExternal) aCoords[0] = aMaster->x();
713 if (!isUpd[1] || isExternal) aCoords[1] = aMaster->y();
715 aPoint2D->setValue(aCoords[0], aCoords[1]);
716 if (aCoincIt != myCoincidentPoints.end()) {
717 if (aMaster && !isExternalAttribute(aMaster))
718 aMaster->setValue(aCoords[0], aCoords[1]);
719 std::set<EntityWrapperPtr>::const_iterator aSlaveIt = aCoincIt->second.begin();
720 for (; aSlaveIt != aCoincIt->second.end(); ++aSlaveIt) {
721 aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>((*aSlaveIt)->baseAttribute());
722 if (aPoint2D && !isExternalAttribute(aPoint2D))
723 aPoint2D->setValue(aCoords[0], aCoords[1]);
729 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
730 if (aScalar && !isExternal) {
731 if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > aTol)
732 aScalar->setValue(aCoords[0]);
737 //blockEvents(false);
740 EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint(
741 EntityWrapperPtr theBase, double theCoeff)
743 std::shared_ptr<PlaneGCSSolver_Builder> aBuilder =
744 std::dynamic_pointer_cast<PlaneGCSSolver_Builder>(PlaneGCSSolver_Builder::getInstance());
746 std::shared_ptr<GeomAPI_XY> aMidPoint;
747 if (theBase->type() == ENTITY_LINE) {
748 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
749 const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
750 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
751 for (int i = 0; i < 2; ++i, ++anIt)
752 aPoints[i] = aBuilder->point(*anIt);
753 aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added(
754 aPoints[1]->xy()->multiplied(theCoeff));
756 else if (theBase->type() == ENTITY_ARC) {
758 double anArcPoint[3][2];
759 const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
760 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
761 for (int i = 0; i < 3; ++i, ++anIt) {
762 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(*anIt);
763 anArcPoint[i][0] = aPoint->x();
764 anArcPoint[i][1] = aPoint->y();
766 // project last point of arc on the arc
767 double x = anArcPoint[1][0] - anArcPoint[0][0];
768 double y = anArcPoint[1][1] - anArcPoint[0][1];
769 double aRad = sqrt(x*x + y*y);
770 x = anArcPoint[2][0] - anArcPoint[0][0];
771 y = anArcPoint[2][1] - anArcPoint[0][1];
772 double aNorm = sqrt(x*x + y*y);
773 if (aNorm >= tolerance) {
774 anArcPoint[2][0] = x * aRad / aNorm;
775 anArcPoint[2][1] = y * aRad / aNorm;
777 anArcPoint[1][0] -= anArcPoint[0][0];
778 anArcPoint[1][1] -= anArcPoint[0][1];
779 if (theCoeff < tolerance) {
780 theX = anArcPoint[0][0] + anArcPoint[1][0];
781 theY = anArcPoint[0][1] + anArcPoint[1][1];
782 } else if (1 - theCoeff < tolerance) {
783 theX = anArcPoint[0][0] + anArcPoint[2][0];
784 theY = anArcPoint[0][1] + anArcPoint[2][1];
786 std::shared_ptr<GeomAPI_Dir2d>
787 aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
788 std::shared_ptr<GeomAPI_Dir2d>
789 aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
790 double anAngle = aStartDir->angle(aEndDir);
794 double aCos = cos(anAngle);
795 double aSin = sin(anAngle);
796 theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
797 theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
799 aMidPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
803 return EntityWrapperPtr();
805 std::list<ParameterWrapperPtr> aParameters;
806 aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->x()));
807 aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->y()));
808 // Create entity (parameters are not filled)
809 GCSPointPtr aPnt(new GCS::Point);
811 std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
813 std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
815 EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt));
816 aResult->setGroup(myGroupID);
817 aResult->setParameters(aParameters);