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>
20 #include <ModelAPI_Validator.h>
21 #include <ModelAPI_Session.h>
22 #include <ModelAPI_AttributeDouble.h>
24 #include <SketchPlugin_Line.h>
25 #include <SketchPlugin_Arc.h>
26 #include <SketchPlugin_Circle.h>
27 #include <SketchPlugin_ConstraintCoincidence.h>
28 #include <SketchPlugin_ConstraintEqual.h>
29 #include <SketchPlugin_ConstraintParallel.h>
30 #include <SketchPlugin_ConstraintTangent.h>
31 #include <SketchPlugin_ConstraintLength.h>
32 #include <SketchPlugin_ConstraintMirror.h>
33 #include <SketchPlugin_MultiRotation.h>
34 #include <SketchPlugin_MultiTranslation.h>
36 #include <ModelAPI_Events.h>
37 #include <SketchPlugin_Line.h>
38 #include <SketchPlugin_Arc.h>
39 #include <SketchPlugin_Circle.h>
41 #include <ModelGeomAlgo_Point2D.h>
42 #include <Events_Loop.h>
51 static const double PI = 3.141592653589793238463;
53 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
57 void SketchPlugin_ConstraintSplit::initAttributes()
59 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
60 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
61 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
64 void SketchPlugin_ConstraintSplit::execute()
66 std::shared_ptr<ModelAPI_Data> aData = data();
68 // Check the base objects are initialized.
69 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
70 aData->attribute(SketchPlugin_Constraint::VALUE()));
71 if(!aBaseObjectAttr->isInitialized()) {
72 setError("Error: Base object is not initialized.");
75 AttributePoint2DPtr aFirstPointAttrOfSplit =
76 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
77 AttributePoint2DPtr aSecondPointAttrOfSplit =
78 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
79 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
80 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
81 setError("Error: Sub-shape is not initialized.");
85 // Wait all constraints being created, then send update events
86 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
87 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
89 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
92 // Find feature constraints
93 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
94 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
95 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
97 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
98 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
99 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
101 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
102 std::list<AttributePtr> aRefsToFeature;
103 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
105 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
108 std::cout << std::endl;
109 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
110 std::cout << std::endl;
112 SketchPlugin_Sketch* aSketch = sketch();
113 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
114 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
115 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
118 std::cout << std::endl;
119 std::cout << "---- IN PARAMETERS ----" << std::endl;
120 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
121 std::cout << std::endl;
123 if (!aCoincidenceToFeature.empty()) {
124 std::cout << "Coincidences to base feature[" <<
125 aCoincidenceToFeature.size() << "]: " << std::endl;
126 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
127 aLast = aCoincidenceToFeature.end();
128 for (int i = 1; anIt != aLast; anIt++, i++) {
129 FeaturePtr aFeature = (*anIt).first;
130 std::string anAttributeId = (*anIt).second.first;
131 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
133 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
134 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
135 std::cout << " -Point attribute:" <<
136 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
140 if (!aTangentFeatures.empty()) {
141 std::cout << std::endl;
142 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
143 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
144 aLast = aTangentFeatures.end();
145 for (int i = 1; anIt != aLast; anIt++, i++) {
146 FeaturePtr aFeature = (*anIt).first;
147 std::string anAttributeId = (*anIt).second.first;
148 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
150 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
151 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
152 std::cout << " -Point attribute:" <<
153 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
157 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
158 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
159 std::cout << std::endl << "References to attributes of base feature [" <<
160 aBaseRefAttributes.size() << "]" << std::endl;
161 for (; aRefIt != aRefLast; aRefIt++) {
162 AttributePtr aBaseAttr = aRefIt->first;
163 std::list<AttributePtr> aRefAttributes = aRefIt->second;
164 std::string aRefsInfo;
165 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
166 aRefAttrLast = aRefAttributes.end();
167 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
168 if (!aRefsInfo.empty())
169 aRefsInfo.append(",");
170 AttributePtr aRAttr = *aRefAttrIt;
171 aRefsInfo.append(aRAttr->id());
172 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
173 aRefsInfo.append("(" + aRFeature->name() + ") ");
175 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
176 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
177 std::cout << aPointAttr->id().c_str() <<
178 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
180 std::cout << std::endl;
181 std::cout << std::endl << "References to base feature [" <<
182 aRefsToFeature.size() << "]" << std::endl;
183 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
184 aRefAttrLast = aRefsToFeature.end();
185 std::string aRefsInfo;
186 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
187 if (!aRefsInfo.empty())
188 aRefsInfo.append(",");
189 AttributePtr aRAttr = *aRefAttrIt;
190 aRefsInfo.append(aRAttr->id());
191 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
192 aRefsInfo.append("(" + aRFeature->name() + ") ");
194 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
197 std::cout << std::endl;
198 std::cout << "---- SPLIT ----" << std::endl;
199 std::cout << std::endl;
202 std::string aFeatureKind = aBaseFeature->getKind();
203 FeaturePtr aSplitFeature, anAfterFeature;
204 std::set<AttributePoint2DPtr> aFurtherCoincidences;
205 std::set<FeaturePtr> aCreatedFeatures;
206 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
207 if (aFeatureKind == SketchPlugin_Line::ID())
208 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
209 aModifiedAttributes);
210 else if (aFeatureKind == SketchPlugin_Arc::ID())
211 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
212 aModifiedAttributes);
213 if (aFeatureKind == SketchPlugin_Circle::ID()) {
214 FeaturePtr aCircleFeature = aBaseFeature;
215 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
216 aCreatedFeatures, aModifiedAttributes);
218 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
220 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
221 aFeaturesToDelete.insert(aCircleFeature);
222 // as circle is removed, temporary fill this attribute*/
223 aBaseObjectAttr->setObject(ResultPtr());
227 std::cout << "---- OUT PARAMETERS ----" << std::endl;
228 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
229 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
230 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
231 std::cout << std::endl;
233 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
234 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
235 aFLast = aCreatedFeatures.end();
236 for (; aFIt != aFLast; aFIt++) {
237 std::cout << getFeatureInfo(*aFIt) << std::endl;
239 std::cout << std::endl;
241 std::cout << "Attributes for further Coincidences:" << std::endl;
242 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
243 aLast = aFurtherCoincidences.end();
244 for (; anIt != aLast; anIt++) {
245 AttributePtr anAttribute = *anIt;
246 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
247 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
248 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
251 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
252 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
253 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
254 std::string aResInfo;
255 for (; aPIt != aPLast; aPIt++) {
256 if (!aResInfo.empty())
259 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
261 AttributePtr anAttr = aPair.first;
262 aResInfo.append(anAttr->id());
263 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
264 aResInfo.append("(" + aFeature->name() + ") ");
266 aResInfo.append(" - is modified to - ");
268 anAttr = aPair.second;
269 aResInfo.append(anAttr->id());
270 aFeature = ModelAPI_Feature::feature(anAttr->owner());
271 aResInfo.append("(" + aFeature->name() + ") ");
273 std::cout << aResInfo << std::endl;
276 std::set<ResultPtr> aFeatureResults;
277 aFeatureResults.insert(getFeatureResult(aBaseFeature));
278 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
279 aFeatureResults.insert(getFeatureResult(anAfterFeature));
281 // coincidence to feature
282 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
283 aFeatureResults, aSplitFeature);
285 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
287 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
289 // delete constraints
291 std::cout << "remove features and references:" << std::endl;
292 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
293 aDLast = aFeaturesToDelete.end();
294 for (; aDIt != aDLast; aDIt++) {
295 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
296 std::cout << std::endl;
299 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
302 std::cout << "update features after split:" << std::endl;
303 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
304 anULast = aFeaturesToUpdate.end();
305 for (; anUIt != anULast; anUIt++) {
306 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
307 std::cout << std::endl;
310 updateFeaturesAfterSplit(aFeaturesToUpdate);
312 // Send events to update the sub-features by the solver.
313 if(isUpdateFlushed) {
314 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
318 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
319 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
320 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
325 bool SketchPlugin_ConstraintSplit::isMacro() const
330 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
332 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
333 data()->attribute(SketchPlugin_Constraint::VALUE()));
334 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
336 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
337 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
338 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
339 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
341 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
342 aFirstPointAttrOfSplit->isInitialized() &&
343 aSecondPointAttrOfSplit->isInitialized()) {
345 ResultPtr aResult = getFeatureResult(aBaseFeature);
346 GeomShapePtr aBaseShape = aResult->shape();
347 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
349 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
350 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
351 aPoints.push_back(aStartPoint);
353 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
354 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
355 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
356 aPoints.push_back(aSecondPoint);
358 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
360 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
361 std::shared_ptr<GeomAPI_Shape> aShape =
362 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
364 AISObjectPtr anAIS = thePrevious;
367 anAIS = AISObjectPtr(new GeomAPI_AISObject);
368 anAIS->createShape(aShape);
370 std::vector<int> aColor;
371 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
372 SKETCH_ENTITY_COLOR);
373 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
377 return AISObjectPtr();
380 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
381 const AttributePtr& theAttribute)
383 AttributePoint2DPtr aPointAttribute;
385 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
386 AttributeRefAttrPtr aRefAttr =
387 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
388 if (aRefAttr.get() && aRefAttr->isInitialized()) {
389 AttributePtr anAttribute = aRefAttr->attr();
390 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
391 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
394 return aPointAttribute;
397 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
398 AttributePoint2DPtr& theStartPointAttr,
399 AttributePoint2DPtr& theEndPointAttr)
401 std::string aFeatureKind = theFeature->getKind();
402 std::string aStartAttributeName, anEndAttributeName;
403 if (aFeatureKind == SketchPlugin_Line::ID()) {
404 aStartAttributeName = SketchPlugin_Line::START_ID();
405 anEndAttributeName = SketchPlugin_Line::END_ID();
407 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
408 aStartAttributeName = SketchPlugin_Arc::START_ID();
409 anEndAttributeName = SketchPlugin_Arc::END_ID();
411 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
412 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
413 theFeature->attribute(aStartAttributeName));
414 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
415 theFeature->attribute(anEndAttributeName));
419 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
420 std::set<FeaturePtr>& theFeaturesToUpdate,
421 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
422 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
424 std::shared_ptr<ModelAPI_Data> aData = data();
426 // Check the base objects are initialized.
427 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
428 aData->attribute(SketchPlugin_Constraint::VALUE()));
429 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
430 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
432 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
433 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
434 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
436 std::set<AttributePtr>::const_iterator aIt;
437 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
438 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
439 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
440 std::string aRefFeatureKind = aRefFeature->getKind();
441 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
442 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
443 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
444 theFeaturesToDelete.insert(aRefFeature);
445 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
446 theFeaturesToUpdate.insert(aRefFeature);
447 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
448 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
449 /// until tangency between arc and line is implemented
450 theFeaturesToDelete.insert(aRefFeature);
452 std::string anAttributeToBeModified;
453 AttributePoint2DPtr aTangentPoint;
454 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
455 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
456 if (aResult1.get() && aResult2.get()) {
457 FeaturePtr aCoincidenceFeature =
458 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
459 (ModelAPI_Feature::feature(aResult1),
460 ModelAPI_Feature::feature(aResult2));
461 // get the point not lying on the splitting feature
462 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
463 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
464 if (!aRefAttr || aRefAttr->isObject())
466 AttributePoint2DPtr aPoint =
467 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
470 if (aPoint->owner() != aBaseFeature) {
471 aTangentPoint = aPoint;
476 if (aTangentPoint.get()) {
477 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
478 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
479 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
480 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
482 else /// there is not coincident point between tangent constraint
483 theFeaturesToDelete.insert(aRefFeature);
486 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
487 std::string anAttributeToBeModified;
488 AttributePoint2DPtr aCoincidentPoint;
489 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
490 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
491 bool isToFeature = false;
492 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
493 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
495 isToFeature = aFeature.get() && aFeature == aBaseFeature;
496 anAttributeToBeModified = anAttrA->id();
498 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
500 isToFeature = aFeature.get() && aFeature == aBaseFeature;
501 anAttributeToBeModified = anAttrB->id();
504 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
506 if (!isToFeature) { /// coincidence to point on base feature
507 AttributePtr anAttribute;
509 if (!anAttrA->isObject()) {
510 AttributePtr aCurAttribute = anAttrA->attr();
511 if (aCurAttribute.get()) {
512 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
513 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
514 anAttribute = anAttrB->attr();
515 anAttributeToBeModified = anAttrA->id();
519 if (!anAttribute.get() && !anAttrB->isObject()) {
520 AttributePtr aCurAttribute = anAttrB->attr();
521 if (aCurAttribute.get()) {
522 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
523 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
524 anAttribute = anAttrA->attr();
525 anAttributeToBeModified = anAttrB->id();
529 if (anAttribute.get())
530 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
532 if (aCoincidentPoint.get() && isToFeature)
533 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
539 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
540 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
541 std::list<AttributePtr>& theRefsToFeature)
545 std::list<AttributePtr> aPointAttributes =
546 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
547 std::set<AttributePtr> aPointAttributesSet;
549 std::list<AttributePtr>::const_iterator aPIt =
550 aPointAttributes.begin(), aPLast = aPointAttributes.end();
551 for (; aPIt != aPLast; aPIt++)
552 aPointAttributesSet.insert(*aPIt);
554 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
555 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
556 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
558 std::set<AttributePtr>::const_iterator aIt;
559 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
560 AttributePtr anAttr = (*aIt);
561 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
562 if (anAttrFeature.get() != this &&
563 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
564 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
565 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
566 AttributePtr anAttrInRef = aRefAttr->attr();
567 if (anAttrInRef.get() &&
568 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
569 if (theRefs.find(anAttrInRef) != theRefs.end())
570 theRefs[anAttrInRef].push_back(aRefAttr);
572 std::list<AttributePtr> anAttrList;
573 anAttrList.push_back(aRefAttr);
574 theRefs[anAttrInRef] = anAttrList;
578 else { /// find attributes referenced to feature itself
579 theRefsToFeature.push_back(anAttr);
585 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
586 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
587 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
588 const std::set<ResultPtr>& theFeatureResults,
589 const FeaturePtr& theSplitFeature)
591 if (theCoincidenceToFeature.empty())
594 // we should build coincidence constraints to end of the split feature
595 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
596 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
597 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
598 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
599 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
600 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
601 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
603 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
604 aCLast = theCoincidenceToFeature.end();
606 std::cout << std::endl;
607 std::cout << "Coincidences to feature(modified):"<< std::endl;
609 for (; aCIt != aCLast; aCIt++) {
610 FeaturePtr aCoincFeature = aCIt->first;
611 std::string anAttributeId = aCIt->second.first;
612 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
613 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
614 aFCLast = theFurtherCoincidences.end();
615 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
616 AttributePoint2DPtr aFeaturePointAttribute;
617 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
618 AttributePoint2DPtr aFCAttribute = *aFCIt;
619 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
620 aFeaturePointAttribute = aFCAttribute;
622 if (aFeaturePointAttribute.get()) {
623 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
624 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
625 // create new coincidences to split feature points
626 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
627 aSFLast = aNewCoincidencesToSplitFeature.end();
628 for (; aSFIt != aSFLast; aSFIt++) {
629 AttributePoint2DPtr aSFAttribute = *aSFIt;
630 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
631 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
632 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
633 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
634 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
635 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
640 /// find feature by shape intersected the point
641 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
643 if (theFeatureResults.size() > 1) { // try to find point on additional feature
644 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
645 GeomShapePtr aShape = anAddtionalResult->shape();
647 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
648 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
650 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
651 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
652 aResultForCoincidence = anAddtionalResult;
654 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
657 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
662 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
663 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
664 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
666 if (theTangentFeatures.empty())
669 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
670 aTLast = theTangentFeatures.end();
672 std::cout << std::endl;
673 std::cout << "Tangencies to feature(modified):"<< std::endl;
675 for (; aTIt != aTLast; aTIt++) {
676 FeaturePtr aTangentFeature = aTIt->first;
677 std::string anAttributeId = aTIt->second.first;
678 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
679 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
680 aFCLast = theFurtherCoincidences.end();
681 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
682 AttributePoint2DPtr aFeaturePointAttribute;
683 /// here we rely on created coincidence between further coincidence point and tangent result
684 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
685 AttributePoint2DPtr aFCAttribute = *aFCIt;
686 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
687 aFeaturePointAttribute = aFCAttribute;
689 if (aFeaturePointAttribute.get()) {
690 FeaturePtr aFeature =
691 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
692 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
695 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
700 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
701 const ResultPtr& theFeatureBaseResult,
702 const std::list<AttributePtr>& theRefsToFeature)
704 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
705 aLast = theRefsToFeature.end();
706 for (; anIt != aLast; anIt++) {
707 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
709 aRefAttr->setObject(theFeatureBaseResult);
713 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
714 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
715 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
718 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
721 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
722 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
723 for (; anIt != aLast; anIt++) {
724 AttributePtr anAttribute = anIt->first;
726 /// not found in references
727 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
729 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
730 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
731 aRLast = aRefAttributes.end();
733 AttributePtr aNewAttribute = anIt->second;
734 for (; aRefIt != aRLast; aRefIt++) {
735 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
736 if (aRefAttr.get()) {
737 aRefAttr->setAttr(aNewAttribute);
739 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
740 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
747 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
748 FeaturePtr& theBaseFeatureModified,
749 FeaturePtr& theAfterFeature,
750 std::set<AttributePoint2DPtr>& thePoints,
751 std::set<FeaturePtr>& theCreatedFeatures,
752 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
754 std::set<FeaturePtr> aCreatedFeatures;
755 FeaturePtr aConstraintFeature;
756 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
758 SketchPlugin_Sketch* aSketch = sketch();
762 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
763 data()->attribute(SketchPlugin_Constraint::VALUE()));
764 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
765 std::string aFeatureKind = aBaseFeature->getKind();
766 if (aFeatureKind != SketchPlugin_Line::ID())
769 AttributePoint2DPtr aFirstPointAttrOfSplit =
770 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
771 AttributePoint2DPtr aSecondPointAttrOfSplit =
772 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
773 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
775 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
776 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
777 setError("Error: Feature has no start and end points.");
781 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
782 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
785 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
786 std::cout << "Start point: " <<
787 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
788 std::cout << "1st point: " <<
789 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
790 std::cout << "2nd point: " <<
791 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
792 std::cout << "End point: " <<
793 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
796 /// create a split feature
798 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
799 theCreatedFeatures.insert(theSplitFeature);
801 // before split feature
802 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
803 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
804 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
807 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
808 /// move end arc point to start of split
811 // after split feature
812 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
814 if (!theBaseFeatureModified.get()) {
815 aFeature = aBaseFeature; ///< use base feature to store all constraints here
816 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
817 aFeature->execute(); // to update result
820 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
821 theCreatedFeatures.insert(aFeature);
822 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
823 aFeature->attribute(SketchPlugin_Line::END_ID())));
825 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
826 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
827 aFeature->attribute(SketchPlugin_Line::START_ID()));
828 theCreatedFeatures.insert(aConstraintFeature);
830 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
831 (aFeature->attribute(SketchPlugin_Line::START_ID())));
832 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
833 (aFeature->attribute(SketchPlugin_Line::END_ID())));
835 if (!theBaseFeatureModified.get())
836 theBaseFeatureModified = aFeature;
838 theAfterFeature = aFeature;
841 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
842 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
843 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
844 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
846 // base split, that is defined before split feature should be changed at end
847 // (after the after feature creation). Otherwise modified value will be used in after feature
848 // before split feature
849 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
850 /// move end arc point to start of split
851 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
852 aFirstPointAttrOfSplit);
853 theBaseFeatureModified->execute(); // to update result
854 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
855 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
856 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
857 theCreatedFeatures.insert(aConstraintFeature);
859 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
860 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
861 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
862 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
865 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
866 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
868 // additional constraints between split and base features
869 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
870 getFeatureResult(aBaseFeature),
871 getFeatureResult(theSplitFeature));
872 theCreatedFeatures.insert(aConstraintFeature);
873 if (theAfterFeature.get()) {
874 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
875 getFeatureResult(aBaseFeature),
876 getFeatureResult(theAfterFeature));
877 theCreatedFeatures.insert(aConstraintFeature);
881 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
882 FeaturePtr& theBaseFeatureModified,
883 FeaturePtr& theAfterFeature,
884 std::set<AttributePoint2DPtr>& thePoints,
885 std::set<FeaturePtr>& theCreatedFeatures,
886 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
888 std::set<FeaturePtr> aCreatedFeatures;
889 FeaturePtr aConstraintFeature;
890 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
892 SketchPlugin_Sketch* aSketch = sketch();
896 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
897 data()->attribute(SketchPlugin_Constraint::VALUE()));
898 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
899 std::string aFeatureKind = aBaseFeature->getKind();
900 if (aFeatureKind != SketchPlugin_Arc::ID())
903 AttributePoint2DPtr aFirstPointAttrOfSplit =
904 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
905 AttributePoint2DPtr aSecondPointAttrOfSplit =
906 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
907 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
908 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
909 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
910 setError("Error: Feature has no start and end points.");
914 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
915 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
916 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
918 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
919 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
921 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
922 std::cout << "Start point: " <<
923 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
924 std::cout << "1st point: " <<
925 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
926 std::cout << "2nd point: " <<
927 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
928 std::cout << "End point: " <<
929 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
933 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
934 theCreatedFeatures.insert(theSplitFeature);
936 // before split feature
937 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
938 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
939 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
942 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
943 /// move end arc point to start of split
946 // after split feature
947 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
949 if (!theBaseFeatureModified.get()) {
950 aFeature = aBaseFeature; ///< use base feature to store all constraints here
951 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
952 aFeature->execute(); // to update result
955 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
956 theCreatedFeatures.insert(aFeature);
957 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
958 aFeature->attribute(SketchPlugin_Arc::END_ID())));
960 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
961 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
962 aFeature->attribute(SketchPlugin_Arc::START_ID()));
963 theCreatedFeatures.insert(aConstraintFeature);
965 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
966 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
967 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
968 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
970 if (!theBaseFeatureModified.get())
971 theBaseFeatureModified = aFeature;
973 theAfterFeature = aFeature;
976 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
977 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
978 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
979 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
981 // base split, that is defined before split feature should be changed at end
982 // (after the after feature creation). Otherwise modified value will be used in after feature
983 // before split feature
984 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
985 /// move end arc point to start of split
986 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
987 aFirstPointAttrOfSplit);
988 theBaseFeatureModified->execute(); // to update result
989 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
990 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
991 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
992 theCreatedFeatures.insert(aConstraintFeature);
994 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
995 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
996 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
997 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1000 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1001 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1003 // additional constraints between split and base features
1004 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1005 getFeatureResult(aBaseFeature),
1006 getFeatureResult(theSplitFeature));
1007 theCreatedFeatures.insert(aConstraintFeature);
1008 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1009 getFeatureResult(theSplitFeature),
1010 getFeatureResult(aBaseFeature));
1011 theCreatedFeatures.insert(aConstraintFeature);
1012 if (theAfterFeature.get()) {
1013 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1014 getFeatureResult(aBaseFeature),
1015 getFeatureResult(theAfterFeature));
1016 theCreatedFeatures.insert(aConstraintFeature);
1017 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1018 getFeatureResult(theSplitFeature),
1019 getFeatureResult(theAfterFeature));
1020 theCreatedFeatures.insert(aConstraintFeature);
1024 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1025 FeaturePtr& theBaseFeatureModified,
1026 FeaturePtr& theAfterFeature,
1027 std::set<AttributePoint2DPtr>& thePoints,
1028 std::set<FeaturePtr>& theCreatedFeatures,
1029 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1031 std::set<FeaturePtr> aCreatedFeatures;
1032 FeaturePtr aConstraintFeature;
1033 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1035 SketchPlugin_Sketch* aSketch = sketch();
1039 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1040 data()->attribute(SketchPlugin_Constraint::VALUE()));
1041 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1042 std::string aFeatureKind = aBaseFeature->getKind();
1043 if (aFeatureKind != SketchPlugin_Circle::ID())
1046 AttributePoint2DPtr aFirstPointAttrOfSplit =
1047 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1048 AttributePoint2DPtr aSecondPointAttrOfSplit =
1049 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1053 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1054 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1055 theCreatedFeatures.insert(theSplitFeature);
1057 /// base feature is a left part of the circle
1058 theBaseFeatureModified = createArcFeature(aBaseFeature,
1059 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1060 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1061 theBaseFeatureModified)->setReversed(!aSplitReversed);
1062 theBaseFeatureModified->execute();
1064 theModifiedAttributes.insert(
1065 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1066 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1068 theCreatedFeatures.insert(theBaseFeatureModified);
1070 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1071 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1072 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1073 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1075 // additional constraints between split and base features
1076 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1077 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1078 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1079 theCreatedFeatures.insert(aConstraintFeature);
1080 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1081 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1082 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1083 theCreatedFeatures.insert(aConstraintFeature);
1085 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1086 getFeatureResult(theSplitFeature),
1087 getFeatureResult(theBaseFeatureModified));
1088 theCreatedFeatures.insert(aConstraintFeature);
1091 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1092 const AttributePoint2DPtr& theStartPointAttr,
1093 const AttributePoint2DPtr& theEndPointAttr,
1094 AttributePoint2DPtr& theFirstPointAttr,
1095 AttributePoint2DPtr& theLastPointAttr) const
1097 // if first point is closer to last point, swap first and last values
1098 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1099 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1100 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1101 theFirstPointAttr = theLastPointAttr;
1102 theLastPointAttr = aTmpPoint;
1106 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1107 const FeaturePtr& theArc,
1108 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1109 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1110 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1111 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1113 static const double anAngleTol = 1.e-12;
1115 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1116 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1117 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1119 // collect directions to each point
1120 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1121 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1122 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1123 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1124 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1125 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1127 // sort points by their angular values
1128 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1129 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1130 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1131 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1132 aFirstPtAngle += aPeriod;
1133 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1134 aSecondPtAngle += aPeriod;
1136 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1137 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1138 theFirstPointAttr = theSecondPointAttr;
1139 theSecondPointAttr = aTmpPoint;
1143 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1144 const AttributePtr& theSourceAttribute)
1146 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1147 theModifiedAttribute);
1148 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1149 theSourceAttribute);
1151 if (aModifiedAttribute.get() && aSourceAttribute.get())
1152 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1155 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1156 const AttributePtr& theFirstPointAttr,
1157 const AttributePtr& theSecondPointAttr)
1159 FeaturePtr aFeature;
1160 SketchPlugin_Sketch* aSketch = sketch();
1161 if (!aSketch || !theBaseFeature.get())
1164 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1166 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1167 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1168 aFeature->execute(); // to obtain result
1173 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1174 const AttributePtr& theFirstPointAttr,
1175 const AttributePtr& theSecondPointAttr)
1177 FeaturePtr aFeature;
1178 SketchPlugin_Sketch* aSketch = sketch();
1179 if (!aSketch || !theBaseFeature.get())
1182 std::string aCenterAttributeId;
1183 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1184 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1185 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1186 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1188 if (aCenterAttributeId.empty())
1191 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1192 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1193 // the "attribute updated"
1194 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1195 aFeature->data()->blockSendAttributeUpdated(true);
1197 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1198 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1200 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1201 theBaseFeature->attribute(aCenterAttributeId));
1202 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1203 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1205 /// fill referersed state of created arc as it is on the base arc
1206 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1207 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1208 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1210 aFeature->data()->blockSendAttributeUpdated(false);
1211 aFeature->execute(); // to obtain result
1216 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1217 const AttributePtr& theFirstAttribute,
1218 const AttributePtr& theSecondAttribute)
1220 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1221 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1222 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1223 aRefAttr->setAttr(theFirstAttribute);
1225 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1226 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1227 aRefAttr->setAttr(theSecondAttribute);
1232 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1233 const std::string& theConstraintId,
1234 const ObjectPtr& theFirstObject,
1235 const ObjectPtr& theSecondObject)
1237 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1238 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1239 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1240 aRefAttr->setObject(theFirstObject);
1242 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1243 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1244 aRefAttr->setObject(theSecondObject);
1249 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1250 const std::set<FeaturePtr>& theFeaturesToUpdate)
1252 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1253 aLast = theFeaturesToUpdate.end();
1254 for (; anIt != aLast; anIt++) {
1255 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1256 std::string aRefFeatureKind = aRefFeature->getKind();
1257 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1258 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1259 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1260 if (aLenghtFeature.get()) {
1261 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1262 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1264 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1265 aValueAttr->setValue(aValue);
1271 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1272 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1274 std::shared_ptr<ModelAPI_Result> aResult;
1276 std::string aFeatureKind = theFeature->getKind();
1277 if (aFeatureKind == SketchPlugin_Line::ID())
1278 aResult = theFeature->firstResult();
1279 else if (aFeatureKind == SketchPlugin_Arc::ID())
1280 aResult = theFeature->lastResult();
1281 else if (aFeatureKind == SketchPlugin_Circle::ID())
1282 aResult = theFeature->lastResult();
1287 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1288 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1290 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1292 std::string aFeatureKind = theFeature->getKind();
1293 if (aFeatureKind == SketchPlugin_Line::ID()) {
1294 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1295 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1297 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1298 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1299 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1301 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1304 return anAttributes;
1308 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1309 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1310 const bool isUseAttributesInfo)
1313 if (!theFeature.get()) {
1317 if (theFeature->data()->isValid())
1318 anInfo.append(theFeature->data()->name().c_str());
1320 if (isUseAttributesInfo) {
1321 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1322 getEdgeAttributes(theFeature));
1323 /// processing of feature with point 2d attributes, like line, arc, circle
1324 if (!aPointsInfo.empty()) {
1327 anInfo += aPointsInfo;
1329 else { /// process constraint coincidence, find points in ref attr attributes
1330 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1331 ModelAPI_AttributeRefAttr::typeId());
1332 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1333 std::string anAttributesInfo;
1334 for(; anIt != aLast; anIt++) {
1335 if (!anAttributesInfo.empty()) {
1336 anAttributesInfo.append(", ");
1337 anAttributesInfo += "\n";
1339 AttributePtr anAttr = *anIt;
1340 std::string aValue = "not defined";
1341 std::string aType = anAttr->attributeType();
1342 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1343 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1344 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1345 if (aRefAttr.get()) {
1346 if (aRefAttr->isObject()) {
1347 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1348 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1351 AttributePtr anAttribute = aRefAttr->attr();
1352 if (anAttribute.get()) {
1353 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1354 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1355 " [" + getFeatureInfo(aFeature, false) + "]";
1360 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1362 if (!anAttributesInfo.empty())
1363 anInfo = anInfo + "\n" + anAttributesInfo;