1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_ConstraintSplit.cpp
4 // Created: 25 Aug 2016
5 // Author: Natalia ERMOLAEVA
7 #include "SketchPlugin_ConstraintSplit.h"
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <GeomAlgoAPI_ShapeTools.h>
15 #include <ModelAPI_AttributeReference.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_AttributeRefAttr.h>
18 #include <ModelAPI_Tools.h>
19 #include <ModelAPI_AttributeBoolean.h>
21 #include <ModelAPI_Validator.h>
22 #include <ModelAPI_Session.h>
23 #include <ModelAPI_AttributeDouble.h>
25 #include <SketchPlugin_Line.h>
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_ConstraintCoincidence.h>
29 #include <SketchPlugin_ConstraintEqual.h>
30 #include <SketchPlugin_ConstraintParallel.h>
31 #include <SketchPlugin_ConstraintTangent.h>
32 #include <SketchPlugin_ConstraintLength.h>
33 #include <SketchPlugin_ConstraintMirror.h>
34 #include <SketchPlugin_MultiRotation.h>
35 #include <SketchPlugin_MultiTranslation.h>
36 #include <SketchPlugin_ConstraintMiddle.h>
38 #include <ModelAPI_Events.h>
39 #include <SketchPlugin_Line.h>
40 #include <SketchPlugin_Arc.h>
41 #include <SketchPlugin_Circle.h>
43 #include <ModelGeomAlgo_Point2D.h>
44 #include <Events_Loop.h>
53 static const double PI = 3.141592653589793238463;
55 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
59 void SketchPlugin_ConstraintSplit::initAttributes()
61 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
62 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
63 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
66 void SketchPlugin_ConstraintSplit::execute()
68 std::shared_ptr<ModelAPI_Data> aData = data();
70 // Check the base objects are initialized.
71 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
72 aData->attribute(SketchPlugin_Constraint::VALUE()));
73 if(!aBaseObjectAttr->isInitialized()) {
74 setError("Error: Base object is not initialized.");
77 AttributePoint2DPtr aFirstPointAttrOfSplit =
78 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
79 AttributePoint2DPtr aSecondPointAttrOfSplit =
80 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
81 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
82 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
83 setError("Error: Sub-shape is not initialized.");
87 // Wait all constraints being created, then send update events
88 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
89 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
91 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
94 // Find feature constraints
95 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
96 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
97 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
99 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
100 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
101 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
103 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
104 std::list<AttributePtr> aRefsToFeature;
105 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
107 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
110 std::cout << std::endl;
111 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
112 std::cout << std::endl;
114 SketchPlugin_Sketch* aSketch = sketch();
115 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
116 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
117 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
120 std::cout << std::endl;
121 std::cout << "---- IN PARAMETERS ----" << std::endl;
122 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
123 std::cout << std::endl;
125 if (!aCoincidenceToFeature.empty()) {
126 std::cout << "Coincidences to base feature[" <<
127 aCoincidenceToFeature.size() << "]: " << std::endl;
128 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
129 aLast = aCoincidenceToFeature.end();
130 for (int i = 1; anIt != aLast; anIt++, i++) {
131 FeaturePtr aFeature = (*anIt).first;
132 std::string anAttributeId = (*anIt).second.first;
133 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
135 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
136 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
137 std::cout << " -Point attribute:" <<
138 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
142 if (!aTangentFeatures.empty()) {
143 std::cout << std::endl;
144 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
145 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
146 aLast = aTangentFeatures.end();
147 for (int i = 1; anIt != aLast; anIt++, i++) {
148 FeaturePtr aFeature = (*anIt).first;
149 std::string anAttributeId = (*anIt).second.first;
150 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
152 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
153 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
154 std::cout << " -Point attribute:" <<
155 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
159 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
160 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
161 std::cout << std::endl << "References to attributes of base feature [" <<
162 aBaseRefAttributes.size() << "]" << std::endl;
163 for (; aRefIt != aRefLast; aRefIt++) {
164 AttributePtr aBaseAttr = aRefIt->first;
165 std::list<AttributePtr> aRefAttributes = aRefIt->second;
166 std::string aRefsInfo;
167 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
168 aRefAttrLast = aRefAttributes.end();
169 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
170 if (!aRefsInfo.empty())
171 aRefsInfo.append(",");
172 AttributePtr aRAttr = *aRefAttrIt;
173 aRefsInfo.append(aRAttr->id());
174 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
175 aRefsInfo.append("(" + aRFeature->name() + ") ");
177 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
178 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
179 std::cout << aPointAttr->id().c_str() <<
180 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
182 std::cout << std::endl;
183 std::cout << std::endl << "References to base feature [" <<
184 aRefsToFeature.size() << "]" << std::endl;
185 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
186 aRefAttrLast = aRefsToFeature.end();
187 std::string aRefsInfo;
188 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
189 if (!aRefsInfo.empty())
190 aRefsInfo.append(",");
191 AttributePtr aRAttr = *aRefAttrIt;
192 aRefsInfo.append(aRAttr->id());
193 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
194 aRefsInfo.append("(" + aRFeature->name() + ") ");
196 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
199 std::cout << std::endl;
200 std::cout << "---- SPLIT ----" << std::endl;
201 std::cout << std::endl;
204 std::string aFeatureKind = aBaseFeature->getKind();
205 FeaturePtr aSplitFeature, anAfterFeature;
206 std::set<AttributePoint2DPtr> aFurtherCoincidences;
207 std::set<FeaturePtr> aCreatedFeatures;
208 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
209 if (aFeatureKind == SketchPlugin_Line::ID())
210 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
211 aModifiedAttributes);
212 else if (aFeatureKind == SketchPlugin_Arc::ID())
213 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
214 aModifiedAttributes);
215 if (aFeatureKind == SketchPlugin_Circle::ID()) {
216 FeaturePtr aCircleFeature = aBaseFeature;
217 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
218 aCreatedFeatures, aModifiedAttributes);
220 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
222 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
223 aFeaturesToDelete.insert(aCircleFeature);
224 // as circle is removed, temporary fill this attribute*/
225 aBaseObjectAttr->setObject(ResultPtr());
229 std::cout << "---- OUT PARAMETERS ----" << std::endl;
230 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
231 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
232 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
233 std::cout << std::endl;
235 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
236 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
237 aFLast = aCreatedFeatures.end();
238 for (; aFIt != aFLast; aFIt++) {
239 std::cout << getFeatureInfo(*aFIt) << std::endl;
241 std::cout << std::endl;
243 std::cout << "Attributes for further Coincidences:" << std::endl;
244 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
245 aLast = aFurtherCoincidences.end();
246 for (; anIt != aLast; anIt++) {
247 AttributePtr anAttribute = *anIt;
248 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
249 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
250 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
253 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
254 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
255 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
256 std::string aResInfo;
257 for (; aPIt != aPLast; aPIt++) {
258 if (!aResInfo.empty())
261 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
263 AttributePtr anAttr = aPair.first;
264 aResInfo.append(anAttr->id());
265 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
266 aResInfo.append("(" + aFeature->name() + ") ");
268 aResInfo.append(" - is modified to - ");
270 anAttr = aPair.second;
271 aResInfo.append(anAttr->id());
272 aFeature = ModelAPI_Feature::feature(anAttr->owner());
273 aResInfo.append("(" + aFeature->name() + ") ");
275 std::cout << aResInfo << std::endl;
278 std::set<ResultPtr> aFeatureResults;
279 aFeatureResults.insert(getFeatureResult(aBaseFeature));
280 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
281 aFeatureResults.insert(getFeatureResult(anAfterFeature));
283 // coincidence to feature
284 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
285 aFeatureResults, aSplitFeature);
287 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
289 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
291 // delete constraints
293 std::cout << "remove features and references:" << std::endl;
294 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
295 aDLast = aFeaturesToDelete.end();
296 for (; aDIt != aDLast; aDIt++) {
297 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
298 std::cout << std::endl;
301 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
302 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
305 std::cout << "update features after split:" << std::endl;
306 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
307 anULast = aFeaturesToUpdate.end();
308 for (; anUIt != anULast; anUIt++) {
309 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
310 std::cout << std::endl;
313 updateFeaturesAfterSplit(aFeaturesToUpdate);
315 // Send events to update the sub-features by the solver.
316 if(isUpdateFlushed) {
317 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
321 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
322 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
323 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
328 bool SketchPlugin_ConstraintSplit::isMacro() const
333 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
335 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
336 data()->attribute(SketchPlugin_Constraint::VALUE()));
337 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
339 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
340 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
341 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
342 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
344 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
345 aFirstPointAttrOfSplit->isInitialized() &&
346 aSecondPointAttrOfSplit->isInitialized()) {
348 ResultPtr aResult = getFeatureResult(aBaseFeature);
349 GeomShapePtr aBaseShape = aResult->shape();
350 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
352 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
353 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
354 aPoints.push_back(aStartPoint);
356 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
357 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
358 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
359 aPoints.push_back(aSecondPoint);
361 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
363 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
364 std::shared_ptr<GeomAPI_Shape> aShape =
365 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
367 AISObjectPtr anAIS = thePrevious;
370 anAIS = AISObjectPtr(new GeomAPI_AISObject);
371 anAIS->createShape(aShape);
373 std::vector<int> aColor;
374 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
375 SKETCH_ENTITY_COLOR);
376 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
380 return AISObjectPtr();
383 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
384 const AttributePtr& theAttribute)
386 AttributePoint2DPtr aPointAttribute;
388 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
389 AttributeRefAttrPtr aRefAttr =
390 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
391 if (aRefAttr.get() && aRefAttr->isInitialized()) {
392 AttributePtr anAttribute = aRefAttr->attr();
393 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
394 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
397 return aPointAttribute;
400 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
401 AttributePoint2DPtr& theStartPointAttr,
402 AttributePoint2DPtr& theEndPointAttr)
404 std::string aFeatureKind = theFeature->getKind();
405 std::string aStartAttributeName, anEndAttributeName;
406 if (aFeatureKind == SketchPlugin_Line::ID()) {
407 aStartAttributeName = SketchPlugin_Line::START_ID();
408 anEndAttributeName = SketchPlugin_Line::END_ID();
410 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
411 aStartAttributeName = SketchPlugin_Arc::START_ID();
412 anEndAttributeName = SketchPlugin_Arc::END_ID();
414 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
415 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
416 theFeature->attribute(aStartAttributeName));
417 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
418 theFeature->attribute(anEndAttributeName));
422 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
423 std::set<FeaturePtr>& theFeaturesToUpdate,
424 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
425 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
427 std::shared_ptr<ModelAPI_Data> aData = data();
429 // Check the base objects are initialized.
430 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
431 aData->attribute(SketchPlugin_Constraint::VALUE()));
432 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
433 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
435 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
436 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
437 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
439 std::set<AttributePtr>::const_iterator aIt;
440 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
441 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
442 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
443 std::string aRefFeatureKind = aRefFeature->getKind();
444 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
445 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
446 aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
447 aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
448 theFeaturesToDelete.insert(aRefFeature);
449 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
450 theFeaturesToUpdate.insert(aRefFeature);
451 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
452 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
453 /// until tangency between arc and line is implemented
454 theFeaturesToDelete.insert(aRefFeature);
456 std::string anAttributeToBeModified;
457 AttributePoint2DPtr aTangentPoint;
458 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
459 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
460 if (aResult1.get() && aResult2.get()) {
461 FeaturePtr aCoincidenceFeature =
462 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
463 (ModelAPI_Feature::feature(aResult1),
464 ModelAPI_Feature::feature(aResult2));
465 // get the point not lying on the splitting feature
466 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
467 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
468 if (!aRefAttr || aRefAttr->isObject())
470 AttributePoint2DPtr aPoint =
471 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
474 if (aPoint->owner() != aBaseFeature) {
475 aTangentPoint = aPoint;
480 if (aTangentPoint.get()) {
481 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
482 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
483 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
484 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
486 else /// there is not coincident point between tangent constraint
487 theFeaturesToDelete.insert(aRefFeature);
490 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
491 std::string anAttributeToBeModified;
492 AttributePoint2DPtr aCoincidentPoint;
493 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
494 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
495 bool isToFeature = false;
496 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
497 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
499 isToFeature = aFeature.get() && aFeature == aBaseFeature;
500 anAttributeToBeModified = anAttrA->id();
502 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
504 isToFeature = aFeature.get() && aFeature == aBaseFeature;
505 anAttributeToBeModified = anAttrB->id();
508 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
510 if (!isToFeature) { /// coincidence to point on base feature
511 AttributePtr anAttribute;
513 if (!anAttrA->isObject()) {
514 AttributePtr aCurAttribute = anAttrA->attr();
515 if (aCurAttribute.get()) {
516 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
517 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
518 anAttribute = anAttrB->attr();
519 anAttributeToBeModified = anAttrA->id();
523 if (!anAttribute.get() && !anAttrB->isObject()) {
524 AttributePtr aCurAttribute = anAttrB->attr();
525 if (aCurAttribute.get()) {
526 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
527 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
528 anAttribute = anAttrA->attr();
529 anAttributeToBeModified = anAttrB->id();
533 if (anAttribute.get())
534 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
536 if (aCoincidentPoint.get() && isToFeature)
537 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
543 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
544 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
545 std::list<AttributePtr>& theRefsToFeature)
549 std::list<AttributePtr> aPointAttributes =
550 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
551 std::set<AttributePtr> aPointAttributesSet;
553 std::list<AttributePtr>::const_iterator aPIt =
554 aPointAttributes.begin(), aPLast = aPointAttributes.end();
555 for (; aPIt != aPLast; aPIt++)
556 aPointAttributesSet.insert(*aPIt);
558 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
559 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
560 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
562 std::set<AttributePtr>::const_iterator aIt;
563 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
564 AttributePtr anAttr = (*aIt);
565 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
566 if (anAttrFeature.get() != this &&
567 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
568 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
569 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
570 AttributePtr anAttrInRef = aRefAttr->attr();
571 if (anAttrInRef.get() &&
572 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
573 if (theRefs.find(anAttrInRef) != theRefs.end())
574 theRefs[anAttrInRef].push_back(aRefAttr);
576 std::list<AttributePtr> anAttrList;
577 anAttrList.push_back(aRefAttr);
578 theRefs[anAttrInRef] = anAttrList;
582 else { /// find attributes referenced to feature itself
583 theRefsToFeature.push_back(anAttr);
589 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
590 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
591 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
592 const std::set<ResultPtr>& theFeatureResults,
593 const FeaturePtr& theSplitFeature)
595 if (theCoincidenceToFeature.empty())
598 // we should build coincidence constraints to end of the split feature
599 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
600 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
601 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
602 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
603 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
604 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
605 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
607 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
608 aCLast = theCoincidenceToFeature.end();
610 std::cout << std::endl;
611 std::cout << "Coincidences to feature(modified):"<< std::endl;
613 for (; aCIt != aCLast; aCIt++) {
614 FeaturePtr aCoincFeature = aCIt->first;
615 std::string anAttributeId = aCIt->second.first;
616 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
617 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
618 aFCLast = theFurtherCoincidences.end();
619 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
620 AttributePoint2DPtr aFeaturePointAttribute;
621 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
622 AttributePoint2DPtr aFCAttribute = *aFCIt;
623 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
624 aFeaturePointAttribute = aFCAttribute;
626 if (aFeaturePointAttribute.get()) {
627 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
628 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
629 // create new coincidences to split feature points
630 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
631 aSFLast = aNewCoincidencesToSplitFeature.end();
632 for (; aSFIt != aSFLast; aSFIt++) {
633 AttributePoint2DPtr aSFAttribute = *aSFIt;
634 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
635 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
636 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
637 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
638 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
639 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
644 /// find feature by shape intersected the point
645 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
647 if (theFeatureResults.size() > 1) { // try to find point on additional feature
648 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
649 GeomShapePtr aShape = anAddtionalResult->shape();
651 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
652 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
654 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
655 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
656 aResultForCoincidence = anAddtionalResult;
658 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
661 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
666 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
667 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
668 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
670 if (theTangentFeatures.empty())
673 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
674 aTLast = theTangentFeatures.end();
676 std::cout << std::endl;
677 std::cout << "Tangencies to feature(modified):"<< std::endl;
679 for (; aTIt != aTLast; aTIt++) {
680 FeaturePtr aTangentFeature = aTIt->first;
681 std::string anAttributeId = aTIt->second.first;
682 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
683 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
684 aFCLast = theFurtherCoincidences.end();
685 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
686 AttributePoint2DPtr aFeaturePointAttribute;
687 /// here we rely on created coincidence between further coincidence point and tangent result
688 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
689 AttributePoint2DPtr aFCAttribute = *aFCIt;
690 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
691 aFeaturePointAttribute = aFCAttribute;
693 if (aFeaturePointAttribute.get()) {
694 FeaturePtr aFeature =
695 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
696 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
699 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
704 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
705 const ResultPtr& theFeatureBaseResult,
706 const std::list<AttributePtr>& theRefsToFeature)
708 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
709 aLast = theRefsToFeature.end();
710 for (; anIt != aLast; anIt++) {
711 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
713 aRefAttr->setObject(theFeatureBaseResult);
717 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
718 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
719 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
722 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
725 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
726 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
727 for (; anIt != aLast; anIt++) {
728 AttributePtr anAttribute = anIt->first;
730 /// not found in references
731 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
733 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
734 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
735 aRLast = aRefAttributes.end();
737 AttributePtr aNewAttribute = anIt->second;
738 for (; aRefIt != aRLast; aRefIt++) {
739 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
740 if (aRefAttr.get()) {
741 aRefAttr->setAttr(aNewAttribute);
743 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
744 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
751 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
752 FeaturePtr& theBaseFeatureModified,
753 FeaturePtr& theAfterFeature,
754 std::set<AttributePoint2DPtr>& thePoints,
755 std::set<FeaturePtr>& theCreatedFeatures,
756 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
758 std::set<FeaturePtr> aCreatedFeatures;
759 FeaturePtr aConstraintFeature;
760 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
762 SketchPlugin_Sketch* aSketch = sketch();
766 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
767 data()->attribute(SketchPlugin_Constraint::VALUE()));
768 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
769 std::string aFeatureKind = aBaseFeature->getKind();
770 if (aFeatureKind != SketchPlugin_Line::ID())
773 AttributePoint2DPtr aFirstPointAttrOfSplit =
774 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
775 AttributePoint2DPtr aSecondPointAttrOfSplit =
776 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
777 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
779 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
780 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
781 setError("Error: Feature has no start and end points.");
785 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
786 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
789 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
790 std::cout << "Start point: " <<
791 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
792 std::cout << "1st point: " <<
793 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
794 std::cout << "2nd point: " <<
795 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
796 std::cout << "End point: " <<
797 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
800 /// create a split feature
802 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
803 theCreatedFeatures.insert(theSplitFeature);
805 // before split feature
806 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
807 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
808 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
811 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
812 /// move end arc point to start of split
815 // after split feature
816 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
818 if (!theBaseFeatureModified.get()) {
819 aFeature = aBaseFeature; ///< use base feature to store all constraints here
820 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
821 aFeature->execute(); // to update result
824 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
825 theCreatedFeatures.insert(aFeature);
826 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
827 aFeature->attribute(SketchPlugin_Line::END_ID())));
829 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
830 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
831 aFeature->attribute(SketchPlugin_Line::START_ID()));
832 theCreatedFeatures.insert(aConstraintFeature);
834 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
835 (aFeature->attribute(SketchPlugin_Line::START_ID())));
836 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
837 (aFeature->attribute(SketchPlugin_Line::END_ID())));
839 if (!theBaseFeatureModified.get())
840 theBaseFeatureModified = aFeature;
842 theAfterFeature = aFeature;
845 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
846 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
847 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
848 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
850 // base split, that is defined before split feature should be changed at end
851 // (after the after feature creation). Otherwise modified value will be used in after feature
852 // before split feature
853 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
854 /// move end arc point to start of split
855 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
856 aFirstPointAttrOfSplit);
857 theBaseFeatureModified->execute(); // to update result
858 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
859 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
860 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
861 theCreatedFeatures.insert(aConstraintFeature);
863 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
864 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
865 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
866 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
869 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
870 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
872 // additional constraints between split and base features
873 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
874 getFeatureResult(aBaseFeature),
875 getFeatureResult(theSplitFeature));
876 theCreatedFeatures.insert(aConstraintFeature);
877 if (theAfterFeature.get()) {
878 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
879 getFeatureResult(aBaseFeature),
880 getFeatureResult(theAfterFeature));
881 theCreatedFeatures.insert(aConstraintFeature);
885 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
886 FeaturePtr& theBaseFeatureModified,
887 FeaturePtr& theAfterFeature,
888 std::set<AttributePoint2DPtr>& thePoints,
889 std::set<FeaturePtr>& theCreatedFeatures,
890 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
892 std::set<FeaturePtr> aCreatedFeatures;
893 FeaturePtr aConstraintFeature;
894 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
896 SketchPlugin_Sketch* aSketch = sketch();
900 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
901 data()->attribute(SketchPlugin_Constraint::VALUE()));
902 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
903 std::string aFeatureKind = aBaseFeature->getKind();
904 if (aFeatureKind != SketchPlugin_Arc::ID())
907 AttributePoint2DPtr aFirstPointAttrOfSplit =
908 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
909 AttributePoint2DPtr aSecondPointAttrOfSplit =
910 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
911 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
912 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
913 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
914 setError("Error: Feature has no start and end points.");
918 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
919 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
920 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
922 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
923 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
925 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
926 std::cout << "Start point: " <<
927 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
928 std::cout << "1st point: " <<
929 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
930 std::cout << "2nd point: " <<
931 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
932 std::cout << "End point: " <<
933 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
937 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
938 theCreatedFeatures.insert(theSplitFeature);
940 // before split feature
941 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
942 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
943 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
946 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
947 /// move end arc point to start of split
950 // after split feature
951 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
953 if (!theBaseFeatureModified.get()) {
954 aFeature = aBaseFeature; ///< use base feature to store all constraints here
955 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
956 aFeature->execute(); // to update result
959 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
960 theCreatedFeatures.insert(aFeature);
961 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
962 aFeature->attribute(SketchPlugin_Arc::END_ID())));
964 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
965 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
966 aFeature->attribute(SketchPlugin_Arc::START_ID()));
967 theCreatedFeatures.insert(aConstraintFeature);
969 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
970 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
971 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
972 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
974 if (!theBaseFeatureModified.get())
975 theBaseFeatureModified = aFeature;
977 theAfterFeature = aFeature;
980 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
981 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
982 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
983 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
985 // base split, that is defined before split feature should be changed at end
986 // (after the after feature creation). Otherwise modified value will be used in after feature
987 // before split feature
988 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
989 /// move end arc point to start of split
990 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
991 aFirstPointAttrOfSplit);
992 theBaseFeatureModified->execute(); // to update result
993 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
994 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
995 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
996 theCreatedFeatures.insert(aConstraintFeature);
998 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
999 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1000 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1001 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1004 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1005 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1007 // additional constraints between split and base features
1008 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1009 getFeatureResult(aBaseFeature),
1010 getFeatureResult(theSplitFeature));
1011 theCreatedFeatures.insert(aConstraintFeature);
1012 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1013 getFeatureResult(theSplitFeature),
1014 getFeatureResult(aBaseFeature));
1015 theCreatedFeatures.insert(aConstraintFeature);
1016 if (theAfterFeature.get()) {
1017 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1018 getFeatureResult(aBaseFeature),
1019 getFeatureResult(theAfterFeature));
1020 theCreatedFeatures.insert(aConstraintFeature);
1021 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1022 getFeatureResult(theSplitFeature),
1023 getFeatureResult(theAfterFeature));
1024 theCreatedFeatures.insert(aConstraintFeature);
1028 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1029 FeaturePtr& theBaseFeatureModified,
1030 FeaturePtr& theAfterFeature,
1031 std::set<AttributePoint2DPtr>& thePoints,
1032 std::set<FeaturePtr>& theCreatedFeatures,
1033 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1035 std::set<FeaturePtr> aCreatedFeatures;
1036 FeaturePtr aConstraintFeature;
1037 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1039 SketchPlugin_Sketch* aSketch = sketch();
1043 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1044 data()->attribute(SketchPlugin_Constraint::VALUE()));
1045 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1046 std::string aFeatureKind = aBaseFeature->getKind();
1047 if (aFeatureKind != SketchPlugin_Circle::ID())
1050 AttributePoint2DPtr aFirstPointAttrOfSplit =
1051 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1052 AttributePoint2DPtr aSecondPointAttrOfSplit =
1053 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1057 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1058 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1059 theCreatedFeatures.insert(theSplitFeature);
1061 /// base feature is a left part of the circle
1062 theBaseFeatureModified = createArcFeature(aBaseFeature,
1063 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1064 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1065 theBaseFeatureModified)->setReversed(!aSplitReversed);
1066 theBaseFeatureModified->execute();
1068 theModifiedAttributes.insert(
1069 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1070 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1072 theCreatedFeatures.insert(theBaseFeatureModified);
1074 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1075 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1076 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1077 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1079 // additional constraints between split and base features
1080 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1081 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1082 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1083 theCreatedFeatures.insert(aConstraintFeature);
1084 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1085 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1086 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1087 theCreatedFeatures.insert(aConstraintFeature);
1089 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1090 getFeatureResult(theSplitFeature),
1091 getFeatureResult(theBaseFeatureModified));
1092 theCreatedFeatures.insert(aConstraintFeature);
1095 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1096 const AttributePoint2DPtr& theStartPointAttr,
1097 const AttributePoint2DPtr& theEndPointAttr,
1098 AttributePoint2DPtr& theFirstPointAttr,
1099 AttributePoint2DPtr& theLastPointAttr) const
1101 // if first point is closer to last point, swap first and last values
1102 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1103 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1104 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1105 theFirstPointAttr = theLastPointAttr;
1106 theLastPointAttr = aTmpPoint;
1110 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1111 const FeaturePtr& theArc,
1112 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1113 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1114 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1115 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1117 static const double anAngleTol = 1.e-12;
1119 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1120 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1121 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1123 // collect directions to each point
1124 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1125 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1126 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1127 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1128 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1129 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1131 // sort points by their angular values
1132 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1133 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1134 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1135 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1136 aFirstPtAngle += aPeriod;
1137 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1138 aSecondPtAngle += aPeriod;
1140 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1141 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1142 theFirstPointAttr = theSecondPointAttr;
1143 theSecondPointAttr = aTmpPoint;
1147 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1148 const AttributePtr& theSourceAttribute)
1150 std::string anAttributeType = theModifiedAttribute->attributeType();
1151 if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1152 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1153 theModifiedAttribute);
1154 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1155 theSourceAttribute);
1157 if (aModifiedAttribute.get() && aSourceAttribute.get())
1158 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1160 else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1161 AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1162 theModifiedAttribute);
1163 AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1164 theSourceAttribute);
1166 if (aModifiedAttribute.get() && aSourceAttribute.get())
1167 aModifiedAttribute->setValue(aSourceAttribute->value());
1171 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1172 const AttributePtr& theFirstPointAttr,
1173 const AttributePtr& theSecondPointAttr)
1175 FeaturePtr aFeature;
1176 SketchPlugin_Sketch* aSketch = sketch();
1177 if (!aSketch || !theBaseFeature.get())
1180 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1182 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1183 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1185 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1186 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1188 aFeature->execute(); // to obtain result
1193 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1194 const AttributePtr& theFirstPointAttr,
1195 const AttributePtr& theSecondPointAttr)
1197 FeaturePtr aFeature;
1198 SketchPlugin_Sketch* aSketch = sketch();
1199 if (!aSketch || !theBaseFeature.get())
1202 std::string aCenterAttributeId;
1203 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1204 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1205 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1206 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1208 if (aCenterAttributeId.empty())
1211 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1212 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1213 // the "attribute updated"
1214 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1215 aFeature->data()->blockSendAttributeUpdated(true);
1217 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1218 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1220 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1221 theBaseFeature->attribute(aCenterAttributeId));
1222 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1223 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1225 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1226 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1228 /// fill referersed state of created arc as it is on the base arc
1229 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1230 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1231 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1233 aFeature->data()->blockSendAttributeUpdated(false);
1234 aFeature->execute(); // to obtain result
1239 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1240 const AttributePtr& theFirstAttribute,
1241 const AttributePtr& theSecondAttribute)
1243 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1244 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1245 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1246 aRefAttr->setAttr(theFirstAttribute);
1248 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1249 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1250 aRefAttr->setAttr(theSecondAttribute);
1255 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1256 const std::string& theConstraintId,
1257 const ObjectPtr& theFirstObject,
1258 const ObjectPtr& theSecondObject)
1260 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1261 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1262 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1263 aRefAttr->setObject(theFirstObject);
1265 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1266 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1267 aRefAttr->setObject(theSecondObject);
1272 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1273 const std::set<FeaturePtr>& theFeaturesToUpdate)
1275 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1276 aLast = theFeaturesToUpdate.end();
1277 for (; anIt != aLast; anIt++) {
1278 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1279 std::string aRefFeatureKind = aRefFeature->getKind();
1280 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1281 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1282 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1283 if (aLenghtFeature.get()) {
1284 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1285 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1287 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1288 aValueAttr->setValue(aValue);
1294 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1295 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1297 std::shared_ptr<ModelAPI_Result> aResult;
1299 std::string aFeatureKind = theFeature->getKind();
1300 if (aFeatureKind == SketchPlugin_Line::ID())
1301 aResult = theFeature->firstResult();
1302 else if (aFeatureKind == SketchPlugin_Arc::ID())
1303 aResult = theFeature->lastResult();
1304 else if (aFeatureKind == SketchPlugin_Circle::ID())
1305 aResult = theFeature->lastResult();
1310 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1311 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1313 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1315 std::string aFeatureKind = theFeature->getKind();
1316 if (aFeatureKind == SketchPlugin_Line::ID()) {
1317 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1318 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1320 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1321 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1322 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1324 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1327 return anAttributes;
1331 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1332 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1333 const bool isUseAttributesInfo)
1336 if (!theFeature.get()) {
1340 if (theFeature->data()->isValid())
1341 anInfo.append(theFeature->data()->name().c_str());
1343 if (isUseAttributesInfo) {
1344 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1345 getEdgeAttributes(theFeature));
1346 /// processing of feature with point 2d attributes, like line, arc, circle
1347 if (!aPointsInfo.empty()) {
1350 anInfo += aPointsInfo;
1352 else { /// process constraint coincidence, find points in ref attr attributes
1353 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1354 ModelAPI_AttributeRefAttr::typeId());
1355 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1356 std::string anAttributesInfo;
1357 for(; anIt != aLast; anIt++) {
1358 if (!anAttributesInfo.empty()) {
1359 anAttributesInfo.append(", ");
1360 anAttributesInfo += "\n";
1362 AttributePtr anAttr = *anIt;
1363 std::string aValue = "not defined";
1364 std::string aType = anAttr->attributeType();
1365 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1366 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1367 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1368 if (aRefAttr.get()) {
1369 if (aRefAttr->isObject()) {
1370 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1371 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1374 AttributePtr anAttribute = aRefAttr->attr();
1375 if (anAttribute.get()) {
1376 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1377 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1378 " [" + getFeatureInfo(aFeature, false) + "]";
1383 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1385 if (!anAttributesInfo.empty())
1386 anInfo = anInfo + "\n" + anAttributesInfo;