FeaturesAPI_ExtrusionBoolean.h
FeaturesAPI_Fillet.h
FeaturesAPI_Intersection.h
+ FeaturesAPI_Measurement.h
FeaturesAPI_MultiRotation.h
FeaturesAPI_MultiTranslation.h
FeaturesAPI_Partition.h
FeaturesAPI_ExtrusionBoolean.cpp
FeaturesAPI_Fillet.cpp
FeaturesAPI_Intersection.cpp
+ FeaturesAPI_Measurement.cpp
FeaturesAPI_MultiRotation.cpp
FeaturesAPI_MultiTranslation.cpp
FeaturesAPI_Partition.cpp
%include "FeaturesAPI_ExtrusionBoolean.h"
%include "FeaturesAPI_Fillet.h"
%include "FeaturesAPI_Intersection.h"
+%include "FeaturesAPI_Measurement.h"
%include "FeaturesAPI_MultiRotation.h"
%include "FeaturesAPI_MultiTranslation.h"
%include "FeaturesAPI_Partition.h"
--- /dev/null
+// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "FeaturesAPI_Measurement.h"
+
+#include <FeaturesPlugin_Measurement.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelHighAPI_Services.h>
+#include <ModelHighAPI_Tools.h>
+
+double measureLength(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theEdge)
+{
+ FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+ fillAttribute(FeaturesPlugin_Measurement::MEASURE_LENGTH(),
+ aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+ fillAttribute(theEdge, aMeasure->selection(FeaturesPlugin_Measurement::EDGE_FOR_LENGTH_ID()));
+ aMeasure->execute();
+
+ // obtain result
+ AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+ aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+ double aValue = aResult->size() ? aResult->value(0) : -1.0;
+
+ // perform removing macro feature Measurement
+ thePart->removeFeature(aMeasure);
+ apply();
+
+ return aValue;
+}
+
+double measureDistance(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theFrom,
+ const ModelHighAPI_Selection& theTo)
+{
+ FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+ fillAttribute(FeaturesPlugin_Measurement::MEASURE_DISTANCE(),
+ aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+ fillAttribute(theFrom,
+ aMeasure->selection(FeaturesPlugin_Measurement::DISTANCE_FROM_OBJECT_ID()));
+ fillAttribute(theTo, aMeasure->selection(FeaturesPlugin_Measurement::DISTANCE_TO_OBJECT_ID()));
+ aMeasure->execute();
+
+ // obtain result
+ AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+ aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+ double aValue = aResult->size() ? aResult->value(0) : -1.0;
+
+ // perform removing macro feature Measurement
+ thePart->removeFeature(aMeasure);
+ apply();
+
+ return aValue;
+}
+
+double measureRadius(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theObject)
+{
+ FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+ fillAttribute(FeaturesPlugin_Measurement::MEASURE_RADIUS(),
+ aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+ fillAttribute(theObject, aMeasure->selection(FeaturesPlugin_Measurement::CIRCULAR_OBJECT_ID()));
+ aMeasure->execute();
+
+ // obtain result
+ AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+ aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+ double aValue = aResult->size() ? aResult->value(0) : -1.0;
+
+ // perform removing macro feature Measurement
+ thePart->removeFeature(aMeasure);
+ apply();
+
+ return aValue;
+}
+
+std::list<double> measureAngle(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theFrom,
+ const ModelHighAPI_Selection& theTo)
+{
+ FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+ fillAttribute(FeaturesPlugin_Measurement::MEASURE_ANGLE(),
+ aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+ fillAttribute(theFrom, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_FROM_EDGE_ID()));
+ fillAttribute(theTo, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_TO_EDGE_ID()));
+ aMeasure->execute();
+
+ // obtain result
+ AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+ aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+ std::list<double> aValues;
+ for (int i = 0, n = aResult->size(); i < n; ++i)
+ aValues.push_back(aResult->value(i));
+
+ // perform removing macro feature Measurement
+ thePart->removeFeature(aMeasure);
+ apply();
+
+ return aValues;
+}
--- /dev/null
+// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef FeaturesAPI_Measurement_H_
+#define FeaturesAPI_Measurement_H_
+
+#include "FeaturesAPI.h"
+
+#include <list>
+#include <memory>
+
+class ModelAPI_Document;
+class ModelHighAPI_Selection;
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate length of the edge.
+FEATURESAPI_EXPORT
+double measureLength(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theEdge);
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate distance between objects.
+FEATURESAPI_EXPORT
+double measureDistance(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theFrom,
+ const ModelHighAPI_Selection& theTo);
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate radius of circular.
+FEATURESAPI_EXPORT
+double measureRadius(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theObject);
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate angle(s) between edges.
+FEATURESAPI_EXPORT
+std::list<double> measureAngle(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& theFrom,
+ const ModelHighAPI_Selection& theTo);
+
+#endif // FeaturesAPI_Measurement_H_
//==================================================================================================
FeaturesAPI_Symmetry::FeaturesAPI_Symmetry(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theMainObjects,
- const ModelHighAPI_Selection& theObject)
+ const std::list<ModelHighAPI_Selection>& theMainObjects,
+ const ModelHighAPI_Selection& theObject)
: ModelHighAPI_Interface(theFeature)
{
if(initialize()) {
AttributeSelectionListPtr anAttrObjects =
aBase->selectionList(FeaturesPlugin_Symmetry::OBJECTS_LIST_ID());
- theDumper << aBase << " = model.addSymmetry(" << aDocName << ", " << anAttrObjects;
+ theDumper << aBase << " = model.addMirror(" << aDocName << ", " << anAttrObjects;
std::string aCreationMethod =
aBase->string(FeaturesPlugin_Symmetry::CREATION_METHOD())->value();
}
//==================================================================================================
-SymmetryPtr addSymmetry(const std::shared_ptr<ModelAPI_Document>& thePart,
- const std::list<ModelHighAPI_Selection>& theMainObjects,
- const ModelHighAPI_Selection& theObject)
+SymmetryPtr addMirror(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theMainObjects,
+ const ModelHighAPI_Selection& theObject)
{
std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Symmetry::ID());
return SymmetryPtr(new FeaturesAPI_Symmetry(aFeature, theMainObjects, theObject));
/// \class FeaturesAPI_Symmetry
/// \ingroup CPPHighAPI
-/// \brief Interface for Symmetry feature.
+/// \brief Interface for the Mirror Copy feature.
class FeaturesAPI_Symmetry: public ModelHighAPI_Interface
{
public:
/// Constructor with values.
FEATURESAPI_EXPORT
explicit FeaturesAPI_Symmetry(const std::shared_ptr<ModelAPI_Feature>& theFeature,
- const std::list<ModelHighAPI_Selection>& theMainObjects,
- const ModelHighAPI_Selection& theObject);
+ const std::list<ModelHighAPI_Selection>& theMainObjects,
+ const ModelHighAPI_Selection& theObject);
/// Destructor.
FEATURESAPI_EXPORT
typedef std::shared_ptr<FeaturesAPI_Symmetry> SymmetryPtr;
/// \ingroup CPPHighAPI
-/// \brief Create Symmetry feature.
+/// \brief Create the Mirror Copy feature.
FEATURESAPI_EXPORT
-SymmetryPtr addSymmetry(const std::shared_ptr<ModelAPI_Document>& thePart,
- const std::list<ModelHighAPI_Selection>& theMainObjects,
- const ModelHighAPI_Selection& theObject);
+SymmetryPtr addMirror(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const std::list<ModelHighAPI_Selection>& theMainObjects,
+ const ModelHighAPI_Selection& theObject);
#endif // FEATURESAPI_SYMMETRY_H_
#include "FeaturesAPI_ExtrusionBoolean.h"
#include "FeaturesAPI_Fillet.h"
#include "FeaturesAPI_Intersection.h"
+ #include "FeaturesAPI_Measurement.h"
#include "FeaturesAPI_MultiRotation.h"
#include "FeaturesAPI_MultiTranslation.h"
#include "FeaturesAPI_Partition.h"
FeaturesPlugin_MultiTranslation.h
FeaturesPlugin_MultiRotation.h
FeaturesPlugin_Fillet.h
+ FeaturesPlugin_Measurement.h
)
SET(PROJECT_SOURCES
FeaturesPlugin_MultiTranslation.cpp
FeaturesPlugin_MultiRotation.cpp
FeaturesPlugin_Fillet.cpp
+ FeaturesPlugin_Measurement.cpp
)
SET(XML_RESOURCES
multitranslation_widget.xml
multirotation_widget.xml
fillet_widget.xml
+ measurement_widget.xml
)
SET(TEXT_RESOURCES
TestUnion4CurvedFaces.py
TestUnion4Faces.py
TestUnionOfUnion.py
+ TestMeasurementLength.py
+ TestMeasurementDistance.py
+ TestMeasurementRadius.py
+ TestMeasurementAngle.py
Test1922.py
Test1942.py
Test1915.py
--- /dev/null
+// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "FeaturesPlugin_Measurement.h"
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Session.h>
+
+#include <GeomAPI_Angle.h>
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Face.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeIterator.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <iomanip>
+#include <sstream>
+
+FeaturesPlugin_Measurement::FeaturesPlugin_Measurement()
+{
+}
+
+void FeaturesPlugin_Measurement::initAttributes()
+{
+ data()->addAttribute(FeaturesPlugin_Measurement::MEASURE_KIND(),
+ ModelAPI_AttributeString::typeId());
+
+ // attribute for length
+ data()->addAttribute(EDGE_FOR_LENGTH_ID(), ModelAPI_AttributeSelection::typeId());
+ // attributes for distance
+ data()->addAttribute(DISTANCE_FROM_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+ data()->addAttribute(DISTANCE_TO_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+ // attribute for radius
+ data()->addAttribute(CIRCULAR_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+ // attribute for angle
+ data()->addAttribute(ANGLE_FROM_EDGE_ID(), ModelAPI_AttributeSelection::typeId());
+ data()->addAttribute(ANGLE_TO_EDGE_ID(), ModelAPI_AttributeSelection::typeId());
+ // attribute for result message and values
+ data()->addAttribute(RESULT_ID(), ModelAPI_AttributeString::typeId());
+ data()->addAttribute(RESULT_VALUES_ID(), ModelAPI_AttributeDoubleArray::typeId());
+}
+
+void FeaturesPlugin_Measurement::execute()
+{
+}
+
+void FeaturesPlugin_Measurement::attributeChanged(const std::string& theID)
+{
+ if (theID == MEASURE_KIND()) {
+ // clear selected objects
+ selection(EDGE_FOR_LENGTH_ID())->reset();
+ selection(DISTANCE_FROM_OBJECT_ID())->reset();
+ selection(DISTANCE_TO_OBJECT_ID())->reset();
+ selection(CIRCULAR_OBJECT_ID())->reset();
+ selection(ANGLE_FROM_EDGE_ID())->reset();
+ selection(ANGLE_TO_EDGE_ID())->reset();
+ string(RESULT_ID())->setValue("");
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+ attribute(RESULT_VALUES_ID()))->setSize(0);
+ }
+ else if (theID != RESULT_ID()) {
+ std::string aKind = string(MEASURE_KIND())->value();
+ if (aKind == MEASURE_LENGTH())
+ computeLength();
+ else if (aKind == MEASURE_DISTANCE())
+ computeDistance();
+ else if (aKind == MEASURE_RADIUS())
+ computeRadius();
+ else if (aKind == MEASURE_ANGLE())
+ computeAngle();
+ }
+}
+
+void FeaturesPlugin_Measurement::computeLength()
+{
+ AttributeSelectionPtr aSelectedFeature = selection(EDGE_FOR_LENGTH_ID());
+
+ GeomShapePtr aShape;
+ GeomEdgePtr anEdge;
+ if (aSelectedFeature)
+ aShape = aSelectedFeature->value();
+ if (!aShape && aSelectedFeature->context())
+ aShape = aSelectedFeature->context()->shape();
+ if (aShape && aShape->isEdge())
+ anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
+ if (!anEdge)
+ return;
+
+ std::ostringstream anOutput;
+ anOutput << "Length = " << std::setprecision(10) << anEdge->length();
+ string(RESULT_ID())->setValue(anOutput.str());
+
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ aValues->setSize(1);
+ aValues->setValue(0, anEdge->length());
+}
+
+void FeaturesPlugin_Measurement::computeDistance()
+{
+ AttributeSelectionPtr aFirstFeature = selection(DISTANCE_FROM_OBJECT_ID());
+ GeomShapePtr aShape1;
+ if (aFirstFeature)
+ aShape1 = aFirstFeature->value();
+ if (!aShape1 && aFirstFeature->context())
+ aShape1 = aFirstFeature->context()->shape();
+
+ AttributeSelectionPtr aSecondFeature = selection(DISTANCE_TO_OBJECT_ID());
+ GeomShapePtr aShape2;
+ if (aSecondFeature)
+ aShape2 = aSecondFeature->value();
+ if (!aShape2 && aSecondFeature->context())
+ aShape2 = aSecondFeature->context()->shape();
+
+ if (!aShape1 || !aShape2)
+ return;
+
+ double aDistance = GeomAlgoAPI_ShapeTools::minimalDistance(aShape1, aShape2);
+
+ std::ostringstream anOutput;
+ anOutput << "Distance = " << std::setprecision(10) << aDistance;
+ string(RESULT_ID())->setValue(anOutput.str());
+
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ aValues->setSize(1);
+ aValues->setValue(0, aDistance);
+}
+
+void FeaturesPlugin_Measurement::computeRadius()
+{
+ AttributeSelectionPtr aSelectedFeature = selection(CIRCULAR_OBJECT_ID());
+
+ GeomShapePtr aShape;
+ if (aSelectedFeature)
+ aShape = aSelectedFeature->value();
+ if (!aShape && aSelectedFeature->context())
+ aShape = aSelectedFeature->context()->shape();
+
+ double aRadius = -1.0;
+ if (aShape) {
+ if (aShape->isEdge()) {
+ GeomEdgePtr anEdge(new GeomAPI_Edge(aShape));
+ if (anEdge->isCircle()) {
+ aRadius = anEdge->circle()->radius();
+ }
+ } else if (aShape->isFace()) {
+ GeomFacePtr aFace(new GeomAPI_Face(aShape));
+ aRadius = GeomAlgoAPI_ShapeTools::radius(aFace);
+ }
+ }
+
+ if (aRadius < 0.0)
+ return;
+
+ std::ostringstream anOutput;
+ anOutput << "Radius = " << std::setprecision(10) << aRadius;
+ string(RESULT_ID())->setValue(anOutput.str());
+
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ aValues->setSize(1);
+ aValues->setValue(0, aRadius);
+}
+
+void FeaturesPlugin_Measurement::computeAngle()
+{
+ AttributeSelectionPtr aFirstFeature = selection(ANGLE_FROM_EDGE_ID());
+ GeomShapePtr aShape1;
+ GeomEdgePtr anEdge1;
+ if (aFirstFeature)
+ aShape1 = aFirstFeature->value();
+ if (!aShape1 && aFirstFeature->context())
+ aShape1 = aFirstFeature->context()->shape();
+ if (aShape1 && aShape1->isEdge())
+ anEdge1 = GeomEdgePtr(new GeomAPI_Edge(aShape1));
+
+
+ AttributeSelectionPtr aSecondFeature = selection(ANGLE_TO_EDGE_ID());
+ GeomShapePtr aShape2;
+ GeomEdgePtr anEdge2;
+ if (aSecondFeature)
+ aShape2 = aSecondFeature->value();
+ if (!aShape2 && aSecondFeature->context())
+ aShape2 = aSecondFeature->context()->shape();
+ if (aShape2 && aShape2->isEdge())
+ anEdge2 = GeomEdgePtr(new GeomAPI_Edge(aShape2));
+
+ if (!anEdge1 || !anEdge2)
+ return;
+
+ GeomShapePtr anInter = anEdge1->intersect(anEdge2);
+
+ std::ostringstream anOutput;
+ anOutput << std::setprecision(10);
+ std::list<double> aValuesList;
+ if (anInter) {
+ if (anInter->isVertex()) {
+ std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(anInter));
+ std::shared_ptr<GeomAPI_Angle> anAngle(
+ new GeomAPI_Angle(anEdge1, anEdge2, aVertex->point()));
+ double anAngleValue = anAngle->angleDegree();
+ anOutput << "Angle = " << anAngleValue << std::endl;
+ aValuesList.push_back(anAngleValue);
+ }
+ else {
+ GeomAPI_ShapeIterator anIt(anInter);
+ for (int anIndex = 1; anIt.more(); anIt.next(), ++anIndex) {
+ GeomShapePtr aCurrent = anIt.current();
+ if (!aCurrent->isVertex())
+ continue;
+ std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(aCurrent));
+ std::shared_ptr<GeomAPI_Angle> anAngle(
+ new GeomAPI_Angle(anEdge1, anEdge2, aVertex->point()));
+ double anAngleValue = anAngle->angleDegree();
+ anOutput << "Angle" << anIndex << " = " << anAngleValue << std::endl;
+ aValuesList.push_back(anAngleValue);
+ }
+ }
+ }
+
+ string(RESULT_ID())->setValue(anOutput.str());
+
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ aValues->setSize((int)aValuesList.size());
+ int anIndex = 0;
+ for (std::list<double>::iterator anIt = aValuesList.begin(); anIt != aValuesList.end(); ++anIt)
+ aValues->setValue(anIndex++, *anIt);
+}
--- /dev/null
+// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef FeaturesPlugin_Measurement_H_
+#define FeaturesPlugin_Measurement_H_
+
+#include "FeaturesPlugin.h"
+#include <ModelAPI_Feature.h>
+
+/// \class FeaturesPlugin_Measurement
+/// \ingroup Plugins
+/// \brief Feature for calculation metrics.
+///
+/// Supported following metrics:
+/// * length of edge,
+/// * distance between shapes,
+/// * radius of arc or cylindrical faces,
+/// * angle between edges.
+class FeaturesPlugin_Measurement : public ModelAPI_Feature
+{
+public:
+ /// Feature kind.
+ inline static const std::string& ID()
+ {
+ static const std::string MY_ID("Measurement");
+ return MY_ID;
+ }
+
+ /// \return the kind of a feature.
+ virtual const std::string& getKind()
+ {
+ return ID();
+ }
+
+ /// Attribute name for measurement method.
+ inline static const std::string& MEASURE_KIND()
+ {
+ static const std::string MY_MEASURE_KIND_ID("MeasureKind");
+ return MY_MEASURE_KIND_ID;
+ }
+
+ /// Attribute name for length measure.
+ inline static const std::string& MEASURE_LENGTH()
+ {
+ static const std::string MY_MEASURE_ID("Length");
+ return MY_MEASURE_ID;
+ }
+
+ /// Attribute name for distance measure.
+ inline static const std::string& MEASURE_DISTANCE()
+ {
+ static const std::string MY_MEASURE_ID("Distance");
+ return MY_MEASURE_ID;
+ }
+
+ /// Attribute name for radius measure.
+ inline static const std::string& MEASURE_RADIUS()
+ {
+ static const std::string MY_MEASURE_ID("Radius");
+ return MY_MEASURE_ID;
+ }
+
+ /// Attribute name for angle measure.
+ inline static const std::string& MEASURE_ANGLE()
+ {
+ static const std::string MY_MEASURE_ID("Angle");
+ return MY_MEASURE_ID;
+ }
+
+
+ /// Attribute name of edge selected for length calculation.
+ inline static const std::string& EDGE_FOR_LENGTH_ID()
+ {
+ static const std::string MY_EDGE_FOR_LENGTH_ID("edge_for_length");
+ return MY_EDGE_FOR_LENGTH_ID;
+ }
+
+ /// Attribute name of first shape selected for distance calculation.
+ inline static const std::string& DISTANCE_FROM_OBJECT_ID()
+ {
+ static const std::string MY_DISTANCE_FROM_OBJECT_ID("distance_from");
+ return MY_DISTANCE_FROM_OBJECT_ID;
+ }
+
+ /// Attribute name of second shape selected for distance calculation.
+ inline static const std::string& DISTANCE_TO_OBJECT_ID()
+ {
+ static const std::string MY_DISTANCE_TO_OBJECT_ID("distance_to");
+ return MY_DISTANCE_TO_OBJECT_ID;
+ }
+
+ // Attribute name of edge or face selected to calculate radius.
+ inline static const std::string& CIRCULAR_OBJECT_ID()
+ {
+ static const std::string MY_CIRCULAR_OBJECT_ID("circular");
+ return MY_CIRCULAR_OBJECT_ID;
+ }
+
+ /// Attribute name of first edge selected for angle calculation.
+ inline static const std::string& ANGLE_FROM_EDGE_ID()
+ {
+ static const std::string MY_ANGLE_FROM_EDGE_ID("angle_from");
+ return MY_ANGLE_FROM_EDGE_ID;
+ }
+
+ /// Attribute name of second shape selected for distance calculation.
+ inline static const std::string& ANGLE_TO_EDGE_ID()
+ {
+ static const std::string MY_ANGLE_TO_EDGE_ID("angle_to");
+ return MY_ANGLE_TO_EDGE_ID;
+ }
+
+ /// Attribute name for result.
+ inline static const std::string& RESULT_ID()
+ {
+ static const std::string MY_RESULT_ID("result");
+ return MY_RESULT_ID;
+ }
+
+ /// Attribute name for values of result.
+ inline static const std::string& RESULT_VALUES_ID()
+ {
+ static const std::string MY_RESULT_VALUES_ID("result_values");
+ return MY_RESULT_VALUES_ID;
+ }
+
+ /// Creates a new part document if needed
+ FEATURESPLUGIN_EXPORT virtual void execute();
+
+ /// Request for initialization of data model of the feature: adding all attributes
+ FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Called on change of any argument-attribute of this object
+ /// \param theID identifier of changed attribute
+ FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// Reimplemented from ModelAPI_Feature::isMacro(). Returns true.
+ virtual bool isMacro() const { return true; }
+
+ /// Use plugin manager for features creation
+ FeaturesPlugin_Measurement();
+
+private:
+ /// Compute length of the edge
+ void computeLength();
+ /// Compute minimal distance between pair of shapes
+ void computeDistance();
+ /// Compute radius of circular edge or cylindrical face
+ void computeRadius();
+ /// Compute angle(s) between pair of edges if they are intersected
+ void computeAngle();
+};
+
+#endif
#include <FeaturesPlugin_ExtrusionFuse.h>
#include <FeaturesPlugin_Fillet.h>
#include <FeaturesPlugin_Intersection.h>
+#include <FeaturesPlugin_Measurement.h>
#include <FeaturesPlugin_MultiRotation.h>
#include <FeaturesPlugin_MultiTranslation.h>
#include <FeaturesPlugin_Partition.h>
new FeaturesPlugin_ValidatorConcealedResult);
aFactory->registerValidator("FeaturesPlugin_ValidatorFilletSelection",
new FeaturesPlugin_ValidatorFilletSelection);
+ aFactory->registerValidator("FeaturesPlugin_ValidatorCircular",
+ new FeaturesPlugin_ValidatorCircular);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new FeaturesPlugin_MultiRotation);
} else if (theFeatureID == FeaturesPlugin_Fillet::ID()) {
return FeaturePtr(new FeaturesPlugin_Fillet);
+ } else if (theFeatureID == FeaturesPlugin_Measurement::ID()) {
+ return FeaturePtr(new FeaturesPlugin_Measurement);
}
// feature of such kind is not found
#include <FeaturesPlugin_Symmetry.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
#include <GeomAlgoAPI_PointBuilder.h>
#include <GeomAlgoAPI_FaceBuilder.h>
}
//=================================================================================================
-void FeaturesPlugin_Symmetry::performSymmetryByPoint()
+bool FeaturesPlugin_Symmetry::collectSourceObjects(ListOfShape& theSourceShapes,
+ std::list<ResultPtr>& theSourceResults)
{
- // Getting objects.
- ListOfShape anObjects;
- std::list<ResultPtr> aContextes;
AttributeSelectionListPtr anObjectsSelList =
selectionList(FeaturesPlugin_Symmetry::OBJECTS_LIST_ID());
if (anObjectsSelList->size() == 0) {
- return;
+ return false;
}
- for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
+ for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
std::shared_ptr<ModelAPI_AttributeSelection> anObjectAttr =
anObjectsSelList->value(anObjectsIndex);
std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
- if(!anObject.get()) { // may be for not-activated parts
+ if (!anObject.get()) { // may be for not-activated parts
eraseResults();
- return;
+ return false;
}
- anObjects.push_back(anObject);
- aContextes.push_back(anObjectAttr->context());
+ theSourceShapes.push_back(anObject);
+ theSourceResults.push_back(anObjectAttr->context());
}
+ return true;
+}
+
+//=================================================================================================
+void FeaturesPlugin_Symmetry::performSymmetryByPoint()
+{
+ // Getting objects.
+ ListOfShape anObjects;
+ std::list<ResultPtr> aContextes;
+ if (!collectSourceObjects(anObjects, aContextes))
+ return;
//Getting point.
std::shared_ptr<GeomAPI_Pnt> aPoint;
std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
aTrsf->setSymmetry(aPoint);
ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
- ResultPartPtr aResultPart = document()->copyPart(anOrigin, data(), aResultIndex);
- aResultPart->setTrsf(*aContext, aTrsf);
- setResult(aResultPart, aResultIndex);
- } else {
+ buildResult(anOrigin, aTrsf, aResultIndex);
+ }
+ else {
GeomAlgoAPI_Symmetry aSymmetryAlgo(aBaseShape, aPoint);
if (!aSymmetryAlgo.check()) {
break;
}
- ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
- loadNamingDS(aSymmetryAlgo, aResultBody, aBaseShape);
- setResult(aResultBody, aResultIndex);
+ buildResult(aSymmetryAlgo, aBaseShape, aResultIndex);
}
aResultIndex++;
}
// Getting objects.
ListOfShape anObjects;
std::list<ResultPtr> aContextes;
- AttributeSelectionListPtr anObjectsSelList =
- selectionList(FeaturesPlugin_Symmetry::OBJECTS_LIST_ID());
- if (anObjectsSelList->size() == 0) {
+ if (!collectSourceObjects(anObjects, aContextes))
return;
- }
- for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
- std::shared_ptr<ModelAPI_AttributeSelection> anObjectAttr =
- anObjectsSelList->value(anObjectsIndex);
- std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
- if(!anObject.get()) { // may be for not-activated parts
- eraseResults();
- return;
- }
- anObjects.push_back(anObject);
- aContextes.push_back(anObjectAttr->context());
- }
//Getting axis.
std::shared_ptr<GeomAPI_Ax1> anAxis;
std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
aTrsf->setSymmetry(anAxis);
ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
- ResultPartPtr aResultPart = document()->copyPart(anOrigin, data(), aResultIndex);
- aResultPart->setTrsf(*aContext, aTrsf);
- setResult(aResultPart, aResultIndex);
- } else {
+ buildResult(anOrigin, aTrsf, aResultIndex);
+ }
+ else {
GeomAlgoAPI_Symmetry aSymmetryAlgo(aBaseShape, anAxis);
if (!aSymmetryAlgo.check()) {
break;
}
- ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
- loadNamingDS(aSymmetryAlgo, aResultBody, aBaseShape);
- setResult(aResultBody, aResultIndex);
+ buildResult(aSymmetryAlgo, aBaseShape, aResultIndex);
}
aResultIndex++;
}
// Getting objects.
ListOfShape anObjects;
std::list<ResultPtr> aContextes;
- AttributeSelectionListPtr anObjectsSelList =
- selectionList(FeaturesPlugin_Symmetry::OBJECTS_LIST_ID());
- if (anObjectsSelList->size() == 0) {
+ if (!collectSourceObjects(anObjects, aContextes))
return;
- }
- for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
- std::shared_ptr<ModelAPI_AttributeSelection> anObjectAttr =
- anObjectsSelList->value(anObjectsIndex);
- std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
- if(!anObject.get()) { // may be for not-activated parts
- eraseResults();
- return;
- }
- anObjects.push_back(anObject);
- aContextes.push_back(anObjectAttr->context());
- }
//Getting axis.
std::shared_ptr<GeomAPI_Ax2> aPlane;
std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
aTrsf->setSymmetry(aPlane);
ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
- ResultPartPtr aResultPart = document()->copyPart(anOrigin, data(), aResultIndex);
- aResultPart->setTrsf(*aContext, aTrsf);
- setResult(aResultPart, aResultIndex);
+ buildResult(anOrigin, aTrsf, aResultIndex);
} else {
GeomAlgoAPI_Symmetry aSymmetryAlgo(aBaseShape, aPlane);
break;
}
- ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
- loadNamingDS(aSymmetryAlgo, aResultBody, aBaseShape);
- setResult(aResultBody, aResultIndex);
+ buildResult(aSymmetryAlgo, aBaseShape, aResultIndex);
}
aResultIndex++;
}
removeResults(aResultIndex);
}
+//=================================================================================================
+void FeaturesPlugin_Symmetry::buildResult(GeomAlgoAPI_Symmetry& theSymmetryAlgo,
+ std::shared_ptr<GeomAPI_Shape> theBaseShape,
+ int theResultIndex)
+{
+ // Compose source shape and the result of symmetry.
+ ListOfShape aShapes;
+ aShapes.push_back(theBaseShape);
+ aShapes.push_back(theSymmetryAlgo.shape());
+ std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+
+ // Store and name the result.
+ ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
+ aResultBody->storeModified(theBaseShape, aCompound);
+ loadNamingDS(theSymmetryAlgo, aResultBody, theBaseShape);
+ setResult(aResultBody, theResultIndex);
+}
+
+//=================================================================================================
+void FeaturesPlugin_Symmetry::buildResult(ResultPartPtr theOriginal,
+ std::shared_ptr<GeomAPI_Trsf> theTrsf,
+ int& theResultIndex)
+{
+ std::shared_ptr<GeomAPI_Trsf> anIdentity(new GeomAPI_Trsf());
+ ResultPartPtr aCopy = document()->copyPart(theOriginal, data(), theResultIndex);
+ aCopy->setTrsf(theOriginal, anIdentity);
+ setResult(aCopy, theResultIndex);
+
+ ++theResultIndex;
+
+ ResultPartPtr aResultPart = document()->copyPart(theOriginal, data(), theResultIndex);
+ aResultPart->setTrsf(theOriginal, theTrsf);
+ setResult(aResultPart, theResultIndex);
+}
+
//=================================================================================================
void FeaturesPlugin_Symmetry::loadNamingDS(GeomAlgoAPI_Symmetry& theSymmetryAlgo,
std::shared_ptr<ModelAPI_ResultBody> theResultBody,
std::shared_ptr<GeomAPI_Shape> theBaseShape)
{
- // Store and name the result.
- theResultBody->storeModified(theBaseShape, theSymmetryAlgo.shape());
-
// Name the faces
std::shared_ptr<GeomAPI_DataMapOfShapeShape> aSubShapes = theSymmetryAlgo.mapOfSubShapes();
std::string aReflectedName = "Symmetried";
#include <GeomAlgoAPI_Symmetry.h>
+class GeomAPI_Trsf;
+
/** \class FeaturesPlugin_Symmetry
* \ingroup Plugins
* \brief Feature that performs reflection with respect to a point, axis, or plane.
/// Symmetry kind.
inline static const std::string& ID()
{
- static const std::string MY_SYMMETRY_ID("Symmetry");
+ static const std::string MY_SYMMETRY_ID("MirrorCopy");
return MY_SYMMETRY_ID;
}
FeaturesPlugin_Symmetry();
private:
+ /// Obtain list of source objects of the mirror
+ bool collectSourceObjects(ListOfShape& theSourceShapes,
+ std::list<std::shared_ptr<ModelAPI_Result>>& theSourceResults);
+
/// Perform symmetry with respect to a point.
void performSymmetryByPoint();
void loadNamingDS(GeomAlgoAPI_Symmetry& theSymmetryAlgo,
std::shared_ptr<ModelAPI_ResultBody> theResultBody,
std::shared_ptr<GeomAPI_Shape> theBaseShape);
+
+ /// Create new result on given shapes and the index of result
+ void buildResult(GeomAlgoAPI_Symmetry& theSymmetryAlgo,
+ std::shared_ptr<GeomAPI_Shape> theBaseShape,
+ int theResultIndex);
+
+ /// Create new result for the given part and transformation
+ void buildResult(std::shared_ptr<ModelAPI_ResultPart> theOriginal,
+ std::shared_ptr<GeomAPI_Trsf> theTrsf,
+ int& theResultIndex);
};
#endif // FEATURESPLUGIN_SYMMETRY_H_
#include <ModelAPI_Tools.h>
#include <GeomValidators_BodyShapes.h>
+#include <GeomValidators_Face.h>
#include <GeomValidators_FeatureKind.h>
#include <GeomValidators_ShapeType.h>
return theError.empty();
}
+
+bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ static std::list<std::string> aEdgeArg(1, "circle");
+ static std::list<std::string> aFaceArg(1, "cylinder");
+
+ Events_InfoMessage aError;
+ bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
+ if (!isValid) {
+ isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
+ if (!isValid)
+ theError = "The shape neither circle nor cylinder";
+ }
+ return isValid;
+}
Events_InfoMessage& theError) const;
};
+/// \class FeaturesPlugin_ValidatorCircular
+/// \ingroup Validators
+/// \brief Verifies the selected object is circular edge or cylindrical face
+class FeaturesPlugin_ValidatorCircular : public ModelAPI_AttributeValidator
+{
+public:
+ //! \return True if the attribute is valid.
+ //! \param[in] theAttribute the checked attribute.
+ //! \param[in] theArguments arguments of the attribute.
+ //! \param[out] theError error message.
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
#endif
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"))
+SketchLine_7 = Sketch_2.addLine(119.1454520140253, 130.0744845530344, 10, 0)
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_3.createdFeature()
+SketchConstraintAngle_1 = Sketch_2.setAngle(SketchLine_8.result(), SketchLine_7.result(), 50)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.result())
+SketchConstraintDistanceHorizontal_2 = Sketch_2.setHorizontalDistance(SketchAPI_Line(SketchLine_8).startPoint(), SketchLine_7.endPoint(), 10)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [("Sketch_1/Edge-SketchLine_3", "Sketch_1/Edge-SketchLine_6", [90]),
+ ("Extrusion_1_1/Generated_Face_5", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", [45]),
+ ("Sketch_1/Edge-SketchCircle_1_2", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", [0]),
+ ("Sketch_1/Edge-SketchLine_3", "Sketch_1/Edge-SketchCircle_1_2", []),
+ ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", []),
+ ("Sketch_2/Edge-SketchLine_7", "Extrusion_1_1/To_Face_1&Extrusion_1_1/Generated_Face_4", [130]),
+ ("Sketch_2/Edge-SketchLine_7", "Extrusion_1_1/To_Face_1&Extrusion_1_1/Generated_Face_1", [140]),
+ ("Sketch_2/Edge-SketchLine_7", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", [85.95645561, 95.19768874])
+ ]
+
+for ref in REF_DATA:
+ angle = model.measureAngle(Part_1_doc, model.selection("EDGE", ref[0]), model.selection("EDGE", ref[1]))
+ assert(angle.size() == len(ref[2]))
+ for a, r in zip(angle, ref[2]):
+ assert(math.fabs(a - r) < TOLERANCE), "Angle {} differs from expected value {}".format(a, r)
+
+# select incorrect data
+angle = model.measureAngle(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"), model.selection("EDGE", "Sketch_2/Edge-SketchLine_7"))
+assert(angle.size() == 0)
+
+model.end()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchArc_1 = Sketch_2.addArc(100, 48.41229182762603, 87.5, 0, 87.5, 96.82458365525073, False)
+SketchArc_2 = Sketch_2.addArc(0, 48.41229182762603, 87.5, 0, 87.5, 96.82458365525073, False)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchArc_1.startPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchArc_2.endPoint(), SketchArc_1.endPoint())
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchArc_1.results()[1], "R")
+SketchConstraintRadius_3 = Sketch_2.setRadius(SketchArc_2.results()[1], "2*R")
+SketchLine_7 = Sketch_2.addLine(0, 48.41229182762603, 100, 48.41229182762603)
+SketchLine_7.setAuxiliary(True)
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_2.center(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchArc_1.center(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_7.result())
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_8 = SketchProjection_3.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchArc_1.startPoint(), SketchLine_8.result())
+SketchProjection_4 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_9 = SketchProjection_4.createdFeature()
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_7.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchArc_2.results()[1])
+SketchConstraintMirror_1 = Sketch_2.addMirror(SketchLine_9.result(), [SketchArc_2.results()[1], SketchArc_1.results()[1]])
+[SketchArc_3, SketchArc_4] = SketchConstraintMirror_1.mirrored()
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")], model.selection(), 100, 0)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [(model.selection("VERTEX", "PartSet/Origin"),
+ model.selection("VERTEX", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1"),
+ 122.4744871),
+ (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1"),
+ model.selection("VERTEX", "Sketch_2/Vertex-SketchArc_1-SketchLine_7e"),
+ 36.94403089),
+ (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"),
+ model.selection("EDGE", "Extrusion_1_1/Generated_Face_5"),
+ 0),
+ (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"),
+ model.selection("EDGE", "Extrusion_2_1/Generated_Face_2&Extrusion_2_1/To_Face_1"),
+ 16.00781059),
+ (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"),
+ model.selection("FACE", "Extrusion_2_1/Generated_Face_2"),
+ 8.412291828),
+ (model.selection("VERTEX", "Sketch_1/Vertex-SketchCircle_1"),
+ model.selection("FACE", "Plane_1"),
+ 35.35533906),
+ (model.selection("FACE", "Extrusion_2_2/From_Face_1"),
+ model.selection("FACE", "Extrusion_2_2/To_Face_1"),
+ 100),
+ (model.selection("FACE", "Extrusion_1_1/Generated_Face_5"),
+ model.selection("FACE", "Extrusion_2_1/Generated_Face_2"),
+ 0),
+ (model.selection("FACE", "Extrusion_1_1/Generated_Face_5"),
+ model.selection("FACE", "Extrusion_1_1/Generated_Face_2"),
+ 27.63932023),
+ (model.selection("SOLID", "Extrusion_1_1"),
+ model.selection("FACE", "Extrusion_2_1/To_Face_1"),
+ 12.5),
+ (model.selection("SOLID", "Extrusion_1_1"),
+ model.selection("SOLID", "Extrusion_2_1"),
+ 0),
+ (model.selection("SOLID", "Extrusion_1_1"),
+ model.selection("SOLID", "Extrusion_2_2"),
+ 87.5)
+ ]
+
+for ref in REF_DATA:
+ dist = model.measureDistance(Part_1_doc, ref[0], ref[1])
+ assert(math.fabs(dist - ref[2]) < TOLERANCE), "Distance {} differs from expected value {}".format(dist, ref[2])
+
+model.end()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [("Extrusion_1_1/From_Face_1&Extrusion_1_1/Generated_Face_1", ParamH.value()),
+ ("Extrusion_1_1/From_Face_1&Extrusion_1_1/Generated_Face_4", ParamL.value()),
+ ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1", ParamR.value() * 2.0 * math.pi),
+ ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", 381.981436664),
+ ("Extrusion_1_1/Generated_Face_5", 60),
+ ("Sketch_1/Edge-SketchLine_3", ParamL.value()),
+ ("Sketch_1/Edge-SketchLine_4", ParamH.value()),
+ ("Sketch_1/Edge-SketchCircle_1_2", ParamR.value() * 2.0 * math.pi)
+ ]
+
+for ref in REF_DATA:
+ length = model.measureLength(Part_1_doc, model.selection("EDGE", ref[0]))
+ assert(math.fabs(length - ref[1]) < TOLERANCE), "Length {} differs from expected value {}".format(length, ref[1])
+
+# select incorrect data
+length = model.measureLength(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_5"))
+assert(length == -1)
+
+model.end()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [(model.selection("EDGE", "Sketch_1/Edge-SketchCircle_1_2"), ParamR.value()),
+ (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"), ParamR.value()),
+ (model.selection("FACE", "Extrusion_1_1/Generated_Face_5"), ParamR.value())
+ ]
+
+for ref in REF_DATA:
+ radius = model.measureRadius(Part_1_doc, ref[0])
+ assert(math.fabs(radius - ref[1]) < TOLERANCE), "Radius {} differs from expected value {}".format(radius, ref[1])
+
+# select incorrect data
+radius = model.measureRadius(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"))
+assert(radius == -1)
+
+model.end()
--- /dev/null
+<!--
+Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+See http:##www.salome-platform.org/ or
+email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+-->
+
+<source>
+ <toolbox id="MeasureKind">
+ <box id="Length" title="Edge length" icon="icons/Features/meas_length_32x32.png">
+ <shape_selector id="edge_for_length"
+ icon="icons/Features/edge.png"
+ label="Edge"
+ tooltip="Select an edge"
+ shape_types="edge"
+ default="">
+ <validator id="GeomValidators_ShapeType" parameters="edge"/>
+ </shape_selector>
+ </box>
+ <box id="Distance" title="Distance between objects" icon="icons/Features/meas_distance_32x32.png">
+ <shape_selector id="distance_from"
+ icon=""
+ label="From"
+ tooltip="Select a shape"
+ shape_types="vertex edge wire face shell solid objects"
+ default="">
+ </shape_selector>
+ <shape_selector id="distance_to"
+ icon=""
+ label="To"
+ tooltip="Select a shape"
+ shape_types="vertex edge wire face shell solid objects"
+ default="">
+ </shape_selector>
+ </box>
+ <box id="Radius" title="Radius of circular" icon="icons/Features/meas_radius_32x32.png">
+ <shape_selector id="circular"
+ icon=""
+ label="Object"
+ tooltip="Select an edge or face"
+ shape_types="edge face"
+ default="">
+ <validator id="FeaturesPlugin_ValidatorCircular"/>
+ </shape_selector>
+ </box>
+ <box id="Angle" title="Angle between edges" icon="icons/Features/meas_angle_32x32.png">
+ <shape_selector id="angle_from"
+ icon="icons/Features/edge.png"
+ label="First edge"
+ tooltip="Select an edge"
+ shape_types="edge"
+ default="">
+ <validator id="GeomValidators_ShapeType" parameters="edge"/>
+ </shape_selector>
+ <shape_selector id="angle_to"
+ icon="icons/Features/edge.png"
+ label="Second edge"
+ tooltip="Select an edge"
+ shape_types="edge"
+ default="">
+ <validator id="GeomValidators_ShapeType" parameters="edge"/>
+ </shape_selector>
+ </box>
+ </toolbox>
+ <label id="result"/>
+</source>
<feature id="Rotation" title="Rotation" tooltip="Perform rotation of an objects around the axis to specified angle" icon="icons/Features/rotation.png">
<source path="rotation_widget.xml"/>
</feature>
- <feature id="Symmetry" title="Symmetry" tooltip="Perform symmetry with respect to a point, an axis or a plane" icon="icons/Features/symmetry.png">
+ <feature id="MirrorCopy" title="Mirror copy" tooltip="Perform symmetry with respect to a point, an axis or a plane" icon="icons/Features/symmetry.png">
<source path="symmetry_widget.xml"/>
</feature>
<feature id="LinearCopy" title="Linear copy" tooltip="Perform copy and translate" icon="icons/Features/multitranslation.png">
<source path="multirotation_widget.xml"/>
</feature>
</group>
+ <group id="Measurement">
+ <feature id="Measurement" title="Measurement" tooltip="Calculate properties of objects" icon="icons/Features/measurement.png">
+ <source path="measurement_widget.xml"/>
+ </feature>
+ </group>
</workbench>
</plugin>
GeomAPI_Ax3.h
GeomAPI_Trsf.h
GeomAPI_Angle2d.h
+ GeomAPI_Angle.h
GeomAPI_Wire.h
GeomAPI_Ellipse.h
GeomAPI_Ellipse2d.h
GeomAPI_IPresentable.cpp
GeomAPI_Trsf.cpp
GeomAPI_Angle2d.cpp
+ GeomAPI_Angle.cpp
GeomAPI_Wire.cpp
GeomAPI_Ellipse.cpp
GeomAPI_Ellipse2d.cpp
--- /dev/null
+// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <GeomAPI_Angle.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pnt.h>
+
+#include <BRep_Tool.hxx>
+#include <ElCLib.hxx>
+#include <Geom_Curve.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <Precision.hxx>
+#include <TopoDS_Edge.hxx>
+
+/// \struct AngleDirections
+/// \brief Used to store info about angle.
+struct AngleDirections {
+ gp_Vec myDir1;
+ gp_Vec myDir2;
+};
+
+#define MY_ANGLE implPtr<AngleDirections>()
+#define PI 3.1415926535897932
+
+
+GeomAPI_Angle::GeomAPI_Angle(const std::shared_ptr<GeomAPI_Edge>& theEdge1,
+ const std::shared_ptr<GeomAPI_Edge>& theEdge2,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint)
+{
+ gp_Pnt aPoint = thePoint->impl<gp_Pnt>();
+ const TopoDS_Edge& anEdge1 = theEdge1->impl<TopoDS_Edge>();
+ const TopoDS_Edge& anEdge2 = theEdge2->impl<TopoDS_Edge>();
+
+ double aF1, aL1;
+ Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aF1, aL1);
+ double aF2, aL2;
+ Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aF2, aL2);
+
+ AngleDirections* anAngle = new AngleDirections;
+ gp_Pnt aP;
+
+ GeomAPI_ProjectPointOnCurve aProj1(aPoint, aCurve1);
+ if (aProj1.NbPoints() > 0)
+ aCurve1->D1(aProj1.Parameter(1), aP, anAngle->myDir1);
+
+ GeomAPI_ProjectPointOnCurve aProj2(aPoint, aCurve2);
+ if (aProj2.NbPoints() > 0)
+ aCurve2->D1(aProj2.Parameter(1), aP, anAngle->myDir2);
+
+ setImpl(anAngle);
+}
+
+double GeomAPI_Angle::angleDegree()
+{
+ return angleRadian() * 180.0 / PI;
+}
+
+double GeomAPI_Angle::angleRadian()
+{
+ AngleDirections* anAngle = MY_ANGLE;
+ if (anAngle->myDir1.SquareMagnitude() < Precision::SquareConfusion() ||
+ anAngle->myDir2.SquareMagnitude() < Precision::SquareConfusion())
+ return 0.0;
+
+ gp_Dir aDir1(anAngle->myDir1);
+ gp_Dir aDir2(anAngle->myDir2);
+ double aRes = aDir1.Angle(aDir2);
+ aRes = ElCLib::InPeriod(aRes, 0.0, 2.0 * PI);
+ if (Abs(aRes) < 1.e-12)
+ aRes = 0.0;
+ return aRes;
+}
--- /dev/null
+// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef GeomAPI_Angle_H_
+#define GeomAPI_Angle_H_
+
+#include <GeomAPI_Interface.h>
+
+class GeomAPI_Edge;
+class GeomAPI_Pnt;
+
+/// \class GeomAPI_Angle
+/// \ingroup DataModel
+/// \brief Build an angle
+class GeomAPI_Angle : public GeomAPI_Interface
+{
+public:
+ /// Creation of an angle defined by two edges in the given intersection point.
+ GEOMAPI_EXPORT
+ GeomAPI_Angle(const std::shared_ptr<GeomAPI_Edge>& theEdge1,
+ const std::shared_ptr<GeomAPI_Edge>& theEdge2,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint);
+
+ /// Returns value of the angle in degrees
+ GEOMAPI_EXPORT double angleDegree();
+ /// Returns value of the angle in radians
+ GEOMAPI_EXPORT double angleRadian();
+};
+
+#endif
// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
//
-#ifndef GeomAPI_Angle_H_
-#define GeomAPI_Angle_H_
+#ifndef GeomAPI_Angle2d_H_
+#define GeomAPI_Angle2d_H_
#include <GeomAPI_Interface.h>
#include <TopoDS.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
+#include <ElCLib.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
+#include <Geom_Plane.hxx>
+#include <GeomAPI_IntCS.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <gp_Ax1.hxx>
#include <gp_Pln.hxx>
return inPlane;
}
+void GeomAPI_Edge::intersectWithPlane(const std::shared_ptr<GeomAPI_Pln> thePlane,
+ std::list<std::shared_ptr<GeomAPI_Pnt>>& theResult) const
+{
+ double aFirst, aLast;
+ const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+ if (!aCurve.IsNull()) {
+ double A, B, C, D;
+ thePlane->coefficients(A, B, C, D);
+ gp_Pln aPln(A, B, C, D);
+
+ Handle(Geom_Plane) aPlane = new Geom_Plane(aPln);
+ GeomAPI_IntCS aIntersect;
+ aIntersect.Perform(aCurve, aPlane);
+ if (aIntersect.IsDone() && (aIntersect.NbPoints() > 0)) {
+ gp_Pnt aPnt;
+ for (int i = 1; i <= aIntersect.NbPoints(); i++) {
+ // check the parameter of intersection in the edge range
+ aIntersect.Parameters(i, A, B, C);
+ if (aCurve->IsPeriodic())
+ C = ElCLib::InPeriod(C, aFirst, aFirst + aCurve->Period());
+ if (C < aFirst - Precision::PConfusion() || C > aLast + Precision::PConfusion())
+ continue;
+
+ // obtain intersection point
+ aPnt = aIntersect.Point(i);
+ std::shared_ptr<GeomAPI_Pnt> aPntPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
+ theResult.push_back(aPntPtr);
+ }
+ }
+ }
+}
+
double GeomAPI_Edge::length() const
{
const TopoDS_Edge& anEdge = TopoDS::Edge(impl<TopoDS_Shape>());
void getRange(double& theFirst, double& theLast) const;
/// Returns true, if the edge is fully placed in the specified plane
+ /// \param thePlane a plane for intersection
GEOMAPI_EXPORT
bool isInPlane(const std::shared_ptr<GeomAPI_Pln> thePlane) const;
+ /// Returns list of intersection points if the edge has intersections with the given plane
+ /// \param thePlane a plane for intersection
+ GEOMAPI_EXPORT
+ void intersectWithPlane(const std::shared_ptr<GeomAPI_Pln> thePlane,
+ std::list<std::shared_ptr<GeomAPI_Pnt> >& theResult) const;
+
/// Returns edge length.
GEOMAPI_EXPORT
double length() const;
std::shared_ptr<GeomAPI_Pln> getPlane() const;
};
+//! Pointer on attribute object
+typedef std::shared_ptr<GeomAPI_Face> GeomFacePtr;
+
#endif
#include <Geom2d_Curve.hxx>
#include <BRepLib_CheckCurveOnSurface.hxx>
#include <BRep_Tool.hxx>
+#include <Geom_CylindricalSurface.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aCentre.X(), aCentre.Y(), aCentre.Z()));
}
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::radius(const std::shared_ptr<GeomAPI_Face>& theCylinder)
+{
+ double aRadius = -1.0;
+ if (theCylinder->isCylindrical()) {
+ const TopoDS_Shape& aShape = theCylinder->impl<TopoDS_Shape>();
+ Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aShape));
+ Handle(Geom_CylindricalSurface) aCyl = Handle(Geom_CylindricalSurface)::DownCast(aSurf);
+ if (!aCyl.IsNull())
+ aRadius = aCyl->Radius();
+ }
+ return aRadius;
+}
+
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
+ const GeomShapePtr& theShape2)
+{
+ const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+ BRepExtrema_DistShapeShape aDist(aShape1, aShape2);
+ aDist.Perform();
+ return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
+}
+
//==================================================================================================
std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
const std::shared_ptr<GeomAPI_Shape> theCompound,
GEOMALGOAPI_EXPORT static std::shared_ptr<GeomAPI_Pnt>
centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape);
+ /// \brief Obtain radius of cylindrical face.
+ /// Return negative value if the face is not a cylinder
+ GEOMALGOAPI_EXPORT static double radius(const std::shared_ptr<GeomAPI_Face>& theCylinder);
+
+ /// \brief Calculate minimal distance between shapes
+ GEOMALGOAPI_EXPORT static double minimalDistance(const GeomShapePtr& theShape1,
+ const GeomShapePtr& theShape2);
+
/// \brief Combines faces with common edges to shells, or solids to compsolids.
/// \param[in] theCompound compound of shapes.
/// \param[in] theType type of combine.
" positions.append((node.lineno, node.col_offset))\n"
"FindName(name).visit(ast.parse(expression))";
+// make the expression be correct for the python interpreter even for the
+// beta=alfa*2 expressions
+static std::string adjustExpression(const std::string& theExpression) {
+ std::string anExpression = theExpression;
+ if (!anExpression.empty() && anExpression.back() == '=') {
+ anExpression = anExpression.substr(0, anExpression.length() - 1);
+ }
+ return anExpression;
+}
+
std::list<std::pair<int, int> >
InitializationPlugin_PyInterp::positions(const std::string& theExpression,
const std::string& theName)
PyObject* aBuiltinModule = PyImport_AddModule("__builtin__");
PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule);
+ std::string anExpression = adjustExpression(theExpression);
// extend aContext with variables
- PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str()));
+ PyDict_SetItemString(aContext, "expression", PyString_FromString(anExpression.c_str()));
PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str()));
PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]"));
PyErr_Print();
return aResult;
}
+ // support "variable_name=" expression as "variable_name"
+ std::string anExpression = adjustExpression(theExpression);
PyObject *aCodePyObj =
PyObject_CallMethod(aCodeopModule, (char*)"compile_command", (char*)"(s)",
- theExpression.c_str());
+ anExpression.c_str());
if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) {
Py_XDECREF(aCodePyObj);
double InitializationPlugin_PyInterp::evaluate(const std::string& theExpression,
std::string& theError)
{
+ // support "variable_name=" expression as "variable_name"
+ std::string anExpression = adjustExpression(theExpression);
+
PyLockWrapper lck; // Acquire GIL until the end of the method
PyCompilerFlags aFlags = {CO_FUTURE_DIVISION};
aFlags.cf_flags = CO_FUTURE_DIVISION;
- PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileStringFlags(theExpression.c_str(),
+ PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileStringFlags(anExpression.c_str(),
"<string>", Py_eval_input, &aFlags);
if(!anExprCode) {
theError = errorMessage();
bool isOldShape = isOldContext &&
(theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
if (isOldShape) return false; // shape is the same, so context is also unchanged
+ bool aToUnblock = false;
// update the referenced object if needed
if (!isOldContext) {
- myRef.setValue(theContext);
+ aToUnblock = !owner()->data()->blockSendAttributeUpdated(true);
+ myRef.setValue(theContext);
}
// do noth use naming if selected shape is result shape itself, but not sub-shape
TDF_Label aRefLab = myRef.myRef->Label();
aSelLab.ForgetAllAttributes(true);
myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father());
+ if (aToUnblock)
+ owner()->data()->blockSendAttributeUpdated(false);
return false;
}
if (theContext->groupName() == ModelAPI_ResultBody::group()) {
}
owner()->data()->sendAttributeUpdated(this);
+
+ if (aToUnblock)
+ owner()->data()->blockSendAttributeUpdated(false);
+
return true;
}
}
return aRes;
} else {
+ // check is this modified or not
+ std::shared_ptr<GeomAPI_Shape> aNewShape = shape();
+ TopoDS_Shape anOldSh;
+ Handle(TNaming_NamedShape) aNS;
+ if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+ anOldSh = aNS->Get();
+ }
+ if (aNewShape.get()) {
+ if (anOldSh.IsNull())
+ theModified = true;
+ else {
+ std::shared_ptr<GeomAPI_Shape> anOldShape(new GeomAPI_Shape);
+ anOldShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(anOldSh));
+ theModified = !anOldShape->isEqual(aNewShape);
+ }
+ }
+ else if (!anOldSh.IsNull()) {
+ theModified = true;
+ }
+
// For correct naming selection, put the shape into the naming structure.
// It seems sub-shapes are not needed: only this shape is (and can be ) selected.
TNaming_Builder aBuilder(aLab);
- aBuilder.Generated(shape()->impl<TopoDS_Shape>());
+ aBuilder.Generated(aNewShape->impl<TopoDS_Shape>());
}
return shape() && !shape()->isNull();
}
if (aReason != theFeature && (aReason)->data()->isValid()) {
if (processFeature(aReason))
aIsModified = true;
- if (aReason->data()->execState() == ModelAPI_StateInvalidArgument)
+ // check validity of aReason once again because it may be removed by dependent feature
+ // (e.g. by SketchPlugin_IntersectionPoint)
+ if (!aReason->data()->isValid() ||
+ aReason->data()->execState() == ModelAPI_StateInvalidArgument)
isReferencedInvalid = true;
}
// searching for the next not used reason
Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
Cylinder_1.result().setName("cylinder")
Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "cylinder/Face_2"), 10, False)
-Symmetry_1 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "cylinder")], model.selection("FACE", "Plane_1"))
+Symmetry_1 = model.addMirror(Part_1_doc, [model.selection("SOLID", "cylinder")], model.selection("FACE", "Plane_1"))
model.do()
# check the name of the Symmetry
#include "ModuleBase_ParamSpinBox.h"
-#include <ModelAPI_Session.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Feature.h>
-#include <ModelAPI_ResultParameter.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_Tools.h>
-
#include <QKeyEvent>
-#include <QLineEdit>
#include <QLocale>
#include <QRegExp>
#include <QToolTip>
#include <QStringListModel>
#include <QCompleter>
+#include <QAbstractItemView>
#include <QShortcut>
#include <string>
#include <iostream>
-//#define DEBUG_COMPLETE_WITH_PARAMETERS
-
ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
- : ModuleBase_DoubleSpinBox(theParent, thePrecision),
- myAcceptVariables(true)
+ : QAbstractSpinBox(theParent),
+ myPrecision(thePrecision),
+ myIsEquation(false),
+ myAcceptVariables(true),
+ mySingleStep(1),
+ myMinimum(DBL_MIN),
+ myMaximum(DBL_MAX)
{
-#ifdef DEBUG_COMPLETE_WITH_PARAMETERS
myCompleter = new QCompleter(this);
- myCompleter->setWidget(this);
+ myCompleter->setWidget(lineEdit());
myCompleter->setCompletionMode(QCompleter::PopupCompletion);
myCompleterModel = new QStringListModel(this);
// Use sorted model to accelerate completion (QCompleter will use binary search)
myCompleter->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
myCompleter->setCaseSensitivity(Qt::CaseInsensitive);
+ connect(myCompleter, SIGNAL(highlighted(const QString&)),
+ this, SLOT(insertCompletion(const QString&)));
- lineEdit()->setCompleter(myCompleter);
-#endif
+ // connectSignalsAndSlots();
+ myEnabledBaseColor = palette().color(QPalette::Active, QPalette::Base);
+ connect(lineEdit(), SIGNAL(textChanged(const QString&)),
+ this, SLOT(onTextChanged(const QString&)));
- connectSignalsAndSlots();
+ setLocale(QLocale::c());
+
+ myValidator = new QDoubleValidator(this);
+ myValidator->setLocale(locale());
+ myValidator->setRange(myMinimum, myMaximum);
+ myValidator->setDecimals(3);
}
void ModuleBase_ParamSpinBox::setCompletionList(QStringList& theList)
{
-#ifdef DEBUG_COMPLETE_WITH_PARAMETERS
theList.sort();
theList.removeDuplicates();
myCompleterModel->setStringList(theList);
-#endif
}
/*!
{
}
+
/*!
\brief Perform \a steps increment/decrement steps.
*/
void ModuleBase_ParamSpinBox::stepBy(int steps)
{
- if ((!myTextValue.isEmpty()) && hasVariable())
+ if (hasVariable())
return;
- ModuleBase_DoubleSpinBox::stepBy(steps);
+ double aVal = lineEdit()->text().toDouble();
+ aVal += steps * mySingleStep;
+ setValue(aVal);
+ QAbstractSpinBox::stepBy(steps);
}
-/*!
- \brief Connect signals and slots.
- */
-void ModuleBase_ParamSpinBox::connectSignalsAndSlots()
+void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
{
- connect(this, SIGNAL(valueChanged(const QString&)),
- this, SLOT(onTextChanged(const QString&)));
+ myIsEquation = hasVariable(theText);
+ emit textChanged(theText);
}
-void ModuleBase_ParamSpinBox::onTextChanged(const QString& text)
-{
- myTextValue = text;
- emit textChanged(text);
-}
-
-double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
-{
- if (!hasVariable(theText))
- return ModuleBase_DoubleSpinBox::valueFromText(theText);
-
- // small hack: return hash of the string to initiate valuesChanged signal
- return qHash(theText);
-}
-
-QString ModuleBase_ParamSpinBox::textFromValue (double theValue) const
-{
- if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){
- return myTextValue;
- }
- return ModuleBase_DoubleSpinBox::textFromValue(theValue);
-}
/*!
\brief This function is used to determine whether input is valid.
QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) const
{
// Trying to interpret the current input text as a numeric value
- if (!hasVariable(str))
- return ModuleBase_DoubleSpinBox::validate(str, pos);
-
- QValidator::State res = QValidator::Invalid;
- if (isAcceptVariables()) {
- res = QValidator::Acceptable;
+ if (!hasVariable(str)) {
+ /// If decimals = 0 do not accept '.' (interpret as int)
+ if ((myValidator->decimals() == 0) && str.endsWith('.'))
+ return QValidator::Invalid;
+ return myValidator->validate(str, pos);
}
- return res;
+
+ return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
}
/*!
The new value is ignored if the spinbox has a variable.
*/
-void ModuleBase_ParamSpinBox::setValue(const double value)
+void ModuleBase_ParamSpinBox::setValue(double value)
{
- if (hasVariable())
- return;
+ myIsEquation = false;
+ double aVal = value;
+ if (aVal < myMinimum)
+ aVal = myMinimum;
+ else if (aVal > myMaximum)
+ aVal = myMaximum;
+ QString aText = QString::number(aVal, 'g', decimals());
+ lineEdit()->setText(aText);
+ emit textChanged(aText);
+}
- myTextValue = ModuleBase_DoubleSpinBox::textFromValue(value);
- ModuleBase_DoubleSpinBox::setValue(value);
+double ModuleBase_ParamSpinBox::value() const
+{
+ return lineEdit()->text().toDouble();
}
/*!
*/
void ModuleBase_ParamSpinBox::setText(const QString& value)
{
- myTextValue = value;
- lineEdit()->setText(value);
+ myIsEquation = hasVariable(value);
+ if (myAcceptVariables && myIsEquation) {
+ lineEdit()->setText(value);
+ emit textChanged(value);
+ }
}
/*!
void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
{
myAcceptVariables = flag;
+ if ((!myAcceptVariables) && myIsEquation) {
+ setValue(0);
+ }
}
/*!
bool ModuleBase_ParamSpinBox::hasVariable() const
{
- if (myTextValue.isEmpty())
- return false;
- return hasVariable(myTextValue);
+ return myIsEquation;
}
bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
{
- //const QString aDigitPattern = QString("[-+]?[0-9]*[%1]?[0-9]*([eE][-+]?[0-9]+)?");
-
- //bool aHasDigit = false;
- //{
- // QRegExp varNameMask(aDigitPattern.arg("."));
- // aHasDigit = varNameMask.exactMatch(theText);
- //}
- //if (!aHasDigit)
- //{
- // QRegExp varNameMask(aDigitPattern.arg(","));
- // aHasDigit = varNameMask.exactMatch(theText);
- //}
bool isDouble = false;
QLocale::c().toDouble(theText, &isDouble);
-
-// theText.toDouble(&isDouble);
-// if (isDouble) {
-// QLocale aLoc; // create default locale
-// QChar aDecPnt = aLoc.decimalPoint();
-// if (aDecPnt == '.')
-// isDouble = theText.contains(aDecPnt) || (!theText.contains(','));
-// else if (aDecPnt == ',')
-// isDouble = theText.contains(aDecPnt) || (!theText.contains('.'));
-// }
return !isDouble;
}
-/*!
- \brief This function is used to determine whether input is valid.
- \return validating operation result
- */
-ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
- double& theValue) const
+void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
{
- if (hasVariable() && !findVariable(theText, theValue)) {
- bool ok = false;
- theValue = locale().toDouble(theText, &ok);
- if (!ok) {
- return NoVariable;
+ switch (e->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ {
+ if (myCompleter->popup()->isVisible()) {
+ myCompleter->popup()->hide();
+ myIsEquation = true;
}
+ emit textChanged(lineEdit()->text());
+ return;
}
- if (!checkRange(theValue)) {
- return Invalid;
+ case Qt::Key_Space:
+ if (e->modifiers() & Qt::ControlModifier) {
+ myCompletePos = lineEdit()->cursorPosition();
+ int aStart, aEnd;
+ QString aPrefix = getPrefix(aStart, aEnd);
+ myCompleter->setCompletionPrefix(aPrefix);
+ myCompleter->complete();
+ }
+ break;
+ default:
+ QAbstractSpinBox::keyReleaseEvent(e);
}
-
- return Acceptable;
}
-/*!
- \brief This function is used to check that string value lies within predefined range.
- \return check status
- */
-bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
+
+QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
{
- return theValue >= minimum() && theValue <= maximum();
+ QString aPrefix;
+ QString aText = lineEdit()->text();
+ theStart = theEnd = myCompletePos;
+ const int aLen = aText.length();
+ if (aLen > 0) {
+ if (myCompletePos > 0) {
+ int aLastChar = myCompletePos - 1;
+ QChar aChar = aText.at(aLastChar);
+ while (aChar.isLetter() || aChar.isDigit()) {
+ aPrefix.prepend(aText.at(aLastChar));
+ aLastChar--;
+ if (aLastChar < 0)
+ break;
+ aChar = aText.at(aLastChar);
+ }
+ theStart = aLastChar + 1;
+ }
+ if (myCompletePos < aLen) {
+ int aLastChar = myCompletePos;
+ QChar aChar = aText.at(aLastChar);
+ while (aChar.isLetter() || aChar.isDigit()) {
+ aPrefix.append(aText.at(aLastChar));
+ aLastChar++;
+ if (aLastChar >= aLen)
+ break;
+ aChar = aText.at(aLastChar);
+ }
+ theEnd = aLastChar;
+ }
+ }
+ return aPrefix;
}
-/*!
- \brief This function is used to determine whether input is a variable name and to get its value.
- \return status of search operation
- */
-bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
- double& outValue) const
+
+void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
{
- ResultParameterPtr aParam;
- return ModelAPI_Tools::findVariable(FeaturePtr(), theName.toStdString(), outValue, aParam);
+ QString aText = lineEdit()->text();
+ int aStart, aEnd;
+ QString aPrefix = getPrefix(aStart, aEnd);
+
+ QString aResult;
+ int aPrefLen = aPrefix.length();
+ if (aPrefLen == 0)
+ aResult = aText.insert(myCompletePos, theText);
+ else {
+ aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
+ }
+ lineEdit()->setText(aResult);
+ myIsEquation = true;
}
-/*!
- \brief This function is called when the spinbox receives key press event.
- */
-//void ModuleBase_ParamSpinBox::keyPressEvent(QKeyEvent* e)
-//{
-// if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
-// QWidget::keyPressEvent(e);
-// } else {
-// ModuleBase_DoubleSpinBox::keyPressEvent(e);
-// }
-//}
-/*!
- \brief This function is called when the spinbox receives show event.
- */
-void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
+void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
{
- ModuleBase_DoubleSpinBox::showEvent(theEvent);
- if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) {
- setText(myTextValue);
- }
+ setReadOnly(!theEnable);
+
+ QPalette aPal = palette();
+ aPal.setColor(QPalette::All, QPalette::Base,
+ theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));
+ setPalette(aPal);
}
#include "ModuleBase.h"
-#include <ModuleBase_DoubleSpinBox.h>
-
+#include <QAbstractSpinBox>
#include <QValidator>
+#include <QLineEdit>
class QStringListModel;
class QCompleter;
* \ingroup GUI
* An extension of a double spin box which let to use parameters and expressions for value definition
*/
-class MODULEBASE_EXPORT ModuleBase_ParamSpinBox : public ModuleBase_DoubleSpinBox
+class MODULEBASE_EXPORT ModuleBase_ParamSpinBox : public QAbstractSpinBox
{
Q_OBJECT
\param theParent a parent object
\param thePrecision a precision of values display
*/
- explicit ModuleBase_ParamSpinBox( QWidget* theParent = 0, int thePrecision = -12 );
+ ModuleBase_ParamSpinBox( QWidget* theParent = 0, int thePrecision = -12 );
/// Set list of completion strings
void setCompletionList(QStringList&);
virtual void stepBy(int);
- virtual double valueFromText(const QString&) const;
- virtual QString textFromValue (double value) const;
+// virtual double valueFromText(const QString&) const;
+// virtual QString textFromValue (double value) const;
virtual QValidator::State validate(QString&, int&) const;
virtual void setValue(double);
+ double value() const;
+
virtual void setText(const QString&);
+ QString text() const { return lineEdit()->text(); }
+
/// Set a flag about accepted variable
void setAcceptVariables(const bool);
/// Returns True if the input value contains variable
bool hasVariable() const;
+ double minimum() const { return myMinimum; }
+ double maximum() const { return myMaximum; }
+
+ void setMinimum(double theMin) { myMinimum = theMin; myValidator->setBottom(theMin); }
+ void setMaximum(double theMax) { myMaximum = theMax; myValidator->setTop(theMax); }
+
+ int decimals() const { return myValidator->decimals(); }
+ void setDecimals(int thePrecision) { myValidator->setDecimals(thePrecision); }
+
+ double singleStep() const { return mySingleStep; }
+ void setSingleStep(double theStep) { mySingleStep = theStep; }
+
+ void setValueEnabled(bool theEnable);
+
protected:
+ /*!
+ \brief This function is called when the spinbox receives key release event.
+ */
+ virtual void keyReleaseEvent(QKeyEvent *event);
+
+ virtual StepEnabled stepEnabled() const { return StepUpEnabled | StepDownEnabled; }
+
/// Returns True if the given text contains variable
/// \param theText a text string
bool hasVariable(const QString& theText) const;
- /// Returns state of the control
- State isValid(const QString&, double&) const;
-
- /// Returns True if the given value is within min and max of the control
- bool checkRange(const double) const;
-
- /// Finds a variable by its name. Returns true in success
- /// \param theName a name of variable
- /// \param outValue an output value of the variable
- bool findVariable(const QString& theName, double& outValue) const;
+// /// Returns state of the control
+// State isValid(const QString&, double&) const;
+//
+// /// Returns True if the given value is within min and max of the control
+// bool checkRange(const double) const;
+//
+// /// Finds a variable by its name. Returns true in success
+// /// \param theName a name of variable
+// /// \param outValue an output value of the variable
+// bool findVariable(const QString& theName, double& outValue) const;
signals:
- void textChanged(const QString& theText);
+ void textChanged(const QString&);
- protected:
- virtual void showEvent(QShowEvent*);
+// protected:
+// virtual void showEvent(QShowEvent*);
+//
+// protected slots:
+// /// A slot called on text change
+// void onTextChanged(const QString&);
+//
+// private:
+// void connectSignalsAndSlots();
- protected slots:
- /// A slot called on text change
- void onTextChanged(const QString&);
+private slots:
+ void insertCompletion(const QString&);
- private:
- void connectSignalsAndSlots();
+ void onTextChanged(const QString&);
- private:
- QString myTextValue;
+private:
+ QString getPrefix(int& theStart, int& theEnd) const;
+ bool myIsEquation;
bool myAcceptVariables;
QStringListModel* myCompleterModel;
QCompleter* myCompleter;
+ int myPrecision;
+
+ double myMinimum;
+ double myMaximum;
+
+ int myCompletePos;
+
+ double mySingleStep;
+
+ /// Cashed color of active base palette
+ QColor myEnabledBaseColor;
+
+ QDoubleValidator* myValidator;
};
#endif
#include <ModelAPI_AttributeRefAttrList.h>
#include <ModelAPI_ResultPart.h>
#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Expression.h>
#include <Events_Loop.h>
#include <ModelAPI_Data.h>
}
}
+FeaturePtr createParameter(const QString& theText)
+{
+ FeaturePtr aParameter;
+ QStringList aList = theText.split("=");
+ if (aList.count() != 2) {
+ return aParameter;
+ }
+ QString aParamName = aList.at(0).trimmed();
+
+ if (isNameExist(aParamName, FeaturePtr())) {
+ return aParameter;
+ }
+
+ if (!ModelAPI_Expression::isVariable(aParamName.toStdString())) {
+ return aParameter;
+ }
+
+ QString aExpression = aList.at(1).trimmed();
+ if (aExpression.isEmpty()) {
+ return aParameter;
+ }
+
+ SessionPtr aMgr = ModelAPI_Session::get();
+ std::shared_ptr<ModelAPI_Document> aDoc = aMgr->activeDocument();
+
+ aParameter = aDoc->addFeature("Parameter");
+ if (aParameter.get()) {
+ AttributeStringPtr aNameAttr = aParameter->string("variable");
+ aNameAttr->setValue(aParamName.toStdString());
+
+ AttributeStringPtr aExprAttr = aParameter->string("expression");
+ aExprAttr->setValue(aExpression.toStdString());
+ aParameter->execute();
+
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ }
+ return aParameter;
+}
+
+void editParameter(FeaturePtr theParam, const QString& theText)
+{
+ QStringList aList = theText.split("=");
+ QString aParamName = aList.at(0).trimmed();
+
+ QString aExpression = aList.at(1).trimmed();
+ if (aExpression.isEmpty()) {
+ return;
+ }
+
+ if (isNameExist(aParamName, theParam)) {
+ return;
+ }
+ AttributeStringPtr aNameAttr = theParam->string("variable");
+ aNameAttr->setValue(aParamName.toStdString());
+
+ AttributeStringPtr aExprAttr = theParam->string("expression");
+ aExprAttr->setValue(aExpression.toStdString());
+ theParam->execute();
+
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+}
+
+bool isNameExist(const QString& theName, FeaturePtr theIgnoreParameter)
+{
+ SessionPtr aMgr = ModelAPI_Session::get();
+ std::shared_ptr<ModelAPI_Document> aDoc = aMgr->activeDocument();
+ FeaturePtr aParamFeature;
+ int aNbFeatures = aDoc->numInternalFeatures();
+ std::string aName = theName.toStdString();
+ for (int i = 0; i < aNbFeatures; i++) {
+ aParamFeature = aDoc->internalFeature(i);
+ if (aParamFeature && aParamFeature->getKind() == "Parameter") {
+ if ((theIgnoreParameter != aParamFeature) && (aParamFeature->name() == aName))
+ return true;
+ }
+ }
+ return false;
+}
+
+FeaturePtr findParameter(const QString& theName)
+{
+ SessionPtr aMgr = ModelAPI_Session::get();
+ std::shared_ptr<ModelAPI_Document> aDoc = aMgr->activeDocument();
+ FeaturePtr aParamFeature;
+ int aNbFeatures = aDoc->numInternalFeatures();
+ std::string aName = theName.toStdString();
+ for (int i = 0; i < aNbFeatures; i++) {
+ aParamFeature = aDoc->internalFeature(i);
+ if (aParamFeature && aParamFeature->getKind() == "Parameter") {
+ if (aParamFeature->name() == aName)
+ return aParamFeature;
+ }
+ }
+ return FeaturePtr();
+}
+
+
} // namespace ModuleBase_Tools
/// \param theAIS - the presentation
void MODULEBASE_EXPORT setPointBallHighlighting(AIS_Shape* theAIS);
+/// Creates a parameter from a given string
+/// \theText a text wit equation
+FeaturePtr MODULEBASE_EXPORT createParameter(const QString& theText);
+
+/// Edits parameter replacing its name and expression according to the given string
+/// \theParam a editing parameter
+/// \theText a text wit equation
+void MODULEBASE_EXPORT editParameter(FeaturePtr theParam, const QString& theText);
+
+/// Returns True if a parameter with the given name already exists
+/// \theName a name of parameter
+bool MODULEBASE_EXPORT isNameExist(const QString& theName, FeaturePtr theIgnoreParameter);
+
+/// Find parameter by its name
+/// \theName a name of parameter
+FeaturePtr MODULEBASE_EXPORT findParameter(const QString& theName);
}
#endif
#include <Config_Keywords.h>
#include <Config_WidgetAPI.h>
+#include <Events_Loop.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_Data.h>
#include <ModelAPI_Object.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_ResultParameter.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeString.h>
#include <ModuleBase_ParamSpinBox.h>
#include <ModuleBase_Tools.h>
#include <iostream>
#endif
-//#define DEBUG_COMPLETE_WITH_PARAMETERS
-
ModuleBase_WidgetDoubleValue::ModuleBase_WidgetDoubleValue(QWidget* theParent,
const Config_WidgetAPI* theData)
: ModuleBase_ModelWidget(theParent, theData)
void ModuleBase_WidgetDoubleValue::activateCustom()
{
ModuleBase_ModelWidget::activateCustom();
-#ifdef DEBUG_COMPLETE_WITH_PARAMETERS
QStringList aParameters;
ModuleBase_Tools::getParameters(aParameters);
mySpinBox->setCompletionList(aParameters);
-#endif
}
bool ModuleBase_WidgetDoubleValue::resetCustom()
AttributeDoublePtr aReal = aData->real(attributeID());
if (mySpinBox->hasVariable()) {
// Here is a text of a real value or an expression.
- std::string aText = mySpinBox->text().toStdString();
- aReal->setText(aText);
+ QString aText = mySpinBox->text();
+ if (aText.contains('=')) {
+ if (!myParameter.get()) {
+ myParameter = ModuleBase_Tools::createParameter(aText);
+ if (!myParameter.get()) {
+ aReal->setExpressionError("Parameter cannot be created");
+ aReal->setExpressionInvalid(true);
+ updateObject(myFeature);
+ return false;
+ } else if (aReal->expressionInvalid()) {
+ aReal->setExpressionError("");
+ aReal->setExpressionInvalid(false);
+ }
+ } else {
+ ModuleBase_Tools::editParameter(myParameter, aText);
+ }
+ aText = aText.split('=').at(0) + "=";
+ } else if (myParameter.get()){
+ // Nullyfy the parameter reference without deletion of the created
+ myParameter = FeaturePtr();
+ }
+ aReal->setText(aText.toStdString());
} else {
// it is important to set the empty text value to the attribute before set the value
// because setValue tries to calculate the attribute value according to the
AttributeDoublePtr aRef = aData->real(attributeID());
std::string aTextRepr = aRef->text();
if (!aTextRepr.empty()) {
- ModuleBase_Tools::setSpinText(mySpinBox, QString::fromStdString(aTextRepr));
+ QString aText = QString::fromStdString(aTextRepr);
+ if (aText.endsWith('=')) {
+ if (!myParameter.get()) {
+ QString aName = aText.left(aText.indexOf('=')).trimmed();
+ myParameter = ModuleBase_Tools::findParameter(aName);
+ }
+ /// If myParameter is empty then it was not created because of an error
+ if (!myParameter.get())
+ return false;
+
+ AttributeStringPtr aExprAttr = myParameter->string("expression");
+ aText += aExprAttr->value().c_str();
+ }
+ ModuleBase_Tools::setSpinText(mySpinBox, aText);
} else {
ModuleBase_Tools::setSpinValue(mySpinBox, aRef->isInitialized() ? aRef->value() : 0);
}
/// Input value control
ModuleBase_ParamSpinBox* mySpinBox;
+
+ FeaturePtr myParameter;
};
#endif
QTextCursor aCursor = textCursor();
aCursor.select(QTextCursor::WordUnderCursor);
const QString aPrefix = aCursor.selectedText();
- if (!aPrefix.isEmpty() && aPrefix.at(aPrefix.length() - 1).isLetter()) {
- performCompletion(aPrefix);
- }
+ performCompletion(aPrefix);
}
void ExpressionEditor::performCompletion(const QString& theCompletionPrefix)
#include <ModuleBase_WidgetIntValue.h>
#include <ModuleBase_ParamSpinBox.h>
#include <ModuleBase_Tools.h>
-#include <ModuleBase_ParamIntSpinBox.h>
+#include <ModuleBase_ParamSpinBox.h>
#include <ModuleBase_IconFactory.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_Data.h>
+#include <ModelAPI_AttributeString.h>
#include <Config_Keywords.h>
#include <Config_WidgetAPI.h>
if (!aLabelIcon.isEmpty())
myLabel->setPixmap(ModuleBase_IconFactory::loadPixmap(aLabelIcon));
- mySpinBox = new ModuleBase_ParamIntSpinBox(this);
+ mySpinBox = new ModuleBase_ParamSpinBox(this);
+ mySpinBox->setDecimals(0);
QString anObjName = QString::fromStdString(attributeID());
mySpinBox->setObjectName(anObjName);
{
}
+void ModuleBase_WidgetIntValue::activateCustom()
+{
+ ModuleBase_ModelWidget::activateCustom();
+ QStringList aParameters;
+ ModuleBase_Tools::getParameters(aParameters);
+ mySpinBox->setCompletionList(aParameters);
+}
+
bool ModuleBase_WidgetIntValue::resetCustom()
{
bool aDone = false;
AttributeIntegerPtr anAttribute = aData->integer(attributeID());
if (mySpinBox->hasVariable()) {
// Here is a text of a real value or an expression.
- std::string aText = mySpinBox->text().toStdString();
- anAttribute->setText(aText);
+ QString aText = mySpinBox->text();
+ if (aText.contains('=')) {
+ if (!myParameter.get()) {
+ myParameter = ModuleBase_Tools::createParameter(aText);
+ if (!myParameter.get()) {
+ anAttribute->setExpressionError("Parameter cannot be created");
+ anAttribute->setExpressionInvalid(true);
+ updateObject(myFeature);
+ return false;
+ } else if (anAttribute->expressionInvalid()) {
+ anAttribute->setExpressionError("");
+ anAttribute->setExpressionInvalid(false);
+ }
+ } else {
+ ModuleBase_Tools::editParameter(myParameter, aText);
+ }
+ aText = aText.split('=').at(0) + "=";
+ } else if (myParameter.get()) {
+ // Nullyfy the parameter reference without deletion of the created
+ myParameter = FeaturePtr();
+ }
+ anAttribute->setText(aText.toStdString());
} else {
// it is important to set the empty text value to the attribute before set the value
// because setValue tries to calculate the attribute value according to the
AttributeIntegerPtr anAttribute = aData->integer(attributeID());
std::string aTextRepr = anAttribute->text();
if (!aTextRepr.empty()) {
- ModuleBase_Tools::setSpinText(mySpinBox, QString::fromStdString(aTextRepr));
+ QString aText = QString::fromStdString(aTextRepr);
+ if (aText.endsWith('=')) {
+ if (!myParameter.get()) {
+ QString aName = aText.left(aText.indexOf('=')).trimmed();
+ myParameter = ModuleBase_Tools::findParameter(aName);
+ }
+ /// If myParameter is empty then it was not created because of an error
+ if (!myParameter.get())
+ return false;
+
+ AttributeStringPtr aExprAttr = myParameter->string("expression");
+ aText += aExprAttr->value().c_str();
+ }
+ ModuleBase_Tools::setSpinText(mySpinBox, aText);
} else {
ModuleBase_Tools::setSpinValue(mySpinBox, anAttribute->value());
}
#include "ModuleBase.h"
#include "ModuleBase_ModelWidget.h"
-class ModuleBase_ParamIntSpinBox;
+class ModuleBase_ParamSpinBox;
class Config_WidgetAPI;
class QWidget;
class QLabel;
virtual ~ModuleBase_WidgetIntValue();
+ /// The methiod called when widget is activated
+ virtual void activateCustom();
+
/// Select the internal content if it can be selected. It is empty in the default realization
virtual void selectContent();
QLabel* myLabel;
/// Input value control
- ModuleBase_ParamIntSpinBox* mySpinBox;
+ ModuleBase_ParamSpinBox* mySpinBox;
+
+ FeaturePtr myParameter;
};
#endif
new PartSet_MultyTranslationSelection);
aFactory->registerValidator("PartSet_SplitSelection", new PartSet_SplitSelection);
aFactory->registerValidator("PartSet_ProjectionSelection", new PartSet_ProjectionSelection);
+ aFactory->registerValidator("PartSet_IntersectionSelection", new PartSet_IntersectionSelection);
}
//******************************************************
{
Handle(AIS_InteractiveObject) anAIS = theAIS->impl<Handle(AIS_InteractiveObject)>();
if (!anAIS.IsNull()) {
- bool aToUseZLayer = false;
FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
- if (aFeature.get() && PartSet_Tools::findRefsToMeFeature(aFeature,
- SketchPlugin_Projection::ID()))
- aToUseZLayer = true;
- Handle(AIS_InteractiveContext) aCtx = anAIS->GetContext();
- Handle(AIS_Dimension) aDim = Handle(AIS_Dimension)::DownCast(anAIS);
- if (!aDim.IsNull()) {
- aToUseZLayer = true;
- } else {
- Handle(SketcherPrs_SymbolPrs) aCons = Handle(SketcherPrs_SymbolPrs)::DownCast(anAIS);
- if (!aCons.IsNull())
- aToUseZLayer = true;
+ if (aFeature.get()) {
+ bool aToUseZLayer = false;
+ if (PartSet_Tools::findRefsToMeFeature(aFeature,SketchPlugin_Projection::ID()))
+ aToUseZLayer = true;
+ else {
+ CompositeFeaturePtr aParent = ModelAPI_Tools::compositeOwner(aFeature);
+ aToUseZLayer = (aParent.get() && (aParent->getKind() == SketchPlugin_Sketch::ID()));
+ }
+ if (aToUseZLayer) {
+ Handle(AIS_InteractiveContext) aCtx = anAIS->GetContext();
+ aCtx->SetZLayer(anAIS, myVisualLayerId);
+ }
}
- if (aToUseZLayer)
- aCtx->SetZLayer(anAIS, myVisualLayerId);
}
}
}
}
+bool PartSet_IntersectionSelection::isValid(const ModuleBase_ISelection* theSelection,
+ ModuleBase_Operation* theOperation) const
+{
+ if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
+ return isEmptySelectionValid(theOperation);
+ } else {
+ int aCount = shapesNbLines(theSelection);
+ return aCount == 0;
+ }
+}
+
std::string PartSet_DifferentObjectsValidator::errorMessage(
const PartSet_DifferentObjectsValidator::ErrorType& theType,
ModuleBase_Operation* theOperation) const;
};
+//! \ingroup Validators
+//! A class to validate a selection for intersection operation
+class PartSet_IntersectionSelection : public ModuleBase_SelectionValidator
+{
+public:
+ PARTSET_EXPORT virtual bool isValid(const ModuleBase_ISelection* theSelection,
+ ModuleBase_Operation* theOperation) const;
+};
+
////////////// Attribute validators ////////////////
"""Package for Features plugin for the Parametric Geometry API of the Modeler.
"""
-from FeaturesAPI import addPlacement, addRotation, addScale, addSymmetry, addTranslation
+from FeaturesAPI import addPlacement, addRotation, addScale, addMirror, addTranslation
from FeaturesAPI import addMultiTranslation, addMultiRotation
from FeaturesAPI import addExtrusion, addExtrusionCut, addExtrusionFuse
from FeaturesAPI import addRevolution, addRevolutionCut, addRevolutionFuse
from FeaturesAPI import addIntersection, addPartition, addUnion, addRemoveSubShapes
from FeaturesAPI import addRecover
from FeaturesAPI import addFillet
+from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle
//
#include "SketchAPI_IntersectionPoint.h"
+#include "SketchAPI_Point.h"
+//--------------------------------------------------------------------------------------
+#include <SketchPlugin_Point.h>
//--------------------------------------------------------------------------------------
#include <GeomAPI_Pnt2d.h>
//--------------------------------------------------------------------------------------
: SketchAPI_SketchEntity(theFeature)
{
if (initialize()) {
- setByExternalLine(theExternal);
+ setByExternalEdge(theExternal);
}
}
: SketchAPI_SketchEntity(theFeature)
{
if (initialize()) {
- setByExternalLineName(theExternalName);
+ setByExternalEdgeName(theExternalName);
}
}
}
//--------------------------------------------------------------------------------------
-void SketchAPI_IntersectionPoint::setByExternalLine(const ModelHighAPI_Selection & theExternalLine)
+void SketchAPI_IntersectionPoint::setByExternalEdge(const ModelHighAPI_Selection & theExternalLine)
{
- fillAttribute(theExternalLine, externalLine());
+ fillAttribute(theExternalLine, externalFeature());
execute();
}
-void SketchAPI_IntersectionPoint::setByExternalLineName(const std::string & theExternalLineName)
+void SketchAPI_IntersectionPoint::setByExternalEdgeName(const std::string & theExternalLineName)
{
- fillAttribute(ModelHighAPI_Selection("EDGE", theExternalLineName), externalLine());
+ fillAttribute(ModelHighAPI_Selection("EDGE", theExternalLineName), externalFeature());
execute();
}
+void SketchAPI_IntersectionPoint::setIncludeToResult(bool theKeepResult)
+{
+ fillAttribute(theKeepResult, includeToResult());
+ execute(true);
+}
+
+//--------------------------------------------------------------------------------------
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> >
+SketchAPI_IntersectionPoint::intersectionPoints() const
+{
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > anEntities;
+
+ std::list<ObjectPtr> anIntersections =
+ feature()->reflist(SketchPlugin_IntersectionPoint::INTERSECTION_POINTS_ID())->list();
+ for (std::list<ObjectPtr>::iterator anIt = anIntersections.begin();
+ anIt != anIntersections.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
+ {
+ std::shared_ptr<SketchAPI_SketchEntity> anEnt(new SketchAPI_Point(aFeature));
+ anEntities.push_back(anEnt);
+ }
+ }
+
+ return anEntities;
+}
+
//--------------------------------------------------------------------------------------
void SketchAPI_IntersectionPoint::dump(ModelHighAPI_Dumper& theDumper) const
FeaturePtr aBase = feature();
const std::string& aSketchName = theDumper.parentName(aBase);
- AttributeSelectionPtr aLine = externalLine();
- theDumper << aBase << " = " <<
- aSketchName << ".addIntersectionPoint(" << aLine << ")" << std::endl;
+ AttributeSelectionPtr anExternal = externalFeature();
+ AttributeBooleanPtr isIncludeToRes = includeToResult();
+ theDumper << aBase << " = " << aSketchName << ".addIntersectionPoint("
+ << anExternal << ", " << isIncludeToRes << ")" << std::endl;
// dump "auxiliary" flag if necessary
SketchAPI_SketchEntity::dump(theDumper);
+
+ // Dump variables for a list of intersected points
+ theDumper << "[";
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > aList = intersectionPoints();
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> >::const_iterator anIt = aList.begin();
+ for (; anIt != aList.end(); ++anIt) {
+ if (anIt != aList.begin())
+ theDumper << ", ";
+ theDumper << (*anIt)->feature();
+ }
+ theDumper << "] = " << theDumper.name(aBase) << ".intersectionPoints()" << std::endl;
}
SKETCHAPI_EXPORT
virtual ~SketchAPI_IntersectionPoint();
- INTERFACE_2(SketchPlugin_IntersectionPoint::ID(),
- coordinates, SketchPlugin_IntersectionPoint::COORD_ID(),
- GeomDataAPI_Point2D, /** IntersectionPoint coordinates */,
- externalLine, SketchPlugin_IntersectionPoint::EXTERNAL_LINE_ID(),
- ModelAPI_AttributeSelection, /** External line */
+ INTERFACE_3(SketchPlugin_IntersectionPoint::ID(),
+ externalFeature, SketchPlugin_IntersectionPoint::EXTERNAL_FEATURE_ID(),
+ ModelAPI_AttributeSelection, /** External edge */,
+ external, SketchPlugin_IntersectionPoint::EXTERNAL_ID(),
+ ModelAPI_AttributeSelection, /** External */,
+ includeToResult, SketchPlugin_IntersectionPoint::INCLUDE_INTO_RESULT(),
+ ModelAPI_AttributeBoolean, /** Include into result */
)
/// Set by external
SKETCHAPI_EXPORT
- void setByExternalLine(const ModelHighAPI_Selection & theExternalLine);
+ void setByExternalEdge(const ModelHighAPI_Selection & theExternaEdge);
/// Set by external name
SKETCHAPI_EXPORT
- void setByExternalLineName(const std::string & theExternalLineName);
+ void setByExternalEdgeName(const std::string & theExternalEdgeName);
+
+ /// Set flag to include projection to result or not
+ SKETCHAPI_EXPORT
+ void setIncludeToResult(bool theKeepResult);
+
+ /// Returns created intersection points
+ SKETCHAPI_EXPORT
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > intersectionPoints() const;
/// Dump wrapped feature
SKETCHAPI_EXPORT
const ModelHighAPI_RefAttr & theCenter,
const ModelHighAPI_Double & theAngle,
const ModelHighAPI_Integer & theNumberOfObjects,
- bool theFullValue)
+ bool theFullValue,
+ bool theReversed)
: ModelHighAPI_Interface(theFeature)
{
if (initialize()) {
fillAttribute(theObjects, rotationList());
fillAttribute(theCenter, center());
+ fillAttribute(theFullValue ? "FullAngle" : "SingleAngle", valueType());
fillAttribute(theAngle, angle());
+ fillAttribute(theReversed, reversed());
fillAttribute(theNumberOfObjects, numberOfObjects());
- fillAttribute(theFullValue ? "FullAngle" : "SingleAngle", valueType());
execute(true);
}
AttributeDoublePtr anAngle = angle();
AttributeIntegerPtr aNbCopies = numberOfObjects();
bool isFullValue = valueType()->value() != "SingleAngle";
+ bool isReversed = reversed()->value();
// Check all attributes are already dumped. If not, store the constraint as postponed.
if (!theDumper.isDumped(aCenter) || !theDumper.isDumped(aRotObjects)) {
theDumper << aBase << " = " << aSketchName << ".addRotation("
<< aRotObjects << ", " << aCenter << ", " << anAngle << ", " << aNbCopies;
- if (isFullValue)
+ if (isFullValue || isReversed)
+ {
theDumper << ", " << isFullValue;
+ if (isReversed)
+ theDumper << ", " << isReversed;
+ }
theDumper << ")" << std::endl;
// Dump variables for a list of rotated features
const ModelHighAPI_RefAttr & theCenter,
const ModelHighAPI_Double & theAngle,
const ModelHighAPI_Integer & theNumberOfObjects,
- bool theFullValue = false);
+ bool theFullValue = false,
+ bool theReversed = false);
/// Destructor
SKETCHAPI_EXPORT
virtual ~SketchAPI_Rotation();
- INTERFACE_7(SketchPlugin_MultiRotation::ID(),
+ INTERFACE_8(SketchPlugin_MultiRotation::ID(),
rotationList, SketchPlugin_MultiRotation::ROTATION_LIST_ID(),
ModelAPI_AttributeRefList, /** Rotation list */,
center, SketchPlugin_MultiRotation::CENTER_ID(),
ModelAPI_AttributeRefAttr, /** Center */,
angle, SketchPlugin_MultiRotation::ANGLE_ID(),
ModelAPI_AttributeDouble, /** Angle */,
+ reversed, SketchPlugin_MultiRotation::REVERSED_ID(),
+ ModelAPI_AttributeBoolean, /** Negative angle */,
numberOfObjects, SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID(),
ModelAPI_AttributeInteger, /** Number of objects */,
valueType, SketchPlugin_MultiRotation::ANGLE_TYPE(),
//--------------------------------------------------------------------------------------
std::shared_ptr<SketchAPI_IntersectionPoint> SketchAPI_Sketch::addIntersectionPoint(
- const ModelHighAPI_Selection & theExternal)
+ const ModelHighAPI_Selection & theExternal,
+ bool theKeepResult)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_IntersectionPoint::ID());
- return IntersectionPointPtr(new SketchAPI_IntersectionPoint(aFeature, theExternal));
+ IntersectionPointPtr anIntersection(new SketchAPI_IntersectionPoint(aFeature, theExternal));
+ anIntersection->setIncludeToResult(theKeepResult);
+ return anIntersection;
}
std::shared_ptr<SketchAPI_IntersectionPoint> SketchAPI_Sketch::addIntersectionPoint(
- const std::string & theExternalName)
+ const std::string & theExternalName,
+ bool theKeepResult)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_IntersectionPoint::ID());
- return IntersectionPointPtr(new SketchAPI_IntersectionPoint(aFeature, theExternalName));
+ IntersectionPointPtr anIntersection(new SketchAPI_IntersectionPoint(aFeature, theExternalName));
+ anIntersection->setIncludeToResult(theKeepResult);
+ return anIntersection;
}
//--------------------------------------------------------------------------------------
const ModelHighAPI_RefAttr & theCenter,
const ModelHighAPI_Double & theAngle,
const ModelHighAPI_Integer & theNumberOfObjects,
- bool theFullValue)
+ bool theFullValue,
+ bool theReversed)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_MultiRotation::ID());
return RotationPtr(
new SketchAPI_Rotation(aFeature, theObjects, theCenter,
- theAngle, theNumberOfObjects, theFullValue));
+ theAngle, theNumberOfObjects, theFullValue, theReversed));
}
//--------------------------------------------------------------------------------------
/// Add intersection point
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_IntersectionPoint>
- addIntersectionPoint(const ModelHighAPI_Selection & theExternal);
+ addIntersectionPoint(const ModelHighAPI_Selection & theExternal,
+ bool theKeepResult = false);
/// Add point
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_IntersectionPoint>
- addIntersectionPoint(const std::string & theExternalName);
+ addIntersectionPoint(const std::string & theExternalName,
+ bool theKeepResult = false);
/// Add line
SKETCHAPI_EXPORT
const ModelHighAPI_RefAttr & theCenter,
const ModelHighAPI_Double & theAngle,
const ModelHighAPI_Integer & theNumberOfObjects,
- bool theFullValue = false);
+ bool theFullValue = false,
+ bool theReversed = false);
/// Add split
SKETCHAPI_EXPORT
TestConstraintMiddlePoint.py
TestEdgesOrder.py
TestMirror.py
- TestMultiRotation.py
TestMultiTranslation.py
+ TestMultiRotation.py
TestMultiRotationWithParameter.py
+ TestMultiRotation01.py
+ TestMultiRotation02.py
+ TestMultiRotation03.py
+ TestMultiRotation04.py
+ TestMultiRotation05.py
TestFillet.py
TestFilletInteracting.py
TestRectangle.py
TestDistanceSignedVsUnsigned05.py
TestSignedDistancePointPoint.py
TestSignedDistancePointLine.py
+ TestIntersectionWithLine.py
+ TestIntersectionWithCircle.py
+ TestIntersectionWithSpline.py
+ TestIntersectionChangeType.py
Test2273.py
Test2280.py
Test2287.py
//
#include "SketchPlugin_IntersectionPoint.h"
+#include "SketchPlugin_Point.h"
#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
#include <ModelAPI_Validator.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Lin.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomDataAPI_Point2D.h>
SketchPlugin_IntersectionPoint::SketchPlugin_IntersectionPoint()
- : SketchPlugin_Point()
+ : SketchPlugin_SketchEntity(),
+ myIsComputing(false)
{
}
void SketchPlugin_IntersectionPoint::initDerivedClassAttributes()
{
- data()->addAttribute(EXTERNAL_LINE_ID(), ModelAPI_AttributeSelection::typeId());
+ data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
+ data()->addAttribute(INTERSECTION_POINTS_ID(), ModelAPI_AttributeRefList::typeId());
+ data()->attribute(INTERSECTION_POINTS_ID())->setIsArgument(false);
- SketchPlugin_Point::initDerivedClassAttributes();
+ data()->addAttribute(INCLUDE_INTO_RESULT(), ModelAPI_AttributeBoolean::typeId());
+
+ data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
}
void SketchPlugin_IntersectionPoint::execute()
{
- SketchPlugin_Sketch* aSketch = sketch();
- if (aSketch) {
- computePoint();
- SketchPlugin_Point::execute();
+ AttributeRefListPtr anIntersectionsList = reflist(INTERSECTION_POINTS_ID());
+ if (!anIntersectionsList || !anIntersectionsList->isInitialized())
+ return; // no intersections
- // set this feature as external
- data()->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
- }
+ computePoint(EXTERNAL_FEATURE_ID());
}
void SketchPlugin_IntersectionPoint::attributeChanged(const std::string& theID)
{
- if (theID == EXTERNAL_LINE_ID()) {
- // compute intersection between line and sketch plane
- computePoint();
- }
+ // compute intersection between line and sketch plane
+ computePoint(theID);
}
-void SketchPlugin_IntersectionPoint::computePoint()
+void SketchPlugin_IntersectionPoint::computePoint(const std::string& theID)
{
- AttributeSelectionPtr aLineAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_LINE_ID()));
-
- std::shared_ptr<GeomAPI_Edge> anEdge;
- if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) {
- anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->value()));
- } else if(aLineAttr->context() && aLineAttr->context()->shape() &&
- aLineAttr->context()->shape()->isEdge()) {
- anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->context()->shape()));
- }
- if(!anEdge.get())
+ if (theID != EXTERNAL_FEATURE_ID() && theID != EXTERNAL_ID())
return;
- std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
- std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
-
- std::shared_ptr<GeomAPI_Pnt> anIntersection = aSketchPlane->intersect(aLine);
- if (!anIntersection)
+ if (myIsComputing)
return;
+ myIsComputing = true;
+
+ AttributeSelectionPtr anExternalFeature = selection(EXTERNAL_FEATURE_ID());
+
+ GeomShapePtr aShape;
+ GeomEdgePtr anEdge;
+ if (anExternalFeature)
+ aShape = anExternalFeature->value();
+ if (!aShape && anExternalFeature->context())
+ aShape = anExternalFeature->context()->shape();
+ if (aShape && aShape->isEdge())
+ anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
+
+ if (anEdge) {
+ std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+ std::list<GeomPointPtr> anIntersectionsPoints;
+ anEdge->intersectWithPlane(aSketchPlane, anIntersectionsPoints);
- std::shared_ptr<GeomDataAPI_Point2D> aCoordAttr =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(COORD_ID()));
- aCoordAttr->setValue(sketch()->to2D(anIntersection));
+ AttributeRefListPtr anIntersectionsList = reflist(INTERSECTION_POINTS_ID());
+ std::list<ObjectPtr> anExistentIntersections = anIntersectionsList->list();
+ std::list<ObjectPtr>::const_iterator aExistInterIt = anExistentIntersections.begin();
+
+ const std::list<ResultPtr>& aResults = results();
+ std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
+
+ int aResultIndex = 0;
+ for (std::list<GeomPointPtr>::iterator aPntIt = anIntersectionsPoints.begin();
+ aPntIt != anIntersectionsPoints.end(); ++aPntIt, ++aResultIndex) {
+ std::shared_ptr<SketchPlugin_Point> aCurSketchPoint;
+ if (aExistInterIt == anExistentIntersections.end()) {
+ // create new point
+ aCurSketchPoint = std::dynamic_pointer_cast<SketchPlugin_Point>(
+ sketch()->addFeature(SketchPlugin_Point::ID()));
+ aCurSketchPoint->boolean(COPY_ID())->setValue(true);
+ anIntersectionsList->append(aCurSketchPoint);
+ } else {
+ // update existent point
+ aCurSketchPoint = std::dynamic_pointer_cast<SketchPlugin_Point>(*aExistInterIt);
+ ++aExistInterIt;
+ }
+
+ ResultConstructionPtr aCurResult;
+ if (aResIt == aResults.end()) {
+ // create new result
+ aCurResult = document()->createConstruction(data(), aResultIndex);
+ aCurResult->setIsInHistory(false);
+ aCurResult->setDisplayed(false);
+ } else {
+ // update existent result
+ aCurResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIt);
+ aCurResult->setShape(std::shared_ptr<GeomAPI_Edge>());
+ ++aResIt;
+ }
+
+ // update coordinates of intersection
+ GeomPnt2dPtr aPointInSketch = sketch()->to2D(*aPntIt);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aCurSketchPoint->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPointInSketch);
+ aCurSketchPoint->execute();
+
+ // update result
+ aCurResult->setShape(aCurSketchPoint->lastResult()->shape());
+ setResult(aCurResult, aResultIndex);
+
+ // make intersection point external
+ GeomShapePtr anEmptyVal;
+ aCurSketchPoint->selection(EXTERNAL_ID())->setValue(aCurResult, anEmptyVal);
+ }
+
+ // remove rest results from previous pass
+ removeResults(aResultIndex);
+ std::set<FeaturePtr> aFeaturesToBeRemoved;
+ for (; aExistInterIt != anExistentIntersections.end(); ++aExistInterIt) {
+ aFeaturesToBeRemoved.insert(ModelAPI_Feature::feature(*aExistInterIt));
+ anIntersectionsList->removeLast();
+ }
+ ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
+
+ if (theID != EXTERNAL_ID())
+ selection(EXTERNAL_ID())->selectValue(anExternalFeature);
+ }
+ myIsComputing = false;
}
#ifndef SketchPlugin_IntersectionPoint_H_
#define SketchPlugin_IntersectionPoint_H_
-#include "SketchPlugin_Point.h"
+#include "SketchPlugin_SketchEntity.h"
/**\class SketchPlugin_IntersectionPoint
* \ingroup Plugins
* \brief Feature for creation of external point as an intersection
* between external edge and a plane of the sketch.
*/
-class SketchPlugin_IntersectionPoint : public SketchPlugin_Point
+class SketchPlugin_IntersectionPoint : public SketchPlugin_SketchEntity
{
public:
/// Point feature kind
return MY_KIND;
}
- static const std::string& EXTERNAL_LINE_ID()
+ static const std::string& EXTERNAL_FEATURE_ID()
{
- static std::string MY_LINE_ID("ExternalLine");
- return MY_LINE_ID;
+ static std::string MY_FEATURE_ID("ExternalFeature");
+ return MY_FEATURE_ID;
+ }
+
+ static const std::string& INTERSECTION_POINTS_ID()
+ {
+ static std::string MY_INTERSECTIONS_ID("IntersectionPoints");
+ return MY_INTERSECTIONS_ID;
+ }
+
+ static const std::string& INCLUDE_INTO_RESULT()
+ {
+ static std::string MY_INCLUDE("IncludeToResult");
+ return MY_INCLUDE;
}
/// Returns true because intersection point is always external
virtual bool isFixed()
{ return true; }
+ /// Returns true if the feature and the feature results can be displayed.
+ /// \return false
+ virtual bool canBeDisplayed() const
+ { return false; }
+
/// Creates a new part document if needed
SKETCHPLUGIN_EXPORT virtual void execute();
private:
/// \brief Find intersection between a line and a sketch plane
- void computePoint();
+ void computePoint(const std::string& theID);
+
+ bool myIsComputing;
};
#endif
#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeBoolean.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeString.h>
#include <ModelAPI_AttributeInteger.h>
#include <cmath>
-#define PI 3.1415926535897932
+static const double PI = 3.1415926535897932;
+static const double PERIOD = 360.0;
+static const double ANGLETOL = 1.e-7;
SketchPlugin_MultiRotation::SketchPlugin_MultiRotation()
+ : isUpdatingAngle(false)
{
}
data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
data()->addAttribute(ROTATION_LIST_ID(), ModelAPI_AttributeRefList::typeId());
+ data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+
ModelAPI_Session::get()->validators()->
registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_A());
ModelAPI_Session::get()->validators()->
reflist(SketchPlugin_Constraint::ENTITY_A())->clear();
}
}
+ else if (!isUpdatingAngle && real(ANGLE_ID())->isInitialized())
+ {
+ isUpdatingAngle = true;
+ AttributeDoublePtr anAngle = real(ANGLE_ID());
+ if (theID == ANGLE_TYPE() && integer(NUMBER_OF_OBJECTS_ID())->isInitialized()) {
+ if (string(ANGLE_TYPE())->value() != "SingleAngle")
+ anAngle->setValue(anAngle->value() * (integer(NUMBER_OF_OBJECTS_ID())->value() - 1));
+ else
+ {
+ int aNbSplits = integer(NUMBER_OF_OBJECTS_ID())->value();
+ if (anAngle->value() < PERIOD - ANGLETOL)
+ aNbSplits -= 1;
+ anAngle->setValue(anAngle->value() / aNbSplits);
+ }
+ }
+ else if (theID == ANGLE_ID()) {
+ if (anAngle->value() > PERIOD + ANGLETOL || anAngle->value() < -ANGLETOL)
+ anAngle->setValue(anAngle->value() + PERIOD * ceil(-anAngle->value() / PERIOD));
+ if (fabs(anAngle->value() - PERIOD) < ANGLETOL)
+ anAngle->setValue(PERIOD);
+ else if (fabs(anAngle->value()) < ANGLETOL)
+ anAngle->setValue(0.);
+ }
+ isUpdatingAngle = false;
+ }
}
return MY_NUMBER_OF_OBJECTS_ID;
}
+ /// Name of the flag to reverse rotation
+ inline static const std::string& REVERSED_ID()
+ {
+ static const std::string MY_REVERSED_ID("MultiRotationReversed");
+ return MY_REVERSED_ID;
+ }
+
/// \brief Creates a new part document if needed
SKETCHPLUGIN_EXPORT virtual void execute();
// double theCenterX, double theCenterY, double theAngle);
bool updateFullAngleValue();
+
+ bool isUpdatingAngle;
};
#endif
new SketchPlugin_ReplicationReferenceValidator);
aFactory->registerValidator("SketchPlugin_SketchFeatureValidator",
new SketchPlugin_SketchFeatureValidator);
+ aFactory->registerValidator("SketchPlugin_MultiRotationAngleValidator",
+ new SketchPlugin_MultiRotationAngleValidator);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
#include "SketchPlugin_Line.h"
#include "SketchPlugin_MacroArc.h"
#include "SketchPlugin_MacroCircle.h"
+#include "SketchPlugin_MultiRotation.h"
#include "SketchPlugin_Point.h"
#include "SketchPlugin_Sketch.h"
#include "SketchPlugin_Trim.h"
#include <ModelAPI_Data.h>
#include <ModelAPI_Validator.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
-
#include <ModelAPI_AttributeRefAttrList.h>
#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_AttributeSelectionList.h>
theError.arg(theAttribute->attributeType());
return false;
}
- AttributeSelectionPtr aLineAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+ AttributeSelectionPtr anExternalAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
std::shared_ptr<GeomAPI_Edge> anEdge;
- if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) {
- anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->value()));
- } else if(aLineAttr->context() &&
- aLineAttr->context()->shape() && aLineAttr->context()->shape()->isEdge()) {
- anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->context()->shape()));
+ if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) {
+ anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->value()));
+ } else if(anExternalAttr->context() && anExternalAttr->context()->shape() &&
+ anExternalAttr->context()->shape()->isEdge()) {
+ anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->context()->shape()));
}
- if (!anEdge || !anEdge->isLine()) {
- theError = "The attribute %1 should be a line";
+ if (!anEdge) {
+ theError = "The attribute %1 should be an edge";
theError.arg(theAttribute->id());
return false;
}
- std::shared_ptr<GeomAPI_Dir> aLineDir = anEdge->line()->direction();
-
// find a sketch
std::shared_ptr<SketchPlugin_Sketch> aSketch;
- std::set<AttributePtr> aRefs = aLineAttr->owner()->data()->refsToMe();
+ std::set<AttributePtr> aRefs = anExternalAttr->owner()->data()->refsToMe();
std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
for (; anIt != aRefs.end(); ++anIt) {
CompositeFeaturePtr aComp =
return false;
}
+ // check the edge is intersected with sketch plane
std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
- std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
- return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
+
+ std::list<GeomPointPtr> anIntersectionsPoints;
+ anEdge->intersectWithPlane(aPlane, anIntersectionsPoints);
+ if (anIntersectionsPoints.empty()) {
+ theError = "The edge is not intersected with sketch plane";
+ return false;
+ }
+ return true;
}
bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
theError = "The object selected is not a sketch feature";
return false;
}
+
+bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
+ theError = "The attribute with the %1 type is not processed";
+ theError.arg(theAttribute->attributeType());
+ return false;
+ }
+
+ AttributeDoublePtr anAngleAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+
+ FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
+ AttributeStringPtr anAngleType =
+ aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
+ AttributeIntegerPtr aNbCopies =
+ aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
+
+ if (anAngleType->value() != "FullAngle")
+ {
+ double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
+ if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
+ {
+ theError = "Rotation single angle should produce full angle less than 360 degree";
+ return false;
+ }
+ }
+ else
+ {
+ double aFullAngleValue = anAngleAttr->value();
+ if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
+ {
+ theError = "Rotation full angle should be in range [0, 360]";
+ return false;
+ }
+ }
+
+ return true;
+}
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_MultiRotationAngleValidator
+ * \ingroup Validators
+ * \brief Validator for checking whether the angle of MultiRotation is in range [0, 360].
+ */
+class SketchPlugin_MultiRotationAngleValidator : public ModelAPI_AttributeValidator
+{
+ //! 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,
+ Events_InfoMessage& theError) const;
+};
+
#endif
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+ TestIntersectionChangeEdge.py
+ Unit test of SketchPlugin_IntersectionPoint class
+"""
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_1.addArc(0, 0, 13.75, -26.66341125962693, -24.98309575119448, 16.60857991180005, False)
+SketchArc_2 = Sketch_1.addArc(0, 0, 53.75, -26.66341125962693, -53.75, -26.66341125962693, False)
+SketchLine_1 = Sketch_1.addLine(13.75, -26.66341125962693, 53.75, -26.66341125962693)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchArc_2.startPoint(), SketchLine_1.endPoint())
+SketchLine_2 = Sketch_1.addLine(-24.98309575119448, 16.60857991180005, -53.75, -26.66341125962693)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.endPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.center(), SketchArc_1.center())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_2.result(), SketchArc_1.results()[1])
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_1.result())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_2.center(), SketchAPI_Point(SketchPoint_1).coordinates())
+SketchConstraintRadius_2 = Sketch_1.setRadius(SketchArc_2.results()[1], 60)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 40)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_1_2r-SketchArc_2_2f-SketchLine_1f-SketchLine_2r")], model.selection(), 50, 50)
+Filling_1 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/From_Face_1"), model.selection("EDGE", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1"), model.selection("VERTEX", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1"), False)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/Vertex-SketchArc_1-SketchArc_2-SketchProjection_1-SketchPoint_1"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchLine_3 = Sketch_2.addLine(-70, 60, 70, 60)
+SketchLine_4 = Sketch_2.addLine(70, 60, 70, -60)
+SketchLine_5 = Sketch_2.addLine(70, -60, -70, -60)
+SketchLine_6 = Sketch_2.addLine(-70, -60, -70, 60)
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_2 = Sketch_2.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_6.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_5.result(), 60, True)
+SketchConstraintDistance_2 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_3.result(), 60, True)
+SketchConstraintDistance_3 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_4.result(), 70, True)
+SketchConstraintDistance_4 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_6.result(), 70, True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_3r-SketchLine_4r-SketchLine_5r-SketchLine_6r")])
+Intersection_1 = model.addIntersection(Part_1_doc, [model.selection("FACE", "Filling_1_1")], [model.selection("FACE", "Face_1_1")])
+
+# set different edges used for intersection and check reference data: number of intersection points and their coordinates
+REF_DATA = [("Sketch_1/Edge-SketchArc_1_2", 1, [[30, 0]]),
+ ("Sketch_1/Edge-SketchLine_2", 1, [[-36.024358588836, 0]]),
+ ("Sketch_1/Edge-SketchArc_2_2", 2, [[60, 0], [-60, 0]]),
+ ("Sketch_1/Edge-SketchLine_1", 0, []),
+ ("Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1", 1, [[30, 50]]),
+ ("Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1", 1, [[-36.024358588836, 50]]),
+ ("Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1", 2, [[60, 50], [-60, 50]]),
+ ("Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1", 0, []),
+ ("Intersection_1_1", 2, [[-0.0515933488223, -11.6181750315], [41.6438615258, -11.6181750315]])]
+TOLERANCE = 1.e-7
+
+Sketch_3 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchIntersectionPoint_1 = Sketch_3.addIntersectionPoint(model.selection("EDGE", "Intersection_1_1"), True)
+model.do()
+
+for ref in REF_DATA:
+ SketchIntersectionPoint_1.setByExternalEdgeName(ref[0])
+ aPoints = SketchIntersectionPoint_1.intersectionPoints()
+ assert(len(aPoints) == ref[1]), "Intersection with edge {} produce {} points, expected {}".format(ref[0], aPoints.size(), ref[1])
+ # check coordinates
+ ind = 0
+ for p in aPoints:
+ pnt = SketchAPI_Point(p)
+ delta = (pnt.coordinates().x() - ref[2][ind][0])**2 + (pnt.coordinates().y() - ref[2][ind][1])**2
+ assert(delta < TOLERANCE * TOLERANCE), "Wrong coordinates of intersection with edge {}: ({}, {}) != expected ({}, {})".format(ref[0], pnt.coordinates().x(), pnt.coordinates().y(), ref[2][ind][0], ref[2][ind][1])
+ ind += 1
+model.do()
+
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+ TestIntersectionWithCircle.py
+ Unit test of SketchPlugin_IntersectionPoint class
+"""
+
+from GeomAPI import *
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamD = model.addParameter(Part_1_doc, "D", "12")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(21.25834261322606, 21.25834261322606, 0, 0)
+SketchLine_2 = Sketch_1.addLine(0, 0, 50, -4.088404617988313e-023)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(50, -4.088404617988313e-023, 50, 50)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(50, 50, 28.74165738677394, 28.74165738677394)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_4.result(), SketchLine_1.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_3.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_4.result())
+SketchArc_1 = Sketch_1.addArc(31, 19, 21.25834261322606, 21.25834261322606, 28.74165738677394, 28.74165738677394, False)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchArc_1.endPoint())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 10)
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_2.result(), 19, True)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchArc_1_2r")], model.selection(), 10, 0)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_4"), "D", True)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchIntersectionPoint_1 = Sketch_2.addIntersectionPoint(model.selection("EDGE", "Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1"), True)
+SketchIntersectionPoint_1.result().setName("SketchIntersectionPoint_1")
+[SketchPoint_2, SketchPoint_3] = SketchIntersectionPoint_1.intersectionPoints()
+SketchCircle_1 = Sketch_2.addCircle(38.14142842854285, 10, 1)
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_2).coordinates())
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_1.results()[1], 1)
+SketchLine_5 = Sketch_2.addLine(23.85857157145715, 10.5, 23.85857157145715, 5)
+SketchLine_6 = Sketch_2.addLine(22.85857157145715, 6, 22.85857157145715, 10.5)
+SketchLine_7 = Sketch_2.addLine(22.85857157145715, 10.5, 23.85857157145715, 10.5)
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_5.startPoint(), SketchLine_7.endPoint())
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_6.result())
+SketchConstraintHorizontal_2 = Sketch_2.setHorizontal(SketchLine_7.result())
+SketchConstraintDistanceHorizontal_1 = Sketch_2.setHorizontalDistance(SketchLine_6.endPoint(), SketchLine_5.startPoint(), 1)
+SketchConstraintDistanceVertical_1 = Sketch_2.setVerticalDistance(SketchLine_5.startPoint(), SketchAPI_Point(SketchPoint_3).coordinates(), 0.5)
+SketchArc_2 = Sketch_2.addArc(23.85857157145715, 6, 23.85857157145715, 5, 22.85857157145715, 6, True)
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_5.result(), SketchArc_2.center())
+SketchConstraintCoincidence_12 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_13 = Sketch_2.setCoincident(SketchArc_2.endPoint(), SketchLine_6.startPoint())
+SketchConstraintDistanceVertical_2 = Sketch_2.setVerticalDistance(SketchAPI_Point(SketchPoint_3).coordinates(), SketchArc_2.startPoint(), 5)
+SketchConstraintTangent_1 = Sketch_2.setTangent(SketchArc_2.results()[1], SketchLine_6.result())
+model.do()
+RevolutionCut_1 = model.addRevolutionCut(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_5r-SketchLine_6r-SketchLine_7r-SketchArc_2_2f")], model.selection("EDGE", "Sketch_2/Edge-SketchLine_5"), 360, 0, [model.selection("SOLID", "Extrusion_1_1")])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_1_2f")], model.selection(), 5, 5, [model.selection("SOLID", "RevolutionCut_1_1")])
+model.do()
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 2)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [13])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [66])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [132])
+model.testResultsVolumes(ExtrusionCut_1, [9451.611727849665840039961040020])
+
+# change parameter and check intersection validity
+ParamD.setValue(15)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 2)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [14])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [74])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [148])
+model.testResultsVolumes(ExtrusionCut_1, [9451.152473626798382611013948917])
+
+# change parameter and check intersection validity
+ParamD.setValue(19)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 2)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [14])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [74])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [148])
+model.testResultsVolumes(ExtrusionCut_1, [9448.046243665688962209969758987])
+
+# change parameter and check intersection validity
+ParamD.setValue(23)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 1)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [50])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [100])
+model.testResultsVolumes(ExtrusionCut_1, [9458.635858820198336616158485413])
+
+# change parameter and check intersection validity
+ParamD.setValue(29)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 1)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [42])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [84])
+model.testResultsVolumes(ExtrusionCut_1, [9463.846034357124153757467865944])
+
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+ TestIntersectionWithLine.py
+ Unit test of SketchPlugin_IntersectionPoint class
+"""
+
+from GeomAPI import *
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamD = model.addParameter(Part_1_doc, "D", "40")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(0, 0, 50, 0)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchPoint_1.result())
+SketchLine_2 = Sketch_1.addLine(50, 0, 50, 10)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(50, 10, 40, 10)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(40, 10, 40, 30)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(40, 30, 50, 30)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(50, 30, 50, 40)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(50, 40, 0, 50)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(0, 50, 0, 0)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_8.endPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_2.result(), SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_8.result(), 50)
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_2.result(), 10)
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_1.startPoint(), SketchLine_4.startPoint(), "D")
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_1.endPoint(), SketchLine_7.startPoint(), 40, True)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f")], model.selection(), 10, 0)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 5, 5, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_5"))
+SketchIntersectionPoint_1 = Sketch_2.addIntersectionPoint(model.selection("EDGE", "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1"))
+[SketchPoint_2] = SketchIntersectionPoint_1.intersectionPoints()
+SketchCircle_1 = Sketch_2.addCircle(40, 10, 5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchCircle_1.results()[1], 5)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+
+assert(SketchIntersectionPoint_1.feature().results().empty() == False)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [13])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [66])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [132])
+model.testResultsVolumes(ExtrusionCut_1, [20303.650459150881943060085177422])
+
+# change parameter and check intersection validity
+ParamD.setValue(35)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().empty() == False)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [13])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [66])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [132])
+model.testResultsVolumes(ExtrusionCut_1, [19303.650459150881943060085177422])
+
+# change parameter and check the intersection is not valid now
+ParamD.setValue(60)
+model.do();
+assert(SketchIntersectionPoint_1.feature().results().empty() == True)
+
+# change parameter to initial value and check intersection validity
+ParamD.setValue(40)
+model.do();
+# coincidence of circle center and intersection point is lost on previous step, restore it
+[SketchPoint_2] = SketchIntersectionPoint_1.intersectionPoints()
+Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchCircle_1.center())
+model.do()
+
+assert(SketchIntersectionPoint_1.feature().results().empty() == False)
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [13])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [66])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [132])
+model.testResultsVolumes(ExtrusionCut_1, [20303.650459150881943060085177422])
+
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+"""
+ TestIntersectionWithSpline.py
+ Unit test of SketchPlugin_IntersectionPoint class
+"""
+
+from GeomAPI import *
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamD = model.addParameter(Part_1_doc, "D", "5")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_1.addArc(-20, 0, -12.51615726667241, -49.43674845641531, -67.51615726667241, 15.56325154358469, False)
+SketchLine_1 = Sketch_1.addLine(-67.51615726667241, 15.56325154358469, -12.51615726667241, 15.56325154358469)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+SketchLine_2 = Sketch_1.addLine(-12.51615726667241, 15.56325154358469, -12.51615726667241, -49.43674845641531)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_2.endPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_3 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_3.result())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 50)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 65)
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchArc_1.center(), SketchAPI_Line(SketchLine_3).startPoint(), 20)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 55)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_1_2f-SketchLine_1f-SketchLine_2f")], model.selection(), 25, 25)
+Filling_1 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1"), model.selection("EDGE", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1")])
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_1_2f-SketchLine_1f-SketchLine_2f")])
+Intersection_1 = model.addIntersection(Part_1_doc, [model.selection("FACE", "Filling_1_1")], [model.selection("FACE", "Face_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_4 = Sketch_2.addLine(-34.11217447219568, 40, 20, -37.28019411294778)
+SketchLine_5 = Sketch_2.addLine(20, -37.28019411294778, 20, 40)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_2.addLine(20, 40, -34.11217447219568, 40)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchLine_4.startPoint(), SketchLine_6.endPoint())
+SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_2 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_2.createdFeature()
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_5.result(), 20, True)
+SketchConstraintDistance_2 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_6.result(), 40, True)
+SketchConstraintDistance_3 = Sketch_2.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "D", True)
+SketchConstraintAngle_1 = Sketch_2.setAngle(SketchLine_5.result(), SketchLine_4.result(), 35)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), 10, 10)
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [], model.selection(), 10, 0, [model.selection("SOLID", "Extrusion_2_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_2_1/Generated_Face_3"))
+SketchIntersectionPoint_1 = Sketch_3.addIntersectionPoint(model.selection("EDGE", "Intersection_1_1"), False)
+[SketchPoint_2, SketchPoint_3] = SketchIntersectionPoint_1.intersectionPoints()
+SketchCircle_1 = Sketch_3.addCircle(-33.22640570408476, 0, 5)
+SketchConstraintCoincidence_8 = Sketch_3.setCoincident(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_2).coordinates())
+SketchCircle_2 = Sketch_3.addCircle(21.47998214403209, 0, 5)
+SketchConstraintCoincidence_9 = Sketch_3.setCoincident(SketchCircle_2.center(), SketchAPI_Point(SketchPoint_3).coordinates())
+SketchConstraintEqual_1 = Sketch_3.setEqual(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+SketchConstraintRadius_2 = Sketch_3.setRadius(SketchCircle_1.results()[1], 5)
+ExtrusionFuse_1.setNestedSketch(Sketch_3)
+model.do()
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 2)
+
+model.testNbResults(ExtrusionFuse_1, 1)
+model.testNbSubResults(ExtrusionFuse_1, [0])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.EDGE, [30])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.VERTEX, [60])
+model.testResultsVolumes(ExtrusionFuse_1, [43388.789797644698410294950008392])
+
+# change parameter and check intersection validity
+ParamD.setValue(15)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 2)
+
+model.testNbResults(ExtrusionFuse_1, 1)
+model.testNbSubResults(ExtrusionFuse_1, [0])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.EDGE, [30])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.VERTEX, [60])
+model.testResultsVolumes(ExtrusionFuse_1, [64385.484780074148147832602262497])
+
+# change parameter and check single intersection
+ParamD.setValue(25)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 1)
+
+model.testNbResults(ExtrusionFuse_1, 1)
+model.testNbSubResults(ExtrusionFuse_1, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.FACE, [11])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.EDGE, [42])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.VERTEX, [84])
+model.testResultsVolumes(ExtrusionFuse_1, [89224.362837261898675933480262756])
+
+# change parameter and check intersection is NOT valid now
+ParamD.setValue(50)
+model.do();
+
+assert(SketchIntersectionPoint_1.feature().results().empty())
+
+# revert parameter to original value and reset coincidences
+ParamD.setValue(5)
+model.do()
+[SketchPoint_2, SketchPoint_3] = SketchIntersectionPoint_1.intersectionPoints()
+SketchConstraintCoincidence_8 = Sketch_3.setCoincident(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_2).coordinates())
+SketchConstraintCoincidence_9 = Sketch_3.setCoincident(SketchCircle_2.center(), SketchAPI_Point(SketchPoint_3).coordinates())
+model.do()
+
+assert(SketchIntersectionPoint_1.feature().results().size() == 2)
+
+model.testNbResults(ExtrusionFuse_1, 1)
+model.testNbSubResults(ExtrusionFuse_1, [0])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.EDGE, [30])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.VERTEX, [60])
+model.testResultsVolumes(ExtrusionFuse_1, [43388.789797644698410294950008392])
+
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(30, 20, 10, 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+model.do()
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchAPI_Point(SketchPoint_1).coordinates(), 90, 5)
+model.do()
+
+# check MultiRotation is invalid
+assert(SketchMultiRotation_1.feature().error() != "")
+
+model.end()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(30, 20, 10, 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+model.do()
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchAPI_Point(SketchPoint_1).coordinates(), 200, 2)
+model.do()
+
+# check MultiRotation is valid
+assert(SketchMultiRotation_1.feature().error() == "")
+
+# update number of copies to make MultiRotation invalid
+SketchMultiRotation_1.feature().integer("MultiRotationObjects").setValue(3)
+model.do()
+assert(SketchMultiRotation_1.feature().error() != "")
+
+model.end()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools
+from SketchAPI import *
+from math import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(30, 20, 10, 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+model.do()
+
+ROT_ANGLE = 90
+ROT_COPIES = 3
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchAPI_Point(SketchPoint_1).coordinates(), ROT_ANGLE, ROT_COPIES)
+model.do()
+
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE)
+
+# set angle value from single to full
+SketchMultiRotation_1.feature().string("AngleType").setValue("FullAngle")
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE*(ROT_COPIES - 1))
+
+# check coordinates of center of mass of each line
+REF_DATA = [[-20, 20],
+ [-20, -20]]
+TOLERANCE = 1.e-7
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+# set angle value from full to single
+SketchMultiRotation_1.feature().string("AngleType").setValue("SingleAngle")
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE)
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools
+from SketchAPI import *
+from math import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(30, 20, 10, 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+model.do()
+
+ROT_ANGLE = 360
+ROT_COPIES = 4
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchAPI_Point(SketchPoint_1).coordinates(), ROT_ANGLE, ROT_COPIES, True)
+model.do()
+
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE)
+
+# check coordinates of center of mass of each line
+REF_DATA = [[-20, 20],
+ [-20, -20],
+ [20, -20]]
+TOLERANCE = 1.e-7
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+# set angle value from full to single
+SketchMultiRotation_1.feature().string("AngleType").setValue("SingleAngle")
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE/ROT_COPIES)
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+# set angle value from single to full
+SketchMultiRotation_1.feature().string("AngleType").setValue("FullAngle")
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE/ROT_COPIES*(ROT_COPIES - 1))
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from GeomAlgoAPI import GeomAlgoAPI_ShapeTools
+from SketchAPI import *
+from math import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, 0, 30, 0)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+model.do()
+
+ROT_ANGLE = 20
+ROT_COPIES = 15
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchAPI_Point(SketchPoint_1).coordinates(), ROT_ANGLE, ROT_COPIES)
+model.do()
+
+# collect coordinates of centers as reference data
+TOLERANCE = 1.e-7
+REF_DATA = [[]]
+aLines = SketchMultiRotation_1.rotated()
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ REF_DATA.append([massCenter.x(), massCenter.y()])
+del REF_DATA[0]
+
+FeatureMultiRotation = SketchMultiRotation_1.feature()
+
+# assign "reversed" flag
+FeatureMultiRotation.boolean("MultiRotationReversed").setValue(True)
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE)
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() + REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], -REF_DATA[ind][1], 0.0)
+ ind += 1
+
+# drop "reversed" flag
+FeatureMultiRotation.boolean("MultiRotationReversed").setValue(False)
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE)
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+# set angle value from single to full
+SketchMultiRotation_1.feature().string("AngleType").setValue("FullAngle")
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE*(ROT_COPIES - 1))
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() - REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], REF_DATA[ind][1], 0.0)
+ ind += 1
+
+# assign "reversed" flag
+FeatureMultiRotation.boolean("MultiRotationReversed").setValue(True)
+model.do()
+assert(SketchMultiRotation_1.angle().value() == ROT_ANGLE*(ROT_COPIES - 1))
+
+# check coordinates of center of mass of each line
+aLines = SketchMultiRotation_1.rotated()
+ind = 0
+for lin in aLines:
+ curShape = lin.feature().lastResult().shape()
+ massCenter = GeomAlgoAPI_ShapeTools.centreOfMass(curShape)
+ assert(fabs(massCenter.x() - REF_DATA[ind][0]) < TOLERANCE and fabs(massCenter.y() + REF_DATA[ind][1]) < TOLERANCE and massCenter.z() == 0), "({}, {}, {}) != ({}, {}, {})".format(massCenter.x(), massCenter.y(), massCenter.z(), REF_DATA[ind][0], -REF_DATA[ind][1], 0.0)
+ ind += 1
+
+model.end()
+
+assert(model.checkPythonDump())
</excluded>
<group id="Projection">
- <!-- Intersection Point -->
- <!-- feature
- id="SketchIntersectionPoint"
- title="Intersection Point"
- tooltip="Create intersection point"
- icon="icons/Sketch/intersection_point.png">
- <sketch_shape_selector
- id="ExternalLine"
- label="Edge"
- tooltip="Select external line."
- shape_types="edge"
- use_external="false"
- use_sketch_plane="false">
- <validator id="GeomValidators_ShapeType" parameters="line"/>
- <validator id="SketchPlugin_IntersectionValidator"/>
- </sketch_shape_selector>
- </feature -->
-
<!-- Projected feature -->
<feature
id="SketchProjection"
<boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"/>
<validator id="PartSet_ProjectionSelection"/>
</feature>
+
+ <!-- Intersection Point -->
+ <feature
+ id="SketchIntersectionPoint"
+ title="Intersection"
+ tooltip="Intersect edge with sketch plane"
+ icon="icons/Sketch/intersection.png">
+ <sketch_shape_selector
+ id="ExternalFeature"
+ label="Object"
+ tooltip="Select external edge."
+ shape_types="edge"
+ use_external="true"
+ can_create_external="false"
+ use_sketch_plane="false">
+ <validator id="SketchPlugin_IntersectionValidator"/>
+ </sketch_shape_selector>
+ <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"/>
+ <validator id="PartSet_IntersectionSelection"/>
+ </feature>
</group>
<group id="Replication">
label="Angle"
icon="icons/Sketch/angle.png"
tooltip="Rotation angle"
- default="90" use_reset="false"/>
+ default="90" min="0" max="360"
+ use_reset="false">
+ <validator id="SketchPlugin_MultiRotationAngleValidator" />
+ </doublevalue>
+ <boolvalue id="MultiRotationReversed"
+ label="Reversed"
+ tooltip="Reverse angular copy"
+ default="false"
+ obligatory="0"/>
</box>
<box id="FullAngle" title="Full angle" icon="icons/Sketch/angle_up_full_32x32.png">
<doublevalue id="MultiRotationAngle"
label="Angle"
icon="icons/Sketch/angle.png"
tooltip="Rotation angle"
- default="90" use_reset="false"/>
+ default="90" min="0" max="360"
+ use_reset="false">
+ <validator id="SketchPlugin_MultiRotationAngleValidator" />
+ </doublevalue>
+ <boolvalue id="MultiRotationReversed"
+ label="Reversed"
+ tooltip="Reverse angular copy"
+ default="false"
+ obligatory="0"/>
</box>
</toolbox>
<integervalue id="MultiRotationObjects"
void SketchSolver_ConstraintMultiRotation::getAttributes(
EntityWrapperPtr& theCenter, ScalarWrapperPtr& theAngle,
- bool& theFullValue, std::list<EntityWrapperPtr>& theEntities)
+ bool& theFullValue, bool& theReversed, std::list<EntityWrapperPtr>& theEntities)
{
AttributePtr anAngleAttr = myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID());
PlaneGCSSolver_AttributeBuilder aValueBuilder;
myBaseConstraint->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
theFullValue = aMethodTypeAttr->value() != "SingleAngle";
+ theReversed = myBaseConstraint->boolean(SketchPlugin_MultiRotation::REVERSED_ID())->value();
+
getEntities(theEntities);
// add owner of central point of Multi-Rotation to the list of monitored features
EntityWrapperPtr aRotationCenter;
std::list<EntityWrapperPtr> aBaseEntities;
- getAttributes(aRotationCenter, myAngle, myIsFullValue, aBaseEntities);
+ getAttributes(aRotationCenter, myAngle, myIsFullValue, myIsRevered, aBaseEntities);
if (!myErrorMsg.empty())
return;
void SketchSolver_ConstraintMultiRotation::updateLocal()
{
double aValue = myBaseConstraint->real(SketchPlugin_MultiRotation::ANGLE_ID())->value();
- if (fabs(myAngle->value() - aValue) > tolerance)
+ bool isReversed = myBaseConstraint->boolean(SketchPlugin_MultiRotation::REVERSED_ID())->value();
+ if (fabs(myAngle->value() - aValue) > tolerance || isReversed != myIsRevered)
myAdjusted = false;
// update angle value
myAngle->setValue(aValue);
+ myIsRevered = isReversed;
// update center
DataPtr aData = myBaseConstraint->data();
myStorage->setNeedToResolve(false);
return;
}
+ if (myIsRevered)
+ anAngleValue *= -1.0;
// Obtain coordinates of rotation center
AttributeRefAttrPtr aCenterAttr =
}
if (myIsFullValue && myNumberOfCopies > 0)
- anAngleValue /= myNumberOfCopies;
+ {
+ // if the full angle value is equal to 360, then distribute rotated items
+ // to avoid superposition of original feature and last copy
+ if (fabs(anAngleValue - 360.0) < 1.e-7)
+ anAngleValue /= (myNumberOfCopies + 1);
+ else
+ anAngleValue /= myNumberOfCopies;
+ }
myRotationVal[0] = sin(anAngleValue * PI / 180.0);
myRotationVal[1] = cos(anAngleValue * PI / 180.0);
virtual void process();
/// \brief Generate list of rotated entities
- /// \param[out] theCenter central point of rotation
- /// \param[out] theAngle rotation angle
- /// \param[out] theFullValue applying translation using the disstance as a full or single value
- /// \param[out] theEntities list of base entities
+ /// \param[out] theCenter central point of rotation
+ /// \param[out] theAngle rotation angle
+ /// \param[out] theFullValue applying translation using the distance as a full or single value
+ /// \param[out] theReversed rotation angle is negative
+ /// \param[out] theEntities list of base entities
void getAttributes(EntityWrapperPtr& theCenter,
ScalarWrapperPtr& theAngle,
bool& theFullValue,
+ bool& theReversed,
std::list<EntityWrapperPtr>& theEntities);
/// \brief This method is used in derived objects to check consistence of constraint.
private:
AttributePoint2DPtr myCenterPointAttribute; ///< a center of rotation
ScalarWrapperPtr myAngle; ///< angle of rotation
+ bool myIsRevered; ///< angle of rotation is negative
double myCenterCoord[2]; ///< coordinates of rotation center
double myRotationVal[2]; ///< sinus and cosine of rotation angle
/// Returns ResultPart object if the given object is a Part feature
/// Otherwise returns NULL
-#define SELECTABLE_COLOR QColor(80, 80, 80)
+#define SELECTABLE_COLOR QColor(110, 110, 110)
#define DISABLED_COLOR QColor(200, 200, 200)
}
}
+//***************************************************
+void XGUI_ObjectsBrowser::ensureVisible(const ObjectPtr theObject)
+{
+ QModelIndex aIndex = myDocModel->objectIndex(theObject);
+ if (aIndex.isValid()) {
+ QModelIndex aParent = aIndex.parent();
+ while (aParent.isValid()) {
+ myTreeView->expand(aParent);
+ aParent = aParent.parent();
+ }
+ myTreeView->scrollTo(aIndex);
+ }
+}
+
//***************************************************
void XGUI_ObjectsBrowser::clearContent()
{
/// \param theObjects list of objects to select
void setObjectsSelected(const QObjectPtrList& theObjects);
+ //! Scroll TreeView to make given object visible
+ //! \param theObject object to make it visible
+ void ensureVisible(const ObjectPtr theObject);
+
//! Returns currently selected indexes
QModelIndexList selectedIndexes() const
{
{
FeaturePtr aFeature;
QObjectPtrList aSelList = theObjects;
+ QObjectPtrList aNewSel;
bool aHasHidden = false;
foreach(ObjectPtr aObj, theObjects) {
aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
for(aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
aHasHidden |= (*aIt)->isConcealed();
aSelList.append(*aIt);
+ aNewSel.append(*aIt);
}
}
}
bool aBlocked = objectBrowser()->blockSignals(true);
objectBrowser()->setObjectsSelected(aSelList);
objectBrowser()->blockSignals(aBlocked);
+ objectBrowser()->ensureVisible(aNewSel.first());
}
if (aHasHidden)
QMessageBox::information(desktop(), tr("Find results"),
{
ResultPtr aResult;
QObjectPtrList aSelList = theObjects;
+ QObjectPtrList aNewSel;
FeaturePtr aFeature;
foreach(ObjectPtr aObj, theObjects) {
aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
aFeature = ModelAPI_Feature::feature(aResult);
if (aFeature.get()) {
aSelList.append(aFeature);
+ aNewSel.append(aFeature);
}
}
}
bool aBlocked = objectBrowser()->blockSignals(true);
objectBrowser()->setObjectsSelected(aSelList);
objectBrowser()->blockSignals(aBlocked);
+ objectBrowser()->ensureVisible(aNewSel.first());
}
}
# Symmetries
-Symmetry_1 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("VERTEX", "PartSet/Origin"))
-Symmetry_2 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_2_1")], model.selection("VERTEX", "Point_1"))
-Symmetry_3 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("VERTEX", "Box_3_1/Front&Box_3_1/Right&Box_3_1/Top"))
-Symmetry_4 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_4_1")], model.selection("VERTEX", "Sketch_1/Vertex-SketchLine_1e"))
-Symmetry_5 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_5_1")], model.selection("VERTEX", "Vertex_1_1"))
-Symmetry_6 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_6_1")], model.selection("VERTEX", "InvalidName"))
-
-Symmetry_7 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_7_1")], model.selection("EDGE", "PartSet/OZ"))
-Symmetry_8 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_8_1")], model.selection("EDGE", "Axis_1"))
-Symmetry_9 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_9_1")], model.selection("EDGE", "Box_9_1/Front&Box_9_1/Top"))
-Symmetry_10 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_10_1")], model.selection("EDGE", "Sketch_1/Edge-SketchLine_1"))
-Symmetry_11 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_11_1")], model.selection("EDGE", "Edge_1_1"))
-Symmetry_12 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_12_1")], model.selection("EDGE", "InvalidName"))
-
-Symmetry_13 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_13_1")], model.selection("FACE", "PartSet/XOY"))
-Symmetry_14 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_14_1")], model.selection("FACE", "Plane_1"))
-Symmetry_15 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_15_1")], model.selection("FACE", "Box_15_1/Front"))
-Symmetry_16 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_16_1")], model.selection("FACE", "Face_1_1"))
-Symmetry_17 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Box_17_1")], model.selection("FACE", "InvalidName"))
-Symmetry_18 = model.addSymmetry(Part_1_doc, [model.selection("SHELL", "Extrusion_1_1")], model.selection("FACE", "Plane_2"))
+Symmetry_1 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("VERTEX", "PartSet/Origin"))
+Symmetry_2 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_2_1")], model.selection("VERTEX", "Point_1"))
+Symmetry_3 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("VERTEX", "Box_3_1/Front&Box_3_1/Right&Box_3_1/Top"))
+Symmetry_4 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_4_1")], model.selection("VERTEX", "Sketch_1/Vertex-SketchLine_1e"))
+Symmetry_5 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_5_1")], model.selection("VERTEX", "Vertex_1_1"))
+Symmetry_6 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_6_1")], model.selection("VERTEX", "InvalidName"))
+
+Symmetry_7 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_7_1")], model.selection("EDGE", "PartSet/OZ"))
+Symmetry_8 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_8_1")], model.selection("EDGE", "Axis_1"))
+Symmetry_9 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_9_1")], model.selection("EDGE", "Box_9_1/Front&Box_9_1/Top"))
+Symmetry_10 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_10_1")], model.selection("EDGE", "Sketch_1/Edge-SketchLine_1"))
+Symmetry_11 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_11_1")], model.selection("EDGE", "Edge_1_1"))
+Symmetry_12 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_12_1")], model.selection("EDGE", "InvalidName"))
+
+Symmetry_13 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_13_1")], model.selection("FACE", "PartSet/XOY"))
+Symmetry_14 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_14_1")], model.selection("FACE", "Plane_1"))
+Symmetry_15 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_15_1")], model.selection("FACE", "Box_15_1/Front"))
+Symmetry_16 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_16_1")], model.selection("FACE", "Face_1_1"))
+Symmetry_17 = model.addMirror(Part_1_doc, [model.selection("SOLID", "Box_17_1")], model.selection("FACE", "InvalidName"))
+Symmetry_18 = model.addMirror(Part_1_doc, [model.selection("SHELL", "Extrusion_1_1")], model.selection("FACE", "Plane_2"))
model.do()
model.end()
from GeomAPI import GeomAPI_Shape
model.testNbResults(Symmetry_1, 1)
-model.testNbSubResults(Symmetry_1, [0])
-model.testNbSubShapes(Symmetry_1, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_1, [2])
+model.testNbSubShapes(Symmetry_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_1, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_1, model, Part_1_doc)
model.testNbResults(Symmetry_2, 1)
-model.testNbSubResults(Symmetry_2, [0])
-model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_2, [2])
+model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_2, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_2, model, Part_1_doc)
model.testNbResults(Symmetry_3, 1)
-model.testNbSubResults(Symmetry_3, [0])
-model.testNbSubShapes(Symmetry_3, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_3, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_3, [2])
+model.testNbSubShapes(Symmetry_3, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_3, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_3, model, Part_1_doc)
model.testNbResults(Symmetry_4, 1)
-model.testNbSubResults(Symmetry_4, [0])
-model.testNbSubShapes(Symmetry_4, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_4, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_4, [2])
+model.testNbSubShapes(Symmetry_4, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_4, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_4, model, Part_1_doc)
model.testNbResults(Symmetry_5, 1)
-model.testNbSubResults(Symmetry_5, [0])
-model.testNbSubShapes(Symmetry_5, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_5, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_5, [2])
+model.testNbSubShapes(Symmetry_5, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_5, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_5, model, Part_1_doc)
model.testNbResults(Symmetry_7, 1)
-model.testNbSubResults(Symmetry_7, [0])
-model.testNbSubShapes(Symmetry_7, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_7, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_7, [2])
+model.testNbSubShapes(Symmetry_7, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_7, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_7, model, Part_1_doc)
model.testNbResults(Symmetry_8, 1)
-model.testNbSubResults(Symmetry_8, [0])
-model.testNbSubShapes(Symmetry_8, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_8, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_8, [2])
+model.testNbSubShapes(Symmetry_8, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_8, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_8, model, Part_1_doc)
model.testNbResults(Symmetry_9, 1)
-model.testNbSubResults(Symmetry_9, [0])
-model.testNbSubShapes(Symmetry_9, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_9, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_9, [2])
+model.testNbSubShapes(Symmetry_9, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_9, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_9, model, Part_1_doc)
model.testNbResults(Symmetry_10, 1)
-model.testNbSubResults(Symmetry_10, [0])
-model.testNbSubShapes(Symmetry_10, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_10, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_10, [2])
+model.testNbSubShapes(Symmetry_10, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_10, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_10, model, Part_1_doc)
model.testNbResults(Symmetry_11, 1)
-model.testNbSubResults(Symmetry_11, [0])
-model.testNbSubShapes(Symmetry_11, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_11, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_11, [2])
+model.testNbSubShapes(Symmetry_11, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_11, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_11, model, Part_1_doc)
model.testNbResults(Symmetry_13, 1)
-model.testNbSubResults(Symmetry_13, [0])
-model.testNbSubShapes(Symmetry_13, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_13, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_13, [2])
+model.testNbSubShapes(Symmetry_13, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_13, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_13, model, Part_1_doc)
model.testNbResults(Symmetry_14, 1)
-model.testNbSubResults(Symmetry_14, [0])
-model.testNbSubShapes(Symmetry_14, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_14, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_14, [2])
+model.testNbSubShapes(Symmetry_14, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_14, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_14, model, Part_1_doc)
model.testNbResults(Symmetry_15, 1)
-model.testNbSubResults(Symmetry_15, [0])
-model.testNbSubShapes(Symmetry_15, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_15, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_15, [2])
+model.testNbSubShapes(Symmetry_15, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_15, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_15, model, Part_1_doc)
model.testNbResults(Symmetry_16, 1)
-model.testNbSubResults(Symmetry_16, [0])
-model.testNbSubShapes(Symmetry_16, GeomAPI_Shape.SOLID, [1])
-model.testNbSubShapes(Symmetry_16, GeomAPI_Shape.FACE, [6])
+model.testNbSubResults(Symmetry_16, [2])
+model.testNbSubShapes(Symmetry_16, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Symmetry_16, GeomAPI_Shape.FACE, [12])
model.testHaveNamingFaces(Symmetry_16, model, Part_1_doc)
model.testNbResults(Symmetry_6, 0)
model.testNbResults(Symmetry_17, 0)
assert(Symmetry_17.feature().error() == 'Attribute "plane_object" is not initialized.')
-# To uncomment when #2046 will be performed
-#model.testNbResults(Symmetry_18, 1)
-#model.testNbSubResults(Symmetry_18, [0])
-#model.testNbSubShapes(Symmetry_18, GeomAPI_Shape.SOLID, [0])
-#model.testNbSubShapes(Symmetry_18, GeomAPI_Shape.SHELL, [1])
-#model.testNbSubShapes(Symmetry_18, GeomAPI_Shape.FACE, [5])
-#model.testHaveNamingFaces(Symmetry_18, model, Part_1_doc)
\ No newline at end of file
+model.testNbResults(Symmetry_18, 1)
+model.testNbSubResults(Symmetry_18, [2])
+model.testNbSubShapes(Symmetry_18, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Symmetry_18, GeomAPI_Shape.SHELL, [2])
+model.testNbSubShapes(Symmetry_18, GeomAPI_Shape.FACE, [10])
+model.testHaveNamingFaces(Symmetry_18, model, Part_1_doc)