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 #define CIRCLE_FEATURE_DELETE_WITHOUT_REFERENCES
53 static const double PI = 3.141592653589793238463;
55 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
59 void SketchPlugin_ConstraintSplit::initAttributes()
61 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
62 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
63 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
66 void SketchPlugin_ConstraintSplit::execute()
68 std::shared_ptr<ModelAPI_Data> aData = data();
70 // Check the base objects are initialized.
71 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
72 aData->attribute(SketchPlugin_Constraint::VALUE()));
73 if(!aBaseObjectAttr->isInitialized()) {
74 setError("Error: Base object is not initialized.");
77 AttributePoint2DPtr aFirstPointAttrOfSplit =
78 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
79 AttributePoint2DPtr aSecondPointAttrOfSplit =
80 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
81 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
82 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
83 setError("Error: Sub-shape is not initialized.");
87 // Wait all constraints being created, then send update events
88 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
89 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
91 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
94 // Find feature constraints
95 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
96 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
97 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
98 #ifdef CIRCLE_FEATURE_DELETE_WITHOUT_REFERENCES
99 FeaturePtr aCircleFeatureToDelete;
102 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
103 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
104 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
106 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
107 std::list<AttributePtr> aRefsToFeature;
108 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
110 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
113 std::cout << std::endl;
114 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
115 std::cout << std::endl;
117 SketchPlugin_Sketch* aSketch = sketch();
118 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
119 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
120 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
123 std::cout << std::endl;
124 std::cout << "---- IN PARAMETERS ----" << std::endl;
125 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
126 std::cout << std::endl;
128 if (!aCoincidenceToFeature.empty()) {
129 std::cout << "Coincidences to base feature[" <<
130 aCoincidenceToFeature.size() << "]: " << std::endl;
131 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
132 aLast = aCoincidenceToFeature.end();
133 for (int i = 1; anIt != aLast; anIt++, i++) {
134 FeaturePtr aFeature = (*anIt).first;
135 std::string anAttributeId = (*anIt).second.first;
136 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
138 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
139 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
140 std::cout << " -Point attribute:" <<
141 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
145 if (!aTangentFeatures.empty()) {
146 std::cout << std::endl;
147 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
148 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
149 aLast = aTangentFeatures.end();
150 for (int i = 1; anIt != aLast; anIt++, i++) {
151 FeaturePtr aFeature = (*anIt).first;
152 std::string anAttributeId = (*anIt).second.first;
153 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
155 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
156 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
157 std::cout << " -Point attribute:" <<
158 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
162 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
163 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
164 std::cout << std::endl << "References to attributes of base feature [" <<
165 aBaseRefAttributes.size() << "]" << std::endl;
166 for (; aRefIt != aRefLast; aRefIt++) {
167 AttributePtr aBaseAttr = aRefIt->first;
168 std::list<AttributePtr> aRefAttributes = aRefIt->second;
169 std::string aRefsInfo;
170 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
171 aRefAttrLast = aRefAttributes.end();
172 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
173 if (!aRefsInfo.empty())
174 aRefsInfo.append(",");
175 AttributePtr aRAttr = *aRefAttrIt;
176 aRefsInfo.append(aRAttr->id());
177 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
178 aRefsInfo.append("(" + aRFeature->name() + ") ");
180 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
181 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
182 std::cout << aPointAttr->id().c_str() <<
183 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
185 std::cout << std::endl;
186 std::cout << std::endl << "References to base feature [" <<
187 aRefsToFeature.size() << "]" << std::endl;
188 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
189 aRefAttrLast = aRefsToFeature.end();
190 std::string aRefsInfo;
191 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
192 if (!aRefsInfo.empty())
193 aRefsInfo.append(",");
194 AttributePtr aRAttr = *aRefAttrIt;
195 aRefsInfo.append(aRAttr->id());
196 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
197 aRefsInfo.append("(" + aRFeature->name() + ") ");
199 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
202 std::cout << std::endl;
203 std::cout << "---- SPLIT ----" << std::endl;
204 std::cout << std::endl;
207 std::string aFeatureKind = aBaseFeature->getKind();
208 FeaturePtr aSplitFeature, anAfterFeature;
209 std::set<AttributePoint2DPtr> aFurtherCoincidences;
210 std::set<FeaturePtr> aCreatedFeatures;
211 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
212 if (aFeatureKind == SketchPlugin_Line::ID())
213 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
214 aModifiedAttributes);
215 else if (aFeatureKind == SketchPlugin_Arc::ID())
216 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
217 aModifiedAttributes);
218 if (aFeatureKind == SketchPlugin_Circle::ID()) {
219 FeaturePtr aCircleFeature = aBaseFeature;
220 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
221 aCreatedFeatures, aModifiedAttributes);
223 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
225 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
226 #ifdef CIRCLE_FEATURE_DELETE_WITHOUT_REFERENCES
227 aCircleFeatureToDelete = aCircleFeature;
229 aFeaturesToDelete.insert(aCircleFeature);
231 // as circle is removed, temporary fill this attribute*/
232 aBaseObjectAttr->setObject(ResultPtr());
236 std::cout << "---- OUT PARAMETERS ----" << std::endl;
237 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
238 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
239 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
240 std::cout << std::endl;
242 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
243 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
244 aFLast = aCreatedFeatures.end();
245 for (; aFIt != aFLast; aFIt++) {
246 std::cout << getFeatureInfo(*aFIt) << std::endl;
248 std::cout << std::endl;
250 std::cout << "Attributes for further Coincidences:" << std::endl;
251 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
252 aLast = aFurtherCoincidences.end();
253 for (; anIt != aLast; anIt++) {
254 AttributePtr anAttribute = *anIt;
255 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
256 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
257 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
260 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
261 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
262 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
263 std::string aResInfo;
264 for (; aPIt != aPLast; aPIt++) {
265 if (!aResInfo.empty())
268 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
270 AttributePtr anAttr = aPair.first;
271 aResInfo.append(anAttr->id());
272 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
273 aResInfo.append("(" + aFeature->name() + ") ");
275 aResInfo.append(" - is modified to - ");
277 anAttr = aPair.second;
278 aResInfo.append(anAttr->id());
279 aFeature = ModelAPI_Feature::feature(anAttr->owner());
280 aResInfo.append("(" + aFeature->name() + ") ");
282 std::cout << aResInfo << std::endl;
285 std::set<ResultPtr> aFeatureResults;
286 aFeatureResults.insert(getFeatureResult(aBaseFeature));
287 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
288 aFeatureResults.insert(getFeatureResult(anAfterFeature));
290 // coincidence to feature
291 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
292 aFeatureResults, aSplitFeature);
294 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
296 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
298 // delete constraints
300 std::cout << "remove features and references:" << std::endl;
301 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
302 aDLast = aFeaturesToDelete.end();
303 for (; aDIt != aDLast; aDIt++) {
304 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
305 std::cout << std::endl;
308 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
309 #ifdef CIRCLE_FEATURE_DELETE_WITHOUT_REFERENCES
310 std::set<FeaturePtr> aCircleFeatures;
311 aCircleFeatures.insert(aCircleFeatureToDelete);
312 ModelAPI_Tools::removeFeatures(aCircleFeatures, false);
316 std::cout << "update features after split:" << std::endl;
317 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
318 anULast = aFeaturesToUpdate.end();
319 for (; anUIt != anULast; anUIt++) {
320 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
321 std::cout << std::endl;
324 updateFeaturesAfterSplit(aFeaturesToUpdate);
326 // Send events to update the sub-features by the solver.
327 if(isUpdateFlushed) {
328 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
332 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
333 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
334 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
339 bool SketchPlugin_ConstraintSplit::isMacro() const
344 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
346 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
347 data()->attribute(SketchPlugin_Constraint::VALUE()));
348 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
350 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
351 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
352 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
353 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
355 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
356 aFirstPointAttrOfSplit->isInitialized() &&
357 aSecondPointAttrOfSplit->isInitialized()) {
359 ResultPtr aResult = getFeatureResult(aBaseFeature);
360 GeomShapePtr aBaseShape = aResult->shape();
361 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
363 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
364 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
365 aPoints.push_back(aStartPoint);
367 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
368 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
369 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
370 aPoints.push_back(aSecondPoint);
372 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
374 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
375 std::shared_ptr<GeomAPI_Shape> aShape =
376 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
378 AISObjectPtr anAIS = thePrevious;
381 anAIS = AISObjectPtr(new GeomAPI_AISObject);
382 anAIS->createShape(aShape);
384 std::vector<int> aColor;
385 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
386 SKETCH_ENTITY_COLOR);
387 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
391 return AISObjectPtr();
394 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
395 const AttributePtr& theAttribute)
397 AttributePoint2DPtr aPointAttribute;
399 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
400 AttributeRefAttrPtr aRefAttr =
401 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
402 if (aRefAttr.get() && aRefAttr->isInitialized()) {
403 AttributePtr anAttribute = aRefAttr->attr();
404 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
405 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
408 return aPointAttribute;
411 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
412 AttributePoint2DPtr& theStartPointAttr,
413 AttributePoint2DPtr& theEndPointAttr)
415 std::string aFeatureKind = theFeature->getKind();
416 std::string aStartAttributeName, anEndAttributeName;
417 if (aFeatureKind == SketchPlugin_Line::ID()) {
418 aStartAttributeName = SketchPlugin_Line::START_ID();
419 anEndAttributeName = SketchPlugin_Line::END_ID();
421 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
422 aStartAttributeName = SketchPlugin_Arc::START_ID();
423 anEndAttributeName = SketchPlugin_Arc::END_ID();
425 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
426 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
427 theFeature->attribute(aStartAttributeName));
428 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
429 theFeature->attribute(anEndAttributeName));
433 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
434 std::set<FeaturePtr>& theFeaturesToUpdate,
435 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
436 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
438 std::shared_ptr<ModelAPI_Data> aData = data();
440 // Check the base objects are initialized.
441 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
442 aData->attribute(SketchPlugin_Constraint::VALUE()));
443 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
444 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
446 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
447 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
448 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
450 std::set<AttributePtr>::const_iterator aIt;
451 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
452 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
453 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
454 std::string aRefFeatureKind = aRefFeature->getKind();
455 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
456 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
457 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
458 theFeaturesToDelete.insert(aRefFeature);
459 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
460 theFeaturesToUpdate.insert(aRefFeature);
461 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
462 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
463 /// until tangency between arc and line is implemented
464 theFeaturesToDelete.insert(aRefFeature);
466 std::string anAttributeToBeModified;
467 AttributePoint2DPtr aTangentPoint;
468 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
469 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
470 if (aResult1.get() && aResult2.get()) {
471 FeaturePtr aCoincidenceFeature =
472 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
473 (ModelAPI_Feature::feature(aResult1),
474 ModelAPI_Feature::feature(aResult2));
475 // get the point not lying on the splitting feature
476 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
477 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
478 if (!aRefAttr || aRefAttr->isObject())
480 AttributePoint2DPtr aPoint =
481 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
484 if (aPoint->owner() != aBaseFeature) {
485 aTangentPoint = aPoint;
490 if (aTangentPoint.get()) {
491 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
492 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
493 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
494 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
496 else /// there is not coincident point between tangent constraint
497 theFeaturesToDelete.insert(aRefFeature);
500 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
501 std::string anAttributeToBeModified;
502 AttributePoint2DPtr aCoincidentPoint;
503 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
504 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
505 bool isToFeature = false;
506 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
507 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
509 isToFeature = aFeature.get() && aFeature == aBaseFeature;
510 anAttributeToBeModified = anAttrA->id();
512 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
514 isToFeature = aFeature.get() && aFeature == aBaseFeature;
515 anAttributeToBeModified = anAttrB->id();
518 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
520 if (!isToFeature) { /// coincidence to point on base feature
521 AttributePtr anAttribute;
523 if (!anAttrA->isObject()) {
524 AttributePtr aCurAttribute = anAttrA->attr();
525 if (aCurAttribute.get()) {
526 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
527 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
528 anAttribute = anAttrB->attr();
529 anAttributeToBeModified = anAttrA->id();
533 if (!anAttribute.get() && !anAttrB->isObject()) {
534 AttributePtr aCurAttribute = anAttrB->attr();
535 if (aCurAttribute.get()) {
536 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
537 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
538 anAttribute = anAttrA->attr();
539 anAttributeToBeModified = anAttrB->id();
543 if (anAttribute.get())
544 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
546 if (aCoincidentPoint.get() && isToFeature)
547 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
553 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
554 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
555 std::list<AttributePtr>& theRefsToFeature)
559 std::list<AttributePtr> aPointAttributes =
560 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
561 std::set<AttributePtr> aPointAttributesSet;
563 std::list<AttributePtr>::const_iterator aPIt =
564 aPointAttributes.begin(), aPLast = aPointAttributes.end();
565 for (; aPIt != aPLast; aPIt++)
566 aPointAttributesSet.insert(*aPIt);
568 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
569 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
570 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
572 std::set<AttributePtr>::const_iterator aIt;
573 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
574 AttributePtr anAttr = (*aIt);
575 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
576 if (anAttrFeature.get() != this &&
577 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
578 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
579 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
580 AttributePtr anAttrInRef = aRefAttr->attr();
581 if (anAttrInRef.get() &&
582 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
583 if (theRefs.find(anAttrInRef) != theRefs.end())
584 theRefs[anAttrInRef].push_back(aRefAttr);
586 std::list<AttributePtr> anAttrList;
587 anAttrList.push_back(aRefAttr);
588 theRefs[anAttrInRef] = anAttrList;
592 else { /// find attributes referenced to feature itself
593 theRefsToFeature.push_back(anAttr);
599 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
600 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
601 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
602 const std::set<ResultPtr>& theFeatureResults,
603 const FeaturePtr& theSplitFeature)
605 if (theCoincidenceToFeature.empty())
608 // we should build coincidence constraints to end of the split feature
609 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
610 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
611 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
612 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
613 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
614 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
615 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
617 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
618 aCLast = theCoincidenceToFeature.end();
620 std::cout << std::endl;
621 std::cout << "Coincidences to feature(modified):"<< std::endl;
623 for (; aCIt != aCLast; aCIt++) {
624 FeaturePtr aCoincFeature = aCIt->first;
625 std::string anAttributeId = aCIt->second.first;
626 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
627 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
628 aFCLast = theFurtherCoincidences.end();
629 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
630 AttributePoint2DPtr aFeaturePointAttribute;
631 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
632 AttributePoint2DPtr aFCAttribute = *aFCIt;
633 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
634 aFeaturePointAttribute = aFCAttribute;
636 if (aFeaturePointAttribute.get()) {
637 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
638 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
639 // create new coincidences to split feature points
640 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
641 aSFLast = aNewCoincidencesToSplitFeature.end();
642 for (; aSFIt != aSFLast; aSFIt++) {
643 AttributePoint2DPtr aSFAttribute = *aSFIt;
644 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
645 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
646 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
647 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
648 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
649 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
654 /// find feature by shape intersected the point
655 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
657 if (theFeatureResults.size() > 1) { // try to find point on additional feature
658 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
659 GeomShapePtr aShape = anAddtionalResult->shape();
661 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
662 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
664 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
665 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
666 aResultForCoincidence = anAddtionalResult;
668 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
671 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
676 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
677 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
678 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
680 if (theTangentFeatures.empty())
683 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
684 aTLast = theTangentFeatures.end();
686 std::cout << std::endl;
687 std::cout << "Tangencies to feature(modified):"<< std::endl;
689 for (; aTIt != aTLast; aTIt++) {
690 FeaturePtr aTangentFeature = aTIt->first;
691 std::string anAttributeId = aTIt->second.first;
692 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
693 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
694 aFCLast = theFurtherCoincidences.end();
695 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
696 AttributePoint2DPtr aFeaturePointAttribute;
697 /// here we rely on created coincidence between further coincidence point and tangent result
698 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
699 AttributePoint2DPtr aFCAttribute = *aFCIt;
700 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
701 aFeaturePointAttribute = aFCAttribute;
703 if (aFeaturePointAttribute.get()) {
704 FeaturePtr aFeature =
705 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
706 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
709 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
714 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
715 const ResultPtr& theFeatureBaseResult,
716 const std::list<AttributePtr>& theRefsToFeature)
718 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
719 aLast = theRefsToFeature.end();
720 for (; anIt != aLast; anIt++) {
721 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
723 aRefAttr->setObject(theFeatureBaseResult);
727 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
728 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
729 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
732 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
735 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
736 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
737 for (; anIt != aLast; anIt++) {
738 AttributePtr anAttribute = anIt->first;
740 /// not found in references
741 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
743 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
744 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
745 aRLast = aRefAttributes.end();
747 AttributePtr aNewAttribute = anIt->second;
748 for (; aRefIt != aRLast; aRefIt++) {
749 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
750 if (aRefAttr.get()) {
751 aRefAttr->setAttr(aNewAttribute);
753 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
754 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
761 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
762 FeaturePtr& theBaseFeatureModified,
763 FeaturePtr& theAfterFeature,
764 std::set<AttributePoint2DPtr>& thePoints,
765 std::set<FeaturePtr>& theCreatedFeatures,
766 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
768 std::set<FeaturePtr> aCreatedFeatures;
769 FeaturePtr aConstraintFeature;
770 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
772 SketchPlugin_Sketch* aSketch = sketch();
776 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
777 data()->attribute(SketchPlugin_Constraint::VALUE()));
778 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
779 std::string aFeatureKind = aBaseFeature->getKind();
780 if (aFeatureKind != SketchPlugin_Line::ID())
783 AttributePoint2DPtr aFirstPointAttrOfSplit =
784 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
785 AttributePoint2DPtr aSecondPointAttrOfSplit =
786 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
787 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
789 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
790 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
791 setError("Error: Feature has no start and end points.");
795 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
796 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
799 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
800 std::cout << "Start point: " <<
801 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
802 std::cout << "1st point: " <<
803 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
804 std::cout << "2nd point: " <<
805 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
806 std::cout << "End point: " <<
807 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
810 /// create a split feature
812 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
813 theCreatedFeatures.insert(theSplitFeature);
815 // before split feature
816 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
817 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
818 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
821 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
822 /// move end arc point to start of split
825 // after split feature
826 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
828 if (!theBaseFeatureModified.get()) {
829 aFeature = aBaseFeature; ///< use base feature to store all constraints here
830 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
831 aFeature->execute(); // to update result
834 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
835 theCreatedFeatures.insert(aFeature);
836 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
837 aFeature->attribute(SketchPlugin_Line::END_ID())));
839 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
840 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
841 aFeature->attribute(SketchPlugin_Line::START_ID()));
842 theCreatedFeatures.insert(aConstraintFeature);
844 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
845 (aFeature->attribute(SketchPlugin_Line::START_ID())));
846 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
847 (aFeature->attribute(SketchPlugin_Line::END_ID())));
849 if (!theBaseFeatureModified.get())
850 theBaseFeatureModified = aFeature;
852 theAfterFeature = aFeature;
855 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
856 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
857 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
858 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
860 // base split, that is defined before split feature should be changed at end
861 // (after the after feature creation). Otherwise modified value will be used in after feature
862 // before split feature
863 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
864 /// move end arc point to start of split
865 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
866 aFirstPointAttrOfSplit);
867 theBaseFeatureModified->execute(); // to update result
868 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
869 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
870 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
871 theCreatedFeatures.insert(aConstraintFeature);
873 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
874 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
875 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
876 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
879 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
880 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
882 // additional constraints between split and base features
883 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
884 getFeatureResult(aBaseFeature),
885 getFeatureResult(theSplitFeature));
886 theCreatedFeatures.insert(aConstraintFeature);
887 if (theAfterFeature.get()) {
888 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
889 getFeatureResult(aBaseFeature),
890 getFeatureResult(theAfterFeature));
891 theCreatedFeatures.insert(aConstraintFeature);
895 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
896 FeaturePtr& theBaseFeatureModified,
897 FeaturePtr& theAfterFeature,
898 std::set<AttributePoint2DPtr>& thePoints,
899 std::set<FeaturePtr>& theCreatedFeatures,
900 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
902 std::set<FeaturePtr> aCreatedFeatures;
903 FeaturePtr aConstraintFeature;
904 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
906 SketchPlugin_Sketch* aSketch = sketch();
910 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
911 data()->attribute(SketchPlugin_Constraint::VALUE()));
912 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
913 std::string aFeatureKind = aBaseFeature->getKind();
914 if (aFeatureKind != SketchPlugin_Arc::ID())
917 AttributePoint2DPtr aFirstPointAttrOfSplit =
918 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
919 AttributePoint2DPtr aSecondPointAttrOfSplit =
920 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
921 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
922 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
923 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
924 setError("Error: Feature has no start and end points.");
928 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
929 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
930 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
932 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
933 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
935 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
936 std::cout << "Start point: " <<
937 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
938 std::cout << "1st point: " <<
939 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
940 std::cout << "2nd point: " <<
941 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
942 std::cout << "End point: " <<
943 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
947 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
948 theCreatedFeatures.insert(theSplitFeature);
950 // before split feature
951 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
952 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
953 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
956 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
957 /// move end arc point to start of split
960 // after split feature
961 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
963 if (!theBaseFeatureModified.get()) {
964 aFeature = aBaseFeature; ///< use base feature to store all constraints here
965 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
966 aFeature->execute(); // to update result
969 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
970 theCreatedFeatures.insert(aFeature);
971 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
972 aFeature->attribute(SketchPlugin_Arc::END_ID())));
974 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
975 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
976 aFeature->attribute(SketchPlugin_Arc::START_ID()));
977 theCreatedFeatures.insert(aConstraintFeature);
979 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
980 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
981 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
982 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
984 if (!theBaseFeatureModified.get())
985 theBaseFeatureModified = aFeature;
987 theAfterFeature = aFeature;
990 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
991 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
992 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
993 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
995 // base split, that is defined before split feature should be changed at end
996 // (after the after feature creation). Otherwise modified value will be used in after feature
997 // before split feature
998 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
999 /// move end arc point to start of split
1000 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1001 aFirstPointAttrOfSplit);
1002 theBaseFeatureModified->execute(); // to update result
1003 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1004 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1005 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1006 theCreatedFeatures.insert(aConstraintFeature);
1008 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1009 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1010 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1011 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1014 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1015 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1017 // additional constraints between split and base features
1018 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1019 getFeatureResult(aBaseFeature),
1020 getFeatureResult(theSplitFeature));
1021 theCreatedFeatures.insert(aConstraintFeature);
1022 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1023 getFeatureResult(theSplitFeature),
1024 getFeatureResult(aBaseFeature));
1025 theCreatedFeatures.insert(aConstraintFeature);
1026 if (theAfterFeature.get()) {
1027 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1028 getFeatureResult(aBaseFeature),
1029 getFeatureResult(theAfterFeature));
1030 theCreatedFeatures.insert(aConstraintFeature);
1031 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1032 getFeatureResult(theSplitFeature),
1033 getFeatureResult(theAfterFeature));
1034 theCreatedFeatures.insert(aConstraintFeature);
1038 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1039 FeaturePtr& theBaseFeatureModified,
1040 FeaturePtr& theAfterFeature,
1041 std::set<AttributePoint2DPtr>& thePoints,
1042 std::set<FeaturePtr>& theCreatedFeatures,
1043 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1045 std::set<FeaturePtr> aCreatedFeatures;
1046 FeaturePtr aConstraintFeature;
1047 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1049 SketchPlugin_Sketch* aSketch = sketch();
1053 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1054 data()->attribute(SketchPlugin_Constraint::VALUE()));
1055 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1056 std::string aFeatureKind = aBaseFeature->getKind();
1057 if (aFeatureKind != SketchPlugin_Circle::ID())
1060 AttributePoint2DPtr aFirstPointAttrOfSplit =
1061 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1062 AttributePoint2DPtr aSecondPointAttrOfSplit =
1063 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1067 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1068 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1069 theCreatedFeatures.insert(theSplitFeature);
1071 /// base feature is a left part of the circle
1072 theBaseFeatureModified = createArcFeature(aBaseFeature,
1073 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1074 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1075 theBaseFeatureModified)->setReversed(!aSplitReversed);
1076 theBaseFeatureModified->execute();
1078 theModifiedAttributes.insert(
1079 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1080 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1082 theCreatedFeatures.insert(theBaseFeatureModified);
1084 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1085 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1086 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1087 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1089 // additional constraints between split and base features
1090 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1091 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1092 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1093 theCreatedFeatures.insert(aConstraintFeature);
1094 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1095 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1096 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1097 theCreatedFeatures.insert(aConstraintFeature);
1099 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1100 getFeatureResult(theSplitFeature),
1101 getFeatureResult(theBaseFeatureModified));
1102 theCreatedFeatures.insert(aConstraintFeature);
1105 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1106 const AttributePoint2DPtr& theStartPointAttr,
1107 const AttributePoint2DPtr& theEndPointAttr,
1108 AttributePoint2DPtr& theFirstPointAttr,
1109 AttributePoint2DPtr& theLastPointAttr) const
1111 // if first point is closer to last point, swap first and last values
1112 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1113 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1114 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1115 theFirstPointAttr = theLastPointAttr;
1116 theLastPointAttr = aTmpPoint;
1120 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1121 const FeaturePtr& theArc,
1122 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1123 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1124 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1125 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1127 static const double anAngleTol = 1.e-12;
1129 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1130 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1131 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1133 // collect directions to each point
1134 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1135 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1136 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1137 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1138 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1139 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1141 // sort points by their angular values
1142 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1143 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1144 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1145 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1146 aFirstPtAngle += aPeriod;
1147 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1148 aSecondPtAngle += aPeriod;
1150 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1151 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1152 theFirstPointAttr = theSecondPointAttr;
1153 theSecondPointAttr = aTmpPoint;
1157 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1158 const AttributePtr& theSourceAttribute)
1160 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1161 theModifiedAttribute);
1162 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1163 theSourceAttribute);
1165 if (aModifiedAttribute.get() && aSourceAttribute.get())
1166 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1169 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1170 const AttributePtr& theFirstPointAttr,
1171 const AttributePtr& theSecondPointAttr)
1173 FeaturePtr aFeature;
1174 SketchPlugin_Sketch* aSketch = sketch();
1175 if (!aSketch || !theBaseFeature.get())
1178 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1180 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1181 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1182 aFeature->execute(); // to obtain result
1187 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1188 const AttributePtr& theFirstPointAttr,
1189 const AttributePtr& theSecondPointAttr)
1191 FeaturePtr aFeature;
1192 SketchPlugin_Sketch* aSketch = sketch();
1193 if (!aSketch || !theBaseFeature.get())
1196 std::string aCenterAttributeId;
1197 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1198 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1199 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1200 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1202 if (aCenterAttributeId.empty())
1205 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1206 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1207 // the "attribute updated"
1208 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1209 aFeature->data()->blockSendAttributeUpdated(true);
1211 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1212 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1214 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1215 theBaseFeature->attribute(aCenterAttributeId));
1216 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1217 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1219 /// fill referersed state of created arc as it is on the base arc
1220 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1221 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1222 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1224 aFeature->data()->blockSendAttributeUpdated(false);
1225 aFeature->execute(); // to obtain result
1230 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1231 const AttributePtr& theFirstAttribute,
1232 const AttributePtr& theSecondAttribute)
1234 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1235 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1236 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1237 aRefAttr->setAttr(theFirstAttribute);
1239 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1240 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1241 aRefAttr->setAttr(theSecondAttribute);
1246 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1247 const std::string& theConstraintId,
1248 const ObjectPtr& theFirstObject,
1249 const ObjectPtr& theSecondObject)
1251 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1252 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1253 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1254 aRefAttr->setObject(theFirstObject);
1256 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1257 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1258 aRefAttr->setObject(theSecondObject);
1263 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1264 const std::set<FeaturePtr>& theFeaturesToUpdate)
1266 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1267 aLast = theFeaturesToUpdate.end();
1268 for (; anIt != aLast; anIt++) {
1269 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1270 std::string aRefFeatureKind = aRefFeature->getKind();
1271 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1272 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1273 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1274 if (aLenghtFeature.get()) {
1275 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1276 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1278 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1279 aValueAttr->setValue(aValue);
1285 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1286 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1288 std::shared_ptr<ModelAPI_Result> aResult;
1290 std::string aFeatureKind = theFeature->getKind();
1291 if (aFeatureKind == SketchPlugin_Line::ID())
1292 aResult = theFeature->firstResult();
1293 else if (aFeatureKind == SketchPlugin_Arc::ID())
1294 aResult = theFeature->lastResult();
1295 else if (aFeatureKind == SketchPlugin_Circle::ID())
1296 aResult = theFeature->lastResult();
1301 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1302 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1304 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1306 std::string aFeatureKind = theFeature->getKind();
1307 if (aFeatureKind == SketchPlugin_Line::ID()) {
1308 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1309 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1311 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1312 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1313 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1315 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1318 return anAttributes;
1322 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1323 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1324 const bool isUseAttributesInfo)
1327 if (!theFeature.get()) {
1331 if (theFeature->data()->isValid())
1332 anInfo.append(theFeature->data()->name().c_str());
1334 if (isUseAttributesInfo) {
1335 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1336 getEdgeAttributes(theFeature));
1337 /// processing of feature with point 2d attributes, like line, arc, circle
1338 if (!aPointsInfo.empty()) {
1341 anInfo += aPointsInfo;
1343 else { /// process constraint coincidence, find points in ref attr attributes
1344 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1345 ModelAPI_AttributeRefAttr::typeId());
1346 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1347 std::string anAttributesInfo;
1348 for(; anIt != aLast; anIt++) {
1349 if (!anAttributesInfo.empty()) {
1350 anAttributesInfo.append(", ");
1351 anAttributesInfo += "\n";
1353 AttributePtr anAttr = *anIt;
1354 std::string aValue = "not defined";
1355 std::string aType = anAttr->attributeType();
1356 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1357 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1358 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1359 if (aRefAttr.get()) {
1360 if (aRefAttr->isObject()) {
1361 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1362 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1365 AttributePtr anAttribute = aRefAttr->attr();
1366 if (anAttribute.get()) {
1367 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1368 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1369 " [" + getFeatureInfo(aFeature, false) + "]";
1374 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1376 if (!anAttributesInfo.empty())
1377 anInfo = anInfo + "\n" + anAttributesInfo;