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_Pnt2d.h>
10 #include <GeomDataAPI_Point2D.h>
11 #include <ModelAPI_AttributeReference.h>
12 #include <ModelAPI_AttributeString.h>
13 #include <ModelAPI_AttributeRefAttr.h>
14 #include <ModelAPI_Tools.h>
16 #include <ModelAPI_Validator.h>
17 #include <ModelAPI_Session.h>
19 #include <SketchPlugin_Line.h>
20 #include <SketchPlugin_Arc.h>
21 #include <SketchPlugin_Circle.h>
22 #include <SketchPlugin_ConstraintCoincidence.h>
23 #include <SketchPlugin_ConstraintEqual.h>
24 #include <SketchPlugin_ConstraintParallel.h>
25 #include <SketchPlugin_ConstraintTangent.h>
26 #include <SketchPlugin_ConstraintMirror.h>
27 #include <SketchPlugin_MultiRotation.h>
28 #include <SketchPlugin_MultiTranslation.h>
30 #include <ModelAPI_Events.h>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Arc.h>
33 #include <SketchPlugin_Circle.h>
35 #include <ModelGeomAlgo_Point2D.h>
36 #include <Events_Loop.h>
43 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
47 void SketchPlugin_ConstraintSplit::initAttributes()
49 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
50 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
51 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
54 void SketchPlugin_ConstraintSplit::execute()
56 std::shared_ptr<ModelAPI_Data> aData = data();
58 // Check the base objects are initialized.
59 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
60 aData->attribute(SketchPlugin_Constraint::VALUE()));
61 if(!aBaseObjectAttr->isInitialized()) {
62 setError("Error: Base object is not initialized.");
65 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
66 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
67 if (!aFirstPointAttr.get() || !aFirstPointAttr->isInitialized() ||
68 !aSecondPointAttr.get() || !aSecondPointAttr->isInitialized()) {
69 setError("Error: Sub-shape is not initialized.");
73 // Wait all constraints being created, then send update events
74 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
75 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
77 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
80 // Find feature constraints
81 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
82 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
84 std::set<FeaturePtr> aFeaturesToDelete;
85 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
86 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
87 std::map<FeaturePtr, IdToPointPair> aCoincidenceToPoint;
88 getConstraints(aFeaturesToDelete, aTangentFeatures, aCoincidenceToFeature, aCoincidenceToPoint);
91 std::cout << std::endl;
92 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
93 std::cout << std::endl;
95 SketchPlugin_Sketch* aSketch = sketch();
96 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
97 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
98 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
101 std::cout << std::endl;
102 std::cout << "IN PARAMETERS" << std::endl;
103 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
104 std::cout << std::endl;
106 if (!aCoincidenceToFeature.empty()) {
107 std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl;
108 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
109 aLast = aCoincidenceToFeature.end();
110 for (int i = 1; anIt != aLast; anIt++, i++) {
111 FeaturePtr aFeature = (*anIt).first;
112 std::string anAttributeId = (*anIt).second.first;
113 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
115 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
116 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
117 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
121 if (!aTangentFeatures.empty()) {
122 std::cout << std::endl;
123 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
124 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
125 aLast = aTangentFeatures.end();
126 for (int i = 1; anIt != aLast; anIt++, i++) {
127 FeaturePtr aFeature = (*anIt).first;
128 std::string anAttributeId = (*anIt).second.first;
129 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
131 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
132 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
133 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
137 if (!aCoincidenceToPoint.empty()) {
138 std::cout << std::endl;
139 std::cout << "Coincidences to points on base feature[" << aCoincidenceToPoint.size() << "]: " << std::endl;
140 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToPoint.begin(),
141 aLast = aCoincidenceToPoint.end();
142 for (int i = 1; anIt != aLast; anIt++, i++) {
143 FeaturePtr aFeature = (*anIt).first;
144 std::string anAttributeId = (*anIt).second.first;
145 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
147 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
148 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
149 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
152 std::cout << std::endl;
153 std::cout << "---- SPLIT ----" << std::endl;
154 std::cout << std::endl;
157 std::string aFeatureKind = aBaseFeature->getKind();
158 FeaturePtr aSplitFeature, anAfterFeature;
159 std::set<AttributePoint2DPtr> aFurtherCoincidences;
160 std::set<FeaturePtr> aCreatedFeatures;
161 if (aFeatureKind == SketchPlugin_Line::ID())
162 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
163 else if (aFeatureKind == SketchPlugin_Arc::ID())
164 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
165 if (aFeatureKind == SketchPlugin_Circle::ID()) {
166 FeaturePtr aCircleFeature = aBaseFeature;
167 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
168 aFeaturesToDelete.insert(aCircleFeature);
169 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute
173 std::cout << "OUT PARAMETERS" << std::endl;
174 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
175 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
176 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
177 std::cout << std::endl;
179 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
180 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
181 aFLast = aCreatedFeatures.end();
182 for (; aFIt != aFLast; aFIt++) {
183 std::cout << getFeatureInfo(*aFIt) << std::endl;
185 std::cout << std::endl;
187 std::cout << "Attributes for further Coincidences:" << std::endl;
188 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
189 aLast = aFurtherCoincidences.end();
190 for (; anIt != aLast; anIt++) {
191 AttributePtr anAttribute = *anIt;
192 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
193 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
194 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
198 std::set<ResultPtr> aFeatureResults;
199 aFeatureResults.insert(getFeatureResult(aBaseFeature));
200 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
201 aFeatureResults.insert(getFeatureResult(anAfterFeature));
203 // coincidence to feature
204 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
206 // coincidence to points
207 updateCoincidenceConstraintsToFeature(aCoincidenceToPoint, aFurtherCoincidences,
208 std::set<ResultPtr>());
210 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
212 // delete constraints
214 std::cout << "remove features and references:" << std::endl;
215 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
216 aDLast = aFeaturesToDelete.end();
217 for (; aDIt != aDLast; aDIt++) {
218 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
219 std::cout << std::endl;
222 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
224 // Send events to update the sub-features by the solver.
225 if(isUpdateFlushed) {
226 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
230 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
231 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
232 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
237 bool SketchPlugin_ConstraintSplit::isMacro() const
242 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
243 const AttributePtr& theAttribute)
245 AttributePoint2DPtr aPointAttribute;
247 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
248 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
249 if (aRefAttr.get() && aRefAttr->isInitialized()) {
250 AttributePtr anAttribute = aRefAttr->attr();
251 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
252 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
255 return aPointAttribute;
258 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
259 AttributePoint2DPtr& theEndPointAttr)
261 AttributePoint2DPtr aPointAttribute;
263 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
264 data()->attribute(SketchPlugin_Constraint::VALUE()));
265 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
267 std::string aFeatureKind = aBaseFeature->getKind();
268 std::string aStartAttributeName, anEndAttributeName;
269 if (aFeatureKind == SketchPlugin_Line::ID()) {
270 aStartAttributeName = SketchPlugin_Line::START_ID();
271 anEndAttributeName = SketchPlugin_Line::END_ID();
273 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
274 aStartAttributeName = SketchPlugin_Arc::START_ID();
275 anEndAttributeName = SketchPlugin_Arc::END_ID();
277 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
278 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
279 aBaseFeature->attribute(aStartAttributeName));
280 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
281 aBaseFeature->attribute(anEndAttributeName));
285 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
286 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
287 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature,
288 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToPoint)
290 std::shared_ptr<ModelAPI_Data> aData = data();
292 // Check the base objects are initialized.
293 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
294 aData->attribute(SketchPlugin_Constraint::VALUE()));
295 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
296 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
298 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
299 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
300 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
302 std::set<AttributePtr>::const_iterator aIt;
303 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
304 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
305 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
306 std::string aRefFeatureKind = aRefFeature->getKind();
307 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
308 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
309 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
310 theFeaturesToDelete.insert(aRefFeature);
311 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
312 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
313 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
315 std::string anAttributeToBeModified;
316 AttributePoint2DPtr aTangentPoint;
317 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
318 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
319 if (aResult1.get() && aResult2.get()) {
320 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
321 (ModelAPI_Feature::feature(aResult1),
322 ModelAPI_Feature::feature(aResult2));
323 aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature);
325 if (aTangentPoint.get()) {
326 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
327 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
328 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
329 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
332 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
335 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
336 std::string anAttributeToBeModified;
337 AttributePoint2DPtr aCoincidentPoint;
338 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
339 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
340 bool isToFeature = false;
341 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
342 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
344 isToFeature = aFeature.get() && aFeature == aBaseFeature;
345 anAttributeToBeModified = anAttrA->id();
347 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
349 isToFeature = aFeature.get() && aFeature == aBaseFeature;
350 anAttributeToBeModified = anAttrB->id();
353 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
355 if (!isToFeature) { /// coincidence to point on base feature
356 AttributePtr anAttribute;
358 if (!anAttrA->isObject()) {
359 AttributePtr aCurAttribute = anAttrA->attr();
360 if (aCurAttribute.get()) {
361 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
362 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
363 anAttribute = anAttrB->attr();
364 anAttributeToBeModified = anAttrA->id();
368 if (!anAttribute.get() && !anAttrB->isObject()) {
369 AttributePtr aCurAttribute = anAttrB->attr();
370 if (aCurAttribute.get()) {
371 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
372 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
373 anAttribute = anAttrA->attr();
374 anAttributeToBeModified = anAttrB->id();
378 if (anAttribute.get())
379 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
381 if (aCoincidentPoint.get()) {
383 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
386 theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified,
390 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
395 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
396 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
397 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
398 const std::set<ResultPtr>& theFeatureResults)
400 if (theCoincidenceToFeature.empty())
403 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
404 aCLast = theCoincidenceToFeature.end();
406 std::cout << std::endl;
407 std::cout << "Coincidences to feature(modified):"<< std::endl;
409 for (; aCIt != aCLast; aCIt++) {
410 FeaturePtr aCoincFeature = aCIt->first;
411 std::string anAttributeId = aCIt->second.first;
412 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
413 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
414 aFCLast = theFurtherCoincidences.end();
415 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
416 AttributePoint2DPtr aFeaturePointAttribute;
417 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
418 AttributePoint2DPtr aFCAttribute = *aFCIt;
419 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
420 aFeaturePointAttribute = aFCAttribute;
422 if (aFeaturePointAttribute.get()) {
423 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
426 /// find feature by shape intersected the point
427 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
429 if (theFeatureResults.size() > 1) { // try to find point on additional feature
430 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
431 GeomShapePtr aShape = anAddtionalResult->shape();
433 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
434 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
436 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
437 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
438 aResultForCoincidence = anAddtionalResult;
440 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
443 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
448 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
449 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
450 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
452 if (theTangentFeatures.empty())
455 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
456 aTLast = theTangentFeatures.end();
458 std::cout << std::endl;
459 std::cout << "Tangencies to feature(modified):"<< std::endl;
461 for (; aTIt != aTLast; aTIt++) {
462 FeaturePtr aTangentFeature = aTIt->first;
463 std::string anAttributeId = aTIt->second.first;
464 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
465 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
466 aFCLast = theFurtherCoincidences.end();
467 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
468 AttributePoint2DPtr aFeaturePointAttribute;
469 /// here we rely on created coincidence between further coincidence point and tangent result
470 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
471 AttributePoint2DPtr aFCAttribute = *aFCIt;
472 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
473 aFeaturePointAttribute = aFCAttribute;
475 if (aFeaturePointAttribute.get()) {
476 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
477 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
480 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
485 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
486 FeaturePtr& theBaseFeatureModified,
487 FeaturePtr& theAfterFeature,
488 std::set<AttributePoint2DPtr>& thePoints,
489 std::set<FeaturePtr>& theCreatedFeatures)
491 std::set<FeaturePtr> aCreatedFeatures;
492 FeaturePtr aConstraintFeature;
493 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
495 SketchPlugin_Sketch* aSketch = sketch();
499 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
500 data()->attribute(SketchPlugin_Constraint::VALUE()));
501 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
502 std::string aFeatureKind = aBaseFeature->getKind();
503 if (aFeatureKind != SketchPlugin_Line::ID())
506 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
507 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
508 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
509 getFeaturePoints(aStartPointAttr, anEndPointAttr);
510 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
511 setError("Error: Feature has no start and end points.");
515 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
518 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
519 theCreatedFeatures.insert(theSplitFeature);
521 // before split feature
522 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
523 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
524 /// move end arc point to start of split
527 // after split feature
528 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
530 if (!theBaseFeatureModified.get()) {
531 aFeature = aBaseFeature; ///< use base feature to store all constraints here
532 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttr);
533 aFeature->execute(); // to update result
536 aFeature = createLineFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
537 theCreatedFeatures.insert(aFeature);
539 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
540 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
541 aFeature->attribute(SketchPlugin_Line::START_ID()));
542 theCreatedFeatures.insert(aConstraintFeature);
544 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
545 (aFeature->attribute(SketchPlugin_Line::START_ID())));
546 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
547 (aFeature->attribute(SketchPlugin_Line::END_ID())));
549 if (!theBaseFeatureModified.get())
550 theBaseFeatureModified = aFeature;
552 theAfterFeature = aFeature;
555 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
556 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
558 // base split, that is defined before split feature should be changed at end
559 // (after the after feature creation). Otherwise modified value will be used in after feature
560 // before split feature
561 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
562 /// move end arc point to start of split
563 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttr);
564 theBaseFeatureModified->execute(); // to update result
565 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
566 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
567 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
568 theCreatedFeatures.insert(aConstraintFeature);
570 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
571 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
572 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
573 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
576 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
577 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
579 // additional constraints between split and base features
580 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
581 getFeatureResult(aBaseFeature),
582 getFeatureResult(theSplitFeature));
583 theCreatedFeatures.insert(aConstraintFeature);
584 if (theAfterFeature.get()) {
585 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
586 getFeatureResult(aBaseFeature),
587 getFeatureResult(theAfterFeature));
588 theCreatedFeatures.insert(aConstraintFeature);
592 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
593 FeaturePtr& theBaseFeatureModified,
594 FeaturePtr& theAfterFeature,
595 std::set<AttributePoint2DPtr>& thePoints,
596 std::set<FeaturePtr>& theCreatedFeatures)
598 std::set<FeaturePtr> aCreatedFeatures;
599 FeaturePtr aConstraintFeature;
600 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
602 SketchPlugin_Sketch* aSketch = sketch();
606 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
607 data()->attribute(SketchPlugin_Constraint::VALUE()));
608 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
609 std::string aFeatureKind = aBaseFeature->getKind();
610 if (aFeatureKind != SketchPlugin_Arc::ID())
613 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
614 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
615 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
616 getFeaturePoints(aStartPointAttr, anEndPointAttr);
617 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
618 setError("Error: Feature has no start and end points.");
622 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
625 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
626 theCreatedFeatures.insert(theSplitFeature);
628 // before split feature
629 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
630 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
631 /// move end arc point to start of split
634 // after split feature
635 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
637 if (!theBaseFeatureModified.get()) {
638 aFeature = aBaseFeature; ///< use base feature to store all constraints here
639 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr);
640 aFeature->execute(); // to update result
643 aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
644 theCreatedFeatures.insert(aFeature);
646 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
647 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
648 aFeature->attribute(SketchPlugin_Arc::START_ID()));
649 theCreatedFeatures.insert(aConstraintFeature);
651 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
652 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
653 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
654 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
656 if (!theBaseFeatureModified.get())
657 theBaseFeatureModified = aFeature;
659 theAfterFeature = aFeature;
662 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
663 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
665 // base split, that is defined before split feature should be changed at end
666 // (after the after feature creation). Otherwise modified value will be used in after feature
667 // before split feature
668 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
669 /// move end arc point to start of split
670 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr);
671 theBaseFeatureModified->execute(); // to update result
672 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
673 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
674 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
675 theCreatedFeatures.insert(aConstraintFeature);
677 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
678 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
679 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
680 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
683 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
684 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
686 // additional constraints between split and base features
687 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
688 getFeatureResult(aBaseFeature),
689 getFeatureResult(theSplitFeature));
690 theCreatedFeatures.insert(aConstraintFeature);
691 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
692 getFeatureResult(theSplitFeature),
693 getFeatureResult(aBaseFeature));
694 theCreatedFeatures.insert(aConstraintFeature);
695 if (theAfterFeature.get()) {
696 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
697 getFeatureResult(aBaseFeature),
698 getFeatureResult(theAfterFeature));
699 theCreatedFeatures.insert(aConstraintFeature);
700 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
701 getFeatureResult(theSplitFeature),
702 getFeatureResult(theAfterFeature));
703 theCreatedFeatures.insert(aConstraintFeature);
707 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
708 FeaturePtr& theBaseFeatureModified,
709 FeaturePtr& theAfterFeature,
710 std::set<AttributePoint2DPtr>& thePoints,
711 std::set<FeaturePtr>& theCreatedFeatures)
713 std::set<FeaturePtr> aCreatedFeatures;
714 FeaturePtr aConstraintFeature;
715 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
717 SketchPlugin_Sketch* aSketch = sketch();
721 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
722 data()->attribute(SketchPlugin_Constraint::VALUE()));
723 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
724 std::string aFeatureKind = aBaseFeature->getKind();
725 if (aFeatureKind != SketchPlugin_Circle::ID())
728 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
729 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
732 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
733 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
734 theCreatedFeatures.insert(theSplitFeature);
736 /// base feature is a left part of the circle
737 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
738 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
739 theBaseFeatureModified->execute();
740 theCreatedFeatures.insert(theBaseFeatureModified);
742 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
743 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
744 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
745 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
747 // additional constraints between split and base features
748 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
749 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
750 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
751 theCreatedFeatures.insert(aConstraintFeature);
752 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
753 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
754 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
755 theCreatedFeatures.insert(aConstraintFeature);
757 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
758 getFeatureResult(theSplitFeature),
759 getFeatureResult(theBaseFeatureModified));
760 theCreatedFeatures.insert(aConstraintFeature);
763 void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr,
764 const AttributePoint2DPtr& theEndPointAttr,
765 AttributePoint2DPtr& theFirstPointAttr,
766 AttributePoint2DPtr& theLastPointAttr)
768 /// if first point is closer to last point, wrap first and last values
769 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
770 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
771 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
772 theFirstPointAttr = theLastPointAttr;
773 theLastPointAttr = aTmpPoint;
777 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
778 const AttributePtr& theSourceAttribute)
780 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
781 theModifiedAttribute);
782 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
785 if (aModifiedAttribute.get() && aSourceAttribute.get())
786 aModifiedAttribute->setValue(aSourceAttribute->pnt());
789 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
790 const AttributePtr& theFirstPointAttr,
791 const AttributePtr& theSecondPointAttr)
794 SketchPlugin_Sketch* aSketch = sketch();
795 if (!aSketch || !theBaseFeature.get())
798 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
800 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
801 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
802 aFeature->execute(); // to obtain result
807 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
808 const AttributePtr& theFirstPointAttr,
809 const AttributePtr& theSecondPointAttr)
812 SketchPlugin_Sketch* aSketch = sketch();
813 if (!aSketch || !theBaseFeature.get())
816 std::string aCenterAttributeId;
817 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
818 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
819 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
820 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
822 if (aCenterAttributeId.empty())
825 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
826 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
827 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
828 aFeature->data()->blockSendAttributeUpdated(true);
830 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
831 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
833 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
834 theBaseFeature->attribute(aCenterAttributeId));
835 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
836 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
837 aFeature->data()->blockSendAttributeUpdated(false);
838 aFeature->execute(); // to obtain result
843 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
844 const AttributePtr& theFirstAttribute,
845 const AttributePtr& theSecondAttribute)
847 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
848 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
849 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
850 aRefAttr->setAttr(theFirstAttribute);
852 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
853 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
854 aRefAttr->setAttr(theSecondAttribute);
859 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
860 const ObjectPtr& theFirstObject,
861 const ObjectPtr& theSecondObject)
863 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
864 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
865 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
866 aRefAttr->setObject(theFirstObject);
868 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
869 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
870 aRefAttr->setObject(theSecondObject);
875 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
876 const std::shared_ptr<ModelAPI_Feature>& theFeature)
878 std::shared_ptr<ModelAPI_Result> aResult;
880 std::string aFeatureKind = theFeature->getKind();
881 if (aFeatureKind == SketchPlugin_Line::ID())
882 aResult = theFeature->firstResult();
883 else if (aFeatureKind == SketchPlugin_Arc::ID())
884 aResult = theFeature->lastResult();
885 else if (aFeatureKind == SketchPlugin_Circle::ID())
886 aResult = theFeature->lastResult();
891 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
892 const std::shared_ptr<ModelAPI_Feature>& theFeature)
894 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
896 std::string aFeatureKind = theFeature->getKind();
897 if (aFeatureKind == SketchPlugin_Line::ID()) {
898 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
899 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
901 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
902 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
903 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
905 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
912 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
913 const std::shared_ptr<ModelAPI_Feature>& theFeature,
914 const bool isUseAttributesInfo)
917 if (!theFeature.get()) {
921 if (theFeature->data()->isValid())
922 anInfo.append(theFeature->data()->name().c_str());
924 if (isUseAttributesInfo) {
925 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
926 getEdgeAttributes(theFeature));
927 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
930 anInfo += aPointsInfo;
932 else { /// process constraint coincidence, find points in ref attr attributes
933 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
934 ModelAPI_AttributeRefAttr::typeId());
935 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
936 std::string anAttributesInfo;
937 for(; anIt != aLast; anIt++) {
938 if (!anAttributesInfo.empty()) {
939 anAttributesInfo.append(", ");
940 anAttributesInfo += "\n";
942 AttributePtr anAttr = *anIt;
943 std::string aValue = "not defined";
944 std::string aType = anAttr->attributeType();
945 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
946 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
947 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
948 if (aRefAttr.get()) {
949 if (aRefAttr->isObject()) {
950 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
951 aValue = "<object:>" + getFeatureInfo(aFeature, false);
954 AttributePtr anAttribute = aRefAttr->attr();
955 if (anAttribute.get()) {
956 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
957 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
958 " [" + getFeatureInfo(aFeature, false) + "]";
963 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
965 if (!anAttributesInfo.empty())
966 anInfo = anInfo + "\n" + anAttributesInfo;