[request] coordinate api as python iterable across types

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
heda
Veteran
Posts: 1348
Joined: Sat Dec 12, 2015 5:49 pm

[request] coordinate api as python iterable across types

Post by heda »

currently the different coordinate representations have differences in behaviour,
it would be nice if that was harmonized and also that all of them worked as iterables,
or had a method like .totuple() or similar.

it is largely just a nice to have that imho on occasion would allow for easier to read code,
with the added benefit that one does not have to remember what works for which type.

Code: Select all

>>> vector
Vector (1.0, 2.0, 3.0)
>>> x, y, z = vector                                          # nice
>>> vertex
<Vertex object at 0x55879787b140>
>>> x, y, z = vertex                                          # oops
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: cannot unpack non-iterable Part.Vertex object
>>> x, y, z = vertex.Point                                    # works, but why have to put .Point
>>> x, y, z = vertex.X, vertex.Y, vertex.Z                    # verbose
>>> 
also shows that vertex is a coordinate related object
that does not render the coordinates, would be nice if it did.

another item is the printed precision, it would be nice if that could be configurable.
similar to https://docs.scipy.org/doc/numpy-1.14.0 ... tions.html

putting all of this out there in hopes that someone will take it on.

an overview (not claiming that it is complete...)

Code: Select all

>>> v = App.Vector(1,2,3)
>>> v
Vector (1.0, 2.0, 3.0)
>>> tuple(v)
(1.0, 2.0, 3.0)

>>> import Part
>>> Part.Point()
<Point (0,0,0) >

>>> p = Part.Point(1,2,3)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: Point constructor accepts:
-- empty parameter list
-- Point
-- Coordinates vector

>>> p = Part.Point((1,2,3))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: Point constructor accepts:
-- empty parameter list
-- Point
-- Coordinates vector

>>> p = Part.Point(v)
>>> p
<Point (1,2,3) >

>>> tuple(p)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'Part.Point' object is not iterable

>>> Part.Vertex()
<Vertex object at 0x5587975b5620>

>>> vx = Part.Vertex(1,2,3)
>>> tuple(vx)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'Part.Vertex' object is not iterable

>>> vx.Point
Vector (1.0, 2.0, 3.0)

>>> tuple(vx.Point)
(1.0, 2.0, 3.0)

>>> import Draft

>>> Draft.Point()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: __init__() missing 1 required positional argument: 'obj'

>>> ptd = Draft.Point(1,2,3)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/tmp/.mount_FreeCARntfqs/usr/Mod/Draft/draftobjects/point.py", line 42, in __init__
    super(Point, self).__init__(obj, "Point")
  File "/tmp/.mount_FreeCARntfqs/usr/Mod/Draft/draftobjects/base.py", line 81, in __init__
    obj.Proxy = self
AttributeError: 'int' object has no attribute 'Proxy'

>>> ptd = Draft.Point((1,2,3))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/tmp/.mount_FreeCARntfqs/usr/Mod/Draft/draftobjects/point.py", line 42, in __init__
    super(Point, self).__init__(obj, "Point")
  File "/tmp/.mount_FreeCARntfqs/usr/Mod/Draft/draftobjects/base.py", line 81, in __init__
    obj.Proxy = self
AttributeError: 'tuple' object has no attribute 'Proxy'

>>> ptd = Draft.Point(v)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/tmp/.mount_FreeCARntfqs/usr/Mod/Draft/draftobjects/point.py", line 42, in __init__
    super(Point, self).__init__(obj, "Point")
  File "/tmp/.mount_FreeCARntfqs/usr/Mod/Draft/draftobjects/base.py", line 81, in __init__
    obj.Proxy = self
AttributeError: 'Base.Vector' object has no attribute 'Proxy'

>>> Draft.makePoint(1,2,3)
<Part::PartFeature>

>>> ptd = Draft.makePoint(1,2,3)
>>> ptd
<Part::PartFeature>

>>> tuple(ptd)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'FeaturePython' object is not iterable

>>> ptd.Shape.Vertex1
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Part.Shape' object has no attribute 'Vertex1'

>>> ptd.Shape.Vertexes
[]

>>> ptd.Shape.ShapeType
Traceback (most recent call last):
  File "<input>", line 1, in <module>
Base.FreeCADError: cannot determine type of null shape

>>> ptd.Shape.TypeId
'Part::TopoShape'
>>> ptd.Shape
<Shape object at 0x558797bf3280>
>>> ptd.Shape.Content
''

>>> ptd.Vector
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'FeaturePython' object has no attribute 'Vector'

>>> ptd.Point
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'FeaturePython' object has no attribute 'Point'


>>> import Mesh

>>> ptm = Mesh.MeshPoint()
>>> ptm = Mesh.MeshPoint(1,2,3)
>>> ptm
MeshPoint (1, 2, 3)

>>> tuple(ptm)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'Mesh.MeshPoint' object is not iterable

>>> ptm.Vector
Vector (1.0, 2.0, 3.0)
>>> 

suppose sketch point belongs here as well, but have not listed that one here, maybe there are even more.
User avatar
onekk
Veteran
Posts: 6146
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: [request] coordinate api as python iterable across types

Post by onekk »

Code: Select all

>>> Draft.makePoint(1,2,3)
<Part::PartFeature>

>>> ptd = Draft.makePoint(1,2,3)
>>> ptd
<Part::PartFeature>

>>> tuple(ptd)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'FeaturePython' object is not iterable

This is correct, not a problem at all.

You invoked a make.... that generally generate a DocumentObject, i.e an objcet that will be visualized and put in the final document.

It is a Visualization object, not a "Geometry entity" in fact it has a Shape property, that retains the geometry information:

Code: Select all

"""example_script
     
   Author: Carlo Dormeletti
   Copyright: 2021
   Licence: CC BY-NC-ND 4.0 IT 
"""

import FreeCAD
from FreeCAD import Placement, Rotation, Vector
import Part
import Draft

DOC_NAME =  "test_gen"

DOC = FreeCAD.newDocument(DOC_NAME)

obj = Draft.makePoint(1,2,3)
print(dir(obj))

print(obj.TypeId)

print(obj.PropertiesList)

print(obj.Placement)


DOC.recompute()

Only thing that I see is that in the Exposed property of the comboview there is no Shape that apparently is present in the class definition, but in the code at:

https://github.com/FreeCAD/FreeCAD/blob ... e_point.py

You will see that is not assigned, but also that Placement is not assigned, this is the PropertyList

['ExpressionEngine', 'Label', 'Label2', 'Placement', 'Proxy', 'Shape', 'Visibility', 'X', 'Y', 'Z']

I suppose that instead of creating a "special object" to hold the entity "Point" as described in OCCT as:

https://dev.opencascade.org/doc/occt-7. ... ct_modat_5

0D entity, in other word a point has no dimension.

Some useful readings

https://wiki.freecadweb.org/Part_Part2DObject

https://wiki.freecadweb.org/Part_TopoShape


I agree that is confusing to have a Shape Property for a thing that has "by definition" no shape, and it is only a "place in 3d", and has "no dimensions", but that is.

In Fact Draft.Point is used mostly to visualize a point, this could be derived from the parameters passed to the method :

Code: Select all

def make_point(X=0, Y=0, Z=0, color=None, name = "Point", point_size= 5):
    """ makePoint(x,y,z ,[color(r,g,b),point_size]) or
        makePoint(Vector,color(r,g,b),point_size]) -

in fact in https://github.com/FreeCAD/FreeCAD/blob ... s/point.py

you will se that Placement is Hidden explicitly and the Shape is put to Part.Vertex(App.Vector(0, 0, 0))

Code: Select all


        obj.setPropertyStatus('Placement', 'Hidden')

    def execute(self, obj):
        import Part
        shape = Part.Vertex(App.Vector(0, 0, 0))
        obj.Shape = shape
        obj.Placement.Base = App.Vector(obj.X.Value,
                                        obj.Y.Value,
                                        obj.Z.Value)
Strange thing is that it seems that Placement Base is assigned using point coordinates, but is not reflected in the Draft.

Maybe this thing has to be investigated.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
Post Reply