From 0098f2bde109b62d3c8e704c1eb827fdf929945a Mon Sep 17 00:00:00 2001 From: Vijai Kumar S Date: Wed, 15 May 2024 02:01:02 +0530 Subject: [PATCH] First batch of python examples --- SDK/Examples/Python/3mf_convert.py | 61 ++++++++++ SDK/Examples/Python/add_triangle.py | 25 ++++ SDK/Examples/Python/beam_lattice.py | 65 ++++++++++ SDK/Examples/Python/color_cube.py | 89 ++++++++++++++ SDK/Examples/Python/create_components.py | 60 +++++++++ SDK/Examples/Python/create_cube.py | 50 ++++++++ SDK/Examples/Python/extract_info.py | 30 +++++ SDK/Examples/Python/lib3mf_common.py | 148 +++++++++++++++++++++++ 8 files changed, 528 insertions(+) create mode 100644 SDK/Examples/Python/3mf_convert.py create mode 100644 SDK/Examples/Python/add_triangle.py create mode 100644 SDK/Examples/Python/beam_lattice.py create mode 100644 SDK/Examples/Python/color_cube.py create mode 100644 SDK/Examples/Python/create_components.py create mode 100644 SDK/Examples/Python/create_cube.py create mode 100644 SDK/Examples/Python/extract_info.py create mode 100644 SDK/Examples/Python/lib3mf_common.py diff --git a/SDK/Examples/Python/3mf_convert.py b/SDK/Examples/Python/3mf_convert.py new file mode 100644 index 000000000..53be1484a --- /dev/null +++ b/SDK/Examples/Python/3mf_convert.py @@ -0,0 +1,61 @@ +# An example to convert between 3MF and STL +import sys +from lib3mf_common import * + + +def find_extension(filename): + idx = filename.rfind('.') + if idx != -1: + return filename[idx:] + return "" + + +def convert(filename): + # Get a wrapper object + wrapper = get_wrapper() + + # Check version always + get_version(wrapper) + + extension = find_extension(filename).lower() + reader_name, writer_name, new_extension = "", "", "" + + if extension == ".stl": + reader_name = "stl" + writer_name = "3mf" + new_extension = ".3mf" + elif extension == ".3mf": + reader_name = "3mf" + writer_name = "stl" + new_extension = ".stl" + + if not reader_name: + print(f"Unknown input file extension: {extension}") + return -1 + + output_filename = filename[:-len(extension)] + new_extension + + model = wrapper.CreateModel() + reader = model.QueryReader(reader_name) + print(f"Reading {filename}...") + reader.ReadFromFile(filename) + + writer = model.QueryWriter(writer_name) + print(f"Writing {output_filename}...") + writer.WriteToFile(output_filename) + print("Done") + return 0 + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage:") + print("Convert 3MF to STL: python3 3mf_convert.py model.3mf") + print("Convert STL to 3MF: python3 3mf_convert.py model.stl") + else: + try: + result = convert(sys.argv[1]) + sys.exit(result) + except Exception as e: + print(str(e)) + sys.exit(1) \ No newline at end of file diff --git a/SDK/Examples/Python/add_triangle.py b/SDK/Examples/Python/add_triangle.py new file mode 100644 index 000000000..afaf16e4d --- /dev/null +++ b/SDK/Examples/Python/add_triangle.py @@ -0,0 +1,25 @@ +from lib3mf_common import * + +# Get wrapper +wrapper = get_wrapper() + +# Get version +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() + +# Initialize a mesh object +meshObject = model.AddMeshObject() + +# Now create 3 vertices +p1 = create_vertex_and_return_index(meshObject, 0, 0, 0) +p2 = create_vertex_and_return_index(meshObject, 0, 1, 0) +p3 = create_vertex_and_return_index(meshObject, 0, 0, 1) + +# Create a triangle with 3 positions +add_triangle(meshObject, p1, p2, p3) + +# Get a 3MF writer and write the single triangle +writer = model.QueryWriter("3mf") +writer.WriteToFile("triangle.3mf") diff --git a/SDK/Examples/Python/beam_lattice.py b/SDK/Examples/Python/beam_lattice.py new file mode 100644 index 000000000..b4a395184 --- /dev/null +++ b/SDK/Examples/Python/beam_lattice.py @@ -0,0 +1,65 @@ +# Beam Lattice example +from lib3mf_common import * + +# Get a wrapper object +wrapper = get_wrapper() + +# Check version always +get_version(wrapper) + +# Create a model and set name +model = wrapper.CreateModel() +mesh_object = model.AddMeshObject() +mesh_object.SetName("Beamlattice") + +# Modifiable size +fSizeX = 100.0 +fSizeY = 200.0 +fSizeZ = 300.0 + +# Define vertices (creates an array of lib3mf position objects) +vertices = [ + create_vertex(mesh_object, 0.0, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0.0, fSizeY, fSizeZ) +] + +# Define beam variables +r0 = 1.0 +r1 = 1.5 +r2 = 2.0 +r3 = 2.5 + +# Create a list of beams (strings are automatically converted to enums) +beams = [ + create_beam(2, 1, r0, r0, 'Butt', 'Butt'), + create_beam(0, 3, r0, r1, 'Sphere', 'Butt'), + create_beam(4, 5, r0, r2, 'Sphere', 'Butt'), + create_beam(6, 7, r0, r3, 'HemiSphere', 'Butt'), + create_beam(0, 1, r1, r0, 'HemiSphere', 'Butt'), + create_beam(5, 4, r1, r1, 'Sphere', 'HemiSphere'), + create_beam(2, 3, r1, r2, 'Sphere', 'Sphere'), + create_beam(7, 6, r1, r3, 'Butt', 'Butt'), + create_beam(1, 2, r2, r2, 'Butt', 'Butt'), + create_beam(6, 5, r2, r3, 'HemiSphere', 'Butt'), + create_beam(3, 0, r3, r0, 'Butt', 'Sphere'), + create_beam(4, 7, r3, r1, 'HemiSphere', 'HemiSphere') +] + +# Set geometry and beams +mesh_object.SetGeometry(vertices, []) +beam_lattice = mesh_object.BeamLattice() +beam_lattice.SetBeams(beams) +beam_lattice.SetMinLength(0.005) + +# Add mesh object to the model +model.AddBuildItem(mesh_object, wrapper.GetIdentityTransform()) + +# Write it out +writer = model.QueryWriter("3mf") +writer.WriteToFile("beamlattice.3mf") diff --git a/SDK/Examples/Python/color_cube.py b/SDK/Examples/Python/color_cube.py new file mode 100644 index 000000000..8cd7b0972 --- /dev/null +++ b/SDK/Examples/Python/color_cube.py @@ -0,0 +1,89 @@ +# Color cube example +from lib3mf_common import * + +# Get wrapper +wrapper = get_wrapper() + +# Get version +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() + +# Initialize a mesh object +mesh_object = model.AddMeshObject() +mesh_object.SetName("Colored Box") + +# Define cube size +fSizeX, fSizeY, fSizeZ = 100.0, 200.0, 300.0 + +# Create vertices +vertices = [ + create_vertex(mesh_object, 0.0, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0.0, fSizeY, fSizeZ) +] + +# Define triangles +triangles = [ + add_triangle(mesh_object, 2, 1, 0), + add_triangle(mesh_object, 0, 3, 2), + add_triangle(mesh_object, 4, 5, 6), + add_triangle(mesh_object, 6, 7, 4), + add_triangle(mesh_object, 0, 1, 5), + add_triangle(mesh_object, 5, 4, 0), + add_triangle(mesh_object, 2, 3, 7), + add_triangle(mesh_object, 7, 6, 2), + add_triangle(mesh_object, 1, 2, 6), + add_triangle(mesh_object, 6, 5, 1), + add_triangle(mesh_object, 3, 0, 4), + add_triangle(mesh_object, 4, 7, 3) +] + +# Set geometry +mesh_object.SetGeometry(vertices, triangles) + +# Define colors +color_group = model.AddColorGroup() +id_red = color_group.AddColor(wrapper.RGBAToColor(255, 0, 0, 255)) +id_green = color_group.AddColor(wrapper.RGBAToColor(0, 255, 0, 255)) +id_blue = color_group.AddColor(wrapper.RGBAToColor(0, 0, 255, 255)) +id_orange = color_group.AddColor(wrapper.RGBAToColor(255, 128, 0, 255)) +id_yellow = color_group.AddColor(wrapper.RGBAToColor(255, 255, 0, 255)) + +# Set triangle colors +sTriangleColorRed = create_triangle_color(color_group, id_red, id_red, id_red) +sTriangleColorGreen = create_triangle_color(color_group, id_green, id_green, id_green) +sTriangleColorBlue = create_triangle_color(color_group, id_blue, id_blue, id_blue) +sTriangleColor1 = create_triangle_color(color_group, id_orange, id_red, id_yellow) +sTriangleColor2 = create_triangle_color(color_group, id_yellow, id_green, id_orange) + + +# One-colored Triangles +mesh_object.SetTriangleProperties(0, sTriangleColorRed) +mesh_object.SetTriangleProperties(1, sTriangleColorRed) +mesh_object.SetTriangleProperties(2, sTriangleColorGreen) +mesh_object.SetTriangleProperties(3, sTriangleColorGreen) +mesh_object.SetTriangleProperties(4, sTriangleColorBlue) +mesh_object.SetTriangleProperties(5, sTriangleColorBlue) + +# Gradient-colored Triangles +mesh_object.SetTriangleProperties(6, sTriangleColor1) +mesh_object.SetTriangleProperties(7, sTriangleColor2) +mesh_object.SetTriangleProperties(8, sTriangleColor1) +mesh_object.SetTriangleProperties(9, sTriangleColor2) +mesh_object.SetTriangleProperties(10, sTriangleColor1) +mesh_object.SetTriangleProperties(11, sTriangleColor2) + +# Set object level property +mesh_object.SetObjectLevelProperty(sTriangleColorRed.ResourceID, sTriangleColorRed.PropertyIDs[0]) + +# Add build item and write to file +model.AddBuildItem(mesh_object, wrapper.GetIdentityTransform()) +writer = model.QueryWriter("3mf") +writer.WriteToFile("colorcube.3mf") diff --git a/SDK/Examples/Python/create_components.py b/SDK/Examples/Python/create_components.py new file mode 100644 index 000000000..d20bc5b3a --- /dev/null +++ b/SDK/Examples/Python/create_components.py @@ -0,0 +1,60 @@ +# An example that create multiple components using transformations +from lib3mf_common import * + +# Get wrapper +wrapper = get_wrapper() + +# Get version +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() +mesh_object = model.AddMeshObject() +mesh_object.SetName("Box") + +# Define the size of the box +fSizeX, fSizeY, fSizeZ = 10.0, 20.0, 30.0 + +# Create vertices +vertices = [ + create_vertex(mesh_object, 0, 0, 0), + create_vertex(mesh_object, fSizeX, 0, 0), + create_vertex(mesh_object, fSizeX, fSizeY, 0), + create_vertex(mesh_object, 0, fSizeY, 0), + create_vertex(mesh_object, 0, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0, fSizeY, fSizeZ) +] + +# Define triangles by vertices indices +triangle_indices = [ + (2, 1, 0), (0, 3, 2), (4, 5, 6), (6, 7, 4), + (0, 1, 5), (5, 4, 0), (2, 3, 7), (7, 6, 2), + (1, 2, 6), (6, 5, 1), (3, 0, 4), (4, 7, 3) +] + +# Create a list of triangles +triangles = [] +for v0, v1, v2 in triangle_indices: + triangles.append(add_triangle(mesh_object, v0, v1, v2)) + +# Set geometry to the mesh object after creating vertices and triangles +mesh_object.SetGeometry(vertices, triangles) + +# Adding components with different transformations +components_object = model.AddComponentsObject() +components_object.AddComponent(mesh_object, create_translation_matrix(0.0, 0.0, 0.0)) +components_object.AddComponent(mesh_object, create_translation_matrix(40.0, 60.0, 80.0)) +components_object.AddComponent(mesh_object, create_translation_matrix(120.0, 30.0, 70.0)) + +# Add the components object to the model as a build item +model.AddBuildItem(components_object, create_translation_matrix(0.0, 0.0, 0.0)) + +# Writing to files (3MF) +writer_3mf = model.QueryWriter("3mf") +writer_3mf.WriteToFile("components.3mf") + +# Dump to a STL file +writer_stl = model.QueryWriter("stl") +writer_stl.WriteToFile("components.stl") diff --git a/SDK/Examples/Python/create_cube.py b/SDK/Examples/Python/create_cube.py new file mode 100644 index 000000000..1e1da1bbc --- /dev/null +++ b/SDK/Examples/Python/create_cube.py @@ -0,0 +1,50 @@ +# Simple cube creation example +from lib3mf_common import * + +# Get a wrapper object +wrapper = get_wrapper() + +# Check version always +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() +mesh_object = model.AddMeshObject() +mesh_object.SetName("Box") + +# Define the size of the cube +fSizeX, fSizeY, fSizeZ = 100.0, 200.0, 300.0 + +# Create vertices +vertices = [ + create_vertex(mesh_object, 0, 0, 0), + create_vertex(mesh_object, fSizeX, 0, 0), + create_vertex(mesh_object, fSizeX, fSizeY, 0), + create_vertex(mesh_object, 0, fSizeY, 0), + create_vertex(mesh_object, 0, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0, fSizeY, fSizeZ) +] + +# Define triangles by vertices indices +triangle_indices = [ + (2, 1, 0), (0, 3, 2), (4, 5, 6), (6, 7, 4), + (0, 1, 5), (5, 4, 0), (2, 3, 7), (7, 6, 2), + (1, 2, 6), (6, 5, 1), (3, 0, 4), (4, 7, 3) +] + +# Create triangles +triangles = [] +for v0, v1, v2 in triangle_indices: + triangles.append(add_triangle(mesh_object, v0, v1, v2)) + +# Set geometry to the mesh object after creating vertices and triangles +mesh_object.SetGeometry(vertices, triangles) + +# Add build item with an identity transform +model.AddBuildItem(mesh_object, wrapper.GetIdentityTransform()) + +# Save the model to a 3MF file +writer = model.QueryWriter("3mf") +writer.WriteToFile("cube.3mf") diff --git a/SDK/Examples/Python/extract_info.py b/SDK/Examples/Python/extract_info.py new file mode 100644 index 000000000..3b9a06d91 --- /dev/null +++ b/SDK/Examples/Python/extract_info.py @@ -0,0 +1,30 @@ +# Extract info from a 3MF model +import sys +from lib3mf_common import * + + +def extract_info(file_path): + wrapper = get_wrapper() + model = wrapper.CreateModel() + + # Initialize a 3MF reader + read_3mf_file_to_model(model, file_path) + + # Print library version + get_version(wrapper) + + # Show meta data info + show_metadata_information(model.GetMetaDataGroup()) + + # Show slice stack info + show_slice_stack_information(model) + + # Show object info + show_object_information(model) + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python extract_info.py model.3mf") + sys.exit() + extract_info(sys.argv[1]) diff --git a/SDK/Examples/Python/lib3mf_common.py b/SDK/Examples/Python/lib3mf_common.py new file mode 100644 index 000000000..37b710d0c --- /dev/null +++ b/SDK/Examples/Python/lib3mf_common.py @@ -0,0 +1,148 @@ +import lib3mf +from lib3mf import get_wrapper + + +def create_vertex(_mesh, x, y, z): + position = lib3mf.Position() + position.Coordinates[0] = float(x) + position.Coordinates[1] = float(y) + position.Coordinates[2] = float(z) + _mesh.AddVertex(position) + return position + + +def create_vertex_and_return_index(_mesh, x, y, z): + position = lib3mf.Position() + position.Coordinates[0] = float(x) + position.Coordinates[1] = float(y) + position.Coordinates[2] = float(z) + vertex_index = _mesh.AddVertex(position) + return vertex_index + + +def add_triangle(_mesh, p1, p2, p3): + triangle = lib3mf.Triangle() + triangle.Indices[0] = p1 + triangle.Indices[1] = p2 + triangle.Indices[2] = p3 + _mesh.AddTriangle(triangle) + return triangle + + + +def get_version(wrapper): + major, minor, micro = wrapper.GetLibraryVersion() + print("Lib3MF version: {:d}.{:d}.{:d}".format(major, minor, micro), end="") + hasInfo, prereleaseinfo = wrapper.GetPrereleaseInformation() + if hasInfo: + print("-" + prereleaseinfo, end="") + hasInfo, buildinfo = wrapper.GetBuildInformation() + if hasInfo: + print("+" + buildinfo, end="") + print("") + + +# Show metadata information +def show_metadata_information(metadata_group): + count = metadata_group.GetMetaDataCount() + for i in range(count): + metadata = metadata_group.GetMetaData(i) + print(f"Metadata: {metadata.GetName()} = {metadata.GetValue()}") + + +# Show slice stack information +def show_slice_stack_information(model): + slice_stacks = model.GetSliceStacks() + while slice_stacks.MoveNext(): + slice_stack = slice_stacks.GetCurrentSliceStack() + print(f"Slice Stack: {slice_stack.GetResourceID()}") + + +# Show object information +def show_object_information(model): + object_iterator = model.GetObjects() + while object_iterator.MoveNext(): + obj = object_iterator.GetCurrentObject() + if obj.IsMeshObject(): + print(f"Mesh Object: {obj.GetResourceID()}") + elif obj.IsComponentsObject(): + print(f"Components Object: {obj.GetResourceID()}") + else: + print(f"Unknown Object: {obj.GetResourceID()}") + + +def read_3mf_file_to_model(model, file_path): + reader = model.QueryReader("3mf") + reader.SetStrictModeActive(False) + reader.ReadFromFile(file_path) + + +def create_translation_matrix(x, y, z): + matrix = lib3mf.Transform() + + # Default to identity matrix with translation + identity_matrix = [ + (1.0, 0.0, 0.0), # Row for X axis + (0.0, 1.0, 0.0), # Row for Y axis + (0.0, 0.0, 1.0), # Row for Z axis + (x, y, z) # Translation + ] + + # Fill the Fields with identity matrix values + for i in range(4): + for j in range(3): + matrix.Fields[i][j] = identity_matrix[i][j] + + return matrix + + +def convert_beam_string_to_enum(beam_mode): + beam_mode = str(beam_mode).lower() + if beam_mode == "butt": + return lib3mf.BeamLatticeCapMode.Butt + if beam_mode == "sphere": + return lib3mf.BeamLatticeCapMode.Sphere + if beam_mode == "hemisphere": + return lib3mf.BeamLatticeCapMode.HemiSphere + + +def create_beam(v0, v1, r0, r1, c0, c1): + beam = lib3mf.Beam() + beam.Indices[0] = v0 + beam.Indices[1] = v1 + beam.Radii[0] = r0 + beam.Radii[1] = r1 + beam.CapModes[0] = convert_beam_string_to_enum(c0) + beam.CapModes[1] = convert_beam_string_to_enum(c1) + return beam + +def create_triangle_color(color_group, color_id1, color_id2, color_id3): + triangle_properties = lib3mf.TriangleProperties() + triangle_properties.ResourceID = color_group.GetResourceID() + triangle_properties.PropertyIDs[0] = color_id1 + triangle_properties.PropertyIDs[1] = color_id2 + triangle_properties.PropertyIDs[2] = color_id3 + return triangle_properties + + +def convert_list_to_array(_list, _datatype): + _array_type = _datatype * len(_list) # Define the type of the array + _array = _array_type() # Create an instance of the array + + # Populate the array + for i, _list_entry in enumerate(_list): + _array[i] = _list_entry + + return _array + + +def vertex_array(_position_list): + return convert_list_to_array(_position_list, lib3mf.Position) + + +def triangle_array(_triangle_list): + return convert_list_to_array(_triangle_list, lib3mf.Triangle) + + +def beam_array(_beam_list): + return convert_list_to_array(_beam_list, lib3mf.Beam)