1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
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_Projection.h>
22 #include <SketchPlugin_Arc.h>
23 #include <SketchPlugin_BSpline.h>
24 #include <SketchPlugin_BSplinePeriodic.h>
25 #include <SketchPlugin_Circle.h>
26 #include <SketchPlugin_Ellipse.h>
27 #include <SketchPlugin_EllipticArc.h>
28 #include <SketchPlugin_Line.h>
29 #include <SketchPlugin_Point.h>
30 #include <SketchPlugin_Sketch.h>
31 #include <SketchPlugin_ConstraintRigid.h>
33 #include <ModelAPI_AttributeRefAttr.h>
34 #include <ModelAPI_AttributeSelection.h>
35 #include <ModelAPI_AttributeDouble.h>
36 #include <ModelAPI_AttributeDoubleArray.h>
37 #include <ModelAPI_AttributeInteger.h>
38 #include <ModelAPI_ResultConstruction.h>
39 #include <ModelAPI_Session.h>
40 #include <ModelAPI_Validator.h>
41 #include <ModelAPI_Tools.h>
42 #include <ModelAPI_Events.h>
44 #include <Events_Loop.h>
46 #include <GeomAPI_BSpline.h>
47 #include <GeomAPI_Circ.h>
48 #include <GeomAPI_Edge.h>
49 #include <GeomAPI_Ellipse.h>
50 #include <GeomAPI_Lin.h>
51 #include <GeomAPI_Pnt.h>
52 #include <GeomAPI_Pnt2d.h>
53 #include <GeomAPI_Vertex.h>
54 #include <GeomAlgoAPI_EdgeBuilder.h>
55 #include <GeomAlgoAPI_Projection.h>
56 #include <GeomDataAPI_Point2D.h>
57 #include <GeomDataAPI_Point2DArray.h>
61 static const double tolerance = 1.e-7;
64 SketchPlugin_Projection::SketchPlugin_Projection()
65 : SketchPlugin_SketchEntity(),
70 void SketchPlugin_Projection::initDerivedClassAttributes()
72 data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
73 data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
74 data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
76 data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
77 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
79 data()->addAttribute(INCLUDE_INTO_RESULT(), ModelAPI_AttributeBoolean::typeId());
81 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
84 void SketchPlugin_Projection::execute()
86 AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
87 if (!aRefAttr || !aRefAttr->isInitialized())
89 FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
91 if (!lastResult().get()) {
92 bool hasProjResult = aProjection->lastResult().get() != NULL;
93 ResultConstructionPtr aConstr = document()->createConstruction(data());
95 aConstr->setShape(aProjection->lastResult()->shape());
96 aConstr->setIsInHistory(false);
97 aConstr->setDisplayed(false);
101 aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
104 // is sketch plane is changed (issue 1791), attribute of projection is not changed, but
105 // projection must be fully recomputed
106 computeProjection(EXTERNAL_FEATURE_ID());
109 void SketchPlugin_Projection::attributeChanged(const std::string& theID)
111 if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
112 myIsComputing = true;
113 computeProjection(theID);
114 myIsComputing = false;
118 static const std::set<std::string>& POINT_PROJECTION()
120 static std::set<std::string> aProj;
122 aProj.insert(SketchPlugin_Point::ID());
126 static const std::set<std::string>& LINE_PROJECTION()
128 static std::set<std::string> aProj;
130 aProj.insert(SketchPlugin_Line::ID());
134 static const std::set<std::string>& CIRCLE_ELLIPSE_PROJECTION()
136 static std::set<std::string> aProj;
138 aProj.insert(SketchPlugin_Circle::ID());
139 aProj.insert(SketchPlugin_Ellipse::ID());
144 static const std::set<std::string>& ARC_PROJECTION()
146 static std::set<std::string> aProj;
148 aProj.insert(SketchPlugin_Arc::ID());
149 aProj.insert(SketchPlugin_EllipticArc::ID());
154 static const std::set<std::string>& BSPLINE_PROJECTION()
156 static std::set<std::string> aProj;
158 aProj.insert(SketchPlugin_BSpline::ID());
159 aProj.insert(SketchPlugin_BSplinePeriodic::ID());
165 static const std::set<std::string>& possibleProjectionTypes(GeomEdgePtr theEdge,
166 GeomVertexPtr theVertex)
169 return POINT_PROJECTION();
171 if (theEdge->isLine())
172 return LINE_PROJECTION();
173 else if (theEdge->isCircle() || theEdge->isArc() || theEdge->isEllipse()) {
174 if (theEdge->isClosed())
175 return CIRCLE_ELLIPSE_PROJECTION();
177 return ARC_PROJECTION();
180 return BSPLINE_PROJECTION();
182 static const std::set<std::string> DUMMY;
186 void SketchPlugin_Projection::computeProjection(const std::string& theID)
188 AttributeSelectionPtr aExtFeature =
189 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_FEATURE_ID()));
193 GeomVertexPtr aVertex;
195 aShape = aExtFeature->value();
196 if (!aShape && aExtFeature->context())
197 aShape = aExtFeature->context()->shape();
199 if (aShape->isEdge())
200 anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
201 else if (aShape->isVertex())
202 aVertex = GeomVertexPtr(new GeomAPI_Vertex(aShape));
204 if (!anEdge && !aVertex)
207 const std::set<std::string>& aProjType = possibleProjectionTypes(anEdge, aVertex);
209 AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
210 FeaturePtr aProjection;
211 if (aRefAttr && aRefAttr->isInitialized())
212 aProjection = ModelAPI_Feature::feature(aRefAttr->object());
214 // if the type of feature differs with already selected, remove it and create once again
215 bool isRebuild = rebuildProjectedFeature(aProjection, aProjType);
217 ResultConstructionPtr aResult =
218 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
219 if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
220 aResult->setShape(std::shared_ptr<GeomAPI_Edge>());
222 aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
225 keepCurrentFeature();
227 bool isProjected = false;
229 isProjected = projectPoint(aProjection, aVertex->point());
231 isProjected = projectEdge(aProjection, anEdge);
234 return; // projection is not computed, stop processing
236 aProjection->boolean(COPY_ID())->setValue(true);
237 aProjection->execute();
238 aRefAttr->setObject(aProjection);
240 restoreCurrentFeature();
242 if (theID == EXTERNAL_FEATURE_ID()) {
243 selection(EXTERNAL_ID())->selectValue(aExtFeature);
246 aResult->setShape(aProjection->lastResult()->shape());
248 GeomShapePtr anEmptyVal;
249 aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
251 static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
252 ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
257 bool SketchPlugin_Projection::rebuildProjectedFeature(
258 FeaturePtr& theProjection,
259 const std::set<std::string>& theSupportedTypes,
260 const std::string& theRequestedFeature)
262 bool isRebuild = false;
264 (theSupportedTypes.find(theProjection->getKind()) == theSupportedTypes.end() ||
265 (!theRequestedFeature.empty() && theProjection->getKind() != theRequestedFeature))) {
266 DocumentPtr aDoc = sketch()->document();
268 AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
269 aRefAttr->setObject(data()->owner()); // to not remove of this remove reference to aProjection
270 std::set<FeaturePtr> aFeaturesToBeRemoved;
271 aFeaturesToBeRemoved.insert(theProjection);
272 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
273 theProjection = FeaturePtr();
274 aRefAttr->setObject(theProjection);
278 if (!theProjection && !theRequestedFeature.empty())
279 theProjection = sketch()->addFeature(theRequestedFeature);
283 bool SketchPlugin_Projection::projectPoint(FeaturePtr& theProjection, const GeomPointPtr& thePoint)
285 std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
287 std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(thePoint);
288 std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
290 rebuildProjectedFeature(theProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
292 // update coordinates of projection
293 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
294 theProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
298 bool SketchPlugin_Projection::projectSegment(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
300 std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
302 std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(theEdge->firstPoint());
303 std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(theEdge->lastPoint());
305 std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
306 std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
307 if (aFirstInSketch->distance(aLastInSketch) < tolerance)
308 return false; // line is semi-orthogonal to the sketch plane
310 rebuildProjectedFeature(theProjection, LINE_PROJECTION(), SketchPlugin_Line::ID());
312 // update attributes of projection
313 std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
314 theProjection->attribute(SketchPlugin_Line::START_ID()));
315 std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
316 theProjection->attribute(SketchPlugin_Line::END_ID()));
317 aStartPnt->setValue(aFirstInSketch);
318 aEndPnt->setValue(aLastInSketch);
323 bool SketchPlugin_Projection::projectEdge(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
325 if (theEdge->isLine())
326 return projectSegment(theProjection, theEdge);
328 std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
330 GeomAlgoAPI_Projection aProjAlgo(aSketchPlane);
331 GeomCurvePtr aProjectedCurve = aProjAlgo.project(theEdge);
334 if (aProjectedCurve->isCircle()) {
335 if (aProjectedCurve->isTrimmed()) {
336 // ARC is a projection
337 isOk = fillArc(theProjection, aProjectedCurve, aSketchPlane);
340 // CIRCLE is a projection
341 isOk = fillCircle(theProjection, aProjectedCurve, aSketchPlane);
344 else if (aProjectedCurve->isEllipse()) {
345 if (aProjectedCurve->isTrimmed()) {
346 // ELLIPTIC ARC is a projection
347 isOk = fillEllipticArc(theProjection, aProjectedCurve, aSketchPlane);
350 // ELLIPSE is a projection
351 isOk = fillEllipse(theProjection, aProjectedCurve, aSketchPlane);
355 isOk = fillBSpline(theProjection, aProjectedCurve, aSketchPlane);
360 bool SketchPlugin_Projection::fillArc(FeaturePtr& theProjection,
361 const GeomCurvePtr& theArc,
362 const GeomPlanePtr& thePlane)
364 rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
366 GeomAPI_Circ aCircle(theArc);
368 double aNormalsDot = aCircle.normal()->dot(thePlane->direction());
369 if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
370 return false; // arc is not in the plane, parallel to the sketch plane
372 bool isInversed = aNormalsDot < 0.;
374 GeomPointPtr aCenter = thePlane->project(aCircle.center());
375 GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
377 GeomPointPtr aFirst = theArc->getPoint(theArc->startParam());
378 GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
380 GeomPointPtr aLast = theArc->getPoint(theArc->endParam());
381 GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
383 bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
385 // update attributes of projection
386 std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
387 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
388 theProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
389 std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
390 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
391 theProjection->attribute(SketchPlugin_Arc::START_ID()));
392 std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
393 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
394 theProjection->attribute(SketchPlugin_Arc::END_ID()));
395 aStartPnt->setValue(aFirstInSketch);
396 aEndPnt->setValue(aLastInSketch);
397 aCenterPnt->setValue(aCenterInSketch);
398 theProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
400 theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
404 bool SketchPlugin_Projection::fillCircle(FeaturePtr& theProjection,
405 const GeomCurvePtr& theCircle,
406 const GeomPlanePtr& thePlane)
408 rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Circle::ID());
410 GeomAPI_Circ aCircle(theCircle);
411 GeomPointPtr aCenter = thePlane->project(aCircle.center());
412 GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
414 // update attributes of projection
415 std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
416 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
417 theProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
418 aCenterPnt->setValue(aCenterInSketch);
419 theProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
423 bool SketchPlugin_Projection::fillEllipse(FeaturePtr& theProjection,
424 const GeomCurvePtr& theEllipse,
425 const GeomPlanePtr& thePlane)
427 rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Ellipse::ID());
429 GeomAPI_Ellipse anEllipse(theEllipse);
430 GeomPointPtr aCenter = thePlane->project(anEllipse.center());
431 GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
432 GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
433 GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
435 // update attributes of projection
436 std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
437 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
438 theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
439 aCenterPnt->setValue(aCenterInSketch);
440 std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
441 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
442 theProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
443 aFocusPnt->setValue(aFocusInSketch);
444 theProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipse.minorRadius());
448 bool SketchPlugin_Projection::fillEllipticArc(FeaturePtr& theProjection,
449 const GeomCurvePtr& theEllipticArc,
450 const GeomPlanePtr& thePlane)
452 rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
454 GeomAPI_Ellipse anEllipse(theEllipticArc);
456 double aNormalsDot = anEllipse.normal()->dot(thePlane->direction());
457 if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
458 return false; // arc is not in the plane, parallel to the sketch plane
460 bool isInversed = aNormalsDot < 0.;
462 GeomPointPtr aCenter = thePlane->project(anEllipse.center());
463 GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
464 GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
465 GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
467 GeomPointPtr aFirst = theEllipticArc->getPoint(theEllipticArc->startParam());
468 GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
469 GeomPointPtr aLast = theEllipticArc->getPoint(theEllipticArc->endParam());
470 GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
472 bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
474 // update attributes of projection
475 std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
476 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
477 theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
478 std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
479 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
480 theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
481 std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
482 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
483 theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
484 std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
485 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
486 theProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
487 aStartPnt->setValue(aFirstInSketch);
488 aEndPnt->setValue(aLastInSketch);
489 aCenterPnt->setValue(aCenterInSketch);
490 aFocusPnt->setValue(aFocusInSketch);
491 theProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
493 theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
497 bool SketchPlugin_Projection::fillBSpline(FeaturePtr& theProjection,
498 const GeomCurvePtr& theCurve,
499 const GeomPlanePtr& thePlane)
501 GeomAPI_BSpline aBSpline(theCurve);
503 rebuildProjectedFeature(theProjection, BSPLINE_PROJECTION(),
504 aBSpline.isPeriodic() ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
506 theProjection->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree());
508 AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
509 theProjection->attribute(SketchPlugin_BSpline::POLES_ID()));
510 std::list<GeomPointPtr> aPoles = aBSpline.poles();
511 aPolesAttr->setSize((int)aPoles.size());
512 std::list<GeomPointPtr>::iterator anIt = aPoles.begin();
513 for (int anIndex = 0; anIt != aPoles.end(); ++anIt, ++anIndex) {
514 GeomPnt2dPtr aPoleInSketch = sketch()->to2D(*anIt);
515 aPolesAttr->setPnt(anIndex, aPoleInSketch);
518 AttributeDoubleArrayPtr aWeightsAttr =
519 theProjection->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
520 std::list<double> aWeights = aBSpline.weights();
521 if (aWeights.empty()) { // rational B-spline
522 int aSize = (int)aPoles.size();
523 aWeightsAttr->setSize(aSize);
524 for (int anIndex = 0; anIndex < aSize; ++anIndex)
525 aWeightsAttr->setValue(anIndex, 1.0);
527 else { // non-rational B-spline
528 aWeightsAttr->setSize((int)aWeights.size());
529 std::list<double>::iterator anIt = aWeights.begin();
530 for (int anIndex = 0; anIt != aWeights.end(); ++anIt, ++anIndex)
531 aWeightsAttr->setValue(anIndex, *anIt);
534 AttributeDoubleArrayPtr aKnotsAttr =
535 theProjection->data()->realArray(SketchPlugin_BSpline::KNOTS_ID());
536 std::list<double> aKnots = aBSpline.knots();
537 int aSize = (int)aKnots.size();
538 aKnotsAttr->setSize(aSize);
539 std::list<double>::iterator aKIt = aKnots.begin();
540 for (int index = 0; index < aSize; ++index, ++aKIt)
541 aKnotsAttr->setValue(index, *aKIt);
543 AttributeIntArrayPtr aMultsAttr =
544 theProjection->data()->intArray(SketchPlugin_BSpline::MULTS_ID());
545 std::list<int> aMultiplicities = aBSpline.mults();
546 aSize = (int)aMultiplicities.size();
547 aMultsAttr->setSize(aSize);
548 std::list<int>::iterator aMIt = aMultiplicities.begin();
549 for (int index = 0; index < aSize; ++index, ++aMIt)
550 aMultsAttr->setValue(index, *aMIt);