From 2e9b24400c6194f045ae581a77bc2a49e6626fe0 Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 3 Sep 2018 13:19:51 +0300 Subject: [PATCH] =?utf8?q?Issue=202556:=20Functionality=20of=20inspection?= =?utf8?q?=20=E2=80=9CWhatIs=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Unit tests for the inspection functionality. --- src/GeomAPI/CMakeLists.txt | 10 ++ src/GeomAPI/GeomAPI.i | 67 ++++++++-- src/GeomAPI/GeomAPI_Cone.cpp | 14 +- src/GeomAPI/GeomAPI_Face.cpp | 10 +- src/GeomAPI/GeomAPI_Pnt.cpp | 14 ++ src/GeomAPI/GeomAPI_Pnt.h | 7 + src/GeomAPI/GeomAPI_Shell.cpp | 40 ++++-- src/GeomAPI/GeomAPI_Solid.cpp | 4 +- src/GeomAPI/GeomAPI_Wire.cpp | 2 + src/GeomAPI/GeomAPI_swig.h | 8 +- src/GeomAPI/Test/TestBox.py | 165 +++++++++++++++++++++++ src/GeomAPI/Test/TestCone.py | 221 +++++++++++++++++++++++++++++++ src/GeomAPI/Test/TestCylinder.py | 149 +++++++++++++++++++++ src/GeomAPI/Test/TestPolygon.py | 102 ++++++++++++++ src/GeomAPI/Test/TestSphere.py | 125 +++++++++++++++++ src/GeomAPI/Test/TestTorus.py | 95 +++++++++++++ 16 files changed, 999 insertions(+), 34 deletions(-) create mode 100644 src/GeomAPI/Test/TestBox.py create mode 100644 src/GeomAPI/Test/TestCone.py create mode 100644 src/GeomAPI/Test/TestCylinder.py create mode 100644 src/GeomAPI/Test/TestPolygon.py create mode 100644 src/GeomAPI/Test/TestSphere.py create mode 100644 src/GeomAPI/Test/TestTorus.py diff --git a/src/GeomAPI/CMakeLists.txt b/src/GeomAPI/CMakeLists.txt index 82b062a0c..4959dde28 100644 --- a/src/GeomAPI/CMakeLists.txt +++ b/src/GeomAPI/CMakeLists.txt @@ -22,6 +22,7 @@ FIND_PACKAGE(SWIG REQUIRED) INCLUDE(${SWIG_USE_FILE}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE(UnitTest) SET(PROJECT_HEADERS GeomAPI.h @@ -157,3 +158,12 @@ ENDIF(WIN32) INSTALL(TARGETS _GeomAPI DESTINATION ${SHAPER_INSTALL_SWIG}) INSTALL(TARGETS GeomAPI DESTINATION ${SHAPER_INSTALL_BIN}) INSTALL(FILES ${SWIG_SCRIPTS} DESTINATION ${SHAPER_INSTALL_SWIG}) + +ADD_UNIT_TESTS( + TestBox.py + TestCone.py + TestCylinder.py + TestPolygon.py + TestSphere.py + TestTorus.py +) diff --git a/src/GeomAPI/GeomAPI.i b/src/GeomAPI/GeomAPI.i index 82e292108..aa2648245 100644 --- a/src/GeomAPI/GeomAPI.i +++ b/src/GeomAPI/GeomAPI.i @@ -29,22 +29,30 @@ // standard definitions %include "typemaps.i" +%include "std_list.i" %include "std_string.i" %include "std_shared_ptr.i" // shared pointers %shared_ptr(GeomAPI_AISObject) +%shared_ptr(GeomAPI_Angle) +%shared_ptr(GeomAPI_Angle2d) %shared_ptr(GeomAPI_Ax1) %shared_ptr(GeomAPI_Ax2) %shared_ptr(GeomAPI_Ax3) +%shared_ptr(GeomAPI_Box) %shared_ptr(GeomAPI_Circ) %shared_ptr(GeomAPI_Circ2d) +%shared_ptr(GeomAPI_Cone) %shared_ptr(GeomAPI_Curve) +%shared_ptr(GeomAPI_Cylinder) %shared_ptr(GeomAPI_DataMapOfShapeMapOfShapes) %shared_ptr(GeomAPI_DataMapOfShapeShape) %shared_ptr(GeomAPI_Dir) %shared_ptr(GeomAPI_Dir2d) %shared_ptr(GeomAPI_Edge) +%shared_ptr(GeomAPI_Ellipse) +%shared_ptr(GeomAPI_Ellipse2d) %shared_ptr(GeomAPI_Face) %shared_ptr(GeomAPI_ICustomPrs) %shared_ptr(GeomAPI_Interface) @@ -58,31 +66,65 @@ %shared_ptr(GeomAPI_Shape) %shared_ptr(GeomAPI_ShapeExplorer) %shared_ptr(GeomAPI_ShapeIterator) +%shared_ptr(GeomAPI_Shell) +%shared_ptr(GeomAPI_Solid) +%shared_ptr(GeomAPI_Sphere) +%shared_ptr(GeomAPI_Torus) +%shared_ptr(GeomAPI_Trsf) %shared_ptr(GeomAPI_Vertex) +%shared_ptr(GeomAPI_Wire) %shared_ptr(GeomAPI_XY) %shared_ptr(GeomAPI_XYZ) -%shared_ptr(GeomAPI_Trsf) -%shared_ptr(GeomAPI_Wire) -%shared_ptr(GeomAPI_Shell) -%shared_ptr(GeomAPI_Solid) -%shared_ptr(GeomAPI_Box) + + +%typemap(in) std::list > &thePoints (std::list > temp) { + std::shared_ptr * temp_pnt; + int newmem = 0; + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject * item = PySequence_GetItem($input, i); + if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pnt, $descriptor(std::shared_ptr *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) { + if (!temp_pnt) { + PyErr_SetString(PyExc_TypeError, "argument must be list of GeomAPI_Pnt."); + return NULL; + } + temp.push_back(*temp_pnt); + if (newmem & SWIG_CAST_NEW_MEMORY) { + delete temp_pnt; + } + } + Py_DECREF(item); + } + $1 = &temp; + } else { + PyErr_SetString(PyExc_ValueError, "argument must be list of GeomAPI_Pnt."); + return NULL; + } +} // all supported interfaces %include "GeomAPI_Interface.h" %include "GeomAPI_Shape.h" %include "GeomAPI_AISObject.h" +%include "GeomAPI_Angle.h" +%include "GeomAPI_Angle2d.h" %include "GeomAPI_Ax1.h" %include "GeomAPI_Ax2.h" %include "GeomAPI_Ax3.h" +%include "GeomAPI_Box.h" %include "GeomAPI_Circ.h" %include "GeomAPI_Circ2d.h" +%include "GeomAPI_Cone.h" %include "GeomAPI_Curve.h" +%include "GeomAPI_Cylinder.h" %include "GeomAPI_DataMapOfShapeMapOfShapes.h" %include "GeomAPI_DataMapOfShapeShape.h" %include "GeomAPI_Dir.h" %include "GeomAPI_Dir2d.h" %include "GeomAPI_Edge.h" +%include "GeomAPI_Ellipse.h" +%include "GeomAPI_Ellipse2d.h" %include "GeomAPI_Face.h" %include "GeomAPI_ICustomPrs.h" %include "GeomAPI_IPresentable.h" @@ -94,11 +136,16 @@ %include "GeomAPI_Pnt2d.h" %include "GeomAPI_ShapeExplorer.h" %include "GeomAPI_ShapeIterator.h" +%include "GeomAPI_Shell.h" +%include "GeomAPI_Solid.h" +%include "GeomAPI_Sphere.h" +%include "GeomAPI_Torus.h" +%include "GeomAPI_Trsf.h" %include "GeomAPI_Vertex.h" +%include "GeomAPI_Wire.h" %include "GeomAPI_XY.h" %include "GeomAPI_XYZ.h" -%include "GeomAPI_Trsf.h" -%include "GeomAPI_Wire.h" -%include "GeomAPI_Shell.h" -%include "GeomAPI_Solid.h" -%include "GeomAPI_Box.h" + +// std::list -> [] +%template(PointList) std::list >; +%template(ShapeList) std::list >; diff --git a/src/GeomAPI/GeomAPI_Cone.cpp b/src/GeomAPI/GeomAPI_Cone.cpp index e18d4d333..c8344c3ac 100644 --- a/src/GeomAPI/GeomAPI_Cone.cpp +++ b/src/GeomAPI/GeomAPI_Cone.cpp @@ -61,11 +61,19 @@ GeomAPI_Cone::GeomAPI_Cone(const std::shared_ptr& theLocation, const double theSemiAngle, const double theRadius1, const double theRadius2) - : GeomAPI_Interface( - newCone(theLocation->impl(), theAxis->impl(), theSemiAngle, theRadius1)), - myRadius1(theRadius1), + : myRadius1(theRadius1), myRadius2(theRadius2) { + gp_Pnt aLoc = theLocation->impl(); + gp_Dir aDir = theAxis->impl(); + if (theRadius1 > theRadius2) { + aLoc.ChangeCoord() += aDir.XYZ() * (theRadius1 - theRadius2) / Tan(theSemiAngle); + aDir.Reverse(); + myRadius1 = theRadius2; + myRadius2 = theRadius1; + } + + setImpl(newCone(aLoc, aDir, theSemiAngle, myRadius1)); } //================================================================================================= diff --git a/src/GeomAPI/GeomAPI_Face.cpp b/src/GeomAPI/GeomAPI_Face.cpp index ff5dbba27..8e8a03655 100644 --- a/src/GeomAPI/GeomAPI_Face.cpp +++ b/src/GeomAPI/GeomAPI_Face.cpp @@ -196,15 +196,17 @@ std::shared_ptr GeomAPI_Face::getCone() const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); if (aSurf->IsKind(STANDARD_TYPE(Geom_ConicalSurface))) { gp_Cone aCon = Handle(Geom_ConicalSurface)::DownCast(aSurf)->Cone(); - const gp_Pnt& aLoc = aCon.Location(); - const gp_Dir& aDir = aCon.Position().Direction(); - double aRadius1 = aCon.RefRadius(); + gp_Pnt aLoc = aCon.Location(); + gp_Dir aDir = aCon.Position().Direction(); double aUMin, aUMax, aVMin, aVMax; BRepTools::UVBounds(aFace, aUMin, aUMax, aVMin, aVMax); double aSemiAngle = Abs(aCon.SemiAngle()); - double aRadius2 = aRadius1 - (aVMax - aVMin) * Sin(aSemiAngle); + double aRadius1 = aCon.RefRadius() + aVMin * Sin(aCon.SemiAngle()); + double aRadius2 = aCon.RefRadius() + aVMax * Sin(aCon.SemiAngle()); + + aLoc.ChangeCoord() += aDir.XYZ() * aVMin * Cos(aCon.SemiAngle()); GeomPointPtr aLocation(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z())); GeomDirPtr aDirection(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z())); diff --git a/src/GeomAPI/GeomAPI_Pnt.cpp b/src/GeomAPI/GeomAPI_Pnt.cpp index 976d3949f..97d66fc6e 100644 --- a/src/GeomAPI/GeomAPI_Pnt.cpp +++ b/src/GeomAPI/GeomAPI_Pnt.cpp @@ -85,6 +85,20 @@ bool GeomAPI_Pnt::isEqual(const std::shared_ptr& theOther) const return distance(theOther) < Precision::Confusion(); } +bool GeomAPI_Pnt::isLess(const std::shared_ptr& theOther) const +{ + if (MY_PNT->X() + Precision::Confusion() < theOther->x()) + return true; + else if (MY_PNT->X() < theOther->x() + Precision::Confusion()) { + if (MY_PNT->Y() + Precision::Confusion() < theOther->y()) + return true; + else if (MY_PNT->Y() < theOther->y() + Precision::Confusion() && + MY_PNT->Z() + Precision::Confusion() < theOther->z()) + return true; + } + return false; +} + std::shared_ptr GeomAPI_Pnt::to2D(const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, const std::shared_ptr& theDirY) { diff --git a/src/GeomAPI/GeomAPI_Pnt.h b/src/GeomAPI/GeomAPI_Pnt.h index 333a2350a..d06d5d9fb 100644 --- a/src/GeomAPI/GeomAPI_Pnt.h +++ b/src/GeomAPI/GeomAPI_Pnt.h @@ -76,6 +76,13 @@ class GeomAPI_Pnt : public GeomAPI_Interface GEOMAPI_EXPORT bool isEqual(const std::shared_ptr& theOther) const; + /// Returns \c true, if the current point is less than theOther. + /// The point is less than other, if X coordinate is less. + /// In case of X's are equal, if Y is less than other. + /// If Y's are equal too, compare Z's. + GEOMAPI_EXPORT + bool isLess(const std::shared_ptr& theOther) const; + /// Projects a point to the plane defined by the origin and 2 axes vectors in this plane GEOMAPI_EXPORT std::shared_ptr to2D(const std::shared_ptr& theOrigin, diff --git a/src/GeomAPI/GeomAPI_Shell.cpp b/src/GeomAPI/GeomAPI_Shell.cpp index baab4a1a9..ae5e12ae9 100644 --- a/src/GeomAPI/GeomAPI_Shell.cpp +++ b/src/GeomAPI/GeomAPI_Shell.cpp @@ -176,7 +176,7 @@ std::shared_ptr GeomAPI_Shell::getCone() const GeomPointPtr anApex; GeomDirPtr anAxis; - double aSemiAngle, aCosSemiAngle; + double aSemiAngle, aTanSemiAngle; double aHeight1, aHeight2; for (TopExp_Explorer anExp(impl(), TopAbs_FACE); anExp.More(); anExp.Next()) { @@ -193,9 +193,9 @@ std::shared_ptr GeomAPI_Shell::getCone() const anApex = aCurCone->apex(); anAxis = aCurCone->axis(); aSemiAngle = aCurCone->semiAngle(); - aCosSemiAngle = Cos(aSemiAngle); - aHeight1 = aCurCone->radius1() * aCosSemiAngle; - aHeight2 = aCurCone->radius2() * aCosSemiAngle; + aTanSemiAngle = Tan(aSemiAngle); + aHeight1 = aCurCone->radius1() / aTanSemiAngle; + aHeight2 = aCurCone->radius2() / aTanSemiAngle; isFirstFace = false; } else { @@ -211,15 +211,15 @@ std::shared_ptr GeomAPI_Shell::getCone() const double aSign = anAxis->dot(aCurCone->axis()); double aCurSemiAngle = aCurCone->semiAngle(); - double aCosCurSemiAngle = Cos(aSemiAngle); + double aTanCurSemiAngle = Tan(aSemiAngle); - double aH = aCurCone->radius1() * aCosCurSemiAngle * aSign; + double aH = aCurCone->radius1() / aTanCurSemiAngle * aSign; if (aH < aHeight1) aHeight1 = aH; else if (aH > aHeight2) aHeight2 = aH; - aH = aCurCone->radius2() * aCosCurSemiAngle * aSign; + aH = aCurCone->radius2() / aTanCurSemiAngle * aSign; if (aH < aHeight1) aHeight1 = aH; else if (aH > aHeight2) @@ -231,8 +231,8 @@ std::shared_ptr GeomAPI_Shell::getCone() const if (isCone) { GeomPointPtr aLocation(new GeomAPI_Pnt( anApex->xyz()->added(anAxis->xyz()->multiplied(aHeight1)))); - double aRadius1 = aHeight1 * Tan(aSemiAngle); - double aRadius2 = aHeight2 * Tan(aSemiAngle); + double aRadius1 = aHeight1 * aTanSemiAngle; + double aRadius2 = aHeight2 * aTanSemiAngle; aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aRadius1, aRadius2)); } @@ -298,11 +298,25 @@ std::shared_ptr GeomAPI_Shell::getParallelepiped() const std::list aCorners; if (aWire->isRectangle(aCorners)) { // convert rectangle to plane with dimensions - GeomPointPtr anOrigin = aCorners.front(); - aCorners.pop_front(); - GeomPointPtr aFront = aCorners.front(); - GeomPointPtr aBack = aCorners.back(); + // find corner with the smallest coordinates + std::list::const_iterator aPrev = --aCorners.end(); + std::list::const_iterator aCur = aPrev--; + std::list::const_iterator aNext = aCorners.begin(); + GeomPointPtr anOrigin = *aCur; + GeomPointPtr aFront = *aNext; + GeomPointPtr aBack = *aPrev; + aPrev = aCur; + aCur = aNext++; + while (aNext != aCorners.end()) { + if ((*aCur)->isLess(anOrigin)) { + anOrigin = *aCur; + aFront = *aNext; + aBack = *aPrev; + } + aPrev = aCur; + aCur = aNext++; + } aPlanes[aNbPlanes].myWidth = aBack->distance(anOrigin); aPlanes[aNbPlanes].myDepth = aFront->distance(anOrigin); diff --git a/src/GeomAPI/GeomAPI_Solid.cpp b/src/GeomAPI/GeomAPI_Solid.cpp index f128d3d65..8ac3a3862 100644 --- a/src/GeomAPI/GeomAPI_Solid.cpp +++ b/src/GeomAPI/GeomAPI_Solid.cpp @@ -273,8 +273,8 @@ std::shared_ptr GeomAPI_Solid::getCone() const anApex->z() + aParam0 * anAxis->z())); // calculate radii of caps - aParam0 /= Cos(aSemiAngle); - aParam1 /= Cos(aSemiAngle); + aParam0 *= Tan(aSemiAngle); + aParam1 *= Tan(aSemiAngle); aCone = GeomConePtr(new GeomAPI_Cone(aLocation, anAxis, aSemiAngle, aParam0, aParam1)); } diff --git a/src/GeomAPI/GeomAPI_Wire.cpp b/src/GeomAPI/GeomAPI_Wire.cpp index bcbaf3e94..65729cbf7 100644 --- a/src/GeomAPI/GeomAPI_Wire.cpp +++ b/src/GeomAPI/GeomAPI_Wire.cpp @@ -81,6 +81,8 @@ bool GeomAPI_Wire::isPolygon(std::list& thePoints) const //================================================================================================== bool GeomAPI_Wire::isRectangle(std::list& thePoints) const { + thePoints.clear(); + const TopoDS_Wire& aWire = TopoDS::Wire(impl()); const Handle(Standard_Type)& aLineType = STANDARD_TYPE(Geom_Line); diff --git a/src/GeomAPI/GeomAPI_swig.h b/src/GeomAPI/GeomAPI_swig.h index a7712b0ed..e92af5fba 100644 --- a/src/GeomAPI/GeomAPI_swig.h +++ b/src/GeomAPI/GeomAPI_swig.h @@ -23,6 +23,8 @@ #include "GeomAPI.h" #include "GeomAPI_AISObject.h" + #include "GeomAPI_Angle.h" + #include "GeomAPI_Angle2d.h" #include "GeomAPI_Ax1.h" #include "GeomAPI_Ax2.h" #include "GeomAPI_Ax3.h" @@ -37,6 +39,8 @@ #include "GeomAPI_Dir.h" #include "GeomAPI_Dir2d.h" #include "GeomAPI_Edge.h" + #include "GeomAPI_Ellipse.h" + #include "GeomAPI_Ellipse2d.h" #include "GeomAPI_Face.h" #include "GeomAPI_ICustomPrs.h" #include "GeomAPI_Interface.h" @@ -54,11 +58,11 @@ #include "GeomAPI_Solid.h" #include "GeomAPI_Sphere.h" #include "GeomAPI_Torus.h" + #include "GeomAPI_Trsf.h" #include "GeomAPI_Vertex.h" + #include "GeomAPI_Wire.h" #include "GeomAPI_XY.h" #include "GeomAPI_XYZ.h" - #include "GeomAPI_Trsf.h" - #include "GeomAPI_Wire.h" #include #include diff --git a/src/GeomAPI/Test/TestBox.py b/src/GeomAPI/Test/TestBox.py new file mode 100644 index 000000000..a8412a4cd --- /dev/null +++ b/src/GeomAPI/Test/TestBox.py @@ -0,0 +1,165 @@ +## 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 +## + +from GeomAPI import * +from SketchAPI import * + +from salome.shaper import model + +import math + +TOLERANCE = 1.e-7 + +def checkBox(theFeature, theCorner, theWidth, theDepth, theHeight): + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + aBox = aShape.solid().getParallelepiped() + assert(aBox is not None) + assert(aBox.isAxesAligned()) + aCorner = aBox.corner() + assert(aCorner.distance(theCorner) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(aCorner.x(), aCorner.y(), aCorner.z(), theCorner.x(), theCorner.y(), theCorner.z()) + assert(math.fabs(aBox.width() - theWidth) < TOLERANCE), "Width {} != {}".format(aBox.width(), theWidth) + assert(math.fabs(aBox.depth() - theDepth) < TOLERANCE), "Depth {} != {}".format(aBox.depth(), theDepth) + assert(math.fabs(aBox.height() - theHeight) < TOLERANCE), "Height {} != {}".format(aBox.height(), theHeight) + +def assertParallelepiped(theBox, theCorner1, theCorner2): + assert(theBox is not None) + assert(theBox.isAxesAligned() == False) + aCorner1 = theBox.corner() + axes = theBox.axes() + dirX = axes.dirX() + dirY = axes.dirY() + dirZ = axes.normal() + aCorner2 = GeomAPI.GeomAPI_Pnt(aCorner1.x() + dirX.x() * theBox.width() + dirY.x() * theBox.depth() + dirZ.x() * theBox.height(), + aCorner1.y() + dirX.y() * theBox.width() + dirY.y() * theBox.depth() + dirZ.y() * theBox.height(), + aCorner1.z() + dirX.z() * theBox.width() + dirY.z() * theBox.depth() + dirZ.z() * theBox.height()) + assert(aCorner1.distance(theCorner1) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(aCorner1.x(), aCorner1.y(), aCorner1.z(), theCorner1.x(), theCorner1.y(), theCorner1.z()) + assert(aCorner2.distance(theCorner2) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(aCorner2.x(), aCorner2.y(), aCorner2.z(), theCorner2.x(), theCorner2.y(), theCorner2.z()) + +def checkRotatedBox(theFeature, theCorner1, theCorner2): + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + aBox = aShape.solid().getParallelepiped() + assertParallelepiped(aBox, theCorner1, theCorner2) + +def checkShellRotatedBox(theDocument, theFaceNames, theCorner1, theCorner2): + aSelection = [] + for name in theFaceNames: + aSelection.append(model.selection("FACE", name)) + aShell = model.addShell(theDocument, aSelection) + aShape = aShell.result().resultSubShapePair()[0].shape() + assert(aShape.isShell()) + assertParallelepiped(aShape.shell().getParallelepiped(), theCorner1, theCorner2) + theDocument.removeFeature(aShell.feature()) + +def checkShellNotBox(theDocument, theFaceNames): + aSelection = [] + for name in theFaceNames: + aSelection.append(model.selection("FACE", name)) + aShell = model.addShell(theDocument, aSelection) + aShape = aShell.result().resultSubShapePair()[0].shape() + assert(aShape.isShell()) + assert(aShape.shell().getParallelepiped() is None) + theDocument.removeFeature(aShell.feature()) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +ParamSize = model.addParameter(Part_1_doc, "BoxSize", "10") +ParamWidth = model.addParameter(Part_1_doc, "Width", "20") +ParamDepth = model.addParameter(Part_1_doc, "Depth", "10") +ParamHeight = model.addParameter(Part_1_doc, "Height", "25") +ParamAngle = model.addParameter(Part_1_doc, "Angle", "30") +Box_1 = model.addBox(Part_1_doc, "BoxSize", "BoxSize", "BoxSize") +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Box_1_1/Top")) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Box_1_1/Front&Box_1_1/Right&Box_1_1/Top"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchLine_1 = Sketch_1.addLine(30, 10, 10, 10) +SketchLine_2 = Sketch_1.addLine(10, 10, 10, 20) +SketchLine_3 = Sketch_1.addLine(10, 20, 30, 20) +SketchLine_4 = Sketch_1.addLine(30, 20, 30, 10) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchPoint_1.result()) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint()) +SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result()) +SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result()) +SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result()) +SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), "Width") +SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), "Depth") +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2r-SketchLine_3r-SketchLine_4r")], model.selection(), "Height", 0) +model.do() + +# Test 1. Check boxes +aCornerBox = GeomAPI.GeomAPI_Pnt(0, 0, 0) +checkBox(Box_1, aCornerBox, ParamSize.value(), ParamSize.value(), ParamSize.value()) +aCornerPara = GeomAPI.GeomAPI_Pnt(ParamSize.value(), ParamSize.value(), ParamSize.value()) +checkBox(Extrusion_1, aCornerPara, ParamWidth.value(), ParamDepth.value(), ParamHeight.value()) + +# Test 2. Rotate box to keep it still axes-aligned +Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_1"), 90) +aCornerPara.setX(aCornerPara.x() + ParamWidth.value() - ParamDepth.value()) +aCornerPara.setY(aCornerPara.y() - ParamWidth.value()) +checkBox(Rotation_1, aCornerPara, ParamDepth.value(), ParamWidth.value(), ParamHeight.value()) + +# Test 3. Rotate boxes +Axis_4 = model.addAxis(Part_1_doc, model.selection("VERTEX", "Box_1_1/Back&Box_1_1/Left&Box_1_1/Bottom"), model.selection("VERTEX", "Box_1_1/Front&Box_1_1/Right&Box_1_1/Top")) +Rotation_2 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "Axis_1"), "Angle") +Rotation_3 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Rotation_1_1")], model.selection("EDGE", "Axis_1"), "Angle") + +aRotDir = GeomAPI.GeomAPI_Dir(1, 1, 1) +anAngle = ParamAngle.value() * math.pi / 180.0 +aCosAngle = math.cos(anAngle) +aSinAngle = math.sin(anAngle) + +aCornerBox = GeomAPI.GeomAPI_Pnt(0, ParamSize.value(), 0) +aCornerBox1 = GeomAPI.GeomAPI_Pnt(ParamSize.value(), 0, ParamSize.value()) +aCornerBox = GeomAPI.GeomAPI_Pnt(aCornerBox.x() * (aCosAngle + (1 - aCosAngle) * aRotDir.x()**2) + aCornerBox.y() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() - aSinAngle * aRotDir.z()) + aCornerBox.z() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() + aSinAngle * aRotDir.y()), + aCornerBox.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() + aSinAngle * aRotDir.z()) + aCornerBox.y() * (aCosAngle + (1 - aCosAngle) * aRotDir.y()**2) + aCornerBox.z() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() - aSinAngle * aRotDir.x()), + aCornerBox.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() - aSinAngle * aRotDir.y()) + aCornerBox.y() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() + aSinAngle * aRotDir.x()) + aCornerBox.z() * (aCosAngle + (1 - aCosAngle) * aRotDir.z()**2)) +aCornerBox1 = GeomAPI.GeomAPI_Pnt(aCornerBox1.x() * (aCosAngle + (1 - aCosAngle) * aRotDir.x()**2) + aCornerBox1.y() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() - aSinAngle * aRotDir.z()) + aCornerBox1.z() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() + aSinAngle * aRotDir.y()), + aCornerBox1.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() + aSinAngle * aRotDir.z()) + aCornerBox1.y() * (aCosAngle + (1 - aCosAngle) * aRotDir.y()**2) + aCornerBox1.z() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() - aSinAngle * aRotDir.x()), + aCornerBox1.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() - aSinAngle * aRotDir.y()) + aCornerBox1.y() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() + aSinAngle * aRotDir.x()) + aCornerBox1.z() * (aCosAngle + (1 - aCosAngle) * aRotDir.z()**2)) +checkRotatedBox(Rotation_2, aCornerBox, aCornerBox1) + +aCornerPara.setY(aCornerPara.y() + ParamWidth.value()) +aCornerPara1 = GeomAPI.GeomAPI_Pnt(aCornerPara.x() + ParamDepth.value(), aCornerPara.y() - ParamWidth.value(), aCornerPara.z() + ParamHeight.value()) +aCornerPara = GeomAPI.GeomAPI_Pnt(aCornerPara.x() * (aCosAngle + (1 - aCosAngle) * aRotDir.x()**2) + aCornerPara.y() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() - aSinAngle * aRotDir.z()) + aCornerPara.z() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() + aSinAngle * aRotDir.y()), + aCornerPara.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() + aSinAngle * aRotDir.z()) + aCornerPara.y() * (aCosAngle + (1 - aCosAngle) * aRotDir.y()**2) + aCornerPara.z() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() - aSinAngle * aRotDir.x()), + aCornerPara.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() - aSinAngle * aRotDir.y()) + aCornerPara.y() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() + aSinAngle * aRotDir.x()) + aCornerPara.z() * (aCosAngle + (1 - aCosAngle) * aRotDir.z()**2)) +aCornerPara1 = GeomAPI.GeomAPI_Pnt(aCornerPara1.x() * (aCosAngle + (1 - aCosAngle) * aRotDir.x()**2) + aCornerPara1.y() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() - aSinAngle * aRotDir.z()) + aCornerPara1.z() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() + aSinAngle * aRotDir.y()), + aCornerPara1.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.y() + aSinAngle * aRotDir.z()) + aCornerPara1.y() * (aCosAngle + (1 - aCosAngle) * aRotDir.y()**2) + aCornerPara1.z() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() - aSinAngle * aRotDir.x()), + aCornerPara1.x() * ((1 - aCosAngle) * aRotDir.x() * aRotDir.z() - aSinAngle * aRotDir.y()) + aCornerPara1.y() * ((1 - aCosAngle) * aRotDir.y() * aRotDir.z() + aSinAngle * aRotDir.x()) + aCornerPara1.z() * (aCosAngle + (1 - aCosAngle) * aRotDir.z()**2)) +checkRotatedBox(Rotation_3, aCornerPara, aCornerPara1) + +# Test 4. Compose a non-closed shell of the box faces and check it is not a box +Shell_objects = ["Rotation_3_1/Rotated_Face_1", "Rotation_3_1/Rotated_Face_2", "Rotation_3_1/Rotated_Face_3", "Rotation_3_1/Rotated_Face_4"] +checkShellNotBox(Part_1_doc, Shell_objects) + +# Test 5. Compose a shell of all box faces +Shell_objects = ["Rotation_3_1/Rotated_Face_1", "Rotation_3_1/Rotated_Face_2", "Rotation_3_1/Rotated_Face_3", "Rotation_3_1/Rotated_Face_4", "Rotation_3_1/Rotated_Face_5", "Rotation_3_1/Rotated_Face_6"] +checkShellRotatedBox(Part_1_doc, Shell_objects, aCornerPara, aCornerPara1) + +model.end() diff --git a/src/GeomAPI/Test/TestCone.py b/src/GeomAPI/Test/TestCone.py new file mode 100644 index 000000000..2c74a1955 --- /dev/null +++ b/src/GeomAPI/Test/TestCone.py @@ -0,0 +1,221 @@ +## 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 +## + +from GeomAPI import * +from SketchAPI import * + +from salome.shaper import model + +import math + +TOLERANCE = 1.e-7 + +def assertCircle(theEdge, theCenter, theRadius): + assert(theEdge.isCircle()) + aCircle = theEdge.circle() + assert(aCircle.center().distance(theCenter) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(aCircle.center().x(), aCircle.center().y(), aCircle.center().z(), theCenter.x(), theCenter.y(), theCenter.z()) + assert(math.fabs(aCircle.radius() - theRadius) < TOLERANCE), "Radius {} != {}".format(aCircle.radius(), theRadius) + +def checkCircleEdge(theDocument, theEdgeName, theCenter, theRadius): + anEdge = model.addEdge(theDocument, [model.selection("EDGE", theEdgeName)]) + aShape = anEdge.result().resultSubShapePair()[0].shape() + assert(aShape.isEdge()) + assertCircle(aShape.edge(), theCenter, theRadius) + theDocument.removeFeature(anEdge.feature()) + +def checkCircleFace(theDocument, theFaceName, theCenter, theRadius): + aFaceFeature = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFaceFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + aFace = aShape.face(); + aSubs = aFace.subShapes(GeomAPI.GeomAPI_Shape.EDGE) + assert(aSubs.size() == 1) + assertCircle(aSubs[0].edge(), theCenter, theRadius) + theDocument.removeFeature(aFaceFeature.feature()) + +def assertEllipse(theEdge, theFirstFocus, theSecondFocus, theMajorRadius, theMinorRadius): + assert(theEdge.isEllipse()) + anEllipse = theEdge.ellipse() + assert(anEllipse.firstFocus().distance(theFirstFocus) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(anEllipse.firstFocus().x(), anEllipse.firstFocus().y(), anEllipse.firstFocus().z(), theFirstFocus.x(), theFirstFocus.y(), theFirstFocus.z()) + assert(anEllipse.secondFocus().distance(theSecondFocus) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(anEllipse.secondFocus().x(), anEllipse.secondFocus().y(), anEllipse.secondFocus().z(), theSecondFocus.x(), theSecondFocus.y(), theSecondFocus.z()) + assert(math.fabs(anEllipse.majorRadius() - theMajorRadius) < TOLERANCE), "Major radius {} != {}".format(anEllipse.majorRadius(), theMajorRadius) + assert(math.fabs(anEllipse.minorRadius() - theMinorRadius) < TOLERANCE), "Minor radius {} != {}".format(anEllipse.minorRadius(), theMinorRadius) + +def checkEllipseEdge(theDocument, theEdgeName, theFirstFocus, theSecondFocus, theMajorRadius, theMinorRadius): + anEdge = model.addEdge(theDocument, [model.selection("EDGE", theEdgeName)]) + aShape = anEdge.result().resultSubShapePair()[0].shape() + assert(aShape.isEdge()) + assertEllipse(aShape.edge(), theFirstFocus, theSecondFocus, theMajorRadius, theMinorRadius) + theDocument.removeFeature(anEdge.feature()) + +def checkEllipseFace(theDocument, theFaceName, theFirstFocus, theSecondFocus, theMajorRadius, theMinorRadius): + aFaceFeature = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFaceFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + aFace = aShape.face(); + aSubs = aFace.subShapes(GeomAPI.GeomAPI_Shape.EDGE) + assert(aSubs.size() == 1) + assertEllipse(aSubs[0].edge(), theFirstFocus, theSecondFocus, theMajorRadius, theMinorRadius) + theDocument.removeFeature(aFaceFeature.feature()) + +def assertCone(theCone, theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight): + assert(theCone is not None) + anApex = theCone.apex() + anAxis = theCone.axis() + assert(anApex.distance(theApex) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(anApex.x(), anApex.y(), anApex.z(), theApex.x(), theApex.y(), theApex.z()) + assert(anAxis.isParallel(theAxis, TOLERANCE)), "dir({}, {}, {}) is not parallel to dir({}, {}, {})".format(anAxis.x(), anAxis.y(), anAxis.z(), theAxis.x(), theAxis.y(), theAxis.z()) + assert(math.fabs(theCone.semiAngle() - theSemiAngle) < TOLERANCE), "SemiAngle {} != {}".format(theCone.semiAngle(), theSemiAngle) + assert(math.fabs(theCone.radius1() - theRadius1) < TOLERANCE), "Radius1 {} != {}".format(theCone.radius1(), theRadius1) + assert(math.fabs(theCone.radius2() - theRadius2) < TOLERANCE), "Radius2 {} != {}".format(theCone.radius2(), theRadius2) + assert(math.fabs(theCone.height() - theHeight) < TOLERANCE), "Height {} != {}".format(theCone.height(), theHeight) + +def checkConeFace(theDocument, theFaceName, theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight): + # check conical face + aFace = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFace.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + assertCone(aShape.face().getCone(), theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight) + theDocument.removeFeature(aFace.feature()) + +def checkConeShell(theDocument, theFaceNames, theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight): + # check conical shell + aSelection = [] + for name in theFaceNames: + aSelection.append(model.selection("FACE", name)) + aShell = model.addShell(theDocument, aSelection) + aShape = aShell.result().resultSubShapePair()[0].shape() + assert(aShape.isShell()) + assertCone(aShape.shell().getCone(), theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight) + theDocument.removeFeature(aShell.feature()) + +def checkConeAll(theDocument, theFeature, theFaceName, theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight): + # check solid + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + assertCone(aShape.solid().getCone(), theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight) + + checkConeShell(theDocument, [theFaceName], theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight) + checkConeFace(theDocument, theFaceName, theApex, theAxis, theSemiAngle, theRadius1, theRadius2, theHeight) + +def checkSegment(theDocument, theEdgeName, theStartPoint, theEndPoint): + anEdgeFeature = model.addEdge(theDocument, [model.selection("EDGE", theEdgeName)]) + aShape = anEdgeFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isEdge()) + anEdge = aShape.edge() + assert(anEdge.isLine()) + assert(anEdge.firstPoint().distance(theStartPoint) < TOLERANCE) + assert(anEdge.lastPoint().distance(theEndPoint) < TOLERANCE) + theDocument.removeFeature(anEdgeFeature.feature()) + +def checkVertex(theDocument, theVertexName, theCoordinates): + aVertex = model.addVertex(theDocument, [model.selection("VERTEX", theVertexName)]) + aShape = aVertex.result().resultSubShapePair()[0].shape() + assert(aShape.isVertex()) + assert(aShape.vertex().point().distance(theCoordinates) < TOLERANCE) + theDocument.removeFeature(aVertex.feature()) + +def semiAngle(theRadius1, theRadius2, theHeight): + return math.atan(math.fabs(theRadius1 - theRadius2) / theHeight) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +ParamR1 = model.addParameter(Part_1_doc, "R1", "50") +ParamR2 = model.addParameter(Part_1_doc, "R2", "5") +ParamH = model.addParameter(Part_1_doc, "H", "70") +ParamShift = model.addParameter(Part_1_doc, "Shift", "5") +ParamAngle = model.addParameter(Part_1_doc, "Angle", "60") +Cone_1 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R1", "R2", "H") +model.do() + +# Test 1. Check cone +aSemiAngle = semiAngle(ParamR1.value(), ParamR2.value(), ParamH.value()) +anApex = GeomAPI.GeomAPI_Pnt(0, 0, ParamR1.value() / math.tan(aSemiAngle)) +anAxis = GeomAPI.GeomAPI_Dir(0, 0, 1) +checkConeAll(Part_1_doc, Cone_1, "Cone_1_1/Face_1", anApex, anAxis, aSemiAngle, ParamR2.value(), ParamR1.value(), ParamH.value()) +checkCircleFace(Part_1_doc, "Cone_1_1/Face_2", GeomAPI.GeomAPI_Pnt(0, 0, ParamH.value()), ParamR2.value()) +checkCircleEdge(Part_1_doc, "Cone_1_1/Face_1&Cone_1_1/Face_2", GeomAPI.GeomAPI_Pnt(0, 0, ParamH.value()), ParamR2.value()) +checkCircleFace(Part_1_doc, "Cone_1_1/Face_3", GeomAPI.GeomAPI_Pnt(0, 0, 0), ParamR1.value()) +checkCircleEdge(Part_1_doc, "Cone_1_1/Face_1&Cone_1_1/Face_3", GeomAPI.GeomAPI_Pnt(0, 0, 0), ParamR1.value()) +checkSegment(Part_1_doc, "Cone_1_1/Face_1", GeomAPI.GeomAPI_Pnt(ParamR1.value(), 0, 0), GeomAPI.GeomAPI_Pnt(ParamR2.value(), 0, ParamH.value())) + +# Test 2. Update cone radii +ParamR1.setValue(0) +model.do() +aSemiAngle = semiAngle(ParamR1.value(), ParamR2.value(), ParamH.value()) +anApex.setZ(0) +checkConeAll(Part_1_doc, Cone_1, "Cone_1_1/Face_1", anApex, anAxis, aSemiAngle, ParamR1.value(), ParamR2.value(), ParamH.value()) +checkCircleFace(Part_1_doc, "Cone_1_1/Face_2", GeomAPI.GeomAPI_Pnt(0, 0, ParamH.value()), ParamR2.value()) +checkCircleEdge(Part_1_doc, "Cone_1_1/Face_1&Cone_1_1/Face_2", GeomAPI.GeomAPI_Pnt(0, 0, ParamH.value()), ParamR2.value()) +checkSegment(Part_1_doc, "Cone_1_1/Face_1", GeomAPI.GeomAPI_Pnt(0, 0, 0), GeomAPI.GeomAPI_Pnt(ParamR2.value(), 0, ParamH.value())) +checkVertex(Part_1_doc, "Cone_1_1/Vertex_2", GeomAPI.GeomAPI_Pnt(0, 0, 0)) + +ParamR2.setValue(50) +ParamR1.setValue(10) +model.do() +aSemiAngle = semiAngle(ParamR1.value(), ParamR2.value(), ParamH.value()) +anApex.setZ(-ParamR1.value() / math.tan(aSemiAngle)) +checkConeAll(Part_1_doc, Cone_1, "Cone_1_1/Face_1", anApex, anAxis, aSemiAngle, ParamR1.value(), ParamR2.value(), ParamH.value()) +checkCircleFace(Part_1_doc, "Cone_1_1/Face_2", GeomAPI.GeomAPI_Pnt(0, 0, ParamH.value()), ParamR2.value()) +checkCircleEdge(Part_1_doc, "Cone_1_1/Face_1&Cone_1_1/Face_2", GeomAPI.GeomAPI_Pnt(0, 0, ParamH.value()), ParamR2.value()) +checkCircleFace(Part_1_doc, "Cone_1_1/Face_3", GeomAPI.GeomAPI_Pnt(0, 0, 0), ParamR1.value()) +checkCircleEdge(Part_1_doc, "Cone_1_1/Face_1&Cone_1_1/Face_3", GeomAPI.GeomAPI_Pnt(0, 0, 0), ParamR1.value()) +checkSegment(Part_1_doc, "Cone_1_1/Face_1", GeomAPI.GeomAPI_Pnt(ParamR1.value(), 0, 0), GeomAPI.GeomAPI_Pnt(ParamR2.value(), 0, ParamH.value())) + +# Test 3. Translate cone +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cone_1_1")], model.selection("EDGE", "PartSet/OX"), "Shift") +anApex.setX(anApex.x() + ParamShift.value()) +checkConeAll(Part_1_doc, Translation_1, "Translation_1_1/Translated_Face_3", anApex, anAxis, aSemiAngle, ParamR1.value(), ParamR2.value(), ParamH.value()) +checkCircleFace(Part_1_doc, "Translation_1_1/Translated_Face_2", GeomAPI.GeomAPI_Pnt(ParamShift.value(), 0, ParamH.value()), ParamR2.value()) +checkCircleEdge(Part_1_doc, "Translation_1_1/Translated_Face_3&Translation_1_1/Translated_Face_2", GeomAPI.GeomAPI_Pnt(ParamShift.value(), 0, ParamH.value()), ParamR2.value()) +checkCircleFace(Part_1_doc, "Translation_1_1/Translated_Face_1", GeomAPI.GeomAPI_Pnt(ParamShift.value(), 0, 0), ParamR1.value()) +checkCircleEdge(Part_1_doc, "Translation_1_1/Translated_Face_3&Translation_1_1/Translated_Face_1", GeomAPI.GeomAPI_Pnt(ParamShift.value(), 0, 0), ParamR1.value()) +checkSegment(Part_1_doc, "Translation_1_1/Translated_Face_3", GeomAPI.GeomAPI_Pnt(ParamR1.value() + ParamShift.value(), 0, 0), GeomAPI.GeomAPI_Pnt(ParamR2.value() + ParamShift.value(), 0, ParamH.value())) + +# Test 4. Rotate cone +Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Translation_1_1")], model.selection("EDGE", "PartSet/OY"), "Angle") +anAngle = ParamAngle.value() * math.pi / 180.0 +anAxis = GeomAPI.GeomAPI_Dir(math.sin(anAngle), 0, math.cos(anAngle)) +x, z = anApex.x(), anApex.z() +anApex.setX(x * math.cos(anAngle) + z * math.sin(anAngle)) +anApex.setZ(-x * math.sin(anAngle) + z * math.cos(anAngle)) +checkConeAll(Part_1_doc, Rotation_1, "Rotation_1_1/Rotated_Face_3", anApex, anAxis, aSemiAngle, ParamR1.value(), ParamR2.value(), ParamH.value()) +aCenter = GeomAPI.GeomAPI_Pnt(ParamShift.value() * math.cos(anAngle) + ParamH.value() * math.sin(anAngle), 0, -ParamShift.value() * math.sin(anAngle) + ParamH.value() * math.cos(anAngle)) +checkCircleFace(Part_1_doc, "Rotation_1_1/Rotated_Face_2", aCenter, ParamR2.value()) +checkCircleEdge(Part_1_doc, "Rotation_1_1/Rotated_Face_3&Rotation_1_1/Rotated_Face_2", aCenter, ParamR2.value()) +aCenter = GeomAPI.GeomAPI_Pnt(ParamShift.value() * math.cos(anAngle), 0, -ParamShift.value() * math.sin(anAngle)) +checkCircleFace(Part_1_doc, "Rotation_1_1/Rotated_Face_1", aCenter, ParamR1.value()) +checkCircleEdge(Part_1_doc, "Rotation_1_1/Rotated_Face_3&Rotation_1_1/Rotated_Face_1", aCenter, ParamR1.value()) + +# Test 5. Split cone by plane and check conical shell and elliptic face +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), 20, False) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Rotation_1_1"), model.selection("FACE", "Plane_1")]) +checkConeShell(Part_1_doc, ["Partition_1_1_1/Modified_Face_2_2", "Partition_1_1_2/Modified_Face_2_2"], anApex, anAxis, aSemiAngle, ParamR1.value(), ParamR2.value(), ParamH.value()) + +aFirstFocus = GeomAPI.GeomAPI_Pnt(20, 0, 31.062397266842858) +aSecondFocus = GeomAPI.GeomAPI_Pnt(20, 0, -1.0935246846933797) +aMajorRadius = 27.91915871311068 +aMinorRadius = 22.824955511666207 +checkEllipseFace(Part_1_doc, "Partition_1_1_2/Modified_Face_2_1", aFirstFocus, aSecondFocus, aMajorRadius, aMinorRadius) +checkEllipseEdge(Part_1_doc, "Partition_1_1_1/Modified_Face_1_divided_1_e_1", aFirstFocus, aSecondFocus, aMajorRadius, aMinorRadius) + +model.end() diff --git a/src/GeomAPI/Test/TestCylinder.py b/src/GeomAPI/Test/TestCylinder.py new file mode 100644 index 000000000..726b837fa --- /dev/null +++ b/src/GeomAPI/Test/TestCylinder.py @@ -0,0 +1,149 @@ +## 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 +## + +from GeomAPI import * +from SketchAPI import * + +from salome.shaper import model + +import math + +TOLERANCE = 1.e-7 + +def assertCylinder(theCylinder, theLocation, theAxis, theRadius, theHeight): + assert(theCylinder is not None) + aLoc = theCylinder.location() + aDir = theCylinder.axis() + assert(aLoc.distance(theLocation) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(aLoc.x(), aLoc.y(), aLoc.z(), theLocation.x(), theLocation.y(), theLocation.z()) + assert(aDir.isParallel(theAxis, TOLERANCE)), "dir({}, {}, {}) is not parallel to dir({}, {}, {})".format(aDir.x(), aDir.y(), aDir.z(), theAxis.x(), theAxis.y(), theAxis.z()) + assert(math.fabs(theCylinder.radius() - theRadius) < TOLERANCE), "Radius {} != {}".format(theCylinder.radius(), theRadius) + assert(math.fabs(theCylinder.height() - theHeight) < TOLERANCE), "Height {} != {}".format(theCylinder.height(), theHeight) + +def checkCylinderFace(theDocument, theFaceName, theLocation, theAxis, theRadius, theHeight): + aFace = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFace.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + assertCylinder(aShape.face().getCylinder(), theLocation, theAxis, theRadius, theHeight) + theDocument.removeFeature(aFace.feature()) + +def checkCylinderShell(theDocument, theFaceNames, theLocation, theAxis, theRadius, theHeight): + aSelection = [] + for name in theFaceNames: + aSelection.append(model.selection("FACE", name)) + aShell = model.addShell(theDocument, aSelection) + aShape = aShell.result().resultSubShapePair()[0].shape() + assert(aShape.isShell()) + assertCylinder(aShape.shell().getCylinder(), theLocation, theAxis, theRadius, theHeight) + theDocument.removeFeature(aShell.feature()) + +def checkCylinderAll(theDocument, theFeature, theFaceName, theLocation, theAxis, theRadius, theHeight): + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + assertCylinder(aShape.solid().getCylinder(), theLocation, theAxis, theRadius, theHeight) + + checkCylinderShell(theDocument, [theFaceName], theLocation, theAxis, theRadius, theHeight) + checkCylinderFace(theDocument, theFaceName, theLocation, theAxis, theRadius, theHeight) + +def checkNonCylinder(theFeature): + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + assert(aShape.solid().getCylinder() is None) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +ParamH = model.addParameter(Part_1_doc, "H", "10") +ParamR = model.addParameter(Part_1_doc, "R", "10") +ParamAngle = model.addParameter(Part_1_doc, "Angle", "30") +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "2*R", "H") +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Cylinder_1_1/Face_2")) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Cylinder_1_1/Face_1&Cylinder_1_1/Face_2__cc"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchCircle_1 = Sketch_1.addCircle(0, 0, 10) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center()) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R") +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), "H", 0) +Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOZ")) +SketchLine_1 = Sketch_2.addLine(5, 20, 0, 20) +SketchLine_2 = Sketch_2.addLine(0, 20, 0, 30) +SketchLine_3 = Sketch_2.addLine(0, 30, 5, 30) +SketchLine_4 = Sketch_2.addLine(5, 30, 5, 20) +SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint()) +SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +SketchConstraintHorizontal_1 = Sketch_2.setHorizontal(SketchLine_1.result()) +SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result()) +SketchConstraintHorizontal_2 = Sketch_2.setHorizontal(SketchLine_3.result()) +SketchConstraintVertical_2 = Sketch_2.setVertical(SketchLine_4.result()) +SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), "R/2") +SketchConstraintLength_2 = Sketch_2.setLength(SketchLine_2.result(), "H") +SketchIntersectionPoint_1 = Sketch_2.addIntersectionPoint(model.selection("EDGE", "Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1"), False) +[SketchPoint_2, SketchPoint_3] = SketchIntersectionPoint_1.intersectionPoints() +SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.result()) +SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OZ"), False) +SketchLine_5 = SketchProjection_2.createdFeature() +SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_5.result()) +model.do() +Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2r-SketchLine_3r-SketchLine_4r")], model.selection("EDGE", "PartSet/OZ"), 270, 0) +model.do() + +# Test 1. Check cylinders +aLoc1 = GeomAPI.GeomAPI_Pnt(0, 0, 0) +aLoc2 = GeomAPI.GeomAPI_Pnt(0, 0, 2 * ParamH.value()) +aLoc3 = GeomAPI.GeomAPI_Pnt(0, 0, 3 * ParamH.value()) +anAxis = GeomAPI.GeomAPI_Dir(0, 0, 1) +checkCylinderAll(Part_1_doc, Cylinder_1, "Cylinder_1_1/Face_1", aLoc1, anAxis, 2 * ParamR.value(), ParamH.value()) +checkCylinderAll(Part_1_doc, Extrusion_1, "Extrusion_1_1/Generated_Face_1", aLoc2, anAxis, ParamR.value(), ParamH.value()) +checkNonCylinder(Revolution_1) +checkCylinderShell(Part_1_doc, ["Revolution_1_1/Generated_Face_4"], aLoc3, anAxis, 0.5 * ParamR.value(), ParamH.value()) +checkCylinderFace(Part_1_doc, "Revolution_1_1/Generated_Face_4", aLoc3, anAxis, 0.5 * ParamR.value(), ParamH.value()) + +# Test 2. Rotate cylinders +Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OX"), "Angle") +Rotation_2 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), "Angle") +Rotation_3 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Revolution_1_1")], model.selection("EDGE", "PartSet/OX"), "Angle") + +anAngle = ParamAngle.value() * math.pi / 180.0 +aCosAngle = math.cos(anAngle) +aSinAngle = math.sin(anAngle) +anAxis = GeomAPI.GeomAPI_Dir(0, anAxis.y() * aCosAngle - anAxis.z() * aSinAngle, anAxis.y() * aSinAngle + anAxis.z() * aCosAngle) +aLoc1 = GeomAPI.GeomAPI_Pnt(0, aLoc1.y() * aCosAngle - aLoc1.z() * aSinAngle, aLoc1.y() * aSinAngle + aLoc1.z() * aCosAngle) +aLoc2 = GeomAPI.GeomAPI_Pnt(0, aLoc2.y() * aCosAngle - aLoc2.z() * aSinAngle, aLoc2.y() * aSinAngle + aLoc2.z() * aCosAngle) +aLoc3 = GeomAPI.GeomAPI_Pnt(0, aLoc3.y() * aCosAngle - aLoc3.z() * aSinAngle, aLoc3.y() * aSinAngle + aLoc3.z() * aCosAngle) +checkCylinderAll(Part_1_doc, Rotation_1, "Rotation_1_1/Rotated_Face_3", aLoc1, anAxis, 2 * ParamR.value(), ParamH.value()) +checkCylinderAll(Part_1_doc, Rotation_2, "Rotation_2_1/Rotated_Face_3", aLoc2, anAxis, ParamR.value(), ParamH.value()) +checkNonCylinder(Rotation_3) +checkCylinderShell(Part_1_doc, ["Rotation_3_1/Rotated_Face_5"], aLoc3, anAxis, 0.5 * ParamR.value(), ParamH.value()) +checkCylinderFace(Part_1_doc, "Rotation_3_1/Rotated_Face_5", aLoc3, anAxis, 0.5 * ParamR.value(), ParamH.value()) + +# Test 3. Split cylinder and compose a shell +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), "2.2*H", False) +Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), "H", False) +Partition_1_objects = [model.selection("SOLID", "Rotation_3_1"), model.selection("FACE", "Plane_1"), model.selection("FACE", "Plane_2")] +Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects) + +Shell_1_objects = ["Partition_1_1_1/Modified_Face_3_5", "Partition_1_1_4/Modified_Face_3_3", "Partition_1_1_2/Modified_Face_1_divided_2_1"] +checkCylinderShell(Part_1_doc, Shell_1_objects, aLoc3, anAxis, 0.5 * ParamR.value(), ParamH.value()) + +model.end() diff --git a/src/GeomAPI/Test/TestPolygon.py b/src/GeomAPI/Test/TestPolygon.py new file mode 100644 index 000000000..c05c38864 --- /dev/null +++ b/src/GeomAPI/Test/TestPolygon.py @@ -0,0 +1,102 @@ +## 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 +## + +from GeomAPI import * +from SketchAPI import * + +from salome.shaper import model + +import math + +TOLERANCE = 1.e-7 + +def assertRectangle(theWire): + assert(theWire is not None) + aCorners = [GeomAPI.GeomAPI_Pnt(0, 0, 0)] + assert(theWire.isRectangle(aCorners)) + +def checkRectangleFace(theDocument, theFaceName): + aFace = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFace.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + aSubs = aShape.subShapes(GeomAPI.GeomAPI_Shape.WIRE) + assert(aSubs.size() == 1) + assertRectangle(aSubs[0].wire()) + theDocument.removeFeature(aFace.feature()) + +def checkRectangleWire(theDocument, theEdgeNames): + aSelection = [] + for name in theEdgeNames: + aSelection.append(model.selection("EDGE", name)) + aWire = model.addWire(theDocument, aSelection) + aShape = aWire.result().resultSubShapePair()[0].shape() + assert(aShape.isWire()) + assertRectangle(aShape.wire()) + theDocument.removeFeature(aWire.feature()) + + +def assertPolygon(theWire): + assert(theWire is not None) + aCorners = [GeomAPI.GeomAPI_Pnt(0, 0, 0)] + assert(theWire.isPolygon(aCorners)) + +def checkPolygonWire(theDocument, theEdgeNames): + aSelection = [] + for name in theEdgeNames: + aSelection.append(model.selection("EDGE", name)) + aWire = model.addWire(theDocument, aSelection) + aShape = aWire.result().resultSubShapePair()[0].shape() + assert(aShape.isWire()) + assertPolygon(aShape.wire()) + theDocument.removeFeature(aWire.feature()) + +def checkPolyline(theDocument, theVertexNames): + aSelection = [] + for name in theVertexNames: + aSelection.append(model.selection("VERTEX", name)) + aWire = model.addPolyline3D(Part_1_doc, aSelection, False) + aShape = aWire.result().resultSubShapePair()[0].shape() + assert(aShape.isWire()) + assertPolygon(aShape.wire()) + theDocument.removeFeature(aWire.feature()) + + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +model.do() + +# Test 1. Check face/wire of box is a rectangle +checkRectangleFace(Part_1_doc, "Box_1_1/Top") +Wire_edges = ["Box_1_1/Left&Box_1_1/Top", "Box_1_1/Front&Box_1_1/Top", "Box_1_1/Right&Box_1_1/Top", "Box_1_1/Back&Box_1_1/Top"] +checkRectangleWire(Part_1_doc, Wire_edges) + +# Test 2. Build a polygon from edges +Wire_edges = ["Box_1_1/Left&Box_1_1/Bottom", "Box_1_1/Front&Box_1_1/Left", "Box_1_1/Left&Box_1_1/Top", "Box_1_1/Back&Box_1_1/Top", "Box_1_1/Right&Box_1_1/Top"] +checkPolygonWire(Part_1_doc, Wire_edges) + +# Test 3. Build a polygon from vertices +Poly_vertices = ["Box_1_1/Back&Box_1_1/Left&Box_1_1/Bottom", "Box_1_1/Front&Box_1_1/Left&Box_1_1/Bottom", "Box_1_1/Front&Box_1_1/Right&Box_1_1/Bottom", "Box_1_1/Front&Box_1_1/Right&Box_1_1/Top", "Box_1_1/Front&Box_1_1/Left&Box_1_1/Top", "Box_1_1/Back&Box_1_1/Right&Box_1_1/Top"] +checkPolyline(Part_1_doc, Poly_vertices) + +model.end() diff --git a/src/GeomAPI/Test/TestSphere.py b/src/GeomAPI/Test/TestSphere.py new file mode 100644 index 000000000..043270f6f --- /dev/null +++ b/src/GeomAPI/Test/TestSphere.py @@ -0,0 +1,125 @@ +## 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 +## + +from GeomAPI import * +from SketchAPI import * + +from salome.shaper import model + +import math + +TOLERANCE = 1.e-7 + +def checkArc(theDocument, theEdgeName, theCenter, theRadius): + # check edge (arc of circle) + anEdge = model.addEdge(theDocument, [model.selection("EDGE", theEdgeName)]) + aShape = anEdge.result().resultSubShapePair()[0].shape() + assert(aShape.isEdge()) + anArcEdge = aShape.edge() + assert(anArcEdge.isArc()) + aCircle = anArcEdge.circle() + assert(aCircle.center().distance(theCenter) < TOLERANCE) + assert(math.fabs(aCircle.radius() - theRadius) < TOLERANCE) + theDocument.removeFeature(anEdge.feature()) + +def assertSphere(theSphere, theCenter, theRadius): + assert(theSphere is not None) + assert(theSphere.center().distance(theCenter) < TOLERANCE) + assert(math.fabs(theSphere.radius() - theRadius) < TOLERANCE) + +def checkSphereFace(theDocument, theFaceName, theCenter, theRadius): + # check spherical face + aFace = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFace.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + assertSphere(aShape.face().getSphere(), theCenter, theRadius) + theDocument.removeFeature(aFace.feature()) + +def checkSphereShell(theDocument, theFaceName, theCenter, theRadius): + # check spherical shell + aShell = model.addShell(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aShell.result().resultSubShapePair()[0].shape() + assert(aShape.isShell()) + assertSphere(aShape.shell().getSphere(), theCenter, theRadius) + theDocument.removeFeature(aShell.feature()) + +def checkSphereAll(theDocument, theFeature, theFaceName, theCenter, theRadius): + # check solid + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + assertSphere(aShape.solid().getSphere(), theCenter, theRadius) + + checkSphereShell(theDocument, theFaceName, theCenter, theRadius) + checkSphereFace(theDocument, theFaceName, theCenter, theRadius) + checkArc(theDocument, theFaceName, theCenter, theRadius) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +ParamR = model.addParameter(Part_1_doc, "R", "50") +ParamShift = model.addParameter(Part_1_doc, "Shift", "30") +ParamAngle = model.addParameter(Part_1_doc, "Angle", "30") +ParamAperture = model.addParameter(Part_1_doc, "Aperture", "360") +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchArc_1 = Sketch_1.addArc(0, 0, 0, -50, 0, 50, False) +SketchArc_1.results()[1].setColor(225, 0, 0) +SketchLine_1 = Sketch_1.addLine(0, 50, 0, -50) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint()) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_1.endPoint()) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchArc_1.center()) +SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_1.result()) +SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result()) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], "R") +model.do() + +# Test 1. Compose sphere +Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_1_2f-SketchLine_1f")], model.selection("EDGE", "Sketch_1/Edge-SketchLine_1"), "Aperture", 0) +aCenter = GeomAPI.GeomAPI_Pnt(0, 0, 0) +checkSphereAll(Part_1_doc, Revolution_1, "Revolution_1_1/Generated_Face_2", aCenter, ParamR.value()) + +# Test 2. Translate sphere +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Revolution_1_1")], model.selection("EDGE", "PartSet/OX"), "Shift") +aCenter.setX(aCenter.x() + ParamShift.value()) +checkSphereAll(Part_1_doc, Translation_1, "Translation_1_1/Translated_Face_1", aCenter, ParamR.value()) + +# Test 3. Rotate sphere +Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Translation_1_1")], model.selection("EDGE", "PartSet/OY"), "Angle") +anAngle = ParamAngle.value() * math.pi / 180.0 +aCenter.setX(ParamShift.value() * math.cos(anAngle)) +aCenter.setZ(-ParamShift.value() * math.sin(anAngle)) +checkSphereAll(Part_1_doc, Rotation_1, "Rotation_1_1/Rotated_Face_1", aCenter, ParamR.value()) + +# Test 4. Check result by changing parameters +ParamR.setValue(100) +model.do() +checkSphereAll(Part_1_doc, Rotation_1, "Rotation_1_1/Rotated_Face_1", aCenter, ParamR.value()) + +ParamAperture.setValue(270) +model.do() +checkSphereFace(Part_1_doc, "Rotation_1_1/Rotated_Face_3", aCenter, ParamR.value()) +checkSphereShell(Part_1_doc, "Rotation_1_1/Rotated_Face_3", aCenter, ParamR.value()) +checkArc(Part_1_doc, "Rotation_1_1/Rotated_Face_3&Rotation_1_1/Rotated_Face_1", aCenter, ParamR.value()) +checkArc(Part_1_doc, "Rotation_1_1/Rotated_Face_3&Rotation_1_1/Rotated_Face_2", aCenter, ParamR.value()) + +model.end() diff --git a/src/GeomAPI/Test/TestTorus.py b/src/GeomAPI/Test/TestTorus.py new file mode 100644 index 000000000..25c7f3edc --- /dev/null +++ b/src/GeomAPI/Test/TestTorus.py @@ -0,0 +1,95 @@ +## 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 +## + +from GeomAPI import * +from SketchAPI import * + +from salome.shaper import model + +import math + +TOLERANCE = 1.e-7 + +def assertTorus(theTorus, theCenter, theAxis, theMajorRadius, theMinorRadius): + assert(theTorus is not None) + aCenter = theTorus.center() + aDir = theTorus.direction() + assert(aCenter.distance(theCenter) < TOLERANCE), "({}, {}, {}) != expected ({}, {}, {})".format(aCenter.x(), aCenter.y(), aCenter.z(), theCenter.x(), theCenter.y(), theCenter.z()) + assert(aDir.isParallel(theAxis, TOLERANCE)), "dir({}, {}, {}) is not parallel to dir({}, {}, {})".format(aDir.x(), aDir.y(), aDir.z(), theAxis.x(), theAxis.y(), theAxis.z()) + assert(math.fabs(theTorus.majorRadius() - theMajorRadius) < TOLERANCE), "Major radius {} != {}".format(theTorus.majorRadius(), theMajorRadius) + assert(math.fabs(theTorus.minorRadius() - theMinorRadius) < TOLERANCE), "Minor radius {} != {}".format(theTorus.minorRadius(), theMinorRadius) + +def checkTorusFace(theDocument, theFaceName, theCenter, theAxis, theMajorRadius, theMinorRadius): + aFace = model.addFace(theDocument, [model.selection("FACE", theFaceName)]) + aShape = aFace.result().resultSubShapePair()[0].shape() + assert(aShape.isFace()) + assertTorus(aShape.face().getTorus(), theCenter, theAxis, theMajorRadius, theMinorRadius) + theDocument.removeFeature(aFace.feature()) + +def checkTorusShell(theDocument, theFaceNames, theCenter, theAxis, theMajorRadius, theMinorRadius): + aSelection = [] + for name in theFaceNames: + aSelection.append(model.selection("FACE", name)) + aShell = model.addShell(theDocument, aSelection) + aShape = aShell.result().resultSubShapePair()[0].shape() + assert(aShape.isShell()) + assertTorus(aShape.shell().getTorus(), theCenter, theAxis, theMajorRadius, theMinorRadius) + theDocument.removeFeature(aShell.feature()) + +def checkTorusAll(theDocument, theFeature, theFaceName, theCenter, theAxis, theMajorRadius, theMinorRadius): + aShape = theFeature.result().resultSubShapePair()[0].shape() + assert(aShape.isSolid()) + assertTorus(aShape.solid().getTorus(), theCenter, theAxis, theMajorRadius, theMinorRadius) + + checkTorusShell(theDocument, [theFaceName], theCenter, theAxis, theMajorRadius, theMinorRadius) + checkTorusFace(theDocument, theFaceName, theCenter, theAxis, theMajorRadius, theMinorRadius) + + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +ParamRMax = model.addParameter(Part_1_doc, "RMax", "15") +ParamRMin = model.addParameter(Part_1_doc, "RMin", "5") +ParamAngle = model.addParameter(Part_1_doc, "Angle", "30") +Torus_1 = model.addTorus(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "RMax", "RMin") +model.do() + +# Test 1. Check torus +aCenter = GeomAPI.GeomAPI_Pnt(0, 0, 0) +anAxis = GeomAPI.GeomAPI_Dir(0, 0, 1) +checkTorusAll(Part_1_doc, Torus_1, "Torus_1_1/Face_1", aCenter, anAxis, ParamRMax.value(), ParamRMin.value()) + +# Test 2. Rotate torus +Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Torus_1_1")], model.selection("EDGE", "PartSet/OX"), "Angle") +anAngle = ParamAngle.value() * math.pi / 180.0 +aCosAngle = math.cos(anAngle) +aSinAngle = math.sin(anAngle) +aCenter = GeomAPI.GeomAPI_Pnt(0, aCenter.y() * aCosAngle - aCenter.z() * aSinAngle, aCenter.y() * aSinAngle + aCenter.z() * aCosAngle) +anAxis = GeomAPI.GeomAPI_Dir(0, anAxis.y() * aCosAngle - anAxis.z() * aSinAngle, anAxis.y() * aSinAngle + anAxis.z() * aCosAngle) +checkTorusAll(Part_1_doc, Rotation_1, "Rotation_1_1/Rotated_Face_1", aCenter, anAxis, ParamRMax.value(), ParamRMin.value()) + +# Test 3. Split torus and compose a shell +Partition_1_objects = [model.selection("SOLID", "Rotation_1_1"), model.selection("FACE", "PartSet/YOZ"), model.selection("FACE", "PartSet/XOZ"), model.selection("FACE", "PartSet/XOY")] +Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects) +Shell_1_objects = ["Partition_1_1_6/Modified_Face_4_4", "Partition_1_1_7/Modified_Face_4_3", "Partition_1_1_7/Modified_Face_1_divided_2_1", "Partition_1_1_5/Modified_Face_4_4"] +checkTorusShell(Part_1_doc, Shell_1_objects, aCenter, anAxis, ParamRMax.value(), ParamRMin.value()) + +model.end() -- 2.39.2