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 getRefAttributes(aBaseFeature, aBaseRefAttributes);
99 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
102 std::cout << std::endl;
103 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
104 std::cout << std::endl;
106 SketchPlugin_Sketch* aSketch = sketch();
107 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
108 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
109 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
112 std::cout << std::endl;
113 std::cout << "---- IN PARAMETERS ----" << std::endl;
114 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
115 std::cout << std::endl;
117 if (!aCoincidenceToFeature.empty()) {
118 std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl;
119 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
120 aLast = aCoincidenceToFeature.end();
121 for (int i = 1; anIt != aLast; anIt++, i++) {
122 FeaturePtr aFeature = (*anIt).first;
123 std::string anAttributeId = (*anIt).second.first;
124 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
126 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
127 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
128 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
132 if (!aTangentFeatures.empty()) {
133 std::cout << std::endl;
134 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
135 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
136 aLast = aTangentFeatures.end();
137 for (int i = 1; anIt != aLast; anIt++, i++) {
138 FeaturePtr aFeature = (*anIt).first;
139 std::string anAttributeId = (*anIt).second.first;
140 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
142 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
143 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
144 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
148 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator aRefIt = aBaseRefAttributes.begin(),
149 aRefLast = aBaseRefAttributes.end();
150 std::cout << std::endl << "References to attributes of base feature [" << aBaseRefAttributes.size() << "]" << std::endl;
151 for (; aRefIt != aRefLast; aRefIt++) {
152 AttributePtr aBaseAttr = aRefIt->first;
153 std::list<AttributePtr> aRefAttributes = aRefIt->second;
154 std::string aRefsInfo;
155 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
156 aRefAttrLast = aRefAttributes.end();
157 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
158 if (!aRefsInfo.empty())
159 aRefsInfo.append(",");
160 AttributePtr aRAttr = *aRefAttrIt;
161 aRefsInfo.append(aRAttr->id());
162 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
163 aRefsInfo.append("(" + aRFeature->name() + ") ");
165 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
166 std::cout << aPointAttr->id().c_str() << ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
168 std::cout << std::endl;
169 std::cout << "---- SPLIT ----" << std::endl;
170 std::cout << std::endl;
173 std::string aFeatureKind = aBaseFeature->getKind();
174 FeaturePtr aSplitFeature, anAfterFeature;
175 std::set<AttributePoint2DPtr> aFurtherCoincidences;
176 std::set<FeaturePtr> aCreatedFeatures;
177 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
178 if (aFeatureKind == SketchPlugin_Line::ID())
179 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
180 aModifiedAttributes);
181 else if (aFeatureKind == SketchPlugin_Arc::ID())
182 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
183 aModifiedAttributes);
184 if (aFeatureKind == SketchPlugin_Circle::ID()) {
185 FeaturePtr aCircleFeature = aBaseFeature;
186 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
187 aModifiedAttributes);
188 aFeaturesToDelete.insert(aCircleFeature);
189 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute
193 std::cout << "---- OUT PARAMETERS ----" << std::endl;
194 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
195 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
196 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
197 std::cout << std::endl;
199 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
200 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
201 aFLast = aCreatedFeatures.end();
202 for (; aFIt != aFLast; aFIt++) {
203 std::cout << getFeatureInfo(*aFIt) << std::endl;
205 std::cout << std::endl;
207 std::cout << "Attributes for further Coincidences:" << std::endl;
208 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
209 aLast = aFurtherCoincidences.end();
210 for (; anIt != aLast; anIt++) {
211 AttributePtr anAttribute = *anIt;
212 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
213 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
214 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
217 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
218 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator aPIt = aModifiedAttributes.begin(),
219 aPLast = aModifiedAttributes.end();
220 std::string aResInfo;
221 for (; aPIt != aPLast; aPIt++) {
222 if (!aResInfo.empty())
225 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
227 AttributePtr anAttr = aPair.first;
228 aResInfo.append(anAttr->id());
229 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
230 aResInfo.append("(" + aFeature->name() + ") ");
232 aResInfo.append(" - is modified to - ");
234 anAttr = aPair.second;
235 aResInfo.append(anAttr->id());
236 aFeature = ModelAPI_Feature::feature(anAttr->owner());
237 aResInfo.append("(" + aFeature->name() + ") ");
239 std::cout << aResInfo << std::endl;
242 std::set<ResultPtr> aFeatureResults;
243 aFeatureResults.insert(getFeatureResult(aBaseFeature));
244 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
245 aFeatureResults.insert(getFeatureResult(anAfterFeature));
247 // coincidence to feature
248 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
251 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
253 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
255 // delete constraints
257 std::cout << "remove features and references:" << std::endl;
258 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
259 aDLast = aFeaturesToDelete.end();
260 for (; aDIt != aDLast; aDIt++) {
261 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
262 std::cout << std::endl;
265 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
268 std::cout << "update features after split:" << std::endl;
269 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
270 anULast = aFeaturesToUpdate.end();
271 for (; anUIt != anULast; anUIt++) {
272 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
273 std::cout << std::endl;
276 updateFeaturesAfterSplit(aFeaturesToUpdate);
278 // Send events to update the sub-features by the solver.
279 if(isUpdateFlushed) {
280 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
284 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
285 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
286 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
291 bool SketchPlugin_ConstraintSplit::isMacro() const
296 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
297 const AttributePtr& theAttribute)
299 AttributePoint2DPtr aPointAttribute;
301 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
302 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
303 if (aRefAttr.get() && aRefAttr->isInitialized()) {
304 AttributePtr anAttribute = aRefAttr->attr();
305 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
306 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
309 return aPointAttribute;
312 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
313 AttributePoint2DPtr& theEndPointAttr)
315 AttributePoint2DPtr aPointAttribute;
317 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
318 data()->attribute(SketchPlugin_Constraint::VALUE()));
319 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
321 std::string aFeatureKind = aBaseFeature->getKind();
322 std::string aStartAttributeName, anEndAttributeName;
323 if (aFeatureKind == SketchPlugin_Line::ID()) {
324 aStartAttributeName = SketchPlugin_Line::START_ID();
325 anEndAttributeName = SketchPlugin_Line::END_ID();
327 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
328 aStartAttributeName = SketchPlugin_Arc::START_ID();
329 anEndAttributeName = SketchPlugin_Arc::END_ID();
331 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
332 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
333 aBaseFeature->attribute(aStartAttributeName));
334 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
335 aBaseFeature->attribute(anEndAttributeName));
339 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
340 std::set<FeaturePtr>& theFeaturesToUpdate,
341 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
342 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
344 std::shared_ptr<ModelAPI_Data> aData = data();
346 // Check the base objects are initialized.
347 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
348 aData->attribute(SketchPlugin_Constraint::VALUE()));
349 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
350 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
352 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
353 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
354 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
356 std::set<AttributePtr>::const_iterator aIt;
357 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
358 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
359 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
360 std::string aRefFeatureKind = aRefFeature->getKind();
361 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
362 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
363 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
364 theFeaturesToDelete.insert(aRefFeature);
365 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
366 theFeaturesToUpdate.insert(aRefFeature);
367 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
368 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
369 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
371 std::string anAttributeToBeModified;
372 AttributePoint2DPtr aTangentPoint;
373 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
374 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
375 if (aResult1.get() && aResult2.get()) {
376 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
377 (ModelAPI_Feature::feature(aResult1),
378 ModelAPI_Feature::feature(aResult2));
379 // get the point not lying on the splitting feature
380 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
381 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
382 if (!aRefAttr || aRefAttr->isObject())
384 AttributePoint2DPtr aPoint =
385 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
388 if (aPoint->owner() != aBaseFeature) {
389 aTangentPoint = aPoint;
394 if (aTangentPoint.get()) {
395 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
396 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
397 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
398 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
401 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
404 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
405 std::string anAttributeToBeModified;
406 AttributePoint2DPtr aCoincidentPoint;
407 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
408 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
409 bool isToFeature = false;
410 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
411 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
413 isToFeature = aFeature.get() && aFeature == aBaseFeature;
414 anAttributeToBeModified = anAttrA->id();
416 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
418 isToFeature = aFeature.get() && aFeature == aBaseFeature;
419 anAttributeToBeModified = anAttrB->id();
422 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
424 if (!isToFeature) { /// coincidence to point on base feature
425 AttributePtr anAttribute;
427 if (!anAttrA->isObject()) {
428 AttributePtr aCurAttribute = anAttrA->attr();
429 if (aCurAttribute.get()) {
430 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
431 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
432 anAttribute = anAttrB->attr();
433 anAttributeToBeModified = anAttrA->id();
437 if (!anAttribute.get() && !anAttrB->isObject()) {
438 AttributePtr aCurAttribute = anAttrB->attr();
439 if (aCurAttribute.get()) {
440 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
441 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
442 anAttribute = anAttrA->attr();
443 anAttributeToBeModified = anAttrB->id();
447 if (anAttribute.get())
448 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
450 if (aCoincidentPoint.get()) {
452 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
456 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
461 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
462 std::map<AttributePtr, std::list<AttributePtr> >& theRefs)
466 std::list<AttributePtr> aPointAttributes = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
467 std::set<AttributePtr> aPointAttributesSet;
469 std::list<AttributePtr>::const_iterator aPIt = aPointAttributes.begin(), aPLast = aPointAttributes.end();
470 for (; aPIt != aPLast; aPIt++)
471 aPointAttributesSet.insert(*aPIt);
473 const std::set<AttributePtr>& aRefsAttributes = theFeature->data()->refsToMe();
474 std::set<AttributePtr>::const_iterator aIt;
475 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
476 AttributePtr anAttr = (*aIt);
477 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
478 if (anAttrFeature.get() != this &&
479 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
480 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
481 if (!aRefAttr->isObject()) {
482 AttributePtr anAttrInRef = aRefAttr->attr();
483 if (anAttrInRef.get() && aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
484 if (theRefs.find(anAttrInRef) != theRefs.end())
485 theRefs[anAttrInRef].push_back(aRefAttr);
487 std::list<AttributePtr> anAttrList;
488 anAttrList.push_back(aRefAttr);
489 theRefs[anAttrInRef] = anAttrList;
497 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
498 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
499 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
500 const std::set<ResultPtr>& theFeatureResults)
502 if (theCoincidenceToFeature.empty())
505 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
506 aCLast = theCoincidenceToFeature.end();
508 std::cout << std::endl;
509 std::cout << "Coincidences to feature(modified):"<< std::endl;
511 for (; aCIt != aCLast; aCIt++) {
512 FeaturePtr aCoincFeature = aCIt->first;
513 std::string anAttributeId = aCIt->second.first;
514 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
515 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
516 aFCLast = theFurtherCoincidences.end();
517 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
518 AttributePoint2DPtr aFeaturePointAttribute;
519 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
520 AttributePoint2DPtr aFCAttribute = *aFCIt;
521 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
522 aFeaturePointAttribute = aFCAttribute;
524 if (aFeaturePointAttribute.get()) {
525 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
526 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
529 /// find feature by shape intersected the point
530 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
532 if (theFeatureResults.size() > 1) { // try to find point on additional feature
533 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
534 GeomShapePtr aShape = anAddtionalResult->shape();
536 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
537 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
539 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
540 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
541 aResultForCoincidence = anAddtionalResult;
543 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
546 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
551 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
552 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
553 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
555 if (theTangentFeatures.empty())
558 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
559 aTLast = theTangentFeatures.end();
561 std::cout << std::endl;
562 std::cout << "Tangencies to feature(modified):"<< std::endl;
564 for (; aTIt != aTLast; aTIt++) {
565 FeaturePtr aTangentFeature = aTIt->first;
566 std::string anAttributeId = aTIt->second.first;
567 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
568 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
569 aFCLast = theFurtherCoincidences.end();
570 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
571 AttributePoint2DPtr aFeaturePointAttribute;
572 /// here we rely on created coincidence between further coincidence point and tangent result
573 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
574 AttributePoint2DPtr aFCAttribute = *aFCIt;
575 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
576 aFeaturePointAttribute = aFCAttribute;
578 if (aFeaturePointAttribute.get()) {
579 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
580 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
583 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
588 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
589 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
590 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
593 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
596 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator anIt = theModifiedAttributes.begin(),
597 aLast = theModifiedAttributes.end();
598 for (; anIt != aLast; anIt++) {
599 AttributePtr anAttribute = anIt->first;
601 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) /// not found in references
603 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
604 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
605 aRLast = aRefAttributes.end();
607 AttributePtr aNewAttribute = anIt->second;
608 for (; aRefIt != aRLast; aRefIt++) {
609 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
610 if (aRefAttr.get()) {
611 aRefAttr->setAttr(aNewAttribute);
613 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
614 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
621 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
622 FeaturePtr& theBaseFeatureModified,
623 FeaturePtr& theAfterFeature,
624 std::set<AttributePoint2DPtr>& thePoints,
625 std::set<FeaturePtr>& theCreatedFeatures,
626 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
628 std::set<FeaturePtr> aCreatedFeatures;
629 FeaturePtr aConstraintFeature;
630 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
632 SketchPlugin_Sketch* aSketch = sketch();
636 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
637 data()->attribute(SketchPlugin_Constraint::VALUE()));
638 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
639 std::string aFeatureKind = aBaseFeature->getKind();
640 if (aFeatureKind != SketchPlugin_Line::ID())
643 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
644 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
645 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
646 getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
647 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
648 setError("Error: Feature has no start and end points.");
652 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
655 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
656 std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
657 std::cout << "1st point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
658 std::cout << "2nd point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
659 std::cout << "End point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
662 /// create a split feature
663 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
664 theCreatedFeatures.insert(theSplitFeature);
666 // before split feature
667 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
668 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
669 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
672 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
673 /// move end arc point to start of split
676 // after split feature
677 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
679 if (!theBaseFeatureModified.get()) {
680 aFeature = aBaseFeature; ///< use base feature to store all constraints here
681 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
682 aFeature->execute(); // to update result
685 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
686 theCreatedFeatures.insert(aFeature);
687 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
688 aFeature->attribute(SketchPlugin_Line::END_ID())));
690 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
691 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
692 aFeature->attribute(SketchPlugin_Line::START_ID()));
693 theCreatedFeatures.insert(aConstraintFeature);
695 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
696 (aFeature->attribute(SketchPlugin_Line::START_ID())));
697 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
698 (aFeature->attribute(SketchPlugin_Line::END_ID())));
700 if (!theBaseFeatureModified.get())
701 theBaseFeatureModified = aFeature;
703 theAfterFeature = aFeature;
706 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
707 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
708 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
709 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
711 // base split, that is defined before split feature should be changed at end
712 // (after the after feature creation). Otherwise modified value will be used in after feature
713 // before split feature
714 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
715 /// move end arc point to start of split
716 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttrOfSplit);
717 theBaseFeatureModified->execute(); // to update result
718 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
719 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
720 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
721 theCreatedFeatures.insert(aConstraintFeature);
723 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
724 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
725 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
726 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
729 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
730 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
732 // additional constraints between split and base features
733 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
734 getFeatureResult(aBaseFeature),
735 getFeatureResult(theSplitFeature));
736 theCreatedFeatures.insert(aConstraintFeature);
737 if (theAfterFeature.get()) {
738 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
739 getFeatureResult(aBaseFeature),
740 getFeatureResult(theAfterFeature));
741 theCreatedFeatures.insert(aConstraintFeature);
745 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
746 FeaturePtr& theBaseFeatureModified,
747 FeaturePtr& theAfterFeature,
748 std::set<AttributePoint2DPtr>& thePoints,
749 std::set<FeaturePtr>& theCreatedFeatures,
750 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
752 std::set<FeaturePtr> aCreatedFeatures;
753 FeaturePtr aConstraintFeature;
754 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
756 SketchPlugin_Sketch* aSketch = sketch();
760 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
761 data()->attribute(SketchPlugin_Constraint::VALUE()));
762 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
763 std::string aFeatureKind = aBaseFeature->getKind();
764 if (aFeatureKind != SketchPlugin_Arc::ID())
767 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
768 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
769 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
770 getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
771 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
772 setError("Error: Feature has no start and end points.");
776 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
777 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
778 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
780 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
781 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
783 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
784 std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
785 std::cout << "1st point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
786 std::cout << "2nd point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
787 std::cout << "End point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
791 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
792 theCreatedFeatures.insert(theSplitFeature);
794 // before split feature
795 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
796 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
797 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
800 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
801 /// move end arc point to start of split
804 // after split feature
805 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
807 if (!theBaseFeatureModified.get()) {
808 aFeature = aBaseFeature; ///< use base feature to store all constraints here
809 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
810 aFeature->execute(); // to update result
813 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
814 theCreatedFeatures.insert(aFeature);
815 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
816 aFeature->attribute(SketchPlugin_Arc::END_ID())));
818 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
819 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
820 aFeature->attribute(SketchPlugin_Arc::START_ID()));
821 theCreatedFeatures.insert(aConstraintFeature);
823 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
824 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
825 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
826 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
828 if (!theBaseFeatureModified.get())
829 theBaseFeatureModified = aFeature;
831 theAfterFeature = aFeature;
834 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
835 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
836 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
837 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
839 // base split, that is defined before split feature should be changed at end
840 // (after the after feature creation). Otherwise modified value will be used in after feature
841 // before split feature
842 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
843 /// move end arc point to start of split
844 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttrOfSplit);
845 theBaseFeatureModified->execute(); // to update result
846 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
847 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
848 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
849 theCreatedFeatures.insert(aConstraintFeature);
851 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
852 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
853 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
854 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
857 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
858 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
860 // additional constraints between split and base features
861 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
862 getFeatureResult(aBaseFeature),
863 getFeatureResult(theSplitFeature));
864 theCreatedFeatures.insert(aConstraintFeature);
865 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
866 getFeatureResult(theSplitFeature),
867 getFeatureResult(aBaseFeature));
868 theCreatedFeatures.insert(aConstraintFeature);
869 if (theAfterFeature.get()) {
870 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
871 getFeatureResult(aBaseFeature),
872 getFeatureResult(theAfterFeature));
873 theCreatedFeatures.insert(aConstraintFeature);
874 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
875 getFeatureResult(theSplitFeature),
876 getFeatureResult(theAfterFeature));
877 theCreatedFeatures.insert(aConstraintFeature);
881 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
882 FeaturePtr& theBaseFeatureModified,
883 FeaturePtr& theAfterFeature,
884 std::set<AttributePoint2DPtr>& thePoints,
885 std::set<FeaturePtr>& theCreatedFeatures,
886 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
888 std::set<FeaturePtr> aCreatedFeatures;
889 FeaturePtr aConstraintFeature;
890 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
892 SketchPlugin_Sketch* aSketch = sketch();
896 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
897 data()->attribute(SketchPlugin_Constraint::VALUE()));
898 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
899 std::string aFeatureKind = aBaseFeature->getKind();
900 if (aFeatureKind != SketchPlugin_Circle::ID())
903 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
904 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
907 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
908 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
909 theCreatedFeatures.insert(theSplitFeature);
911 /// base feature is a left part of the circle
912 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
913 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
914 theBaseFeatureModified->execute();
916 theModifiedAttributes.insert(std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
917 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
919 theCreatedFeatures.insert(theBaseFeatureModified);
921 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
922 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
923 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
924 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
926 // additional constraints between split and base features
927 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
928 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
929 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
930 theCreatedFeatures.insert(aConstraintFeature);
931 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
932 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
933 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
934 theCreatedFeatures.insert(aConstraintFeature);
936 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
937 getFeatureResult(theSplitFeature),
938 getFeatureResult(theBaseFeatureModified));
939 theCreatedFeatures.insert(aConstraintFeature);
942 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
943 const AttributePoint2DPtr& theStartPointAttr,
944 const AttributePoint2DPtr& theEndPointAttr,
945 AttributePoint2DPtr& theFirstPointAttr,
946 AttributePoint2DPtr& theLastPointAttr) const
948 // if first point is closer to last point, swap first and last values
949 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
950 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
951 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
952 theFirstPointAttr = theLastPointAttr;
953 theLastPointAttr = aTmpPoint;
957 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
958 const FeaturePtr& theArc,
959 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
960 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
961 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
962 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
964 static const double anAngleTol = 1.e-12;
966 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
967 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
968 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
970 // collect directions to each point
971 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
972 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
973 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
974 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
975 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
976 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
978 // sort points by their angular values
979 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
980 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
981 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
982 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
983 aFirstPtAngle += aPeriod;
984 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
985 aSecondPtAngle += aPeriod;
987 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
988 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
989 theFirstPointAttr = theSecondPointAttr;
990 theSecondPointAttr = aTmpPoint;
994 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
995 const AttributePtr& theSourceAttribute)
997 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
998 theModifiedAttribute);
999 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1000 theSourceAttribute);
1002 if (aModifiedAttribute.get() && aSourceAttribute.get())
1003 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1006 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1007 const AttributePtr& theFirstPointAttr,
1008 const AttributePtr& theSecondPointAttr)
1010 FeaturePtr aFeature;
1011 SketchPlugin_Sketch* aSketch = sketch();
1012 if (!aSketch || !theBaseFeature.get())
1015 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1017 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1018 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1019 aFeature->execute(); // to obtain result
1024 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1025 const AttributePtr& theFirstPointAttr,
1026 const AttributePtr& theSecondPointAttr)
1028 FeaturePtr aFeature;
1029 SketchPlugin_Sketch* aSketch = sketch();
1030 if (!aSketch || !theBaseFeature.get())
1033 std::string aCenterAttributeId;
1034 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1035 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1036 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1037 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1039 if (aCenterAttributeId.empty())
1042 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1043 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
1044 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1045 aFeature->data()->blockSendAttributeUpdated(true);
1047 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1048 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1050 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1051 theBaseFeature->attribute(aCenterAttributeId));
1052 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1053 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1055 /// fill referersed state of created arc as it is on the base arc
1056 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1057 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1058 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1060 aFeature->data()->blockSendAttributeUpdated(false);
1061 aFeature->execute(); // to obtain result
1066 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1067 const AttributePtr& theFirstAttribute,
1068 const AttributePtr& theSecondAttribute)
1070 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1071 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1072 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1073 aRefAttr->setAttr(theFirstAttribute);
1075 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1076 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1077 aRefAttr->setAttr(theSecondAttribute);
1082 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
1083 const ObjectPtr& theFirstObject,
1084 const ObjectPtr& theSecondObject)
1086 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1087 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1088 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1089 aRefAttr->setObject(theFirstObject);
1091 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1092 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1093 aRefAttr->setObject(theSecondObject);
1098 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1099 const std::set<FeaturePtr>& theFeaturesToUpdate)
1101 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1102 aLast = theFeaturesToUpdate.end();
1103 for (; anIt != aLast; anIt++) {
1104 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1105 std::string aRefFeatureKind = aRefFeature->getKind();
1106 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1107 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1108 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1109 if (aLenghtFeature.get()) {
1110 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1111 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1113 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1114 aValueAttr->setValue(aValue);
1120 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1121 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1123 std::shared_ptr<ModelAPI_Result> aResult;
1125 std::string aFeatureKind = theFeature->getKind();
1126 if (aFeatureKind == SketchPlugin_Line::ID())
1127 aResult = theFeature->firstResult();
1128 else if (aFeatureKind == SketchPlugin_Arc::ID())
1129 aResult = theFeature->lastResult();
1130 else if (aFeatureKind == SketchPlugin_Circle::ID())
1131 aResult = theFeature->lastResult();
1136 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1137 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1139 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1141 std::string aFeatureKind = theFeature->getKind();
1142 if (aFeatureKind == SketchPlugin_Line::ID()) {
1143 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1144 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1146 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1147 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1148 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1150 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1153 return anAttributes;
1157 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1158 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1159 const bool isUseAttributesInfo)
1162 if (!theFeature.get()) {
1166 if (theFeature->data()->isValid())
1167 anInfo.append(theFeature->data()->name().c_str());
1169 if (isUseAttributesInfo) {
1170 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1171 getEdgeAttributes(theFeature));
1172 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
1175 anInfo += aPointsInfo;
1177 else { /// process constraint coincidence, find points in ref attr attributes
1178 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1179 ModelAPI_AttributeRefAttr::typeId());
1180 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1181 std::string anAttributesInfo;
1182 for(; anIt != aLast; anIt++) {
1183 if (!anAttributesInfo.empty()) {
1184 anAttributesInfo.append(", ");
1185 anAttributesInfo += "\n";
1187 AttributePtr anAttr = *anIt;
1188 std::string aValue = "not defined";
1189 std::string aType = anAttr->attributeType();
1190 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1191 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1192 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1193 if (aRefAttr.get()) {
1194 if (aRefAttr->isObject()) {
1195 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1196 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1199 AttributePtr anAttribute = aRefAttr->attr();
1200 if (anAttribute.get()) {
1201 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1202 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1203 " [" + getFeatureInfo(aFeature, false) + "]";
1208 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1210 if (!anAttributesInfo.empty())
1211 anInfo = anInfo + "\n" + anAttributesInfo;