Primitive Examples

Box

The function areEqual() compares two shapes and returns True if they are equal and False otherwise. Here it is used to compare solid boxes, one with x, y, z dimensions 1x100x10 and the other 1x100x9. These boxes are created in the default position, with one corner at the origin and dimensions extending in the positive direction.

box1 = Part.makeBox(1, 100, 10)
print(areEqual(box1, Part.makeBox(1, 100, 10)))
print(areEqual(box1, Part.makeBox(1, 100, 9)))
True
False

The function isSubset() compares two shapes and returns True if the first is a subset of the second, and False otherwise. Equal is considered to be a subset, that is, the subset need not be a strict subset, so the result is True if the objects are equal.

print(isSubset(Part.makeBox(1, 100, 10), box1))
print(isSubset(Part.makeBox(1, 100, 9),  box1))
print(isSubset(box1, Part.makeBox(1, 100, 9)))
True
True
False

These have no output

testEqual(box1, Part.makeBox(1, 100, 10))
testNotEqual(box1, Part.makeBox(1, 100, 9))

and these raise exceptions

testNotEqual(box1, Part.makeBox(1, 100, 10))
testEqual(box1, Part.makeBox(1, 100, 9))
Traceback (most recent call last):
...
Exception: Objects are equal
Traceback (most recent call last):
...
Exception: Objects are not equal

A solid box can also be constructed by extruding a square made from line segments starting at the origin:

L1 = Part.LineSegment(o, x)
L2 = Part.LineSegment(x, Vector(1, 100, 0))
L3 = Part.LineSegment(Vector(1, 100,0), Vector(0, 100, 0))
L4 = Part.LineSegment(Vector(0, 100, 0), o)
sq = Part.Shape([L1, L2, L3, L4])
# Part.show(sq )

f = Part.makeFilledFace(sq.Edges)
# Part.show(f)
box2 = f.extrude(Vector(0,0,10))
# Part.show(box2)

print(areEqual(box1, box2))
testEqual(box1, box2,)
True

Circle

The default Part.makeCircle(r)() produces a circular line on the XY plane with radius r. (A one dimensional object embedded in a two dimensional plane in three dimensional space). The function Part.Circle(r)() does essentially the same thing but takes arguments for the center, normal and radius, and has to be converted to a shape object.

c = Part.makeCircle(5)
#Part.show(c)
c2 = c.copy()
testEqual(c, c2)
testNotEqual(c, Part.makeCircle(6))

testEqual(c, Part.Circle(o, z, 5).toShape() )

A circle has attributes that can be checked as follows.

print(c.Curve.Radius == 5.0)
print(c.Curve.Center == o )
print(c.Curve.Axis   == z )
True
True
True

Within its plane, a circle is symmetic around its center, so this circle can be rotated any number of degrees around the Z-axis and produces an equal object

c2.rotate(o, z, 180)
testEqual(c, c2)
c2.rotate(o, z, 90)
testEqual(c, c2)
c2.rotate(o, z, 33)
testEqual(c, c2)

but translation produces an object that is not equal.

c2.translate(Vector(0,0,10))
testNotEqual(c, c2)

This circle is centered at the origin and is on the plane normal to z axis. A circle has one edge and no faces, properties that can be checked.

C = Part.makeCircle(10)
print( len(C.Edges) )
print( len(C.Faces) )
print( len(C.Solids) )
1
0
0

When constructing a face (two dimensional object) from a circle (one dimensional object) it is usually important that the circle is not a partial circle, that is, it forms a complete closed loop. This is also a property that can be checked.

print( C.isClosed() )
True

A face can be constructed by filling in the circle. For some reason this needs to be converted to a wire first.

C2 = Part.Face(Part.Wire(C))
print( C2.ShapeType )
print( len(C2.Faces) )
print( len(C2.Solids) )
#Part.show(C2)
Face
1
0

Sphere

FreeCAD Part.Sphere() produces a two dimensional curved surface (face) embedded in three dimensional space (R3). (The mathematical topology of the object is S2 ). The fact that this sphere is hollow can be seen by displaying with a piece cut out, or checked by verifying that the object contains no solids.

S2 = Part.Sphere().toShape()
#Part.show(S2)
print( S2.ShapeType )  #Face
print( len(S2.Solids)) # 0

# Part.show(s2.cut(Part.makeBox(10,10,10)))
Face
0

Below concentrates on solid objects. Notice the difference between Part.Sphere() which is hollow and Part.makeSphere() which is solid. Solid objects will be more interesting for things like 3D printing.

The default Part.makeSphere(r) produces a solid sphere centered at the origin with radius r. This is a three dimensional object. A sphere can be rotated in any direction about its center and produce an equal object, but translation gives an object that is not equal.

s = Part.makeSphere(10)
#Part.show(s.cut(Part.makeBox(10,10,10)))
print(s.ShapeType)

sr = Part.makeSphere(10)
sr.rotate(o, z, 180)
testEqual(s, sr)

sr.translate(Vector(0,0,10))
testNotEqual(s, sr)

testNotEqual(s, Part.makeSphere(9))
Solid

A sphere object has edges, faces and solids.

print(len(s.Edges))
print(len(s.Faces))
print( len(s.Solids))
3
1
1

A sphere can also be constructed by revolving a circle. A full circle revolved 360 degrees covers the sphere twice over, which causes anomolies according to the help for revolve(). Revolving 180 degrees is better.

(There is an anomaly here. makeSphere gives ShapeType ‘Solid’ whereas Circle gives ShapeType ‘Face’, but cutting leaves an empty object. See Puzzles.)

Revolving a full circle seems broken. Intuitively this may seem like the most obvious way to proceed, but does not work.

c10 = Part.Circle(o, z, 10)

# Part.show(c10.toShape())
# Part.show(Part.makeCircle(10))

print( c10.toShape().revolve(o, x, 180).isValid() ) # False
print( c10.toShape().revolve(o, y, 180).isValid() ) # False
print( c10.toShape().revolve(o, z, 180).isValid() ) # True but flat (z is norm)
# Part.show(c10.toShape().revolve(o, z, 180))
False
False
True

A solid sphere can also be constructed by revolving a half circle line and filling in the result to make a solid. According to the help for revolve() this is better than revolving a full circle. (This is an algorithmic improvement, not a theoretical difference.). LastParameter for a circle is 2 * pi radians, so h10 in the next is a half circle on the X-Y plane. Revolving around the Z-axis results in a flat full circle, filled in to make an object of ShapeType ‘Face’. Revolving around the X-axis produces an object that is not valid. I think this is because of the problem mentioned in the help for revolve, the meshing algorithm does not like to rotate around a point where there is no vertex. The Y-axis goes through both vertexes and revolving around it works well.

c10 = Part.Circle(o, z, 10)
h10 = c10.toShape(c10.LastParameter/4, 3*c10.LastParameter/4)
print( h10.ShapeType )
# Part.show(h10)   # unfilled half circle on X-Y plane

print( h10.revolve(o, z, 360).isValid() )     # True
print( h10.revolve(o, x, 360).isValid() )     # False
print( h10.revolve(o, y, 360).isValid() )     # True

sf10 = h10.revolve(o, y, 360)
print( sf10.ShapeType )
# Part.show(sf10)

s10 = Part.makeSolid(Part.makeShell([sf10]))
# Part.show(s10)
print( s10.ShapeType )
print( len(s10.Solids) )

print( s10.cut(s).isValid() ) # True
print( s.cut(s10).isValid() ) # True

#testEqual(s, s10) # this test seems a bit fragile

# Part.show(s.cut(Part.makeBox(10,10,10)))
# Part.show(s10.cut(Part.makeBox(10,10,10)))
# Part.show(s10.cut(s))
# Part.show(s.cut(s10))
# Part.show((s10.cut(s)).cut(Part.makeBox(10,10,10)))
# Part.show((s.cut(s10)).cut(Part.makeBox(10,10,10)))
Edge
True
False
True
Face
Solid
1
True
True

To support speculation about difficulty for the meshing algorithm, this example selects a different section of the circle and rotates successfully around the X-axis.

c10 = Part.Circle(o, z, 10)
print( c10.toShape(0, c10.LastParameter/2).revolve(o, x, 360).isValid() )# True
s10x = Part.makeSolid(Part.makeShell([c10.toShape(0,
                 c10.LastParameter/2).revolve(o, x, 360)]))
print( s10x.ShapeType )
# Part.show(s10x)
testEqual(s, s10x)
True
Solid

And this example creates the circle on the Y-Z plane and selects a circle section that rotates successfully around the Z-axis.

c10z = Part.Circle(o, x, 10)
print( c10z.toShape(0, c10z.LastParameter/2).revolve(o, x, 360).isValid() )# True

s10z = Part.makeSolid(Part.makeShell([
          c10z.toShape(0, c10z.LastParameter/2).revolve(o, z, 360)  ]))
print( s10z.ShapeType )
# Part.show(s10z)
testEqual(s, s10z)
True
Solid

While Part.makeSphere() will generally be easier to use to make a sphere, or portions of it, an arc can be used to make different rotation profiles. The next example shows making a sphere using Part.arc() and Part.makeRevolution() so easy test comparisons are possible, but that will generally not be the most interesting rotation profile.

Part.makeRevolution() takes 7 arguments. (Prior to FreeCAD 0.19, if the first argument was Part.Shape object then it was used to determine the ShapeType and only the 6 first arguments were supported.)

Notice also that the angle, center, and axis arguments are in a different order from the revolve() method.

arc = Part.Arc(-10*z, 10*x, 10*z)
#Part.show(arc.toShape())

aS = Part.makeRevolution(arc, arc.FirstParameter, arc.LastParameter,
              360, o, z, Part.Solid)
print(aS.isClosed() )  #True
print(aS.isValid() )   #True
print( aS.ShapeType )  #Solid
#Part.show(aS)

Part.makeRevolution(arc, arc.FirstParameter, arc.LastParameter,
              360, o, z, Part.Face).ShapeType  # Face

#Part.show(aS)

testEqual(s, aS)

testEqual(s, Part.makeRevolution(arc.toShape(),
           arc.FirstParameter, arc.LastParameter, 360, o, z) )

# This should work in 0.19
#if (100* float(FreeCAD.Version()[0]) + float(FreeCAD.Version()[1]) >= 19.0 ):
#testEqual(s, Part.makeRevolution(arc.toShape(),
#           arc.FirstParameter, arc.LastParameter, 360, o, z, Part.Solid) )
#testEqual(s, Part.makeRevolution(arc.toShape(),
#           arc.FirstParameter, arc.LastParameter, 360, o, z, Part.Solid) )
#if (100* float(FreeCAD.Version()[0]) + float(FreeCAD.Version()[1]) >= 19.0 ):
#  aSe = Part.makeRevolution(arc.toShape(), arc.FirstParameter, arc.LastParameter,
#              360, o, z, Part.Face).ShapeType  #Face
True
True
Solid

It is important that the shape created by Part.makeRevolution() is closed or the result is not likely to be valid, and the problem is not immediately indicated unless you check. Subsequent use of the returned object is likely to be problematic but the source of the problem may not be obvious.

A revolved Face object produces a solid but beware that revolving other object will not produce solids. (More on this further below.)

arcS = arc.toShape().revolve(o, z, 360)
print( arcS.ShapeType )
#Part.makeSolid(Part.makeShell([arcS]))
#Part.makeSolid(arcS)
#Part.makeFilledFace(arcS.Edges)

testNotEqual(s, arcS )
Face

py:func:Part.makeRevolution can also be used to make a solid hemisphere. It is used next to illustrate mirror and fuse.

py:obj:`Part.makeSphere(radius, center, axis, fromLatitude, toLatitude, rotationAngle) where fromLatitude is angle to start of sweep, measured fom a normal to the axis, toLatitude is angle to end of sweep, measured from a normal to the axis, and rotationAngle is the circular sweep around the axis. Angles in degrees.

#Part.show(Part.makeSphere(10, o, y, 45, 90, 360))
#Part.show(Part.makeSphere(10, o, y, 45, 60, 360))
#Part.show(Part.makeSphere(10, o, y, 45, 60, 270))

hS  = Part.makeSphere(10, o, y, 0, 90, 360)
hSm = Part.makeSphere(10, o, -y, 0, 90, 360)

testEqual(s, hS.fuse(hSm)  )
testEqual(hSm, hS.mirror(o, y) )
testEqual(s, hS.fuse(hS.mirror(o, y))  )
testEqual(s, hS.mirror(o, y).fuse(hS)  )

#Part.show(hS)
#Part.show(hSm)
#Part.show(hS.fuse(hSm) )

arc = Part.Arc(-10*z, 10*x, 10*z)
hSr = Part.makeRevolution(arc,
           arc.FirstParameter, arc.LastParameter, 180, o, z, Part.Solid)

print( hSr.isClosed() )  # True
print( hSr.isValid() )   # True
print( hSr.ShapeType )   # Solid
#Part.show(hSr)

testEqual(hS, hSr )
testEqual(hS.mirror(o, y), hSr.mirror(o, y) )
testEqual(s, hS.mirror(o, y).fuse(hSr) )
testEqual(s, hSr.mirror(o, y).fuse(hS) )

#Part.show(hS.mirror(o, y).fuse(hSr))
#Part.show(hSr.mirror(o, y).fuse(hS))

hSrm = Part.makeRevolution(Part.Arc(-10*z, -10*x, 10*z),
           arc.FirstParameter, arc.LastParameter, 180, o, z, Part.Solid)
print( hSrm.isClosed() )   # True
print( hSrm.isValid() )    # True
print( hSrm.ShapeType )    # Solid
#Part.show(hSrm)
#Part.show(hSrm.fuse(hS))
hS2 = hSm.fuse(hS)
#Part.show(hS2)

hSm1 = hS.mirror(o, x)
print( hSm1.isClosed() )  # True
print( hSm1.isValid() )   # True
print( hSm1.ShapeType )   # Solid
#Part.show(hSm1)
#Part.show(hS.fuse(hSm1) )

# STILL TO FIX BELOW
# this produces a flat disk, which
# LOOKS TO ME LIKE A BUG OR LIMIT ON ANGLE, OR UNDOCUMENTED AND UNCHECKED FEATURE
hSm = Part.makeRevolution(arc,
           arc.FirstParameter, arc.LastParameter, -180, o, z, Part.Solid)
#Part.show(hSm)

# NEXT SHOULD BE SAME AS ABOVE (reversing signs on 180 and z)
# this works but has some anomolies across the flat face
hSm = Part.makeRevolution(arc,
           arc.FirstParameter, arc.LastParameter, 180, o, -z, Part.Solid)

#Part.show(hSm)
print( hSm.isClosed() )  #True
print( hSm.isValid() )   #False  but  ???


Part.makeShell(hSm.Faces).isValid()  #False but ???
shellm = Part.makeShell(hSm.Faces)
shellm.isValid()
#Part.makeShell([hSm.Faces]).isValid()RuntimeError: check failed, shape may be empty
#Part.show(shellm)
#hSm = hS.mirror(o, x)
HS = hS.fuse([hSm])   # FAILS USING GUI UNION TOO
#testEqual(s, HS.cleaned(), debug = True)
#Part.show(HS)
# this misses a quarter HS = hS.fuse(hS.mirror(o, x))
True
True
Solid
True
True
Solid
True
True
Solid
True
False

Part.makeRevolution() and Shape method revolve() use different approaches. Shape method revolve() uses BRepPrimAPI_MakeRevol which accepts a shape as input. Part.makeRevolution() accepts a GeomCurve.

So Shape method revolve() using accepts a wider range of objects: with a vertex it creates an edge; with an edge it creates a face; with a wire it creates a shell; with a face it creates a solid; with a shell it creates a compound solid.

On the other hand, Part.makeRevolution() has some flexibility on what the output will be.

arc = Part.Arc(-10*z, 10*x, 10*z)
arcShapeEdge = arc.toShape()
print( arcShapeEdge.ShapeType )  #Edge

arcShapeWire = Part.Wire(arcShapeEdge)
print( arcShapeWire.ShapeType )  #Wire

# makeRevolution
s0 =Part.makeRevolution(arc, arc.FirstParameter, arc.LastParameter,
              360, o, z, Part.Solid)

print( s0.ShapeType )  #Solid
testEqual(s, s0)
Edge
Wire
Solid

From a vertex revolve to create an edge, and then revolve again to give a sphere. This works if the vertex is revolved 180 degrees to give a half circle, and that is revolved 360 degrees to give the sphere:

zp = Part.Point(Vector(10,0,0)).toShape()
print( zp.ShapeType ) #Vertex

s1 = Part.makeSolid(Part.makeShell([zp.revolve(o,z,180).revolve(o, x, 360)]))
#Part.show(s1)
print( s1.ShapeType )  #Solid
print( s1.isClosed() ) #True
print( s1.isValid()  ) #True
testEqual(s, s1)
Vertex
Solid
True
True

However, it fails if the rotations are 360 first then 180. This is possibly because of the issue mentioned in the revolve doc, that rotation works best about an axis that goes though vertexes. The problem is more than anomolies suggested in the doc.

From an edge revolve create a face. This works to give solid (but isClosed() seems wrong):

zz = arcShapeEdge.revolve(o, z, 360)
#Part.show(zz)
print( zz.ShapeType  )  #Face
print( zz.isClosed() )  #False #Looks like a BUG.
print( zz.isValid()  )  #True
s2 = Part.makeSolid(Part.makeShell([zz]))
print( s2.ShapeType  )  #Solid
print( s2.isClosed() )  #True
print( s2.isValid()  )  #True
print( len(s2.Solids) ) # 1
#Part.show(s2)
testEqual(s, s2)
Face
False
True
Solid
True
True
1

For a wire revolve creates a shell:

ar = arcShapeWire.revolve(o, z, 360)
print( ar.ShapeType  ) #Shell
print( ar.isClosed() ) #True
print( ar.isValid()  ) #True

s3 =  Part.makeSolid(ar)
Part.show(s3)
print( s3.ShapeType  ) #Solid
print( s3.isClosed() ) #True
print( s3.isValid()  ) #True
print( len(s3.Solids) ) # 1
testEqual(s, s3)
Shell
True
True
Solid
True
True
1

And 4 and 5 from post if they can be made to work

Ellipse

Part.Sphere() produces a face and Part.makeSphere() produces a solid, but there is not yet a Part.makeEllipsoid() to make a solid.

An ellipsoid can be produced by revolving an ellipse. If the ellipse is not filled in (has no faces) then the revolution will be hollow.

The following shows different ways to use an ellipse to make a solid ellipsoid with the general shape of a rugby ball. (It could be made to look like a flying saucer but that will be left to the reader.)

Part.Ellipse().toShape() makes a shape that is an edge with no faces. The ellipsoid made by revolving this has faces but is not solid (a hollow ellipsoid).

To start, make an ellipse, on the XY-plane through the origin, with radii, 6.0 and 2.0.

e = Part.Ellipse(o, 6.0, 2.0)
print(len(e.toShape().Faces))
#Part.show(e.toShape())
0

Create a half ellipse on the XY-plane with ends on the X-axis and revolve it a full turn around the X-axis using method revolve()

eh = e.toShape(0, e.LastParameter/2)
#Part.show(eh)
print( eh.ShapeType )  #Edge
print( len(eh.Solids)) # 0
#TEST ON Z AXIS
ecS = eh.revolve(o, x, 360)
#Part.show(ecS )
print( ecS.ShapeType )  #Face
print( len(ecS.Solids)) # 0
print( ecS.isClosed() )  #False #Looks like a BUG.
print( ecS.isValid()  ) #True

e1 = Part.makeSolid(Part.makeShell([ecS]))
#Part.show(e1 )
print( e1.ShapeType )  #Solid
print( len(e1.Solids)) # 1
print( e1.isClosed() ) #True
print( e1.isValid()  ) #True

#( still trying Part.makeRevolution arg need to be GeomCurve)
#ecS = Part.makeRevolution(e, 0, e.LastParameter/2, 360, o, x)
#ecS = Part.makeRevolution(eh, eh.LastParameter, 0, 360, o, x)
#Part.OCCDomainError: creation of revolved shape failed    BUG ???
Edge
0
Face
0
False
True
Solid
1
True
True

1/ revolve full ellipse a half turn around the x axis

#ed = Part.makeRevolution(e.toShape(), 0, e.LastParameter, 180, o, x)

ed = e.toShape().revolve(o, y, 180) #saucer THIS SHOULD USE x BUT THAT FAILS
#Part.show(ed)
print(ed.ShapeType)   # Face  (hollow ellipsoid)
print(len(ed.Solids)) # 0
print(len(ed.Faces))  # 1
print( ed.isClosed() )  #False #Looks like a BUG.
print( ed.isValid()  ) #True

#TRY THIS IN GUI
#ed1 = e.toShape().revolve(o, x, 180) # should be rugby ball but
#Part.show(ed1)            # does not show
#print( ed1.ShapeType )  #Face
#print( len(ed1.Solids)) # 0
#print( ed1.isClosed() )  #False #Looks like a BUG.
#print( ed1.isValid()  ) #True
#ed1.PrincipalProperties
Face
0
1
False
True

I THINK THIS IS THE SAME AS FIRST NOW An algorithmically better way to make an ellipsoid, according to the revolve documentation, is to cut the ellipse so there are vertices. LastParameter is 2 pi radians so this cuts the sweep to the half circle from 0 to pi:

e = Part.Ellipse(o, 6.0, 2.0)
h = e.toShape(0, e.LastParameter/2)
#Part.show(h)
hd = h.revolve(o, x, 360) #rugby ball, hollow
ed2 = Part.makeSolid(Part.makeShell([hd]))
#Part.show(ed2)

print(h.ShapeType)     #Edge
print(hd.ShapeType)    #Face
print(ed2.ShapeType)   #Solid
print(len(ed2.Solids)) #1
print(hd.isClosed())   #False   ???
print(hd.isValid())    #True

print(len(ed2.Faces))  #1
#DO TESTEQUAL
Edge
Face
Solid
1
False
True
1

3/ a different 1/2 ellipse revolved around long axis, mirror and join

NOT YET WORKING
e3 = e.toShape(e.LastParameter/4, 3*e.LastParameter/4)
#Part.show(e3)

#THESE ROTATION WORKS FINE DESPITE NOT THROUGH VERTEXES
#hd = e3.revolve(o, x, 360) #half rugby hollow, double cover Also works
hd = e3.revolve(o, x, 180) #half rugby hollow, singe cover
#Part.show(hd)
print(hd.ShapeType)   #Face
print(len(hd.Solids)) #0
print(hd.isClosed())  #False   ???
print(hd.isValid())   #True

hdm = hd.mirror(o, x)
#Part.show(hdm)
print(hdm.ShapeType)   #Face
print(len(hdm.Solids)) #0
print(hdm.isClosed())  #False   ???
print(hdm.isValid())   #True)

#check = Part.makeShell([hdm])
#Part.show(check)
#sh3 = Part.makeShell([hd, hdm]) #SUPPOSED TO MAKE SHELL FROM LIST OF FACES BUT LOSES hdm
TRY THIS IN GUI

#sh3 = Part.makeShell([hd.Faces + hdm.Faces]) #Part.show(sh3) # no show print(sh3.ShapeType) #Face print(len(sh3.Solids)) #0 print(sh3.isClosed()) #False ??? print(sh3.isValid()) #True

#ed3 = Part.makeSolid(sh3) #Part.show(ed3) # ONLY HALF

#filled= Part.makeFilledFace(hd.toShape().Edges)

#rugby = hd.fuse(hdm) # No. Fuse wants solids (warning only in gui) #Part.show(rugby)

Face
0
False
True
Face
0
False
True

4/ 1/4 ellipse revolved to give 1/2 ellipsoid, mirror and join

NOT YET

e = Part.Ellipse(o, 6.0, 2.0).toShape()
#Part.show(e)
ed = e.revolve(o, y, 180) #saucer
#Part.show(ed)
#ed1 = Part.makeShell(ed) #Error creating objec
#ed2 = Part.makeSolid(ed) # Creation of solid failed: No shells
#Part.show(ed2)
print( len(ed.Solids) )
0

construct 2nd half rather than mirror

NOT YET

e = Part.Ellipse(o, 6.0, 2.0).toShape()
#Part.show(e)
ed = e.revolve(o, y, 180) #saucer
#ed = e.revolve(o, x, 180) # why not rugby ball
#Part.show(ed)

e2 = Part.Ellipse(o, 6.0, 2.0).toShape()
e2.rotate(o,  z,  90)
#Part.show(e2)
ed2 = e2.revolve(o, y, 180) # why not
ed2 = e2.revolve(o, x, 180) # why saucer
#Part.show(ed2)
testNotEqual(e, e2)
e.rotate(o,  x,  90)
e2.translate(x)
e2.rotate(x,  x,  90)
e2.rotate(x,  z, -90)
e2.translate(-x)
#testEqual(e, e2)

wi = Part.Wire(e)
print(wi.isClosed())  #True

d = Part.Face(wi)
dd = d.extrude(Vector(20,0,0))
#Part.show(dd)

#b = Part.makeCylinder(8, 20, o, x, 90)
#b = b.cut(dd)
True

This would not need to be rotated, but s2 does not work the way I think # e2 = Part.Ellipse(Vector(0.0, 0.0, 6),Vector(0.0, 2, 8), Vector(0.0, 0.0, 8)).toShape() #Part.show(e2)

An ellipsoid with equal radii is a circle a sphere made this way can be compared with a sphere made with makeSphere().

eC = Part.Ellipse(o, 5.0, 5.0)
edC = Part.makeSolid(Part.makeShell([
          eC.toShape(0, eC.LastParameter/2).revolve(o, x, 360)  ]))

# Part.show(edC)
testEqual( edC,Part. makeSphere(5) )

Try above using makeRevolution.

eC = Part.Ellipse(o, 5.0, 5.0)
ech = eC.toShape(0, eC.LastParameter/2)
#ecS = Part.makeRevolution(ech.Curve)
#ecS = Part.makeRevolution(ech)
#ecS = Part.makeRevolution(ech, ech.FirstParameter, ech.LastParameter, 360, o, x, Part.Solid)

Cone

Make a cone with base radius 5, top radius 10, and height 15

cone  = Part.makeCone(5, 10.0, 15)
#Part.show(cone)
cone2  = cone.copy()

testEqual(cone, cone2)

The cone is symmetic under Z axis rotation

cone2.rotate(o, z, 20)
testEqual(cone, cone2)

but not symmetic under X axis rotation

cone2.rotate(o, x, 20)
testNotEqual(cone, cone2)

cone2.translate(Vector(0,0,10))
testNotEqual(cone, cone2)

Translation and rotation can be undone, but if not undone in the reverse order then the axis for the rotation needs to be modified to the center of the cone.

cone2.rotate(Vector(0,0,10), x, -20)
cone2.translate(Vector(0,0,-10))
testEqual(cone, cone2)

c  = Part.makeCylinder(5, 10.0, o, z, 360)
c2 = c.copy()
testEqual(c, c2)

c2.rotate(o, z, 180)
testEqual(c, c2)

c2.rotate(o, Vector(1,0,0), 180)
c2.translate(Vector(0,0,10))
testEqual(c, c2)

c2 = c.copy()
testEqual(c, c2)

c2.rotate(o, z, 90)
testEqual(c, c2)

c2.rotate(o, Vector(1,0,0), 90)
testNotEqual(c, c2)

Polygon

Make a line betweeen two points

line  = Part.makeLine((0.5, 0.5, 0.5),(1, 2, 3))
line2 = line.copy()
testEqual(line, line2)

Make a plane (rectangle) from origin 2 units in x direction and 4 in Y direction.

plane = Part.makePlane(2, 4)

# there seems to be a bug here?
#plane2 = plane.rotate(o, z, 20)
#Part.show(plane2)

plane2 = plane.copy()
testEqual(plane, plane2)

plane2.rotate(o, z, 20)
testNotEqual(plane, plane2)

Make a polygon of a list of points

poly  = Part.makePolygon([o, x, y, z])
poly2 = poly.copy()
testEqual(poly, poly2)

poly2.rotate(o, z, 20)
testNotEqual(poly, poly2)

Torus

Make a torus SxS with first radius 20 in the X-Y plane and second radius 5

torus =  Part.makeTorus(20, 5)
#Part.show(torus)


torus2 = torus.copy()
#Part.show(torus2)
testEqual(torus, torus2 )

torus2.rotate(o, z, 90)
testEqual(torus, torus2 )

Flipping will be equal

torus2.rotate(o, x, 180)
testEqual(torus, torus2 )

but half flip is not

torus2.rotate(o, x, 90)
testNotEqual(torus, torus2 )

pnt is the center of torus and dir is the normal direction. The default is o, z. Starting with default and rotating 90 around x-axis is the same as indicating y-axis as the initial normal direction.

torus2 = torus.copy()
torus2.rotate(o, x, 90)
testEqual(torus2,  Part.makeTorus(20, 5, o, y))