Community
Meshmixer
Welcome to Autodesk’s Meshmixer Forums. Share your knowledge, ask questions, and explore popular Meshmixer topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MeshMixer Scripting for repetive task

26 REPLIES 26
SOLVED
Reply
Message 1 of 27
Anonymous
8425 Views, 26 Replies

MeshMixer Scripting for repetive task

Hi there,

i get from a 3rd party software several STL-Files which i have to modify in MM.

Always the same steps:

 

1) open file 🙂

2) hollow with wall thickness 2.5 mm

3) horizontal plane cut about 1/3 of the model height from the bottom (model is plane and horizontaly aligned)

4) save/export to another directory

 

Takes a lot of time and is boring, too!

I think there should be a solution that a task will take all files from the import directory one by one, performing the operations with MM and finally save the new STLs in my output dir.

Is such a repetive task makeable with AppleScript or only with the MM API (python or C++) ?

We have iMacs as well as Windows-PCs

And, i would pay for that script of course if a solution is to time consuming.

 

Best regards and thanks in advance

Karim

Tags (3)
26 REPLIES 26
Message 2 of 27
MagWeb
in reply to: Anonymous

Yep, no problem for me to do it with mmApi and Python. Needs just some lines of code.

Stay tuned.

Do you prefer some file picker for import or do you want to process an input file (always with the same name and format) from a certain location?

Same for the export code: Some fixed output name, format and location or a variable dialog?

---

Do you have some basic Python coding skills to modify some source code (needs to setup mmApi) or do you prefer a readymade Mac application (.app) without need to setup Python and mmApi on each machine?

 

 



Gunter Weber
Triangle Artisan

Message 3 of 27
Anonymous
in reply to: MagWeb

Hi and thanks for your reply!

Yes, i do have some programing experience, doing some swift programming, thats why it is a shame that i can't do it by myself in a reasonable time.

What i did yesterday was to download all the GitHub stuff.

 

And i was playing around and found e.g. the open, save, planeCut, hollow and accept commands.

What i did not found was a kind of command reference for the mmApi, which would make things easier.

And also no way to give the planeCut command some arguments like angle or rotation or positioning the plane.

Same with the hollow command, e.g. wall-thickness parameter or so.

 

Again, many thanks for taking your time to get an solution

Karim

Message 4 of 27
Anonymous
in reply to: MagWeb

Sorry, didn't answer all questions.

i think we can leave it as easy as possible

 

a) inputFiles are always in the same location

b) script is performing the actions on each File in a do while loop or so.

c) files are renamed from "name" to "name_hollowed" in the same location

 

Best regards

Karim

 

Message 5 of 27
MagWeb
in reply to: Anonymous

There's some (not complete) documentation shipping with the download in distrib/documentation/python_html. Run index.html in your browser. In its mm.tool module section you find links to the available ToolStrings and most of the ToolParameters. 

 

The basic routine is:

1. launch a tool (e.g. Hollow):

mm.begin_tool(remote, "hollow")

2. set parameters if they aren't default (e.g. Hollow>Offset at 2.5  world units):

mm.set_toolparam(remote, "offsetDistanceWorld", 2.5)

- you need to add this line for each parameter to be changed.

 

3. some (not all)  tools (which come with buttons like UpdateHollow) need to be updated after a parameter was changed:

mm.tool_utility_command(remote, "update") 

4. accept the tool:

mm.accept_tool(remote)

--------

 

Here's a code building a tiny window in your screen's upper right. Hitting its Run button you can select an input file.

It automatically appends this object to an existing scene (You might simply open the default plane object), performs its hollowing at 2.5 , cutting at a third of its height and saves the file in the same format adding "_mod" to its name to the same directory as it was loaded from (to avoid an additional SaveTo dialog):

from Tkinter import *
from tkFileDialog   import askopenfilename, asksaveasfilename
import Tkinter as tk

import mmapi
from mmRemote import *
import mm

remote = mmRemote()
remote.connect()

thickness_hollow = 2.5

path_to_file = ""

def Load_File():
    path_to_file = askopenfilename(parent = root)
    if path_to_file is "":
        return
    else:
        mm.append_objects_from_file(remote,path_to_file)
        Hollow(path_to_file)

def Hollow(path_to_file):
    mm.begin_tool(remote, "hollow")
    mm.set_toolparam(remote, "offsetDistanceWorld", thickness_hollow)
    mm.tool_utility_command(remote, "update")    
    mm.accept_tool(remote)
    Cut(path_to_file)

def Cut(path_to_file):
    (fMin,fMax) = mm.get_selected_bounding_box(remote)
    cut_height = fMin[1] +  (fMax[1]-fMin[1])/3
    mm.begin_tool(remote, "planeCut")    
    mm.set_toolparam(remote, "origin", (0.0, cut_height, 0.0))
    mm.accept_tool(remote)
    Save_File(path_to_file)

def Save_File(path_to_file):
    path_out = path_to_file.split('.')
    save_path = path_out[0] + '_mod.' + path_out[1]
    mm.export_mesh(remote,save_path)
    
# Setup a tiny GUI window:    
root = Tk()
root.title("Hollow and Cut")
w = 240 
h = 30 
ws = root.winfo_screenwidth() 
x = ws - w
y = 0
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
root.attributes("-topmost", True)

buttonLoad = Button(root, text="Run", command = Load_File)
buttonLoad.pack()

def on_closing():
    remote.shutdown()
    root.destroy()    
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()

 



Gunter Weber
Triangle Artisan

Message 6 of 27
MagWeb
in reply to: MagWeb

Sorry, you posted while I was typing. If you want to process several files we would need to allow to load multiple files and apply the action on these. This needs to switch the objects.  Should be no problem.



Gunter Weber
Triangle Artisan

Message 7 of 27
MagWeb
in reply to: MagWeb

This one allows multiple input. It loads, processes, saves and deletes the objects in the scene one by one:

from Tkinter import *
from tkFileDialog   import askopenfilenames
import Tkinter as tk

import mmapi
from mmRemote import *
import mm

remote = mmRemote()
remote.connect()

thickness_hollow = 2.5

path_to_file = ""

def Load_File():
    input_files = askopenfilenames(parent = root)
    if input_files is "":
        return
    else:
        file_List = root.tk.splitlist(input_files)        
        for i in file_List:
            mm.append_objects_from_file(remote,i)
            path_to_file = i
            Hollow()
            Cut()
            Save_File(path_to_file)


def Hollow():
    mm.begin_tool(remote, "hollow")
    mm.set_toolparam(remote, "offsetDistanceWorld", thickness_hollow)
    mm.tool_utility_command(remote, "update")    
    mm.accept_tool(remote)
 

def Cut():
    (fMin,fMax) = mm.get_selected_bounding_box(remote)
    cut_height = fMin[1] +  (fMax[1]-fMin[1])/3
    mm.begin_tool(remote, "planeCut")    
    mm.set_toolparam(remote, "origin", (0.0, cut_height, 0.0))
    mm.accept_tool(remote)


def Save_File(path_to_file):
    path_out = path_to_file.split('.')
    save_path = path_out[0] + '_hollowed.' + path_out[1]
    mm.export_mesh(remote,save_path)
    cmd = mmapi.StoredCommands()
    cmd.AppendSceneCommand_DeleteSelectedObjects();
    remote.runCommand(cmd)
   
# Setup a tiny GUI window:    
root = Tk()
root.title("Hollow and Cut")
w = 240 
h = 30 
ws = root.winfo_screenwidth() 
x = ws - w
y = 0
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
root.attributes("-topmost", True)

buttonLoad = Button(root, text="Run", command = Load_File)
buttonLoad.pack()

def on_closing():
    remote.shutdown()
    root.destroy()    
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()


Gunter Weber
Triangle Artisan

Message 8 of 27
Anonymous
in reply to: MagWeb

Thank you so much for help!!!

I am just on the road, can test tomorrow morning , but what could be go wrong??

 

many many thanks!!

Karim

 

P.S: How do i start that script? if i copy and paste the code to a new .py File and start it with

python ./hollow_and_cut.py nothin happens. Do i have it to load inside MM?

Message 9 of 27
MagWeb
in reply to: Anonymous

Please check whether mmApi does its job first:

On WIN:

1. Open MM and load the bunny.

2. Go to your mmApi download directory. Within mm-api-master go to distrib/python and open test.py with python IDLE

3. IDLE should show the Shell and the Code windows. Give the focus to the code and run the code via menu:Run/RunModule.

>>> In MM the bunny should be cut in half

On MAC:

same procedure but in step two go to distrib/python_osx

 

Now if the bunny is cut via test.py:

Go to mm-api-master/python and copy the folder named "mm".

Paste it into mm-api-master/distrib/python (on WIN) or mm-api-master/distrib/python_osx (on MAC)

 

Now the .py codes using mmApi stored in mm-api-master/distrib/python (or mm-api-master/distrib/python_osx) should work.

 

To run the codes posted above create a new file in python IDLE and paste the code. Now running that Code via menu Run/RunModule you will be asked to save the file first. Save it to (name isn't important) mm-api-master/distrib/python (on WIN) or mm-api-master/distrib/python_osx (on MAC). Now the little Tkinter window should pop up. Use its Run button to load the objects and process them. The results will be stored in the same directory you loaded the files from.

 

 



Gunter Weber
Triangle Artisan

Message 10 of 27
Anonymous
in reply to: MagWeb

HI again, so i tried underMacOs Catalina.

The App isn't starting, tried already to change the rights with chmod 777, but the error message is still "can't be opened ". Also tried right mouse click, "Open"!

 

And your other Script hangs on writing the modified File back.

I attached a  screenshot to clarify and put a print in the pythonShellWindow.

The renamed File is perfect, but it didn't save to the directory.

 

I can test later on an iMac with HighSierra at home, maybe it will run there.

BG

Karim

 

 

Message 11 of 27
MagWeb
in reply to: Anonymous

mm.export_mesh(remote,save_path)

export only works on mesh files (I checked .obj and .stl). MIX instead can't work. It saves the scene instead of an object (including stuff like Complex objects, Pivots, Target ....)

If you really want to save to that special format we would need to use

mm.save_mix(remote, save_path)

For export one could solve that:

def Save_File(path_to_file):
    path_out = path_to_file.split('.')
    save_path = path_out[0] + '_hollowed.' + path_out[1]
    if path_out[1] == 'mix':
        mm.save_mix(remote, save_path)
    else:
        mm.export_mesh(remote,save_path)

But a mix may come with several objects. So for the processing part we would need to detect new objects and iterate through this list to do hollowing/cutting for each. Doable but maybe not the straight way. 

----

I tried the .app version on a different (Sierra) machine : Works fine here...

 



Gunter Weber
Triangle Artisan

Message 12 of 27
Anonymous
in reply to: MagWeb

STL is perfect for me, i need to print the modified files with Formlabs preform software.

I was testing with the bunny, that's why it doesn't work for me, sorry!

How can i choose all files to process with your script within a directory?

 

 

Message 13 of 27
Anonymous
in reply to: Anonymous

again me.

just tested with High Sierrra.

can't open the HollowCutApp either, but i can choose alle files at once with the HollowScript.

Don't know why this won't work with Catalina

Message 14 of 27
MagWeb
in reply to: Anonymous

Know about some tkinter issues on Catalina - but it's new for me that it doesn't allow multiple selections on an askopenfilenames dialog....

 

As an alternative you may try to use askdirectory instead. This version asks for a directory, loads all .obj and .stl files within that directory and saves to a subfolder "Hollowed":

import os

from Tkinter import *
from tkFileDialog   import askdirectory
import Tkinter as tk

import mmapi
from mmRemote import *
import mm

remote = mmRemote()
remote.connect()

thickness_hollow = 2.5

def Load_File():
    input_dir = askdirectory(parent = root)
if input_dir is "":
return
supported_extensions = ['obj','stl'] file_List = [fn for fn in os.listdir(input_dir)if any(fn.endswith(ext) for ext in supported_extensions)] for i in file_List: mm.append_objects_from_file(remote,input_dir+'/'+i) Hollow() Cut() Save_File(i, input_dir) def Hollow(): mm.begin_tool(remote, "hollow") mm.set_toolparam(remote, "offsetDistanceWorld", thickness_hollow) mm.tool_utility_command(remote, "update") mm.accept_tool(remote) def Cut(): (fMin,fMax) = mm.get_selected_bounding_box(remote) cut_height = fMin[1] + (fMax[1]-fMin[1])/3 mm.begin_tool(remote, "planeCut") mm.set_toolparam(remote, "origin", (0.0, cut_height, 0.0)) mm.accept_tool(remote) def Save_File(i, input_dir): out_dir = input_dir + '/Hollowed/' try: os.mkdir(input_dir + '/Hollowed') except: None ext = i.split('.') save_path = out_dir + ext[0] +'_hollowed.' + ext[1] mm.export_mesh(remote,save_path) cmd = mmapi.StoredCommands() cmd.AppendSceneCommand_DeleteSelectedObjects(); remote.runCommand(cmd) # Setup a tiny GUI window: root = Tk() root.title("Hollow and Cut") w = 240 h = 30 ws = root.winfo_screenwidth() x = ws - w y = 0 root.geometry('%dx%d+%d+%d' % (w, h, x, y)) root.attributes("-topmost", True) buttonLoad = Button(root, text="Run", command = Load_File) buttonLoad.pack() def on_closing(): remote.shutdown() root.destroy() root.protocol("WM_DELETE_WINDOW", on_closing) root.mainloop()

---

You may try to compile a standalone .app version yourself which is easy using py2app. Pip install py2app and follow these instructions. Would be interesting to know whether such a compiled .app rises the multi selection issue on Catalina too...

 

 

 



Gunter Weber
Triangle Artisan

Message 15 of 27
Anonymous
in reply to: MagWeb

Good Morning,

the ascDirectory version runs perfectly!!!!!

 

Thanks, thanks thanks!

Karim

Message 16 of 27
MagWeb
in reply to: Anonymous

Great!

 

Just a hint on AcceptSolution button.

This is meant to be clicked at the post(s) which solved the question. For other users this flag makes it easy to find the solving information.



Gunter Weber
Triangle Artisan

Message 17 of 27
Anonymous
in reply to: MagWeb

I am seeing an error "ImportError: No module named mm"

 

Also, how would I add an "Inspect" and "Auto Repair All" command before saving?

 

Thanks

Message 18 of 27
MagWeb
in reply to: Anonymous

Easiest fix of the ImportError:

If you are running your script from ..../mm-api-master/distrib/python ( where test.py is located):

You need to copy the whole mm directory from ..../mm-api-master/python to ..../mm-api-master/distrib/python

 

Example script to run Inspector:

import mmapi
from mmRemote import *
import mm

remote = mmRemote()
remote.connect()


mm.begin_tool(remote,'inspector')
# optional parameters:    (note: I need to set replaceType first - otherwise it uses default FlatFill
mm.set_toolparam(remote, 'replaceType', 2) # Integer: MinimalFill = 0, FlatFill = 1, SmoothFill = 2
mm.set_toolparam(remote, 'smallComponentThreshold', 0.002) # Float

# AutoRepairAll:
mm.tool_utility_command(remote, "repairAll")

# to leave Inspector:
mm.accept_tool(remote)

remote.shutdown()

 



Gunter Weber
Triangle Artisan

Message 19 of 27
Anonymous
in reply to: MagWeb

It worked! I was very close to figuring it out myself, but was using

mm.tool_utility_command(remote, "autoRepairAll")

 insead of

mm.tool_utility_command(remote, "repairAll")

I can't find a lot of the commands listed anywhere (even in the html files), so I'm not sure how you know the commands! But thanks

Message 20 of 27
MagWeb
in reply to: Anonymous

See StoredCommands.h and search for some tool....



Gunter Weber
Triangle Artisan

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report