1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_ConstraintSplit.cpp
4 // Created: 25 Aug 2016
5 // Author: Natalia ERMOLAEVA
7 #include "SketchPlugin_ConstraintSplit.h"
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <GeomAlgoAPI_ShapeTools.h>
15 #include <ModelAPI_AttributeReference.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_AttributeRefAttr.h>
18 #include <ModelAPI_Tools.h>
20 #include <ModelAPI_Validator.h>
21 #include <ModelAPI_Session.h>
22 #include <ModelAPI_AttributeDouble.h>
24 #include <SketchPlugin_Line.h>
25 #include <SketchPlugin_Arc.h>
26 #include <SketchPlugin_Circle.h>
27 #include <SketchPlugin_ConstraintCoincidence.h>
28 #include <SketchPlugin_ConstraintEqual.h>
29 #include <SketchPlugin_ConstraintParallel.h>
30 #include <SketchPlugin_ConstraintTangent.h>
31 #include <SketchPlugin_ConstraintLength.h>
32 #include <SketchPlugin_ConstraintMirror.h>
33 #include <SketchPlugin_MultiRotation.h>
34 #include <SketchPlugin_MultiTranslation.h>
36 #include <ModelAPI_Events.h>
37 #include <SketchPlugin_Line.h>
38 #include <SketchPlugin_Arc.h>
39 #include <SketchPlugin_Circle.h>
41 #include <ModelGeomAlgo_Point2D.h>
42 #include <Events_Loop.h>
51 static const double PI = 3.141592653589793238463;
53 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
57 void SketchPlugin_ConstraintSplit::initAttributes()
59 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
60 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
61 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
64 void SketchPlugin_ConstraintSplit::execute()
66 std::shared_ptr<ModelAPI_Data> aData = data();
68 // Check the base objects are initialized.
69 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
70 aData->attribute(SketchPlugin_Constraint::VALUE()));
71 if(!aBaseObjectAttr->isInitialized()) {
72 setError("Error: Base object is not initialized.");
75 AttributePoint2DPtr aFirstPointAttrOfSplit =
76 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
77 AttributePoint2DPtr aSecondPointAttrOfSplit =
78 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
79 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
80 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
81 setError("Error: Sub-shape is not initialized.");
85 // Wait all constraints being created, then send update events
86 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
87 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
89 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
92 // Find feature constraints
93 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
94 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
95 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
96 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
97 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
98 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
100 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
101 std::list<AttributePtr> aRefsToFeature;
102 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
104 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
107 std::cout << std::endl;
108 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
109 std::cout << std::endl;
111 SketchPlugin_Sketch* aSketch = sketch();
112 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
113 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
114 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
117 std::cout << std::endl;
118 std::cout << "---- IN PARAMETERS ----" << std::endl;
119 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
120 std::cout << std::endl;
122 if (!aCoincidenceToFeature.empty()) {
123 std::cout << "Coincidences to base feature[" <<
124 aCoincidenceToFeature.size() << "]: " << std::endl;
125 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
126 aLast = aCoincidenceToFeature.end();
127 for (int i = 1; anIt != aLast; anIt++, i++) {
128 FeaturePtr aFeature = (*anIt).first;
129 std::string anAttributeId = (*anIt).second.first;
130 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
132 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
133 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
134 std::cout << " -Point attribute:" <<
135 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
139 if (!aTangentFeatures.empty()) {
140 std::cout << std::endl;
141 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
142 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
143 aLast = aTangentFeatures.end();
144 for (int i = 1; anIt != aLast; anIt++, i++) {
145 FeaturePtr aFeature = (*anIt).first;
146 std::string anAttributeId = (*anIt).second.first;
147 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
149 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
150 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
151 std::cout << " -Point attribute:" <<
152 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
156 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
157 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
158 std::cout << std::endl << "References to attributes of base feature [" <<
159 aBaseRefAttributes.size() << "]" << std::endl;
160 for (; aRefIt != aRefLast; aRefIt++) {
161 AttributePtr aBaseAttr = aRefIt->first;
162 std::list<AttributePtr> aRefAttributes = aRefIt->second;
163 std::string aRefsInfo;
164 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
165 aRefAttrLast = aRefAttributes.end();
166 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
167 if (!aRefsInfo.empty())
168 aRefsInfo.append(",");
169 AttributePtr aRAttr = *aRefAttrIt;
170 aRefsInfo.append(aRAttr->id());
171 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
172 aRefsInfo.append("(" + aRFeature->name() + ") ");
174 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
175 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
176 std::cout << aPointAttr->id().c_str() <<
177 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
179 std::cout << std::endl;
180 std::cout << std::endl << "References to base feature [" <<
181 aRefsToFeature.size() << "]" << std::endl;
182 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
183 aRefAttrLast = aRefsToFeature.end();
184 std::string aRefsInfo;
185 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
186 if (!aRefsInfo.empty())
187 aRefsInfo.append(",");
188 AttributePtr aRAttr = *aRefAttrIt;
189 aRefsInfo.append(aRAttr->id());
190 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
191 aRefsInfo.append("(" + aRFeature->name() + ") ");
193 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
196 std::cout << std::endl;
197 std::cout << "---- SPLIT ----" << std::endl;
198 std::cout << std::endl;
201 std::string aFeatureKind = aBaseFeature->getKind();
202 FeaturePtr aSplitFeature, anAfterFeature;
203 std::set<AttributePoint2DPtr> aFurtherCoincidences;
204 std::set<FeaturePtr> aCreatedFeatures;
205 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
206 if (aFeatureKind == SketchPlugin_Line::ID())
207 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
208 aModifiedAttributes);
209 else if (aFeatureKind == SketchPlugin_Arc::ID())
210 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
211 aModifiedAttributes);
212 if (aFeatureKind == SketchPlugin_Circle::ID()) {
213 FeaturePtr aCircleFeature = aBaseFeature;
214 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
215 aCreatedFeatures, aModifiedAttributes);
217 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
219 aFeaturesToDelete.insert(aCircleFeature);
220 // as circle is removed, temporary fill this attribute*/
221 aBaseObjectAttr->setObject(ResultPtr());
225 std::cout << "---- OUT PARAMETERS ----" << std::endl;
226 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
227 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
228 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
229 std::cout << std::endl;
231 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
232 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
233 aFLast = aCreatedFeatures.end();
234 for (; aFIt != aFLast; aFIt++) {
235 std::cout << getFeatureInfo(*aFIt) << std::endl;
237 std::cout << std::endl;
239 std::cout << "Attributes for further Coincidences:" << std::endl;
240 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
241 aLast = aFurtherCoincidences.end();
242 for (; anIt != aLast; anIt++) {
243 AttributePtr anAttribute = *anIt;
244 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
245 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
246 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
249 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
250 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
251 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
252 std::string aResInfo;
253 for (; aPIt != aPLast; aPIt++) {
254 if (!aResInfo.empty())
257 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
259 AttributePtr anAttr = aPair.first;
260 aResInfo.append(anAttr->id());
261 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
262 aResInfo.append("(" + aFeature->name() + ") ");
264 aResInfo.append(" - is modified to - ");
266 anAttr = aPair.second;
267 aResInfo.append(anAttr->id());
268 aFeature = ModelAPI_Feature::feature(anAttr->owner());
269 aResInfo.append("(" + aFeature->name() + ") ");
271 std::cout << aResInfo << std::endl;
274 std::set<ResultPtr> aFeatureResults;
275 aFeatureResults.insert(getFeatureResult(aBaseFeature));
276 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
277 aFeatureResults.insert(getFeatureResult(anAfterFeature));
279 // coincidence to feature
280 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
281 aFeatureResults, aSplitFeature);
283 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
285 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
287 // delete constraints
289 std::cout << "remove features and references:" << std::endl;
290 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
291 aDLast = aFeaturesToDelete.end();
292 for (; aDIt != aDLast; aDIt++) {
293 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
294 std::cout << std::endl;
297 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
300 std::cout << "update features after split:" << std::endl;
301 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
302 anULast = aFeaturesToUpdate.end();
303 for (; anUIt != anULast; anUIt++) {
304 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
305 std::cout << std::endl;
308 updateFeaturesAfterSplit(aFeaturesToUpdate);
310 // Send events to update the sub-features by the solver.
311 if(isUpdateFlushed) {
312 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
316 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
317 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
318 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
323 bool SketchPlugin_ConstraintSplit::isMacro() const
328 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
330 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
331 data()->attribute(SketchPlugin_Constraint::VALUE()));
332 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
334 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
335 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
336 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
337 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
339 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
340 aFirstPointAttrOfSplit->isInitialized() &&
341 aSecondPointAttrOfSplit->isInitialized()) {
343 ResultPtr aResult = getFeatureResult(aBaseFeature);
344 GeomShapePtr aBaseShape = aResult->shape();
345 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
347 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
348 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
349 aPoints.push_back(aStartPoint);
351 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
352 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
353 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
354 aPoints.push_back(aSecondPoint);
356 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
358 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
359 std::shared_ptr<GeomAPI_Shape> aShape =
360 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
362 AISObjectPtr anAIS = thePrevious;
365 anAIS = AISObjectPtr(new GeomAPI_AISObject);
366 anAIS->createShape(aShape);
368 std::vector<int> aColor;
369 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
370 SKETCH_ENTITY_COLOR);
371 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
375 return AISObjectPtr();
378 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
379 const AttributePtr& theAttribute)
381 AttributePoint2DPtr aPointAttribute;
383 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
384 AttributeRefAttrPtr aRefAttr =
385 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
386 if (aRefAttr.get() && aRefAttr->isInitialized()) {
387 AttributePtr anAttribute = aRefAttr->attr();
388 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
389 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
392 return aPointAttribute;
395 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
396 AttributePoint2DPtr& theStartPointAttr,
397 AttributePoint2DPtr& theEndPointAttr)
399 std::string aFeatureKind = theFeature->getKind();
400 std::string aStartAttributeName, anEndAttributeName;
401 if (aFeatureKind == SketchPlugin_Line::ID()) {
402 aStartAttributeName = SketchPlugin_Line::START_ID();
403 anEndAttributeName = SketchPlugin_Line::END_ID();
405 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
406 aStartAttributeName = SketchPlugin_Arc::START_ID();
407 anEndAttributeName = SketchPlugin_Arc::END_ID();
409 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
410 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
411 theFeature->attribute(aStartAttributeName));
412 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
413 theFeature->attribute(anEndAttributeName));
417 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
418 std::set<FeaturePtr>& theFeaturesToUpdate,
419 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
420 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
422 std::shared_ptr<ModelAPI_Data> aData = data();
424 // Check the base objects are initialized.
425 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
426 aData->attribute(SketchPlugin_Constraint::VALUE()));
427 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
428 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
430 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
431 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
432 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
434 std::set<AttributePtr>::const_iterator aIt;
435 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
436 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
437 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
438 std::string aRefFeatureKind = aRefFeature->getKind();
439 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
440 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
441 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
442 theFeaturesToDelete.insert(aRefFeature);
443 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
444 theFeaturesToUpdate.insert(aRefFeature);
445 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
446 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
447 /// until tangency between arc and line is implemented
448 theFeaturesToDelete.insert(aRefFeature);
450 std::string anAttributeToBeModified;
451 AttributePoint2DPtr aTangentPoint;
452 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
453 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
454 if (aResult1.get() && aResult2.get()) {
455 FeaturePtr aCoincidenceFeature =
456 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
457 (ModelAPI_Feature::feature(aResult1),
458 ModelAPI_Feature::feature(aResult2));
459 // get the point not lying on the splitting feature
460 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
461 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
462 if (!aRefAttr || aRefAttr->isObject())
464 AttributePoint2DPtr aPoint =
465 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
468 if (aPoint->owner() != aBaseFeature) {
469 aTangentPoint = aPoint;
474 if (aTangentPoint.get()) {
475 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
476 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
477 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
478 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
480 else /// there is not coincident point between tangent constraint
481 theFeaturesToDelete.insert(aRefFeature);
484 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
485 std::string anAttributeToBeModified;
486 AttributePoint2DPtr aCoincidentPoint;
487 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
488 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
489 bool isToFeature = false;
490 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
491 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
493 isToFeature = aFeature.get() && aFeature == aBaseFeature;
494 anAttributeToBeModified = anAttrA->id();
496 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
498 isToFeature = aFeature.get() && aFeature == aBaseFeature;
499 anAttributeToBeModified = anAttrB->id();
502 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
504 if (!isToFeature) { /// coincidence to point on base feature
505 AttributePtr anAttribute;
507 if (!anAttrA->isObject()) {
508 AttributePtr aCurAttribute = anAttrA->attr();
509 if (aCurAttribute.get()) {
510 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
511 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
512 anAttribute = anAttrB->attr();
513 anAttributeToBeModified = anAttrA->id();
517 if (!anAttribute.get() && !anAttrB->isObject()) {
518 AttributePtr aCurAttribute = anAttrB->attr();
519 if (aCurAttribute.get()) {
520 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
521 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
522 anAttribute = anAttrA->attr();
523 anAttributeToBeModified = anAttrB->id();
527 if (anAttribute.get())
528 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
530 if (aCoincidentPoint.get() && isToFeature)
531 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
537 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
538 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
539 std::list<AttributePtr>& theRefsToFeature)
543 std::list<AttributePtr> aPointAttributes =
544 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
545 std::set<AttributePtr> aPointAttributesSet;
547 std::list<AttributePtr>::const_iterator aPIt =
548 aPointAttributes.begin(), aPLast = aPointAttributes.end();
549 for (; aPIt != aPLast; aPIt++)
550 aPointAttributesSet.insert(*aPIt);
552 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
553 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
554 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
556 std::set<AttributePtr>::const_iterator aIt;
557 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
558 AttributePtr anAttr = (*aIt);
559 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
560 if (anAttrFeature.get() != this &&
561 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
562 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
563 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
564 AttributePtr anAttrInRef = aRefAttr->attr();
565 if (anAttrInRef.get() &&
566 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
567 if (theRefs.find(anAttrInRef) != theRefs.end())
568 theRefs[anAttrInRef].push_back(aRefAttr);
570 std::list<AttributePtr> anAttrList;
571 anAttrList.push_back(aRefAttr);
572 theRefs[anAttrInRef] = anAttrList;
576 else { /// find attributes referenced to feature itself
577 theRefsToFeature.push_back(anAttr);
583 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
584 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
585 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
586 const std::set<ResultPtr>& theFeatureResults,
587 const FeaturePtr& theSplitFeature)
589 if (theCoincidenceToFeature.empty())
592 // we should build coincidence constraints to end of the split feature
593 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
594 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
595 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
596 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
597 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
598 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
599 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
601 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
602 aCLast = theCoincidenceToFeature.end();
604 std::cout << std::endl;
605 std::cout << "Coincidences to feature(modified):"<< std::endl;
607 for (; aCIt != aCLast; aCIt++) {
608 FeaturePtr aCoincFeature = aCIt->first;
609 std::string anAttributeId = aCIt->second.first;
610 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
611 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
612 aFCLast = theFurtherCoincidences.end();
613 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
614 AttributePoint2DPtr aFeaturePointAttribute;
615 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
616 AttributePoint2DPtr aFCAttribute = *aFCIt;
617 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
618 aFeaturePointAttribute = aFCAttribute;
620 if (aFeaturePointAttribute.get()) {
621 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
622 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
623 // create new coincidences to split feature points
624 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
625 aSFLast = aNewCoincidencesToSplitFeature.end();
626 for (; aSFIt != aSFLast; aSFIt++) {
627 AttributePoint2DPtr aSFAttribute = *aSFIt;
628 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
629 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
630 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
631 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
632 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
633 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
638 /// find feature by shape intersected the point
639 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
641 if (theFeatureResults.size() > 1) { // try to find point on additional feature
642 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
643 GeomShapePtr aShape = anAddtionalResult->shape();
645 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
646 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
648 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
649 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
650 aResultForCoincidence = anAddtionalResult;
652 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
655 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
660 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
661 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
662 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
664 if (theTangentFeatures.empty())
667 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
668 aTLast = theTangentFeatures.end();
670 std::cout << std::endl;
671 std::cout << "Tangencies to feature(modified):"<< std::endl;
673 for (; aTIt != aTLast; aTIt++) {
674 FeaturePtr aTangentFeature = aTIt->first;
675 std::string anAttributeId = aTIt->second.first;
676 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
677 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
678 aFCLast = theFurtherCoincidences.end();
679 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
680 AttributePoint2DPtr aFeaturePointAttribute;
681 /// here we rely on created coincidence between further coincidence point and tangent result
682 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
683 AttributePoint2DPtr aFCAttribute = *aFCIt;
684 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
685 aFeaturePointAttribute = aFCAttribute;
687 if (aFeaturePointAttribute.get()) {
688 FeaturePtr aFeature =
689 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
690 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
693 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
698 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
699 const ResultPtr& theFeatureBaseResult,
700 const std::list<AttributePtr>& theRefsToFeature)
702 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
703 aLast = theRefsToFeature.end();
704 for (; anIt != aLast; anIt++) {
705 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
707 aRefAttr->setObject(theFeatureBaseResult);
711 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
712 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
713 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
716 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
719 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
720 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
721 for (; anIt != aLast; anIt++) {
722 AttributePtr anAttribute = anIt->first;
724 /// not found in references
725 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
727 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
728 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
729 aRLast = aRefAttributes.end();
731 AttributePtr aNewAttribute = anIt->second;
732 for (; aRefIt != aRLast; aRefIt++) {
733 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
734 if (aRefAttr.get()) {
735 aRefAttr->setAttr(aNewAttribute);
737 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
738 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
745 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
746 FeaturePtr& theBaseFeatureModified,
747 FeaturePtr& theAfterFeature,
748 std::set<AttributePoint2DPtr>& thePoints,
749 std::set<FeaturePtr>& theCreatedFeatures,
750 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
752 std::set<FeaturePtr> aCreatedFeatures;
753 FeaturePtr aConstraintFeature;
754 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
756 SketchPlugin_Sketch* aSketch = sketch();
760 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
761 data()->attribute(SketchPlugin_Constraint::VALUE()));
762 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
763 std::string aFeatureKind = aBaseFeature->getKind();
764 if (aFeatureKind != SketchPlugin_Line::ID())
767 AttributePoint2DPtr aFirstPointAttrOfSplit =
768 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
769 AttributePoint2DPtr aSecondPointAttrOfSplit =
770 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
771 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
773 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
774 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
775 setError("Error: Feature has no start and end points.");
779 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
780 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
783 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
784 std::cout << "Start point: " <<
785 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
786 std::cout << "1st point: " <<
787 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
788 std::cout << "2nd point: " <<
789 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
790 std::cout << "End point: " <<
791 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
794 /// create a split feature
796 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
797 theCreatedFeatures.insert(theSplitFeature);
799 // before split feature
800 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
801 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
802 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
805 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
806 /// move end arc point to start of split
809 // after split feature
810 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
812 if (!theBaseFeatureModified.get()) {
813 aFeature = aBaseFeature; ///< use base feature to store all constraints here
814 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
815 aFeature->execute(); // to update result
818 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
819 theCreatedFeatures.insert(aFeature);
820 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
821 aFeature->attribute(SketchPlugin_Line::END_ID())));
823 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
824 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
825 aFeature->attribute(SketchPlugin_Line::START_ID()));
826 theCreatedFeatures.insert(aConstraintFeature);
828 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
829 (aFeature->attribute(SketchPlugin_Line::START_ID())));
830 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
831 (aFeature->attribute(SketchPlugin_Line::END_ID())));
833 if (!theBaseFeatureModified.get())
834 theBaseFeatureModified = aFeature;
836 theAfterFeature = aFeature;
839 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
840 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
841 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
842 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
844 // base split, that is defined before split feature should be changed at end
845 // (after the after feature creation). Otherwise modified value will be used in after feature
846 // before split feature
847 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
848 /// move end arc point to start of split
849 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
850 aFirstPointAttrOfSplit);
851 theBaseFeatureModified->execute(); // to update result
852 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
853 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
854 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
855 theCreatedFeatures.insert(aConstraintFeature);
857 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
858 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
859 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
860 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
863 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
864 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
866 // additional constraints between split and base features
867 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
868 getFeatureResult(aBaseFeature),
869 getFeatureResult(theSplitFeature));
870 theCreatedFeatures.insert(aConstraintFeature);
871 if (theAfterFeature.get()) {
872 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
873 getFeatureResult(aBaseFeature),
874 getFeatureResult(theAfterFeature));
875 theCreatedFeatures.insert(aConstraintFeature);
879 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
880 FeaturePtr& theBaseFeatureModified,
881 FeaturePtr& theAfterFeature,
882 std::set<AttributePoint2DPtr>& thePoints,
883 std::set<FeaturePtr>& theCreatedFeatures,
884 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
886 std::set<FeaturePtr> aCreatedFeatures;
887 FeaturePtr aConstraintFeature;
888 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
890 SketchPlugin_Sketch* aSketch = sketch();
894 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
895 data()->attribute(SketchPlugin_Constraint::VALUE()));
896 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
897 std::string aFeatureKind = aBaseFeature->getKind();
898 if (aFeatureKind != SketchPlugin_Arc::ID())
901 AttributePoint2DPtr aFirstPointAttrOfSplit =
902 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
903 AttributePoint2DPtr aSecondPointAttrOfSplit =
904 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
905 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
906 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
907 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
908 setError("Error: Feature has no start and end points.");
912 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
913 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
914 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
916 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
917 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
919 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
920 std::cout << "Start point: " <<
921 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
922 std::cout << "1st point: " <<
923 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
924 std::cout << "2nd point: " <<
925 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
926 std::cout << "End point: " <<
927 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
931 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
932 theCreatedFeatures.insert(theSplitFeature);
934 // before split feature
935 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
936 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
937 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
940 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
941 /// move end arc point to start of split
944 // after split feature
945 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
947 if (!theBaseFeatureModified.get()) {
948 aFeature = aBaseFeature; ///< use base feature to store all constraints here
949 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
950 aFeature->execute(); // to update result
953 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
954 theCreatedFeatures.insert(aFeature);
955 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
956 aFeature->attribute(SketchPlugin_Arc::END_ID())));
958 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
959 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
960 aFeature->attribute(SketchPlugin_Arc::START_ID()));
961 theCreatedFeatures.insert(aConstraintFeature);
963 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
964 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
965 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
966 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
968 if (!theBaseFeatureModified.get())
969 theBaseFeatureModified = aFeature;
971 theAfterFeature = aFeature;
974 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
975 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
976 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
977 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
979 // base split, that is defined before split feature should be changed at end
980 // (after the after feature creation). Otherwise modified value will be used in after feature
981 // before split feature
982 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
983 /// move end arc point to start of split
984 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
985 aFirstPointAttrOfSplit);
986 theBaseFeatureModified->execute(); // to update result
987 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
988 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
989 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
990 theCreatedFeatures.insert(aConstraintFeature);
992 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
993 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
994 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
995 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
998 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
999 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1001 // additional constraints between split and base features
1002 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1003 getFeatureResult(aBaseFeature),
1004 getFeatureResult(theSplitFeature));
1005 theCreatedFeatures.insert(aConstraintFeature);
1006 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1007 getFeatureResult(theSplitFeature),
1008 getFeatureResult(aBaseFeature));
1009 theCreatedFeatures.insert(aConstraintFeature);
1010 if (theAfterFeature.get()) {
1011 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1012 getFeatureResult(aBaseFeature),
1013 getFeatureResult(theAfterFeature));
1014 theCreatedFeatures.insert(aConstraintFeature);
1015 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1016 getFeatureResult(theSplitFeature),
1017 getFeatureResult(theAfterFeature));
1018 theCreatedFeatures.insert(aConstraintFeature);
1022 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1023 FeaturePtr& theBaseFeatureModified,
1024 FeaturePtr& theAfterFeature,
1025 std::set<AttributePoint2DPtr>& thePoints,
1026 std::set<FeaturePtr>& theCreatedFeatures,
1027 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1029 std::set<FeaturePtr> aCreatedFeatures;
1030 FeaturePtr aConstraintFeature;
1031 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1033 SketchPlugin_Sketch* aSketch = sketch();
1037 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1038 data()->attribute(SketchPlugin_Constraint::VALUE()));
1039 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1040 std::string aFeatureKind = aBaseFeature->getKind();
1041 if (aFeatureKind != SketchPlugin_Circle::ID())
1044 AttributePoint2DPtr aFirstPointAttrOfSplit =
1045 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1046 AttributePoint2DPtr aSecondPointAttrOfSplit =
1047 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1051 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1052 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1053 theCreatedFeatures.insert(theSplitFeature);
1055 /// base feature is a left part of the circle
1056 theBaseFeatureModified = createArcFeature(aBaseFeature,
1057 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1058 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1059 theBaseFeatureModified)->setReversed(!aSplitReversed);
1060 theBaseFeatureModified->execute();
1062 theModifiedAttributes.insert(
1063 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1064 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1066 theCreatedFeatures.insert(theBaseFeatureModified);
1068 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1069 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1070 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1071 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1073 // additional constraints between split and base features
1074 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1075 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1076 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1077 theCreatedFeatures.insert(aConstraintFeature);
1078 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1079 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1080 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1081 theCreatedFeatures.insert(aConstraintFeature);
1083 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1084 getFeatureResult(theSplitFeature),
1085 getFeatureResult(theBaseFeatureModified));
1086 theCreatedFeatures.insert(aConstraintFeature);
1089 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1090 const AttributePoint2DPtr& theStartPointAttr,
1091 const AttributePoint2DPtr& theEndPointAttr,
1092 AttributePoint2DPtr& theFirstPointAttr,
1093 AttributePoint2DPtr& theLastPointAttr) const
1095 // if first point is closer to last point, swap first and last values
1096 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1097 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1098 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1099 theFirstPointAttr = theLastPointAttr;
1100 theLastPointAttr = aTmpPoint;
1104 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1105 const FeaturePtr& theArc,
1106 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1107 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1108 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1109 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1111 static const double anAngleTol = 1.e-12;
1113 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1114 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1115 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1117 // collect directions to each point
1118 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1119 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1120 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1121 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1122 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1123 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1125 // sort points by their angular values
1126 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1127 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1128 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1129 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1130 aFirstPtAngle += aPeriod;
1131 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1132 aSecondPtAngle += aPeriod;
1134 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1135 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1136 theFirstPointAttr = theSecondPointAttr;
1137 theSecondPointAttr = aTmpPoint;
1141 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1142 const AttributePtr& theSourceAttribute)
1144 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1145 theModifiedAttribute);
1146 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1147 theSourceAttribute);
1149 if (aModifiedAttribute.get() && aSourceAttribute.get())
1150 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1153 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1154 const AttributePtr& theFirstPointAttr,
1155 const AttributePtr& theSecondPointAttr)
1157 FeaturePtr aFeature;
1158 SketchPlugin_Sketch* aSketch = sketch();
1159 if (!aSketch || !theBaseFeature.get())
1162 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1164 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1165 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1166 aFeature->execute(); // to obtain result
1171 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1172 const AttributePtr& theFirstPointAttr,
1173 const AttributePtr& theSecondPointAttr)
1175 FeaturePtr aFeature;
1176 SketchPlugin_Sketch* aSketch = sketch();
1177 if (!aSketch || !theBaseFeature.get())
1180 std::string aCenterAttributeId;
1181 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1182 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1183 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1184 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1186 if (aCenterAttributeId.empty())
1189 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1190 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1191 // the "attribute updated"
1192 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1193 aFeature->data()->blockSendAttributeUpdated(true);
1195 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1196 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1198 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1199 theBaseFeature->attribute(aCenterAttributeId));
1200 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1201 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1203 /// fill referersed state of created arc as it is on the base arc
1204 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1205 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1206 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1208 aFeature->data()->blockSendAttributeUpdated(false);
1209 aFeature->execute(); // to obtain result
1214 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1215 const AttributePtr& theFirstAttribute,
1216 const AttributePtr& theSecondAttribute)
1218 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1219 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1220 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1221 aRefAttr->setAttr(theFirstAttribute);
1223 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1224 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1225 aRefAttr->setAttr(theSecondAttribute);
1230 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1231 const std::string& theConstraintId,
1232 const ObjectPtr& theFirstObject,
1233 const ObjectPtr& theSecondObject)
1235 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1236 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1237 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1238 aRefAttr->setObject(theFirstObject);
1240 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1241 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1242 aRefAttr->setObject(theSecondObject);
1247 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1248 const std::set<FeaturePtr>& theFeaturesToUpdate)
1250 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1251 aLast = theFeaturesToUpdate.end();
1252 for (; anIt != aLast; anIt++) {
1253 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1254 std::string aRefFeatureKind = aRefFeature->getKind();
1255 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1256 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1257 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1258 if (aLenghtFeature.get()) {
1259 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1260 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1262 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1263 aValueAttr->setValue(aValue);
1269 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1270 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1272 std::shared_ptr<ModelAPI_Result> aResult;
1274 std::string aFeatureKind = theFeature->getKind();
1275 if (aFeatureKind == SketchPlugin_Line::ID())
1276 aResult = theFeature->firstResult();
1277 else if (aFeatureKind == SketchPlugin_Arc::ID())
1278 aResult = theFeature->lastResult();
1279 else if (aFeatureKind == SketchPlugin_Circle::ID())
1280 aResult = theFeature->lastResult();
1285 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1286 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1288 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1290 std::string aFeatureKind = theFeature->getKind();
1291 if (aFeatureKind == SketchPlugin_Line::ID()) {
1292 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1293 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1295 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1296 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1297 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1299 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1302 return anAttributes;
1306 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1307 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1308 const bool isUseAttributesInfo)
1311 if (!theFeature.get()) {
1315 if (theFeature->data()->isValid())
1316 anInfo.append(theFeature->data()->name().c_str());
1318 if (isUseAttributesInfo) {
1319 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1320 getEdgeAttributes(theFeature));
1321 /// processing of feature with point 2d attributes, like line, arc, circle
1322 if (!aPointsInfo.empty()) {
1325 anInfo += aPointsInfo;
1327 else { /// process constraint coincidence, find points in ref attr attributes
1328 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1329 ModelAPI_AttributeRefAttr::typeId());
1330 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1331 std::string anAttributesInfo;
1332 for(; anIt != aLast; anIt++) {
1333 if (!anAttributesInfo.empty()) {
1334 anAttributesInfo.append(", ");
1335 anAttributesInfo += "\n";
1337 AttributePtr anAttr = *anIt;
1338 std::string aValue = "not defined";
1339 std::string aType = anAttr->attributeType();
1340 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1341 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1342 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1343 if (aRefAttr.get()) {
1344 if (aRefAttr->isObject()) {
1345 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1346 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1349 AttributePtr anAttribute = aRefAttr->attr();
1350 if (anAttribute.get()) {
1351 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1352 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1353 " [" + getFeatureInfo(aFeature, false) + "]";
1358 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1360 if (!anAttributesInfo.empty())
1361 anInfo = anInfo + "\n" + anAttributesInfo;