Unit tests for the inspection functionality.
INCLUDE(${SWIG_USE_FILE})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+INCLUDE(UnitTest)
SET(PROJECT_HEADERS
GeomAPI.h
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
+)
// 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)
%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<std::shared_ptr<GeomAPI_Pnt> > &thePoints (std::list<std::shared_ptr<GeomAPI_Pnt> > temp) {
+ std::shared_ptr<GeomAPI_Pnt> * 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<GeomAPI_Pnt> *), 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"
%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<std::shared_ptr<GeomAPI_Pnt> >;
+%template(ShapeList) std::list<std::shared_ptr<GeomAPI_Shape> >;
const double theSemiAngle,
const double theRadius1,
const double theRadius2)
- : GeomAPI_Interface(
- newCone(theLocation->impl<gp_Pnt>(), theAxis->impl<gp_Dir>(), theSemiAngle, theRadius1)),
- myRadius1(theRadius1),
+ : myRadius1(theRadius1),
myRadius2(theRadius2)
{
+ gp_Pnt aLoc = theLocation->impl<gp_Pnt>();
+ gp_Dir aDir = theAxis->impl<gp_Dir>();
+ if (theRadius1 > theRadius2) {
+ aLoc.ChangeCoord() += aDir.XYZ() * (theRadius1 - theRadius2) / Tan(theSemiAngle);
+ aDir.Reverse();
+ myRadius1 = theRadius2;
+ myRadius2 = theRadius1;
+ }
+
+ setImpl(newCone(aLoc, aDir, theSemiAngle, myRadius1));
}
//=================================================================================================
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()));
return distance(theOther) < Precision::Confusion();
}
+bool GeomAPI_Pnt::isLess(const std::shared_ptr<GeomAPI_Pnt>& 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_Pnt2d> GeomAPI_Pnt::to2D(const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
const std::shared_ptr<GeomAPI_Dir>& theDirX, const std::shared_ptr<GeomAPI_Dir>& theDirY)
{
GEOMAPI_EXPORT
bool isEqual(const std::shared_ptr<GeomAPI_Pnt>& 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<GeomAPI_Pnt>& theOther) const;
+
/// Projects a point to the plane defined by the origin and 2 axes vectors in this plane
GEOMAPI_EXPORT
std::shared_ptr<GeomAPI_Pnt2d> to2D(const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
GeomPointPtr anApex;
GeomDirPtr anAxis;
- double aSemiAngle, aCosSemiAngle;
+ double aSemiAngle, aTanSemiAngle;
double aHeight1, aHeight2;
for (TopExp_Explorer anExp(impl<TopoDS_Shape>(), TopAbs_FACE); anExp.More(); anExp.Next()) {
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 {
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)
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));
}
std::list<GeomPointPtr> 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<GeomPointPtr>::const_iterator aPrev = --aCorners.end();
+ std::list<GeomPointPtr>::const_iterator aCur = aPrev--;
+ std::list<GeomPointPtr>::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);
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));
}
//==================================================================================================
bool GeomAPI_Wire::isRectangle(std::list<GeomPointPtr>& thePoints) const
{
+ thePoints.clear();
+
const TopoDS_Wire& aWire = TopoDS::Wire(impl<TopoDS_Shape>());
const Handle(Standard_Type)& aLineType = STANDARD_TYPE(Geom_Line);
#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"
#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"
#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 <memory>
#include <string>
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from 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()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from 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()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from 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()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from 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()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from 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()
--- /dev/null
+## Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+from 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()