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: 

MagWeb's mmApi scripts

71 REPLIES 71
Reply
Message 1 of 72
MagWeb
7403 Views, 71 Replies

MagWeb's mmApi scripts

Instead of spreading scripts all over the forum I'll post them in this thread from now on.

 

1 Script:

ToolManager 

 

On a user's request I repost a message I did at MM's old forum on March 23, 2018, 01:30:51 PM:

Download below

"

Here’s a long raw script meant to run api commands without coding a .py file. Well, you’ll need the api to run (important instructions at post’s bottom) or compile the script to a standalone application (recommended it’s easy and seems to be faster) but after that it’s something I find very useful. I post it as it is without any warranty at your own risk in the hope you find it useful and maybe some better coder polishes this…

Why to use it:
For some tools MM remembers the last used parameter setting. For some tools or special parameters it always loads hard coded default values entering a tool. Now what to do if you want the parameters at a step before „last“ or different to defaults? In MM you always have to set this manually - hopefully your own brain remembers all parameters…..

What this script does:
With this ToolManager you can save current tool parameters and reload them. Means you can save several settings for the same tool and others as well.
As there is no direct function to get the current tool’s name in mmApi and it needs to be known to call this very tool and its parameters again, I use a pretty ugly workaround:
There’s a long list of tools and their parameters (BTW: There are more parameters than listed in the documentation or StoredCommands.h, so see this list as a reference too). As the tools have unique (one exception only: Bridge and Handle use the same parameters!) combinations of parameters one can find the tool itself. So the code iterates through the list of params trying to get that kind of value from MM. If MM responds with an empty list the very parameter isn’t currently available so skip to the next…. This ends in a list of available values and a toollname fitting to this combination which is saved in ToolManager.

Usage:
+Standard Tool features:
- Hitting „Save Tool“ button will save current tool settings to the list at top if MM is in some tool. So do your settings in MM and hit „SaveTool“ before leaving the tool. You may do several saves while being in the same tool too.
- The new entry in the list will be called „setting“ + some number by default. RMB-double click (on MAC),  MMB-double click (on WIN) an item in the list opens a dialog where you can set a more meaningful description.
- Hitting „Delete“ will remove an selected item from the list.
- To restore a saved tool setting LMB-double click the item in the list. Note: It will cancel a tool currently open in MM. So if you want to keep the current result hit Accept in MM first.
- To change saved parameters in a saved setting, double click the item to run the tool with saved settings. Now change your settings  in MM and hit UpdateTool in ToolManager. New settings are saved to the item now.
+ AutoSet features:
- Clicking AutoSet will perform listed tool actions from top to bottom and automatically accept them. This way you can perform some kind of simple „scripting“ .
- There are tools in MM not owning some parameters (e.g. Duplicate). Therefor they can’t be detected by my approach as described above. You can add such tools at the list’s bottom by hitting AddCom. A dialog will pop up where you can choose such a command to add.
- You can copy a selected item hitting the Copy button it will be copied to the bottom of the list.
- You can move an item up/down LMB-dragging it in the list. This is needed to get the right order of commands running AutoSet
- By default all added items in the list are active while running AutoSet. If you want to exclude an item without deleting it use the +/-Auto button. This toggles between active and inactive which greys-out  selected item in the list.
I/O:
- You can save the current set of saved tools to a .csv file hitting SaveSet
- You can load such a set via LoadSet. This will replace the current list

Limitations:
- Using mmApi sends each parameter one by one. So expect some „motion“ in the scene while restoring tool settings of tools using a transformation widget.
- There’s no way I found to get/save the brush-type,-falloff,-color,-stencil in SCULPT so it will still use the last used one. Against that all other brush parameters can be saved (even symmetry plane settings)
- In case of SELECT/Edit/Handle and Bridge his approach can’t decide which was used. It will always think it’s Handle (maybe fixed by a decision dialog in the future)
- Don’t expect advanced mmApi stuff on this level of simply calling tools.
- Maybe bad, inefficient coding for now but working….

################
How to run this script:
- Download and setup mmApi using instructions at: https://github.com/meshmixer/mm-api
- Download, unzip attached file „ToolManager.py“ to mm-api-master/distrib/python (or python_osx on MAC)
- Edit def get_toolparam_mat3f(remote, param_name): in tool.py (mm directory) that way:

def get_toolparam_mat3f(remote, param_name):
    """Returns the current value of the given Tool parameter, or empty list if the parameter is not found."""
    cmd = mmapi.StoredCommands()
    key = cmd.AppendGetToolParameterCommand(param_name)
    remote.runCommand(cmd)
    m = mmapi.mat3f()
    bFound = cmd.GetToolParameterCommandResult(key, m)
    if bFound:
        return tuple(m.m) #MagWeb: added output as tuple
    else:
        return ()

tuple(m.m) is needed to return 9 element tuples instead of SWIG objects in case of rotation matrices
##################

enjoy

"

 

You can do stuff like this:

 

 

 

Screencast will be displayed here after you click Post.

bf8ff1a3-6198-4d7d-8e47-90d793fed1fb

 



Gunter Weber
Triangle Artisan

71 REPLIES 71
Message 21 of 72
hfcandrew
in reply to: MagWeb

You mean you were able to reproduce the camera error?

 

I played around with scene manager and I was able to click and drag the items.

 

I tried all permutations of on/off for anti-aliasing, basic rendering and view cube and it did not fix the display issue.

 

But yes any 'selection' does stick. Thanks for the type about select all.

 

Next I'll work on doing a couple GUI layout changes, collapsible menus then try compiling this as an .exe. Still very much learning as I go.

 

For the tool manager I have a pretty good work flow figured out. Also I was able to combine the 'label maker' into the 'tool manager'.

 

I'll post a screencast later with how I am using it all.

Message 22 of 72
MagWeb
in reply to: hfcandrew


@hfcandrew wrote:

You mean you were able to reproduce the camera error?

Yes, these rendering issues happen near to top view or bottom view (while they seem to work fine on nearby front, back, left or right views).  This seems to be no MM issue as I can set top and bottom views using manually homemade coordinates via mmApi without such rendering errors. I need to look at the cam coordinates  grabbed via the api. Can you confirm that this doesn't happen on a stored views near a horizontal aspect?

 


@hfcandrew wrote:

I played around with scene manager and I was able to click and drag the items.

Fine (think that's a core feature of the code)! What was the reason for being unable to drag items (as you said on a former post)?

 


@hfcandrew wrote:

 

I tried all permutations of on/off for anti-aliasing, basic rendering and view cube and it did not fix the display issue.


Thanks for testing. Meanwhile I don't think the rendering issues  are related to MM settings but a mmApi issue using the SWIG generated interface directly.

 


@hfcandrew wrote:

 

Next I'll work on doing a couple GUI layout changes, collapsible menus then try compiling this as an .exe. Still very much learning as I go.

 

For the tool manager I have a pretty good work flow figured out. Also I was able to combine the 'label maker' into the 'tool manager'.


That's the nice thing of coding. One can combine  and modify things as needed

 


@hfcandrew wrote:

 

I'll post a screencast later with how I am using it all.


I'm curious...



Gunter Weber
Triangle Artisan

Message 23 of 72
hfcandrew
in reply to: MagWeb

Here she is. I didn't use any camera saves as it is not working, and I think I can approve on some of the pausing for selections, but this certainly cuts the orthotic design process down a fair bit!

 

Attached is the .csv

 

 

Message 24 of 72
hfcandrew
in reply to: MagWeb

Yes, these rendering issues happen near to top view or bottom view (while they seem to work fine on nearby front, back, left or right views).  This seems to be no MM issue as I can set top and bottom views using manually homemade coordinates via mmApi without such rendering errors. I need to look at the cam coordinates  grabbed via the api. Can you confirm that this doesn't happen on a stored views near a horizontal aspect?

      You are correct, this is only occurring on 'Top' views.

 

Fine (think that's a core feature of the code)! What was the reason for being unable to drag items (as you said on a former post)?

     Simply that the click and drag does not work for me on ToolManager, nothing occurs. I get code repeating through if I try: 

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1547, in __call__
return self.func(*args)
File "C:\Users\Imaging\Documents\meshmixerpython\ToolManager_V2b.py", line 601, in Move_Item
t['cursor'] = "hand"
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1343, in __setitem__
self.configure({key: value})
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1336, in configure
return self._configure('configure', cnf, kw)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1327, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: bad cursor spec "hand"
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1547, in __call__
return self.func(*args)
File "C:\Users\Imaging\Documents\meshmixerpython\ToolManager_V2b.py", line 601, in Move_Item
t['cursor'] = "hand"
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1343, in __setitem__
self.configure({key: value})
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1336, in configure
return self._configure('configure', cnf, kw)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1327, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: bad cursor spec "hand"

 

Thanks for testing. Meanwhile I don't think the rendering issues  are related to MM settings but a mmApi issue using the SWIG generated interface directly.

      Okay interesting, a potential v3 fix I suppose!

Message 25 of 72
MagWeb
in reply to: hfcandrew

 

Ad d&d issue:

Could you try to comment out line 601 in def Move_Item()?

def Move_Item(event): 
    t = event.widget
 #   t['cursor'] = "hand" 
    src=t.selection()
    dest = t.identify_row(event.y)
    ind = t.index(dest)
    par = t.parent(dest)
    t.move(src, par, ind)

 Seems the string "hand" to define the cursor type isn't handled at Win while it works on a Mac. Here's a list of cursor strings which should work for you (if you really need this visual feedback while dragging).



Gunter Weber
Triangle Artisan

Message 26 of 72
hfcandrew
in reply to: MagWeb

Yep that works! I changed it to a 'star' to look extra pretty, haha. Thanks again my friend!

Message 27 of 72
drnunes
in reply to: hfcandrew

Hi @MagWeb @hfcandrew
I need your help.
The scripts MagWeb shared here (MM Slicer, MMSceneManager_01, ToolManager_V2) aren't working.
I''m running Windows 10, Python 2.7.16 and Meshmixer 3.5.474
When I run test.py inside the mm-api-master \ distrib \ python folder the script works and sends the plane cut command and the imported bunny is cut.
If I try to run the scripts inside the mm-api-master \ python \ examples folder they don't work even by copying them to \ distrib \ python.
I've copied MM Slicer.py, MMSceneManager_01.py, ToolManager_V2.py to mm-api-master \ distrib \ python but when I double click them nothing happens
How can I fix this?

Message 28 of 72
MagWeb
in reply to: drnunes

Example codes as well as my codes above try to import a mm module (test.py doesn't. It uses SWIG commands directly) and put out an error:

ImportError: No module named mm

 

To solve this:

Copy the whole directory mm from ...python/mm (where  examples is located too) as a subdirectory to ...distrib/python .

So there should be e.g ...distrib/python/mm/scene.py (and others)

Now run all codes from ...distrib/python.

 



Gunter Weber
Triangle Artisan

Message 29 of 72
drnunes
in reply to: MagWeb

Thanks @MagWeb
Everything is working now.
I'm a dentist and ToolManager_V2 is an excelent tool to automate dental models building workflow.

Here are some suggestions for V3
An option to enable/disable autoaccept
Keyboard Shortcut to PlayDown
Load of a default csv when opening the script.

I've looked at documents and scripts but I can't understand how Meshmixer deals with positioning (local vs world).
I'm trying to find a way to do a plane cut at a specific distance from bottom of the bounding box of an object. As an example, I'd like to cut all my dental models with 25mm height.
I did a plane cut and save as a new set. In the csv file I get:

setting 1,"[['origin', (0.0, 0.2169470340013504, -0.00021694433235097677)], ['rotation', (1.0, 0.0, 0.0, -0.0, -0.9999995231628418, -0.0010000148322433233, 0.0, 0.0010000148322433233, -0.9999995231628418)], ['cutType', 0], ['fillType', 3], ['normal', (0.0, -0.9999995231628418, 0.0010000148322433233)]]",planeCut,X,X

Origin I think are the coordinates where plane cut starts?
Normal is the position you set
The numeric values are (x,y,z) coordinates but are difficult to understand and translate those numbers.

I',m not a programmer  but I think the solution could be the expression get object-space bounding box of selected object (fMin,fMax).
fMin should be the base of object (dental model), and I need plane cut to be 25mm above it.
Is it possible to change the values in csv as a solution? 

 

 

 

 

Message 30 of 72
hfcandrew
in reply to: drnunes

Yes all good suggestions. I think MagWeb is working on some of these things, and I am trying to learn more coding too to be useful for my own desired changes.

 

I have found a work around for the plane cut problem. Just align the model to the printer bed, then save a plane cut at your 25mm (world)above the printer bed.

 

fyi if you are using this for dental modeling these people already have a full MM API automated dental package for sale: https://d3tool.com/product/d3mesh/

 

 

Message 31 of 72
MagWeb
in reply to: hfcandrew

Internally MM  use a normalised coordinate space. This is a bounding box of the whole scene which is a cube of 2 x 2 x 2. Each dimension ranges from -1 to +1. So the values you see are no world coordinates but converted to that scene coordinates. In MM the app converts its internal system automatically to human readable numbers and units.

 

If we would want to read world coordinates we need to convert the scene coordinates we receive from MM via mm.toWorld(remote, something). If we have world coordinates and want to send them to MM we need to convert them to scene coordinates via mm.toWorld(remote, something) to get the expected result.

ToolManager keeps scene coordinates and doesn't convert. This is resulting in those strange numbers in the .csv .



Gunter Weber
Triangle Artisan

Message 32 of 72
hfcandrew
in reply to: MagWeb

Oh that makes sense that ToolManager saves data as a converted version of scene data. Because I have found if I open a scan of a foot in a new MM window, the saved tools from the .csv don't run 100% exactly the same for transformations.

 

So I have been importing each scan into the same scene (.mix file) I saved for consistency.

 

So figuring out those conversions back to world and saving those to the .csv would make it run more consistently.

Message 33 of 72
MagWeb
in reply to: hfcandrew

Yes, it makes sense to convert scene coordinates toWorld (and vice versa) if one wants to apply a stored, coordinates related tool on a different scene... Didn't realise until now.... ToDo on a V3!



Gunter Weber
Triangle Artisan

Message 34 of 72
MagWeb
in reply to: drnunes

@drnunes wrote:

 

I've looked at documents and scripts but I can't understand how Meshmixer deals with positioning (local vs world).
(...)

In the csv file I get:

setting 1,"[['origin', (0.0, 0.2169470340013504, -0.00021694433235097677)], ['rotation', (1.0, 0.0, 0.0, -0.0, -0.9999995231628418, -0.0010000148322433233, 0.0, 0.0010000148322433233, -0.9999995231628418)], ['cutType', 0], ['fillType', 3], ['normal', (0.0, -0.9999995231628418, 0.0010000148322433233)]]",planeCut,X,X

Origin I think are the coordinates where plane cut starts?
Normal is the position you set
The numeric values are (x,y,z) coordinates but are difficult to understand and translate those numbers.

I',m not a programmer  but I think the solution could be the expression get object-space bounding box of selected object (fMin,fMax).


Just to explain MM's frame handling:

There's a World, a never changing and never ending universe, where someone decided to set certain fixed points to measure distances  and directions.

You watch that universe sitting in a space ship navigating in space. You do not rotate the World (WorldFrame) to see it from different aspects but move your ship. Same happens navigating the Camera (= the ship) watching a virtual 3D World.

Now you might be interested in the details of a certain cubic area of interest inside the World's universe. Your interest depends on the objects you're interested in. So your cubic area's size depends on the objects. That cubic area is the Scene. As one can't set its size in ratio to a non-limited World, you decide to calculate distances inside the Scene relative to the Scene. All stuff left (or below or in front) of the cube's center gets a negative value while all stuff right (or above or in the rear) gets a positive one for the corresponding axes. For easier calculation you set the range for the cube's axes from -1 to +1 (scene coordinates) while you keep the World's axes directions.

Now there might be moving objects in the scene. Let's say, a dog with a nose (front) and a tail (back). As the object transforms (translates, rotates, grows/shrinks) its nose will be always on the dog's front (relative front) but in the World's absolute system it might point to the rear. This individual frame moving along with the object is the LocalFrame.

To describe a LocalFrame in the Scene's or World's system you need to know its position (best to use its center as origin) and its rotation matrix and  and maybe a scale factor.

 

MM tools using positions (as PlaneCut, Transform or Mirror) own these parameters (scaling a non ending plane doesn't make sense)  too. Origin describes the pivoting point of the plane (center of the white cube in the transform widget in scene coordinates), rotation describes the plane's twisting (as if you dragged the widget's arcs), normal describes the side to cut off (it's a normal vector)



Gunter Weber
Triangle Artisan

Message 35 of 72
MagWeb
in reply to: MagWeb

Ok, here's a new version of ToolManager:

 

  • fixed wrong text inserts in the help text
  • changed the d&d cursor type to a cross platform "star"
  • fixed rendering issues on restoring a saved cam position
  • changed .csv writer to binary mode. That should fix the empty rows in the output csv on WIN.
  • added hotkey Q to call PlayDown (we could add hotkeys for other things too. Be aware that the ToolManager window needs the focus to receive the shortcut. Switching between MM and the ToolManager might be irritating)
  • different behaviour of a Break: Break will now cause a stop of the cue on the next item below the break and calls these settings. PlayDown now accepts changes in the settings you did manually during the break. So you can insert a break above a stored tool to "disable" AutoAccept.
  • On exit ToolManager saves the current cue to a temporary lastCue.csv (to the same folder the script runs from). So you can quickly load the last cue of commands via the new LastSet button.

 



Gunter Weber
Triangle Artisan

Message 36 of 72
MagWeb
in reply to: MagWeb

forgot:

  • origin coordinates are stored in World coordinates now (and converted back to Scene coordinates sending to MM)


Gunter Weber
Triangle Artisan

Message 37 of 72
hfcandrew
in reply to: MagWeb

Thanks!

As usual somethings are not functioning.

 


@MagWeb wrote:

Ok, here's a new version of ToolManager:

 

  • fixed wrong text inserts in the help text (Good, works!)
  • changed the d&d cursor type to a cross platform "star" (Good, works!)
  • fixed rendering issues on restoring a saved cam position (Good, works!)
  • changed .csv writer to binary mode. That should fix the empty rows in the output csv on WIN. (Good, works!)
  • added hotkey Q to call PlayDown (we could add hotkeys for other things too. Be aware that the ToolManager window needs the focus to receive the shortcut. Switching between MM and the ToolManager might be irritating) (Good! Now I was thinking, as you mentioned to avoid the irritation of clicking back and forth. If the API essentially 'listens in' to whats happening in MM. Would it be possible to have the API listen and wait for 'Q' to be hit on the keyboard in MM, and when it detects that, then 'play down')
  • different behaviour of a Break: Break will now cause a stop of the cue on the next item below the break and calls these settings. PlayDown now accepts changes in the settings you did manually during the break. So you can insert a break above a stored tool to "disable" AutoAccept. (The break occuring on that next items is working, but but I then 'play down' it does not accept the actions of the tool it paused on, just skips past it.)
  • On exit ToolManager saves the current cue to a temporary lastCue.csv (to the same folder the script runs from). So you can quickly load the last cue of commands via the new LastSet button. (Good, works! Nice idea)

 


 

Message 38 of 72
MagWeb
in reply to: hfcandrew

Found UpdateTool  is broken in V3 - Already fixed that.

Waiting for other glitches to be fixed though...

 

At Break behaviour:

Let's say there's something like:

 

PlaneCut

Break

Mirror

PlaneCut

 

The cue stops at Mirror and loads the saved setting of Mirror in MM.

Now manually move the mirror plane in MM

Now if you do PlayDown it should accept the current Mirror (it will NOT store the new plane position until you do UpdateTool) and continue with the next item which is a PlaneCut.

Doesn't that work for you? Here it does... 

Can you post a csv of a cue skipping the accept?



Gunter Weber
Triangle Artisan

Message 39 of 72
MagWeb
in reply to: MagWeb

Keyboard events in MM aren't passed over to the API - that's the problem. Maybe I can find a MM shortcut calling some action in MM which can be used as a trigger (e.g. W to show the wireframe) . Let's see...



Gunter Weber
Triangle Artisan

Message 40 of 72
hfcandrew
in reply to: MagWeb

I think the skipping a tool after a break issue come with now how it calls in an accept  command, and also how it is set to pause on a selection command if it is trying to do an action and nothing is currently selected. But I just realized all I need to do is put in a 'select' tool.

 

For example:  Break>SmoothBoundary>Discard           - Will pause at smooth boundary for you to select your area. After doing that and hitting play down, it does not accept the smoothing first.

 

But if you go: Break>SelectTool>SmoothBoundary>Discard     - It works fine.

 

Not a big deal at all, don't worry about it, just had to learn the new way of doing it.

 

If I may make a suggestion for the hot key, 'W' is something I use often anyways, so I wouldn't want it hit 'W' and accidentally play down. I was thinking '`' for 'set as target' (beside '1'  on my keyboard) is a much less used button, so may be less risky to use, but hitting this clears current selections and things. So the questions is what is the least used hotkey in MM that would not mess up a current selection or any other process?

 

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

Post to forums