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 (!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;
155 std::cout << std::endl;
156 std::cout << "---- SPLIT ----" << std::endl;
157 std::cout << std::endl;
160 std::string aFeatureKind = aBaseFeature->getKind();
161 FeaturePtr aSplitFeature, anAfterFeature;
162 std::set<AttributePoint2DPtr> aFurtherCoincidences;
163 std::set<FeaturePtr> aCreatedFeatures;
164 if (aFeatureKind == SketchPlugin_Line::ID())
165 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
166 else if (aFeatureKind == SketchPlugin_Arc::ID())
167 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
168 if (aFeatureKind == SketchPlugin_Circle::ID()) {
169 FeaturePtr aCircleFeature = aBaseFeature;
170 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
171 aFeaturesToDelete.insert(aCircleFeature);
172 aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute
176 std::cout << "OUT PARAMETERS" << std::endl;
177 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
178 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
179 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
180 std::cout << std::endl;
182 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
183 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
184 aFLast = aCreatedFeatures.end();
185 for (; aFIt != aFLast; aFIt++) {
186 std::cout << getFeatureInfo(*aFIt) << std::endl;
188 std::cout << std::endl;
190 std::cout << "Attributes for further Coincidences:" << std::endl;
191 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
192 aLast = aFurtherCoincidences.end();
193 for (; anIt != aLast; anIt++) {
194 AttributePtr anAttribute = *anIt;
195 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
196 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
197 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
201 std::set<ResultPtr> aFeatureResults;
202 aFeatureResults.insert(getFeatureResult(aBaseFeature));
203 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
204 aFeatureResults.insert(getFeatureResult(anAfterFeature));
206 // coincidence to feature
207 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
209 // coincidence to points
210 updateCoincidenceConstraintsToFeature(aCoincidenceToPoint, aFurtherCoincidences,
211 std::set<ResultPtr>());
213 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
215 // delete constraints
217 std::cout << "remove features and references:" << std::endl;
218 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
219 aDLast = aFeaturesToDelete.end();
220 for (; aDIt != aDLast; aDIt++) {
221 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
222 std::cout << std::endl;
225 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
227 // Send events to update the sub-features by the solver.
228 if(isUpdateFlushed) {
229 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
233 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
234 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
235 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
240 bool SketchPlugin_ConstraintSplit::isMacro() const
245 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
246 const AttributePtr& theAttribute)
248 AttributePoint2DPtr aPointAttribute;
250 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
251 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
252 if (aRefAttr.get() && aRefAttr->isInitialized()) {
253 AttributePtr anAttribute = aRefAttr->attr();
254 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
255 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
258 return aPointAttribute;
261 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
262 AttributePoint2DPtr& theEndPointAttr)
264 AttributePoint2DPtr aPointAttribute;
266 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
267 data()->attribute(SketchPlugin_Constraint::VALUE()));
268 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
270 std::string aFeatureKind = aBaseFeature->getKind();
271 std::string aStartAttributeName, anEndAttributeName;
272 if (aFeatureKind == SketchPlugin_Line::ID()) {
273 aStartAttributeName = SketchPlugin_Line::START_ID();
274 anEndAttributeName = SketchPlugin_Line::END_ID();
276 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
277 aStartAttributeName = SketchPlugin_Arc::START_ID();
278 anEndAttributeName = SketchPlugin_Arc::END_ID();
280 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
281 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
282 aBaseFeature->attribute(aStartAttributeName));
283 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
284 aBaseFeature->attribute(anEndAttributeName));
288 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
289 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
290 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature,
291 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToPoint)
293 std::shared_ptr<ModelAPI_Data> aData = data();
295 // Check the base objects are initialized.
296 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
297 aData->attribute(SketchPlugin_Constraint::VALUE()));
298 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
299 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
301 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
302 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
303 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
305 std::set<AttributePtr>::const_iterator aIt;
306 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
307 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
308 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
309 std::string aRefFeatureKind = aRefFeature->getKind();
310 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
311 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
312 aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
313 theFeaturesToDelete.insert(aRefFeature);
314 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
315 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
316 theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
318 std::string anAttributeToBeModified;
319 AttributePoint2DPtr aTangentPoint;
320 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
321 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
322 if (aResult1.get() && aResult2.get()) {
323 FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
324 (ModelAPI_Feature::feature(aResult1),
325 ModelAPI_Feature::feature(aResult2));
326 aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature);
328 if (aTangentPoint.get()) {
329 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
330 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
331 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
332 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
335 theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
338 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
339 std::string anAttributeToBeModified;
340 AttributePoint2DPtr aCoincidentPoint;
341 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
342 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
343 bool isToFeature = false;
344 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
345 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
347 isToFeature = aFeature.get() && aFeature == aBaseFeature;
348 anAttributeToBeModified = anAttrA->id();
350 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
352 isToFeature = aFeature.get() && aFeature == aBaseFeature;
353 anAttributeToBeModified = anAttrB->id();
356 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
358 if (!isToFeature) { /// coincidence to point on base feature
359 AttributePtr anAttribute;
361 if (!anAttrA->isObject()) {
362 AttributePtr aCurAttribute = anAttrA->attr();
363 if (aCurAttribute.get()) {
364 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
365 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
366 anAttribute = anAttrB->attr();
367 anAttributeToBeModified = anAttrA->id();
371 if (!anAttribute.get() && !anAttrB->isObject()) {
372 AttributePtr aCurAttribute = anAttrB->attr();
373 if (aCurAttribute.get()) {
374 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
375 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
376 anAttribute = anAttrA->attr();
377 anAttributeToBeModified = anAttrB->id();
381 if (anAttribute.get())
382 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
384 if (aCoincidentPoint.get()) {
386 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
389 theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified,
393 theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
398 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
399 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
400 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
401 const std::set<ResultPtr>& theFeatureResults)
403 if (theCoincidenceToFeature.empty())
406 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
407 aCLast = theCoincidenceToFeature.end();
409 std::cout << std::endl;
410 std::cout << "Coincidences to feature(modified):"<< std::endl;
412 for (; aCIt != aCLast; aCIt++) {
413 FeaturePtr aCoincFeature = aCIt->first;
414 std::string anAttributeId = aCIt->second.first;
415 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
416 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
417 aFCLast = theFurtherCoincidences.end();
418 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
419 AttributePoint2DPtr aFeaturePointAttribute;
420 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
421 AttributePoint2DPtr aFCAttribute = *aFCIt;
422 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
423 aFeaturePointAttribute = aFCAttribute;
425 if (aFeaturePointAttribute.get()) {
426 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
429 /// find feature by shape intersected the point
430 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
432 if (theFeatureResults.size() > 1) { // try to find point on additional feature
433 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
434 GeomShapePtr aShape = anAddtionalResult->shape();
436 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
437 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
439 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
440 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
441 aResultForCoincidence = anAddtionalResult;
443 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
446 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
451 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
452 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
453 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
455 if (theTangentFeatures.empty())
458 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
459 aTLast = theTangentFeatures.end();
461 std::cout << std::endl;
462 std::cout << "Tangencies to feature(modified):"<< std::endl;
464 for (; aTIt != aTLast; aTIt++) {
465 FeaturePtr aTangentFeature = aTIt->first;
466 std::string anAttributeId = aTIt->second.first;
467 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
468 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
469 aFCLast = theFurtherCoincidences.end();
470 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
471 AttributePoint2DPtr aFeaturePointAttribute;
472 /// here we rely on created coincidence between further coincidence point and tangent result
473 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
474 AttributePoint2DPtr aFCAttribute = *aFCIt;
475 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
476 aFeaturePointAttribute = aFCAttribute;
478 if (aFeaturePointAttribute.get()) {
479 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
480 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
483 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
488 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
489 FeaturePtr& theBaseFeatureModified,
490 FeaturePtr& theAfterFeature,
491 std::set<AttributePoint2DPtr>& thePoints,
492 std::set<FeaturePtr>& theCreatedFeatures)
494 std::set<FeaturePtr> aCreatedFeatures;
495 FeaturePtr aConstraintFeature;
496 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
498 SketchPlugin_Sketch* aSketch = sketch();
502 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
503 data()->attribute(SketchPlugin_Constraint::VALUE()));
504 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
505 std::string aFeatureKind = aBaseFeature->getKind();
506 if (aFeatureKind != SketchPlugin_Line::ID())
509 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
510 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
511 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
512 getFeaturePoints(aStartPointAttr, anEndPointAttr);
513 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
514 setError("Error: Feature has no start and end points.");
518 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
521 theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
522 theCreatedFeatures.insert(theSplitFeature);
524 // before split feature
525 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
526 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
527 /// move end arc point to start of split
530 // after split feature
531 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
533 if (!theBaseFeatureModified.get()) {
534 aFeature = aBaseFeature; ///< use base feature to store all constraints here
535 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttr);
536 aFeature->execute(); // to update result
539 aFeature = createLineFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
540 theCreatedFeatures.insert(aFeature);
542 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
543 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
544 aFeature->attribute(SketchPlugin_Line::START_ID()));
545 theCreatedFeatures.insert(aConstraintFeature);
547 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
548 (aFeature->attribute(SketchPlugin_Line::START_ID())));
549 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
550 (aFeature->attribute(SketchPlugin_Line::END_ID())));
552 if (!theBaseFeatureModified.get())
553 theBaseFeatureModified = aFeature;
555 theAfterFeature = aFeature;
558 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
559 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
561 // base split, that is defined before split feature should be changed at end
562 // (after the after feature creation). Otherwise modified value will be used in after feature
563 // before split feature
564 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
565 /// move end arc point to start of split
566 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttr);
567 theBaseFeatureModified->execute(); // to update result
568 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
569 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
570 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
571 theCreatedFeatures.insert(aConstraintFeature);
573 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
574 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
575 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
576 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
579 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
580 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
582 // additional constraints between split and base features
583 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
584 getFeatureResult(aBaseFeature),
585 getFeatureResult(theSplitFeature));
586 theCreatedFeatures.insert(aConstraintFeature);
587 if (theAfterFeature.get()) {
588 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
589 getFeatureResult(aBaseFeature),
590 getFeatureResult(theAfterFeature));
591 theCreatedFeatures.insert(aConstraintFeature);
595 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
596 FeaturePtr& theBaseFeatureModified,
597 FeaturePtr& theAfterFeature,
598 std::set<AttributePoint2DPtr>& thePoints,
599 std::set<FeaturePtr>& theCreatedFeatures)
601 std::set<FeaturePtr> aCreatedFeatures;
602 FeaturePtr aConstraintFeature;
603 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
605 SketchPlugin_Sketch* aSketch = sketch();
609 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
610 data()->attribute(SketchPlugin_Constraint::VALUE()));
611 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
612 std::string aFeatureKind = aBaseFeature->getKind();
613 if (aFeatureKind != SketchPlugin_Arc::ID())
616 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
617 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
618 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
619 getFeaturePoints(aStartPointAttr, anEndPointAttr);
620 if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
621 setError("Error: Feature has no start and end points.");
625 arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
628 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
629 theCreatedFeatures.insert(theSplitFeature);
631 // before split feature
632 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
633 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
634 /// move end arc point to start of split
637 // after split feature
638 if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
640 if (!theBaseFeatureModified.get()) {
641 aFeature = aBaseFeature; ///< use base feature to store all constraints here
642 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr);
643 aFeature->execute(); // to update result
646 aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
647 theCreatedFeatures.insert(aFeature);
649 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
650 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
651 aFeature->attribute(SketchPlugin_Arc::START_ID()));
652 theCreatedFeatures.insert(aConstraintFeature);
654 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
655 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
656 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
657 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
659 if (!theBaseFeatureModified.get())
660 theBaseFeatureModified = aFeature;
662 theAfterFeature = aFeature;
665 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
666 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
668 // base split, that is defined before split feature should be changed at end
669 // (after the after feature creation). Otherwise modified value will be used in after feature
670 // before split feature
671 if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
672 /// move end arc point to start of split
673 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr);
674 theBaseFeatureModified->execute(); // to update result
675 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
676 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
677 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
678 theCreatedFeatures.insert(aConstraintFeature);
680 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
681 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
682 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
683 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
686 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
687 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
689 // additional constraints between split and base features
690 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
691 getFeatureResult(aBaseFeature),
692 getFeatureResult(theSplitFeature));
693 theCreatedFeatures.insert(aConstraintFeature);
694 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
695 getFeatureResult(theSplitFeature),
696 getFeatureResult(aBaseFeature));
697 theCreatedFeatures.insert(aConstraintFeature);
698 if (theAfterFeature.get()) {
699 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
700 getFeatureResult(aBaseFeature),
701 getFeatureResult(theAfterFeature));
702 theCreatedFeatures.insert(aConstraintFeature);
703 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
704 getFeatureResult(theSplitFeature),
705 getFeatureResult(theAfterFeature));
706 theCreatedFeatures.insert(aConstraintFeature);
710 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
711 FeaturePtr& theBaseFeatureModified,
712 FeaturePtr& theAfterFeature,
713 std::set<AttributePoint2DPtr>& thePoints,
714 std::set<FeaturePtr>& theCreatedFeatures)
716 std::set<FeaturePtr> aCreatedFeatures;
717 FeaturePtr aConstraintFeature;
718 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
720 SketchPlugin_Sketch* aSketch = sketch();
724 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
725 data()->attribute(SketchPlugin_Constraint::VALUE()));
726 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
727 std::string aFeatureKind = aBaseFeature->getKind();
728 if (aFeatureKind != SketchPlugin_Circle::ID())
731 AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
732 AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
735 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
736 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
737 theCreatedFeatures.insert(theSplitFeature);
739 /// base feature is a left part of the circle
740 theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
741 std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
742 theBaseFeatureModified->execute();
743 theCreatedFeatures.insert(theBaseFeatureModified);
745 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
746 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
747 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
748 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
750 // additional constraints between split and base features
751 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
752 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
753 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
754 theCreatedFeatures.insert(aConstraintFeature);
755 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
756 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
757 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
758 theCreatedFeatures.insert(aConstraintFeature);
760 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
761 getFeatureResult(theSplitFeature),
762 getFeatureResult(theBaseFeatureModified));
763 theCreatedFeatures.insert(aConstraintFeature);
766 void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr,
767 const AttributePoint2DPtr& theEndPointAttr,
768 AttributePoint2DPtr& theFirstPointAttr,
769 AttributePoint2DPtr& theLastPointAttr)
771 /// if first point is closer to last point, wrap first and last values
772 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
773 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
774 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
775 theFirstPointAttr = theLastPointAttr;
776 theLastPointAttr = aTmpPoint;
780 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
781 const AttributePtr& theSourceAttribute)
783 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
784 theModifiedAttribute);
785 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
788 if (aModifiedAttribute.get() && aSourceAttribute.get())
789 aModifiedAttribute->setValue(aSourceAttribute->pnt());
792 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
793 const AttributePtr& theFirstPointAttr,
794 const AttributePtr& theSecondPointAttr)
797 SketchPlugin_Sketch* aSketch = sketch();
798 if (!aSketch || !theBaseFeature.get())
801 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
802 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
803 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
804 aFeature->data()->blockSendAttributeUpdated(true);
806 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
807 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
808 aFeature->data()->blockSendAttributeUpdated(false);
809 aFeature->execute(); // to obtain result
814 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
815 const AttributePtr& theFirstPointAttr,
816 const AttributePtr& theSecondPointAttr)
819 SketchPlugin_Sketch* aSketch = sketch();
820 if (!aSketch || !theBaseFeature.get())
823 std::string aCenterAttributeId;
824 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
825 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
826 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
827 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
829 if (aCenterAttributeId.empty())
832 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
833 // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
834 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
835 aFeature->data()->blockSendAttributeUpdated(true);
837 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
838 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
840 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
841 theBaseFeature->attribute(aCenterAttributeId));
842 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
843 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
844 aFeature->data()->blockSendAttributeUpdated(false);
845 aFeature->execute(); // to obtain result
850 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
851 const AttributePtr& theFirstAttribute,
852 const AttributePtr& theSecondAttribute)
854 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
855 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
856 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
857 aRefAttr->setAttr(theFirstAttribute);
859 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
860 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
861 aRefAttr->setAttr(theSecondAttribute);
866 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
867 const ObjectPtr& theFirstObject,
868 const ObjectPtr& theSecondObject)
870 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
871 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
872 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
873 aRefAttr->setObject(theFirstObject);
875 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
876 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
877 aRefAttr->setObject(theSecondObject);
882 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
883 const std::shared_ptr<ModelAPI_Feature>& theFeature)
885 std::shared_ptr<ModelAPI_Result> aResult;
887 std::string aFeatureKind = theFeature->getKind();
888 if (aFeatureKind == SketchPlugin_Line::ID())
889 aResult = theFeature->firstResult();
890 else if (aFeatureKind == SketchPlugin_Arc::ID())
891 aResult = theFeature->lastResult();
892 else if (aFeatureKind == SketchPlugin_Circle::ID())
893 aResult = theFeature->lastResult();
898 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
899 const std::shared_ptr<ModelAPI_Feature>& theFeature)
901 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
903 std::string aFeatureKind = theFeature->getKind();
904 if (aFeatureKind == SketchPlugin_Line::ID()) {
905 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
906 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
908 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
909 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
910 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
912 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
919 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
920 const std::shared_ptr<ModelAPI_Feature>& theFeature,
921 const bool isUseAttributesInfo)
924 if (!theFeature.get()) {
928 //anInfo.append(theFeature->getKind().c_str());
929 if (theFeature->data()->isValid()) {
930 //anInfo.append(", name=");
931 anInfo.append(theFeature->data()->name().c_str());
933 if (isUseAttributesInfo) {
934 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
935 getEdgeAttributes(theFeature));
936 if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
939 anInfo += aPointsInfo;
941 else { /// process constraint coincidence, find points in ref attr attributes
942 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
943 ModelAPI_AttributeRefAttr::typeId());
944 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
945 std::string anAttributesInfo;
946 for(; anIt != aLast; anIt++) {
947 if (!anAttributesInfo.empty()) {
948 anAttributesInfo.append(", ");
949 anAttributesInfo += "\n";
951 AttributePtr anAttr = *anIt;
952 std::string aValue = "not defined";
953 std::string aType = anAttr->attributeType();
954 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
955 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
956 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
957 if (aRefAttr.get()) {
958 if (aRefAttr->isObject()) {
959 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
960 aValue = "<object:>" + getFeatureInfo(aFeature, false);
963 AttributePtr anAttribute = aRefAttr->attr();
964 if (anAttribute.get()) {
965 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
966 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
967 " [" + getFeatureInfo(aFeature, false) + "]";
972 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
974 if (!anAttributesInfo.empty())
975 anInfo = anInfo + "\n" + anAttributesInfo;