1 // Copyright (C) 2014-2023 CEA, EDF
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "SketchPlugin_Trim.h"
22 #include <GeomAPI_Dir2d.h>
23 #include <GeomAPI_Edge.h>
24 #include <GeomAPI_Pnt2d.h>
25 #include <GeomAPI_XY.h>
26 #include <GeomDataAPI_Point2D.h>
27 #include <GeomAlgoAPI_ShapeTools.h>
29 #include <ModelAPI_AttributeReference.h>
30 #include <ModelAPI_AttributeString.h>
31 #include <ModelAPI_AttributeRefAttr.h>
32 #include <ModelAPI_Tools.h>
33 #include <ModelAPI_AttributeBoolean.h>
35 #include <ModelAPI_Validator.h>
36 #include <ModelAPI_Session.h>
37 #include <ModelAPI_AttributeDouble.h>
39 #include <ModelGeomAlgo_Shape.h>
41 #include <SketchPlugin_Arc.h>
42 #include <SketchPlugin_ConstraintMiddle.h>
43 #include <SketchPlugin_Circle.h>
44 #include <SketchPlugin_ConstraintCoincidence.h>
45 #include <SketchPlugin_ConstraintEqual.h>
46 #include <SketchPlugin_ConstraintTangent.h>
47 #include <SketchPlugin_ConstraintLength.h>
48 #include <SketchPlugin_ConstraintMirror.h>
49 #include <SketchPlugin_ConstraintCollinear.h>
50 #include <SketchPlugin_Ellipse.h>
51 #include <SketchPlugin_EllipticArc.h>
52 #include <SketchPlugin_Line.h>
53 #include <SketchPlugin_MultiRotation.h>
54 #include <SketchPlugin_MultiTranslation.h>
55 #include <SketchPlugin_Point.h>
57 #include <ModelAPI_EventReentrantMessage.h>
59 #include <ModelAPI_Events.h>
60 #include <SketchPlugin_Line.h>
61 #include <SketchPlugin_Arc.h>
62 #include <SketchPlugin_Circle.h>
64 #include <ModelGeomAlgo_Point2D.h>
65 #include <Events_Loop.h>
73 #ifdef DEBUG_TRIM_METHODS
77 static const double PI = 3.141592653589793238463;
79 SketchPlugin_Trim::SketchPlugin_Trim()
83 void SketchPlugin_Trim::initAttributes()
85 data()->addAttribute(SELECTED_OBJECT(), ModelAPI_AttributeReference::typeId());
86 data()->addAttribute(SELECTED_POINT(), GeomDataAPI_Point2D::typeId());
88 data()->addAttribute(PREVIEW_POINT(), GeomDataAPI_Point2D::typeId());
89 data()->addAttribute(PREVIEW_OBJECT(), ModelAPI_AttributeReference::typeId());
91 data()->attribute(PREVIEW_POINT())->setIsArgument(false);
92 data()->attribute(SELECTED_POINT())->setIsArgument(false);
93 data()->attribute(PREVIEW_OBJECT())->setIsArgument(false);
95 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PREVIEW_POINT());
96 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PREVIEW_OBJECT());
99 void SketchPlugin_Trim::findShapePoints(const std::string& theObjectAttributeId,
100 const std::string& thePointAttributeId,
101 std::shared_ptr<GeomAPI_Pnt>& aStartPoint,
102 std::shared_ptr<GeomAPI_Pnt>& aLastPoint)
104 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
105 data()->attribute(theObjectAttributeId));
106 ObjectPtr aBaseObject = aBaseObjectAttr->value();
108 AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
109 data()->attribute(thePointAttributeId));
110 std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
111 std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
112 anAttributePnt2d->y());
114 if (myCashedShapes.find(aBaseObject) == myCashedShapes.end()) {
115 SketchPlugin_SegmentationTools::fillObjectShapes(
116 this, aBaseObject, myCashedShapes, myObjectToPoints);
119 const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
120 if (!aShapes.empty()) {
121 std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
122 for (; anIt != aLast; anIt++) {
123 GeomShapePtr aBaseShape = *anIt;
124 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
125 if (ModelGeomAlgo_Point2D::isPointOnEdge(aBaseShape, anAttributePnt, aProjectedPoint)) {
127 if (aBaseShape->shapeType() == GeomAPI_Shape::EDGE) {
128 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aBaseShape));
129 //GeomAPI_Shape::Orientation anOrientation = anEdge->orientation();
130 //if (anOrientation == GeomAPI_Shape::REVERSED) {
131 aStartPoint = anEdge->lastPoint();
132 aLastPoint = anEdge->firstPoint();
135 //aStartPoint = anEdge->firstPoint();
136 //aLastPoint = anEdge->lastPoint();
143 std::cout << "<findShapePoints> => "
144 << std::endl << "Attribute point: "
145 << anAttributePnt->x() << ", " << anAttributePnt->y() << ", " << anAttributePnt->z() << "]"
146 << std::endl << "Start Point: ["
147 << aStartPoint->x() << ", " << aStartPoint->y() << ", " << aStartPoint->z() << "]"
148 << std::endl << "Last Point: ["
149 << aLastPoint->x() << ", " << aLastPoint->y() << ", " << aLastPoint->z() << "]"
154 std::shared_ptr<GeomAPI_Pnt2d> SketchPlugin_Trim::convertPoint(
155 const std::shared_ptr<GeomAPI_Pnt>& thePoint)
157 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
161 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
162 data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
163 ObjectPtr aBaseObject = aBaseObjectAttr->value();
164 if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end()) {
165 SketchPlugin_SegmentationTools::fillObjectShapes(
166 this, aBaseObject, myCashedShapes, myObjectToPoints);
170 const GeomAlgoAPI_ShapeTools::PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
171 for (GeomAlgoAPI_ShapeTools::PointToRefsMap::const_iterator aPointIt = aRefsMap.begin();
172 aPointIt != aRefsMap.end() && !aFound; aPointIt++) {
173 if (aPointIt->first->isEqual(thePoint)) {
174 const std::pair<std::list<AttributePoint2DPtr >,
175 std::list<ObjectPtr > >& anInfo = aPointIt->second;
176 const std::list<AttributePoint2DPtr >& anAttributes = anInfo.first;
177 if (!anAttributes.empty()) {
178 aPoint = anAttributes.front()->pnt();
182 aPoint = sketch()->to2D(thePoint);
188 // returns an end of the shape to define direction of split if feature's attribute
190 aPoint = sketch()->to2D(thePoint);
195 void SketchPlugin_Trim::execute()
197 #ifdef DEBUG_TRIM_METHODS
198 std::cout << "SketchPlugin_Trim::execute: " << data()->name() << std::endl;
201 SketchPlugin_Sketch* aSketch = sketch();
203 setError("Error: Sketch object is empty.");
207 // Check the base objects are initialized.
208 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
209 data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
210 if(!aBaseObjectAttr->isInitialized()) {
211 setError("Error: Base object is not initialized.");
214 ObjectPtr aBaseObject = aBaseObjectAttr->value();
215 if (!aBaseObject.get()) {
216 setError("Error: Base object is not initialized.");
219 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
221 /// Remove reference of this feature to feature used in preview, it is not necessary anymore
222 /// as trim will be removed after execute
223 AttributeReferencePtr aPreviewObjectAttr =
224 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
225 data()->attribute(SketchPlugin_Trim::PREVIEW_OBJECT()));
227 ObjectPtr aPreviewObject = aPreviewObjectAttr->value();
228 AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
229 data()->attribute(PREVIEW_POINT()));
230 std::shared_ptr<GeomAPI_Pnt2d> aPreviewPnt2d = aPoint->pnt();
231 // nullify pointer of preview attribute
232 aPreviewObjectAttr->setValue(ResultPtr());
234 bool anIsEqualPreviewAndSelected = aPreviewObject == aBaseObject;
237 std::shared_ptr<GeomAPI_Pnt> aStartShapePoint, aLastShapePoint;
239 std::cout << " Base Feature: " << aBaseFeature->data()->name() << std::endl;
241 findShapePoints(SELECTED_OBJECT(), SELECTED_POINT(), aStartShapePoint, aLastShapePoint);
242 if (!aStartShapePoint || !aLastShapePoint) {
243 setError("Error: Selected point is not placed on any edge");
247 std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint2d = convertPoint(aStartShapePoint);
248 std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint2d = convertPoint(aLastShapePoint);
249 /// find features that should be deleted (e.g. Middle Point) or updated (e.g. Length)
250 std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
251 getConstraints(aFeaturesToDelete, aFeaturesToUpdate);
252 // find references(attributes and features) to the base feature
253 std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
254 std::list<AttributePtr> aRefsToFeature;
255 SketchPlugin_SegmentationTools::getRefAttributes(
256 aBaseFeature, aBaseRefAttributes, aRefsToFeature);
258 std::cout << "---- getRefAttributes ----" << std::endl;
259 std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
260 aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
261 std::cout << std::endl << "References to attributes of base feature [" <<
262 aBaseRefAttributes.size() << "]" << std::endl;
263 for (; aRefIt != aRefLast; aRefIt++) {
264 AttributePtr aBaseAttr = aRefIt->first;
265 std::list<AttributePtr> aRefAttributes = aRefIt->second;
266 std::string aRefsInfo;
267 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
268 aRefAttrLast = aRefAttributes.end();
269 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
270 if (!aRefsInfo.empty())
271 aRefsInfo.append(",");
272 AttributePtr aRAttr = *aRefAttrIt;
273 aRefsInfo.append(aRAttr->id());
274 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
275 aRefsInfo.append("(" + aRFeature->name() + ") ");
277 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
278 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
279 std::cout << aPointAttr->id().c_str() <<
280 ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
282 std::cout << std::endl;
283 std::cout << std::endl << "References to base feature [" <<
284 aRefsToFeature.size() << "]" << std::endl;
285 std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
286 aRefAttrLast = aRefsToFeature.end();
287 std::string aRefsInfo;
288 for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
289 if (!aRefsInfo.empty())
290 aRefsInfo.append(",");
291 AttributePtr aRAttr = *aRefAttrIt;
292 aRefsInfo.append(aRAttr->id());
293 FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
294 aRefsInfo.append("(" + aRFeature->name() + ") ");
296 std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
297 std::cout << "---- getRefAttributes:end ----" << std::endl;
300 keepCurrentFeature();
302 std::set<AttributePoint2DPtr> aFurtherCoincidences;
303 std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
304 const std::string& aKind = aBaseFeature->getKind();
305 FeaturePtr aReplacingFeature, aNewFeature;
306 if (aKind == SketchPlugin_Circle::ID() ||
307 aKind == SketchPlugin_Ellipse::ID()) {
308 aReplacingFeature = trimClosed(aStartShapePoint2d, aLastShapePoint2d,
309 aFurtherCoincidences, aModifiedAttributes);
311 aFeaturesToDelete.insert(aBaseFeature);
312 // as circle is removed, erase it from dependencies(arguments) of this feature
313 // otherwise Trim feature will be removed with the circle before
314 // this operation is finished
315 aBaseObjectAttr->setObject(ResultPtr());
317 else if (aKind == SketchPlugin_Line::ID()) {
318 aNewFeature = trimLine(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
319 aFurtherCoincidences, aModifiedAttributes);
321 else if (aKind == SketchPlugin_Arc::ID()) {
322 aNewFeature = trimArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
323 aFurtherCoincidences, aModifiedAttributes);
325 else if (aKind == SketchPlugin_EllipticArc::ID()) {
326 aNewFeature = trimEllipticArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
327 aFurtherCoincidences, aModifiedAttributes);
330 restoreCurrentFeature();
332 // constraints to end points of trim feature
333 if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end()) {
334 SketchPlugin_SegmentationTools::fillObjectShapes(
335 this, aBaseObject, myCashedShapes, myObjectToPoints);
338 // create coincidence to objects, intersected the base object
339 const GeomAlgoAPI_ShapeTools::PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
340 for (std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
341 aLast = aFurtherCoincidences.end();
342 anIt != aLast; anIt++) {
343 AttributePoint2DPtr aPointAttribute = (*anIt);
344 std::shared_ptr<GeomAPI_Pnt2d> aPoint2d = aPointAttribute->pnt();
347 std::cout << "<compare Points> => " << std::endl
348 << "aPoint2d: [" << aPoint2d->x() << ", " << aPoint2d->y() << "]" << std::endl;
349 if (aStartShapePoint2d.get())
350 std::cout << "Start Point: [" << aStartShapePoint2d->x() << ", " << aStartShapePoint2d->y()
352 if (aLastShapePoint2d.get())
353 std::cout << "Last Point: [" << aLastShapePoint2d->x() << ", " << aLastShapePoint2d->y()
357 std::shared_ptr<GeomAPI_Pnt> aExtrPoint;
358 if (aStartShapePoint2d.get() && aPoint2d->isEqual(aStartShapePoint2d))
359 aExtrPoint = aStartShapePoint;
360 else if (aLastShapePoint2d.get() && aPoint2d->isEqual(aLastShapePoint2d))
361 aExtrPoint = aLastShapePoint;
363 if (!aExtrPoint.get())
366 std::pair<std::list<AttributePoint2DPtr >, std::list<ObjectPtr > > anInfo;
367 for (GeomAlgoAPI_ShapeTools::PointToRefsMap::const_iterator aRefIt = aRefsMap.begin();
368 aRefIt != aRefsMap.end(); aRefIt++)
370 if (aRefIt->first->isEqual(aExtrPoint)) {
371 anInfo = aRefIt->second;
372 // prefer a segment instead of a point, because further coincidence with a segment
373 // decreases only 1 DoF (instead of 2 for point) and prevents an overconstraint situation.
375 for (std::list<ObjectPtr>::const_iterator anInfoIt = anInfo.second.begin();
376 anInfoIt != anInfo.second.end() && !isEdge; ++anInfoIt) {
377 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(*anInfoIt);
379 GeomShapePtr aShape = aResult->shape();
380 isEdge = aShape && aShape->isEdge();
387 const std::list<ObjectPtr>& anObjects = anInfo.second;
388 for (std::list<ObjectPtr>::const_iterator anObjectIt = anObjects.begin();
389 anObjectIt != anObjects.end(); anObjectIt++) {
390 SketchPlugin_Tools::createConstraintAttrObject(sketch(),
391 SketchPlugin_ConstraintCoincidence::ID(),
392 aPointAttribute, *anObjectIt);
396 // move constraints from base feature to replacing feature: ignore coincidences to feature
397 // if attributes of coincidence participated in split
398 ResultPtr aReplacingResult;
399 if (aReplacingFeature.get()) {
400 aReplacingFeature->execute(); // need it to obtain result
401 aReplacingResult = aReplacingFeature->lastResult();
403 for(std::list<AttributePtr>::const_iterator anIt = aRefsToFeature.begin(),
404 aLast = aRefsToFeature.end();
405 anIt != aLast; anIt++) {
406 AttributePtr anAttribute = *anIt;
408 if (setCoincidenceToAttribute(anAttribute, aFurtherCoincidences, aFeaturesToDelete))
411 // move tangency constraint to the nearest feature if possible
412 if (aNewFeature.get() && moveTangency(anAttribute, aNewFeature))
415 if (aReplacingResult.get()) {
416 AttributeRefAttrPtr aRefAttr =
417 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
419 aRefAttr->setObject(aReplacingResult);
421 AttributeReferencePtr aReferenceAttr =
422 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(anAttribute);
423 if (aReferenceAttr.get())
424 aReferenceAttr->setObject(aReplacingResult);
429 SketchPlugin_SegmentationTools::updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
431 // Wait all constraints being created, then send update events
432 static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
433 bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
435 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
437 // delete constraints
439 if (aFeaturesToDelete.size() > 0) {
440 std::cout << "after SPlit: removeFeaturesAndReferences: " << std::endl;
442 for (std::set<FeaturePtr>::const_iterator anIt = aFeaturesToDelete.begin();
443 anIt != aFeaturesToDelete.end(); anIt++) {
444 FeaturePtr aFeature = *anIt;
445 std::cout << aFeature->data()->name() << std::endl;
449 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
450 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
452 SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(aFeaturesToUpdate);
454 // Send events to update the sub-features by the solver.
455 if(isUpdateFlushed) {
456 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
459 if (anIsEqualPreviewAndSelected) {
460 // equal preview and selected objects
461 // nothing to do if the preview and selected objects are different
462 if (aReplacingResult.get()) { // base object was removed
463 aPreviewObject = aReplacingResult;
464 //aMessage->setSelectedObject(aReplacingResult);
465 #ifdef DEBUG_TRIM_METHODS
466 if (!aSelectedShape.get())
467 std::cout << "Set empty selected object" << std::endl;
469 std::cout << "Set shape with ShapeType: " << aSelectedShape->shapeTypeStr() << std::endl;
473 aPreviewObject = ObjectPtr();
475 aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one
476 aBaseObject = aBaseFeature->lastResult();
477 std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
479 ResultPtr aBaseResult = std::dynamic_pointer_cast<ModelAPI_Result>(aBaseObject);
481 GeomShapePtr aShape = aBaseResult->shape();
482 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
483 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPreviewPnt, aProjectedPoint))
484 aPreviewObject = aBaseResult;
486 if (!aPreviewObject.get() && aNewFeature.get()) {
487 ResultPtr aNewFeatureResult = aNewFeature->lastResult();
488 if (aNewFeatureResult.get()) {
489 GeomShapePtr aShape = aNewFeatureResult->shape();
490 std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
491 if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPreviewPnt, aProjectedPoint))
492 aPreviewObject = aNewFeatureResult;
497 if (aPreviewObject.get()) {
498 std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage = std::shared_ptr
499 <ModelAPI_EventReentrantMessage>(new ModelAPI_EventReentrantMessage(
500 ModelAPI_EventReentrantMessage::eventId(), this));
501 aMessage->setSelectedObject(aPreviewObject);
502 Events_Loop::loop()->send(aMessage);
505 std::cout << "SketchPlugin_Trim::done" << std::endl;
510 std::string SketchPlugin_Trim::processEvent(const std::shared_ptr<Events_Message>& theMessage)
512 #ifdef DEBUG_TRIM_METHODS
513 std::cout << "SketchPlugin_Trim::processEvent:" << data()->name() << std::endl;
515 std::string aFilledAttributeName;
517 std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage =
518 std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
519 if (aMessage.get()) {
520 ObjectPtr anObject = aMessage->selectedObject();
521 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aMessage->clickedPoint();
523 if (anObject.get() && aPoint.get()) {
524 if (myCashedShapes.find(anObject) == myCashedShapes.end()) {
525 SketchPlugin_SegmentationTools::fillObjectShapes(
526 this, anObject, myCashedShapes, myObjectToPoints);
528 const std::set<GeomShapePtr>& aShapes = myCashedShapes[anObject];
529 if (aShapes.size() > 1) {
530 std::shared_ptr<ModelAPI_AttributeReference> aRefSelectedAttr =
531 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
532 data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
533 std::shared_ptr<ModelAPI_AttributeReference> aRefPreviewAttr =
534 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
535 data()->attribute(SketchPlugin_Trim::PREVIEW_OBJECT()));
536 aRefSelectedAttr->setValue(anObject);
537 aRefPreviewAttr->setValue(anObject);
539 std::shared_ptr<GeomDataAPI_Point2D> aPointSelectedAttr =
540 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
541 data()->attribute(SketchPlugin_Trim::SELECTED_POINT()));
542 std::shared_ptr<GeomDataAPI_Point2D> aPointPreviewAttr =
543 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
544 data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
545 aPointSelectedAttr->setValue(aPoint);
546 aPointPreviewAttr->setValue(aPoint);
548 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
550 GeomShapePtr aSelectedShape = SketchPlugin_SegmentationTools::getSubShape(this,
551 SELECTED_OBJECT(), SELECTED_POINT(), myCashedShapes, myObjectToPoints);
552 #ifdef DEBUG_TRIM_METHODS
553 if (!aSelectedShape.get())
554 std::cout << "Set empty selected object" << std::endl;
556 std::cout << "Set shape with ShapeType: " << aSelectedShape->shapeTypeStr() << std::endl;
558 aFilledAttributeName = SketchPlugin_Trim::SELECTED_OBJECT();
562 return aFilledAttributeName;
566 bool SketchPlugin_Trim::setCoincidenceToAttribute(const AttributePtr& theAttribute,
567 const std::set<AttributePoint2DPtr>& theFurtherCoincidences,
568 std::set<std::shared_ptr<ModelAPI_Feature>>& theFeaturesToDelete)
570 FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
571 if (aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
574 AttributePoint2DPtr aRefPointAttr = SketchPlugin_ConstraintCoincidence::getPoint(aFeature);
575 if (!aRefPointAttr.get())
577 std::shared_ptr<GeomAPI_Pnt2d> aRefPnt2d = aRefPointAttr->pnt();
579 std::set<AttributePoint2DPtr>::const_iterator anIt = theFurtherCoincidences.begin(),
580 aLast = theFurtherCoincidences.end();
581 bool aFoundPoint = false;
582 for (; anIt != aLast && !aFoundPoint; anIt++) {
583 AttributePoint2DPtr aPointAttribute = (*anIt);
584 std::shared_ptr<GeomAPI_Pnt2d> aPoint2d = aPointAttribute->pnt();
585 if (aPoint2d->isEqual(aRefPnt2d)) {
586 // create new coincidence and then remove the old one
587 SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
588 SketchPlugin_ConstraintCoincidence::ID(),
589 aRefPointAttr, aPointAttribute);
590 theFeaturesToDelete.insert(aFeature);
596 bool SketchPlugin_Trim::moveTangency(const AttributePtr& theAttribute,
597 const FeaturePtr& theFeature)
599 FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
600 if (aFeature->getKind() != SketchPlugin_ConstraintTangent::ID())
603 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
608 // get shape of tangent object to the current
609 std::string aTangentAttr = SketchPlugin_Constraint::ENTITY_A();
610 if (aRefAttr->id() == SketchPlugin_Constraint::ENTITY_A())
611 aTangentAttr = SketchPlugin_Constraint::ENTITY_B();
612 AttributeRefAttrPtr aTangentRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
613 aFeature->attribute(aTangentAttr));
614 FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentRefAttr->object());
616 // get shape of the feature of the attribute
617 FeaturePtr anAttributeFeature = ModelAPI_Feature::feature(aRefAttr->object());
618 anAttributeFeature->execute(); // the modified value should be applyed to recompute shape
619 GeomAlgoAPI_ShapeTools::PointToRefsMap aPointToAttributeOrObject;
620 std::list<FeaturePtr> aFeatures;
621 aFeatures.push_back(anAttributeFeature);
622 ModelGeomAlgo_Point2D::getPointsIntersectedShape(aTangentFeature, aFeatures,
623 aPointToAttributeOrObject);
624 if (!aPointToAttributeOrObject.empty())
625 return true; // the attribute feature has a point of intersection, so we do not replace it
627 // get shape of the feature
628 aPointToAttributeOrObject.clear();
630 aFeatures.push_back(theFeature);
631 ModelGeomAlgo_Point2D::getPointsIntersectedShape(aTangentFeature, aFeatures,
632 aPointToAttributeOrObject);
633 if (!aPointToAttributeOrObject.empty()) {
634 std::set<ResultPtr> anEdgeShapes;
635 ModelGeomAlgo_Shape::shapesOfType(theFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
636 if (!anEdgeShapes.empty()) {
637 ResultPtr aResult = *anEdgeShapes.begin();
639 aRefAttr->setObject(aResult);
640 return true; // the attribute feature has a point of intersection, so we do not replace it
647 AISObjectPtr SketchPlugin_Trim::getAISObject(AISObjectPtr thePrevious)
649 return SketchPlugin_SegmentationTools::getAISObject(thePrevious,
650 this, PREVIEW_OBJECT(), PREVIEW_POINT(), SELECTED_OBJECT(), SELECTED_POINT());
653 void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
654 std::set<FeaturePtr>& theFeaturesToUpdate)
656 std::shared_ptr<ModelAPI_Data> aData = data();
658 // Check the base objects are initialized.
659 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
660 aData->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
661 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
662 ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
664 std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
665 std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
666 aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
668 std::set<AttributePtr>::const_iterator aIt;
669 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
670 std::shared_ptr<ModelAPI_Attribute> anAttr = (*aIt);
671 FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
672 std::string aRefFeatureKind = aRefFeature->getKind();
673 std::string anAttributeId = anAttr->id();
674 if ((aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() &&
675 anAttributeId == SketchPlugin_ConstraintMirror::MIRROR_LIST_ID()) ||
676 (aRefFeatureKind == SketchPlugin_MultiRotation::ID() &&
677 anAttributeId == SketchPlugin_MultiRotation::ROTATION_LIST_ID()) ||
678 (aRefFeatureKind == SketchPlugin_MultiTranslation::ID() &&
679 anAttributeId == SketchPlugin_MultiTranslation::TRANSLATION_LIST_ID()) ||
680 aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
681 theFeaturesToDelete.insert(aRefFeature);
682 else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
683 theFeaturesToUpdate.insert(aRefFeature);
687 void SketchPlugin_Trim::removeReferencesToAttribute(const AttributePtr& theAttribute,
688 std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes)
690 /// not found in references
691 if (theBaseRefAttributes.find(theAttribute) == theBaseRefAttributes.end())
694 std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(theAttribute);
695 std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
696 aRLast = aRefAttributes.end();
698 std::set<FeaturePtr> aFeaturesToDelete;
699 for (; aRefIt != aRLast; aRefIt++) {
700 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
701 if (aRefAttr.get()) {
702 aFeaturesToDelete.insert(ModelAPI_Feature::feature(aRefAttr->owner()));
707 // delete constraints
708 if (aFeaturesToDelete.size() > 0) {
709 std::cout << "removeReferencesToAttribute: " << std::endl;
711 for (std::set<FeaturePtr>::const_iterator anIt = aFeaturesToDelete.begin();
712 anIt != aFeaturesToDelete.end(); anIt++) {
713 FeaturePtr aFeature = *anIt;
714 std::cout << aFeature->data()->name() << std::endl;
718 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
719 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
722 FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
723 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
724 std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
725 std::set<AttributePoint2DPtr>& thePoints,
726 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
728 FeaturePtr anNewFeature;
730 // Check the base objects are initialized.
731 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
732 data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
733 ObjectPtr aBaseObject = aBaseObjectAttr->value();
734 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
737 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
738 SketchPlugin_SegmentationTools::getFeaturePoints(
739 aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
741 std::shared_ptr<GeomAPI_Pnt2d> aStartFeaturePoint = aStartPointAttrOfBase->pnt();
742 std::shared_ptr<GeomAPI_Pnt2d> aLastFeaturePoint = anEndPointAttrOfBase->pnt();
744 std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
745 std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
746 arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
747 aStartShapePoint, aLastShapePoint);
749 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
750 if (aStartShapePoint.get())
751 std::cout << "Start point: [" << aStartShapePoint->x() << ", " <<
752 aStartShapePoint->y() << "]" << std::endl;
753 std::cout << "1st point: [" << aStartFeaturePoint->x() << ", " <<
754 aStartFeaturePoint->y() << "]" << std::endl;
755 if (aLastShapePoint.get())
756 std::cout << "2st point: [" << aLastShapePoint->x() << ", " <<
757 aLastShapePoint->y() << "]" << std::endl;
758 std::cout << "End point: [" << aLastFeaturePoint->x() << ", " <<
759 aLastFeaturePoint->y() << "]" << std::endl;
762 bool isStartPoint = !aStartShapePoint.get() || aStartFeaturePoint->isEqual(aStartShapePoint);
763 bool isLastPoint = !aLastShapePoint.get() || aLastFeaturePoint->isEqual(aLastShapePoint);
764 if (isStartPoint || isLastPoint) {
765 // result is one line: changed existing line
766 std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Line::START_ID()
767 : SketchPlugin_Line::END_ID();
768 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
769 if (aStartShapePoint.get() && aLastShapePoint.get())
770 aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
772 aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
774 // it is important to delete references before the feature modification because
775 // if deletion will be after the feature modification, solver returns the feature back
776 removeReferencesToAttribute(aBaseFeature->attribute(aModifiedAttribute),
777 theBaseRefAttributes);
779 fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
780 //theModifiedAttributes.insert(
781 // std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr()));
783 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
784 (aBaseFeature->attribute(aModifiedAttribute)));
787 // result is two lines: start line point - start shape point,
788 // last shape point - last line point
789 // create second line
790 anNewFeature = SketchPlugin_SegmentationTools::createLineFeature(
791 aBaseFeature, aLastShapePoint, aLastFeaturePoint);
792 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
793 (anNewFeature->attribute(SketchPlugin_Line::START_ID())));
795 std::string aModifiedAttribute = SketchPlugin_Line::END_ID();
796 theModifiedAttributes.insert(
797 std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
798 anNewFeature->attribute(SketchPlugin_Line::END_ID())));
801 fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
803 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
804 (aBaseFeature->attribute(aModifiedAttribute)));
806 // Collinear constraint for lines
807 SketchPlugin_Tools::createConstraintObjectObject(sketch(),
808 SketchPlugin_ConstraintCollinear::ID(),
809 aBaseFeature->lastResult(),
810 anNewFeature->lastResult());
815 FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
816 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
817 std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
818 std::set<AttributePoint2DPtr>& thePoints,
819 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
821 FeaturePtr anNewFeature;
822 // Check the base objects are initialized.
823 AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
824 data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
825 ObjectPtr aBaseObject = aBaseObjectAttr->value();
826 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
829 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
830 SketchPlugin_SegmentationTools::getFeaturePoints(
831 aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
833 std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
834 std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
836 std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
837 std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
838 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
839 aStartShapePoint, aLastShapePoint);
841 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
842 if (aStartShapePoint.get())
843 std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
844 aStartShapePoint->y() << "]" << std::endl;
845 std::cout << "Start arc attribute point: [" << aStartArcPoint->x() << ", " <<
846 aStartArcPoint->y() << "]" << std::endl;
847 if (aLastShapePoint.get())
848 std::cout << "Last shape point: [" << aLastShapePoint->x() << ", " <<
849 aLastShapePoint->y() << "]" << std::endl;
850 std::cout << "Last arc attribute point: [" << aLastArcPoint->x() << ", " <<
851 aLastArcPoint->y() << "]" << std::endl;
854 bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint);
855 bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint);
856 if (isStartPoint || isLastPoint) {
857 // result is one arc: changed existing arc
858 std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Arc::START_ID()
859 : SketchPlugin_Arc::END_ID();
860 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
861 if (aStartShapePoint.get() && aLastShapePoint.get())
862 aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
864 aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
866 removeReferencesToAttribute(aBaseFeature->attribute(aModifiedAttribute),
867 theBaseRefAttributes);
869 fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
871 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
872 (aBaseFeature->attribute(aModifiedAttribute)));
875 // result is two arcs: start arc point - start shape point, last shape point - last arc point
877 anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
878 aBaseFeature, aLastShapePoint, aLastArcPoint);
879 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
880 (anNewFeature->attribute(SketchPlugin_Arc::START_ID())));
882 std::string aModifiedAttribute = SketchPlugin_Arc::END_ID();
883 theModifiedAttributes.insert(
884 std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
885 anNewFeature->attribute(SketchPlugin_Arc::END_ID())));
888 fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
890 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
891 (aBaseFeature->attribute(aModifiedAttribute)));
893 // equal Radius constraint for arcs
894 SketchPlugin_Tools::createConstraintObjectObject(sketch(),
895 SketchPlugin_ConstraintEqual::ID(),
896 aBaseFeature->lastResult(),
897 anNewFeature->lastResult());
898 // coincident centers constraint
899 SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
900 SketchPlugin_ConstraintCoincidence::ID(),
901 aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
902 anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
905 std::cout << "Created arc on points:" << std::endl;
906 std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
907 aStartShapePoint->y() << "]" << std::endl;
913 FeaturePtr SketchPlugin_Trim::trimEllipticArc(
914 const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
915 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
916 std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
917 std::set<AttributePoint2DPtr>& thePoints,
918 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
920 FeaturePtr anNewFeature;
921 // Check the base objects are initialized.
922 AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
923 ObjectPtr aBaseObject = aBaseObjectAttr->value();
924 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
927 AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
928 SketchPlugin_SegmentationTools::getFeaturePoints(
929 aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
931 std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
932 std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
934 std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
935 std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
936 arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
937 aStartShapePoint, aLastShapePoint);
939 std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
940 if (aStartShapePoint.get())
941 std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
942 aStartShapePoint->y() << "]" << std::endl;
943 std::cout << "Start arc attribute point: [" << aStartArcPoint->x() << ", " <<
944 aStartArcPoint->y() << "]" << std::endl;
945 if (aLastShapePoint.get())
946 std::cout << "Last shape point: [" << aLastShapePoint->x() << ", " <<
947 aLastShapePoint->y() << "]" << std::endl;
948 std::cout << "Last arc attribute point: [" << aLastArcPoint->x() << ", " <<
949 aLastArcPoint->y() << "]" << std::endl;
952 bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint);
953 bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint);
954 if (isStartPoint || isLastPoint) {
955 // result is one arc: changed existing arc
956 std::string aModifiedAttribute = isStartPoint ? SketchPlugin_EllipticArc::START_POINT_ID()
957 : SketchPlugin_EllipticArc::END_POINT_ID();
958 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
959 if (aStartShapePoint.get() && aLastShapePoint.get())
960 aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
962 aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
964 removeReferencesToAttribute(aBaseFeature->attribute(aModifiedAttribute),
965 theBaseRefAttributes);
967 fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
969 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
970 (aBaseFeature->attribute(aModifiedAttribute)));
973 // result is two arcs: start arc point - start shape point, last shape point - last arc point
975 anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
976 aBaseFeature, aLastShapePoint, aLastArcPoint);
977 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
978 anNewFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
980 std::string aModifiedAttribute = SketchPlugin_EllipticArc::END_POINT_ID();
981 theModifiedAttributes.insert(
982 std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
983 anNewFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
986 fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
988 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
989 (aBaseFeature->attribute(aModifiedAttribute)));
991 // make elliptic arcs equal
992 SketchPlugin_Tools::createConstraintObjectObject(sketch(),
993 SketchPlugin_ConstraintEqual::ID(),
994 aBaseFeature->lastResult(),
995 anNewFeature->lastResult());
996 // coincident centers constraint
997 SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
998 SketchPlugin_ConstraintCoincidence::ID(),
999 aBaseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()),
1000 anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
1003 std::cout << "Created arc on points:" << std::endl;
1004 std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
1005 aStartShapePoint->y() << "]" << std::endl;
1008 return anNewFeature;
1011 FeaturePtr SketchPlugin_Trim::trimClosed(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
1012 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
1013 std::set<AttributePoint2DPtr>& thePoints,
1014 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1016 // Check the base objects are initialized.
1017 AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
1018 ObjectPtr aBaseObject = aBaseObjectAttr->value();
1019 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1022 FeaturePtr anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
1023 aBaseFeature, theStartShapePoint, theLastShapePoint);
1024 // arc created by trim of circle is always correct, that means that it is not inversed
1025 const std::string& aReversedAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
1026 SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
1027 anNewFeature->boolean(aReversedAttrName)->setValue(false);
1029 if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
1030 theModifiedAttributes.insert(
1031 std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1032 anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
1034 else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) {
1035 theModifiedAttributes.insert(std::make_pair(
1036 aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
1037 anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID())));
1038 theModifiedAttributes.insert(std::make_pair(
1039 aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()),
1040 anNewFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())));
1041 theModifiedAttributes.insert(std::make_pair(
1042 aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()),
1043 anNewFeature->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID())));
1044 theModifiedAttributes.insert(std::make_pair(
1045 aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
1046 anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID())));
1047 theModifiedAttributes.insert(std::make_pair(
1048 aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
1049 anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID())));
1050 theModifiedAttributes.insert(std::make_pair(
1051 aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
1052 anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID())));
1053 theModifiedAttributes.insert(std::make_pair(
1054 aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()),
1055 anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID())));
1057 // update the PARENT_ID reference for all the features created by the ellipse
1058 const std::set<AttributePtr>& aRefs = aBaseFeature->data()->refsToMe();
1059 std::list<AttributePtr> aRefsToParent;
1060 for (std::set<AttributePtr>::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) {
1061 if ((*aRef)->id() == SketchPlugin_SketchEntity::PARENT_ID())
1062 aRefsToParent.push_back(*aRef);
1064 for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
1065 aRef != aRefsToParent.end(); ++aRef) {
1066 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(anNewFeature);
1068 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRef)->owner());
1069 SketchPlugin_Tools::replaceInName(anOwner, aBaseFeature->name(), anNewFeature->name());
1070 SketchPlugin_Tools::replaceInName(anOwner->lastResult(),
1071 aBaseFeature->name(), anNewFeature->name());
1075 const std::string& aStartAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
1076 SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID();
1077 const std::string& aEndAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
1078 SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID();
1080 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1081 (anNewFeature->attribute(aStartAttrName)));
1082 thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1083 (anNewFeature->attribute(aEndAttrName)));
1085 return anNewFeature;
1088 void SketchPlugin_Trim::arrangePointsOnLine(const AttributePoint2DPtr& theStartPointAttr,
1089 const AttributePoint2DPtr& /*theEndPointAttr*/,
1090 std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
1091 std::shared_ptr<GeomAPI_Pnt2d>& theLastPoint) const
1093 if (!theFirstPoint.get() || !theLastPoint.get())
1096 // if first point is closer to last point, swap first and last values
1097 if (theStartPointAttr->pnt()->distance(theFirstPoint) >
1098 theStartPointAttr->pnt()->distance(theLastPoint)) {
1099 std::shared_ptr<GeomAPI_Pnt2d> aTmpPoint = theFirstPoint;
1100 theFirstPoint = theLastPoint;
1101 theLastPoint = aTmpPoint;
1105 void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc,
1106 const AttributePoint2DPtr& theStartPointAttr,
1107 const AttributePoint2DPtr& /*theEndPointAttr*/,
1108 std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
1109 std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint) const
1111 if (!theFirstPoint.get() || !theSecondPoint.get())
1114 static const double anAngleTol = 1.e-12;
1116 const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
1117 SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID();
1118 const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
1119 SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
1121 std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1122 theArc->attribute(aCenterAttrName))->pnt();
1123 bool isReversed = theArc->boolean(aReversedAttrName)->value();
1125 // collect directions to each point
1126 std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1127 new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1128 std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1129 new GeomAPI_Dir2d(theFirstPoint->xy()->decreased(aCenter->xy())));
1130 std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1131 new GeomAPI_Dir2d(theSecondPoint->xy()->decreased(aCenter->xy())));
1133 // sort points by their angular values
1134 double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1135 double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1136 double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1137 if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1138 aFirstPtAngle += aPeriod;
1139 if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1140 aSecondPtAngle += aPeriod;
1142 if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1143 std::shared_ptr<GeomAPI_Pnt2d> aTmpPoint = theFirstPoint;
1144 theFirstPoint = theSecondPoint;
1145 theSecondPoint = aTmpPoint;
1149 void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttribute,
1150 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
1152 std::string anAttributeType = theModifiedAttribute->attributeType();
1153 if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1154 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1155 theModifiedAttribute);
1156 aModifiedAttribute->setValue(thePoint);
1159 FeaturePtr aFeature = ModelAPI_Feature::feature(theModifiedAttribute->owner());
1160 std::cout << "<fillPointAttribute[" << aFeature->data()->name() << ": " <<
1161 theModifiedAttribute->id() <<
1162 "]> => Pnt2d - [" << thePoint->x() << ", " << thePoint->y() << "]" << std::endl;
1167 void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
1168 const AttributePtr& theSourceAttribute)
1170 std::string anAttributeType = theModifiedAttribute->attributeType();
1171 if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1172 AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1173 theModifiedAttribute);
1174 AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1175 theSourceAttribute);
1177 if (aModifiedAttribute.get() && aSourceAttribute.get())
1178 aModifiedAttribute->setValue(aSourceAttribute->pnt());
1180 else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1181 AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1182 theModifiedAttribute);
1183 AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1184 theSourceAttribute);
1186 if (aModifiedAttribute.get() && aSourceAttribute.get())
1187 aModifiedAttribute->setValue(aSourceAttribute->value());