From b6a827b5f2b1c61957dc2b22bfa11eba72175413 Mon Sep 17 00:00:00 2001 From: dbv Date: Fri, 1 Jul 2016 12:33:37 +0300 Subject: [PATCH] Added option to create Construction Point by distance on edge. Fixed tests. --- src/ConstructionAPI/ConstructionAPI_Point.cpp | 85 ++++++++++++----- src/ConstructionAPI/ConstructionAPI_Point.h | 70 +++++++++----- src/ConstructionAPI/Test/TestPoint.py | 2 +- src/ConstructionPlugin/CMakeLists.txt | 8 +- .../ConstructionPlugin_Point.cpp | 90 ++++++++++++++---- .../ConstructionPlugin_Point.h | 86 ++++++++++++++--- .../Test/TestAxisCreation.py | 2 + src/ConstructionPlugin/Test/TestPointName.py | 1 + .../icons/distance_value.png | Bin 0 -> 550 bytes src/ConstructionPlugin/icons/edge.png | Bin 0 -> 312 bytes .../icons/point_by_distance_on_edge_32x32.png | Bin 0 -> 703 bytes .../icons/point_by_xyz_32x32.png | Bin 0 -> 1090 bytes src/ConstructionPlugin/icons/x_size.png | Bin 0 -> 519 bytes src/ConstructionPlugin/icons/y_size.png | Bin 0 -> 517 bytes src/ConstructionPlugin/icons/z_size.png | Bin 0 -> 462 bytes src/ConstructionPlugin/point_widget.xml | 52 +++++++++- .../icons/dimension_up_32x32.png | Bin 483 -> 430 bytes .../icons/dimension_up_down_32x32.png | Bin 628 -> 559 bytes src/GeomAPI/GeomAPI_Edge.cpp | 10 ++ src/GeomAPI/GeomAPI_Edge.h | 4 + src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp | 45 +++++++++ src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h | 11 +++ src/GeomValidators/GeomValidators_Finite.cpp | 12 ++- .../InitializationPlugin_Plugin.cpp | 1 + src/ModelAPI/Test/TestUndoRedo.py | 1 + .../Test/TestConstraintCoincidence.py | 5 +- .../Test/TestConstraintMiddlePoint.py | 5 +- 27 files changed, 397 insertions(+), 93 deletions(-) create mode 100644 src/ConstructionPlugin/icons/distance_value.png create mode 100644 src/ConstructionPlugin/icons/edge.png create mode 100644 src/ConstructionPlugin/icons/point_by_distance_on_edge_32x32.png create mode 100644 src/ConstructionPlugin/icons/point_by_xyz_32x32.png create mode 100644 src/ConstructionPlugin/icons/x_size.png create mode 100644 src/ConstructionPlugin/icons/y_size.png create mode 100644 src/ConstructionPlugin/icons/z_size.png diff --git a/src/ConstructionAPI/ConstructionAPI_Point.cpp b/src/ConstructionAPI/ConstructionAPI_Point.cpp index ff5a89de3..c982cc2a7 100644 --- a/src/ConstructionAPI/ConstructionAPI_Point.cpp +++ b/src/ConstructionAPI/ConstructionAPI_Point.cpp @@ -4,39 +4,54 @@ // History: // 29/03/16 - Sergey POKHODENKO - Creation of the file -//-------------------------------------------------------------------------------------- #include "ConstructionAPI_Point.h" -//-------------------------------------------------------------------------------------- + #include -//-------------------------------------------------------------------------------------- -ConstructionAPI_Point::ConstructionAPI_Point( - const std::shared_ptr & theFeature) + +//================================================================================================== +ConstructionAPI_Point::ConstructionAPI_Point(const std::shared_ptr& theFeature) : ModelHighAPI_Interface(theFeature) { initialize(); } -ConstructionAPI_Point::ConstructionAPI_Point( - const std::shared_ptr & theFeature, - const ModelHighAPI_Double & theX, - const ModelHighAPI_Double & theY, - const ModelHighAPI_Double & theZ) +//================================================================================================== +ConstructionAPI_Point::ConstructionAPI_Point(const std::shared_ptr& theFeature, + const ModelHighAPI_Double& theX, + const ModelHighAPI_Double& theY, + const ModelHighAPI_Double& theZ) +: ModelHighAPI_Interface(theFeature) +{ + if(initialize()) { + setByXYZ(theX, theY, theZ); + } +} + +//================================================================================================== +ConstructionAPI_Point::ConstructionAPI_Point(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theEdge, + const ModelHighAPI_Double& theDistanceValue, + const bool theDistancePercent, + const bool theReverse) : ModelHighAPI_Interface(theFeature) { - if (initialize()) - setPoint(theX, theY, theZ); + if(initialize()) { + setByDistanceOnEdge(theEdge, theDistanceValue, theDistancePercent, theReverse); + } } +//================================================================================================== ConstructionAPI_Point::~ConstructionAPI_Point() { } -//-------------------------------------------------------------------------------------- -void ConstructionAPI_Point::setPoint(const ModelHighAPI_Double & theX, - const ModelHighAPI_Double & theY, - const ModelHighAPI_Double & theZ) +//================================================================================================== +void ConstructionAPI_Point::setByXYZ(const ModelHighAPI_Double& theX, + const ModelHighAPI_Double& theY, + const ModelHighAPI_Double& theZ) { + fillAttribute(ConstructionPlugin_Point::CREATION_METHOD_BY_XYZ(), mycreationMethod); fillAttribute(theX, myx); fillAttribute(theY, myy); fillAttribute(theZ, myz); @@ -44,14 +59,40 @@ void ConstructionAPI_Point::setPoint(const ModelHighAPI_Double & theX, execute(); } -//-------------------------------------------------------------------------------------- -PointPtr addPoint( - const std::shared_ptr & thePart, - const ModelHighAPI_Double& theX, - const ModelHighAPI_Double& theY, - const ModelHighAPI_Double& theZ) +//================================================================================================== +void ConstructionAPI_Point::setByDistanceOnEdge(const ModelHighAPI_Selection& theEdge, + const ModelHighAPI_Double& theDistanceValue, + const bool theDistancePercent, + const bool theReverse) +{ + fillAttribute(ConstructionPlugin_Point::CREATION_METHOD_BY_DISTANCE_ON_EDGE(), mycreationMethod); + fillAttribute(theEdge, myedge); + fillAttribute(theDistanceValue, mydistanceValue); + fillAttribute(theDistancePercent, mydistancePercent); + fillAttribute(theReverse, myreverse); + + execute(); +} + +//================================================================================================== +PointPtr addPoint(const std::shared_ptr& thePart, + const ModelHighAPI_Double& theX, + const ModelHighAPI_Double& theY, + const ModelHighAPI_Double& theZ) { // TODO(spo): check that thePart is not empty std::shared_ptr aFeature = thePart->addFeature(ConstructionAPI_Point::ID()); return PointPtr(new ConstructionAPI_Point(aFeature, theX, theY, theZ)); } + +//================================================================================================== +PointPtr addPoint(const std::shared_ptr & thePart, + const ModelHighAPI_Selection& theEdge, + const ModelHighAPI_Double& theDistanceValue, + const bool theDistancePercent, + const bool theReverse) +{ + // TODO(spo): check that thePart is not empty + std::shared_ptr aFeature = thePart->addFeature(ConstructionAPI_Point::ID()); + return PointPtr(new ConstructionAPI_Point(aFeature, theEdge, theDistanceValue, theDistancePercent, theReverse)); +} diff --git a/src/ConstructionAPI/ConstructionAPI_Point.h b/src/ConstructionAPI/ConstructionAPI_Point.h index d2af33298..3e67ce80e 100644 --- a/src/ConstructionAPI/ConstructionAPI_Point.h +++ b/src/ConstructionAPI/ConstructionAPI_Point.h @@ -7,63 +7,89 @@ #ifndef SRC_CONSTRUCTIONAPI_CONSTRUCTIONAPI_POINT_H_ #define SRC_CONSTRUCTIONAPI_CONSTRUCTIONAPI_POINT_H_ -//-------------------------------------------------------------------------------------- #include "ConstructionAPI.h" #include #include #include -//-------------------------------------------------------------------------------------- + class ModelAPI_AttributeDouble; class ModelAPI_Document; class ModelHighAPI_Double; -//-------------------------------------------------------------------------------------- -/**\class ConstructionAPI_Point - * \ingroup CPPHighAPI - * \brief Interface for Point feature - */ -class ConstructionAPI_Point : public ModelHighAPI_Interface + +/// \class ConstructionAPI_Point +/// \ingroup CPPHighAPI +/// \brief Interface for Point feature +class ConstructionAPI_Point: public ModelHighAPI_Interface { public: /// Constructor without values CONSTRUCTIONAPI_EXPORT - explicit ConstructionAPI_Point(const std::shared_ptr & theFeature); + explicit ConstructionAPI_Point(const std::shared_ptr& theFeature); + + /// Constructor with values + CONSTRUCTIONAPI_EXPORT + ConstructionAPI_Point(const std::shared_ptr& theFeature, + const ModelHighAPI_Double& theX, + const ModelHighAPI_Double& theY, + const ModelHighAPI_Double& theZ); + /// Constructor with values CONSTRUCTIONAPI_EXPORT - ConstructionAPI_Point(const std::shared_ptr & theFeature, - const ModelHighAPI_Double & theX, - const ModelHighAPI_Double & theY, - const ModelHighAPI_Double & theZ); + ConstructionAPI_Point(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theEdge, + const ModelHighAPI_Double& theDistanceValue, + const bool theDistancePercent = false, + const bool theReverse = false); + /// Destructor CONSTRUCTIONAPI_EXPORT virtual ~ConstructionAPI_Point(); - INTERFACE_3(ConstructionPlugin_Point::ID(), + INTERFACE_8(ConstructionPlugin_Point::ID(), + creationMethod, ConstructionPlugin_Point::CREATION_METHOD(), ModelAPI_AttributeString, /** Creation method */, x, ConstructionPlugin_Point::X(), ModelAPI_AttributeDouble, /** X attribute */, y, ConstructionPlugin_Point::Y(), ModelAPI_AttributeDouble, /** Y attribute */, - z, ConstructionPlugin_Point::Z(), ModelAPI_AttributeDouble, /** Z attribute */ + z, ConstructionPlugin_Point::Z(), ModelAPI_AttributeDouble, /** Z attribute */, + edge, ConstructionPlugin_Point::EDGE(), ModelAPI_AttributeSelection, /** Edge attribute */, + distanceValue, ConstructionPlugin_Point::DISTANCE_VALUE(), ModelAPI_AttributeDouble, /** Distance value attribute */, + distancePercent, ConstructionPlugin_Point::DISTANCE_PERCENT(), ModelAPI_AttributeBoolean, /** Distance percent attribute */, + reverse, ConstructionPlugin_Point::REVERSE(), ModelAPI_AttributeBoolean, /** Reverse attribute */ ) /// Set point values CONSTRUCTIONAPI_EXPORT - void setPoint(const ModelHighAPI_Double & theX, + void setByXYZ(const ModelHighAPI_Double & theX, const ModelHighAPI_Double & theY, const ModelHighAPI_Double & theZ); + + /// Set edge and distance on it for point + CONSTRUCTIONAPI_EXPORT + void setByDistanceOnEdge(const ModelHighAPI_Selection& theEdge, + const ModelHighAPI_Double& theDistanceValue, + const bool theDistancePercent = false, + const bool theReverse = false); }; -//! Pointer on Point object +/// Pointer on Point object typedef std::shared_ptr PointPtr; -/**\ingroup CPPHighAPI - * \brief Create Point feature - */ +/// \ingroup CPPHighAPI +/// \brief Create Point feature CONSTRUCTIONAPI_EXPORT PointPtr addPoint(const std::shared_ptr & thePart, const ModelHighAPI_Double & theX, const ModelHighAPI_Double & theY, const ModelHighAPI_Double & theZ); -//-------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------- +/// \ingroup CPPHighAPI +/// \brief Create Point feature +CONSTRUCTIONAPI_EXPORT +PointPtr addPoint(const std::shared_ptr & thePart, + const ModelHighAPI_Selection& theEdge, + const ModelHighAPI_Double& theDistanceValue, + const bool theDistancePercent = false, + const bool theReverse = false); + #endif /* SRC_CONSTRUCTIONAPI_CONSTRUCTIONAPI_POINT_H_ */ diff --git a/src/ConstructionAPI/Test/TestPoint.py b/src/ConstructionAPI/Test/TestPoint.py index 7c184c5c5..2ed6c9f05 100644 --- a/src/ConstructionAPI/Test/TestPoint.py +++ b/src/ConstructionAPI/Test/TestPoint.py @@ -28,7 +28,7 @@ class PointTestCase(unittest.TestCase): self.assertEqual(0, point.y().value()) self.assertEqual(0, point.z().value()) - point.setPoint(10, "20", "x + 30") + point.setByXYZ(10, "20", "x + 30") self.assertEqual(10, point.x().value()) self.assertEqual("20", point.y().text()) self.assertEqual("x + 30", point.z().text()) diff --git a/src/ConstructionPlugin/CMakeLists.txt b/src/ConstructionPlugin/CMakeLists.txt index 5fd66b7b8..bdbc15f85 100644 --- a/src/ConstructionPlugin/CMakeLists.txt +++ b/src/ConstructionPlugin/CMakeLists.txt @@ -7,15 +7,15 @@ SET(PROJECT_HEADERS ConstructionPlugin.h ConstructionPlugin_Plugin.h ConstructionPlugin_Point.h - ConstructionPlugin_Axis.h - ConstructionPlugin_Plane.h + ConstructionPlugin_Axis.h + ConstructionPlugin_Plane.h ) SET(PROJECT_SOURCES ConstructionPlugin_Plugin.cpp ConstructionPlugin_Point.cpp - ConstructionPlugin_Axis.cpp - ConstructionPlugin_Plane.cpp + ConstructionPlugin_Axis.cpp + ConstructionPlugin_Plane.cpp ) SET(XML_RESOURCES diff --git a/src/ConstructionPlugin/ConstructionPlugin_Point.cpp b/src/ConstructionPlugin/ConstructionPlugin_Point.cpp index c164e44a4..c7b4f1d44 100644 --- a/src/ConstructionPlugin/ConstructionPlugin_Point.cpp +++ b/src/ConstructionPlugin/ConstructionPlugin_Point.cpp @@ -5,53 +5,101 @@ // Author: Mikhail PONIKAROV #include "ConstructionPlugin_Point.h" -#include "ModelAPI_Session.h" -#include "ModelAPI_Document.h" -#include "ModelAPI_Data.h" -#include "ModelAPI_AttributeDouble.h" + +#include +#include +#include +#include #include -#include -#include -#include +#include +#include -using namespace std; +#include +#include +//================================================================================================== ConstructionPlugin_Point::ConstructionPlugin_Point() { } +//================================================================================================== const std::string& ConstructionPlugin_Point::getKind() { static std::string MY_KIND = ConstructionPlugin_Point::ID(); return MY_KIND; } +//================================================================================================== void ConstructionPlugin_Point::initAttributes() { - data()->addAttribute(ConstructionPlugin_Point::X(), ModelAPI_AttributeDouble::typeId()); - data()->addAttribute(ConstructionPlugin_Point::Y(), ModelAPI_AttributeDouble::typeId()); - data()->addAttribute(ConstructionPlugin_Point::Z(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(X(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(Y(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(Z(), ModelAPI_AttributeDouble::typeId()); + + data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId()); + + data()->addAttribute(EDGE(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(DISTANCE_VALUE(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(DISTANCE_PERCENT(), ModelAPI_AttributeBoolean::typeId()); + data()->addAttribute(REVERSE(), ModelAPI_AttributeBoolean::typeId()); } +//================================================================================================== void ConstructionPlugin_Point::execute() { - std::shared_ptr aPnt( - new GeomAPI_Pnt(data()->real(ConstructionPlugin_Point::X())->value(), - data()->real(ConstructionPlugin_Point::Y())->value(), - data()->real(ConstructionPlugin_Point::Z())->value())); - - std::shared_ptr aConstr = document()->createConstruction(data()); - aConstr->setShape(GeomAlgoAPI_PointBuilder::point(aPnt)); - setResult(aConstr); + GeomShapePtr aShape; + + std::string aCreationMethod = string(CREATION_METHOD())->value(); + if(aCreationMethod == CREATION_METHOD_BY_XYZ()) { + aShape = createByXYZ(); + } else if(aCreationMethod == CREATION_METHOD_BY_DISTANCE_ON_EDGE()) { + aShape = createByDistanceOnEdge(); + } + + if(aShape.get()) { + std::shared_ptr aConstr = document()->createConstruction(data()); + aConstr->setShape(aShape); + setResult(aConstr); + } } -bool ConstructionPlugin_Point::customisePresentation(ResultPtr theResult, +//================================================================================================== +bool ConstructionPlugin_Point::customisePresentation(ResultPtr theResult, AISObjectPtr thePrs, - std::shared_ptr theDefaultPrs) + std::shared_ptr theDefaultPrs) { bool isCustomized = theDefaultPrs.get() != NULL && theDefaultPrs->customisePresentation(theResult, thePrs, theDefaultPrs); //thePrs->setPointMarker(1, 1.); // Set point as a '+' symbol return true; } + +//================================================================================================== +GeomShapePtr ConstructionPlugin_Point::createByXYZ() +{ + return GeomAlgoAPI_PointBuilder::point(real(X())->value(), + real(Y())->value(), + real(Z())->value()); +} + +//================================================================================================== +GeomShapePtr ConstructionPlugin_Point::createByDistanceOnEdge() +{ + // Get edge. + AttributeSelectionPtr anEdgeSelection = selection(EDGE()); + GeomShapePtr aShape = anEdgeSelection->value(); + if(!aShape.get()) { + aShape = anEdgeSelection->context()->shape(); + } + std::shared_ptr anEdge(new GeomAPI_Edge(aShape)); + + // Get distance value and percent flag. + double aValue = real(DISTANCE_VALUE())->value(); + bool anIsPercent = boolean(DISTANCE_PERCENT())->value(); + + // Get reverse flag. + bool anIsReverse = boolean(REVERSE())->value(); + + return GeomAlgoAPI_ShapeTools::findVertexOnEdge(anEdge, aValue, anIsPercent, anIsReverse); +} diff --git a/src/ConstructionPlugin/ConstructionPlugin_Point.h b/src/ConstructionPlugin/ConstructionPlugin_Point.h index d1f15287f..956eeeb00 100644 --- a/src/ConstructionPlugin/ConstructionPlugin_Point.h +++ b/src/ConstructionPlugin/ConstructionPlugin_Point.h @@ -8,53 +8,104 @@ #define ConstructionPlugin_Point_H_ #include "ConstructionPlugin.h" + +#include #include #include -#include -/**\class ConstructionPlugin_Point - * \ingroup Plugins - * \brief Feature for creation of the new part in PartSet. - */ -class ConstructionPlugin_Point : public ModelAPI_Feature, public GeomAPI_ICustomPrs +/// \class ConstructionPlugin_Point +/// \ingroup Plugins +/// \brief Feature for creation of the new part in PartSet. +class ConstructionPlugin_Point: public ModelAPI_Feature, public GeomAPI_ICustomPrs { - public: - /// Returns the kind of a feature +public: + /// Returns the kind of a feature. CONSTRUCTIONPLUGIN_EXPORT virtual const std::string& getKind(); - /// Point kind + /// Point kind. inline static const std::string& ID() { static const std::string CONSTRUCTION_POINT_KIND("Point"); return CONSTRUCTION_POINT_KIND; } - /// attribute name for X coordinate + /// Attribute name for creation method. + inline static const std::string& CREATION_METHOD() + { + static const std::string MY_CREATION_METHOD_ID("creation_method"); + return MY_CREATION_METHOD_ID; + } + + /// Attribute name for creation method. + inline static const std::string& CREATION_METHOD_BY_XYZ() + { + static const std::string MY_CREATION_METHOD_ID("by_xyz"); + return MY_CREATION_METHOD_ID; + } + + /// Attribute name for creation method. + inline static const std::string& CREATION_METHOD_BY_DISTANCE_ON_EDGE() + { + static const std::string MY_CREATION_METHOD_ID("by_distance_on_edge"); + return MY_CREATION_METHOD_ID; + } + + /// Attribute name for X coordinate. inline static const std::string& X() { static const std::string POINT_ATTR_X("x"); return POINT_ATTR_X; } - /// attribute name for Y coordinate + + /// Attribute name for Y coordinate. inline static const std::string& Y() { static const std::string POINT_ATTR_Y("y"); return POINT_ATTR_Y; } - /// attribute name for Z coordinate + + /// Attribute name for Z coordinate. inline static const std::string& Z() { static const std::string POINT_ATTR_Z("z"); return POINT_ATTR_Z; } - /// Creates a new part document if needed + /// Attribute name for seleted edge. + inline static const std::string& EDGE() + { + static const std::string ATTR_ID("edge"); + return ATTR_ID; + } + + /// Attribute name for distance. + inline static const std::string& DISTANCE_VALUE() + { + static const std::string ATTR_ID("value"); + return ATTR_ID; + } + + /// Attribute name for percent flag. + inline static const std::string& DISTANCE_PERCENT() + { + static const std::string ATTR_ID("percent"); + return ATTR_ID; + } + + /// Attribute name for reverse flag. + inline static const std::string& REVERSE() + { + static const std::string ATTR_ID("reverse"); + return ATTR_ID; + } + + /// Creates a new part document if needed. CONSTRUCTIONPLUGIN_EXPORT virtual void execute(); - /// Request for initialization of data model of the feature: adding all attributes + /// Request for initialization of data model of the feature: adding all attributes. CONSTRUCTIONPLUGIN_EXPORT virtual void initAttributes(); - /// Construction result is allways recomuted on the fly + /// Construction result is allways recomuted on the fly. CONSTRUCTIONPLUGIN_EXPORT virtual bool isPersistentResult() {return false;} /// Use plugin manager for features creation @@ -63,6 +114,11 @@ class ConstructionPlugin_Point : public ModelAPI_Feature, public GeomAPI_ICustom /// Customize presentation of the feature virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs, std::shared_ptr theDefaultPrs); + +private: + std::shared_ptr createByXYZ(); + std::shared_ptr createByDistanceOnEdge(); + }; #endif diff --git a/src/ConstructionPlugin/Test/TestAxisCreation.py b/src/ConstructionPlugin/Test/TestAxisCreation.py index 34039691e..35885a872 100644 --- a/src/ConstructionPlugin/Test/TestAxisCreation.py +++ b/src/ConstructionPlugin/Test/TestAxisCreation.py @@ -26,6 +26,7 @@ aSession.startOperation() aPointFeature = aPart.addFeature("Point") aPointFeatureData = aPointFeature.data() assert(aPointFeatureData is not None) +aPointFeatureData.string("creation_method").setValue("by_xyz") aPointFeatureData.real("x").setValue(0.) aPointFeatureData.real("y").setValue(0.) aPointFeatureData.real("z").setValue(0.) @@ -40,6 +41,7 @@ aSession.startOperation() aPointFeature = aPart.addFeature("Point") aPointFeatureData = aPointFeature.data() assert(aPointFeatureData is not None) +aPointFeatureData.string("creation_method").setValue("by_xyz") aPointFeatureData.real("x").setValue(0.) aPointFeatureData.real("y").setValue(0.) aPointFeatureData.real("z").setValue(100.) diff --git a/src/ConstructionPlugin/Test/TestPointName.py b/src/ConstructionPlugin/Test/TestPointName.py index 43a942db0..274c931b2 100644 --- a/src/ConstructionPlugin/Test/TestPointName.py +++ b/src/ConstructionPlugin/Test/TestPointName.py @@ -7,6 +7,7 @@ aSession.startOperation() aFeature = aDoc.addFeature("Point") aFeatureData = aFeature.data() assert(aFeatureData is not None) +aFeatureData.string("creation_method").setValue("by_xyz") aFeatureData.real("x").setValue(0.) aFeatureData.real("y").setValue(0.) aFeatureData.real("z").setValue(0.) diff --git a/src/ConstructionPlugin/icons/distance_value.png b/src/ConstructionPlugin/icons/distance_value.png new file mode 100644 index 0000000000000000000000000000000000000000..b40da2e2d31b450d4705eeb4b35bac4572c5f97f GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGh)&Kwv)&Y=jd7JK}(#iL~v`gSWY1g2C67C`YB!O7Y$^W0CgU>%@pgIr+TJ{&D zQOnNbrzpq(MF-!1Dh}SW3~b!qiaQ7VGqrZfHL-Tdv$S+hwXkwd2eE-(D>SxtEi$)q z$yB%V`~!5sXP{Uc*abk-|AN8*EX5_fWhks zd={YduqniaL9UQ>^!?9Z;2(QeA~<2Qm}|fSQn097;6nMR%$E$nfcO9k4017pxQl<3 osB1t1xfrYeNWoYIiO2sL0HJ05`(L)YEdT%j07*qoM6N<$f=A}@_5c6? literal 0 HcmV?d00001 diff --git a/src/ConstructionPlugin/icons/edge.png b/src/ConstructionPlugin/icons/edge.png new file mode 100644 index 0000000000000000000000000000000000000000..53dbb08209ac7146945737f458421bba72069360 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4f%C91l5uNKibeP{t#q*Ko9uk%z7GxX%ZHx0BQk zTst1T-glqzopr0JVg2 Ah($7<5HgbW?9;ba!ELWdLwtX>N2bZe?^J zG%heMIczh2P5=M`JxN4CR9HvFm%UHhKp4hT#Lxi=kiZTbBLgD~5=c>UVM6#U1!iW% z0IXfIWvNuDOQ%XzX#qj_5HlM?w<59dAG8Z!5<`n9nCG$1^b%fUK5T>Zb9|5A^Y6W2 zCr%*%Wh^F$1@!clq>oPaa#GZPE5!pH-|88fjk3m`0le^vu0%*EogG4dlLzM>q| zcubs-CJ+sQ-+=Oc&}AQQDNdUtIcXWB$z$Z?UXTWmjac%HI5`o+mjKxqxUl4%QeA`? zCedH<#`~3C!^xW=6}{|E_`}$LlAMU)L%7O+=PIu;SekuXRC;Cr&GeLX4`e%N>aUS6 zKSoZ(Fb;?nPF#=1cqdlTPy<;F{Be{QI2G@!Jtqk#x&GuT z{n?(Agc!yF$@gM)Y8sM{1mj=eCX_3E;FkR|URR{KafqP={@&m%{)V@Bjw=U0uwse> z>>o1YHIZ2Z1Sj7t)axC1T`*!cuooTgRny&0Re!PPBq4@zV8t5jQf?af$%`;L&VNf^ zb!x<(lY|(?@qgv|8n@gMn0Lya&s!3Wy~ka$D9w8aF_eIqw;NY}1zE$X_*+=t?> z>Th5?D$Pqm4BLU^!=2oGj}u;)cHMIjLz_5xT8JTmtkaV7^F4fsOdByYa( literal 0 HcmV?d00001 diff --git a/src/ConstructionPlugin/icons/point_by_xyz_32x32.png b/src/ConstructionPlugin/icons/point_by_xyz_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..663ba954523caf22c2aec609b505995904bfc9fc GIT binary patch literal 1090 zcmV-I1ikx-P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGvt^fcVt^tf)bNB!N02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y1G7m)K~z{rwU^IJ6k!<0cU9B~QpwpLcIg;c zL?A^(Fz(D&2X$uD4Z4ZP=+Y&KF5aYwf-Z$11eJwpdWrslh>EUVIvFHXlu2c2VcYjR zzVGnvyYGy8 zdNFpI=yLqM5dJ6&081HXAZv=P2Vf`?HlQ53qb*WQ)>PS zv06Za1yHu^QcmrMr7;utGmdwjBPUpV3lM%QeXfZeD?r?vO^uB;NMHX6I^0qlX6vr> zNpw*Qw8R1&-v^hZuNT0dp|d#9BYhHGY=*R?0tiNU)pGpHsZyyC>*PYF;01goQP_37 zB^UMh3MUTL)B;3Tg)u(s1brDNc!Cj6BX$ORz+?Ew^}M92Lq|8Y0FbtN2OGt$$dqT( zYAzGTPKn9X0vLnoZh~J?gqlOV##7wT)P6}-ha}GQ0w@leL7MmVJm}{h!VQc2$dG=& z!ihQ)3?qJzL}~#IMBJ{*C4^Z(xOMX*#V@P8U-dweL9`VGdm+=Wd}zg&JPbCTDF{^8~u5%gH74^Xz2wkp+7v*B^nZN+BtG5&h~(~ z9cyw{iFigWU|K!OMTYm42hL{U#)<=c^)_BPld0kau`7TDEP{&D6A8_7z0+8g+%TSk zmZXuRty!G#tiS_{JT>X?6UmRp5Q_MPtGX@D4%fwIVFxPcjEugjSWA64nbw@AX0Crx4ZQPryGH z(c2--lx!>TAI~TRz6n8KzR(TLlxVB4fC-4;UG=`AU55V(%t8DnI0puV zZfK??+kp%47{qS?9GSf{IJOV literal 0 HcmV?d00001 diff --git a/src/ConstructionPlugin/icons/x_size.png b/src/ConstructionPlugin/icons/x_size.png new file mode 100644 index 0000000000000000000000000000000000000000..8f292c79ea75a6a99b29fbe22cb44cacb17279d6 GIT binary patch literal 519 zcmV+i0{H!jP)SQ0LIgD? zS{w@<1aXlLowB$%J2<&GiKAK-JNO5*9V&>_)lDZ81aVO$mwPVaa2JU8;J1AFywC5w zCw6M`n_whw4>p$wP>FPY4hUNyKNRh>Q~7uhfe6!pV*y=2M1+MP0>A~t0Xc{3;F&%xaa3`vd@Y z4^B7G`zD3KmVf`-s(YK1Ek z0w+L+Q!&=PyzhvrvTul9L_^Q>rSsJ?P;SX&#>9=RxWbi}e*w*Fncv&uFj4>j002ov JPDHLkV1i0c)-nJ9 literal 0 HcmV?d00001 diff --git a/src/ConstructionPlugin/icons/y_size.png b/src/ConstructionPlugin/icons/y_size.png new file mode 100644 index 0000000000000000000000000000000000000000..9d3e5f96206d874ad26f4ca0f58846f873f37c7e GIT binary patch literal 517 zcmV+g0{Z=lP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGh)&Kwv)&Y=jd7J{03-W(A@~<9?}p>YO@&l9j@xca%06wIN~qh z65^gO)v4vj1TGx$AQTjaGFnU4j2v7f#a>#>5dV~0s#20sAuczuT#vH627>0Mh!y@> z?O}h6oA-SYWmr^d9_D?aipX!Fvuui(1`yYPee6GhdtBU7SyI85w8&?Z7gV1l{tJZK zFfB@20iHMyg9o6BJ&U=H^EEDd#g`uAB#STD&;~e|sF#@kh*y4Yk(=-1T8WnHGEQ#gbhp}ga4n$n=oPyt+n?Le67GR{Cu`W00000NkvXX Hu0mjf25Z!Q literal 0 HcmV?d00001 diff --git a/src/ConstructionPlugin/icons/z_size.png b/src/ConstructionPlugin/icons/z_size.png new file mode 100644 index 0000000000000000000000000000000000000000..c1f108aaac19e04e93a20db8c34a1f4a490ed033 GIT binary patch literal 462 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=fts&@Fyn;$$~izmi4xa{lHmNblJdl&REC1Y%)Ao4ywnl}6Fmbx z%N*l6KcJ!Zo-U3d7XHZs#UJ~Hi#aXWkHk0p*tR3v;r9Rk|0O$)@;uUGWOeA(Z~S3@ zLO`M3h?$vL+3e^IgBb#)d|w)*HZbcs>KsUK*fCprd&lDWyH;dxShZsJ{H__n4V!k% zUcYEb@B|y@3=QK5K|kgOu7;W!*9|tT@IIi~#Kv$qSvBAdo4|dhN4FjRh;;mCH1v2I z^@nW%qu_Oi>IHwoJFNb{bWn8Lz+%YOvFqne#-|P!d4i0EHCQh4FtzXqlz!Xpn(=Ku ztB6wu8)FTd$By5YN+#?&!bKmZ2o~~B5-I*BoSu=9z@&XB(;-7cdcuEptv=S~!;Jlm z$BwN@I>-3Ek;|TG@tcV=vJWI1PCuaTV0ymchh~7kTpV-9(S#-?=7w2C4L<}0nuShO zE6n3K;&VeJ`LF`B!%o2$;TsswH_l*T{%6d^WQ Bs}TSI literal 0 HcmV?d00001 diff --git a/src/ConstructionPlugin/point_widget.xml b/src/ConstructionPlugin/point_widget.xml index 5ce9fe1fb..4557509f3 100644 --- a/src/ConstructionPlugin/point_widget.xml +++ b/src/ConstructionPlugin/point_widget.xml @@ -1,7 +1,53 @@ - - - + + + + + + + + + + + + + + + + + diff --git a/src/FeaturesPlugin/icons/dimension_up_32x32.png b/src/FeaturesPlugin/icons/dimension_up_32x32.png index 8b6ad7ce587466cddec83ea11e6a9ce260ea2e77..4b4c35fa3c719ef483716446237a3de7925b029d 100644 GIT binary patch delta 404 zcmV;F0c-x_1Fi#*B!2;OQb$4nuFf3k00004XF*Lt006O%3;baP00009a7bBm000}V z000}V0gPR9_y7O^7<5HgbW?9;ba!ELWdLwtX>N2bZe?^JG%heMIczh2P5=M_A4x<( zR9Hvt*FS5*Ko|z_Zgvx?xs-P4;0FohGB{{16nDQ>Cs&b9{eKD$f_@7Z!9OUaEu~P( z^$B<&@i}uyaPfv8%5!=1K5>dST5C$g*;q*RQGGH)PkAp<$Uos*zcK zP~w$cTZV?GV1LNK%vU0i%%(U845o3){#4HgUw3yJiF&Dzk= zMkH#2B`es#7JlIm`6oWV;2Ym(Y}ST`uCQ4ZSOhE1eR<=q&@Ckxm7sNZ%UOV4H-@ybQLXB9OfQ5yXt$$)I0Z%M6l_BQVLh%o| zOLB`L7WXT6ZhreQb2F@HtqGIuxDP-sG-x2dUdx7^t3EkdAoEuMQJNU_1%nh>0fD^$ z2`$?Xr3F2$k!Mo?iTVeIk?pt*ps3!ui_MF(Cle3j7FdqA1FQg6N2Lx-eT*t#m9`3^ zI=B3uk`2FJJAaPrWmExCoeI4pTAeGc&5j(vc03R8LPAzor7Cg#VznSwF6T3Cbpuj} z`bKNL`Peu;8rCyb1+wkQ{eG7Nh)8w5v^{8iztnFN_9%cCfh*7fNFG@D4BY|u2pUbR zHRY#)*I_)3_kg|Xt|QbwTx8cjKRGn<8T%?u01|)%AVL9101|+)11Q^Zi$E%NrjQr7 z20#ZH+i{nS0Dwzi#w7XsB_Ycu`S1@~kN~^`r6f`8NttNb00000NkvXXu0mjf1%S6H diff --git a/src/FeaturesPlugin/icons/dimension_up_down_32x32.png b/src/FeaturesPlugin/icons/dimension_up_down_32x32.png index adee89f65f9f7e8988a05d3c9d355d0d631d2088..b081893cdad1b7b983bc32a22e28fd89def52b93 100644 GIT binary patch delta 459 zcmV;+0W|*f1g`{;Zhx#vL_t(oh3%F-O9Md=hM!3e5=bYKvlW|^Rw7slIW0u=#9mT~ zm7o@aUH*WGm5o@~DISU-CWyTVwidRE(STpX7&W&RIU$A^+*L_)Q|-*|yz{cNGdrS` z!c=U>%>uo^SRwBj0Y!chydPKsMu8bq95J~8+i~N-8ITH0C4Zo|koPWhu}p6uTNfN4 z0c_ZgtBt4a5M2FyldS<@;ok`W>n;4Uw&V8bfLS_+ZO65Mec%`nYLBl9tN?zne$&A; zdV~PogPHiVbzcT5g}fIx0^t{B_*W7V2nk3sJsxYYHI_wFJyuP`E78&uP@&cdf8^iz zX-P6Yeht_#d7G*>8GjL_WU+X-eg5wR07R7d)4+Y5>FD;zTQ$KlB5<4A zy;7*TKz*!ms!T#8k4yY^R~o=rj}*qmZm@Ap0_VdV@D@0;PToL(eu<_BQ|)tU9vTAJ~t> z9WZkX{sZikb%9`+D8eySZjW9c0m~*G>y>Qr)ZmP$yaZ5{r7tTl?pbuqEf8d~`&CkR zrp3+(;P>X!+!g;Bz(%72N>zHQPONC6^I;yC2Wmm)#((|_b~zt9KwWx0FTIkz0gnGA z>?_dADgJ1qS=xe?7BR2eCbt0G0p3p;U#0LTr3fIW_#LKM zw476XR;p+H3~vI>m97F8EkY)MoZ>g&O2c(Mr}){TWj+f4oDYwIeL2PRR*j!40G2BK Ti%j1D015yANkvXXu0mjf&9V2q diff --git a/src/GeomAPI/GeomAPI_Edge.cpp b/src/GeomAPI/GeomAPI_Edge.cpp index 594829f8c..84f63b17f 100644 --- a/src/GeomAPI/GeomAPI_Edge.cpp +++ b/src/GeomAPI/GeomAPI_Edge.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include @@ -23,6 +25,8 @@ #include #include +#include + GeomAPI_Edge::GeomAPI_Edge() { TopoDS_Edge* anEdge = new TopoDS_Edge; @@ -219,3 +223,9 @@ bool GeomAPI_Edge::isInPlane(std::shared_ptr thePlane) const } return inPlane; } + +double GeomAPI_Edge::length() const +{ + const TopoDS_Edge& anEdge = TopoDS::Edge(impl()); + return GCPnts_AbscissaPoint::Length(BRepAdaptor_Curve(anEdge)); +} diff --git a/src/GeomAPI/GeomAPI_Edge.h b/src/GeomAPI/GeomAPI_Edge.h index e4dfcf2a8..afe8243ea 100644 --- a/src/GeomAPI/GeomAPI_Edge.h +++ b/src/GeomAPI/GeomAPI_Edge.h @@ -69,6 +69,10 @@ public: /// Returns true, if the edge is fully placed in the specified plane GEOMAPI_EXPORT bool isInPlane(const std::shared_ptr thePlane) const; + + /// Returns edge length. + GEOMAPI_EXPORT + double length() const; }; #endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index f1c9569aa..029743117 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -23,12 +23,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -665,3 +667,46 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr theE BRepExtrema_ExtCF anExt(anEdge, aFace); return anExt.IsParallel() == Standard_True; } + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::findVertexOnEdge(const std::shared_ptr theEdge, + const double theValue, + const bool theIsPercent, + const bool theIsReverse) +{ + std::shared_ptr aVertex; + + if(!theEdge.get()) { + return aVertex; + } + + double aValue = theValue; + if(theIsPercent) { + aValue = theEdge->length() / 100.0 * aValue; + } + + const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge->impl()); + Standard_Real aUFirst, aULast; + Handle(Geom_Curve) anEdgeCurve = BRep_Tool::Curve(anEdge, aUFirst, aULast); + + if(!anEdgeCurve.IsNull() ) { + Handle(Geom_Curve) aReOrientedCurve = anEdgeCurve; + + if(theIsReverse) { + aReOrientedCurve = anEdgeCurve->Reversed(); + aUFirst = anEdgeCurve->ReversedParameter(aULast); + } + + // Get the point by length + GeomAdaptor_Curve anAdapCurve = GeomAdaptor_Curve(aReOrientedCurve); + GCPnts_AbscissaPoint anAbsPnt(anAdapCurve, aValue, aUFirst); + Standard_Real aParam = anAbsPnt.Parameter(); + gp_Pnt aPnt = anAdapCurve.Value(aParam); + BRepBuilderAPI_MakeVertex aMkVertex(aPnt); + const TopoDS_Vertex& aShape = aMkVertex.Vertex(); + aVertex.reset(new GeomAPI_Vertex()); + aVertex->setImpl(new TopoDS_Vertex(aShape)); + } + + return aVertex; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h index 01b1e7366..f1814c750 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h @@ -103,6 +103,17 @@ public: GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr theEdge, const std::shared_ptr theFace); + /// \brief Creates vertex by edge and distance on it. + /// \param[in] theEdge edge. + /// \param[in] theValue distance value. + /// \param[in] theIsPercent if true theValue will be treated as a percentage of theEdge total length. + /// \param[in] theIsReverse if true the distance will be measured from the edge end point. + /// \ return created vertex. + GEOMALGOAPI_EXPORT static std::shared_ptr findVertexOnEdge(const std::shared_ptr theEdge, + const double theValue, + const bool theIsPercent = false, + const bool theIsReverse = false); + }; #endif diff --git a/src/GeomValidators/GeomValidators_Finite.cpp b/src/GeomValidators/GeomValidators_Finite.cpp index 6668b8bba..67f8d70c9 100755 --- a/src/GeomValidators/GeomValidators_Finite.cpp +++ b/src/GeomValidators/GeomValidators_Finite.cpp @@ -17,7 +17,17 @@ bool GeomValidators_Finite::isValid(const AttributePtr& theAttribute, { bool aValid = true; - if (theAttribute->attributeType() == ModelAPI_AttributeSelectionList::typeId()) { + const std::string anAttributeType = theAttribute->attributeType(); + + if(anAttributeType == ModelAPI_AttributeSelection::typeId()) { + AttributeSelectionPtr aSelectionAttr = std::dynamic_pointer_cast(theAttribute); + ResultPtr aResult = aSelectionAttr->context(); + ResultConstructionPtr aConstruction = std::dynamic_pointer_cast(aResult); + if (aConstruction.get() && aConstruction->isInfinite()) { + aValid = false; + theError = "Infinite result is selected."; + } + } else if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) { AttributeSelectionListPtr aSelectionListAttr = std::dynamic_pointer_cast(theAttribute); for (int i = 0, aSize = aSelectionListAttr->size(); i < aSize; i++) { diff --git a/src/InitializationPlugin/InitializationPlugin_Plugin.cpp b/src/InitializationPlugin/InitializationPlugin_Plugin.cpp index 0c47e2a52..cdfe868ac 100644 --- a/src/InitializationPlugin/InitializationPlugin_Plugin.cpp +++ b/src/InitializationPlugin/InitializationPlugin_Plugin.cpp @@ -119,6 +119,7 @@ FeaturePtr InitializationPlugin_Plugin::createPoint(DocumentPtr theDoc, const st double theX, double theY, double theZ) { std::shared_ptr aPoint = theDoc->addFeature("Point"); + aPoint->string("creation_method")->setValue("by_xyz"); aPoint->real("x")->setValue(theX); aPoint->real("y")->setValue(theY); aPoint->real("z")->setValue(theZ); diff --git a/src/ModelAPI/Test/TestUndoRedo.py b/src/ModelAPI/Test/TestUndoRedo.py index 1df119f97..b9701a1b9 100644 --- a/src/ModelAPI/Test/TestUndoRedo.py +++ b/src/ModelAPI/Test/TestUndoRedo.py @@ -8,6 +8,7 @@ aSession.startOperation() aFeature = aDoc.addFeature("Point") # Since validators are introduced we have to initialize all # the feature's attributes +aFeature.string("creation_method").setValue("by_xyz") aFeature.real("x").setValue(1.) aFeature.real("y").setValue(-1.) aFeature.real("z").setValue(0.) diff --git a/src/SketchPlugin/Test/TestConstraintCoincidence.py b/src/SketchPlugin/Test/TestConstraintCoincidence.py index a0a7bc3cc..c7ba672da 100644 --- a/src/SketchPlugin/Test/TestConstraintCoincidence.py +++ b/src/SketchPlugin/Test/TestConstraintCoincidence.py @@ -1,7 +1,7 @@ """ TestConstraintCoincidence.py Unit test of SketchPlugin_ConstraintCoincidence class - + SketchPlugin_Constraint static const std::string MY_CONSTRAINT_VALUE("ConstraintValue"); static const std::string MY_FLYOUT_VALUE_PNT("ConstraintFlyoutValuePnt"); @@ -9,7 +9,7 @@ static const std::string MY_ENTITY_B("ConstraintEntityB"); static const std::string MY_ENTITY_C("ConstraintEntityC"); static const std::string MY_ENTITY_D("ConstraintEntityD"); - + SketchPlugin_ConstraintCoincidence static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidence"); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); @@ -61,6 +61,7 @@ aDocument = aSession.moduleDocument() # add an origin aSession.startOperation() aFeature = aDocument.addFeature("Point") +aFeature.string("creation_method").setValue("by_xyz") aFeature.real("x").setValue(0.) aFeature.real("y").setValue(0.) aFeature.real("z").setValue(0.) diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py index 09506082b..42e213893 100644 --- a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py +++ b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py @@ -1,7 +1,7 @@ """ TestConstraintCoincidence.py Unit test of SketchPlugin_ConstraintCoincidence class - + SketchPlugin_Constraint static const std::string MY_CONSTRAINT_VALUE("ConstraintValue"); static const std::string MY_FLYOUT_VALUE_PNT("ConstraintFlyoutValuePnt"); @@ -9,7 +9,7 @@ static const std::string MY_ENTITY_B("ConstraintEntityB"); static const std::string MY_ENTITY_C("ConstraintEntityC"); static const std::string MY_ENTITY_D("ConstraintEntityD"); - + SketchPlugin_ConstraintCoincidence static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidence"); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); @@ -45,6 +45,7 @@ aDocument = aSession.moduleDocument() # add an origin aSession.startOperation() aFeature = aDocument.addFeature("Point") +aFeature.string("creation_method").setValue("by_xyz") aFeature.real("x").setValue(0.) aFeature.real("y").setValue(0.) aFeature.real("z").setValue(0.) -- 2.39.2