1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_ConstraintSplit.cpp
4 // Created: 25 Aug 2016
5 // Author: Natalia ERMOLAEVA
7 #include "SketchPlugin_ConstraintSplit.h"
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <GeomAlgoAPI_ShapeTools.h>
15 #include <ModelAPI_AttributeReference.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_AttributeRefAttr.h>
18 #include <ModelAPI_Tools.h>
19 #include <ModelAPI_AttributeBoolean.h>
21 #include <ModelAPI_Validator.h>
22 #include <ModelAPI_Session.h>
23 #include <ModelAPI_AttributeDouble.h>
25 #include <SketchPlugin_Line.h>
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_ConstraintCoincidence.h>
29 #include <SketchPlugin_ConstraintEqual.h>
30 #include <SketchPlugin_ConstraintParallel.h>
31 #include <SketchPlugin_ConstraintTangent.h>
32 #include <SketchPlugin_ConstraintLength.h>
33 #include <SketchPlugin_ConstraintMirror.h>
34 #include <SketchPlugin_MultiRotation.h>
35 #include <SketchPlugin_MultiTranslation.h>
36 #include <SketchPlugin_ConstraintMiddle.h>
38 #include <ModelAPI_Events.h>
39 #include <SketchPlugin_Line.h>
40 #include <SketchPlugin_Arc.h>
41 #include <SketchPlugin_Circle.h>
43 #include <ModelGeomAlgo_Point2D.h>
44 #include <Events_Loop.h>
48 //#define CREATE_CONSTRAINTS
55 static const double PI = 3.141592653589793238463;
57 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
61 void SketchPlugin_ConstraintSplit::initAttributes()
63 data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
64 data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
65 data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
68 void SketchPlugin_ConstraintSplit::execute()
70 std::shared_ptr<ModelAPI_Data> aData = data();
72 // Check the base objects are initialized.
73 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
74 aData->attribute(SketchPlugin_Constraint::VALUE()));
75 if(!aBaseObjectAttr->isInitialized()) {
76 setError("Error: Base object is not initialized.");
79 AttributePoint2DPtr aFirstPointAttrOfSplit =
80 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
81 AttributePoint2DPtr aSecondPointAttrOfSplit =
82 getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
83 if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
84 !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
85 setError("Error: Sub-shape is not initialized.");
89 // Wait all constraints being created, then send update events
90 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
91 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
93 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
96 // Find feature constraints
97 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
98 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
99 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
101 std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
102 std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
103 getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
105 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
106 std::list<AttributePtr> aRefsToFeature;
107 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
109 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
112 std::cout << std::endl;
113 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
114 std::cout << std::endl;
116 SketchPlugin_Sketch* aSketch = sketch();
117 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
118 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
119 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
122 std::cout << std::endl;
123 std::cout << "---- IN PARAMETERS ----" << std::endl;
124 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
125 std::cout << std::endl;
127 if (!aCoincidenceToFeature.empty()) {
128 std::cout << "Coincidences to base feature[" <<
129 aCoincidenceToFeature.size() << "]: " << std::endl;
130 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
131 aLast = aCoincidenceToFeature.end();
132 for (int i = 1; anIt != aLast; anIt++, i++) {
133 FeaturePtr aFeature = (*anIt).first;
134 std::string anAttributeId = (*anIt).second.first;
135 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
137 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
138 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
139 std::cout << " -Point attribute:" <<
140 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
144 if (!aTangentFeatures.empty()) {
145 std::cout << std::endl;
146 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
147 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
148 aLast = aTangentFeatures.end();
149 for (int i = 1; anIt != aLast; anIt++, i++) {
150 FeaturePtr aFeature = (*anIt).first;
151 std::string anAttributeId = (*anIt).second.first;
152 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
154 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
155 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
156 std::cout << " -Point attribute:" <<
157 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
161 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
162 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
163 std::cout << std::endl << "References to attributes of base feature [" <<
164 aBaseRefAttributes.size() << "]" << std::endl;
165 for (; aRefIt != aRefLast; aRefIt++) {
166 AttributePtr aBaseAttr = aRefIt->first;
167 std::list<AttributePtr> aRefAttributes = aRefIt->second;
168 std::string aRefsInfo;
169 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
170 aRefAttrLast = aRefAttributes.end();
171 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
172 if (!aRefsInfo.empty())
173 aRefsInfo.append(",");
174 AttributePtr aRAttr = *aRefAttrIt;
175 aRefsInfo.append(aRAttr->id());
176 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
177 aRefsInfo.append("(" + aRFeature->name() + ") ");
179 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
180 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
181 std::cout << aPointAttr->id().c_str() <<
182 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
184 std::cout << std::endl;
185 std::cout << std::endl << "References to base feature [" <<
186 aRefsToFeature.size() << "]" << std::endl;
187 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
188 aRefAttrLast = aRefsToFeature.end();
189 std::string aRefsInfo;
190 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
191 if (!aRefsInfo.empty())
192 aRefsInfo.append(",");
193 AttributePtr aRAttr = *aRefAttrIt;
194 aRefsInfo.append(aRAttr->id());
195 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
196 aRefsInfo.append("(" + aRFeature->name() + ") ");
198 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
201 std::cout << std::endl;
202 std::cout << "---- SPLIT ----" << std::endl;
203 std::cout << std::endl;
206 std::string aFeatureKind = aBaseFeature->getKind();
207 FeaturePtr aSplitFeature, anAfterFeature;
208 std::set<AttributePoint2DPtr> aFurtherCoincidences;
209 std::set<FeaturePtr> aCreatedFeatures;
210 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
211 if (aFeatureKind == SketchPlugin_Line::ID())
212 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
213 aModifiedAttributes);
214 else if (aFeatureKind == SketchPlugin_Arc::ID())
215 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
216 aModifiedAttributes);
217 if (aFeatureKind == SketchPlugin_Circle::ID()) {
218 FeaturePtr aCircleFeature = aBaseFeature;
219 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
220 aCreatedFeatures, aModifiedAttributes);
222 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
224 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
225 aFeaturesToDelete.insert(aCircleFeature);
226 // as circle is removed, temporary fill this attribute*/
227 aBaseObjectAttr->setObject(ResultPtr());
231 std::cout << "---- OUT PARAMETERS ----" << std::endl;
232 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
233 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
234 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
235 std::cout << std::endl;
237 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
238 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
239 aFLast = aCreatedFeatures.end();
240 for (; aFIt != aFLast; aFIt++) {
241 std::cout << getFeatureInfo(*aFIt) << std::endl;
243 std::cout << std::endl;
245 std::cout << "Attributes for further Coincidences:" << std::endl;
246 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
247 aLast = aFurtherCoincidences.end();
248 for (; anIt != aLast; anIt++) {
249 AttributePtr anAttribute = *anIt;
250 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
251 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
252 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
255 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
256 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
257 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
258 std::string aResInfo;
259 for (; aPIt != aPLast; aPIt++) {
260 if (!aResInfo.empty())
263 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
265 AttributePtr anAttr = aPair.first;
266 aResInfo.append(anAttr->id());
267 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
268 aResInfo.append("(" + aFeature->name() + ") ");
270 aResInfo.append(" - is modified to - ");
272 anAttr = aPair.second;
273 aResInfo.append(anAttr->id());
274 aFeature = ModelAPI_Feature::feature(anAttr->owner());
275 aResInfo.append("(" + aFeature->name() + ") ");
277 std::cout << aResInfo << std::endl;
280 std::set<ResultPtr> aFeatureResults;
281 aFeatureResults.insert(getFeatureResult(aBaseFeature));
282 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
283 aFeatureResults.insert(getFeatureResult(anAfterFeature));
285 // coincidence to feature
286 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
287 aFeatureResults, aSplitFeature);
289 updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
291 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
293 // delete constraints
295 std::cout << "remove features and references:" << std::endl;
296 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
297 aDLast = aFeaturesToDelete.end();
298 for (; aDIt != aDLast; aDIt++) {
299 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
300 std::cout << std::endl;
303 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
304 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
307 std::cout << "update features after split:" << std::endl;
308 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
309 anULast = aFeaturesToUpdate.end();
310 for (; anUIt != anULast; anUIt++) {
311 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
312 std::cout << std::endl;
315 updateFeaturesAfterSplit(aFeaturesToUpdate);
317 // Send events to update the sub-features by the solver.
318 if(isUpdateFlushed) {
319 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
323 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
324 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
325 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
330 bool SketchPlugin_ConstraintSplit::isMacro() const
335 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
337 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
338 data()->attribute(SketchPlugin_Constraint::VALUE()));
339 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
341 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
342 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
343 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
344 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
346 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
347 aFirstPointAttrOfSplit->isInitialized() &&
348 aSecondPointAttrOfSplit->isInitialized()) {
350 ResultPtr aResult = getFeatureResult(aBaseFeature);
351 GeomShapePtr aBaseShape = aResult->shape();
352 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
354 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
355 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
356 aPoints.push_back(aStartPoint);
358 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
359 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
360 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
361 aPoints.push_back(aSecondPoint);
363 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
365 GeomAlgoAPI_ShapeTools::splitShape_p(aBaseShape, aPoints, aSplitShapes);
366 std::shared_ptr<GeomAPI_Shape> aShape =
367 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
369 AISObjectPtr anAIS = thePrevious;
372 anAIS = AISObjectPtr(new GeomAPI_AISObject);
373 anAIS->createShape(aShape);
374 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
375 aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
377 bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
379 std::vector<int> aColor;
380 double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
381 int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
382 if (isConstruction) {
383 aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color",
384 SKETCH_AUXILIARY_COLOR);
385 aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
386 aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
389 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
390 SKETCH_ENTITY_COLOR);
392 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
393 anAIS->setWidth(aWidth + 1);
394 anAIS->setLineStyle(aLineStyle);
398 return AISObjectPtr();
401 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
402 const AttributePtr& theAttribute)
404 AttributePoint2DPtr aPointAttribute;
406 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
407 AttributeRefAttrPtr aRefAttr =
408 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
409 if (aRefAttr.get() && aRefAttr->isInitialized()) {
410 AttributePtr anAttribute = aRefAttr->attr();
411 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
412 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
415 return aPointAttribute;
418 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
419 AttributePoint2DPtr& theStartPointAttr,
420 AttributePoint2DPtr& theEndPointAttr)
422 std::string aFeatureKind = theFeature->getKind();
423 std::string aStartAttributeName, anEndAttributeName;
424 if (aFeatureKind == SketchPlugin_Line::ID()) {
425 aStartAttributeName = SketchPlugin_Line::START_ID();
426 anEndAttributeName = SketchPlugin_Line::END_ID();
428 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
429 aStartAttributeName = SketchPlugin_Arc::START_ID();
430 anEndAttributeName = SketchPlugin_Arc::END_ID();
432 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
433 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
434 theFeature->attribute(aStartAttributeName));
435 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
436 theFeature->attribute(anEndAttributeName));
440 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
441 std::set<FeaturePtr>& theFeaturesToUpdate,
442 std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
443 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
445 std::shared_ptr<ModelAPI_Data> aData = data();
447 // Check the base objects are initialized.
448 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
449 aData->attribute(SketchPlugin_Constraint::VALUE()));
450 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
451 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
453 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
454 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
455 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
457 std::set<AttributePtr>::const_iterator aIt;
458 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
459 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
460 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
461 std::string aRefFeatureKind = aRefFeature->getKind();
462 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
463 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
464 aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
465 aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
466 theFeaturesToDelete.insert(aRefFeature);
467 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
468 theFeaturesToUpdate.insert(aRefFeature);
469 else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
470 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
471 /// until tangency between arc and line is implemented
472 theFeaturesToDelete.insert(aRefFeature);
474 std::string anAttributeToBeModified;
475 AttributePoint2DPtr aTangentPoint;
476 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
477 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
478 if (aResult1.get() && aResult2.get()) {
479 FeaturePtr aCoincidenceFeature =
480 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
481 (ModelAPI_Feature::feature(aResult1),
482 ModelAPI_Feature::feature(aResult2));
483 // get the point not lying on the splitting feature
484 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
485 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
486 if (!aRefAttr || aRefAttr->isObject())
488 AttributePoint2DPtr aPoint =
489 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
492 if (aPoint->owner() != aBaseFeature) {
493 aTangentPoint = aPoint;
498 if (aTangentPoint.get()) {
499 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
500 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
501 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
502 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
504 else /// there is not coincident point between tangent constraint
505 theFeaturesToDelete.insert(aRefFeature);
508 else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
509 std::string anAttributeToBeModified;
510 AttributePoint2DPtr aCoincidentPoint;
511 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
512 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
513 bool isToFeature = false;
514 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
515 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
517 isToFeature = aFeature.get() && aFeature == aBaseFeature;
518 anAttributeToBeModified = anAttrA->id();
520 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
522 isToFeature = aFeature.get() && aFeature == aBaseFeature;
523 anAttributeToBeModified = anAttrB->id();
526 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
528 if (!isToFeature) { /// coincidence to point on base feature
529 AttributePtr anAttribute;
531 if (!anAttrA->isObject()) {
532 AttributePtr aCurAttribute = anAttrA->attr();
533 if (aCurAttribute.get()) {
534 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
535 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
536 anAttribute = anAttrB->attr();
537 anAttributeToBeModified = anAttrA->id();
541 if (!anAttribute.get() && !anAttrB->isObject()) {
542 AttributePtr aCurAttribute = anAttrB->attr();
543 if (aCurAttribute.get()) {
544 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
545 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
546 anAttribute = anAttrA->attr();
547 anAttributeToBeModified = anAttrB->id();
551 if (anAttribute.get())
552 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
554 if (aCoincidentPoint.get() && isToFeature)
555 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
561 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
562 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
563 std::list<AttributePtr>& theRefsToFeature)
567 std::list<AttributePtr> aPointAttributes =
568 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
569 std::set<AttributePtr> aPointAttributesSet;
571 std::list<AttributePtr>::const_iterator aPIt =
572 aPointAttributes.begin(), aPLast = aPointAttributes.end();
573 for (; aPIt != aPLast; aPIt++)
574 aPointAttributesSet.insert(*aPIt);
576 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
577 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
578 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
580 std::set<AttributePtr>::const_iterator aIt;
581 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
582 AttributePtr anAttr = (*aIt);
583 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
584 if (anAttrFeature.get() != this &&
585 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
586 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
587 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
588 AttributePtr anAttrInRef = aRefAttr->attr();
589 if (anAttrInRef.get() &&
590 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
591 if (theRefs.find(anAttrInRef) != theRefs.end())
592 theRefs[anAttrInRef].push_back(aRefAttr);
594 std::list<AttributePtr> anAttrList;
595 anAttrList.push_back(aRefAttr);
596 theRefs[anAttrInRef] = anAttrList;
600 else { /// find attributes referenced to feature itself
601 theRefsToFeature.push_back(anAttr);
607 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
608 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
609 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
610 const std::set<ResultPtr>& theFeatureResults,
611 const FeaturePtr& theSplitFeature)
613 if (theCoincidenceToFeature.empty())
616 // we should build coincidence constraints to end of the split feature
617 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
618 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
619 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
620 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
621 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
622 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
623 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
625 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
626 aCLast = theCoincidenceToFeature.end();
628 std::cout << std::endl;
629 std::cout << "Coincidences to feature(modified):"<< std::endl;
631 for (; aCIt != aCLast; aCIt++) {
632 FeaturePtr aCoincFeature = aCIt->first;
633 std::string anAttributeId = aCIt->second.first;
634 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
635 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
636 aFCLast = theFurtherCoincidences.end();
637 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
638 AttributePoint2DPtr aFeaturePointAttribute;
639 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
640 AttributePoint2DPtr aFCAttribute = *aFCIt;
641 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
642 aFeaturePointAttribute = aFCAttribute;
644 if (aFeaturePointAttribute.get()) {
645 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
646 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
647 // create new coincidences to split feature points
648 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
649 aSFLast = aNewCoincidencesToSplitFeature.end();
650 for (; aSFIt != aSFLast; aSFIt++) {
651 AttributePoint2DPtr aSFAttribute = *aSFIt;
652 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
653 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
654 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
655 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
656 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
657 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
662 /// find feature by shape intersected the point
663 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
665 if (theFeatureResults.size() > 1) { // try to find point on additional feature
666 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
667 GeomShapePtr aShape = anAddtionalResult->shape();
669 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
670 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
672 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
673 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
674 aResultForCoincidence = anAddtionalResult;
676 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
679 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
684 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
685 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
686 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
688 if (theTangentFeatures.empty())
691 std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
692 aTLast = theTangentFeatures.end();
694 std::cout << std::endl;
695 std::cout << "Tangencies to feature(modified):"<< std::endl;
697 for (; aTIt != aTLast; aTIt++) {
698 FeaturePtr aTangentFeature = aTIt->first;
699 std::string anAttributeId = aTIt->second.first;
700 AttributePoint2DPtr aTangentPoint = aTIt->second.second;
701 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
702 aFCLast = theFurtherCoincidences.end();
703 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
704 AttributePoint2DPtr aFeaturePointAttribute;
705 /// here we rely on created coincidence between further coincidence point and tangent result
706 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
707 AttributePoint2DPtr aFCAttribute = *aFCIt;
708 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
709 aFeaturePointAttribute = aFCAttribute;
711 if (aFeaturePointAttribute.get()) {
712 FeaturePtr aFeature =
713 std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
714 aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
717 std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
722 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
723 const ResultPtr& theFeatureBaseResult,
724 const std::list<AttributePtr>& theRefsToFeature)
726 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
727 aLast = theRefsToFeature.end();
728 for (; anIt != aLast; anIt++) {
729 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
731 aRefAttr->setObject(theFeatureBaseResult);
735 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
736 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
737 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
740 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
743 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
744 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
745 for (; anIt != aLast; anIt++) {
746 AttributePtr anAttribute = anIt->first;
748 /// not found in references
749 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
751 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
752 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
753 aRLast = aRefAttributes.end();
755 AttributePtr aNewAttribute = anIt->second;
756 for (; aRefIt != aRLast; aRefIt++) {
757 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
758 if (aRefAttr.get()) {
759 aRefAttr->setAttr(aNewAttribute);
761 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
762 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
769 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
770 FeaturePtr& theBaseFeatureModified,
771 FeaturePtr& theAfterFeature,
772 std::set<AttributePoint2DPtr>& thePoints,
773 std::set<FeaturePtr>& theCreatedFeatures,
774 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
776 std::set<FeaturePtr> aCreatedFeatures;
777 FeaturePtr aConstraintFeature;
778 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
780 SketchPlugin_Sketch* aSketch = sketch();
784 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
785 data()->attribute(SketchPlugin_Constraint::VALUE()));
786 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
787 std::string aFeatureKind = aBaseFeature->getKind();
788 if (aFeatureKind != SketchPlugin_Line::ID())
791 AttributePoint2DPtr aFirstPointAttrOfSplit =
792 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
793 AttributePoint2DPtr aSecondPointAttrOfSplit =
794 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
795 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
797 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
798 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
799 setError("Error: Feature has no start and end points.");
803 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
804 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
807 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
808 std::cout << "Start point: " <<
809 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
810 std::cout << "1st point: " <<
811 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
812 std::cout << "2nd point: " <<
813 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
814 std::cout << "End point: " <<
815 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
818 /// create a split feature
820 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
821 theCreatedFeatures.insert(theSplitFeature);
823 // before split feature
824 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
825 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
826 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
829 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
830 /// move end arc point to start of split
833 // after split feature
834 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
836 if (!theBaseFeatureModified.get()) {
837 aFeature = aBaseFeature; ///< use base feature to store all constraints here
838 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
839 aFeature->execute(); // to update result
842 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
843 theCreatedFeatures.insert(aFeature);
844 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
845 aFeature->attribute(SketchPlugin_Line::END_ID())));
847 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
848 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
849 aFeature->attribute(SketchPlugin_Line::START_ID()));
850 theCreatedFeatures.insert(aConstraintFeature);
852 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
853 (aFeature->attribute(SketchPlugin_Line::START_ID())));
854 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
855 (aFeature->attribute(SketchPlugin_Line::END_ID())));
857 if (!theBaseFeatureModified.get())
858 theBaseFeatureModified = aFeature;
860 theAfterFeature = aFeature;
863 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
864 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
865 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
866 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
868 // base split, that is defined before split feature should be changed at end
869 // (after the after feature creation). Otherwise modified value will be used in after feature
870 // before split feature
871 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
872 /// move end arc point to start of split
873 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
874 aFirstPointAttrOfSplit);
875 theBaseFeatureModified->execute(); // to update result
876 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
877 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
878 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
879 theCreatedFeatures.insert(aConstraintFeature);
881 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
882 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
883 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
884 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
887 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
888 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
890 #ifdef CREATE_CONSTRAINTS
891 // additional constraints between split and base features
892 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
893 getFeatureResult(aBaseFeature),
894 getFeatureResult(theSplitFeature));
895 theCreatedFeatures.insert(aConstraintFeature);
896 if (theAfterFeature.get()) {
897 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
898 getFeatureResult(aBaseFeature),
899 getFeatureResult(theAfterFeature));
900 theCreatedFeatures.insert(aConstraintFeature);
905 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
906 FeaturePtr& theBaseFeatureModified,
907 FeaturePtr& theAfterFeature,
908 std::set<AttributePoint2DPtr>& thePoints,
909 std::set<FeaturePtr>& theCreatedFeatures,
910 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
912 std::set<FeaturePtr> aCreatedFeatures;
913 FeaturePtr aConstraintFeature;
914 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
916 SketchPlugin_Sketch* aSketch = sketch();
920 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
921 data()->attribute(SketchPlugin_Constraint::VALUE()));
922 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
923 std::string aFeatureKind = aBaseFeature->getKind();
924 if (aFeatureKind != SketchPlugin_Arc::ID())
927 AttributePoint2DPtr aFirstPointAttrOfSplit =
928 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
929 AttributePoint2DPtr aSecondPointAttrOfSplit =
930 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
931 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
932 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
933 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
934 setError("Error: Feature has no start and end points.");
938 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
939 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
940 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
942 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
943 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
945 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
946 std::cout << "Start point: " <<
947 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
948 std::cout << "1st point: " <<
949 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
950 std::cout << "2nd point: " <<
951 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
952 std::cout << "End point: " <<
953 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
957 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
958 theCreatedFeatures.insert(theSplitFeature);
960 // before split feature
961 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
962 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
963 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
966 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
967 /// move end arc point to start of split
970 // after split feature
971 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
973 if (!theBaseFeatureModified.get()) {
974 aFeature = aBaseFeature; ///< use base feature to store all constraints here
975 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
976 aFeature->execute(); // to update result
979 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
980 theCreatedFeatures.insert(aFeature);
981 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
982 aFeature->attribute(SketchPlugin_Arc::END_ID())));
984 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
985 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
986 aFeature->attribute(SketchPlugin_Arc::START_ID()));
987 theCreatedFeatures.insert(aConstraintFeature);
989 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
990 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
991 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
992 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
994 if (!theBaseFeatureModified.get())
995 theBaseFeatureModified = aFeature;
997 theAfterFeature = aFeature;
1000 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1001 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1002 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1003 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1005 // base split, that is defined before split feature should be changed at end
1006 // (after the after feature creation). Otherwise modified value will be used in after feature
1007 // before split feature
1008 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1009 /// move end arc point to start of split
1010 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1011 aFirstPointAttrOfSplit);
1012 theBaseFeatureModified->execute(); // to update result
1013 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1014 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1015 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1016 theCreatedFeatures.insert(aConstraintFeature);
1018 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1019 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1020 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1021 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1024 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1025 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1027 // additional constraints between split and base features
1028 #ifdef CREATE_CONSTRAINTS
1029 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1030 getFeatureResult(aBaseFeature),
1031 getFeatureResult(theSplitFeature));
1032 theCreatedFeatures.insert(aConstraintFeature);
1033 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1034 getFeatureResult(theSplitFeature),
1035 getFeatureResult(aBaseFeature));
1036 theCreatedFeatures.insert(aConstraintFeature);
1037 if (theAfterFeature.get()) {
1038 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1039 getFeatureResult(aBaseFeature),
1040 getFeatureResult(theAfterFeature));
1041 theCreatedFeatures.insert(aConstraintFeature);
1042 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1043 getFeatureResult(theSplitFeature),
1044 getFeatureResult(theAfterFeature));
1045 theCreatedFeatures.insert(aConstraintFeature);
1050 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1051 FeaturePtr& theBaseFeatureModified,
1052 FeaturePtr& theAfterFeature,
1053 std::set<AttributePoint2DPtr>& thePoints,
1054 std::set<FeaturePtr>& theCreatedFeatures,
1055 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1057 std::set<FeaturePtr> aCreatedFeatures;
1058 FeaturePtr aConstraintFeature;
1059 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1061 SketchPlugin_Sketch* aSketch = sketch();
1065 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1066 data()->attribute(SketchPlugin_Constraint::VALUE()));
1067 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1068 std::string aFeatureKind = aBaseFeature->getKind();
1069 if (aFeatureKind != SketchPlugin_Circle::ID())
1072 AttributePoint2DPtr aFirstPointAttrOfSplit =
1073 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1074 AttributePoint2DPtr aSecondPointAttrOfSplit =
1075 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1079 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1080 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1081 theCreatedFeatures.insert(theSplitFeature);
1083 /// base feature is a left part of the circle
1084 theBaseFeatureModified = createArcFeature(aBaseFeature,
1085 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1086 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1087 theBaseFeatureModified)->setReversed(!aSplitReversed);
1088 theBaseFeatureModified->execute();
1090 theModifiedAttributes.insert(
1091 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1092 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1094 theCreatedFeatures.insert(theBaseFeatureModified);
1096 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1097 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1098 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1099 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1101 // additional constraints between split and base features
1102 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1103 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1104 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1105 theCreatedFeatures.insert(aConstraintFeature);
1106 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1107 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1108 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1109 theCreatedFeatures.insert(aConstraintFeature);
1111 #ifdef CREATE_CONSTRAINTS
1112 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1113 getFeatureResult(theSplitFeature),
1114 getFeatureResult(theBaseFeatureModified));
1115 theCreatedFeatures.insert(aConstraintFeature);
1119 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1120 const AttributePoint2DPtr& theStartPointAttr,
1121 const AttributePoint2DPtr& theEndPointAttr,
1122 AttributePoint2DPtr& theFirstPointAttr,
1123 AttributePoint2DPtr& theLastPointAttr) const
1125 // if first point is closer to last point, swap first and last values
1126 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1127 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1128 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1129 theFirstPointAttr = theLastPointAttr;
1130 theLastPointAttr = aTmpPoint;
1134 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1135 const FeaturePtr& theArc,
1136 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1137 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1138 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1139 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1141 static const double anAngleTol = 1.e-12;
1143 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1144 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1145 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1147 // collect directions to each point
1148 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1149 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1150 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1151 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1152 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1153 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1155 // sort points by their angular values
1156 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1157 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1158 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1159 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1160 aFirstPtAngle += aPeriod;
1161 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1162 aSecondPtAngle += aPeriod;
1164 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1165 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1166 theFirstPointAttr = theSecondPointAttr;
1167 theSecondPointAttr = aTmpPoint;
1171 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1172 const AttributePtr& theSourceAttribute)
1174 std::string anAttributeType = theModifiedAttribute->attributeType();
1175 if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1176 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1177 theModifiedAttribute);
1178 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1179 theSourceAttribute);
1181 if (aModifiedAttribute.get() && aSourceAttribute.get())
1182 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1184 else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1185 AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1186 theModifiedAttribute);
1187 AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1188 theSourceAttribute);
1190 if (aModifiedAttribute.get() && aSourceAttribute.get())
1191 aModifiedAttribute->setValue(aSourceAttribute->value());
1195 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1196 const AttributePtr& theFirstPointAttr,
1197 const AttributePtr& theSecondPointAttr)
1199 FeaturePtr aFeature;
1200 SketchPlugin_Sketch* aSketch = sketch();
1201 if (!aSketch || !theBaseFeature.get())
1204 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1206 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1207 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1209 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1210 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1212 aFeature->execute(); // to obtain result
1217 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1218 const AttributePtr& theFirstPointAttr,
1219 const AttributePtr& theSecondPointAttr)
1221 FeaturePtr aFeature;
1222 SketchPlugin_Sketch* aSketch = sketch();
1223 if (!aSketch || !theBaseFeature.get())
1226 std::string aCenterAttributeId;
1227 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1228 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1229 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1230 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1232 if (aCenterAttributeId.empty())
1235 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1236 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1237 // the "attribute updated"
1238 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1239 bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
1241 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1242 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1244 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1245 theBaseFeature->attribute(aCenterAttributeId));
1246 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1247 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1249 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1250 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1252 /// fill referersed state of created arc as it is on the base arc
1253 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1254 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1255 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1257 aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
1258 aFeature->execute(); // to obtain result
1263 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1264 const AttributePtr& theFirstAttribute,
1265 const AttributePtr& theSecondAttribute)
1267 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1268 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1269 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1270 aRefAttr->setAttr(theFirstAttribute);
1272 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1273 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1274 aRefAttr->setAttr(theSecondAttribute);
1279 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1280 const std::string& theConstraintId,
1281 const ObjectPtr& theFirstObject,
1282 const ObjectPtr& theSecondObject)
1284 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1285 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1286 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1287 aRefAttr->setObject(theFirstObject);
1289 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1290 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1291 aRefAttr->setObject(theSecondObject);
1296 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1297 const std::set<FeaturePtr>& theFeaturesToUpdate)
1299 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1300 aLast = theFeaturesToUpdate.end();
1301 for (; anIt != aLast; anIt++) {
1302 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1303 std::string aRefFeatureKind = aRefFeature->getKind();
1304 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1305 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1306 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1307 if (aLenghtFeature.get()) {
1308 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1309 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1311 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1312 aValueAttr->setValue(aValue);
1318 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1319 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1321 std::shared_ptr<ModelAPI_Result> aResult;
1323 std::string aFeatureKind = theFeature->getKind();
1324 if (aFeatureKind == SketchPlugin_Line::ID())
1325 aResult = theFeature->firstResult();
1326 else if (aFeatureKind == SketchPlugin_Arc::ID())
1327 aResult = theFeature->lastResult();
1328 else if (aFeatureKind == SketchPlugin_Circle::ID())
1329 aResult = theFeature->lastResult();
1334 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1335 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1337 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1339 std::string aFeatureKind = theFeature->getKind();
1340 if (aFeatureKind == SketchPlugin_Line::ID()) {
1341 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1342 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1344 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1345 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1346 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1348 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1351 return anAttributes;
1355 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1356 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1357 const bool isUseAttributesInfo)
1360 if (!theFeature.get()) {
1364 if (theFeature->data()->isValid())
1365 anInfo.append(theFeature->data()->name().c_str());
1367 if (isUseAttributesInfo) {
1368 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1369 getEdgeAttributes(theFeature));
1370 /// processing of feature with point 2d attributes, like line, arc, circle
1371 if (!aPointsInfo.empty()) {
1374 anInfo += aPointsInfo;
1376 else { /// process constraint coincidence, find points in ref attr attributes
1377 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1378 ModelAPI_AttributeRefAttr::typeId());
1379 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1380 std::string anAttributesInfo;
1381 for(; anIt != aLast; anIt++) {
1382 if (!anAttributesInfo.empty()) {
1383 anAttributesInfo.append(", ");
1384 anAttributesInfo += "\n";
1386 AttributePtr anAttr = *anIt;
1387 std::string aValue = "not defined";
1388 std::string aType = anAttr->attributeType();
1389 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1390 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1391 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1392 if (aRefAttr.get()) {
1393 if (aRefAttr->isObject()) {
1394 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1395 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1398 AttributePtr anAttribute = aRefAttr->attr();
1399 if (anAttribute.get()) {
1400 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1401 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1402 " [" + getFeatureInfo(aFeature, false) + "]";
1407 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1409 if (!anAttributesInfo.empty())
1410 anInfo = anInfo + "\n" + anAttributesInfo;