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 std::cout << "SKETCH FEATURES (before split):" << std::endl;
96 SketchPlugin_Sketch* aSketch = sketch();
97 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
98 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
99 std::cout << std::endl;
102 std::cout << std::endl;
103 std::cout << "IN PARAMETERS" << std::endl;
104 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
105 std::cout << std::endl;
107 if (!aCoincidenceToFeature.empty()) {
108 std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl;
109 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
110 aLast = aCoincidenceToFeature.end();
111 for (int i = 1; anIt != aLast; anIt++, i++) {
112 FeaturePtr aFeature = (*anIt).first;
113 std::string anAttributeId = (*anIt).second.first;
114 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
116 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
117 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
118 std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
122 if (!aCoincidenceToPoint.empty()) {
123 std::cout << "Coincidences to points on base feature[" << aCoincidenceToPoint.size() << "]: " << std::endl;
124 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToPoint.begin(),
125 aLast = aCoincidenceToPoint.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;
139 std::cout << std::endl;
140 std::cout << "---- SPLIT ----" << std::endl;
141 std::cout << std::endl;
144 std::string aFeatureKind = aBaseFeature->getKind();
145 FeaturePtr aSplitFeature, anAfterFeature;
146 std::set<AttributePoint2DPtr> aFurtherCoincidences;
147 std::set<FeaturePtr> aCreatedFeatures;
148 if (aFeatureKind == SketchPlugin_Line::ID())
149 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
150 else if (aFeatureKind == SketchPlugin_Arc::ID())
151 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
152 if (aFeatureKind == SketchPlugin_Circle::ID()) {
153 FeaturePtr aCircleFeature = aBaseFeature;
154 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
155 aFeaturesToDelete.insert(aCircleFeature);
156 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute
160 std::cout << "OUT PARAMETERS" << std::endl;
161 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
162 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
163 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
164 std::cout << std::endl;
166 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
167 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
168 aFLast = aCreatedFeatures.end();
169 for (; aFIt != aFLast; aFIt++) {
170 std::cout << getFeatureInfo(*aFIt) << std::endl;
172 std::cout << std::endl;
174 std::cout << "Attributes for further Coincidences:" << std::endl;
175 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
176 aLast = aFurtherCoincidences.end();
177 for (; anIt != aLast; anIt++) {
178 AttributePtr anAttribute = *anIt;
179 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
180 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
181 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
185 std::set<ResultPtr> aFeatureResults;
186 aFeatureResults.insert(getFeatureResult(aBaseFeature));
187 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
188 aFeatureResults.insert(getFeatureResult(anAfterFeature));
190 // coincidence to feature
191 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
193 // coincidence to points
194 updateCoincidenceConstraintsToFeature(aCoincidenceToPoint, aFurtherCoincidences,
195 std::set<ResultPtr>());
200 // delete constraints
202 std::cout << "remove features and references:" << std::endl;
203 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
204 aDLast = aFeaturesToDelete.end();
205 for (; aDIt != aDLast; aDIt++) {
206 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
207 std::cout << std::endl;
210 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
212 // Send events to update the sub-features by the solver.
213 if(isUpdateFlushed) {
214 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
218 std::cout << "SKETCH FEATURES (after split):" << std::endl;
219 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
220 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
221 std::cout << std::endl;
226 bool SketchPlugin_ConstraintSplit::isMacro() const
231 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
232 const AttributePtr& theAttribute)
234 AttributePoint2DPtr aPointAttribute;
236 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
237 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
238 if (aRefAttr.get() && aRefAttr->isInitialized()) {
239 AttributePtr anAttribute = aRefAttr->attr();
240 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
241 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
244 return aPointAttribute;
247 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
248 AttributePoint2DPtr& theEndPointAttr)
250 AttributePoint2DPtr aPointAttribute;
252 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
253 data()->attribute(SketchPlugin_Constraint::VALUE()));
254 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
256 std::string aFeatureKind = aBaseFeature->getKind();
257 std::string aStartAttributeName, anEndAttributeName;
258 if (aFeatureKind == SketchPlugin_Line::ID()) {
259 aStartAttributeName = SketchPlugin_Line::START_ID();
260 anEndAttributeName = SketchPlugin_Line::END_ID();
262 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
263 aStartAttributeName = SketchPlugin_Arc::START_ID();
264 anEndAttributeName = SketchPlugin_Arc::END_ID();
266 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
267 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
268 aBaseFeature->attribute(aStartAttributeName));
269 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
270 aBaseFeature->attribute(anEndAttributeName));
274 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
275 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
276 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature,
277 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToPoint)
279 std::shared_ptr<ModelAPI_Data> aData = data();
281 // Check the base objects are initialized.
282 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
283 aData->attribute(SketchPlugin_Constraint::VALUE()));
284 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
285 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
287 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
288 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
289 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
291 std::set<AttributePtr>::const_iterator aIt;
292 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
293 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
294 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
295 std::string aRefFeatureKind = aRefFeature->getKind();
296 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
297 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
298 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
299 theFeaturesToDelete.insert(aRefFeature);
300 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
301 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
302 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
304 std::string anAttributeToBeModified;
305 AttributePoint2DPtr aTangentPoint;
306 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
307 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
308 if (aResult1.get() && aResult2.get()) {
309 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
310 (ModelAPI_Feature::feature(aResult1),
311 ModelAPI_Feature::feature(aResult2));
312 aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature);
314 if (aTangentPoint.get()) {
315 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
316 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
317 ? SketchPlugin_Constraint::ENTITY_B() : SketchPlugin_Constraint::ENTITY_A();
318 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
321 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
324 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
325 std::string anAttributeToBeModified;
326 AttributePoint2DPtr aCoincidentPoint;
327 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
328 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
329 bool isToFeature = false;
330 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
331 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
333 isToFeature = aFeature.get() && aFeature == aBaseFeature;
334 anAttributeToBeModified = anAttrA->id();
336 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
338 isToFeature = aFeature.get() && aFeature == aBaseFeature;
339 anAttributeToBeModified = anAttrB->id();
342 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
344 if (!isToFeature) { /// coincidence to point on base feature
345 AttributePtr anAttribute;
347 if (!anAttrA->isObject()) {
348 AttributePtr aCurAttribute = anAttrA->attr();
349 if (aCurAttribute.get()) {
350 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
351 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
352 anAttribute = anAttrA->attr();
353 anAttributeToBeModified = anAttrA->id();
357 if (!anAttribute.get() && !anAttrB->isObject()) {
358 AttributePtr aCurAttribute = anAttrB->attr();
359 if (aCurAttribute.get()) {
360 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
361 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
362 anAttribute = anAttrB->attr();
363 anAttributeToBeModified = anAttrB->id();
367 if (anAttribute.get())
368 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
370 if (aCoincidentPoint.get()) {
372 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
375 theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified,
379 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
384 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
385 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
386 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
387 const std::set<ResultPtr>& theFeatureResults)
389 if (theCoincidenceToFeature.empty())
392 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
393 aCLast = theCoincidenceToFeature.end();
395 std::cout << std::endl;
396 std::cout << "Coincidences to feature(modified):"<< std::endl;
398 for (; aCIt != aCLast; aCIt++) {
399 FeaturePtr aCoincFeature = aCIt->first;
400 std::string anAttributeId = aCIt->second.first;
401 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
402 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
403 aFCLast = theFurtherCoincidences.end();
404 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
405 AttributePoint2DPtr aFeaturePointAttribute;
406 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
407 AttributePoint2DPtr aFCAttribute = *aFCIt;
408 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
409 aFeaturePointAttribute = aFCAttribute;
411 if (aFeaturePointAttribute.get()) {
412 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
415 /// find feature by shape intersected the point
416 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
418 if (theFeatureResults.size() > 1) { // try to find point on additional feature
419 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
420 GeomShapePtr aShape = anAddtionalResult->shape();
422 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
423 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
425 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
426 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
427 aResultForCoincidence = anAddtionalResult;
429 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
432 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
437 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
438 FeaturePtr& theBaseFeatureModified,
439 FeaturePtr& theAfterFeature,
440 std::set<AttributePoint2DPtr>& thePoints,
441 std::set<FeaturePtr>& theCreatedFeatures)
443 std::set<FeaturePtr> aCreatedFeatures;
444 FeaturePtr aConstraintFeature;
445 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
447 SketchPlugin_Sketch* aSketch = sketch();
451 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
452 data()->attribute(SketchPlugin_Constraint::VALUE()));
453 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
454 std::string aFeatureKind = aBaseFeature->getKind();
455 if (aFeatureKind != SketchPlugin_Line::ID())
458 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
459 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
460 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
461 getFeaturePoints(aStartPointAttr, anEndPointAttr);
462 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
463 setError("Error: Feature has no start and end points.");
467 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
470 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
471 theCreatedFeatures.insert(theSplitFeature);
473 // before split feature
474 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
475 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
476 /// move end arc point to start of split
479 // after split feature
480 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
482 if (!theBaseFeatureModified.get()) {
483 aFeature = aBaseFeature; ///< use base feature to store all constraints here
484 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttr);
485 aFeature->execute(); // to update result
488 aFeature = createLineFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
489 theCreatedFeatures.insert(aFeature);
491 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
492 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
493 aFeature->attribute(SketchPlugin_Line::START_ID()));
494 theCreatedFeatures.insert(aConstraintFeature);
496 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
497 (aFeature->attribute(SketchPlugin_Line::START_ID())));
498 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
499 (aFeature->attribute(SketchPlugin_Line::END_ID())));
501 if (!theBaseFeatureModified.get())
502 theBaseFeatureModified = aFeature;
504 theAfterFeature = aFeature;
507 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
508 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
510 // base split, that is defined before split feature should be changed at end
511 // (after the after feature creation). Otherwise modified value will be used in after feature
512 // before split feature
513 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
514 /// move end arc point to start of split
515 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttr);
516 theBaseFeatureModified->execute(); // to update result
517 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
518 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
519 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
520 theCreatedFeatures.insert(aConstraintFeature);
522 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
523 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
524 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
525 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
528 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
529 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
531 // additional constraints between split and base features
532 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
533 getFeatureResult(aBaseFeature),
534 getFeatureResult(theSplitFeature));
535 theCreatedFeatures.insert(aConstraintFeature);
536 if (theAfterFeature.get()) {
537 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
538 getFeatureResult(aBaseFeature),
539 getFeatureResult(theAfterFeature));
540 theCreatedFeatures.insert(aConstraintFeature);
544 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
545 FeaturePtr& theBaseFeatureModified,
546 FeaturePtr& theAfterFeature,
547 std::set<AttributePoint2DPtr>& thePoints,
548 std::set<FeaturePtr>& theCreatedFeatures)
550 std::set<FeaturePtr> aCreatedFeatures;
551 FeaturePtr aConstraintFeature;
552 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
554 SketchPlugin_Sketch* aSketch = sketch();
558 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
559 data()->attribute(SketchPlugin_Constraint::VALUE()));
560 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
561 std::string aFeatureKind = aBaseFeature->getKind();
562 if (aFeatureKind != SketchPlugin_Arc::ID())
565 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
566 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
567 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
568 getFeaturePoints(aStartPointAttr, anEndPointAttr);
569 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
570 setError("Error: Feature has no start and end points.");
574 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
577 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
578 theCreatedFeatures.insert(theSplitFeature);
580 // before split feature
581 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
582 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
583 /// move end arc point to start of split
586 // after split feature
587 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
589 if (!theBaseFeatureModified.get()) {
590 aFeature = aBaseFeature; ///< use base feature to store all constraints here
591 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr);
592 aFeature->execute(); // to update result
595 aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
596 theCreatedFeatures.insert(aFeature);
598 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
599 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
600 aFeature->attribute(SketchPlugin_Arc::START_ID()));
601 theCreatedFeatures.insert(aConstraintFeature);
603 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
604 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
605 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
606 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
608 if (!theBaseFeatureModified.get())
609 theBaseFeatureModified = aFeature;
611 theAfterFeature = aFeature;
614 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
615 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
617 // base split, that is defined before split feature should be changed at end
618 // (after the after feature creation). Otherwise modified value will be used in after feature
619 // before split feature
620 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
621 /// move end arc point to start of split
622 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr);
623 theBaseFeatureModified->execute(); // to update result
624 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
625 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
626 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
627 theCreatedFeatures.insert(aConstraintFeature);
629 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
630 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
631 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
632 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
635 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
636 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
638 // additional constraints between split and base features
639 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
640 getFeatureResult(aBaseFeature),
641 getFeatureResult(theSplitFeature));
642 theCreatedFeatures.insert(aConstraintFeature);
643 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
644 getFeatureResult(theSplitFeature),
645 getFeatureResult(aBaseFeature));
646 theCreatedFeatures.insert(aConstraintFeature);
647 if (theAfterFeature.get()) {
648 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
649 getFeatureResult(aBaseFeature),
650 getFeatureResult(theAfterFeature));
651 theCreatedFeatures.insert(aConstraintFeature);
652 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
653 getFeatureResult(theSplitFeature),
654 getFeatureResult(theAfterFeature));
655 theCreatedFeatures.insert(aConstraintFeature);
659 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
660 FeaturePtr& theBaseFeatureModified,
661 FeaturePtr& theAfterFeature,
662 std::set<AttributePoint2DPtr>& thePoints,
663 std::set<FeaturePtr>& theCreatedFeatures)
665 std::set<FeaturePtr> aCreatedFeatures;
666 FeaturePtr aConstraintFeature;
667 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
669 SketchPlugin_Sketch* aSketch = sketch();
673 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
674 data()->attribute(SketchPlugin_Constraint::VALUE()));
675 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
676 std::string aFeatureKind = aBaseFeature->getKind();
677 if (aFeatureKind != SketchPlugin_Circle::ID())
680 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
681 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
684 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
685 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
686 theCreatedFeatures.insert(theSplitFeature);
688 /// base feature is a left part of the circle
689 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
690 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
691 theBaseFeatureModified->execute();
692 theCreatedFeatures.insert(theBaseFeatureModified);
694 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
695 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
696 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
697 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
699 // additional constraints between split and base features
700 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
701 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
702 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
703 theCreatedFeatures.insert(aConstraintFeature);
704 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
705 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
706 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
707 theCreatedFeatures.insert(aConstraintFeature);
709 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
710 getFeatureResult(theSplitFeature),
711 getFeatureResult(theBaseFeatureModified));
712 theCreatedFeatures.insert(aConstraintFeature);
715 void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr,
716 const AttributePoint2DPtr& theEndPointAttr,
717 AttributePoint2DPtr& theFirstPointAttr,
718 AttributePoint2DPtr& theLastPointAttr)
720 /// if first point is closer to last point, wrap first and last values
721 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
722 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
723 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
724 theFirstPointAttr = theLastPointAttr;
725 theLastPointAttr = aTmpPoint;
729 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
730 const AttributePtr& theSourceAttribute)
732 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
733 theModifiedAttribute);
734 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
737 if (aModifiedAttribute.get() && aSourceAttribute.get())
738 aModifiedAttribute->setValue(aSourceAttribute->pnt());
741 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
742 const AttributePtr& theFirstPointAttr,
743 const AttributePtr& theSecondPointAttr)
746 SketchPlugin_Sketch* aSketch = sketch();
747 if (!aSketch || !theBaseFeature.get())
750 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
751 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
752 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
753 aFeature->data()->blockSendAttributeUpdated(true);
755 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
756 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
757 aFeature->data()->blockSendAttributeUpdated(false);
758 aFeature->execute(); // to obtain result
763 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
764 const AttributePtr& theFirstPointAttr,
765 const AttributePtr& theSecondPointAttr)
768 SketchPlugin_Sketch* aSketch = sketch();
769 if (!aSketch || !theBaseFeature.get())
772 std::string aCenterAttributeId;
773 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
774 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
775 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
776 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
778 if (aCenterAttributeId.empty())
781 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
782 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
783 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
784 aFeature->data()->blockSendAttributeUpdated(true);
786 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
787 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
789 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
790 theBaseFeature->attribute(aCenterAttributeId));
791 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
792 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
793 aFeature->data()->blockSendAttributeUpdated(false);
794 aFeature->execute(); // to obtain result
799 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
800 const AttributePtr& theFirstAttribute,
801 const AttributePtr& theSecondAttribute)
803 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
804 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
805 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
806 aRefAttr->setAttr(theFirstAttribute);
808 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
809 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
810 aRefAttr->setAttr(theSecondAttribute);
815 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
816 const ObjectPtr& theFirstObject,
817 const ObjectPtr& theSecondObject)
819 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
820 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
821 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
822 aRefAttr->setObject(theFirstObject);
824 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
825 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
826 aRefAttr->setObject(theSecondObject);
831 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
832 const std::shared_ptr<ModelAPI_Feature>& theFeature)
834 std::shared_ptr<ModelAPI_Result> aResult;
836 std::string aFeatureKind = theFeature->getKind();
837 if (aFeatureKind == SketchPlugin_Line::ID())
838 aResult = theFeature->firstResult();
839 else if (aFeatureKind == SketchPlugin_Arc::ID())
840 aResult = theFeature->lastResult();
841 else if (aFeatureKind == SketchPlugin_Circle::ID())
842 aResult = theFeature->lastResult();
847 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
848 const std::shared_ptr<ModelAPI_Feature>& theFeature)
850 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
852 std::string aFeatureKind = theFeature->getKind();
853 if (aFeatureKind == SketchPlugin_Line::ID()) {
854 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
855 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
857 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
858 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
859 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
861 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
868 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
869 const std::shared_ptr<ModelAPI_Feature>& theFeature,
870 const bool isUseAttributesInfo)
873 if (!theFeature.get()) {
877 //anInfo.append(theFeature->getKind().c_str());
878 if (theFeature->data()->isValid()) {
879 //anInfo.append(", name=");
880 anInfo.append(theFeature->data()->name().c_str());
882 if (isUseAttributesInfo) {
883 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
884 getEdgeAttributes(theFeature));
885 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
888 anInfo += aPointsInfo;
890 else { /// process constraint coincidence, find points in ref attr attributes
891 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
892 ModelAPI_AttributeRefAttr::typeId());
893 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
894 std::string anAttributesInfo;
895 for(; anIt != aLast; anIt++) {
896 if (!anAttributesInfo.empty()) {
897 anAttributesInfo.append(", ");
898 anAttributesInfo += "\n";
900 AttributePtr anAttr = *anIt;
901 std::string aValue = "not defined";
902 std::string aType = anAttr->attributeType();
903 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
904 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
905 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
906 if (aRefAttr.get()) {
907 if (aRefAttr->isObject()) {
908 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
909 aValue = "<object:>" + getFeatureInfo(aFeature, false);
912 AttributePtr anAttribute = aRefAttr->attr();
913 if (anAttribute.get()) {
914 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
915 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
916 " [" + getFeatureInfo(aFeature, false) + "]";
921 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
923 if (!anAttributesInfo.empty())
924 anInfo = anInfo + "\n" + anAttributesInfo;