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, */
104 aCoincidenceToFeature);
106 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
107 std::list<AttributePtr> aRefsToFeature;
108 getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
110 std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
113 std::cout << std::endl;
114 std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
115 std::cout << std::endl;
117 SketchPlugin_Sketch* aSketch = sketch();
118 std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
119 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
120 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
123 std::cout << std::endl;
124 std::cout << "---- IN PARAMETERS ----" << std::endl;
125 std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
126 std::cout << std::endl;
128 if (!aCoincidenceToFeature.empty()) {
129 std::cout << "Coincidences to base feature[" <<
130 aCoincidenceToFeature.size() << "]: " << std::endl;
131 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
132 aLast = aCoincidenceToFeature.end();
133 for (int i = 1; anIt != aLast; anIt++, i++) {
134 FeaturePtr aFeature = (*anIt).first;
135 std::string anAttributeId = (*anIt).second.first;
136 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
138 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
139 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
140 std::cout << " -Point attribute:" <<
141 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
145 /*if (!aTangentFeatures.empty()) {
146 std::cout << std::endl;
147 std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
148 std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
149 aLast = aTangentFeatures.end();
150 for (int i = 1; anIt != aLast; anIt++, i++) {
151 FeaturePtr aFeature = (*anIt).first;
152 std::string anAttributeId = (*anIt).second.first;
153 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
155 std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
156 std::cout << " -Attribute to correct:" << anAttributeId << std::endl;
157 std::cout << " -Point attribute:" <<
158 ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
162 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
163 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
164 std::cout << std::endl << "References to attributes of base feature [" <<
165 aBaseRefAttributes.size() << "]" << std::endl;
166 for (; aRefIt != aRefLast; aRefIt++) {
167 AttributePtr aBaseAttr = aRefIt->first;
168 std::list<AttributePtr> aRefAttributes = aRefIt->second;
169 std::string aRefsInfo;
170 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
171 aRefAttrLast = aRefAttributes.end();
172 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
173 if (!aRefsInfo.empty())
174 aRefsInfo.append(",");
175 AttributePtr aRAttr = *aRefAttrIt;
176 aRefsInfo.append(aRAttr->id());
177 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
178 aRefsInfo.append("(" + aRFeature->name() + ") ");
180 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
181 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
182 std::cout << aPointAttr->id().c_str() <<
183 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
185 std::cout << std::endl;
186 std::cout << std::endl << "References to base feature [" <<
187 aRefsToFeature.size() << "]" << std::endl;
188 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
189 aRefAttrLast = aRefsToFeature.end();
190 std::string aRefsInfo;
191 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
192 if (!aRefsInfo.empty())
193 aRefsInfo.append(",");
194 AttributePtr aRAttr = *aRefAttrIt;
195 aRefsInfo.append(aRAttr->id());
196 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
197 aRefsInfo.append("(" + aRFeature->name() + ") ");
199 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
202 std::cout << std::endl;
203 std::cout << "---- SPLIT ----" << std::endl;
204 std::cout << std::endl;
207 std::string aFeatureKind = aBaseFeature->getKind();
208 FeaturePtr aSplitFeature, anAfterFeature;
209 std::set<AttributePoint2DPtr> aFurtherCoincidences;
210 std::set<FeaturePtr> aCreatedFeatures;
211 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
212 if (aFeatureKind == SketchPlugin_Line::ID())
213 splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
214 aModifiedAttributes);
215 else if (aFeatureKind == SketchPlugin_Arc::ID())
216 splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
217 aModifiedAttributes);
218 if (aFeatureKind == SketchPlugin_Circle::ID()) {
219 FeaturePtr aCircleFeature = aBaseFeature;
220 splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
221 aCreatedFeatures, aModifiedAttributes);
223 updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
225 AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
226 aFeaturesToDelete.insert(aCircleFeature);
227 // as circle is removed, temporary fill this attribute*/
228 aBaseObjectAttr->setObject(ResultPtr());
232 std::cout << "---- OUT PARAMETERS ----" << std::endl;
233 std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
234 std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
235 std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
236 std::cout << std::endl;
238 std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
239 std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
240 aFLast = aCreatedFeatures.end();
241 for (; aFIt != aFLast; aFIt++) {
242 std::cout << getFeatureInfo(*aFIt) << std::endl;
244 std::cout << std::endl;
246 std::cout << "Attributes for further Coincidences:" << std::endl;
247 std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
248 aLast = aFurtherCoincidences.end();
249 for (; anIt != aLast; anIt++) {
250 AttributePtr anAttribute = *anIt;
251 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
252 std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
253 << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
256 std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
257 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
258 aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
259 std::string aResInfo;
260 for (; aPIt != aPLast; aPIt++) {
261 if (!aResInfo.empty())
264 std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
266 AttributePtr anAttr = aPair.first;
267 aResInfo.append(anAttr->id());
268 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
269 aResInfo.append("(" + aFeature->name() + ") ");
271 aResInfo.append(" - is modified to - ");
273 anAttr = aPair.second;
274 aResInfo.append(anAttr->id());
275 aFeature = ModelAPI_Feature::feature(anAttr->owner());
276 aResInfo.append("(" + aFeature->name() + ") ");
278 std::cout << aResInfo << std::endl;
281 std::set<ResultPtr> aFeatureResults;
282 aFeatureResults.insert(getFeatureResult(aBaseFeature));
283 if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
284 aFeatureResults.insert(getFeatureResult(anAfterFeature));
286 // coincidence to feature
287 updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
288 aFeatureResults, aSplitFeature);
290 //updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
292 updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
294 // delete constraints
296 std::cout << "remove features and references:" << std::endl;
297 std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
298 aDLast = aFeaturesToDelete.end();
299 for (; aDIt != aDLast; aDIt++) {
300 std::cout << getFeatureInfo(*aDIt, false) << std::endl;
301 std::cout << std::endl;
304 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
305 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
308 std::cout << "update features after split:" << std::endl;
309 std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
310 anULast = aFeaturesToUpdate.end();
311 for (; anUIt != anULast; anUIt++) {
312 std::cout << getFeatureInfo(*anUIt, false) << std::endl;
313 std::cout << std::endl;
316 updateFeaturesAfterSplit(aFeaturesToUpdate);
318 // Send events to update the sub-features by the solver.
319 if(isUpdateFlushed) {
320 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
324 std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
325 for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
326 std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
331 bool SketchPlugin_ConstraintSplit::isMacro() const
336 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
338 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
339 data()->attribute(SketchPlugin_Constraint::VALUE()));
340 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
342 AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
343 data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
344 AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
345 data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
347 if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
348 aFirstPointAttrOfSplit->isInitialized() &&
349 aSecondPointAttrOfSplit->isInitialized()) {
351 ResultPtr aResult = getFeatureResult(aBaseFeature);
352 GeomShapePtr aBaseShape = aResult->shape();
353 std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
355 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
356 std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
357 aPoints.push_back(aStartPoint);
359 std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
360 std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
361 sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
362 aPoints.push_back(aSecondPoint);
364 std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
366 GeomAlgoAPI_ShapeTools::splitShape_p(aBaseShape, aPoints, aSplitShapes);
367 std::shared_ptr<GeomAPI_Shape> aShape =
368 GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
370 AISObjectPtr anAIS = thePrevious;
373 anAIS = AISObjectPtr(new GeomAPI_AISObject);
374 anAIS->createShape(aShape);
375 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
376 aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
378 bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
380 std::vector<int> aColor;
381 double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
382 int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
383 if (isConstruction) {
384 aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color",
385 SKETCH_AUXILIARY_COLOR);
386 aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
387 aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
390 aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
391 SKETCH_ENTITY_COLOR);
393 anAIS->setColor(aColor[0], aColor[1], aColor[2]);
394 anAIS->setWidth(aWidth + 1);
395 anAIS->setLineStyle(aLineStyle);
399 return AISObjectPtr();
402 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
403 const AttributePtr& theAttribute)
405 AttributePoint2DPtr aPointAttribute;
407 if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
408 AttributeRefAttrPtr aRefAttr =
409 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
410 if (aRefAttr.get() && aRefAttr->isInitialized()) {
411 AttributePtr anAttribute = aRefAttr->attr();
412 if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
413 aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
416 return aPointAttribute;
419 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
420 AttributePoint2DPtr& theStartPointAttr,
421 AttributePoint2DPtr& theEndPointAttr)
423 std::string aFeatureKind = theFeature->getKind();
424 std::string aStartAttributeName, anEndAttributeName;
425 if (aFeatureKind == SketchPlugin_Line::ID()) {
426 aStartAttributeName = SketchPlugin_Line::START_ID();
427 anEndAttributeName = SketchPlugin_Line::END_ID();
429 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
430 aStartAttributeName = SketchPlugin_Arc::START_ID();
431 anEndAttributeName = SketchPlugin_Arc::END_ID();
433 if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
434 theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
435 theFeature->attribute(aStartAttributeName));
436 theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
437 theFeature->attribute(anEndAttributeName));
441 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
442 std::set<FeaturePtr>& theFeaturesToUpdate,
443 //std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
444 std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
446 std::shared_ptr<ModelAPI_Data> aData = data();
448 // Check the base objects are initialized.
449 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
450 aData->attribute(SketchPlugin_Constraint::VALUE()));
451 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
452 ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
454 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
455 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
456 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
458 std::set<AttributePtr>::const_iterator aIt;
459 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
460 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
461 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
462 std::string aRefFeatureKind = aRefFeature->getKind();
463 if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
464 aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
465 aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
466 aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
467 theFeaturesToDelete.insert(aRefFeature);
468 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
469 theFeaturesToUpdate.insert(aRefFeature);
470 /*else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
471 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
472 /// until tangency between arc and line is implemented
473 theFeaturesToDelete.insert(aRefFeature);
475 std::string anAttributeToBeModified;
476 AttributePoint2DPtr aTangentPoint;
477 ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
478 ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
479 if (aResult1.get() && aResult2.get()) {
480 FeaturePtr aCoincidenceFeature =
481 SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
482 (ModelAPI_Feature::feature(aResult1),
483 ModelAPI_Feature::feature(aResult2));
484 // get the point not lying on the splitting feature
485 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
486 AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
487 if (!aRefAttr || aRefAttr->isObject())
489 AttributePoint2DPtr aPoint =
490 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
493 if (aPoint->owner() != aBaseFeature) {
494 aTangentPoint = aPoint;
499 if (aTangentPoint.get()) {
500 FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
501 std::string anAttributeToBeModified = aFeature1 == aBaseFeature
502 ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
503 theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
505 else /// there is not coincident point between tangent constraint
506 theFeaturesToDelete.insert(aRefFeature);
509 */else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
510 std::string anAttributeToBeModified;
511 AttributePoint2DPtr aCoincidentPoint;
512 AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
513 AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
514 bool isToFeature = false;
515 if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
516 FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
518 isToFeature = aFeature.get() && aFeature == aBaseFeature;
519 anAttributeToBeModified = anAttrA->id();
521 aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
523 isToFeature = aFeature.get() && aFeature == aBaseFeature;
524 anAttributeToBeModified = anAttrB->id();
527 aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
529 if (!isToFeature) { /// coincidence to point on base feature
530 AttributePtr anAttribute;
532 if (!anAttrA->isObject()) {
533 AttributePtr aCurAttribute = anAttrA->attr();
534 if (aCurAttribute.get()) {
535 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
536 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
537 anAttribute = anAttrB->attr();
538 anAttributeToBeModified = anAttrA->id();
542 if (!anAttribute.get() && !anAttrB->isObject()) {
543 AttributePtr aCurAttribute = anAttrB->attr();
544 if (aCurAttribute.get()) {
545 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
546 if (aCurFeature.get() && aCurFeature == aBaseFeature) {
547 anAttribute = anAttrA->attr();
548 anAttributeToBeModified = anAttrB->id();
552 if (anAttribute.get())
553 aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
555 if (aCoincidentPoint.get() && isToFeature)
556 theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
562 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
563 std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
564 std::list<AttributePtr>& theRefsToFeature)
568 std::list<AttributePtr> aPointAttributes =
569 theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
570 std::set<AttributePtr> aPointAttributesSet;
572 std::list<AttributePtr>::const_iterator aPIt =
573 aPointAttributes.begin(), aPLast = aPointAttributes.end();
574 for (; aPIt != aPLast; aPIt++)
575 aPointAttributesSet.insert(*aPIt);
577 std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
578 std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
579 aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
581 std::set<AttributePtr>::const_iterator aIt;
582 for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
583 AttributePtr anAttr = (*aIt);
584 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
585 if (anAttrFeature.get() != this &&
586 anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
587 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
588 if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
589 AttributePtr anAttrInRef = aRefAttr->attr();
590 if (anAttrInRef.get() &&
591 aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
592 if (theRefs.find(anAttrInRef) != theRefs.end())
593 theRefs[anAttrInRef].push_back(aRefAttr);
595 std::list<AttributePtr> anAttrList;
596 anAttrList.push_back(aRefAttr);
597 theRefs[anAttrInRef] = anAttrList;
601 else { /// find attributes referenced to feature itself
602 theRefsToFeature.push_back(anAttr);
608 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
609 const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
610 const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
611 const std::set<ResultPtr>& theFeatureResults,
612 const FeaturePtr& theSplitFeature)
614 if (theCoincidenceToFeature.empty())
617 // we should build coincidence constraints to end of the split feature
618 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
619 AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
620 getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
621 if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
622 aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
623 if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
624 aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
626 std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
627 aCLast = theCoincidenceToFeature.end();
629 std::cout << std::endl;
630 std::cout << "Coincidences to feature(modified):"<< std::endl;
632 for (; aCIt != aCLast; aCIt++) {
633 FeaturePtr aCoincFeature = aCIt->first;
634 std::string anAttributeId = aCIt->second.first;
635 AttributePoint2DPtr aCoincPoint = aCIt->second.second;
636 std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
637 aFCLast = theFurtherCoincidences.end();
638 std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
639 AttributePoint2DPtr aFeaturePointAttribute;
640 for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
641 AttributePoint2DPtr aFCAttribute = *aFCIt;
642 if (aCoincPnt->isEqual(aFCAttribute->pnt()))
643 aFeaturePointAttribute = aFCAttribute;
645 if (aFeaturePointAttribute.get()) {
646 aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
647 aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
648 // create new coincidences to split feature points
649 std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
650 aSFLast = aNewCoincidencesToSplitFeature.end();
651 for (; aSFIt != aSFLast; aSFIt++) {
652 AttributePoint2DPtr aSFAttribute = *aSFIt;
653 if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
654 std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
655 if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
656 aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
657 createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
658 aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
663 /// find feature by shape intersected the point
664 ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
666 if (theFeatureResults.size() > 1) { // try to find point on additional feature
667 ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
668 GeomShapePtr aShape = anAddtionalResult->shape();
670 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
671 std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
673 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
674 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
675 aResultForCoincidence = anAddtionalResult;
677 aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
680 std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
685 //void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
686 // const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
687 // const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
689 // if (theTangentFeatures.empty())
692 // std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
693 // aTLast = theTangentFeatures.end();
695 // std::cout << std::endl;
696 // std::cout << "Tangencies to feature(modified):"<< std::endl;
698 // for (; aTIt != aTLast; aTIt++) {
699 // FeaturePtr aTangentFeature = aTIt->first;
700 // std::string anAttributeId = aTIt->second.first;
701 // AttributePoint2DPtr aTangentPoint = aTIt->second.second;
702 // std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
703 // aFCLast = theFurtherCoincidences.end();
704 // std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
705 // AttributePoint2DPtr aFeaturePointAttribute;
706 // /// here we rely on created coincidence between further coincidence point and tangent result
707 // for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
708 // AttributePoint2DPtr aFCAttribute = *aFCIt;
709 // if (aCoincPnt->isEqual(aFCAttribute->pnt()))
710 // aFeaturePointAttribute = aFCAttribute;
712 // if (aFeaturePointAttribute.get()) {
713 // FeaturePtr aFeature =
714 // std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
715 // aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
718 // std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
723 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
724 const ResultPtr& theFeatureBaseResult,
725 const std::list<AttributePtr>& theRefsToFeature)
727 std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
728 aLast = theRefsToFeature.end();
729 for (; anIt != aLast; anIt++) {
730 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
732 aRefAttr->setObject(theFeatureBaseResult);
736 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
737 const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
738 const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
741 std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
744 std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
745 anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end();
746 for (; anIt != aLast; anIt++) {
747 AttributePtr anAttribute = anIt->first;
749 /// not found in references
750 if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
752 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
753 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
754 aRLast = aRefAttributes.end();
756 AttributePtr aNewAttribute = anIt->second;
757 for (; aRefIt != aRLast; aRefIt++) {
758 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
759 if (aRefAttr.get()) {
760 aRefAttr->setAttr(aNewAttribute);
762 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
763 std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
770 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
771 FeaturePtr& theBaseFeatureModified,
772 FeaturePtr& theAfterFeature,
773 std::set<AttributePoint2DPtr>& thePoints,
774 std::set<FeaturePtr>& theCreatedFeatures,
775 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
777 std::set<FeaturePtr> aCreatedFeatures;
778 FeaturePtr aConstraintFeature;
779 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
781 SketchPlugin_Sketch* aSketch = sketch();
785 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
786 data()->attribute(SketchPlugin_Constraint::VALUE()));
787 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
788 std::string aFeatureKind = aBaseFeature->getKind();
789 if (aFeatureKind != SketchPlugin_Line::ID())
792 AttributePoint2DPtr aFirstPointAttrOfSplit =
793 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
794 AttributePoint2DPtr aSecondPointAttrOfSplit =
795 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
796 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
798 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
799 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
800 setError("Error: Feature has no start and end points.");
804 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
805 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
808 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
809 std::cout << "Start point: " <<
810 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
811 std::cout << "1st point: " <<
812 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
813 std::cout << "2nd point: " <<
814 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
815 std::cout << "End point: " <<
816 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
819 /// create a split feature
821 createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
822 theCreatedFeatures.insert(theSplitFeature);
824 // before split feature
825 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
826 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
827 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
830 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
831 /// move end arc point to start of split
834 // after split feature
835 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
837 if (!theBaseFeatureModified.get()) {
838 aFeature = aBaseFeature; ///< use base feature to store all constraints here
839 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
840 aFeature->execute(); // to update result
843 aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
844 theCreatedFeatures.insert(aFeature);
845 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
846 aFeature->attribute(SketchPlugin_Line::END_ID())));
848 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
849 theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
850 aFeature->attribute(SketchPlugin_Line::START_ID()));
851 theCreatedFeatures.insert(aConstraintFeature);
853 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
854 (aFeature->attribute(SketchPlugin_Line::START_ID())));
855 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
856 (aFeature->attribute(SketchPlugin_Line::END_ID())));
858 if (!theBaseFeatureModified.get())
859 theBaseFeatureModified = aFeature;
861 theAfterFeature = aFeature;
864 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
865 (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
866 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
867 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
869 // base split, that is defined before split feature should be changed at end
870 // (after the after feature creation). Otherwise modified value will be used in after feature
871 // before split feature
872 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
873 /// move end arc point to start of split
874 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
875 aFirstPointAttrOfSplit);
876 theBaseFeatureModified->execute(); // to update result
877 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
878 theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
879 theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
880 theCreatedFeatures.insert(aConstraintFeature);
882 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
883 (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
884 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
885 (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
888 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
889 (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
891 #ifdef CREATE_CONSTRAINTS
892 // additional constraints between split and base features
893 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
894 getFeatureResult(aBaseFeature),
895 getFeatureResult(theSplitFeature));
896 theCreatedFeatures.insert(aConstraintFeature);
897 if (theAfterFeature.get()) {
898 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
899 getFeatureResult(aBaseFeature),
900 getFeatureResult(theAfterFeature));
901 theCreatedFeatures.insert(aConstraintFeature);
906 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
907 FeaturePtr& theBaseFeatureModified,
908 FeaturePtr& theAfterFeature,
909 std::set<AttributePoint2DPtr>& thePoints,
910 std::set<FeaturePtr>& theCreatedFeatures,
911 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
913 std::set<FeaturePtr> aCreatedFeatures;
914 FeaturePtr aConstraintFeature;
915 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
917 SketchPlugin_Sketch* aSketch = sketch();
921 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
922 data()->attribute(SketchPlugin_Constraint::VALUE()));
923 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
924 std::string aFeatureKind = aBaseFeature->getKind();
925 if (aFeatureKind != SketchPlugin_Arc::ID())
928 AttributePoint2DPtr aFirstPointAttrOfSplit =
929 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
930 AttributePoint2DPtr aSecondPointAttrOfSplit =
931 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
932 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
933 getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
934 if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
935 setError("Error: Feature has no start and end points.");
939 // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
940 aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
941 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
943 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
944 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
946 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
947 std::cout << "Start point: " <<
948 ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
949 std::cout << "1st point: " <<
950 ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
951 std::cout << "2nd point: " <<
952 ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
953 std::cout << "End point: " <<
954 ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
958 theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
959 theCreatedFeatures.insert(theSplitFeature);
961 // before split feature
962 if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
963 theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
964 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
967 theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
968 /// move end arc point to start of split
971 // after split feature
972 if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
974 if (!theBaseFeatureModified.get()) {
975 aFeature = aBaseFeature; ///< use base feature to store all constraints here
976 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
977 aFeature->execute(); // to update result
980 aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
981 theCreatedFeatures.insert(aFeature);
982 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
983 aFeature->attribute(SketchPlugin_Arc::END_ID())));
985 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
986 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
987 aFeature->attribute(SketchPlugin_Arc::START_ID()));
988 theCreatedFeatures.insert(aConstraintFeature);
990 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
991 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
992 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
993 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
995 if (!theBaseFeatureModified.get())
996 theBaseFeatureModified = aFeature;
998 theAfterFeature = aFeature;
1001 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1002 (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1003 theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1004 theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1006 // base split, that is defined before split feature should be changed at end
1007 // (after the after feature creation). Otherwise modified value will be used in after feature
1008 // before split feature
1009 if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1010 /// move end arc point to start of split
1011 fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1012 aFirstPointAttrOfSplit);
1013 theBaseFeatureModified->execute(); // to update result
1014 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1015 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1016 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1017 theCreatedFeatures.insert(aConstraintFeature);
1019 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1020 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1021 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1022 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1025 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1026 (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1028 // additional constraints between split and base features
1029 #ifdef CREATE_CONSTRAINTS
1030 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1031 getFeatureResult(aBaseFeature),
1032 getFeatureResult(theSplitFeature));
1033 theCreatedFeatures.insert(aConstraintFeature);
1034 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1035 getFeatureResult(theSplitFeature),
1036 getFeatureResult(aBaseFeature));
1037 theCreatedFeatures.insert(aConstraintFeature);
1038 if (theAfterFeature.get()) {
1039 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1040 getFeatureResult(aBaseFeature),
1041 getFeatureResult(theAfterFeature));
1042 theCreatedFeatures.insert(aConstraintFeature);
1043 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1044 getFeatureResult(theSplitFeature),
1045 getFeatureResult(theAfterFeature));
1046 theCreatedFeatures.insert(aConstraintFeature);
1051 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1052 FeaturePtr& theBaseFeatureModified,
1053 FeaturePtr& theAfterFeature,
1054 std::set<AttributePoint2DPtr>& thePoints,
1055 std::set<FeaturePtr>& theCreatedFeatures,
1056 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1058 std::set<FeaturePtr> aCreatedFeatures;
1059 FeaturePtr aConstraintFeature;
1060 theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1062 SketchPlugin_Sketch* aSketch = sketch();
1066 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1067 data()->attribute(SketchPlugin_Constraint::VALUE()));
1068 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1069 std::string aFeatureKind = aBaseFeature->getKind();
1070 if (aFeatureKind != SketchPlugin_Circle::ID())
1073 AttributePoint2DPtr aFirstPointAttrOfSplit =
1074 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1075 AttributePoint2DPtr aSecondPointAttrOfSplit =
1076 getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1080 createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1081 bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1082 theCreatedFeatures.insert(theSplitFeature);
1084 /// base feature is a left part of the circle
1085 theBaseFeatureModified = createArcFeature(aBaseFeature,
1086 aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1087 std::dynamic_pointer_cast<SketchPlugin_Arc>(
1088 theBaseFeatureModified)->setReversed(!aSplitReversed);
1089 theBaseFeatureModified->execute();
1091 theModifiedAttributes.insert(
1092 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1093 theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1095 theCreatedFeatures.insert(theBaseFeatureModified);
1097 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1098 (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1099 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1100 (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1102 // additional constraints between split and base features
1103 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1104 theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1105 theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1106 theCreatedFeatures.insert(aConstraintFeature);
1107 aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1108 theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1109 theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1110 theCreatedFeatures.insert(aConstraintFeature);
1112 #ifdef CREATE_CONSTRAINTS
1113 aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1114 getFeatureResult(theSplitFeature),
1115 getFeatureResult(theBaseFeatureModified));
1116 theCreatedFeatures.insert(aConstraintFeature);
1120 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1121 const AttributePoint2DPtr& theStartPointAttr,
1122 const AttributePoint2DPtr& theEndPointAttr,
1123 AttributePoint2DPtr& theFirstPointAttr,
1124 AttributePoint2DPtr& theLastPointAttr) const
1126 // if first point is closer to last point, swap first and last values
1127 if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1128 theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1129 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1130 theFirstPointAttr = theLastPointAttr;
1131 theLastPointAttr = aTmpPoint;
1135 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1136 const FeaturePtr& theArc,
1137 const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1138 const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1139 std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1140 std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1142 static const double anAngleTol = 1.e-12;
1144 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1145 theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1146 bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1148 // collect directions to each point
1149 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1150 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1151 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1152 new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1153 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1154 new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1156 // sort points by their angular values
1157 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1158 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1159 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1160 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1161 aFirstPtAngle += aPeriod;
1162 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1163 aSecondPtAngle += aPeriod;
1165 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1166 AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1167 theFirstPointAttr = theSecondPointAttr;
1168 theSecondPointAttr = aTmpPoint;
1172 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1173 const AttributePtr& theSourceAttribute)
1175 std::string anAttributeType = theModifiedAttribute->attributeType();
1176 if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1177 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1178 theModifiedAttribute);
1179 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1180 theSourceAttribute);
1182 if (aModifiedAttribute.get() && aSourceAttribute.get())
1183 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1185 else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1186 AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1187 theModifiedAttribute);
1188 AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1189 theSourceAttribute);
1191 if (aModifiedAttribute.get() && aSourceAttribute.get())
1192 aModifiedAttribute->setValue(aSourceAttribute->value());
1196 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1197 const AttributePtr& theFirstPointAttr,
1198 const AttributePtr& theSecondPointAttr)
1200 FeaturePtr aFeature;
1201 SketchPlugin_Sketch* aSketch = sketch();
1202 if (!aSketch || !theBaseFeature.get())
1205 aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1207 fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1208 fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1210 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1211 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1213 aFeature->execute(); // to obtain result
1218 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1219 const AttributePtr& theFirstPointAttr,
1220 const AttributePtr& theSecondPointAttr)
1222 FeaturePtr aFeature;
1223 SketchPlugin_Sketch* aSketch = sketch();
1224 if (!aSketch || !theBaseFeature.get())
1227 std::string aCenterAttributeId;
1228 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1229 aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1230 else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1231 aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1233 if (aCenterAttributeId.empty())
1236 aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1237 // update fillet arc: make the arc correct for sure, so, it is not needed to process
1238 // the "attribute updated"
1239 // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1240 bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
1242 aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1243 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1245 fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1246 theBaseFeature->attribute(aCenterAttributeId));
1247 fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1248 fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1250 fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1251 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1253 /// fill referersed state of created arc as it is on the base arc
1254 if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1255 bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1256 aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1258 aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
1259 aFeature->execute(); // to obtain result
1264 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1265 const AttributePtr& theFirstAttribute,
1266 const AttributePtr& theSecondAttribute)
1268 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1269 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1270 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1271 aRefAttr->setAttr(theFirstAttribute);
1273 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1274 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1275 aRefAttr->setAttr(theSecondAttribute);
1280 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1281 const std::string& theConstraintId,
1282 const ObjectPtr& theFirstObject,
1283 const ObjectPtr& theSecondObject)
1285 FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1286 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1287 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1288 aRefAttr->setObject(theFirstObject);
1290 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1291 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1292 aRefAttr->setObject(theSecondObject);
1297 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1298 const std::set<FeaturePtr>& theFeaturesToUpdate)
1300 std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1301 aLast = theFeaturesToUpdate.end();
1302 for (; anIt != aLast; anIt++) {
1303 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1304 std::string aRefFeatureKind = aRefFeature->getKind();
1305 if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1306 std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1307 std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1308 if (aLenghtFeature.get()) {
1309 std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1310 ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1312 if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1313 aValueAttr->setValue(aValue);
1319 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1320 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1322 std::shared_ptr<ModelAPI_Result> aResult;
1324 std::string aFeatureKind = theFeature->getKind();
1325 if (aFeatureKind == SketchPlugin_Line::ID())
1326 aResult = theFeature->firstResult();
1327 else if (aFeatureKind == SketchPlugin_Arc::ID())
1328 aResult = theFeature->lastResult();
1329 else if (aFeatureKind == SketchPlugin_Circle::ID())
1330 aResult = theFeature->lastResult();
1335 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1336 const std::shared_ptr<ModelAPI_Feature>& theFeature)
1338 std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1340 std::string aFeatureKind = theFeature->getKind();
1341 if (aFeatureKind == SketchPlugin_Line::ID()) {
1342 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1343 anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1345 else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1346 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1347 anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1349 else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1352 return anAttributes;
1356 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1357 const std::shared_ptr<ModelAPI_Feature>& theFeature,
1358 const bool isUseAttributesInfo)
1361 if (!theFeature.get()) {
1365 if (theFeature->data()->isValid())
1366 anInfo.append(theFeature->data()->name().c_str());
1368 if (isUseAttributesInfo) {
1369 std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1370 getEdgeAttributes(theFeature));
1371 /// processing of feature with point 2d attributes, like line, arc, circle
1372 if (!aPointsInfo.empty()) {
1375 anInfo += aPointsInfo;
1377 else { /// process constraint coincidence, find points in ref attr attributes
1378 std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1379 ModelAPI_AttributeRefAttr::typeId());
1380 std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1381 std::string anAttributesInfo;
1382 for(; anIt != aLast; anIt++) {
1383 if (!anAttributesInfo.empty()) {
1384 anAttributesInfo.append(", ");
1385 anAttributesInfo += "\n";
1387 AttributePtr anAttr = *anIt;
1388 std::string aValue = "not defined";
1389 std::string aType = anAttr->attributeType();
1390 if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1391 std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1392 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1393 if (aRefAttr.get()) {
1394 if (aRefAttr->isObject()) {
1395 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1396 aValue = "<object:>" + getFeatureInfo(aFeature, false);
1399 AttributePtr anAttribute = aRefAttr->attr();
1400 if (anAttribute.get()) {
1401 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1402 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1403 " [" + getFeatureInfo(aFeature, false) + "]";
1408 anAttributesInfo.append(" " + anAttr->id() + ": " + aValue);
1410 if (!anAttributesInfo.empty())
1411 anInfo = anInfo + "\n" + anAttributesInfo;