0
$\begingroup$

I working on python script that add text label on bottom of the dental 3d model of teeth+gums and strugling with some issues. On input script has .stl files of 3d dental models (thay were previously created in special software). Bottom of this dental 3d models can has one or more cavities/impressions (this done for material economy during 3d printing). Script must determine the largest flat area

largest flat area

of the bottom of every model and place a engrave text on it. This text should be centered on previously mantioned largest flat area of the model. This text should not go out of borders of model (there should be some space between text and border of model). Size of this text should adjust size of this flat area. Output is also .stl files with 3d models. Ideal output result: enter image description here

As reference for how to realize it in blender I use this video: https://www.youtube.com/watch?v=lL7OBZ6AIVA - I use 3d model of text and apply Boolean Modifier with Diference mode to get engrave text. Also I use ChatGPT and some of my superficial knowledge of Python.

Problems that I have:

1)I don't know how to automaticaly position text as on photo. In this code for a specific one model I play with rotation and delta rotation of the text, but I understand that there must be easier way to do it.

2)It not always detect arear that I want to have label on properly, sometimes it is on some other surface. enter image description here

3)Depth of engrave is to small. enter image description here

Here is a link for models that I use for testing: https://drive.google.com/file/d/1St-oi0KzBmv_pf4uqcc8CXOxGc3_7pB5/view?usp=sharing Could, please, someone review this code and help with it? P.S. Sorry for my bad english)

import bpy
import os

# Delete default cube
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects['Cube'].select_set(True)
bpy.ops.object.delete()

# Get the current directory
current_directory = os.getcwd()

# Create a directory to save the labeled models if it doesn't exist
labeled_directory = os.path.join(current_directory, 'Result')
os.makedirs(labeled_directory, exist_ok=True)

# Get all .stl files in the current directory
stl_files = [file for file in os.listdir(current_directory) if file.lower().endswith('.stl')]

for stl_file in stl_files:
    # Import the STL model
    bpy.ops.import_mesh.stl(filepath=os.path.join(current_directory, stl_file))

    # Get the imported object
    imported_obj = bpy.context.selected_objects[0]

    # Find the largest flat surface
    max_area = 0
    max_face = None

    for face in imported_obj.data.polygons:
        face_area = face.area

        if face_area > max_area:
            max_area = face_area
            max_face = face

    if max_face is not None:
        # Create a text object
        bpy.ops.object.text_add()
        text_obj = bpy.context.object
        text_obj.data.body = "Hello"

        # Set font size
        text_obj.data.size = 0.2

        # Change horizontal and vertical alignment to Center
        text_obj.data.align_x = 'CENTER'
        text_obj.data.align_y = 'CENTER'

        # Convert text field to mesh
        bpy.ops.object.convert(target='MESH')

        # Set origin to center of the text mesh
        bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='BOUNDS')

        # Rotate the text
        text_obj.rotation_euler = (0, -0.26, 0)
        
        # Rotate the text
        text_obj.delta_rotation_euler = (-1.86, -1.33, 0.2) 

        # Add Solidify modifier to extrude the text
        bpy.ops.object.modifier_add(type='SOLIDIFY')
        solidify_modifier = text_obj.modifiers['Solidify']
        solidify_modifier.thickness = 0.3

        # Apply the Solidify modifier
        bpy.ops.object.modifier_apply(modifier=solidify_modifier.name)

        # Calculate the scale factor to fit the text mesh within the face
        text_dimensions = text_obj.dimensions
        max_face_dimensions = max_face.center - imported_obj.location

        scale_factor = min(max_face_dimensions.x / text_dimensions.x, max_face_dimensions.y / text_dimensions.y)
        text_obj.scale *= scale_factor

        # Calculate the position of the text mesh at the center of the face
        text_position = max_face.center + imported_obj.location
        text_obj.location = text_position

        # Apply boolean modifier to the imported object with difference operation
        bpy.ops.object.select_all(action='DESELECT')
        imported_obj.select_set(True)
        text_obj.select_set(True)
        bpy.context.view_layer.objects.active = imported_obj
        bpy.ops.object.modifier_add(type='BOOLEAN')
        bool_modifier = imported_obj.modifiers.new(name='Difference', type='BOOLEAN')
        bool_modifier.operation = 'DIFFERENCE'
        bool_modifier.object = text_obj

        # Apply the boolean modifier
        bpy.ops.object.modifier_apply(modifier=bool_modifier.name)

        # Delete the text object
        bpy.ops.object.select_all(action='DESELECT')
        text_obj.select_set(True)
        bpy.ops.object.delete()

        # Save the labeled model as STL
        labeled_file = os.path.join(labeled_directory, f"Labeled_{stl_file}")
        bpy.ops.export_mesh.stl(filepath=labeled_file)

    # Delete the imported object
    bpy.ops.object.select_all(action='DESELECT')
    imported_obj.select_set(True)
    bpy.ops.object.delete()

print("Script executed successfully!")
$\endgroup$

1 Answer 1

0
$\begingroup$

I have a solution that leads to the following result (margin of 0.1), only highlighted in red for better visibility: enter image description here

Here is the code https://pastebin.com/qVxzmvnA. There are some Parameters that can be adjusted to get better results.

Hints

  • A smaller margin will sometimes yield a better result. Margin of 0.03 from the above example enter image description here
  • The console of blender should be shown to monitor the process.
    enter image description here Which will look something like this: enter image description here

How does it work

  1. The polygon get imported with blender .stl import operator.
  2. Since the polygon has many small faces, it joints all faces with a given angle into one big face. Using the decimate modifier of blender.
  3. Then the largest area is retrieved. Since there are some coasting in the face. They will be cut off, and we get a good base to work with.
  4. Now we can convert this 3d flat surface to a 2d polygon to ease the computation.
  5. The largest interior rectangle with respect to the ratio is computed for different angles. Smaller angel steps will increase computing time because more rectangles have to be calculated. More on largest interior rectangle: here and here.
  6. The best rectangle of all is chosen and converted back to 3d.
  7. The text get moved, scaled, rotated inside the rectangle.
  8. The text get engraved into the object using the boolean modifier of blender.
  9. The finished result get exported with blender .stl export operator.
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .