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 = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
76 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
77 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
78 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
79 setError("Error: Sub-shape is not initialized.");
83 // Wait all constraints being created, then send update events
84 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
85 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
87 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
90 // Find feature constraints
91 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
92 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
93 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
94 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
95 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
96 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
98 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
99 std::list<AttributePtr> aRefsToFeature;
100 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
102 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
105 std::cout << std::endl;
106 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
107 std::cout << std::endl;
109 SketchPlugin_Sketch* aSketch = sketch();
110 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
111 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
112 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
115 std::cout << std::endl;
116 std::cout << "---- IN PARAMETERS ----" << std::endl;
117 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
118 std::cout << std::endl;
120 if (!aCoincidenceToFeature.empty()) {
121 std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl;
122 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
123 aLast = aCoincidenceToFeature.end();
124 for (int i = 1; anIt != aLast; anIt++, i++) {
125 FeaturePtr aFeature = (*anIt).first;
126 std::string anAttributeId = (*anIt).second.first;
127 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
129 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
130 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
131 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
135 if (!aTangentFeatures.empty()) {
136 std::cout << std::endl;
137 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
138 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
139 aLast = aTangentFeatures.end();
140 for (int i = 1; anIt != aLast; anIt++, i++) {
141 FeaturePtr aFeature = (*anIt).first;
142 std::string anAttributeId = (*anIt).second.first;
143 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
145 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
146 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
147 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
151 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator aRefIt = aBaseRefAttributes.begin(),
152 aRefLast = aBaseRefAttributes.end();
153 std::cout << std::endl << "References to attributes of base feature [" << aBaseRefAttributes.size() << "]" << std::endl;
154 for (; aRefIt != aRefLast; aRefIt++) {
155 AttributePtr aBaseAttr = aRefIt->first;
156 std::list<AttributePtr> aRefAttributes = aRefIt->second;
157 std::string aRefsInfo;
158 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
159 aRefAttrLast = aRefAttributes.end();
160 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
161 if (!aRefsInfo.empty())
162 aRefsInfo.append(",");
163 AttributePtr aRAttr = *aRefAttrIt;
164 aRefsInfo.append(aRAttr->id());
165 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
166 aRefsInfo.append("(" + aRFeature->name() + ") ");
168 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
169 std::cout << aPointAttr->id().c_str() << ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
171 std::cout << std::endl;
172 std::cout << std::endl << "References to base feature [" << aRefsToFeature.size() << "]" << std::endl;
173 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
174 aRefAttrLast = aRefsToFeature.end();
175 std::string aRefsInfo;
176 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
177 if (!aRefsInfo.empty())
178 aRefsInfo.append(",");
179 AttributePtr aRAttr = *aRefAttrIt;
180 aRefsInfo.append(aRAttr->id());
181 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
182 aRefsInfo.append("(" + aRFeature->name() + ") ");
184 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
187 std::cout << std::endl;
188 std::cout << "---- SPLIT ----" << std::endl;
189 std::cout << std::endl;
192 std::string aFeatureKind = aBaseFeature->getKind();
193 FeaturePtr aSplitFeature, anAfterFeature;
194 std::set<AttributePoint2DPtr> aFurtherCoincidences;
195 std::set<FeaturePtr> aCreatedFeatures;
196 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
197 if (aFeatureKind == SketchPlugin_Line::ID())
198 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
199 aModifiedAttributes);
200 else if (aFeatureKind == SketchPlugin_Arc::ID())
201 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
202 aModifiedAttributes);
203 if (aFeatureKind == SketchPlugin_Circle::ID()) {
204 FeaturePtr aCircleFeature = aBaseFeature;
205 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
206 aModifiedAttributes);
208 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
210 aFeaturesToDelete.insert(aCircleFeature);
211 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute*/
215 std::cout << "---- OUT PARAMETERS ----" << std::endl;
216 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
217 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
218 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
219 std::cout << std::endl;
221 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
222 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
223 aFLast = aCreatedFeatures.end();
224 for (; aFIt != aFLast; aFIt++) {
225 std::cout << getFeatureInfo(*aFIt) << std::endl;
227 std::cout << std::endl;
229 std::cout << "Attributes for further Coincidences:" << std::endl;
230 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
231 aLast = aFurtherCoincidences.end();
232 for (; anIt != aLast; anIt++) {
233 AttributePtr anAttribute = *anIt;
234 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
235 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
236 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
239 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
240 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator aPIt = aModifiedAttributes.begin(),
241 aPLast = aModifiedAttributes.end();
242 std::string aResInfo;
243 for (; aPIt != aPLast; aPIt++) {
244 if (!aResInfo.empty())
247 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
249 AttributePtr anAttr = aPair.first;
250 aResInfo.append(anAttr->id());
251 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
252 aResInfo.append("(" + aFeature->name() + ") ");
254 aResInfo.append(" - is modified to - ");
256 anAttr = aPair.second;
257 aResInfo.append(anAttr->id());
258 aFeature = ModelAPI_Feature::feature(anAttr->owner());
259 aResInfo.append("(" + aFeature->name() + ") ");
261 std::cout << aResInfo << std::endl;
264 std::set<ResultPtr> aFeatureResults;
265 aFeatureResults.insert(getFeatureResult(aBaseFeature));
266 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
267 aFeatureResults.insert(getFeatureResult(anAfterFeature));
269 // coincidence to feature
270 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
273 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
275 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
277 // delete constraints
279 std::cout << "remove features and references:" << std::endl;
280 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
281 aDLast = aFeaturesToDelete.end();
282 for (; aDIt != aDLast; aDIt++) {
283 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
284 std::cout << std::endl;
287 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
290 std::cout << "update features after split:" << std::endl;
291 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
292 anULast = aFeaturesToUpdate.end();
293 for (; anUIt != anULast; anUIt++) {
294 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
295 std::cout << std::endl;
298 updateFeaturesAfterSplit(aFeaturesToUpdate);
300 // Send events to update the sub-features by the solver.
301 if(isUpdateFlushed) {
302 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
306 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
307 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
308 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
313 bool SketchPlugin_ConstraintSplit::isMacro() const
318 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
320 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
321 data()->attribute(SketchPlugin_Constraint::VALUE()));
322 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
324 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
325 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
326 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
327 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
329 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
330 aFirstPointAttrOfSplit->isInitialized() &&
331 aSecondPointAttrOfSplit->isInitialized()) {
333 ResultPtr aResult = getFeatureResult(aBaseFeature);
334 GeomShapePtr aBaseShape = aResult->shape();
335 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
337 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
338 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
339 aPoints.push_back(aStartPoint);
341 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
342 std::shared_ptr<GeomAPI_Pnt> aSecondPoint = sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
343 aPoints.push_back(aSecondPoint);
345 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
347 GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
348 std::shared_ptr<GeomAPI_Shape> aShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
350 AISObjectPtr anAIS = thePrevious;
353 anAIS = AISObjectPtr(new GeomAPI_AISObject);
354 anAIS->createShape(aShape);
356 std::vector<int> aColor;
357 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
358 SKETCH_ENTITY_COLOR);
359 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
363 return AISObjectPtr();
366 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
367 const AttributePtr& theAttribute)
369 AttributePoint2DPtr aPointAttribute;
371 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
372 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
373 if (aRefAttr.get() && aRefAttr->isInitialized()) {
374 AttributePtr anAttribute = aRefAttr->attr();
375 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
376 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
379 return aPointAttribute;
382 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
383 AttributePoint2DPtr& theEndPointAttr)
385 AttributePoint2DPtr aPointAttribute;
387 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
388 data()->attribute(SketchPlugin_Constraint::VALUE()));
389 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
391 std::string aFeatureKind = aBaseFeature->getKind();
392 std::string aStartAttributeName, anEndAttributeName;
393 if (aFeatureKind == SketchPlugin_Line::ID()) {
394 aStartAttributeName = SketchPlugin_Line::START_ID();
395 anEndAttributeName = SketchPlugin_Line::END_ID();
397 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
398 aStartAttributeName = SketchPlugin_Arc::START_ID();
399 anEndAttributeName = SketchPlugin_Arc::END_ID();
401 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
402 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
403 aBaseFeature->attribute(aStartAttributeName));
404 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
405 aBaseFeature->attribute(anEndAttributeName));
409 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
410 std::set<FeaturePtr>& theFeaturesToUpdate,
411 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
412 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
414 std::shared_ptr<ModelAPI_Data> aData = data();
416 // Check the base objects are initialized.
417 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
418 aData->attribute(SketchPlugin_Constraint::VALUE()));
419 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
420 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
422 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
423 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
424 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
426 std::set<AttributePtr>::const_iterator aIt;
427 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
428 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
429 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
430 std::string aRefFeatureKind = aRefFeature->getKind();
431 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
432 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
433 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
434 theFeaturesToDelete.insert(aRefFeature);
435 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
436 theFeaturesToUpdate.insert(aRefFeature);
437 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
438 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
439 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
441 std::string anAttributeToBeModified;
442 AttributePoint2DPtr aTangentPoint;
443 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
444 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
445 if (aResult1.get() && aResult2.get()) {
446 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
447 (ModelAPI_Feature::feature(aResult1),
448 ModelAPI_Feature::feature(aResult2));
449 // get the point not lying on the splitting feature
450 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
451 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
452 if (!aRefAttr || aRefAttr->isObject())
454 AttributePoint2DPtr aPoint =
455 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
458 if (aPoint->owner() != aBaseFeature) {
459 aTangentPoint = aPoint;
464 if (aTangentPoint.get()) {
465 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
466 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
467 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
468 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
471 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
474 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
475 std::string anAttributeToBeModified;
476 AttributePoint2DPtr aCoincidentPoint;
477 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
478 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
479 bool isToFeature = false;
480 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
481 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
483 isToFeature = aFeature.get() && aFeature == aBaseFeature;
484 anAttributeToBeModified = anAttrA->id();
486 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
488 isToFeature = aFeature.get() && aFeature == aBaseFeature;
489 anAttributeToBeModified = anAttrB->id();
492 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
494 if (!isToFeature) { /// coincidence to point on base feature
495 AttributePtr anAttribute;
497 if (!anAttrA->isObject()) {
498 AttributePtr aCurAttribute = anAttrA->attr();
499 if (aCurAttribute.get()) {
500 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
501 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
502 anAttribute = anAttrB->attr();
503 anAttributeToBeModified = anAttrA->id();
507 if (!anAttribute.get() && !anAttrB->isObject()) {
508 AttributePtr aCurAttribute = anAttrB->attr();
509 if (aCurAttribute.get()) {
510 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
511 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
512 anAttribute = anAttrA->attr();
513 anAttributeToBeModified = anAttrB->id();
517 if (anAttribute.get())
518 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
520 if (aCoincidentPoint.get()) {
522 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
526 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
531 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
532 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
533 std::list<AttributePtr>& theRefsToFeature)
537 std::list<AttributePtr> aPointAttributes = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
538 std::set<AttributePtr> aPointAttributesSet;
540 std::list<AttributePtr>::const_iterator aPIt = aPointAttributes.begin(), aPLast = aPointAttributes.end();
541 for (; aPIt != aPLast; aPIt++)
542 aPointAttributesSet.insert(*aPIt);
544 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
545 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
546 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
548 std::set<AttributePtr>::const_iterator aIt;
549 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
550 AttributePtr anAttr = (*aIt);
551 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
552 if (anAttrFeature.get() != this &&
553 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
554 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
555 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
556 AttributePtr anAttrInRef = aRefAttr->attr();
557 if (anAttrInRef.get() && aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
558 if (theRefs.find(anAttrInRef) != theRefs.end())
559 theRefs[anAttrInRef].push_back(aRefAttr);
561 std::list<AttributePtr> anAttrList;
562 anAttrList.push_back(aRefAttr);
563 theRefs[anAttrInRef] = anAttrList;
567 else { /// find attributes referenced to feature itself
568 theRefsToFeature.push_back(anAttr);
574 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
575 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
576 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
577 const std::set<ResultPtr>& theFeatureResults)
579 if (theCoincidenceToFeature.empty())
582 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
583 aCLast = theCoincidenceToFeature.end();
585 std::cout << std::endl;
586 std::cout << "Coincidences to feature(modified):"<< std::endl;
588 for (; aCIt != aCLast; aCIt++) {
589 FeaturePtr aCoincFeature = aCIt->first;
590 std::string anAttributeId = aCIt->second.first;
591 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
592 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
593 aFCLast = theFurtherCoincidences.end();
594 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
595 AttributePoint2DPtr aFeaturePointAttribute;
596 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
597 AttributePoint2DPtr aFCAttribute = *aFCIt;
598 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
599 aFeaturePointAttribute = aFCAttribute;
601 if (aFeaturePointAttribute.get()) {
602 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
603 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
606 /// find feature by shape intersected the point
607 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
609 if (theFeatureResults.size() > 1) { // try to find point on additional feature
610 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
611 GeomShapePtr aShape = anAddtionalResult->shape();
613 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
614 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
616 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
617 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
618 aResultForCoincidence = anAddtionalResult;
620 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
623 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
628 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
629 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
630 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
632 if (theTangentFeatures.empty())
635 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
636 aTLast = theTangentFeatures.end();
638 std::cout << std::endl;
639 std::cout << "Tangencies to feature(modified):"<< std::endl;
641 for (; aTIt != aTLast; aTIt++) {
642 FeaturePtr aTangentFeature = aTIt->first;
643 std::string anAttributeId = aTIt->second.first;
644 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
645 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
646 aFCLast = theFurtherCoincidences.end();
647 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
648 AttributePoint2DPtr aFeaturePointAttribute;
649 /// here we rely on created coincidence between further coincidence point and tangent result
650 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
651 AttributePoint2DPtr aFCAttribute = *aFCIt;
652 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
653 aFeaturePointAttribute = aFCAttribute;
655 if (aFeaturePointAttribute.get()) {
656 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
657 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
660 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
665 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(const ResultPtr& theFeatureBaseResult,
666 const std::list<AttributePtr>& theRefsToFeature)
668 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
669 aLast = theRefsToFeature.end();
670 for (; anIt != aLast; anIt++) {
671 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
673 aRefAttr->setObject(theFeatureBaseResult);
677 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
678 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
679 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
682 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
685 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator anIt = theModifiedAttributes.begin(),
686 aLast = theModifiedAttributes.end();
687 for (; anIt != aLast; anIt++) {
688 AttributePtr anAttribute = anIt->first;
690 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) /// not found in references
692 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
693 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
694 aRLast = aRefAttributes.end();
696 AttributePtr aNewAttribute = anIt->second;
697 for (; aRefIt != aRLast; aRefIt++) {
698 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
699 if (aRefAttr.get()) {
700 aRefAttr->setAttr(aNewAttribute);
702 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
703 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
710 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
711 FeaturePtr& theBaseFeatureModified,
712 FeaturePtr& theAfterFeature,
713 std::set<AttributePoint2DPtr>& thePoints,
714 std::set<FeaturePtr>& theCreatedFeatures,
715 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
717 std::set<FeaturePtr> aCreatedFeatures;
718 FeaturePtr aConstraintFeature;
719 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
721 SketchPlugin_Sketch* aSketch = sketch();
725 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
726 data()->attribute(SketchPlugin_Constraint::VALUE()));
727 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
728 std::string aFeatureKind = aBaseFeature->getKind();
729 if (aFeatureKind != SketchPlugin_Line::ID())
732 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
733 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
734 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
735 getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
736 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
737 setError("Error: Feature has no start and end points.");
741 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
744 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
745 std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
746 std::cout << "1st point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
747 std::cout << "2nd point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
748 std::cout << "End point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
751 /// create a split feature
752 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
753 theCreatedFeatures.insert(theSplitFeature);
755 // before split feature
756 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
757 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
758 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
761 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
762 /// move end arc point to start of split
765 // after split feature
766 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
768 if (!theBaseFeatureModified.get()) {
769 aFeature = aBaseFeature; ///< use base feature to store all constraints here
770 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
771 aFeature->execute(); // to update result
774 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
775 theCreatedFeatures.insert(aFeature);
776 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
777 aFeature->attribute(SketchPlugin_Line::END_ID())));
779 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
780 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
781 aFeature->attribute(SketchPlugin_Line::START_ID()));
782 theCreatedFeatures.insert(aConstraintFeature);
784 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
785 (aFeature->attribute(SketchPlugin_Line::START_ID())));
786 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
787 (aFeature->attribute(SketchPlugin_Line::END_ID())));
789 if (!theBaseFeatureModified.get())
790 theBaseFeatureModified = aFeature;
792 theAfterFeature = aFeature;
795 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
796 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
797 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
798 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
800 // base split, that is defined before split feature should be changed at end
801 // (after the after feature creation). Otherwise modified value will be used in after feature
802 // before split feature
803 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
804 /// move end arc point to start of split
805 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttrOfSplit);
806 theBaseFeatureModified->execute(); // to update result
807 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
808 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
809 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
810 theCreatedFeatures.insert(aConstraintFeature);
812 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
813 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
814 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
815 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
818 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
819 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
821 // additional constraints between split and base features
822 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
823 getFeatureResult(aBaseFeature),
824 getFeatureResult(theSplitFeature));
825 theCreatedFeatures.insert(aConstraintFeature);
826 if (theAfterFeature.get()) {
827 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
828 getFeatureResult(aBaseFeature),
829 getFeatureResult(theAfterFeature));
830 theCreatedFeatures.insert(aConstraintFeature);
834 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
835 FeaturePtr& theBaseFeatureModified,
836 FeaturePtr& theAfterFeature,
837 std::set<AttributePoint2DPtr>& thePoints,
838 std::set<FeaturePtr>& theCreatedFeatures,
839 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
841 std::set<FeaturePtr> aCreatedFeatures;
842 FeaturePtr aConstraintFeature;
843 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
845 SketchPlugin_Sketch* aSketch = sketch();
849 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
850 data()->attribute(SketchPlugin_Constraint::VALUE()));
851 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
852 std::string aFeatureKind = aBaseFeature->getKind();
853 if (aFeatureKind != SketchPlugin_Arc::ID())
856 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
857 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
858 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
859 getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
860 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
861 setError("Error: Feature has no start and end points.");
865 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
866 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
867 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
869 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
870 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
872 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
873 std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
874 std::cout << "1st point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
875 std::cout << "2nd point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
876 std::cout << "End point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
880 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
881 theCreatedFeatures.insert(theSplitFeature);
883 // before split feature
884 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
885 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
886 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
889 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
890 /// move end arc point to start of split
893 // after split feature
894 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
896 if (!theBaseFeatureModified.get()) {
897 aFeature = aBaseFeature; ///< use base feature to store all constraints here
898 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
899 aFeature->execute(); // to update result
902 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
903 theCreatedFeatures.insert(aFeature);
904 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
905 aFeature->attribute(SketchPlugin_Arc::END_ID())));
907 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
908 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
909 aFeature->attribute(SketchPlugin_Arc::START_ID()));
910 theCreatedFeatures.insert(aConstraintFeature);
912 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
913 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
914 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
915 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
917 if (!theBaseFeatureModified.get())
918 theBaseFeatureModified = aFeature;
920 theAfterFeature = aFeature;
923 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
924 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
925 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
926 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
928 // base split, that is defined before split feature should be changed at end
929 // (after the after feature creation). Otherwise modified value will be used in after feature
930 // before split feature
931 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
932 /// move end arc point to start of split
933 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttrOfSplit);
934 theBaseFeatureModified->execute(); // to update result
935 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
936 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
937 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
938 theCreatedFeatures.insert(aConstraintFeature);
940 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
941 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
942 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
943 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
946 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
947 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
949 // additional constraints between split and base features
950 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
951 getFeatureResult(aBaseFeature),
952 getFeatureResult(theSplitFeature));
953 theCreatedFeatures.insert(aConstraintFeature);
954 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
955 getFeatureResult(theSplitFeature),
956 getFeatureResult(aBaseFeature));
957 theCreatedFeatures.insert(aConstraintFeature);
958 if (theAfterFeature.get()) {
959 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
960 getFeatureResult(aBaseFeature),
961 getFeatureResult(theAfterFeature));
962 theCreatedFeatures.insert(aConstraintFeature);
963 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
964 getFeatureResult(theSplitFeature),
965 getFeatureResult(theAfterFeature));
966 theCreatedFeatures.insert(aConstraintFeature);
970 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
971 FeaturePtr& theBaseFeatureModified,
972 FeaturePtr& theAfterFeature,
973 std::set<AttributePoint2DPtr>& thePoints,
974 std::set<FeaturePtr>& theCreatedFeatures,
975 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
977 std::set<FeaturePtr> aCreatedFeatures;
978 FeaturePtr aConstraintFeature;
979 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
981 SketchPlugin_Sketch* aSketch = sketch();
985 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
986 data()->attribute(SketchPlugin_Constraint::VALUE()));
987 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
988 std::string aFeatureKind = aBaseFeature->getKind();
989 if (aFeatureKind != SketchPlugin_Circle::ID())
992 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
993 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
996 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
997 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
998 theCreatedFeatures.insert(theSplitFeature);
1000 /// base feature is a left part of the circle
1001 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1002 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
1003 theBaseFeatureModified->execute();
1005 theModifiedAttributes.insert(std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1006 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1008 theCreatedFeatures.insert(theBaseFeatureModified);
1010 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1011 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1012 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1013 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1015 // additional constraints between split and base features
1016 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1017 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1018 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1019 theCreatedFeatures.insert(aConstraintFeature);
1020 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1021 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1022 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1023 theCreatedFeatures.insert(aConstraintFeature);
1025 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1026 getFeatureResult(theSplitFeature),
1027 getFeatureResult(theBaseFeatureModified));
1028 theCreatedFeatures.insert(aConstraintFeature);
1031 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1032 const AttributePoint2DPtr& theStartPointAttr,
1033 const AttributePoint2DPtr& theEndPointAttr,
1034 AttributePoint2DPtr& theFirstPointAttr,
1035 AttributePoint2DPtr& theLastPointAttr) const
1037 // if first point is closer to last point, swap first and last values
1038 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1039 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1040 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1041 theFirstPointAttr = theLastPointAttr;
1042 theLastPointAttr = aTmpPoint;
1046 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1047 const FeaturePtr& theArc,
1048 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1049 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1050 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1051 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1053 static const double anAngleTol = 1.e-12;
1055 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1056 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1057 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1059 // collect directions to each point
1060 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1061 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1062 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1063 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1064 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1065 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1067 // sort points by their angular values
1068 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1069 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1070 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1071 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1072 aFirstPtAngle += aPeriod;
1073 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1074 aSecondPtAngle += aPeriod;
1076 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1077 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1078 theFirstPointAttr = theSecondPointAttr;
1079 theSecondPointAttr = aTmpPoint;
1083 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1084 const AttributePtr& theSourceAttribute)
1086 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1087 theModifiedAttribute);
1088 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1089 theSourceAttribute);
1091 if (aModifiedAttribute.get() && aSourceAttribute.get())
1092 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1095 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1096 const AttributePtr& theFirstPointAttr,
1097 const AttributePtr& theSecondPointAttr)
1099 FeaturePtr aFeature;
1100 SketchPlugin_Sketch* aSketch = sketch();
1101 if (!aSketch || !theBaseFeature.get())
1104 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1106 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1107 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1108 aFeature->execute(); // to obtain result
1113 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1114 const AttributePtr& theFirstPointAttr,
1115 const AttributePtr& theSecondPointAttr)
1117 FeaturePtr aFeature;
1118 SketchPlugin_Sketch* aSketch = sketch();
1119 if (!aSketch || !theBaseFeature.get())
1122 std::string aCenterAttributeId;
1123 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1124 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1125 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1126 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1128 if (aCenterAttributeId.empty())
1131 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1132 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
1133 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1134 aFeature->data()->blockSendAttributeUpdated(true);
1136 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1137 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1139 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1140 theBaseFeature->attribute(aCenterAttributeId));
1141 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1142 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1144 /// fill referersed state of created arc as it is on the base arc
1145 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1146 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1147 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1149 aFeature->data()->blockSendAttributeUpdated(false);
1150 aFeature->execute(); // to obtain result
1155 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1156 const AttributePtr& theFirstAttribute,
1157 const AttributePtr& theSecondAttribute)
1159 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1160 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1161 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1162 aRefAttr->setAttr(theFirstAttribute);
1164 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1165 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1166 aRefAttr->setAttr(theSecondAttribute);
1171 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
1172 const ObjectPtr& theFirstObject,
1173 const ObjectPtr& theSecondObject)
1175 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1176 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1177 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1178 aRefAttr->setObject(theFirstObject);
1180 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1181 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1182 aRefAttr->setObject(theSecondObject);
1187 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1188 const std::set<FeaturePtr>& theFeaturesToUpdate)
1190 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1191 aLast = theFeaturesToUpdate.end();
1192 for (; anIt != aLast; anIt++) {
1193 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1194 std::string aRefFeatureKind = aRefFeature->getKind();
1195 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1196 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1197 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1198 if (aLenghtFeature.get()) {
1199 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1200 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1202 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1203 aValueAttr->setValue(aValue);
1209 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1210 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1212 std::shared_ptr<ModelAPI_Result> aResult;
1214 std::string aFeatureKind = theFeature->getKind();
1215 if (aFeatureKind == SketchPlugin_Line::ID())
1216 aResult = theFeature->firstResult();
1217 else if (aFeatureKind == SketchPlugin_Arc::ID())
1218 aResult = theFeature->lastResult();
1219 else if (aFeatureKind == SketchPlugin_Circle::ID())
1220 aResult = theFeature->lastResult();
1225 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1226 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1228 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1230 std::string aFeatureKind = theFeature->getKind();
1231 if (aFeatureKind == SketchPlugin_Line::ID()) {
1232 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1233 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1235 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1236 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1237 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1239 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1242 return anAttributes;
1246 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1247 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1248 const bool isUseAttributesInfo)
1251 if (!theFeature.get()) {
1255 if (theFeature->data()->isValid())
1256 anInfo.append(theFeature->data()->name().c_str());
1258 if (isUseAttributesInfo) {
1259 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1260 getEdgeAttributes(theFeature));
1261 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
1264 anInfo += aPointsInfo;
1266 else { /// process constraint coincidence, find points in ref attr attributes
1267 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1268 ModelAPI_AttributeRefAttr::typeId());
1269 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1270 std::string anAttributesInfo;
1271 for(; anIt != aLast; anIt++) {
1272 if (!anAttributesInfo.empty()) {
1273 anAttributesInfo.append(", ");
1274 anAttributesInfo += "\n";
1276 AttributePtr anAttr = *anIt;
1277 std::string aValue = "not defined";
1278 std::string aType = anAttr->attributeType();
1279 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1280 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1281 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1282 if (aRefAttr.get()) {
1283 if (aRefAttr->isObject()) {
1284 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1285 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1288 AttributePtr anAttribute = aRefAttr->attr();
1289 if (anAttribute.get()) {
1290 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1291 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1292 " [" + getFeatureInfo(aFeature, false) + "]";
1297 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1299 if (!anAttributesInfo.empty())
1300 anInfo = anInfo + "\n" + anAttributesInfo;