1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_ConstraintSplit.cpp
4 // Created: 17 Jul 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 (!aCoincidenceToPoint.empty()) {
122 std::cout << "Coincidences to points on base feature[" << aCoincidenceToPoint.size() << "]: " << std::endl;
123 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToPoint.begin(),
124 aLast = aCoincidenceToPoint.end();
125 for (int i = 1; anIt != aLast; anIt++, i++) {
126 FeaturePtr aFeature = (*anIt).first;
127 std::string anAttributeId = (*anIt).second.first;
128 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
130 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
131 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
132 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
138 std::cout << std::endl;
139 std::cout << "---- SPLIT ----" << std::endl;
140 std::cout << std::endl;
143 std::string aFeatureKind = aBaseFeature->getKind();
144 FeaturePtr aSplitFeature, anAfterFeature;
145 std::set<AttributePoint2DPtr> aFurtherCoincidences;
146 std::set<FeaturePtr> aCreatedFeatures;
147 if (aFeatureKind == SketchPlugin_Line::ID())
148 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
149 else if (aFeatureKind == SketchPlugin_Arc::ID())
150 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
151 if (aFeatureKind == SketchPlugin_Circle::ID()) {
152 FeaturePtr aCircleFeature = aBaseFeature;
153 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
154 aFeaturesToDelete.insert(aCircleFeature);
155 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute
159 std::cout << "OUT PARAMETERS" << std::endl;
160 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
161 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
162 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
163 std::cout << std::endl;
165 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
166 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
167 aFLast = aCreatedFeatures.end();
168 for (; aFIt != aFLast; aFIt++) {
169 std::cout << getFeatureInfo(*aFIt) << std::endl;
171 std::cout << std::endl;
173 std::cout << "Attributes for further Coincidences:" << std::endl;
174 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
175 aLast = aFurtherCoincidences.end();
176 for (; anIt != aLast; anIt++) {
177 AttributePtr anAttribute = *anIt;
178 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
179 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
180 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
184 std::set<ResultPtr> aFeatureResults;
185 aFeatureResults.insert(getFeatureResult(aBaseFeature));
186 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
187 aFeatureResults.insert(getFeatureResult(anAfterFeature));
189 // coincidence to feature
190 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
192 // coincidence to points
193 updateCoincidenceConstraintsToFeature(aCoincidenceToPoint, aFurtherCoincidences,
194 std::set<ResultPtr>());
199 // delete constraints
201 std::cout << "remove features and references:" << std::endl;
202 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
203 aDLast = aFeaturesToDelete.end();
204 for (; aDIt != aDLast; aDIt++) {
205 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
206 std::cout << std::endl;
209 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
211 // Send events to update the sub-features by the solver.
212 if(isUpdateFlushed) {
213 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
217 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
218 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
219 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
224 bool SketchPlugin_ConstraintSplit::isMacro() const
229 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
230 const AttributePtr& theAttribute)
232 AttributePoint2DPtr aPointAttribute;
234 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
235 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
236 if (aRefAttr.get() && aRefAttr->isInitialized()) {
237 AttributePtr anAttribute = aRefAttr->attr();
238 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
239 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
242 return aPointAttribute;
245 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
246 AttributePoint2DPtr& theEndPointAttr)
248 AttributePoint2DPtr aPointAttribute;
250 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
251 data()->attribute(SketchPlugin_Constraint::VALUE()));
252 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
254 std::string aFeatureKind = aBaseFeature->getKind();
255 std::string aStartAttributeName, anEndAttributeName;
256 if (aFeatureKind == SketchPlugin_Line::ID()) {
257 aStartAttributeName = SketchPlugin_Line::START_ID();
258 anEndAttributeName = SketchPlugin_Line::END_ID();
260 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
261 aStartAttributeName = SketchPlugin_Arc::START_ID();
262 anEndAttributeName = SketchPlugin_Arc::END_ID();
264 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
265 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
266 aBaseFeature->attribute(aStartAttributeName));
267 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
268 aBaseFeature->attribute(anEndAttributeName));
272 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
273 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
274 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature,
275 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToPoint)
277 std::shared_ptr<ModelAPI_Data> aData = data();
279 // Check the base objects are initialized.
280 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
281 aData->attribute(SketchPlugin_Constraint::VALUE()));
282 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
283 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
285 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
286 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
287 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
289 std::set<AttributePtr>::const_iterator aIt;
290 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
291 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
292 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
293 std::string aRefFeatureKind = aRefFeature->getKind();
294 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
295 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
296 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
297 theFeaturesToDelete.insert(aRefFeature);
298 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
299 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
300 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
302 std::string anAttributeToBeModified;
303 AttributePoint2DPtr aTangentPoint;
304 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
305 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
306 if (aResult1.get() && aResult2.get()) {
307 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
308 (ModelAPI_Feature::feature(aResult1),
309 ModelAPI_Feature::feature(aResult2));
310 aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature);
312 if (aTangentPoint.get()) {
313 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
314 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
315 ? SketchPlugin_Constraint::ENTITY_B() : SketchPlugin_Constraint::ENTITY_A();
316 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
319 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
322 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
323 std::string anAttributeToBeModified;
324 AttributePoint2DPtr aCoincidentPoint;
325 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
326 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
327 bool isToFeature = false;
328 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
329 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
331 isToFeature = aFeature.get() && aFeature == aBaseFeature;
332 anAttributeToBeModified = anAttrA->id();
334 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
336 isToFeature = aFeature.get() && aFeature == aBaseFeature;
337 anAttributeToBeModified = anAttrB->id();
340 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
342 if (!isToFeature) { /// coincidence to point on base feature
343 AttributePtr anAttribute;
345 if (!anAttrA->isObject()) {
346 AttributePtr aCurAttribute = anAttrA->attr();
347 if (aCurAttribute.get()) {
348 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
349 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
350 anAttribute = anAttrB->attr();
351 anAttributeToBeModified = anAttrA->id();
355 if (!anAttribute.get() && !anAttrB->isObject()) {
356 AttributePtr aCurAttribute = anAttrB->attr();
357 if (aCurAttribute.get()) {
358 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
359 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
360 anAttribute = anAttrA->attr();
361 anAttributeToBeModified = anAttrB->id();
365 if (anAttribute.get())
366 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
368 if (aCoincidentPoint.get()) {
370 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
373 theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified,
377 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
382 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
383 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
384 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
385 const std::set<ResultPtr>& theFeatureResults)
387 if (theCoincidenceToFeature.empty())
390 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
391 aCLast = theCoincidenceToFeature.end();
393 std::cout << std::endl;
394 std::cout << "Coincidences to feature(modified):"<< std::endl;
396 for (; aCIt != aCLast; aCIt++) {
397 FeaturePtr aCoincFeature = aCIt->first;
398 std::string anAttributeId = aCIt->second.first;
399 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
400 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
401 aFCLast = theFurtherCoincidences.end();
402 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
403 AttributePoint2DPtr aFeaturePointAttribute;
404 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
405 AttributePoint2DPtr aFCAttribute = *aFCIt;
406 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
407 aFeaturePointAttribute = aFCAttribute;
409 if (aFeaturePointAttribute.get()) {
410 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
413 /// find feature by shape intersected the point
414 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
416 if (theFeatureResults.size() > 1) { // try to find point on additional feature
417 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
418 GeomShapePtr aShape = anAddtionalResult->shape();
420 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
421 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
423 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
424 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
425 aResultForCoincidence = anAddtionalResult;
427 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
430 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
435 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
436 FeaturePtr& theBaseFeatureModified,
437 FeaturePtr& theAfterFeature,
438 std::set<AttributePoint2DPtr>& thePoints,
439 std::set<FeaturePtr>& theCreatedFeatures)
441 std::set<FeaturePtr> aCreatedFeatures;
442 FeaturePtr aConstraintFeature;
443 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
445 SketchPlugin_Sketch* aSketch = sketch();
449 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
450 data()->attribute(SketchPlugin_Constraint::VALUE()));
451 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
452 std::string aFeatureKind = aBaseFeature->getKind();
453 if (aFeatureKind != SketchPlugin_Line::ID())
456 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
457 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
458 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
459 getFeaturePoints(aStartPointAttr, anEndPointAttr);
460 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
461 setError("Error: Feature has no start and end points.");
465 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
468 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
469 theCreatedFeatures.insert(theSplitFeature);
471 // before split feature
472 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
473 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
474 /// move end arc point to start of split
477 // after split feature
478 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
480 if (!theBaseFeatureModified.get()) {
481 aFeature = aBaseFeature; ///< use base feature to store all constraints here
482 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttr);
483 aFeature->execute(); // to update result
486 aFeature = createLineFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
487 theCreatedFeatures.insert(aFeature);
489 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
490 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
491 aFeature->attribute(SketchPlugin_Line::START_ID()));
492 theCreatedFeatures.insert(aConstraintFeature);
494 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
495 (aFeature->attribute(SketchPlugin_Line::START_ID())));
496 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
497 (aFeature->attribute(SketchPlugin_Line::END_ID())));
499 if (!theBaseFeatureModified.get())
500 theBaseFeatureModified = aFeature;
502 theAfterFeature = aFeature;
505 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
506 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
508 // base split, that is defined before split feature should be changed at end
509 // (after the after feature creation). Otherwise modified value will be used in after feature
510 // before split feature
511 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
512 /// move end arc point to start of split
513 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttr);
514 theBaseFeatureModified->execute(); // to update result
515 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
516 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
517 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
518 theCreatedFeatures.insert(aConstraintFeature);
520 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
521 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
522 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
523 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
526 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
527 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
529 // additional constraints between split and base features
530 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
531 getFeatureResult(aBaseFeature),
532 getFeatureResult(theSplitFeature));
533 theCreatedFeatures.insert(aConstraintFeature);
534 if (theAfterFeature.get()) {
535 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
536 getFeatureResult(aBaseFeature),
537 getFeatureResult(theAfterFeature));
538 theCreatedFeatures.insert(aConstraintFeature);
542 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
543 FeaturePtr& theBaseFeatureModified,
544 FeaturePtr& theAfterFeature,
545 std::set<AttributePoint2DPtr>& thePoints,
546 std::set<FeaturePtr>& theCreatedFeatures)
548 std::set<FeaturePtr> aCreatedFeatures;
549 FeaturePtr aConstraintFeature;
550 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
552 SketchPlugin_Sketch* aSketch = sketch();
556 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
557 data()->attribute(SketchPlugin_Constraint::VALUE()));
558 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
559 std::string aFeatureKind = aBaseFeature->getKind();
560 if (aFeatureKind != SketchPlugin_Arc::ID())
563 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
564 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
565 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
566 getFeaturePoints(aStartPointAttr, anEndPointAttr);
567 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
568 setError("Error: Feature has no start and end points.");
572 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
575 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
576 theCreatedFeatures.insert(theSplitFeature);
578 // before split feature
579 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
580 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
581 /// move end arc point to start of split
584 // after split feature
585 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
587 if (!theBaseFeatureModified.get()) {
588 aFeature = aBaseFeature; ///< use base feature to store all constraints here
589 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr);
590 aFeature->execute(); // to update result
593 aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
594 theCreatedFeatures.insert(aFeature);
596 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
597 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
598 aFeature->attribute(SketchPlugin_Arc::START_ID()));
599 theCreatedFeatures.insert(aConstraintFeature);
601 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
602 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
603 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
604 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
606 if (!theBaseFeatureModified.get())
607 theBaseFeatureModified = aFeature;
609 theAfterFeature = aFeature;
612 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
613 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
615 // base split, that is defined before split feature should be changed at end
616 // (after the after feature creation). Otherwise modified value will be used in after feature
617 // before split feature
618 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
619 /// move end arc point to start of split
620 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr);
621 theBaseFeatureModified->execute(); // to update result
622 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
623 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
624 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
625 theCreatedFeatures.insert(aConstraintFeature);
627 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
628 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
629 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
630 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
633 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
634 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
636 // additional constraints between split and base features
637 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
638 getFeatureResult(aBaseFeature),
639 getFeatureResult(theSplitFeature));
640 theCreatedFeatures.insert(aConstraintFeature);
641 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
642 getFeatureResult(theSplitFeature),
643 getFeatureResult(aBaseFeature));
644 theCreatedFeatures.insert(aConstraintFeature);
645 if (theAfterFeature.get()) {
646 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
647 getFeatureResult(aBaseFeature),
648 getFeatureResult(theAfterFeature));
649 theCreatedFeatures.insert(aConstraintFeature);
650 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
651 getFeatureResult(theSplitFeature),
652 getFeatureResult(theAfterFeature));
653 theCreatedFeatures.insert(aConstraintFeature);
657 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
658 FeaturePtr& theBaseFeatureModified,
659 FeaturePtr& theAfterFeature,
660 std::set<AttributePoint2DPtr>& thePoints,
661 std::set<FeaturePtr>& theCreatedFeatures)
663 std::set<FeaturePtr> aCreatedFeatures;
664 FeaturePtr aConstraintFeature;
665 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
667 SketchPlugin_Sketch* aSketch = sketch();
671 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
672 data()->attribute(SketchPlugin_Constraint::VALUE()));
673 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
674 std::string aFeatureKind = aBaseFeature->getKind();
675 if (aFeatureKind != SketchPlugin_Circle::ID())
678 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
679 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
682 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
683 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
684 theCreatedFeatures.insert(theSplitFeature);
686 /// base feature is a left part of the circle
687 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
688 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
689 theBaseFeatureModified->execute();
690 theCreatedFeatures.insert(theBaseFeatureModified);
692 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
693 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
694 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
695 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
697 // additional constraints between split and base features
698 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
699 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
700 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
701 theCreatedFeatures.insert(aConstraintFeature);
702 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
703 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
704 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
705 theCreatedFeatures.insert(aConstraintFeature);
707 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
708 getFeatureResult(theSplitFeature),
709 getFeatureResult(theBaseFeatureModified));
710 theCreatedFeatures.insert(aConstraintFeature);
713 void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr,
714 const AttributePoint2DPtr& theEndPointAttr,
715 AttributePoint2DPtr& theFirstPointAttr,
716 AttributePoint2DPtr& theLastPointAttr)
718 /// if first point is closer to last point, wrap first and last values
719 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
720 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
721 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
722 theFirstPointAttr = theLastPointAttr;
723 theLastPointAttr = aTmpPoint;
727 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
728 const AttributePtr& theSourceAttribute)
730 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
731 theModifiedAttribute);
732 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
735 if (aModifiedAttribute.get() && aSourceAttribute.get())
736 aModifiedAttribute->setValue(aSourceAttribute->pnt());
739 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
740 const AttributePtr& theFirstPointAttr,
741 const AttributePtr& theSecondPointAttr)
744 SketchPlugin_Sketch* aSketch = sketch();
745 if (!aSketch || !theBaseFeature.get())
748 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
749 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
750 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
751 aFeature->data()->blockSendAttributeUpdated(true);
753 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
754 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
755 aFeature->data()->blockSendAttributeUpdated(false);
756 aFeature->execute(); // to obtain result
761 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
762 const AttributePtr& theFirstPointAttr,
763 const AttributePtr& theSecondPointAttr)
766 SketchPlugin_Sketch* aSketch = sketch();
767 if (!aSketch || !theBaseFeature.get())
770 std::string aCenterAttributeId;
771 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
772 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
773 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
774 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
776 if (aCenterAttributeId.empty())
779 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
780 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
781 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
782 aFeature->data()->blockSendAttributeUpdated(true);
784 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
785 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
787 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
788 theBaseFeature->attribute(aCenterAttributeId));
789 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
790 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
791 aFeature->data()->blockSendAttributeUpdated(false);
792 aFeature->execute(); // to obtain result
797 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
798 const AttributePtr& theFirstAttribute,
799 const AttributePtr& theSecondAttribute)
801 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
802 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
803 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
804 aRefAttr->setAttr(theFirstAttribute);
806 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
807 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
808 aRefAttr->setAttr(theSecondAttribute);
813 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
814 const ObjectPtr& theFirstObject,
815 const ObjectPtr& theSecondObject)
817 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
818 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
819 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
820 aRefAttr->setObject(theFirstObject);
822 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
823 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
824 aRefAttr->setObject(theSecondObject);
829 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
830 const std::shared_ptr<ModelAPI_Feature>& theFeature)
832 std::shared_ptr<ModelAPI_Result> aResult;
834 std::string aFeatureKind = theFeature->getKind();
835 if (aFeatureKind == SketchPlugin_Line::ID())
836 aResult = theFeature->firstResult();
837 else if (aFeatureKind == SketchPlugin_Arc::ID())
838 aResult = theFeature->lastResult();
839 else if (aFeatureKind == SketchPlugin_Circle::ID())
840 aResult = theFeature->lastResult();
845 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
846 const std::shared_ptr<ModelAPI_Feature>& theFeature)
848 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
850 std::string aFeatureKind = theFeature->getKind();
851 if (aFeatureKind == SketchPlugin_Line::ID()) {
852 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
853 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
855 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
856 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
857 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
859 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
866 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
867 const std::shared_ptr<ModelAPI_Feature>& theFeature,
868 const bool isUseAttributesInfo)
871 if (!theFeature.get()) {
875 //anInfo.append(theFeature->getKind().c_str());
876 if (theFeature->data()->isValid()) {
877 //anInfo.append(", name=");
878 anInfo.append(theFeature->data()->name().c_str());
880 if (isUseAttributesInfo) {
881 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
882 getEdgeAttributes(theFeature));
883 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
886 anInfo += aPointsInfo;
888 else { /// process constraint coincidence, find points in ref attr attributes
889 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
890 ModelAPI_AttributeRefAttr::typeId());
891 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
892 std::string anAttributesInfo;
893 for(; anIt != aLast; anIt++) {
894 if (!anAttributesInfo.empty()) {
895 anAttributesInfo.append(", ");
896 anAttributesInfo += "\n";
898 AttributePtr anAttr = *anIt;
899 std::string aValue = "not defined";
900 std::string aType = anAttr->attributeType();
901 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
902 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
903 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
904 if (aRefAttr.get()) {
905 if (aRefAttr->isObject()) {
906 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
907 aValue = "<object:>" + getFeatureInfo(aFeature, false);
910 AttributePtr anAttribute = aRefAttr->attr();
911 if (anAttribute.get()) {
912 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
913 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
914 " [" + getFeatureInfo(aFeature, false) + "]";
919 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
921 if (!anAttributesInfo.empty())
922 anInfo = anInfo + "\n" + anAttributesInfo;