Salome HOME
68ce5aaf3b7cc2b4628166aff6bf1915937e5d12
[modules/shaper.git] / src / SketchSolver / SolveSpaceSolver / SolveSpaceSolver_Builder.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SolveSpaceSolver_Builder.cpp
4 // Created: 25 Mar 2015
5 // Author:  Artem ZHIDKOV
6
7 #include <SolveSpaceSolver_Builder.h>
8 #include <SolveSpaceSolver_Solver.h>
9 #include <SolveSpaceSolver_Storage.h>
10 #include <SolveSpaceSolver_ParameterWrapper.h>
11 #include <SolveSpaceSolver_EntityWrapper.h>
12 #include <SolveSpaceSolver_ConstraintWrapper.h>
13 #include <SolveSpaceSolver_ConstraintType.h>
14
15 #include <SketchSolver_Manager.h>
16
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_XY.h>
20 #include <GeomDataAPI_Dir.h>
21 #include <GeomDataAPI_Point.h>
22 #include <GeomDataAPI_Point2D.h>
23 #include <ModelAPI_Attribute.h>
24 #include <ModelAPI_AttributeRefAttr.h>
25
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_Line.h>
29 #include <SketchPlugin_Point.h>
30
31 #include <math.h>
32
33
34 static EntityWrapperPtr createLine(FeaturePtr theFeature,
35                                    const std::list<EntityWrapperPtr>& theAttributes,
36                                    const GroupID& theGroupID,
37                                    const EntityID& theSketchID);
38 static EntityWrapperPtr createCircle(FeaturePtr theFeature,
39                                      const std::list<EntityWrapperPtr>& theAttributes,
40                                      const GroupID& theGroupID,
41                                      const EntityID& theSketchID);
42 static EntityWrapperPtr createArc(FeaturePtr theFeature,
43                                   const std::list<EntityWrapperPtr>& theAttributes,
44                                   const GroupID& theGroupID,
45                                   const EntityID& theSketchID);
46
47 /// \brief Set flags of constraint to identify which points are coincident in the Tangency
48 ///        (for more information, see SolveSpace documentation)
49 static void adjustTangency(ConstraintWrapperPtr theConstraint);
50 /// \brief Set flags for angle constraint
51 static void adjustAngle(ConstraintWrapperPtr theConstraint);
52 /// \brief Update mirror points
53 static void adjustMirror(ConstraintWrapperPtr theConstraint);
54 /// \brief Update positions of rotated features
55 static void adjustMultiRotation(ConstraintWrapperPtr theConstraint);
56 /// \brief Update positions of translated features
57 static void adjustMultiTranslation(ConstraintWrapperPtr theConstraint);
58
59 /// \brief Transform points to be symmetric regarding to the mirror line
60 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
61                              EntityWrapperPtr theMirrored,
62                              EntityWrapperPtr theMirrorLine);
63
64
65
66 // Initialization of constraint builder self pointer
67 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
68
69 BuilderPtr SolveSpaceSolver_Builder::getInstance()
70 {
71   if (!mySelf) {
72     mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
73     SketchSolver_Manager::instance()->setBuilder(mySelf);
74   }
75   return mySelf;
76 }
77
78 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
79 {
80   return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
81 }
82
83 SolverPtr SolveSpaceSolver_Builder::createSolver() const
84 {
85   return SolverPtr(new SolveSpaceSolver_Solver);
86 }
87
88
89 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
90     ConstraintPtr theConstraint,
91     const GroupID& theGroupID,
92     const EntityID& theSketchID,
93     const SketchSolver_ConstraintType& theType,
94     const double& theValue,
95     const EntityWrapperPtr& thePoint1,
96     const EntityWrapperPtr& thePoint2,
97     const EntityWrapperPtr& theEntity1,
98     const EntityWrapperPtr& theEntity2) const
99 {
100   if (theType == CONSTRAINT_SYMMETRIC)
101     return createMirror(theConstraint, theGroupID, theSketchID,
102                         thePoint1, thePoint2, theEntity1);
103
104   int aType = ConstraintType::toSolveSpace(theType);
105   if (aType == SLVS_C_UNKNOWN)
106     return std::list<ConstraintWrapperPtr>();
107
108   Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
109   EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
110   std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
111   for (int i = 0; i < 4; ++i) {
112     if (!anOriginal[i])
113       continue;
114     aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
115     if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
116       return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
117     aConstrAttrList.push_back(anOriginal[i]);
118   }
119
120   Slvs_Constraint aConstraint = Slvs_MakeConstraint(
121       SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
122       theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
123   ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
124   aResult->setValue(theValue);
125   aResult->setEntities(aConstrAttrList);
126   adjustConstraint(aResult);
127
128   return std::list<ConstraintWrapperPtr>(1, aResult);
129 }
130
131 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
132     ConstraintPtr theConstraint,
133     const GroupID& theGroupID,
134     const EntityID& theSketchID,
135     const SketchSolver_ConstraintType& theType,
136     const double& theValue,
137     const bool theFullValue,
138     const EntityWrapperPtr& thePoint1,
139     const EntityWrapperPtr& thePoint2,
140     const std::list<EntityWrapperPtr>& theTrsfEnt) const
141 {
142   if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
143     return std::list<ConstraintWrapperPtr>();
144
145   int aType = ConstraintType::toSolveSpace(theType);
146   if (aType == SLVS_C_UNKNOWN)
147     return std::list<ConstraintWrapperPtr>();
148
149   Slvs_Constraint aConstraint =
150       Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
151       theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
152
153   std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
154   if (thePoint2)
155     aConstrAttrList.push_front(thePoint2);
156   aConstrAttrList.push_front(thePoint1);
157
158   ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
159   aResult->setValue(theValue);
160   aResult->setIsFullValue(theFullValue);
161   aResult->setEntities(aConstrAttrList);
162   return std::list<ConstraintWrapperPtr>(1, aResult);
163 }
164
165
166 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
167     ConstraintPtr theConstraint,
168     const GroupID& theGroupID,
169     const EntityID& theSketchID,
170     const EntityWrapperPtr& theEntity1,
171     const EntityWrapperPtr& theEntity2,
172     const EntityWrapperPtr& theMirrorLine) const
173 {
174   Slvs_Constraint aConstraint;
175   std::list<ConstraintWrapperPtr> aResult;
176   std::list<EntityWrapperPtr> aConstrAttrList;
177   if (theEntity1->type() == ENTITY_POINT) {
178     if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
179       makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
180
181     aConstraint = Slvs_MakeConstraint(
182         SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
183         0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
184         (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
185
186     aConstrAttrList.push_back(theEntity1);
187     aConstrAttrList.push_back(theEntity2);
188     aConstrAttrList.push_back(theMirrorLine);
189
190     ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
191         theConstraint, aConstraint));
192     aWrapper->setEntities(aConstrAttrList);
193     aResult.push_back(aWrapper);
194   }
195   else if (theEntity1->type() == ENTITY_LINE) {
196     const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
197     const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
198     std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
199     std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
200     for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
201       std::list<ConstraintWrapperPtr> aMrrList =
202           createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
203       aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
204     }
205   }
206   else if (theEntity1->type() == ENTITY_CIRCLE) {
207     const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
208     std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
209     for (; anIt1 != aPoints1.end(); ++anIt1)
210       if ((*anIt1)->type() == ENTITY_POINT)
211         break;
212     const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
213     std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
214     for (; anIt2 != aPoints2.end(); ++anIt2)
215       if ((*anIt2)->type() == ENTITY_POINT)
216         break;
217
218     std::list<ConstraintWrapperPtr> aMrrList =
219         createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
220     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
221
222     // Additional constraint for equal radii
223     aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
224         0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
225     aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
226   }
227   else if (theEntity1->type() == ENTITY_ARC) {
228     // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
229     FeaturePtr aMirrArc = theEntity2->baseFeature();
230     aMirrArc->data()->blockSendAttributeUpdated(true);
231
232     std::list<ConstraintWrapperPtr> aMrrList;
233     std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
234     std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
235     if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
236       makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
237
238     // Workaround to avoid problems in SolveSpace.
239     // The symmetry of two arcs will be done using symmetry of three points on these arcs:
240     // start point, end point, and any other point on the arc
241     std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
242     std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
243     // indices of points of arc, center corresponds center, first point corresponds last point
244     aMirrorArcPoints.reverse();
245
246     anIt1 = aBaseArcPoints.begin();
247     anIt2 = aMirrorArcPoints.begin();
248     for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
249       aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
250       aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
251     }
252     // Restore event sending
253     aMirrArc->data()->blockSendAttributeUpdated(false);
254   }
255   return aResult;
256 }
257
258 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
259 {
260   SketchSolver_ConstraintType aType = theConstraint->type();
261   // Update flags in constraints
262   if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
263     adjustTangency(theConstraint);
264   else if (aType == CONSTRAINT_ANGLE)
265     adjustAngle(theConstraint);
266   else if (aType == CONSTRAINT_SYMMETRIC)
267     adjustMirror(theConstraint);
268   else if (aType == CONSTRAINT_MULTI_ROTATION)
269     adjustMultiRotation(theConstraint);
270   else if (aType == CONSTRAINT_MULTI_TRANSLATION)
271     adjustMultiTranslation(theConstraint);
272 }
273
274 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
275     FeaturePtr theFeature,
276     const std::list<EntityWrapperPtr>& theAttributes,
277     const GroupID& theGroupID,
278     const EntityID& theSketchID) const
279 {
280   static EntityWrapperPtr aDummy;
281   if (!theFeature->data()->isValid())
282     return aDummy;
283
284   // Sketch
285   CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
286   if (aSketch)
287     return createSketchEntity(aSketch, theGroupID);
288
289   // SketchPlugin features
290   std::shared_ptr<SketchPlugin_Feature> aFeature =
291       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
292   if (!aFeature)
293     return aDummy;
294
295   // Verify the feature by its kind
296   const std::string& aFeatureKind = aFeature->getKind();
297   // Line
298   if (aFeatureKind == SketchPlugin_Line::ID())
299     return createLine(theFeature, theAttributes, theGroupID, theSketchID);
300   // Circle
301   else if (aFeatureKind == SketchPlugin_Circle::ID())
302     return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
303   // Arc
304   else if (aFeatureKind == SketchPlugin_Arc::ID())
305     return createArc(theFeature, theAttributes,theGroupID, theSketchID);
306   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
307   else if (aFeatureKind == SketchPlugin_Point::ID()) {
308     AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
309     if (!aPoint->isInitialized())
310       return aDummy;
311     EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID, theSketchID);
312     if (!aSub)
313       return aDummy;
314
315     const Slvs_Entity& aSubEnt =
316         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
317     return EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
318   }
319
320   // wrong entity
321   return aDummy;
322 }
323
324 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
325     AttributePtr theAttribute,
326     const GroupID& theGroupID,
327     const EntityID& theSketchID) const
328 {
329   AttributePtr anAttribute = theAttribute;
330   AttributeRefAttrPtr aRefAttr =
331       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
332   if (aRefAttr) {
333     if (aRefAttr->isObject()) {
334       // do not create features here
335       return EntityWrapperPtr();
336     } else
337       anAttribute = aRefAttr->attr();
338   }
339
340   std::list<ParameterWrapperPtr> aParameters;
341   Slvs_Entity anEntity;
342   anEntity.type = 0;
343
344   // Point in 3D
345   std::shared_ptr<GeomDataAPI_Point> aPoint =
346       std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
347   if (aPoint) {
348     aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
349     aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
350     aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
351     // Create entity (parameters are not filled)
352     anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
353         SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
354   } else {
355     // Point in 2D
356     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
357       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
358     if (aPoint2D) {
359       aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
360       aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
361       // Create entity (parameters are not filled)
362       anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
363           (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
364     } else {
365       // Scalar value (used for the distance entities)
366       AttributeDoublePtr aScalar =
367           std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
368       if (aScalar) {
369         aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
370         // Create entity (parameter is not filled)
371         anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
372           (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
373       }
374     }
375   }
376
377   if (anEntity.type == 0) {
378     // unknown attribute type
379     return EntityWrapperPtr();
380   }
381
382   EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
383   aResult->setParameters(aParameters);
384   return aResult;
385 }
386
387
388
389 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
390     CompositeFeaturePtr theSketch,
391     const GroupID& theGroupID) const
392 {
393   DataPtr aSketchData = theSketch->data();
394   if (!aSketchData || !aSketchData->isValid())
395     return EntityWrapperPtr(); // the sketch is incorrect
396
397   // Get parameters of workplane
398   AttributePtr aDirX    = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
399   AttributePtr aNorm    = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
400   AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
401   if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
402     return EntityWrapperPtr();
403
404   EntityWrapperPtr aNewEnt;
405   std::list<EntityWrapperPtr> aSubs;
406
407   // Create SolveSpace entity corresponding to the sketch origin
408   aNewEnt = createAttribute(anOrigin, theGroupID);
409   if (!aNewEnt)
410     return EntityWrapperPtr();
411   aSubs.push_back(aNewEnt);
412
413   // Create SolveSpace entity corresponding the the sketch normal
414   aNewEnt = createNormal(aNorm, aDirX, theGroupID);
415   if (!aNewEnt)
416     return EntityWrapperPtr();
417   aSubs.push_back(aNewEnt);
418
419   // Create workplane
420   Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
421       SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
422
423   aNewEnt = EntityWrapperPtr(
424       new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
425   aNewEnt->setSubEntities(aSubs);
426   return aNewEnt;
427 }
428
429 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
430     AttributePtr theNormal,
431     AttributePtr theDirX,
432     const GroupID& theGroupID) const
433 {
434   std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
435   std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
436   if (!aDirX || !aNorm ||
437       (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || 
438       !aNorm->isInitialized())
439     return EntityWrapperPtr();
440   // calculate Y direction
441   std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
442
443   // quaternion parameters of normal vector
444   double qw, qx, qy, qz;
445   Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
446                       &qx, &qy, &qz);
447   double aNormCoord[4] = { qw, qx, qy, qz };
448
449   // Create parameters of the normal
450   std::list<ParameterWrapperPtr> aParameters;
451   for (int i = 0; i < 4; i++)
452     aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
453
454   // Create a normal with empty parameters
455   Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
456       SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
457   EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
458   aNormal->setParameters(aParameters);
459   return aNormal;
460 }
461
462 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
463     const GroupID& theGroup, const double theValue, const bool theExpr) const
464 {
465   Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
466   ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
467   aWrapper->setIsParametric(theExpr);
468   return aWrapper;
469 }
470
471
472
473
474
475 // ================   Auxiliary functions   ==========================
476 EntityWrapperPtr createLine(FeaturePtr theFeature,
477                             const std::list<EntityWrapperPtr>& theAttributes,
478                             const GroupID& theGroupID,
479                             const EntityID& theSketchID)
480 {
481   EntityWrapperPtr aNewEntity;
482   std::list<EntityWrapperPtr> aSubs;
483
484   AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
485   AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
486   if (!aStart->isInitialized() || !aEnd->isInitialized())
487     return aNewEntity;
488
489   EntityWrapperPtr aStartEnt, aEndEnt;
490   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
491   for (; anIt != theAttributes.end(); ++anIt) {
492     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
493         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
494     if (aSlvsEntity->isBase(aStart))
495       aStartEnt = aSlvsEntity;
496     else if (aSlvsEntity->isBase(aEnd))
497       aEndEnt = aSlvsEntity;
498   }
499   if (!aStartEnt || !aEndEnt)
500     return aNewEntity;
501
502   aSubs.push_back(aStartEnt);
503   aSubs.push_back(aEndEnt);
504   Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
505       (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
506
507   aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
508   aNewEntity->setSubEntities(aSubs);
509   return aNewEntity;
510 }
511
512 EntityWrapperPtr createCircle(FeaturePtr theFeature,
513                               const std::list<EntityWrapperPtr>& theAttributes,
514                               const GroupID& theGroupID,
515                               const EntityID& theSketchID)
516 {
517   EntityWrapperPtr aNewEntity;
518   std::list<EntityWrapperPtr> aSubs;
519
520   AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
521   AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
522   if (!aCenter->isInitialized() || !aRadius->isInitialized())
523     return aNewEntity;
524
525   EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
526   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
527   for (; anIt != theAttributes.end(); ++anIt) {
528     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
529         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
530     if (aSlvsEntity->isBase(aCenter))
531       aCenterEnt = aSlvsEntity;
532     else if (aSlvsEntity->isBase(aRadius))
533       aRadiusEnt = aSlvsEntity;
534     else if (aSlvsEntity->type() == ENTITY_NORMAL)
535       aNormalEnt = aSlvsEntity;
536   }
537   if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
538     return aNewEntity;
539
540   aSubs.push_back(aCenterEnt);
541   aSubs.push_back(aRadiusEnt);
542   Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
543       (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
544       (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
545
546   aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
547   aNewEntity->setSubEntities(aSubs);
548   return aNewEntity;
549 }
550
551 EntityWrapperPtr createArc(FeaturePtr theFeature,
552                            const std::list<EntityWrapperPtr>& theAttributes,
553                            const GroupID& theGroupID,
554                            const EntityID& theSketchID)
555 {
556   EntityWrapperPtr aNewEntity;
557   std::list<EntityWrapperPtr> aSubs;
558
559   AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
560   AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
561   AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
562   if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
563     return aNewEntity;
564
565   EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
566   std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
567   for (; anIt != theAttributes.end(); ++anIt) {
568     std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity = 
569         std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
570     if (aSlvsEntity->isBase(aCenter))
571       aCenterEnt = aSlvsEntity;
572     else if (aSlvsEntity->isBase(aStart))
573       aStartEnt = aSlvsEntity;
574     else if (aSlvsEntity->isBase(aEnd))
575       aEndEnt = aSlvsEntity;
576     else if (aSlvsEntity->type() == ENTITY_NORMAL)
577       aNormalEnt = aSlvsEntity;
578   }
579   if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
580     return aNewEntity;
581
582   aSubs.push_back(aCenterEnt);
583   aSubs.push_back(aStartEnt);
584   aSubs.push_back(aEndEnt);
585   Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
586       (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
587       (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
588
589   aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
590   aNewEntity->setSubEntities(aSubs);
591   return aNewEntity;
592 }
593
594
595 void adjustTangency(ConstraintWrapperPtr theConstraint)
596 {
597   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
598
599   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
600     std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
601
602   // Collect start, end points of entities
603   std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
604   bool isCoinc[2][2] = {false};
605   const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
606   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
607   for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
608     const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
609     std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
610     if ((*aSIt)->type() == ENTITY_ARC)
611       ++aPIt;
612     for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
613       aStartEntPoints[i][j] = aBuilder->point(*aPIt);
614       if (i > 0) { // check coincidence
615         for (int k = 0; k < 2; ++k)
616           if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
617             isCoinc[0][k] = isCoinc[i][j] = true;
618       }
619     }
620   }
621
622   Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
623   if (isCoinc[0][0] == false && isCoinc[0][1] == true)
624     aSlvsConstraint.other = 1;
625   else aSlvsConstraint.other = 0;
626   if (isCoinc[1][0] == false && isCoinc[1][1] == true)
627     aSlvsConstraint.other2 = 1;
628   else aSlvsConstraint.other2 = 0;
629 }
630
631 void adjustAngle(ConstraintWrapperPtr theConstraint)
632 {
633   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
634
635   std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
636     std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
637
638   bool isFixed[2][2];
639   std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
640   const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
641   std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
642   for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
643     const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
644     std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
645     for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
646       isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
647       aPoints[i][j] = aBuilder->point(*aLPIt);
648     }
649   }
650
651   if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
652     return; // both lines are fixed => no need to update them
653
654   std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
655     std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
656     std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
657   };
658   std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
659   if (!anIntersection)
660     return;
661   double aDist[2][2];
662   for (int i = 0; i < 2; i++) {
663     for (int j = 0; j < 2; j++) {
664       aDist[i][j] = anIntersection->distance(aPoints[i][j]);
665       if (fabs(aDist[i][j]) <= tolerance)
666         aDist[i][j] = 0.0;
667     }
668     if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
669         aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
670       // the intersection point is an inner point of the line,
671       // we change the sign of distance till start point to calculate correct coordinates
672       // after rotation
673       aDist[i][0] *= -1.0;
674     }
675   }
676   std::shared_ptr<GeomAPI_Dir2d> aDir[2];
677   for (int i = 0; i < 2; i++) {
678     if (aDist[i][1] > fabs(aDist[i][0]))
679       aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
680           aPoints[i][1]->xy()->decreased(anIntersection->xy())));
681     else {
682       aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
683           aPoints[i][0]->xy()->decreased(anIntersection->xy())));
684       // main direction is opposite => change signs
685       if (aDist[i][0] < 0.0) {
686         aDist[i][0] *= -1.0;
687         aDist[i][1] *= -1.0;
688       }
689     }
690   }
691
692   Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
693   aSlvsConstraint.other = false;
694   for (int i = 0; i < 2; i++)
695     if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
696       aSlvsConstraint.other = !aSlvsConstraint.other;
697
698   // Recalculate positions of lines to avoid conflicting constraints
699   // while changing angle value several times
700   double cosA = cos(aConstraint->value() * PI / 180.0);
701   double sinA = sin(aConstraint->value() * PI / 180.0);
702   if (aDir[0]->cross(aDir[1]) < 0.0)
703     sinA *= -1.0;
704   int aLineToUpd = 1;
705   if (isFixed[1][0] && isFixed[1][1]) {
706     sinA *= -1.0;
707     aLineToUpd = 0;
708   }
709   double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA;
710   double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA;
711
712   std::shared_ptr<GeomAPI_Pnt2d> aNewPoints[2];
713   for (int i = 0; i < 2; i++) {
714     aNewPoints[i] = std::shared_ptr<GeomAPI_Pnt2d>(
715         new GeomAPI_Pnt2d(anIntersection->x() + x * aDist[aLineToUpd][i],
716                           anIntersection->y() + y * aDist[aLineToUpd][i]));
717   }
718
719   std::shared_ptr<GeomAPI_XY> aDelta;
720   if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1])
721     aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy());
722   else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1])
723     aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy());
724   if (aDelta) {
725     for (int i = 0; i < 2; i++) {
726       aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x());
727       aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y());
728     }
729   }
730
731   // Update positions of points
732   std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
733   if (aLineToUpd > 0) ++anUpdLine;
734   const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
735   std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
736   for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
737     double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
738     const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
739     std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
740     for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
741       (*aParIt)->setValue(aCoord[j]);
742   }
743 }
744
745 void adjustMirror(ConstraintWrapperPtr theConstraint)
746 {
747   std::vector<EntityWrapperPtr> aPoints;
748   EntityWrapperPtr aMirrorLine;
749
750   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
751   std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
752   for (; anIt != aSubs.end(); ++anIt) {
753     if ((*anIt)->type() == ENTITY_POINT)
754       aPoints.push_back(*anIt);
755     else if ((*anIt)->type() == ENTITY_LINE)
756       aMirrorLine = *anIt;
757   }
758
759   makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
760 }
761
762 void makeMirrorPoints(EntityWrapperPtr theOriginal,
763                       EntityWrapperPtr theMirrored,
764                       EntityWrapperPtr theMirrorLine)
765 {
766   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
767
768   std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
769   std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
770   // orthogonal direction
771   aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
772
773   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
774   std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
775   double aDist = aVec->dot(aMLDir->xy());
776   aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
777   double aCoord[2] = {aVec->x(), aVec->y()};
778   std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
779   for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
780     (*aMIt)->setValue(aCoord[i]);
781
782   // update corresponding attribute
783   AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
784   if (anAttr) {
785     std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
786     aMirroredPnt->setValue(aCoord[0], aCoord[1]);
787   }
788 }
789
790 static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
791                    std::shared_ptr<GeomAPI_Pnt2d> theCenter,
792                    double theSin, double theCos)
793 {
794   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
795       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
796   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
797       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
798
799   if (theSource->type() == ENTITY_POINT) {
800     // Rotate single point
801     std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
802         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
803     std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
804         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
805     if (aSrcAttr && aDstAttr) {
806       std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
807       double aNewX = aVec->x() * theCos - aVec->y() * theSin;
808       double aNewY = aVec->x() * theSin + aVec->y() * theCos;
809       aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
810     }
811     return;
812   }
813
814   FeaturePtr aDestFeature = aDest->baseFeature();
815   if (aDestFeature)
816     aDestFeature->data()->blockSendAttributeUpdated(true);
817
818   // Rotate points of the feature
819   const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
820   const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
821   std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
822   for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
823        aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
824     rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
825
826   if (aDestFeature)
827     aDestFeature->data()->blockSendAttributeUpdated(false);
828 }
829
830 static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
831                       std::shared_ptr<GeomAPI_XY> theDelta)
832 {
833   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
834       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
835   std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
836       std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
837
838   if (theSource->type() == ENTITY_POINT) {
839     // Translate single point
840     std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
841         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
842     std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
843         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
844     if (aSrcAttr && aDstAttr)
845       aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
846     return;
847   }
848
849   FeaturePtr aDestFeature = aDest->baseFeature();
850   if (aDestFeature)
851     aDestFeature->data()->blockSendAttributeUpdated(true);
852
853   // Translate points of the feature
854   const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
855   const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
856   std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
857   for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
858        aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
859     translate(*aSrcIt, *aDstIt, theDelta);
860
861   if (aDestFeature)
862     aDestFeature->data()->blockSendAttributeUpdated(false);
863 }
864
865 void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
866 {
867   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
868
869   double anAngleValue = theConstraint->value();
870   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
871
872   bool isFullValue = theConstraint->isFullValue();
873   int aNbObjects = aSubs.size()-2;
874   if (isFullValue && aNbObjects > 0) {
875     anAngleValue /= aNbObjects;
876   }
877
878   double anAngleRad = anAngleValue * PI / 180.0;
879   double aSin = sin(anAngleRad);
880   double aCos = cos(anAngleRad);
881
882   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
883
884   std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
885   std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
886   for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
887     rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
888 }
889
890 void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
891 {
892   BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
893
894   const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
895   std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
896
897   std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
898   std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
899   std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
900
901   bool isFullValue = theConstraint->isFullValue();
902   int aNbObjects = aSubs.size()-3;
903   if (isFullValue && aNbObjects > 0) {
904     aDelta->setX(aDelta->x()/aNbObjects);
905     aDelta->setY(aDelta->y()/aNbObjects);
906   }
907
908   std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
909   for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
910     translate(*aPrevIt, *aSIt, aDelta);
911 }