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 <ModelAPI_AttributeReference.h>
14 #include <ModelAPI_AttributeString.h>
15 #include <ModelAPI_AttributeRefAttr.h>
16 #include <ModelAPI_Tools.h>
18 #include <ModelAPI_Validator.h>
19 #include <ModelAPI_Session.h>
20 #include <ModelAPI_AttributeDouble.h>
22 #include <SketchPlugin_Line.h>
23 #include <SketchPlugin_Arc.h>
24 #include <SketchPlugin_Circle.h>
25 #include <SketchPlugin_ConstraintCoincidence.h>
26 #include <SketchPlugin_ConstraintEqual.h>
27 #include <SketchPlugin_ConstraintParallel.h>
28 #include <SketchPlugin_ConstraintTangent.h>
29 #include <SketchPlugin_ConstraintLength.h>
30 #include <SketchPlugin_ConstraintMirror.h>
31 #include <SketchPlugin_MultiRotation.h>
32 #include <SketchPlugin_MultiTranslation.h>
34 #include <ModelAPI_Events.h>
35 #include <SketchPlugin_Line.h>
36 #include <SketchPlugin_Arc.h>
37 #include <SketchPlugin_Circle.h>
39 #include <ModelGeomAlgo_Point2D.h>
40 #include <Events_Loop.h>
49 static const double PI = 3.141592653589793238463;
51 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
55 void SketchPlugin_ConstraintSplit::initAttributes()
57 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
58 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
59 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
62 void SketchPlugin_ConstraintSplit::execute()
64 std::shared_ptr<ModelAPI_Data> aData = data();
66 // Check the base objects are initialized.
67 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
68 aData->attribute(SketchPlugin_Constraint::VALUE()));
69 if(!aBaseObjectAttr->isInitialized()) {
70 setError("Error: Base object is not initialized.");
73 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
74 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
75 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
76 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
77 setError("Error: Sub-shape is not initialized.");
81 // Wait all constraints being created, then send update events
82 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
83 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
85 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
88 // Find feature constraints
89 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
90 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
91 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
92 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
93 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
94 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
96 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
97 std::list<AttributePtr> aRefsToFeature;
98 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
100 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
103 std::cout << std::endl;
104 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
105 std::cout << std::endl;
107 SketchPlugin_Sketch* aSketch = sketch();
108 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
109 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
110 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
113 std::cout << std::endl;
114 std::cout << "---- IN PARAMETERS ----" << std::endl;
115 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
116 std::cout << std::endl;
118 if (!aCoincidenceToFeature.empty()) {
119 std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl;
120 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
121 aLast = aCoincidenceToFeature.end();
122 for (int i = 1; anIt != aLast; anIt++, i++) {
123 FeaturePtr aFeature = (*anIt).first;
124 std::string anAttributeId = (*anIt).second.first;
125 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
127 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
128 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
129 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
133 if (!aTangentFeatures.empty()) {
134 std::cout << std::endl;
135 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
136 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
137 aLast = aTangentFeatures.end();
138 for (int i = 1; anIt != aLast; anIt++, i++) {
139 FeaturePtr aFeature = (*anIt).first;
140 std::string anAttributeId = (*anIt).second.first;
141 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
143 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
144 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
145 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
149 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator aRefIt = aBaseRefAttributes.begin(),
150 aRefLast = aBaseRefAttributes.end();
151 std::cout << std::endl << "References to attributes of base feature [" << aBaseRefAttributes.size() << "]" << std::endl;
152 for (; aRefIt != aRefLast; aRefIt++) {
153 AttributePtr aBaseAttr = aRefIt->first;
154 std::list<AttributePtr> aRefAttributes = aRefIt->second;
155 std::string aRefsInfo;
156 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
157 aRefAttrLast = aRefAttributes.end();
158 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
159 if (!aRefsInfo.empty())
160 aRefsInfo.append(",");
161 AttributePtr aRAttr = *aRefAttrIt;
162 aRefsInfo.append(aRAttr->id());
163 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
164 aRefsInfo.append("(" + aRFeature->name() + ") ");
166 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
167 std::cout << aPointAttr->id().c_str() << ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
169 std::cout << std::endl;
170 std::cout << std::endl << "References to base feature [" << aRefsToFeature.size() << "]" << std::endl;
171 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
172 aRefAttrLast = aRefsToFeature.end();
173 std::string aRefsInfo;
174 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
175 if (!aRefsInfo.empty())
176 aRefsInfo.append(",");
177 AttributePtr aRAttr = *aRefAttrIt;
178 aRefsInfo.append(aRAttr->id());
179 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
180 aRefsInfo.append("(" + aRFeature->name() + ") ");
182 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
185 std::cout << std::endl;
186 std::cout << "---- SPLIT ----" << std::endl;
187 std::cout << std::endl;
190 std::string aFeatureKind = aBaseFeature->getKind();
191 FeaturePtr aSplitFeature, anAfterFeature;
192 std::set<AttributePoint2DPtr> aFurtherCoincidences;
193 std::set<FeaturePtr> aCreatedFeatures;
194 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
195 if (aFeatureKind == SketchPlugin_Line::ID())
196 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
197 aModifiedAttributes);
198 else if (aFeatureKind == SketchPlugin_Arc::ID())
199 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
200 aModifiedAttributes);
201 if (aFeatureKind == SketchPlugin_Circle::ID()) {
202 FeaturePtr aCircleFeature = aBaseFeature;
203 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
204 aModifiedAttributes);
206 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
208 aFeaturesToDelete.insert(aCircleFeature);
209 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute*/
213 std::cout << "---- OUT PARAMETERS ----" << std::endl;
214 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
215 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
216 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
217 std::cout << std::endl;
219 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
220 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
221 aFLast = aCreatedFeatures.end();
222 for (; aFIt != aFLast; aFIt++) {
223 std::cout << getFeatureInfo(*aFIt) << std::endl;
225 std::cout << std::endl;
227 std::cout << "Attributes for further Coincidences:" << std::endl;
228 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
229 aLast = aFurtherCoincidences.end();
230 for (; anIt != aLast; anIt++) {
231 AttributePtr anAttribute = *anIt;
232 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
233 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
234 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
237 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
238 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator aPIt = aModifiedAttributes.begin(),
239 aPLast = aModifiedAttributes.end();
240 std::string aResInfo;
241 for (; aPIt != aPLast; aPIt++) {
242 if (!aResInfo.empty())
245 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
247 AttributePtr anAttr = aPair.first;
248 aResInfo.append(anAttr->id());
249 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
250 aResInfo.append("(" + aFeature->name() + ") ");
252 aResInfo.append(" - is modified to - ");
254 anAttr = aPair.second;
255 aResInfo.append(anAttr->id());
256 aFeature = ModelAPI_Feature::feature(anAttr->owner());
257 aResInfo.append("(" + aFeature->name() + ") ");
259 std::cout << aResInfo << std::endl;
262 std::set<ResultPtr> aFeatureResults;
263 aFeatureResults.insert(getFeatureResult(aBaseFeature));
264 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
265 aFeatureResults.insert(getFeatureResult(anAfterFeature));
267 // coincidence to feature
268 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
271 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
273 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
275 // delete constraints
277 std::cout << "remove features and references:" << std::endl;
278 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
279 aDLast = aFeaturesToDelete.end();
280 for (; aDIt != aDLast; aDIt++) {
281 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
282 std::cout << std::endl;
285 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
288 std::cout << "update features after split:" << std::endl;
289 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
290 anULast = aFeaturesToUpdate.end();
291 for (; anUIt != anULast; anUIt++) {
292 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
293 std::cout << std::endl;
296 updateFeaturesAfterSplit(aFeaturesToUpdate);
298 // Send events to update the sub-features by the solver.
299 if(isUpdateFlushed) {
300 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
304 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
305 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
306 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
311 bool SketchPlugin_ConstraintSplit::isMacro() const
316 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
317 const AttributePtr& theAttribute)
319 AttributePoint2DPtr aPointAttribute;
321 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
322 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
323 if (aRefAttr.get() && aRefAttr->isInitialized()) {
324 AttributePtr anAttribute = aRefAttr->attr();
325 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
326 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
329 return aPointAttribute;
332 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
333 AttributePoint2DPtr& theEndPointAttr)
335 AttributePoint2DPtr aPointAttribute;
337 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
338 data()->attribute(SketchPlugin_Constraint::VALUE()));
339 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
341 std::string aFeatureKind = aBaseFeature->getKind();
342 std::string aStartAttributeName, anEndAttributeName;
343 if (aFeatureKind == SketchPlugin_Line::ID()) {
344 aStartAttributeName = SketchPlugin_Line::START_ID();
345 anEndAttributeName = SketchPlugin_Line::END_ID();
347 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
348 aStartAttributeName = SketchPlugin_Arc::START_ID();
349 anEndAttributeName = SketchPlugin_Arc::END_ID();
351 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
352 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
353 aBaseFeature->attribute(aStartAttributeName));
354 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
355 aBaseFeature->attribute(anEndAttributeName));
359 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
360 std::set<FeaturePtr>& theFeaturesToUpdate,
361 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
362 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
364 std::shared_ptr<ModelAPI_Data> aData = data();
366 // Check the base objects are initialized.
367 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
368 aData->attribute(SketchPlugin_Constraint::VALUE()));
369 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
370 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
372 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
373 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
374 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
376 std::set<AttributePtr>::const_iterator aIt;
377 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
378 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
379 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
380 std::string aRefFeatureKind = aRefFeature->getKind();
381 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
382 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
383 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
384 theFeaturesToDelete.insert(aRefFeature);
385 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
386 theFeaturesToUpdate.insert(aRefFeature);
387 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
388 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
389 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
391 std::string anAttributeToBeModified;
392 AttributePoint2DPtr aTangentPoint;
393 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
394 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
395 if (aResult1.get() && aResult2.get()) {
396 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
397 (ModelAPI_Feature::feature(aResult1),
398 ModelAPI_Feature::feature(aResult2));
399 // get the point not lying on the splitting feature
400 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
401 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
402 if (!aRefAttr || aRefAttr->isObject())
404 AttributePoint2DPtr aPoint =
405 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
408 if (aPoint->owner() != aBaseFeature) {
409 aTangentPoint = aPoint;
414 if (aTangentPoint.get()) {
415 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
416 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
417 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
418 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
421 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
424 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
425 std::string anAttributeToBeModified;
426 AttributePoint2DPtr aCoincidentPoint;
427 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
428 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
429 bool isToFeature = false;
430 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
431 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
433 isToFeature = aFeature.get() && aFeature == aBaseFeature;
434 anAttributeToBeModified = anAttrA->id();
436 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
438 isToFeature = aFeature.get() && aFeature == aBaseFeature;
439 anAttributeToBeModified = anAttrB->id();
442 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
444 if (!isToFeature) { /// coincidence to point on base feature
445 AttributePtr anAttribute;
447 if (!anAttrA->isObject()) {
448 AttributePtr aCurAttribute = anAttrA->attr();
449 if (aCurAttribute.get()) {
450 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
451 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
452 anAttribute = anAttrB->attr();
453 anAttributeToBeModified = anAttrA->id();
457 if (!anAttribute.get() && !anAttrB->isObject()) {
458 AttributePtr aCurAttribute = anAttrB->attr();
459 if (aCurAttribute.get()) {
460 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
461 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
462 anAttribute = anAttrA->attr();
463 anAttributeToBeModified = anAttrB->id();
467 if (anAttribute.get())
468 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
470 if (aCoincidentPoint.get()) {
472 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
476 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
481 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
482 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
483 std::list<AttributePtr>& theRefsToFeature)
487 std::list<AttributePtr> aPointAttributes = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
488 std::set<AttributePtr> aPointAttributesSet;
490 std::list<AttributePtr>::const_iterator aPIt = aPointAttributes.begin(), aPLast = aPointAttributes.end();
491 for (; aPIt != aPLast; aPIt++)
492 aPointAttributesSet.insert(*aPIt);
494 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
495 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
496 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
498 std::set<AttributePtr>::const_iterator aIt;
499 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
500 AttributePtr anAttr = (*aIt);
501 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
502 if (anAttrFeature.get() != this &&
503 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
504 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
505 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
506 AttributePtr anAttrInRef = aRefAttr->attr();
507 if (anAttrInRef.get() && aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
508 if (theRefs.find(anAttrInRef) != theRefs.end())
509 theRefs[anAttrInRef].push_back(aRefAttr);
511 std::list<AttributePtr> anAttrList;
512 anAttrList.push_back(aRefAttr);
513 theRefs[anAttrInRef] = anAttrList;
517 else { /// find attributes referenced to feature itself
518 theRefsToFeature.push_back(anAttr);
524 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
525 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
526 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
527 const std::set<ResultPtr>& theFeatureResults)
529 if (theCoincidenceToFeature.empty())
532 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
533 aCLast = theCoincidenceToFeature.end();
535 std::cout << std::endl;
536 std::cout << "Coincidences to feature(modified):"<< std::endl;
538 for (; aCIt != aCLast; aCIt++) {
539 FeaturePtr aCoincFeature = aCIt->first;
540 std::string anAttributeId = aCIt->second.first;
541 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
542 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
543 aFCLast = theFurtherCoincidences.end();
544 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
545 AttributePoint2DPtr aFeaturePointAttribute;
546 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
547 AttributePoint2DPtr aFCAttribute = *aFCIt;
548 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
549 aFeaturePointAttribute = aFCAttribute;
551 if (aFeaturePointAttribute.get()) {
552 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
553 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
556 /// find feature by shape intersected the point
557 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
559 if (theFeatureResults.size() > 1) { // try to find point on additional feature
560 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
561 GeomShapePtr aShape = anAddtionalResult->shape();
563 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
564 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
566 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
567 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
568 aResultForCoincidence = anAddtionalResult;
570 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
573 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
578 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
579 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
580 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
582 if (theTangentFeatures.empty())
585 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
586 aTLast = theTangentFeatures.end();
588 std::cout << std::endl;
589 std::cout << "Tangencies to feature(modified):"<< std::endl;
591 for (; aTIt != aTLast; aTIt++) {
592 FeaturePtr aTangentFeature = aTIt->first;
593 std::string anAttributeId = aTIt->second.first;
594 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
595 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
596 aFCLast = theFurtherCoincidences.end();
597 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
598 AttributePoint2DPtr aFeaturePointAttribute;
599 /// here we rely on created coincidence between further coincidence point and tangent result
600 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
601 AttributePoint2DPtr aFCAttribute = *aFCIt;
602 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
603 aFeaturePointAttribute = aFCAttribute;
605 if (aFeaturePointAttribute.get()) {
606 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
607 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
610 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
615 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(const ResultPtr& theFeatureBaseResult,
616 const std::list<AttributePtr>& theRefsToFeature)
618 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
619 aLast = theRefsToFeature.end();
620 for (; anIt != aLast; anIt++) {
621 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
623 aRefAttr->setObject(theFeatureBaseResult);
627 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
628 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
629 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
632 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
635 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator anIt = theModifiedAttributes.begin(),
636 aLast = theModifiedAttributes.end();
637 for (; anIt != aLast; anIt++) {
638 AttributePtr anAttribute = anIt->first;
640 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) /// not found in references
642 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
643 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
644 aRLast = aRefAttributes.end();
646 AttributePtr aNewAttribute = anIt->second;
647 for (; aRefIt != aRLast; aRefIt++) {
648 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
649 if (aRefAttr.get()) {
650 aRefAttr->setAttr(aNewAttribute);
652 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
653 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
660 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
661 FeaturePtr& theBaseFeatureModified,
662 FeaturePtr& theAfterFeature,
663 std::set<AttributePoint2DPtr>& thePoints,
664 std::set<FeaturePtr>& theCreatedFeatures,
665 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
667 std::set<FeaturePtr> aCreatedFeatures;
668 FeaturePtr aConstraintFeature;
669 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
671 SketchPlugin_Sketch* aSketch = sketch();
675 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
676 data()->attribute(SketchPlugin_Constraint::VALUE()));
677 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
678 std::string aFeatureKind = aBaseFeature->getKind();
679 if (aFeatureKind != SketchPlugin_Line::ID())
682 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
683 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
684 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
685 getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
686 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
687 setError("Error: Feature has no start and end points.");
691 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
694 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
695 std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
696 std::cout << "1st point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
697 std::cout << "2nd point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
698 std::cout << "End point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
701 /// create a split feature
702 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
703 theCreatedFeatures.insert(theSplitFeature);
705 // before split feature
706 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
707 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
708 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
711 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
712 /// move end arc point to start of split
715 // after split feature
716 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
718 if (!theBaseFeatureModified.get()) {
719 aFeature = aBaseFeature; ///< use base feature to store all constraints here
720 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
721 aFeature->execute(); // to update result
724 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
725 theCreatedFeatures.insert(aFeature);
726 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
727 aFeature->attribute(SketchPlugin_Line::END_ID())));
729 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
730 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
731 aFeature->attribute(SketchPlugin_Line::START_ID()));
732 theCreatedFeatures.insert(aConstraintFeature);
734 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
735 (aFeature->attribute(SketchPlugin_Line::START_ID())));
736 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
737 (aFeature->attribute(SketchPlugin_Line::END_ID())));
739 if (!theBaseFeatureModified.get())
740 theBaseFeatureModified = aFeature;
742 theAfterFeature = aFeature;
745 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
746 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
747 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
748 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
750 // base split, that is defined before split feature should be changed at end
751 // (after the after feature creation). Otherwise modified value will be used in after feature
752 // before split feature
753 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
754 /// move end arc point to start of split
755 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttrOfSplit);
756 theBaseFeatureModified->execute(); // to update result
757 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
758 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
759 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
760 theCreatedFeatures.insert(aConstraintFeature);
762 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
763 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
764 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
765 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
768 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
769 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
771 // additional constraints between split and base features
772 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
773 getFeatureResult(aBaseFeature),
774 getFeatureResult(theSplitFeature));
775 theCreatedFeatures.insert(aConstraintFeature);
776 if (theAfterFeature.get()) {
777 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
778 getFeatureResult(aBaseFeature),
779 getFeatureResult(theAfterFeature));
780 theCreatedFeatures.insert(aConstraintFeature);
784 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
785 FeaturePtr& theBaseFeatureModified,
786 FeaturePtr& theAfterFeature,
787 std::set<AttributePoint2DPtr>& thePoints,
788 std::set<FeaturePtr>& theCreatedFeatures,
789 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
791 std::set<FeaturePtr> aCreatedFeatures;
792 FeaturePtr aConstraintFeature;
793 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
795 SketchPlugin_Sketch* aSketch = sketch();
799 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
800 data()->attribute(SketchPlugin_Constraint::VALUE()));
801 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
802 std::string aFeatureKind = aBaseFeature->getKind();
803 if (aFeatureKind != SketchPlugin_Arc::ID())
806 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
807 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
808 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
809 getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
810 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
811 setError("Error: Feature has no start and end points.");
815 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
816 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
817 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
819 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
820 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
822 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
823 std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
824 std::cout << "1st point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
825 std::cout << "2nd point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
826 std::cout << "End point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
830 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
831 theCreatedFeatures.insert(theSplitFeature);
833 // before split feature
834 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
835 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
836 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
839 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
840 /// move end arc point to start of split
843 // after split feature
844 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
846 if (!theBaseFeatureModified.get()) {
847 aFeature = aBaseFeature; ///< use base feature to store all constraints here
848 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
849 aFeature->execute(); // to update result
852 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
853 theCreatedFeatures.insert(aFeature);
854 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
855 aFeature->attribute(SketchPlugin_Arc::END_ID())));
857 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
858 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
859 aFeature->attribute(SketchPlugin_Arc::START_ID()));
860 theCreatedFeatures.insert(aConstraintFeature);
862 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
863 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
864 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
865 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
867 if (!theBaseFeatureModified.get())
868 theBaseFeatureModified = aFeature;
870 theAfterFeature = aFeature;
873 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
874 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
875 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
876 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
878 // base split, that is defined before split feature should be changed at end
879 // (after the after feature creation). Otherwise modified value will be used in after feature
880 // before split feature
881 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
882 /// move end arc point to start of split
883 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttrOfSplit);
884 theBaseFeatureModified->execute(); // to update result
885 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
886 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
887 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
888 theCreatedFeatures.insert(aConstraintFeature);
890 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
891 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
892 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
893 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
896 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
897 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
899 // additional constraints between split and base features
900 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
901 getFeatureResult(aBaseFeature),
902 getFeatureResult(theSplitFeature));
903 theCreatedFeatures.insert(aConstraintFeature);
904 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
905 getFeatureResult(theSplitFeature),
906 getFeatureResult(aBaseFeature));
907 theCreatedFeatures.insert(aConstraintFeature);
908 if (theAfterFeature.get()) {
909 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
910 getFeatureResult(aBaseFeature),
911 getFeatureResult(theAfterFeature));
912 theCreatedFeatures.insert(aConstraintFeature);
913 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
914 getFeatureResult(theSplitFeature),
915 getFeatureResult(theAfterFeature));
916 theCreatedFeatures.insert(aConstraintFeature);
920 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
921 FeaturePtr& theBaseFeatureModified,
922 FeaturePtr& theAfterFeature,
923 std::set<AttributePoint2DPtr>& thePoints,
924 std::set<FeaturePtr>& theCreatedFeatures,
925 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
927 std::set<FeaturePtr> aCreatedFeatures;
928 FeaturePtr aConstraintFeature;
929 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
931 SketchPlugin_Sketch* aSketch = sketch();
935 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
936 data()->attribute(SketchPlugin_Constraint::VALUE()));
937 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
938 std::string aFeatureKind = aBaseFeature->getKind();
939 if (aFeatureKind != SketchPlugin_Circle::ID())
942 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
943 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
946 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
947 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
948 theCreatedFeatures.insert(theSplitFeature);
950 /// base feature is a left part of the circle
951 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
952 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
953 theBaseFeatureModified->execute();
955 theModifiedAttributes.insert(std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
956 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
958 theCreatedFeatures.insert(theBaseFeatureModified);
960 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
961 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
962 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
963 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
965 // additional constraints between split and base features
966 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
967 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
968 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
969 theCreatedFeatures.insert(aConstraintFeature);
970 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
971 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
972 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
973 theCreatedFeatures.insert(aConstraintFeature);
975 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
976 getFeatureResult(theSplitFeature),
977 getFeatureResult(theBaseFeatureModified));
978 theCreatedFeatures.insert(aConstraintFeature);
981 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
982 const AttributePoint2DPtr& theStartPointAttr,
983 const AttributePoint2DPtr& theEndPointAttr,
984 AttributePoint2DPtr& theFirstPointAttr,
985 AttributePoint2DPtr& theLastPointAttr) const
987 // if first point is closer to last point, swap first and last values
988 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
989 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
990 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
991 theFirstPointAttr = theLastPointAttr;
992 theLastPointAttr = aTmpPoint;
996 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
997 const FeaturePtr& theArc,
998 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
999 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1000 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1001 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1003 static const double anAngleTol = 1.e-12;
1005 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1006 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1007 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1009 // collect directions to each point
1010 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1011 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1012 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1013 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1014 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1015 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1017 // sort points by their angular values
1018 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1019 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1020 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1021 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1022 aFirstPtAngle += aPeriod;
1023 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1024 aSecondPtAngle += aPeriod;
1026 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1027 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1028 theFirstPointAttr = theSecondPointAttr;
1029 theSecondPointAttr = aTmpPoint;
1033 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1034 const AttributePtr& theSourceAttribute)
1036 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1037 theModifiedAttribute);
1038 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1039 theSourceAttribute);
1041 if (aModifiedAttribute.get() && aSourceAttribute.get())
1042 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1045 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1046 const AttributePtr& theFirstPointAttr,
1047 const AttributePtr& theSecondPointAttr)
1049 FeaturePtr aFeature;
1050 SketchPlugin_Sketch* aSketch = sketch();
1051 if (!aSketch || !theBaseFeature.get())
1054 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1056 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1057 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1058 aFeature->execute(); // to obtain result
1063 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1064 const AttributePtr& theFirstPointAttr,
1065 const AttributePtr& theSecondPointAttr)
1067 FeaturePtr aFeature;
1068 SketchPlugin_Sketch* aSketch = sketch();
1069 if (!aSketch || !theBaseFeature.get())
1072 std::string aCenterAttributeId;
1073 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1074 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1075 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1076 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1078 if (aCenterAttributeId.empty())
1081 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1082 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
1083 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1084 aFeature->data()->blockSendAttributeUpdated(true);
1086 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1087 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1089 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1090 theBaseFeature->attribute(aCenterAttributeId));
1091 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1092 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1094 /// fill referersed state of created arc as it is on the base arc
1095 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1096 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1097 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1099 aFeature->data()->blockSendAttributeUpdated(false);
1100 aFeature->execute(); // to obtain result
1105 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1106 const AttributePtr& theFirstAttribute,
1107 const AttributePtr& theSecondAttribute)
1109 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1110 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1111 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1112 aRefAttr->setAttr(theFirstAttribute);
1114 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1115 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1116 aRefAttr->setAttr(theSecondAttribute);
1121 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
1122 const ObjectPtr& theFirstObject,
1123 const ObjectPtr& theSecondObject)
1125 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1126 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1127 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1128 aRefAttr->setObject(theFirstObject);
1130 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1131 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1132 aRefAttr->setObject(theSecondObject);
1137 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1138 const std::set<FeaturePtr>& theFeaturesToUpdate)
1140 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1141 aLast = theFeaturesToUpdate.end();
1142 for (; anIt != aLast; anIt++) {
1143 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1144 std::string aRefFeatureKind = aRefFeature->getKind();
1145 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1146 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1147 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1148 if (aLenghtFeature.get()) {
1149 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1150 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1152 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1153 aValueAttr->setValue(aValue);
1159 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1160 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1162 std::shared_ptr<ModelAPI_Result> aResult;
1164 std::string aFeatureKind = theFeature->getKind();
1165 if (aFeatureKind == SketchPlugin_Line::ID())
1166 aResult = theFeature->firstResult();
1167 else if (aFeatureKind == SketchPlugin_Arc::ID())
1168 aResult = theFeature->lastResult();
1169 else if (aFeatureKind == SketchPlugin_Circle::ID())
1170 aResult = theFeature->lastResult();
1175 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1176 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1178 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1180 std::string aFeatureKind = theFeature->getKind();
1181 if (aFeatureKind == SketchPlugin_Line::ID()) {
1182 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1183 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1185 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1186 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1187 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1189 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1192 return anAttributes;
1196 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1197 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1198 const bool isUseAttributesInfo)
1201 if (!theFeature.get()) {
1205 if (theFeature->data()->isValid())
1206 anInfo.append(theFeature->data()->name().c_str());
1208 if (isUseAttributesInfo) {
1209 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1210 getEdgeAttributes(theFeature));
1211 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
1214 anInfo += aPointsInfo;
1216 else { /// process constraint coincidence, find points in ref attr attributes
1217 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1218 ModelAPI_AttributeRefAttr::typeId());
1219 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1220 std::string anAttributesInfo;
1221 for(; anIt != aLast; anIt++) {
1222 if (!anAttributesInfo.empty()) {
1223 anAttributesInfo.append(", ");
1224 anAttributesInfo += "\n";
1226 AttributePtr anAttr = *anIt;
1227 std::string aValue = "not defined";
1228 std::string aType = anAttr->attributeType();
1229 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1230 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1231 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1232 if (aRefAttr.get()) {
1233 if (aRefAttr->isObject()) {
1234 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1235 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1238 AttributePtr anAttribute = aRefAttr->attr();
1239 if (anAttribute.get()) {
1240 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1241 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1242 " [" + getFeatureInfo(aFeature, false) + "]";
1247 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1249 if (!anAttributesInfo.empty())
1250 anInfo = anInfo + "\n" + anAttributesInfo;