3

I am using Autodesk Fusion 360 to model a 3D part (see figure below), which I can then export and save as either a .step, .iges, .sat or .smt file.

What I am trying to achieve is to convert this part into a 3D numpy array in Python. Every element of the array will be 0 or 1 to indicate if there is solid material in that position or no material at all (air).

For example, if my object has the dimensions of the figure, each element of an array of size 100x100x50 would represent a volume of 1 mm3 of the object. All the light blue little cubes will have a value of 1 to show that there is solid material at this position, while the red cube will have a value of 0 to indicate that this space does not consist of solid material.

enter image description here

Could this be done using FreeCAD APIs? Or is there any other way to import the .step/.iges/.sat/.smt file in Python and convert/parse it to create the required array?

DimP
  • 216
  • 3
  • 9

3 Answers3

1

I have finally found a way that works for me and might actually explain better what I have been trying to achieve.

Apparently, FreeCAD has an option where after you have activated the "Points" workbench, you can choose to convert your object into a "point cloud". Each point does not have any mass and the entire new point cloud structure can be exported into a space-separated '.asc' file.

After that, it is trivial to import this into Python numpy arrays. I have personally used a voxel-based representation to visualise the imported object in Python, which can be done using the latest matplotlib or mayavi (these are the two I have tried at least).

DimP
  • 216
  • 3
  • 9
0

Split Part into little parts is possible, following example in /Mod/Part/BOPTools/SplitFeatures.py. But it is not ready to use for your needs, and requires time to adopt. But definitely it is possible to split the part into many parts of any shape you like: https://www.freecadweb.org/wiki/Part_Slice

Then you may use this code to build a numpy array:

import FreeCAD
import Part
import numpy as np

# Creating sample parts
solid_ = Part.makeBox(10, 10, 10)
shell_ = Part.makeShell(solid_.Shells)
part_compound = [solid_, shell_]

# Generate numpy array
result = []
for part in part_compound:
    result = [*result, [part.CenterOfMass.x,
                        part.CenterOfMass.y,
                        part.CenterOfMass.z,
                        isinstance(part, Part.Solid)]]
print(np.array(result))

This will result an array, where each part's center of mass will be denoted, by its x,y,z and fourth element will be 1 if those part is solid, 0 otherwise.

Code is compatible with Python 3.6 only, so use a docker image: https://github.com/ZhukovGreen/docker-freecad-cli

zhukovgreen
  • 1,551
  • 16
  • 26
  • The `*result` gives me an error. On top of that, I think your code will give me the centre of mass for the entire part. I want to first segment the part in the small teal cubes you can see in OP and then get an array of points representing each of them. – DimP Oct 25 '17 at 14:16
  • @DimP I think the reason of error is that you use different version of python. Mine is 3.6 (https://github.com/ZhukovGreen/docker-freecad-cli). – zhukovgreen Oct 25 '17 at 14:32
  • @DimP I am not sure I understand your idea behind `small teal cubes` and `array of point representing each of them`. If you have a cube 1 by 1, then in order to describe it's position it is enoug to give a Mass center coordinates – zhukovgreen Oct 25 '17 at 14:34
  • That's right. However, the 1x1 cubes do not exist for now. All I have is the grey object you can see in the figure. I need to segment that into the cubes first. – DimP Oct 25 '17 at 15:54
0

you can check if a point lies inside of solid with:

solid_shape.isInside(point:App.Vector, tolerance:float, on_boundary_is_inside:bool)

example:

import numpy as np
import FreeCAD as App
import Part

num_pts = 50

shape = Part.makeSphere(1)  # radius
bb = shape.BoundBox
x = np.linspace(bb.XMin, bb.XMax, num_pts)
y = np.linspace(bb.YMin, bb.YMax, num_pts)
z = np.linspace(bb.ZMin, bb.ZMax, num_pts)

mesh_x = np.array([[x] * num_pts] * num_pts).transpose(0, 1, 2)
mesh_y = np.array([[y] * num_pts] * num_pts).transpose(2, 0, 1)
mesh_z = np.array([[z] * num_pts] * num_pts).transpose(1, 2, 0)

mesh = np.array([mesh_x.flatten(), mesh_y.flatten(), mesh_z.flatten()]).T
bool_array = np.array([shape.isInside(App.Vector(p), 0.000001, False) for p in mesh])

v_r = float(sum(bool_array)) / float(len(bool_array))
v_r   # estimation of Volumeratio
Lo L
  • 21
  • 3