1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_ConstraintSplit.cpp
4 // Created: 25 Aug 2016
5 // Author: Natalia ERMOLAEVA
7 #include "SketchPlugin_ConstraintSplit.h"
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <GeomAlgoAPI_ShapeTools.h>
15 #include <ModelAPI_AttributeReference.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_AttributeRefAttr.h>
18 #include <ModelAPI_Tools.h>
19 #include <ModelAPI_AttributeBoolean.h>
21 #include <ModelAPI_Validator.h>
22 #include <ModelAPI_Session.h>
23 #include <ModelAPI_AttributeDouble.h>
25 #include <SketchPlugin_Line.h>
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_ConstraintCoincidence.h>
29 #include <SketchPlugin_ConstraintEqual.h>
30 #include <SketchPlugin_ConstraintParallel.h>
31 #include <SketchPlugin_ConstraintTangent.h>
32 #include <SketchPlugin_ConstraintLength.h>
33 #include <SketchPlugin_ConstraintMirror.h>
34 #include <SketchPlugin_MultiRotation.h>
35 #include <SketchPlugin_MultiTranslation.h>
36 #include <SketchPlugin_ConstraintMiddle.h>
38 #include <ModelAPI_Events.h>
39 #include <SketchPlugin_Line.h>
40 #include <SketchPlugin_Arc.h>
41 #include <SketchPlugin_Circle.h>
43 #include <ModelGeomAlgo_Point2D.h>
44 #include <Events_Loop.h>
53 static const double PI = 3.141592653589793238463;
55 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
59 void SketchPlugin_ConstraintSplit::initAttributes()
61 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
62 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
63 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
66 void SketchPlugin_ConstraintSplit::execute()
68 std::shared_ptr<ModelAPI_Data> aData = data();
70 // Check the base objects are initialized.
71 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
72 aData->attribute(SketchPlugin_Constraint::VALUE()));
73 if(!aBaseObjectAttr->isInitialized()) {
74 setError("Error: Base object is not initialized.");
77 AttributePoint2DPtr aFirstPointAttrOfSplit =
78 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
79 AttributePoint2DPtr aSecondPointAttrOfSplit =
80 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
81 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
82 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
83 setError("Error: Sub-shape is not initialized.");
87 // Wait all constraints being created, then send update events
88 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
89 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
91 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
94 // Find feature constraints
95 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
96 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
97 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
99 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
100 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
101 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
103 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
104 std::list<AttributePtr> aRefsToFeature;
105 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
107 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
110 std::cout << std::endl;
111 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
112 std::cout << std::endl;
114 SketchPlugin_Sketch* aSketch = sketch();
115 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
116 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
117 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
120 std::cout << std::endl;
121 std::cout << "---- IN PARAMETERS ----" << std::endl;
122 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
123 std::cout << std::endl;
125 if (!aCoincidenceToFeature.empty()) {
126 std::cout << "Coincidences to base feature[" <<
127 aCoincidenceToFeature.size() << "]: " << std::endl;
128 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
129 aLast = aCoincidenceToFeature.end();
130 for (int i = 1; anIt != aLast; anIt++, i++) {
131 FeaturePtr aFeature = (*anIt).first;
132 std::string anAttributeId = (*anIt).second.first;
133 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
135 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
136 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
137 std::cout << " -Point attribute:" <<
138 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
142 if (!aTangentFeatures.empty()) {
143 std::cout << std::endl;
144 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
145 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
146 aLast = aTangentFeatures.end();
147 for (int i = 1; anIt != aLast; anIt++, i++) {
148 FeaturePtr aFeature = (*anIt).first;
149 std::string anAttributeId = (*anIt).second.first;
150 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
152 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
153 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
154 std::cout << " -Point attribute:" <<
155 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
159 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
160 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
161 std::cout << std::endl << "References to attributes of base feature [" <<
162 aBaseRefAttributes.size() << "]" << std::endl;
163 for (; aRefIt != aRefLast; aRefIt++) {
164 AttributePtr aBaseAttr = aRefIt->first;
165 std::list<AttributePtr> aRefAttributes = aRefIt->second;
166 std::string aRefsInfo;
167 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
168 aRefAttrLast = aRefAttributes.end();
169 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
170 if (!aRefsInfo.empty())
171 aRefsInfo.append(",");
172 AttributePtr aRAttr = *aRefAttrIt;
173 aRefsInfo.append(aRAttr->id());
174 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
175 aRefsInfo.append("(" + aRFeature->name() + ") ");
177 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
178 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
179 std::cout << aPointAttr->id().c_str() <<
180 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
182 std::cout << std::endl;
183 std::cout << std::endl << "References to base feature [" <<
184 aRefsToFeature.size() << "]" << std::endl;
185 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
186 aRefAttrLast = aRefsToFeature.end();
187 std::string aRefsInfo;
188 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
189 if (!aRefsInfo.empty())
190 aRefsInfo.append(",");
191 AttributePtr aRAttr = *aRefAttrIt;
192 aRefsInfo.append(aRAttr->id());
193 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
194 aRefsInfo.append("(" + aRFeature->name() + ") ");
196 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
199 std::cout << std::endl;
200 std::cout << "---- SPLIT ----" << std::endl;
201 std::cout << std::endl;
204 std::string aFeatureKind = aBaseFeature->getKind();
205 FeaturePtr aSplitFeature, anAfterFeature;
206 std::set<AttributePoint2DPtr> aFurtherCoincidences;
207 std::set<FeaturePtr> aCreatedFeatures;
208 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
209 if (aFeatureKind == SketchPlugin_Line::ID())
210 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
211 aModifiedAttributes);
212 else if (aFeatureKind == SketchPlugin_Arc::ID())
213 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
214 aModifiedAttributes);
215 if (aFeatureKind == SketchPlugin_Circle::ID()) {
216 FeaturePtr aCircleFeature = aBaseFeature;
217 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
218 aCreatedFeatures, aModifiedAttributes);
220 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
222 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
223 aFeaturesToDelete.insert(aCircleFeature);
224 // as circle is removed, temporary fill this attribute*/
225 aBaseObjectAttr->setObject(ResultPtr());
229 std::cout << "---- OUT PARAMETERS ----" << std::endl;
230 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
231 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
232 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
233 std::cout << std::endl;
235 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
236 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
237 aFLast = aCreatedFeatures.end();
238 for (; aFIt != aFLast; aFIt++) {
239 std::cout << getFeatureInfo(*aFIt) << std::endl;
241 std::cout << std::endl;
243 std::cout << "Attributes for further Coincidences:" << std::endl;
244 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
245 aLast = aFurtherCoincidences.end();
246 for (; anIt != aLast; anIt++) {
247 AttributePtr anAttribute = *anIt;
248 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
249 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
250 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
253 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
254 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
255 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
256 std::string aResInfo;
257 for (; aPIt != aPLast; aPIt++) {
258 if (!aResInfo.empty())
261 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
263 AttributePtr anAttr = aPair.first;
264 aResInfo.append(anAttr->id());
265 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
266 aResInfo.append("(" + aFeature->name() + ") ");
268 aResInfo.append(" - is modified to - ");
270 anAttr = aPair.second;
271 aResInfo.append(anAttr->id());
272 aFeature = ModelAPI_Feature::feature(anAttr->owner());
273 aResInfo.append("(" + aFeature->name() + ") ");
275 std::cout << aResInfo << std::endl;
278 std::set<ResultPtr> aFeatureResults;
279 aFeatureResults.insert(getFeatureResult(aBaseFeature));
280 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
281 aFeatureResults.insert(getFeatureResult(anAfterFeature));
283 // coincidence to feature
284 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
285 aFeatureResults, aSplitFeature);
287 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
289 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
291 // delete constraints
293 std::cout << "remove features and references:" << std::endl;
294 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
295 aDLast = aFeaturesToDelete.end();
296 for (; aDIt != aDLast; aDIt++) {
297 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
298 std::cout << std::endl;
301 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
302 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
305 std::cout << "update features after split:" << std::endl;
306 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
307 anULast = aFeaturesToUpdate.end();
308 for (; anUIt != anULast; anUIt++) {
309 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
310 std::cout << std::endl;
313 updateFeaturesAfterSplit(aFeaturesToUpdate);
315 // Send events to update the sub-features by the solver.
316 if(isUpdateFlushed) {
317 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
321 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
322 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
323 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
328 bool SketchPlugin_ConstraintSplit::isMacro() const
333 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
335 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
336 data()->attribute(SketchPlugin_Constraint::VALUE()));
337 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
339 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
340 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
341 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
342 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
344 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
345 aFirstPointAttrOfSplit->isInitialized() &&
346 aSecondPointAttrOfSplit->isInitialized()) {
348 ResultPtr aResult = getFeatureResult(aBaseFeature);
349 GeomShapePtr aBaseShape = aResult->shape();
350 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
352 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
353 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
354 aPoints.push_back(aStartPoint);
356 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
357 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
358 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
359 aPoints.push_back(aSecondPoint);
361 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
363 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
364 std::shared_ptr<GeomAPI_Shape> aShape =
365 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
367 AISObjectPtr anAIS = thePrevious;
370 anAIS = AISObjectPtr(new GeomAPI_AISObject);
371 anAIS->createShape(aShape);
372 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
373 aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
375 bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
377 std::vector<int> aColor;
378 double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
379 int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
380 if (isConstruction) {
381 aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color",
382 SKETCH_AUXILIARY_COLOR);
383 aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
384 aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
387 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
388 SKETCH_ENTITY_COLOR);
390 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
391 anAIS->setWidth(aWidth + 1);
392 anAIS->setLineStyle(aLineStyle);
396 return AISObjectPtr();
399 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
400 const AttributePtr& theAttribute)
402 AttributePoint2DPtr aPointAttribute;
404 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
405 AttributeRefAttrPtr aRefAttr =
406 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
407 if (aRefAttr.get() && aRefAttr->isInitialized()) {
408 AttributePtr anAttribute = aRefAttr->attr();
409 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
410 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
413 return aPointAttribute;
416 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
417 AttributePoint2DPtr& theStartPointAttr,
418 AttributePoint2DPtr& theEndPointAttr)
420 std::string aFeatureKind = theFeature->getKind();
421 std::string aStartAttributeName, anEndAttributeName;
422 if (aFeatureKind == SketchPlugin_Line::ID()) {
423 aStartAttributeName = SketchPlugin_Line::START_ID();
424 anEndAttributeName = SketchPlugin_Line::END_ID();
426 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
427 aStartAttributeName = SketchPlugin_Arc::START_ID();
428 anEndAttributeName = SketchPlugin_Arc::END_ID();
430 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
431 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
432 theFeature->attribute(aStartAttributeName));
433 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
434 theFeature->attribute(anEndAttributeName));
438 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
439 std::set<FeaturePtr>& theFeaturesToUpdate,
440 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
441 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
443 std::shared_ptr<ModelAPI_Data> aData = data();
445 // Check the base objects are initialized.
446 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
447 aData->attribute(SketchPlugin_Constraint::VALUE()));
448 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
449 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
451 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
452 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
453 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
455 std::set<AttributePtr>::const_iterator aIt;
456 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
457 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
458 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
459 std::string aRefFeatureKind = aRefFeature->getKind();
460 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
461 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
462 aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
463 aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
464 theFeaturesToDelete.insert(aRefFeature);
465 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
466 theFeaturesToUpdate.insert(aRefFeature);
467 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
468 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
469 /// until tangency between arc and line is implemented
470 theFeaturesToDelete.insert(aRefFeature);
472 std::string anAttributeToBeModified;
473 AttributePoint2DPtr aTangentPoint;
474 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
475 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
476 if (aResult1.get() && aResult2.get()) {
477 FeaturePtr aCoincidenceFeature =
478 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
479 (ModelAPI_Feature::feature(aResult1),
480 ModelAPI_Feature::feature(aResult2));
481 // get the point not lying on the splitting feature
482 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
483 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
484 if (!aRefAttr || aRefAttr->isObject())
486 AttributePoint2DPtr aPoint =
487 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
490 if (aPoint->owner() != aBaseFeature) {
491 aTangentPoint = aPoint;
496 if (aTangentPoint.get()) {
497 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
498 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
499 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
500 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
502 else /// there is not coincident point between tangent constraint
503 theFeaturesToDelete.insert(aRefFeature);
506 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
507 std::string anAttributeToBeModified;
508 AttributePoint2DPtr aCoincidentPoint;
509 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
510 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
511 bool isToFeature = false;
512 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
513 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
515 isToFeature = aFeature.get() && aFeature == aBaseFeature;
516 anAttributeToBeModified = anAttrA->id();
518 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
520 isToFeature = aFeature.get() && aFeature == aBaseFeature;
521 anAttributeToBeModified = anAttrB->id();
524 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
526 if (!isToFeature) { /// coincidence to point on base feature
527 AttributePtr anAttribute;
529 if (!anAttrA->isObject()) {
530 AttributePtr aCurAttribute = anAttrA->attr();
531 if (aCurAttribute.get()) {
532 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
533 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
534 anAttribute = anAttrB->attr();
535 anAttributeToBeModified = anAttrA->id();
539 if (!anAttribute.get() && !anAttrB->isObject()) {
540 AttributePtr aCurAttribute = anAttrB->attr();
541 if (aCurAttribute.get()) {
542 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
543 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
544 anAttribute = anAttrA->attr();
545 anAttributeToBeModified = anAttrB->id();
549 if (anAttribute.get())
550 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
552 if (aCoincidentPoint.get() && isToFeature)
553 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
559 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
560 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
561 std::list<AttributePtr>& theRefsToFeature)
565 std::list<AttributePtr> aPointAttributes =
566 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
567 std::set<AttributePtr> aPointAttributesSet;
569 std::list<AttributePtr>::const_iterator aPIt =
570 aPointAttributes.begin(), aPLast = aPointAttributes.end();
571 for (; aPIt != aPLast; aPIt++)
572 aPointAttributesSet.insert(*aPIt);
574 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
575 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
576 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
578 std::set<AttributePtr>::const_iterator aIt;
579 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
580 AttributePtr anAttr = (*aIt);
581 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
582 if (anAttrFeature.get() != this &&
583 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
584 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
585 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
586 AttributePtr anAttrInRef = aRefAttr->attr();
587 if (anAttrInRef.get() &&
588 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
589 if (theRefs.find(anAttrInRef) != theRefs.end())
590 theRefs[anAttrInRef].push_back(aRefAttr);
592 std::list<AttributePtr> anAttrList;
593 anAttrList.push_back(aRefAttr);
594 theRefs[anAttrInRef] = anAttrList;
598 else { /// find attributes referenced to feature itself
599 theRefsToFeature.push_back(anAttr);
605 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
606 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
607 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
608 const std::set<ResultPtr>& theFeatureResults,
609 const FeaturePtr& theSplitFeature)
611 if (theCoincidenceToFeature.empty())
614 // we should build coincidence constraints to end of the split feature
615 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
616 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
617 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
618 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
619 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
620 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
621 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
623 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
624 aCLast = theCoincidenceToFeature.end();
626 std::cout << std::endl;
627 std::cout << "Coincidences to feature(modified):"<< std::endl;
629 for (; aCIt != aCLast; aCIt++) {
630 FeaturePtr aCoincFeature = aCIt->first;
631 std::string anAttributeId = aCIt->second.first;
632 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
633 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
634 aFCLast = theFurtherCoincidences.end();
635 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
636 AttributePoint2DPtr aFeaturePointAttribute;
637 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
638 AttributePoint2DPtr aFCAttribute = *aFCIt;
639 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
640 aFeaturePointAttribute = aFCAttribute;
642 if (aFeaturePointAttribute.get()) {
643 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
644 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
645 // create new coincidences to split feature points
646 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
647 aSFLast = aNewCoincidencesToSplitFeature.end();
648 for (; aSFIt != aSFLast; aSFIt++) {
649 AttributePoint2DPtr aSFAttribute = *aSFIt;
650 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
651 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
652 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
653 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
654 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
655 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
660 /// find feature by shape intersected the point
661 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
663 if (theFeatureResults.size() > 1) { // try to find point on additional feature
664 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
665 GeomShapePtr aShape = anAddtionalResult->shape();
667 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
668 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
670 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
671 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
672 aResultForCoincidence = anAddtionalResult;
674 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
677 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
682 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
683 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
684 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
686 if (theTangentFeatures.empty())
689 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
690 aTLast = theTangentFeatures.end();
692 std::cout << std::endl;
693 std::cout << "Tangencies to feature(modified):"<< std::endl;
695 for (; aTIt != aTLast; aTIt++) {
696 FeaturePtr aTangentFeature = aTIt->first;
697 std::string anAttributeId = aTIt->second.first;
698 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
699 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
700 aFCLast = theFurtherCoincidences.end();
701 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
702 AttributePoint2DPtr aFeaturePointAttribute;
703 /// here we rely on created coincidence between further coincidence point and tangent result
704 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
705 AttributePoint2DPtr aFCAttribute = *aFCIt;
706 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
707 aFeaturePointAttribute = aFCAttribute;
709 if (aFeaturePointAttribute.get()) {
710 FeaturePtr aFeature =
711 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
712 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
715 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
720 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
721 const ResultPtr& theFeatureBaseResult,
722 const std::list<AttributePtr>& theRefsToFeature)
724 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
725 aLast = theRefsToFeature.end();
726 for (; anIt != aLast; anIt++) {
727 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
729 aRefAttr->setObject(theFeatureBaseResult);
733 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
734 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
735 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
738 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
741 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
742 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
743 for (; anIt != aLast; anIt++) {
744 AttributePtr anAttribute = anIt->first;
746 /// not found in references
747 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
749 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
750 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
751 aRLast = aRefAttributes.end();
753 AttributePtr aNewAttribute = anIt->second;
754 for (; aRefIt != aRLast; aRefIt++) {
755 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
756 if (aRefAttr.get()) {
757 aRefAttr->setAttr(aNewAttribute);
759 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
760 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
767 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
768 FeaturePtr& theBaseFeatureModified,
769 FeaturePtr& theAfterFeature,
770 std::set<AttributePoint2DPtr>& thePoints,
771 std::set<FeaturePtr>& theCreatedFeatures,
772 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
774 std::set<FeaturePtr> aCreatedFeatures;
775 FeaturePtr aConstraintFeature;
776 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
778 SketchPlugin_Sketch* aSketch = sketch();
782 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
783 data()->attribute(SketchPlugin_Constraint::VALUE()));
784 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
785 std::string aFeatureKind = aBaseFeature->getKind();
786 if (aFeatureKind != SketchPlugin_Line::ID())
789 AttributePoint2DPtr aFirstPointAttrOfSplit =
790 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
791 AttributePoint2DPtr aSecondPointAttrOfSplit =
792 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
793 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
795 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
796 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
797 setError("Error: Feature has no start and end points.");
801 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
802 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
805 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
806 std::cout << "Start point: " <<
807 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
808 std::cout << "1st point: " <<
809 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
810 std::cout << "2nd point: " <<
811 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
812 std::cout << "End point: " <<
813 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
816 /// create a split feature
818 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
819 theCreatedFeatures.insert(theSplitFeature);
821 // before split feature
822 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
823 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
824 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
827 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
828 /// move end arc point to start of split
831 // after split feature
832 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
834 if (!theBaseFeatureModified.get()) {
835 aFeature = aBaseFeature; ///< use base feature to store all constraints here
836 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
837 aFeature->execute(); // to update result
840 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
841 theCreatedFeatures.insert(aFeature);
842 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
843 aFeature->attribute(SketchPlugin_Line::END_ID())));
845 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
846 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
847 aFeature->attribute(SketchPlugin_Line::START_ID()));
848 theCreatedFeatures.insert(aConstraintFeature);
850 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
851 (aFeature->attribute(SketchPlugin_Line::START_ID())));
852 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
853 (aFeature->attribute(SketchPlugin_Line::END_ID())));
855 if (!theBaseFeatureModified.get())
856 theBaseFeatureModified = aFeature;
858 theAfterFeature = aFeature;
861 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
862 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
863 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
864 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
866 // base split, that is defined before split feature should be changed at end
867 // (after the after feature creation). Otherwise modified value will be used in after feature
868 // before split feature
869 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
870 /// move end arc point to start of split
871 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
872 aFirstPointAttrOfSplit);
873 theBaseFeatureModified->execute(); // to update result
874 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
875 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
876 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
877 theCreatedFeatures.insert(aConstraintFeature);
879 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
880 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
881 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
882 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
885 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
886 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
888 // additional constraints between split and base features
889 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
890 getFeatureResult(aBaseFeature),
891 getFeatureResult(theSplitFeature));
892 theCreatedFeatures.insert(aConstraintFeature);
893 if (theAfterFeature.get()) {
894 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
895 getFeatureResult(aBaseFeature),
896 getFeatureResult(theAfterFeature));
897 theCreatedFeatures.insert(aConstraintFeature);
901 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
902 FeaturePtr& theBaseFeatureModified,
903 FeaturePtr& theAfterFeature,
904 std::set<AttributePoint2DPtr>& thePoints,
905 std::set<FeaturePtr>& theCreatedFeatures,
906 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
908 std::set<FeaturePtr> aCreatedFeatures;
909 FeaturePtr aConstraintFeature;
910 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
912 SketchPlugin_Sketch* aSketch = sketch();
916 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
917 data()->attribute(SketchPlugin_Constraint::VALUE()));
918 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
919 std::string aFeatureKind = aBaseFeature->getKind();
920 if (aFeatureKind != SketchPlugin_Arc::ID())
923 AttributePoint2DPtr aFirstPointAttrOfSplit =
924 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
925 AttributePoint2DPtr aSecondPointAttrOfSplit =
926 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
927 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
928 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
929 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
930 setError("Error: Feature has no start and end points.");
934 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
935 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
936 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
938 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
939 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
941 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
942 std::cout << "Start point: " <<
943 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
944 std::cout << "1st point: " <<
945 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
946 std::cout << "2nd point: " <<
947 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
948 std::cout << "End point: " <<
949 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
953 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
954 theCreatedFeatures.insert(theSplitFeature);
956 // before split feature
957 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
958 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
959 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
962 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
963 /// move end arc point to start of split
966 // after split feature
967 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
969 if (!theBaseFeatureModified.get()) {
970 aFeature = aBaseFeature; ///< use base feature to store all constraints here
971 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
972 aFeature->execute(); // to update result
975 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
976 theCreatedFeatures.insert(aFeature);
977 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
978 aFeature->attribute(SketchPlugin_Arc::END_ID())));
980 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
981 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
982 aFeature->attribute(SketchPlugin_Arc::START_ID()));
983 theCreatedFeatures.insert(aConstraintFeature);
985 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
986 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
987 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
988 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
990 if (!theBaseFeatureModified.get())
991 theBaseFeatureModified = aFeature;
993 theAfterFeature = aFeature;
996 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
997 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
998 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
999 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1001 // base split, that is defined before split feature should be changed at end
1002 // (after the after feature creation). Otherwise modified value will be used in after feature
1003 // before split feature
1004 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1005 /// move end arc point to start of split
1006 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1007 aFirstPointAttrOfSplit);
1008 theBaseFeatureModified->execute(); // to update result
1009 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1010 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1011 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1012 theCreatedFeatures.insert(aConstraintFeature);
1014 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1015 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1016 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1017 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1020 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1021 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1023 // additional constraints between split and base features
1024 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1025 getFeatureResult(aBaseFeature),
1026 getFeatureResult(theSplitFeature));
1027 theCreatedFeatures.insert(aConstraintFeature);
1028 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1029 getFeatureResult(theSplitFeature),
1030 getFeatureResult(aBaseFeature));
1031 theCreatedFeatures.insert(aConstraintFeature);
1032 if (theAfterFeature.get()) {
1033 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1034 getFeatureResult(aBaseFeature),
1035 getFeatureResult(theAfterFeature));
1036 theCreatedFeatures.insert(aConstraintFeature);
1037 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1038 getFeatureResult(theSplitFeature),
1039 getFeatureResult(theAfterFeature));
1040 theCreatedFeatures.insert(aConstraintFeature);
1044 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1045 FeaturePtr& theBaseFeatureModified,
1046 FeaturePtr& theAfterFeature,
1047 std::set<AttributePoint2DPtr>& thePoints,
1048 std::set<FeaturePtr>& theCreatedFeatures,
1049 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1051 std::set<FeaturePtr> aCreatedFeatures;
1052 FeaturePtr aConstraintFeature;
1053 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1055 SketchPlugin_Sketch* aSketch = sketch();
1059 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1060 data()->attribute(SketchPlugin_Constraint::VALUE()));
1061 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1062 std::string aFeatureKind = aBaseFeature->getKind();
1063 if (aFeatureKind != SketchPlugin_Circle::ID())
1066 AttributePoint2DPtr aFirstPointAttrOfSplit =
1067 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1068 AttributePoint2DPtr aSecondPointAttrOfSplit =
1069 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1073 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1074 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1075 theCreatedFeatures.insert(theSplitFeature);
1077 /// base feature is a left part of the circle
1078 theBaseFeatureModified = createArcFeature(aBaseFeature,
1079 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1080 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1081 theBaseFeatureModified)->setReversed(!aSplitReversed);
1082 theBaseFeatureModified->execute();
1084 theModifiedAttributes.insert(
1085 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1086 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1088 theCreatedFeatures.insert(theBaseFeatureModified);
1090 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1091 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1092 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1093 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1095 // additional constraints between split and base features
1096 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1097 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1098 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1099 theCreatedFeatures.insert(aConstraintFeature);
1100 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1101 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1102 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1103 theCreatedFeatures.insert(aConstraintFeature);
1105 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1106 getFeatureResult(theSplitFeature),
1107 getFeatureResult(theBaseFeatureModified));
1108 theCreatedFeatures.insert(aConstraintFeature);
1111 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1112 const AttributePoint2DPtr& theStartPointAttr,
1113 const AttributePoint2DPtr& theEndPointAttr,
1114 AttributePoint2DPtr& theFirstPointAttr,
1115 AttributePoint2DPtr& theLastPointAttr) const
1117 // if first point is closer to last point, swap first and last values
1118 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1119 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1120 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1121 theFirstPointAttr = theLastPointAttr;
1122 theLastPointAttr = aTmpPoint;
1126 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1127 const FeaturePtr& theArc,
1128 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1129 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1130 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1131 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1133 static const double anAngleTol = 1.e-12;
1135 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1136 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1137 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1139 // collect directions to each point
1140 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1141 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1142 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1143 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1144 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1145 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1147 // sort points by their angular values
1148 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1149 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1150 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1151 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1152 aFirstPtAngle += aPeriod;
1153 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1154 aSecondPtAngle += aPeriod;
1156 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1157 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1158 theFirstPointAttr = theSecondPointAttr;
1159 theSecondPointAttr = aTmpPoint;
1163 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1164 const AttributePtr& theSourceAttribute)
1166 std::string anAttributeType = theModifiedAttribute->attributeType();
1167 if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1168 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1169 theModifiedAttribute);
1170 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1171 theSourceAttribute);
1173 if (aModifiedAttribute.get() && aSourceAttribute.get())
1174 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1176 else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1177 AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1178 theModifiedAttribute);
1179 AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1180 theSourceAttribute);
1182 if (aModifiedAttribute.get() && aSourceAttribute.get())
1183 aModifiedAttribute->setValue(aSourceAttribute->value());
1187 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(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 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1198 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1199 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1201 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1202 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1204 aFeature->execute(); // to obtain result
1209 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1210 const AttributePtr& theFirstPointAttr,
1211 const AttributePtr& theSecondPointAttr)
1213 FeaturePtr aFeature;
1214 SketchPlugin_Sketch* aSketch = sketch();
1215 if (!aSketch || !theBaseFeature.get())
1218 std::string aCenterAttributeId;
1219 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1220 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1221 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1222 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1224 if (aCenterAttributeId.empty())
1227 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1228 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1229 // the "attribute updated"
1230 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1231 aFeature->data()->blockSendAttributeUpdated(true);
1233 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1234 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1236 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1237 theBaseFeature->attribute(aCenterAttributeId));
1238 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1239 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1241 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1242 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1244 /// fill referersed state of created arc as it is on the base arc
1245 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1246 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1247 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1249 aFeature->data()->blockSendAttributeUpdated(false);
1250 aFeature->execute(); // to obtain result
1255 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1256 const AttributePtr& theFirstAttribute,
1257 const AttributePtr& theSecondAttribute)
1259 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1260 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1261 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1262 aRefAttr->setAttr(theFirstAttribute);
1264 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1265 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1266 aRefAttr->setAttr(theSecondAttribute);
1271 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1272 const std::string& theConstraintId,
1273 const ObjectPtr& theFirstObject,
1274 const ObjectPtr& theSecondObject)
1276 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1277 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1278 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1279 aRefAttr->setObject(theFirstObject);
1281 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1282 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1283 aRefAttr->setObject(theSecondObject);
1288 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1289 const std::set<FeaturePtr>& theFeaturesToUpdate)
1291 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1292 aLast = theFeaturesToUpdate.end();
1293 for (; anIt != aLast; anIt++) {
1294 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1295 std::string aRefFeatureKind = aRefFeature->getKind();
1296 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1297 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1298 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1299 if (aLenghtFeature.get()) {
1300 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1301 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1303 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1304 aValueAttr->setValue(aValue);
1310 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1311 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1313 std::shared_ptr<ModelAPI_Result> aResult;
1315 std::string aFeatureKind = theFeature->getKind();
1316 if (aFeatureKind == SketchPlugin_Line::ID())
1317 aResult = theFeature->firstResult();
1318 else if (aFeatureKind == SketchPlugin_Arc::ID())
1319 aResult = theFeature->lastResult();
1320 else if (aFeatureKind == SketchPlugin_Circle::ID())
1321 aResult = theFeature->lastResult();
1326 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1327 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1329 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1331 std::string aFeatureKind = theFeature->getKind();
1332 if (aFeatureKind == SketchPlugin_Line::ID()) {
1333 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1334 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1336 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1337 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1338 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1340 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1343 return anAttributes;
1347 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1348 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1349 const bool isUseAttributesInfo)
1352 if (!theFeature.get()) {
1356 if (theFeature->data()->isValid())
1357 anInfo.append(theFeature->data()->name().c_str());
1359 if (isUseAttributesInfo) {
1360 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1361 getEdgeAttributes(theFeature));
1362 /// processing of feature with point 2d attributes, like line, arc, circle
1363 if (!aPointsInfo.empty()) {
1366 anInfo += aPointsInfo;
1368 else { /// process constraint coincidence, find points in ref attr attributes
1369 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1370 ModelAPI_AttributeRefAttr::typeId());
1371 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1372 std::string anAttributesInfo;
1373 for(; anIt != aLast; anIt++) {
1374 if (!anAttributesInfo.empty()) {
1375 anAttributesInfo.append(", ");
1376 anAttributesInfo += "\n";
1378 AttributePtr anAttr = *anIt;
1379 std::string aValue = "not defined";
1380 std::string aType = anAttr->attributeType();
1381 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1382 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1383 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1384 if (aRefAttr.get()) {
1385 if (aRefAttr->isObject()) {
1386 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1387 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1390 AttributePtr anAttribute = aRefAttr->attr();
1391 if (anAttribute.get()) {
1392 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1393 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1394 " [" + getFeatureInfo(aFeature, false) + "]";
1399 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1401 if (!anAttributesInfo.empty())
1402 anInfo = anInfo + "\n" + anAttributesInfo;