Salome HOME
Projection of outer edge onto the sketch plane (improvement #1297)
authorazv <azv@opencascade.com>
Wed, 20 Apr 2016 09:12:03 +0000 (12:12 +0300)
committerazv <azv@opencascade.com>
Thu, 21 Apr 2016 05:58:58 +0000 (08:58 +0300)
Not visible in GUI now

12 files changed:
src/GeomAPI/GeomAPI_Circ.cpp
src/GeomAPI/GeomAPI_Circ.h
src/GeomAPI/GeomAPI_Pln.cpp
src/GeomAPI/GeomAPI_Pln.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Projection.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Projection.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/icons/projection.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml

index dca0897977df88670c05901bb2d102540c16f65f..c7c4573f0df838d72e73172cc011f5321613762e 100644 (file)
@@ -92,3 +92,11 @@ const bool GeomAPI_Circ::parameter(const std::shared_ptr<GeomAPI_Pnt> thePoint,
   Handle(Geom_Circle) aCurve = new Geom_Circle(*MY_CIRC);
   return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt>(), theTolerance, theParameter) == Standard_True;
 }
+
+//=================================================================================================
+std::shared_ptr<GeomAPI_Dir> GeomAPI_Circ::normal() const
+{
+  const gp_Ax1& anAxis = MY_CIRC->Axis();
+  const gp_Dir& aDir = anAxis.Direction();
+  return std::shared_ptr<GeomAPI_Dir>(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z()));
+}
index 32cac89686e2ee8ebb7e5a0b2054cf773c4bb3fd..625ca3895b0a677dc6d652a611e6bb383d3f479b 100644 (file)
@@ -42,6 +42,9 @@ class GeomAPI_Circ : public GeomAPI_Interface
   /// Return radius of the circle
   GEOMAPI_EXPORT double radius() const;
 
+  /// Return orthogonal direction to the circle's plane
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Dir> normal() const;
+
   /// Project point on circle
   GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt> project(
       const std::shared_ptr<GeomAPI_Pnt>& thePoint) const;
index 4ba71589844abbf5e043c48076f5124325f121e5..347e994f4d4a98d3c1735678f5dc8d11e518c779 100644 (file)
@@ -74,3 +74,15 @@ std::shared_ptr<GeomAPI_Pnt> GeomAPI_Pln::intersect(const std::shared_ptr<GeomAP
   double aParam = aNormal->dot(aLocation->decreased(aLineLoc)) / aDot;
   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aLineLoc->added(aLineDir->multiplied(aParam))));
 }
+
+std::shared_ptr<GeomAPI_Pnt> GeomAPI_Pln::project(const std::shared_ptr<GeomAPI_Pnt>& thePoint) const
+{
+  std::shared_ptr<GeomAPI_XYZ> aNormal = direction()->xyz();
+  std::shared_ptr<GeomAPI_XYZ> aLocation = location()->xyz();
+
+  std::shared_ptr<GeomAPI_XYZ> aVec = thePoint->xyz()->decreased(aLocation);
+  double aDot = aNormal->dot(aVec);
+  std::shared_ptr<GeomAPI_XYZ> aProjection = 
+      aLocation->added(aVec->decreased(aNormal->multiplied(aDot)));
+  return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aProjection));
+}
index 81bc519a0900c49affc2f3a93ec3b4ee23c6ccd6..3c319b78955457a22245d66922e3ad276afd3f71 100644 (file)
@@ -54,7 +54,11 @@ class GeomAPI_Pln : public GeomAPI_Interface
 
   /// Returns intersection point or empty if no intersections
   GEOMAPI_EXPORT
-    std::shared_ptr<GeomAPI_Pnt> intersect(const std::shared_ptr<GeomAPI_Lin>& theLine) const;
+  std::shared_ptr<GeomAPI_Pnt> intersect(const std::shared_ptr<GeomAPI_Lin>& theLine) const;
+
+  /// Returns projection of the given point onto the plane
+  GEOMAPI_EXPORT
+  std::shared_ptr<GeomAPI_Pnt> project(const std::shared_ptr<GeomAPI_Pnt>& thePoint) const;
 };
 
 #endif
index ce8173d6c2150f3726fd5db2d117b7a177c1bb54..c2d0224e2f59c547d88488ab8e5fb789c65eebd1 100644 (file)
@@ -37,6 +37,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ExternalValidator.h
     SketchPlugin_Validators.h
     SketchPlugin_Tools.h
+    SketchPlugin_Projection.h
 )
 
 SET(PROJECT_SOURCES
@@ -72,6 +73,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_ExternalValidator.cpp
     SketchPlugin_Validators.cpp
     SketchPlugin_Tools.cpp
+    SketchPlugin_Projection.cpp
 )
 
 SET(PROJECT_LIBRARIES
index b0f84cc79008fbce693501597d0945640def36fb..635583b0c14011a42a5f6d631431eb8442655f2f 100644 (file)
@@ -7,6 +7,7 @@
 #include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Projection.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintCollinear.h>
@@ -81,6 +82,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_ArcTangentPointValidator);
   aFactory->registerValidator("SketchPlugin_IntersectionValidator",
                               new SketchPlugin_IntersectionValidator);
+  aFactory->registerValidator("SketchPlugin_ProjectionValidator",
+                              new SketchPlugin_ProjectionValidator);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
@@ -126,6 +129,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(string theFeatureID)
     return FeaturePtr(new SketchPlugin_Circle);
   } else if (theFeatureID == SketchPlugin_Arc::ID()) {
     return FeaturePtr(new SketchPlugin_Arc);
+  } else if (theFeatureID == SketchPlugin_Projection::ID()) {
+    return FeaturePtr(new SketchPlugin_Projection);
   } else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintCoincidence);
   } else if (theFeatureID == SketchPlugin_ConstraintCollinear::ID()) {
@@ -203,6 +208,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCoincidence::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCollinear::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistance::ID(), aHasSketchPlane);
diff --git a/src/SketchPlugin/SketchPlugin_Projection.cpp b/src/SketchPlugin/SketchPlugin_Projection.cpp
new file mode 100644 (file)
index 0000000..de39ac7
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_Projection.cpp
+// Created: 07 May 2014
+// Author:  Artem ZHIDKOV
+
+#include <SketchPlugin_Projection.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Lin.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <cmath>
+
+static const double tolerance = 1.e-7;
+
+SketchPlugin_Projection::SketchPlugin_Projection()
+    : SketchPlugin_SketchEntity(),
+      myIsComputing(false)
+{
+}
+
+void SketchPlugin_Projection::initDerivedClassAttributes()
+{
+  data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_Projection::execute()
+{
+  AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
+  if (!aRefAttr || !aRefAttr->isInitialized())
+    return;
+  FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
+
+  bool hasResult = lastResult();
+
+  std::shared_ptr<GeomAPI_Edge> anEdge;
+  if (aProjection->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Line::START_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Line::END_ID()));
+
+    // edge to store result
+    std::shared_ptr<GeomAPI_Pnt> aFirst = sketch()->to3D(aStartPnt->x(), aStartPnt->y());
+    std::shared_ptr<GeomAPI_Pnt> aLast = sketch()->to3D(aEndPnt->x(), aEndPnt->y());
+    anEdge = GeomAlgoAPI_EdgeBuilder::line(aFirst, aLast);
+  }
+  else {
+    std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+    std::shared_ptr<GeomAPI_Dir> aNormal = aSketchPlane->direction();
+
+    if (aProjection->getKind() == SketchPlugin_Circle::ID()) {
+      std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
+
+      // edge to store result
+      std::shared_ptr<GeomAPI_Pnt> aCenter = sketch()->to3D(aCenterPnt->x(), aCenterPnt->y());
+      double aRadius = aProjection->real(SketchPlugin_Circle::RADIUS_ID())->value();
+      anEdge = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius);
+    }
+    else if (aProjection->getKind() == SketchPlugin_Arc::ID()) {
+      std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
+      std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aProjection->attribute(SketchPlugin_Arc::START_ID()));
+      std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aProjection->attribute(SketchPlugin_Arc::END_ID()));
+
+      // edge to store result
+      std::shared_ptr<GeomAPI_Pnt> aCenter = sketch()->to3D(aCenterPnt->x(), aCenterPnt->y());
+      std::shared_ptr<GeomAPI_Pnt> aFirst = sketch()->to3D(aStartPnt->x(), aStartPnt->y());
+      std::shared_ptr<GeomAPI_Pnt> aLast = sketch()->to3D(aEndPnt->x(), aEndPnt->y());
+      anEdge = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aFirst, aLast, aNormal);
+    }
+  }
+
+  std::shared_ptr<ModelAPI_ResultConstruction> aConstr = document()->createConstruction(data());
+  aConstr->setShape(anEdge);
+  aConstr->setIsInHistory(false);
+  setResult(aConstr);
+
+  if (!hasResult)
+    aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
+}
+
+void SketchPlugin_Projection::move(double theDeltaX, double theDeltaY)
+{
+  // feature cannot be moved
+}
+
+void SketchPlugin_Projection::attributeChanged(const std::string& theID)
+{
+  if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
+    myIsComputing = true;
+    computeProjection(theID);
+    myIsComputing = false;
+  }
+}
+
+void SketchPlugin_Projection::computeProjection(const std::string& theID)
+{
+  AttributeSelectionPtr aExtFeature =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_FEATURE_ID()));
+
+  std::shared_ptr<GeomAPI_Edge> anEdge;
+  if (aExtFeature && aExtFeature->value() && aExtFeature->value()->isEdge()) {
+    anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aExtFeature->value()));
+  } else if (aExtFeature->context() && aExtFeature->context()->shape() && aExtFeature->context()->shape()->isEdge()) {
+    anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aExtFeature->context()->shape()));
+  }
+  if (!anEdge.get())
+    return;
+
+  AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
+  FeaturePtr aProjection;
+  if (aRefAttr && aRefAttr->isInitialized())
+    aProjection = ModelAPI_Feature::feature(aRefAttr->object());
+
+  // if the type of feature differs with already selected, remove it and create once again
+  if (aProjection) {
+    if ((anEdge->isLine() && aProjection->getKind() != SketchPlugin_Line::ID()) ||
+        (anEdge->isCircle() && aProjection->getKind() != SketchPlugin_Circle::ID()) ||
+        (anEdge->isArc() && aProjection->getKind() != SketchPlugin_Arc::ID())) {
+      DocumentPtr aDoc = sketch()->document();
+      aDoc->removeFeature(aProjection);
+      aProjection = FeaturePtr();
+      aRefAttr->setObject(aProjection);
+    }
+  }
+
+  std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+  if (anEdge->isLine()) {
+    std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
+    std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
+
+    std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
+    std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
+    if (aFirstInSketch->distance(aLastInSketch) < tolerance)
+      return; // line is semi-orthogonal to the sketch plane
+
+    if (!aProjection)
+      aProjection = sketch()->addFeature(SketchPlugin_Line::ID());
+
+    // update attributes of projection
+    std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Line::START_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Line::END_ID()));
+    aStartPnt->setValue(aFirstInSketch);
+    aEndPnt->setValue(aLastInSketch);
+  }
+  else if (anEdge->isCircle()) {
+    std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
+    double aRadius = aCircle->radius();
+
+    std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
+
+    if (!aProjection)
+      aProjection = sketch()->addFeature(SketchPlugin_Circle::ID());
+
+    // update attributes of projection
+    std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
+    aCenterPnt->setValue(aCenterInSketch);
+    aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aRadius);
+  }
+  else if (anEdge->isArc()) {
+    std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
+    std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
+    std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
+    std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
+
+    std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
+    std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
+
+    if (!aProjection)
+      aProjection = sketch()->addFeature(SketchPlugin_Arc::ID());
+
+    // update attributes of projection
+    std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Arc::START_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aProjection->attribute(SketchPlugin_Arc::END_ID()));
+    aStartPnt->setValue(aFirstInSketch);
+    aEndPnt->setValue(aLastInSketch);
+    aCenterPnt->setValue(aCenterInSketch);
+  }
+
+  aProjection->execute();
+  aRefAttr->setObject(aProjection);
+
+  if (theID == EXTERNAL_FEATURE_ID())
+    selection(EXTERNAL_ID())->setValue(aExtFeature->context(), aExtFeature->context()->shape());
+}
diff --git a/src/SketchPlugin/SketchPlugin_Projection.h b/src/SketchPlugin/SketchPlugin_Projection.h
new file mode 100644 (file)
index 0000000..f71b899
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_Projection.h
+// Created: 20 April 2016
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_Projection_H_
+#define SketchPlugin_Projection_H_
+
+#include "SketchPlugin_SketchEntity.h"
+
+/** \class SketchPlugin_Projection
+ *  \ingroup Plugins
+ *  \brief Feature for creation of external feature as a projection onto the sketch plane.
+ */
+class SketchPlugin_Projection : public SketchPlugin_SketchEntity
+{
+public:
+  /// Projection feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_PROJECTION_ID("SketchProjection");
+    return MY_PROJECTION_ID;
+  }
+  /// Returns the kind of a feature
+  virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_Projection::ID();
+    return MY_KIND;
+  }
+
+  static const std::string& EXTERNAL_FEATURE_ID()
+  {
+    static std::string MY_EXT_FEATURE_ID("ExternalFeature");
+    return MY_EXT_FEATURE_ID;
+  }
+
+  static const std::string& PROJECTED_FEATURE_ID()
+  {
+    static std::string MY_PROJ_FEATURE_ID("ProjectedFeature");
+    return MY_PROJ_FEATURE_ID;
+  }
+
+  /// Returns true because projected feature is always external
+  virtual bool isFixed()
+  { return true; }
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Moves the feature
+  /// \param theDeltaX the delta for X coordinate is moved
+  /// \param theDeltaY the delta for Y coordinate is moved
+  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
+
+  /// Called on change of any argument-attribute of this object: for external point
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_Projection();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+
+private:
+  /// \brief Find projection of a feature onto sketch plane
+  void computeProjection(const std::string& theID);
+
+  bool myIsComputing;
+};
+
+#endif
index 6b4b55c9276e0e7eccf423d9e4edc8941dd53bf3..6f66dc5c734d0669c3a82d0c6fc4d0f731481420 100755 (executable)
@@ -32,6 +32,7 @@
 #include <ModelAPI_Session.h>
 #include <ModelAPI_ResultConstruction.h>
 
+#include <GeomAPI_Circ.h>
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Vertex.h>
@@ -813,3 +814,61 @@ bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribut
   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
   return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
 }
+
+bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
+                                               const std::list<std::string>& theArguments,
+                                               std::string& theError) const
+{
+  if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
+    theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
+    return false;
+  }
+
+  AttributeSelectionPtr aFeatureAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+  std::shared_ptr<GeomAPI_Edge> anEdge;
+  if(aFeatureAttr && aFeatureAttr->value() && aFeatureAttr->value()->isEdge()) {
+    anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
+  } else if(aFeatureAttr->context() && aFeatureAttr->context()->shape() &&
+            aFeatureAttr->context()->shape()->isEdge()) {
+    anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
+  }
+
+  if (!anEdge) {
+    theError = "The attribute " + theAttribute->id() + " should be an edge";
+    return false;
+  }
+
+  // find a sketch
+  std::shared_ptr<SketchPlugin_Sketch> aSketch;
+  std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
+  std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
+  for (; anIt != aRefs.end(); ++anIt) {
+    CompositeFeaturePtr aComp =
+        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
+    if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
+      aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
+      break;
+    }
+  }
+  if (!aSketch) {
+    theError = "There is no sketch referring to the current feature";
+    return false;
+  }
+
+  std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
+  std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
+
+  if (anEdge->isLine()) {
+    std::shared_ptr<GeomAPI_Dir> aLineDir = anEdge->line()->direction();
+    double aDot = aNormal->dot(aLineDir);
+    return aDot > -1.0 + tolerance && aDot < 1.0 - tolerance;
+  }
+  else if (anEdge->isCircle() || anEdge->isArc()) {
+    std::shared_ptr<GeomAPI_Dir> aCircNormal = anEdge->circle()->normal();
+    double aDot = fabs(aNormal->dot(aCircNormal));
+    return fabs(aDot - 1.0) < tolerance * tolerance;
+  }
+
+  return false;
+}
index 49854af5e11f9d1ce32f11219c310a2283227ad8..f201e1b3a0da5248a9a1099910e8be0b39e7f3c6 100644 (file)
@@ -234,4 +234,20 @@ class SketchPlugin_IntersectionValidator : public ModelAPI_AttributeValidator
                        std::string& theError) const;
 };
 
+/**\class SketchPlugin_ProjectionValidator
+ * \ingroup Validators
+ * \brief Validator for the attribute to be projected onto the sketch plane.
+ */
+class SketchPlugin_ProjectionValidator : public ModelAPI_AttributeValidator
+{
+ public:
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       std::string& theError) const;
+};
+
 #endif
diff --git a/src/SketchPlugin/icons/projection.png b/src/SketchPlugin/icons/projection.png
new file mode 100644 (file)
index 0000000..38ec567
Binary files /dev/null and b/src/SketchPlugin/icons/projection.png differ
index 2839741b74160a3152ba5b5def0f752c307bc592..3a03d14740467c07c827b2e0bc60c1bfe09dc80c 100644 (file)
@@ -5,7 +5,7 @@
     <group id="Geometry">
       <feature
         id="Sketch"
-        nested="SketchPoint SketchIntersectionPoint SketchLine SketchCircle SketchArc SketchRectangle SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
+        nested="SketchPoint SketchIntersectionPoint SketchLine SketchCircle SketchArc SketchRectangle SketchProjection SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
         when_nested="accept abort"
         title="Sketch"
         tooltip="Create sketch"
       </feature>
     </group>
 
-    <!--<group id="Projection"> -->
+    <!--<group id="Projection">-->
       <!-- Intersection Point -->
       <!-- feature
         id="SketchIntersectionPoint"
         </sketch_shape_selector>
         <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
       </feature -->
+
+      <!-- Projected feature -->
+      <!--<feature
+        id="SketchProjection"
+        title="Projection"
+        tooltip="Project feature onto sketch plane"
+        icon="icons/Sketch/projection.png">
+        <sketch_shape_selector
+              id="ExternalFeature"
+              label="Edge"
+              tooltip="Select external edge."
+              shape_types="edge"
+              use_sketch_plane="false">
+          <validator id="SketchPlugin_ProjectionValidator"/>
+        </sketch_shape_selector>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+      </feature> -->
     <!--</group>-->
 
     <group id="Replication">