Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Need help, or want to share a macro? Post here!
PaulG
Posts: 28
Joined: Mon Feb 25, 2019 5:38 pm

Re: Bug in Part.makeRevolution()

Postby PaulG » Mon May 13, 2019 8:40 pm

wmayer wrote:
Sun May 12, 2019 9:34 am
git commit f6ee90557
Thanks for changing the handling of the ShapeType argument. I've played with it some and I think it makes more sense this way.

Am I correct in thinking that the Shape revolve() method, which returns a Face, actual uses Part.makeRevolution()? I have had no luck grepping code to find where Shape class methods are implemented. (Is this done in Python or cpp?)

I can get (almost) the revolve() method result using Part.makeRevolution():

Code: Select all

import Part
from FreeCAD import Vector

o = Vector(0, 0, 0) 
x = Vector(1, 0, 0) 
y = Vector(0, 1, 0) 
z = Vector(0, 0, 1) 

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

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

b = arc.toShape().revolve(o, z, 360)
b.ShapeType  #Face

0 == len( a.cut(b).Vertexes )  #True
0 == len( a.cut(b).Faces    )  #True
0 == len( a.cut(b).Solids   )  #True

0 == len( b.cut(a).Vertexes )  #True
0 == len( b.cut(a).Faces    )  #True
0 == len( b.cut(a).Solids   )  #True

a.isEqual(b)  #False    isEqual() seems fussy
I think it would also be nice for the revolve() method to support the ShapeType argument so that it could be used to easily create a solid. I'm not intending to suggest a large amount of work, I'm think it would be trivial if Part.makeRevolution() is already being used.
chrisb
Posts: 15164
Joined: Tue Mar 17, 2015 9:14 am

Re: Bug in Part.makeRevolution()

Postby chrisb » Mon May 13, 2019 8:46 pm

Moved to Python scripting and macros forum.
wmayer
Site Admin
Posts: 14044
Joined: Thu Feb 19, 2009 10:32 am

Re: Bug in Part.makeRevolution()

Postby wmayer » Tue May 14, 2019 6:28 am

Am I correct in thinking that the Shape revolve() method, which returns a Face, actual uses Part.makeRevolution()?
No. In the end Shape revolve() uses BRepPrimAPI_MakeRevol that accepts a shape as input and Part.makeRevolution() accepts a GeomCurve.

BRepPrimAPI_MakeRevol is the more advanced method because it accepts a wider range of objects:
  1. for a vertex it creates an edge
  2. for an edge it creates a face
  3. for a wire it creates a shell
  4. for a face it creates a solid
  5. for a shell it creates a compound solid
PaulG
Posts: 28
Joined: Mon Feb 25, 2019 5:38 pm

Re: Bug in Part.makeRevolution()

Postby PaulG » Tue May 14, 2019 2:55 pm

Thanks! Yes I see that is more advanced in some respects. But I could sure see use for object methods that can handle some of the messy detail like, for example, having the option to go from edges to faces, or from edges to solids. Or separate methods for different results, with a good naming convention. I seem to get into a mess trying to do stuff that should be simple, and it ends up not feeling like an object oriented language. I'm more comfortable with a procedural language so that's not a problem, I am just surprised.
PaulG
Posts: 28
Joined: Mon Feb 25, 2019 5:38 pm

Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Postby PaulG » Fri May 17, 2019 7:26 pm

(I've adjusted the subject line to reflect more recent content)
wmayer wrote:
Tue May 14, 2019 6:28 am
... Shape revolve() uses BRepPrimAPI_MakeRevol that accepts a shape as input and Part.makeRevolution() accepts a GeomCurve.

BRepPrimAPI_MakeRevol is the more advanced method because it accepts a wider range of objects:
  1. for a vertex it creates an edge
  2. for an edge it creates a face
  3. for a wire it creates a shell
  4. for a face it creates a solid
  5. for a shell it creates a compound solid
[Using FreeCAD 0.18.1 and 0.19 16786 (Git) on Mint 18.1, python 2]

I've been working through examples of all of these, trying to get to a solid sphere at the end. I have had luck with Part.makeRevolution(), and revolve 1/ (but fails trying to revolve a circle), 2/ (with some possible bugs), and 3/. For 4/ and 5/ either there are some bugs, or I misunderstand something, or both.

There are two general sorts of problems. One is that revolving a disk around an axis across its plane should result in a sphere, and it does not. The other is that closed objects are not always being identified as such. That is, constructions that should give closed objects, and appear to achieve that, do not report that the object is closed.

Code: Select all

import Part
from FreeCAD import Vector

o = Vector(0,0,0)
x = Vector(1,0,0)
y = Vector(0,1,0)
z = Vector(0,0,1)

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

arcShapeWire = Part.Wire(arcShapeEdge)
arcShapeWire.ShapeType  #Wire
0/ Part.makeRevolution works to give a solid

Code: Select all

s0 =Part.makeRevolution(arc, arc.FirstParameter, arc.LastParameter, 
                 360, o, z, Part.Solid)
Part.show(s0)
s0.ShapeType  #Solid
s0.isClosed() #True
s0.isValid()  #True
1/ for a vertex it creates an edge.
This works to get to a solid if the vertex is rotated 180 degrees to give a half circle, and that is rotated 360 degrees to give a sphere:

Code: Select all

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

s1 = Part.makeSolid(Part.makeShell([zp.revolve(o,z,180).revolve(o, x, 360)]))
Part.show(s1)
s1.ShapeType  #Solid
s1.isClosed() #True
s1.isValid()  #True
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. However, the problem here is more than anomolies suggested in the doc. It fails totally:

Code: Select all

#revolve point to get circle (Edge)
zc =zp.revolve(o,z,360)
zc.ShapeType  #Edge
zc.isClosed() #True
zc.isValid()  #True

#revolve Edge to get sphere (Face). Does not work, around neither x nor y axis.
#zs = zc.revolve(o, y, 180)
zs = zc.revolve(o, x, 180)
zs.ShapeType  #Face
zs.isClosed() #False   
zs.isValid()  #False
Part.show(zs) # shows nothing
2/ for an edge it creates a face.
This works to get to a solid (but isClosed() seems wrong):

Code: Select all

zz = arcShapeEdge.revolve(o, z, 360)
Part.show(zz)
zz.ShapeType  #Face
zz.isClosed() #False #Looks like a BUG. The face is the closed surface of a sphere.
zz.isValid()  #True
s2 = Part.makeSolid(Part.makeShell([zz]))
s2.ShapeType   #Solid
s2.isClosed()  #True
s2.isValid()   #True
len(s2.Solids) # 1
Part.show(s2)
3/ for a wire it creates a shell.
This works to get to a solid:

Code: Select all

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

s3 =  Part.makeSolid(ar)
Part.show(s3)
s3.ShapeType  #Solid
s3.isClosed() #True
s3.isValid()  #True
len(s3.Solids) # 1

4/ for a face it creates a solid

Code: Select all

zC = Part.Face(Part.Wire(Part.Circle(o,z,10).toShape()))
Part.show(zC)  # closed disk
zC.ShapeType   #Face
zC.isClosed()  #False (BUG I think)  Maybe the source of following problems
zC.isValid()   #True
s4 =zC.revolve(o, x, 180)  # x or y should work, but next fails for both
s4.ShapeType   #Solid
s4.isClosed()  #True
s4.isValid()   #False  no doubt this indicates a problem
Part.show(s4)  # BUG still a flat disk

#try with a closed outline
zC = Part.Shape([arc, Part.LineSegment(-10*z, 10*z)])
zC.ShapeType   #Compound
zC.isClosed()  #False   # BUG this should be closed
zC.isValid()   #True
zF = Part.makeFilledFace(zC)  #Error creating object
s4a =zC.revolve(o, z, 360)
s4a.ShapeType   #Compound   
s4a.isClosed()  #False
s4a.isValid()   #True
Part.show(s4a)  #  looks like a sphere but hollow
Part.show(s4a.cut(Part.makeBox(10,10,10)) ) #cutout shows hollow

s4b = Part.makeSolid(s4a)  #Part.OCCError: Creation of solid failed: No shells or compsolids found in shape

s4b = Part.Solid(s4a)  #Part.OCCError: Creation of solid failed: No shells or compsolids found in shape
5/ for a shell it creates a compound solid

This fails

Code: Select all

Part.makeShell(Part.Face(Part.Wire(Part.Circle(o,z,10).toShape())))
#TypeError: PyCXX: Error creating object
but this works

Code: Select all

z5 = Part.makeShell([Part.Face(Part.Wire(Part.Circle(o,z,10).toShape()))])
z5.ShapeType   #Shell
z5.isClosed()  #False   seems like a BUG. This is a closed disk
z5.isValid()   #True
Part.show(z5)  # displays  closed disk
However, revolving around x or y give the same bad result.
(Revolves ok around z but that just gives a CompSolid but disk still.)

Code: Select all

s5 = z5.revolve(o, x, 180)
s5.ShapeType   #'CompSolid
s5.isClosed()  #True
s5.isValid()   #False
Part.show(s5)  #  displays a disk, as if rotating around z  BUG?
chrisb
Posts: 15164
Joined: Tue Mar 17, 2015 9:14 am

Re: Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Postby chrisb » Fri May 17, 2019 9:18 pm

I'm not sure about doing this from python, but in the GUI you don't revolve a circle to get a sphere, you use a half circle, to omit self intersections.
PaulG
Posts: 28
Joined: Mon Feb 25, 2019 5:38 pm

Re: Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Postby PaulG » Fri May 17, 2019 11:48 pm

I thing the underlying code for the construction is the same for scripts as it is for the GUI. Is using a half circle something that is imposed somehow in the GUI, or something you know from experience?
chrisb
Posts: 15164
Joined: Tue Mar 17, 2015 9:14 am

Re: Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Postby chrisb » Sat May 18, 2019 5:14 am

In Part workbench simply nothing happens, CheckGeometry with BOPCheck enabled shows errors.
In PartDesign workbench an error popup is shown "Revolve axis intersects the sketch".
PaulG
Posts: 28
Joined: Mon Feb 25, 2019 5:38 pm

Re: Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Postby PaulG » Sat May 18, 2019 7:11 pm

chrisb wrote:
Sat May 18, 2019 5:14 am
In Part workbench simply nothing happens, CheckGeometry with BOPCheck enabled shows errors.
In PartDesign workbench an error popup is shown "Revolve axis intersects the sketch".
I see. PartDesign workbench is smart enough to catch the problem and report to the user that this has to be done a different way. Part workbench has the same behaviour as I get scripting. You call it "simply nothing happens" and I call it an error or bug. It removes the circle that was displaying before the operation, attempts to display an invalid object and fails leaving a blank display, and leaves an invalid object in the model tree. Most users would probably be smart enough to undo and have a cleaner document.

I guess I was just expecting Part to be a bit smarter, either successfully do the revolution or throw an error.
chrisb
Posts: 15164
Joined: Tue Mar 17, 2015 9:14 am

Re: Part.makeRevolution() and Shape revolve() - bugs or misunderstandings

Postby chrisb » Sat May 18, 2019 10:34 pm

PaulG wrote:
Sat May 18, 2019 7:11 pm
You call it "simply nothing happens" and I call it an error or bug.
That's not what I call it, that's what happens. If this is an error is another question and you may well be right. But it could also be called a feature request to react smarter to faulty input.