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>
35 #include <SketchPlugin_ConstraintMiddle.h>
37 #include <ModelAPI_Events.h>
38 #include <SketchPlugin_Line.h>
39 #include <SketchPlugin_Arc.h>
40 #include <SketchPlugin_Circle.h>
42 #include <ModelGeomAlgo_Point2D.h>
43 #include <Events_Loop.h>
52 static const double PI = 3.141592653589793238463;
54 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
58 void SketchPlugin_ConstraintSplit::initAttributes()
60 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
61 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
62 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
65 void SketchPlugin_ConstraintSplit::execute()
67 std::shared_ptr<ModelAPI_Data> aData = data();
69 // Check the base objects are initialized.
70 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
71 aData->attribute(SketchPlugin_Constraint::VALUE()));
72 if(!aBaseObjectAttr->isInitialized()) {
73 setError("Error: Base object is not initialized.");
76 AttributePoint2DPtr aFirstPointAttrOfSplit =
77 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
78 AttributePoint2DPtr aSecondPointAttrOfSplit =
79 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
80 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
81 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
82 setError("Error: Sub-shape is not initialized.");
86 // Wait all constraints being created, then send update events
87 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
88 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
90 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
93 // Find feature constraints
94 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
95 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
96 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
98 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
99 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
100 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
102 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
103 std::list<AttributePtr> aRefsToFeature;
104 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
106 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
109 std::cout << std::endl;
110 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
111 std::cout << std::endl;
113 SketchPlugin_Sketch* aSketch = sketch();
114 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
115 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
116 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
119 std::cout << std::endl;
120 std::cout << "---- IN PARAMETERS ----" << std::endl;
121 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
122 std::cout << std::endl;
124 if (!aCoincidenceToFeature.empty()) {
125 std::cout << "Coincidences to base feature[" <<
126 aCoincidenceToFeature.size() << "]: " << std::endl;
127 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
128 aLast = aCoincidenceToFeature.end();
129 for (int i = 1; anIt != aLast; anIt++, i++) {
130 FeaturePtr aFeature = (*anIt).first;
131 std::string anAttributeId = (*anIt).second.first;
132 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
134 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
135 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
136 std::cout << " -Point attribute:" <<
137 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
141 if (!aTangentFeatures.empty()) {
142 std::cout << std::endl;
143 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
144 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
145 aLast = aTangentFeatures.end();
146 for (int i = 1; anIt != aLast; anIt++, i++) {
147 FeaturePtr aFeature = (*anIt).first;
148 std::string anAttributeId = (*anIt).second.first;
149 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
151 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
152 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
153 std::cout << " -Point attribute:" <<
154 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
158 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
159 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
160 std::cout << std::endl << "References to attributes of base feature [" <<
161 aBaseRefAttributes.size() << "]" << std::endl;
162 for (; aRefIt != aRefLast; aRefIt++) {
163 AttributePtr aBaseAttr = aRefIt->first;
164 std::list<AttributePtr> aRefAttributes = aRefIt->second;
165 std::string aRefsInfo;
166 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
167 aRefAttrLast = aRefAttributes.end();
168 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
169 if (!aRefsInfo.empty())
170 aRefsInfo.append(",");
171 AttributePtr aRAttr = *aRefAttrIt;
172 aRefsInfo.append(aRAttr->id());
173 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
174 aRefsInfo.append("(" + aRFeature->name() + ") ");
176 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
177 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
178 std::cout << aPointAttr->id().c_str() <<
179 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
181 std::cout << std::endl;
182 std::cout << std::endl << "References to base feature [" <<
183 aRefsToFeature.size() << "]" << std::endl;
184 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
185 aRefAttrLast = aRefsToFeature.end();
186 std::string aRefsInfo;
187 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
188 if (!aRefsInfo.empty())
189 aRefsInfo.append(",");
190 AttributePtr aRAttr = *aRefAttrIt;
191 aRefsInfo.append(aRAttr->id());
192 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
193 aRefsInfo.append("(" + aRFeature->name() + ") ");
195 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
198 std::cout << std::endl;
199 std::cout << "---- SPLIT ----" << std::endl;
200 std::cout << std::endl;
203 std::string aFeatureKind = aBaseFeature->getKind();
204 FeaturePtr aSplitFeature, anAfterFeature;
205 std::set<AttributePoint2DPtr> aFurtherCoincidences;
206 std::set<FeaturePtr> aCreatedFeatures;
207 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
208 if (aFeatureKind == SketchPlugin_Line::ID())
209 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
210 aModifiedAttributes);
211 else if (aFeatureKind == SketchPlugin_Arc::ID())
212 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
213 aModifiedAttributes);
214 if (aFeatureKind == SketchPlugin_Circle::ID()) {
215 FeaturePtr aCircleFeature = aBaseFeature;
216 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
217 aCreatedFeatures, aModifiedAttributes);
219 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
221 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
222 aFeaturesToDelete.insert(aCircleFeature);
223 // as circle is removed, temporary fill this attribute*/
224 aBaseObjectAttr->setObject(ResultPtr());
228 std::cout << "---- OUT PARAMETERS ----" << std::endl;
229 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
230 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
231 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
232 std::cout << std::endl;
234 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
235 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
236 aFLast = aCreatedFeatures.end();
237 for (; aFIt != aFLast; aFIt++) {
238 std::cout << getFeatureInfo(*aFIt) << std::endl;
240 std::cout << std::endl;
242 std::cout << "Attributes for further Coincidences:" << std::endl;
243 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
244 aLast = aFurtherCoincidences.end();
245 for (; anIt != aLast; anIt++) {
246 AttributePtr anAttribute = *anIt;
247 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
248 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
249 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
252 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
253 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
254 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
255 std::string aResInfo;
256 for (; aPIt != aPLast; aPIt++) {
257 if (!aResInfo.empty())
260 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
262 AttributePtr anAttr = aPair.first;
263 aResInfo.append(anAttr->id());
264 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
265 aResInfo.append("(" + aFeature->name() + ") ");
267 aResInfo.append(" - is modified to - ");
269 anAttr = aPair.second;
270 aResInfo.append(anAttr->id());
271 aFeature = ModelAPI_Feature::feature(anAttr->owner());
272 aResInfo.append("(" + aFeature->name() + ") ");
274 std::cout << aResInfo << std::endl;
277 std::set<ResultPtr> aFeatureResults;
278 aFeatureResults.insert(getFeatureResult(aBaseFeature));
279 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
280 aFeatureResults.insert(getFeatureResult(anAfterFeature));
282 // coincidence to feature
283 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
284 aFeatureResults, aSplitFeature);
286 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
288 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
290 // delete constraints
292 std::cout << "remove features and references:" << std::endl;
293 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
294 aDLast = aFeaturesToDelete.end();
295 for (; aDIt != aDLast; aDIt++) {
296 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
297 std::cout << std::endl;
300 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
301 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
304 std::cout << "update features after split:" << std::endl;
305 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
306 anULast = aFeaturesToUpdate.end();
307 for (; anUIt != anULast; anUIt++) {
308 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
309 std::cout << std::endl;
312 updateFeaturesAfterSplit(aFeaturesToUpdate);
314 // Send events to update the sub-features by the solver.
315 if(isUpdateFlushed) {
316 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
320 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
321 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
322 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
327 bool SketchPlugin_ConstraintSplit::isMacro() const
332 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
334 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
335 data()->attribute(SketchPlugin_Constraint::VALUE()));
336 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
338 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
339 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
340 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
341 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
343 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
344 aFirstPointAttrOfSplit->isInitialized() &&
345 aSecondPointAttrOfSplit->isInitialized()) {
347 ResultPtr aResult = getFeatureResult(aBaseFeature);
348 GeomShapePtr aBaseShape = aResult->shape();
349 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
351 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
352 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
353 aPoints.push_back(aStartPoint);
355 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
356 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
357 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
358 aPoints.push_back(aSecondPoint);
360 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
362 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
363 std::shared_ptr<GeomAPI_Shape> aShape =
364 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
366 AISObjectPtr anAIS = thePrevious;
369 anAIS = AISObjectPtr(new GeomAPI_AISObject);
370 anAIS->createShape(aShape);
372 std::vector<int> aColor;
373 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
374 SKETCH_ENTITY_COLOR);
375 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
379 return AISObjectPtr();
382 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
383 const AttributePtr& theAttribute)
385 AttributePoint2DPtr aPointAttribute;
387 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
388 AttributeRefAttrPtr aRefAttr =
389 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
390 if (aRefAttr.get() && aRefAttr->isInitialized()) {
391 AttributePtr anAttribute = aRefAttr->attr();
392 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
393 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
396 return aPointAttribute;
399 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
400 AttributePoint2DPtr& theStartPointAttr,
401 AttributePoint2DPtr& theEndPointAttr)
403 std::string aFeatureKind = theFeature->getKind();
404 std::string aStartAttributeName, anEndAttributeName;
405 if (aFeatureKind == SketchPlugin_Line::ID()) {
406 aStartAttributeName = SketchPlugin_Line::START_ID();
407 anEndAttributeName = SketchPlugin_Line::END_ID();
409 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
410 aStartAttributeName = SketchPlugin_Arc::START_ID();
411 anEndAttributeName = SketchPlugin_Arc::END_ID();
413 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
414 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
415 theFeature->attribute(aStartAttributeName));
416 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
417 theFeature->attribute(anEndAttributeName));
421 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
422 std::set<FeaturePtr>& theFeaturesToUpdate,
423 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
424 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
426 std::shared_ptr<ModelAPI_Data> aData = data();
428 // Check the base objects are initialized.
429 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
430 aData->attribute(SketchPlugin_Constraint::VALUE()));
431 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
432 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
434 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
435 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
436 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
438 std::set<AttributePtr>::const_iterator aIt;
439 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
440 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
441 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
442 std::string aRefFeatureKind = aRefFeature->getKind();
443 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
444 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
445 aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
446 aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
447 theFeaturesToDelete.insert(aRefFeature);
448 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
449 theFeaturesToUpdate.insert(aRefFeature);
450 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
451 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
452 /// until tangency between arc and line is implemented
453 theFeaturesToDelete.insert(aRefFeature);
455 std::string anAttributeToBeModified;
456 AttributePoint2DPtr aTangentPoint;
457 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
458 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
459 if (aResult1.get() && aResult2.get()) {
460 FeaturePtr aCoincidenceFeature =
461 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
462 (ModelAPI_Feature::feature(aResult1),
463 ModelAPI_Feature::feature(aResult2));
464 // get the point not lying on the splitting feature
465 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
466 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
467 if (!aRefAttr || aRefAttr->isObject())
469 AttributePoint2DPtr aPoint =
470 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
473 if (aPoint->owner() != aBaseFeature) {
474 aTangentPoint = aPoint;
479 if (aTangentPoint.get()) {
480 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
481 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
482 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
483 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
485 else /// there is not coincident point between tangent constraint
486 theFeaturesToDelete.insert(aRefFeature);
489 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
490 std::string anAttributeToBeModified;
491 AttributePoint2DPtr aCoincidentPoint;
492 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
493 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
494 bool isToFeature = false;
495 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
496 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
498 isToFeature = aFeature.get() && aFeature == aBaseFeature;
499 anAttributeToBeModified = anAttrA->id();
501 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
503 isToFeature = aFeature.get() && aFeature == aBaseFeature;
504 anAttributeToBeModified = anAttrB->id();
507 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
509 if (!isToFeature) { /// coincidence to point on base feature
510 AttributePtr anAttribute;
512 if (!anAttrA->isObject()) {
513 AttributePtr aCurAttribute = anAttrA->attr();
514 if (aCurAttribute.get()) {
515 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
516 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
517 anAttribute = anAttrB->attr();
518 anAttributeToBeModified = anAttrA->id();
522 if (!anAttribute.get() && !anAttrB->isObject()) {
523 AttributePtr aCurAttribute = anAttrB->attr();
524 if (aCurAttribute.get()) {
525 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
526 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
527 anAttribute = anAttrA->attr();
528 anAttributeToBeModified = anAttrB->id();
532 if (anAttribute.get())
533 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
535 if (aCoincidentPoint.get() && isToFeature)
536 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
542 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
543 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
544 std::list<AttributePtr>& theRefsToFeature)
548 std::list<AttributePtr> aPointAttributes =
549 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
550 std::set<AttributePtr> aPointAttributesSet;
552 std::list<AttributePtr>::const_iterator aPIt =
553 aPointAttributes.begin(), aPLast = aPointAttributes.end();
554 for (; aPIt != aPLast; aPIt++)
555 aPointAttributesSet.insert(*aPIt);
557 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
558 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
559 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
561 std::set<AttributePtr>::const_iterator aIt;
562 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
563 AttributePtr anAttr = (*aIt);
564 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
565 if (anAttrFeature.get() != this &&
566 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
567 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
568 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
569 AttributePtr anAttrInRef = aRefAttr->attr();
570 if (anAttrInRef.get() &&
571 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
572 if (theRefs.find(anAttrInRef) != theRefs.end())
573 theRefs[anAttrInRef].push_back(aRefAttr);
575 std::list<AttributePtr> anAttrList;
576 anAttrList.push_back(aRefAttr);
577 theRefs[anAttrInRef] = anAttrList;
581 else { /// find attributes referenced to feature itself
582 theRefsToFeature.push_back(anAttr);
588 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
589 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
590 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
591 const std::set<ResultPtr>& theFeatureResults,
592 const FeaturePtr& theSplitFeature)
594 if (theCoincidenceToFeature.empty())
597 // we should build coincidence constraints to end of the split feature
598 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
599 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
600 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
601 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
602 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
603 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
604 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
606 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
607 aCLast = theCoincidenceToFeature.end();
609 std::cout << std::endl;
610 std::cout << "Coincidences to feature(modified):"<< std::endl;
612 for (; aCIt != aCLast; aCIt++) {
613 FeaturePtr aCoincFeature = aCIt->first;
614 std::string anAttributeId = aCIt->second.first;
615 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
616 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
617 aFCLast = theFurtherCoincidences.end();
618 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
619 AttributePoint2DPtr aFeaturePointAttribute;
620 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
621 AttributePoint2DPtr aFCAttribute = *aFCIt;
622 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
623 aFeaturePointAttribute = aFCAttribute;
625 if (aFeaturePointAttribute.get()) {
626 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
627 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
628 // create new coincidences to split feature points
629 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
630 aSFLast = aNewCoincidencesToSplitFeature.end();
631 for (; aSFIt != aSFLast; aSFIt++) {
632 AttributePoint2DPtr aSFAttribute = *aSFIt;
633 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
634 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
635 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
636 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
637 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
638 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
643 /// find feature by shape intersected the point
644 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
646 if (theFeatureResults.size() > 1) { // try to find point on additional feature
647 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
648 GeomShapePtr aShape = anAddtionalResult->shape();
650 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
651 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
653 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
654 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
655 aResultForCoincidence = anAddtionalResult;
657 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
660 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
665 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
666 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
667 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
669 if (theTangentFeatures.empty())
672 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
673 aTLast = theTangentFeatures.end();
675 std::cout << std::endl;
676 std::cout << "Tangencies to feature(modified):"<< std::endl;
678 for (; aTIt != aTLast; aTIt++) {
679 FeaturePtr aTangentFeature = aTIt->first;
680 std::string anAttributeId = aTIt->second.first;
681 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
682 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
683 aFCLast = theFurtherCoincidences.end();
684 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
685 AttributePoint2DPtr aFeaturePointAttribute;
686 /// here we rely on created coincidence between further coincidence point and tangent result
687 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
688 AttributePoint2DPtr aFCAttribute = *aFCIt;
689 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
690 aFeaturePointAttribute = aFCAttribute;
692 if (aFeaturePointAttribute.get()) {
693 FeaturePtr aFeature =
694 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
695 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
698 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
703 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
704 const ResultPtr& theFeatureBaseResult,
705 const std::list<AttributePtr>& theRefsToFeature)
707 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
708 aLast = theRefsToFeature.end();
709 for (; anIt != aLast; anIt++) {
710 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
712 aRefAttr->setObject(theFeatureBaseResult);
716 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
717 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
718 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
721 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
724 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
725 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
726 for (; anIt != aLast; anIt++) {
727 AttributePtr anAttribute = anIt->first;
729 /// not found in references
730 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
732 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
733 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
734 aRLast = aRefAttributes.end();
736 AttributePtr aNewAttribute = anIt->second;
737 for (; aRefIt != aRLast; aRefIt++) {
738 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
739 if (aRefAttr.get()) {
740 aRefAttr->setAttr(aNewAttribute);
742 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
743 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
750 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
751 FeaturePtr& theBaseFeatureModified,
752 FeaturePtr& theAfterFeature,
753 std::set<AttributePoint2DPtr>& thePoints,
754 std::set<FeaturePtr>& theCreatedFeatures,
755 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
757 std::set<FeaturePtr> aCreatedFeatures;
758 FeaturePtr aConstraintFeature;
759 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
761 SketchPlugin_Sketch* aSketch = sketch();
765 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
766 data()->attribute(SketchPlugin_Constraint::VALUE()));
767 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
768 std::string aFeatureKind = aBaseFeature->getKind();
769 if (aFeatureKind != SketchPlugin_Line::ID())
772 AttributePoint2DPtr aFirstPointAttrOfSplit =
773 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
774 AttributePoint2DPtr aSecondPointAttrOfSplit =
775 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
776 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
778 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
779 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
780 setError("Error: Feature has no start and end points.");
784 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
785 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
788 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
789 std::cout << "Start point: " <<
790 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
791 std::cout << "1st point: " <<
792 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
793 std::cout << "2nd point: " <<
794 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
795 std::cout << "End point: " <<
796 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
799 /// create a split feature
801 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
802 theCreatedFeatures.insert(theSplitFeature);
804 // before split feature
805 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
806 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
807 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
810 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
811 /// move end arc point to start of split
814 // after split feature
815 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
817 if (!theBaseFeatureModified.get()) {
818 aFeature = aBaseFeature; ///< use base feature to store all constraints here
819 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
820 aFeature->execute(); // to update result
823 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
824 theCreatedFeatures.insert(aFeature);
825 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
826 aFeature->attribute(SketchPlugin_Line::END_ID())));
828 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
829 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
830 aFeature->attribute(SketchPlugin_Line::START_ID()));
831 theCreatedFeatures.insert(aConstraintFeature);
833 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
834 (aFeature->attribute(SketchPlugin_Line::START_ID())));
835 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
836 (aFeature->attribute(SketchPlugin_Line::END_ID())));
838 if (!theBaseFeatureModified.get())
839 theBaseFeatureModified = aFeature;
841 theAfterFeature = aFeature;
844 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
845 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
846 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
847 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
849 // base split, that is defined before split feature should be changed at end
850 // (after the after feature creation). Otherwise modified value will be used in after feature
851 // before split feature
852 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
853 /// move end arc point to start of split
854 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
855 aFirstPointAttrOfSplit);
856 theBaseFeatureModified->execute(); // to update result
857 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
858 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
859 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
860 theCreatedFeatures.insert(aConstraintFeature);
862 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
863 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
864 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
865 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
868 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
869 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
871 // additional constraints between split and base features
872 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
873 getFeatureResult(aBaseFeature),
874 getFeatureResult(theSplitFeature));
875 theCreatedFeatures.insert(aConstraintFeature);
876 if (theAfterFeature.get()) {
877 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
878 getFeatureResult(aBaseFeature),
879 getFeatureResult(theAfterFeature));
880 theCreatedFeatures.insert(aConstraintFeature);
884 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
885 FeaturePtr& theBaseFeatureModified,
886 FeaturePtr& theAfterFeature,
887 std::set<AttributePoint2DPtr>& thePoints,
888 std::set<FeaturePtr>& theCreatedFeatures,
889 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
891 std::set<FeaturePtr> aCreatedFeatures;
892 FeaturePtr aConstraintFeature;
893 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
895 SketchPlugin_Sketch* aSketch = sketch();
899 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
900 data()->attribute(SketchPlugin_Constraint::VALUE()));
901 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
902 std::string aFeatureKind = aBaseFeature->getKind();
903 if (aFeatureKind != SketchPlugin_Arc::ID())
906 AttributePoint2DPtr aFirstPointAttrOfSplit =
907 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
908 AttributePoint2DPtr aSecondPointAttrOfSplit =
909 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
910 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
911 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
912 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
913 setError("Error: Feature has no start and end points.");
917 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
918 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
919 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
921 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
922 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
924 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
925 std::cout << "Start point: " <<
926 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
927 std::cout << "1st point: " <<
928 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
929 std::cout << "2nd point: " <<
930 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
931 std::cout << "End point: " <<
932 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
936 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
937 theCreatedFeatures.insert(theSplitFeature);
939 // before split feature
940 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
941 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
942 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
945 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
946 /// move end arc point to start of split
949 // after split feature
950 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
952 if (!theBaseFeatureModified.get()) {
953 aFeature = aBaseFeature; ///< use base feature to store all constraints here
954 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
955 aFeature->execute(); // to update result
958 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
959 theCreatedFeatures.insert(aFeature);
960 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
961 aFeature->attribute(SketchPlugin_Arc::END_ID())));
963 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
964 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
965 aFeature->attribute(SketchPlugin_Arc::START_ID()));
966 theCreatedFeatures.insert(aConstraintFeature);
968 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
969 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
970 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
971 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
973 if (!theBaseFeatureModified.get())
974 theBaseFeatureModified = aFeature;
976 theAfterFeature = aFeature;
979 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
980 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
981 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
982 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
984 // base split, that is defined before split feature should be changed at end
985 // (after the after feature creation). Otherwise modified value will be used in after feature
986 // before split feature
987 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
988 /// move end arc point to start of split
989 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
990 aFirstPointAttrOfSplit);
991 theBaseFeatureModified->execute(); // to update result
992 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
993 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
994 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
995 theCreatedFeatures.insert(aConstraintFeature);
997 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
998 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
999 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1000 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1003 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1004 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1006 // additional constraints between split and base features
1007 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1008 getFeatureResult(aBaseFeature),
1009 getFeatureResult(theSplitFeature));
1010 theCreatedFeatures.insert(aConstraintFeature);
1011 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1012 getFeatureResult(theSplitFeature),
1013 getFeatureResult(aBaseFeature));
1014 theCreatedFeatures.insert(aConstraintFeature);
1015 if (theAfterFeature.get()) {
1016 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1017 getFeatureResult(aBaseFeature),
1018 getFeatureResult(theAfterFeature));
1019 theCreatedFeatures.insert(aConstraintFeature);
1020 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1021 getFeatureResult(theSplitFeature),
1022 getFeatureResult(theAfterFeature));
1023 theCreatedFeatures.insert(aConstraintFeature);
1027 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1028 FeaturePtr& theBaseFeatureModified,
1029 FeaturePtr& theAfterFeature,
1030 std::set<AttributePoint2DPtr>& thePoints,
1031 std::set<FeaturePtr>& theCreatedFeatures,
1032 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1034 std::set<FeaturePtr> aCreatedFeatures;
1035 FeaturePtr aConstraintFeature;
1036 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1038 SketchPlugin_Sketch* aSketch = sketch();
1042 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1043 data()->attribute(SketchPlugin_Constraint::VALUE()));
1044 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1045 std::string aFeatureKind = aBaseFeature->getKind();
1046 if (aFeatureKind != SketchPlugin_Circle::ID())
1049 AttributePoint2DPtr aFirstPointAttrOfSplit =
1050 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1051 AttributePoint2DPtr aSecondPointAttrOfSplit =
1052 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1056 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1057 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1058 theCreatedFeatures.insert(theSplitFeature);
1060 /// base feature is a left part of the circle
1061 theBaseFeatureModified = createArcFeature(aBaseFeature,
1062 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1063 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1064 theBaseFeatureModified)->setReversed(!aSplitReversed);
1065 theBaseFeatureModified->execute();
1067 theModifiedAttributes.insert(
1068 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1069 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1071 theCreatedFeatures.insert(theBaseFeatureModified);
1073 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1074 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1075 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1076 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1078 // additional constraints between split and base features
1079 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1080 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1081 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1082 theCreatedFeatures.insert(aConstraintFeature);
1083 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1084 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1085 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1086 theCreatedFeatures.insert(aConstraintFeature);
1088 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1089 getFeatureResult(theSplitFeature),
1090 getFeatureResult(theBaseFeatureModified));
1091 theCreatedFeatures.insert(aConstraintFeature);
1094 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1095 const AttributePoint2DPtr& theStartPointAttr,
1096 const AttributePoint2DPtr& theEndPointAttr,
1097 AttributePoint2DPtr& theFirstPointAttr,
1098 AttributePoint2DPtr& theLastPointAttr) const
1100 // if first point is closer to last point, swap first and last values
1101 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1102 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1103 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1104 theFirstPointAttr = theLastPointAttr;
1105 theLastPointAttr = aTmpPoint;
1109 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1110 const FeaturePtr& theArc,
1111 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1112 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1113 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1114 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1116 static const double anAngleTol = 1.e-12;
1118 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1119 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1120 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1122 // collect directions to each point
1123 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1124 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1125 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1126 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1127 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1128 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1130 // sort points by their angular values
1131 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1132 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1133 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1134 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1135 aFirstPtAngle += aPeriod;
1136 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1137 aSecondPtAngle += aPeriod;
1139 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1140 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1141 theFirstPointAttr = theSecondPointAttr;
1142 theSecondPointAttr = aTmpPoint;
1146 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1147 const AttributePtr& theSourceAttribute)
1149 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1150 theModifiedAttribute);
1151 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1152 theSourceAttribute);
1154 if (aModifiedAttribute.get() && aSourceAttribute.get())
1155 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1158 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1159 const AttributePtr& theFirstPointAttr,
1160 const AttributePtr& theSecondPointAttr)
1162 FeaturePtr aFeature;
1163 SketchPlugin_Sketch* aSketch = sketch();
1164 if (!aSketch || !theBaseFeature.get())
1167 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1169 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1170 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1171 aFeature->execute(); // to obtain result
1176 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1177 const AttributePtr& theFirstPointAttr,
1178 const AttributePtr& theSecondPointAttr)
1180 FeaturePtr aFeature;
1181 SketchPlugin_Sketch* aSketch = sketch();
1182 if (!aSketch || !theBaseFeature.get())
1185 std::string aCenterAttributeId;
1186 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1187 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1188 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1189 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1191 if (aCenterAttributeId.empty())
1194 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1195 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1196 // the "attribute updated"
1197 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1198 aFeature->data()->blockSendAttributeUpdated(true);
1200 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1201 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1203 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1204 theBaseFeature->attribute(aCenterAttributeId));
1205 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1206 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1208 /// fill referersed state of created arc as it is on the base arc
1209 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1210 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1211 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1213 aFeature->data()->blockSendAttributeUpdated(false);
1214 aFeature->execute(); // to obtain result
1219 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1220 const AttributePtr& theFirstAttribute,
1221 const AttributePtr& theSecondAttribute)
1223 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1224 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1225 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1226 aRefAttr->setAttr(theFirstAttribute);
1228 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1229 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1230 aRefAttr->setAttr(theSecondAttribute);
1235 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1236 const std::string& theConstraintId,
1237 const ObjectPtr& theFirstObject,
1238 const ObjectPtr& theSecondObject)
1240 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1241 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1242 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1243 aRefAttr->setObject(theFirstObject);
1245 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1246 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1247 aRefAttr->setObject(theSecondObject);
1252 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1253 const std::set<FeaturePtr>& theFeaturesToUpdate)
1255 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1256 aLast = theFeaturesToUpdate.end();
1257 for (; anIt != aLast; anIt++) {
1258 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1259 std::string aRefFeatureKind = aRefFeature->getKind();
1260 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1261 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1262 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1263 if (aLenghtFeature.get()) {
1264 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1265 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1267 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1268 aValueAttr->setValue(aValue);
1274 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1275 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1277 std::shared_ptr<ModelAPI_Result> aResult;
1279 std::string aFeatureKind = theFeature->getKind();
1280 if (aFeatureKind == SketchPlugin_Line::ID())
1281 aResult = theFeature->firstResult();
1282 else if (aFeatureKind == SketchPlugin_Arc::ID())
1283 aResult = theFeature->lastResult();
1284 else if (aFeatureKind == SketchPlugin_Circle::ID())
1285 aResult = theFeature->lastResult();
1290 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1291 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1293 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1295 std::string aFeatureKind = theFeature->getKind();
1296 if (aFeatureKind == SketchPlugin_Line::ID()) {
1297 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1298 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1300 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1301 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1302 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1304 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1307 return anAttributes;
1311 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1312 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1313 const bool isUseAttributesInfo)
1316 if (!theFeature.get()) {
1320 if (theFeature->data()->isValid())
1321 anInfo.append(theFeature->data()->name().c_str());
1323 if (isUseAttributesInfo) {
1324 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1325 getEdgeAttributes(theFeature));
1326 /// processing of feature with point 2d attributes, like line, arc, circle
1327 if (!aPointsInfo.empty()) {
1330 anInfo += aPointsInfo;
1332 else { /// process constraint coincidence, find points in ref attr attributes
1333 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1334 ModelAPI_AttributeRefAttr::typeId());
1335 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1336 std::string anAttributesInfo;
1337 for(; anIt != aLast; anIt++) {
1338 if (!anAttributesInfo.empty()) {
1339 anAttributesInfo.append(", ");
1340 anAttributesInfo += "\n";
1342 AttributePtr anAttr = *anIt;
1343 std::string aValue = "not defined";
1344 std::string aType = anAttr->attributeType();
1345 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1346 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1347 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1348 if (aRefAttr.get()) {
1349 if (aRefAttr->isObject()) {
1350 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1351 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1354 AttributePtr anAttribute = aRefAttr->attr();
1355 if (anAttribute.get()) {
1356 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1357 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1358 " [" + getFeatureInfo(aFeature, false) + "]";
1363 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1365 if (!anAttributesInfo.empty())
1366 anInfo = anInfo + "\n" + anAttributesInfo;