Obtaining data from FacesValue Speckle (Python)

Hi,

I uploaded an object from Grasshopper to speckle.xyz, and received it in python (specklepy), I want to get the data from the category named “EdgesValue”, please see attached photo:


Here’s my code for obtaining data from “EdgesValue”:

received_base = operations.receive(obj_id=“0a93c542d2d4b42b14c5631c4565156c”,

remote_transport=transport)

data = received_base[“@{0}”][0][“EdgesValue”]

print(data)

However, it doesnot work. Python seems not be able to find the key named “EdgesValue”:

Any help would be much appreciated!

Can you share the stream/commit with me? By DM if needed.

If not then, what does print( dir( received_base[“@{0}”][0] ) ) return

If internal to the EdgesValue list any of the members of that list also show a image then you may need to use @EdgesValue as the key

@ZhuoranJia I just quickly jumped into grasshopper to replicate to save you the exploration.

Indeed, the default behaviour of the SpeckleGH is that Brep definitions detach and chunk the content of the EdgesValue.

In this example, EdgesValue is not actually an attribute of the Brep object, but rather a dynamically computed property that is defined using the @property decorator - or in this case the equivalent in cSharp. Therefore, trying to access it with brepj['EdgesValue'] will raise a KeyError , because EdgesValue is not actually a dictionary key.

Instead, to access a computed property like EdgesValue , you need to use the regular attribute access syntax (Brep.EdgesValue ), rather than the dictionary-like syntax (Brep['EdgesValue'] ).

This is related to how we are decomposing and serializing Breps coming from Grasshopper, which detaches and chunks those values to handle them when very large.

There isn’t any way presently in the Speckle UI to distinguish these properties.

In python, you can distinguish object attributes vs object computed properties.

def list_properties(obj):
    attributes = []
    properties = []
    for member in dir(obj):
      if member.startswith('_'):
            continue
      if callable(getattr(obj, member)):
        continue
      if isinstance(getattr(type(obj), member, None), property):
        properties.append(member)
      else:
        attributes.append(member)

    print("Attributes:")
    for name in attributes:
        print(f"- {name}")
    print("Properties:")
    for name in properties:
        print(f"- {name} (computed)")

list_properties(gh_data)

which for Objects.Geometry.Brep

gives:

Attributes:
- Curve2D
- Curve3D
- Edges
- Faces
- IsClosed
- Loops
- Orientation
- Surfaces
- Trims
- Vertices
- applicationId
- area
- bbox
- id
- provenance
- speckle_type
- totalChildrenCount
- volume
Properties:
- Curve2DValues (computed)
- Curve3DValues (computed)
- EdgesValue (computed)
- FacesValue (computed)
- LoopsValue (computed)
- SurfacesValue (computed)
- TrimsValue (computed)
- VerticesValue (computed)
- displayValue (computed)
- units (computed)
1 Like

Hi Jonathon,

Thank you for your explanation! That problem is solved now. I have two more questions.

  1. Why there is no attributes such as Edges, Faces, and Vertices etc. shown in the speckle’s GH_data structure:

  2. For this project, My main purpose is to extract the vertices and faces data from the GH_data and use them for triangulation with Trimesh library, I can extract vertices data easily with
    vertices = received_base[“@{0}”][0][“Vertices”], however, when I try to extract faces data using faces = received_base[“@{0}”][0][“Faces”], it gives me the same thing:


    How can I get the actual data of each face (e.g., the vertices of each face, etc.)?

Thank you very much!

I presume you mean not shown in the UI.

Short answer: To save space.

The conversion from GH Brep to Speckle uses EdgesValue just for serialization/deserialization and is 1:1 with the values used for Edges and likewise Loops, Faces and Trims

As you can see in your python example, the attribute is present, but it isn’t in the speckl stream. It simply doesn’t exist. The frontend UI only shows the raw Speckle data as far as it can. The data tree in the UI doesn’t work like the Speckle Connectors or Specklepy as it doesn’t translate those values back into the geometric primitives.

Longer answer: To save space.

e.g. The Vertices property is a List of Points which makes sense in terms of what they are computational, whereas VerticesValue is a List of double values. This makes it straightforward for Speckle to detach, chunk and then serialize the parent object - again related to the Decomposition API | Speckle Docs

you can access the Vertices and the Faces in the same way as I demonstrated in my last post.

print(gh_data.Vertices)

[Point(x: 0.0, y: 0.0, z: -1000.0, id: None, speckle_type: Objects.Geometry.Point),
 Point(x: 0.0, y: 0.0, z: 1000.0, id: None, speckle_type: Objects.Geometry.Point)]

print(gh_data.VerticesValue)

[1, 0.0, 0.0, -1000.0, 0.0, 0.0, 1000.0]

print(gh_data.FacesValue)

[4, 0, 0, 0, 0]

print(gh_data.Faces)

[BrepFace(id: None, speckle_type: Objects.Geometry.BrepFace, totalChildrenCount: None)]

Here you can see how the Vertices and Faces are more tangible than the VerticesValue and FacesValue

And to interrogate a face using the method above:

list_properties(gh_data.Faces[0])

Attributes:
- LoopIndices
- OrientationReversed
- OuterLoopIndex
- SurfaceIndex
- applicationId
- id
- speckle_type
- totalChildrenCount
Properties:
- units (computed)

I don’t know how familiar you are with Brep geometry, but whereas there is a clear relationship between Vertices and Faces in the displayValue mesh Speckle stores for objects, the same is not true for Breps. As you see the properties of a Face are the Brep Loops.

tldr;
To answer your question directly, you cannot get the vertices of each face in the way you describe for Brep Faces as if they were Mesh Faces.

1 Like

Thank you very much for your answer!

1 Like