(I got a little cocky there. My script doesn't do a check for hard edges!)

On Thursday, 5 April 2018 15:51:55 UTC+10, Michael Boon wrote:
>
> It's a bit of a myth, or at least an over-simplification, to say that 
> PyMel is slower and maya.cmds is faster. MEL and maya.cmds tend to be slow 
> because they do string processing for almost everything (and for that 
> reason they're also error-prone once you get into scenes with instances). 
> PyMel tends to be slow because it often wraps maya.cmds, and then spends 
> more time creating Python objects for things, but it can also be faster 
> than cmds because it often wraps the API and sometimes you can get the API 
> to do the work under the hood where cmds would be juggling strings.
>
> So in general, like Justin suggested, profile your code (there's a profile 
> module in Python) and look for hot spots.
>
> In this case though, I have written a script using PyMel that I can't 
> share, but it's only 8 simple lines and I think it does what you want, 
> plenty fast for your needs. Sorry! That's rude I know, but I don't own it! 
> Use the MeshFace class, and its methods connectedFaces and getNormal. Don't 
> use ls or polyListComponentConversion at all in your loop - those can be 
> pathological examples of PyMel slowness.
>
> I hope that helps :)
>
>
> On Wednesday, 4 April 2018 14:44:28 UTC+10, Darby Edelen wrote:
>>
>> Hello,
>>
>> I'm new to the list and relatively new to Maya.
>>
>> I've been missing a tool in Cinema 4D that allows the user to select 
>> contiguous faces within boundaries defined by differences in polygon normal 
>> angles (boundaries = hard edges or an arbitrary angle), so I rolled my own 
>> Maya script.
>>
>> It seems to be working well, but it gets quite slow as the number of 
>> faces to select increases.  For example, on my home PC it takes about 6 
>> seconds to select 320 faces along the inside of a ring.
>>
>> If you have any ideas on how I could implement this more efficiently I 
>> would love your input.  I've heard that PyMEL tends to be the slowest of 
>> options for scripting, but it's super convenient to work in a more 
>> 'pythonic' mode.  I started playing with the OpenMaya API but found that it 
>> doesn't seem to have a polyListComponentConversion equivalent and my brain 
>> is fried enough that I can't think about implementing my own version using 
>> the API.  I have a suspicion that the polyListComponentConversion function 
>> is one of those adding the most time to execution;  I'm using it to find 
>> the boundary edges of the faces currently marked for selection.
>>
>> I've attached a .py file and pasted my code here as well:
>>
>> import pymel.core as pm
>> import time
>> import itertools
>>
>> def compare_normals(n1, n2):
>>     #Take dot product of normals and convert to degrees difference
>>     return 90.0 * (1.0 - n1*n2)
>>
>> def check_angle(edge, angle, hard_edges=True):
>>     if edge.isOnBoundary():
>>         #Boundary reached; no need to continue!
>>         return False
>>     
>>     soft = True
>>     if hard_edges:
>>         #Check for hard or soft edge
>>         soft = edge.isSmooth()
>>     
>>     #Get all faces connected to this edge
>>     faces = pm.ls(edge.connectedFaces(), fl=True)
>>     #Compare the face normals between edges to determine if the face 
>> should be selected
>>     face_compare = {c for c in itertools.combinations(faces, 2) if 
>> compare_normals(c[0].getNormal(), c[1].getNormal()) > angle}
>>     
>>     #Returns True if the face should be selected
>>     return len(face_compare) == 0 and soft
>>     
>>
>> def get_connected_faces(faces, angle=0.0, hard_edges=True):
>>     #Get edge boundary of current face selection
>>     boundary = pm.ls(pm.polyListComponentConversion(faces, bo=True, 
>> te=True), fl=True)
>>     #Combine currently selected faces with neighboring faces that pass 
>> the face normal test
>>     new_faces = faces | set(pm.ls([edge.connectedFaces() for edge in 
>> boundary if \
>>                                    check_angle(edge, angle, hard_edges)], 
>> fl=True))
>>
>>     if new_faces != faces:
>>         #Yield the new faces to select for as long as we haven't 
>> exhausted our supply
>>         yield new_faces
>>     #Stop when there are no more faces to select
>>     raise StopIteration
>>
>> t1 = time.clock()
>>
>> angle_tolerance = 30.0
>> hard_edges = True
>>
>> #Get the initial selection
>> selection = pm.ls(sl=True, fl=True)
>> #Filter the selection to face components
>> selected_faces = {face for face in selection if isinstance(face, 
>> pm.general.MeshFace)}
>>
>> if selected_faces:
>>     #Since there are faces selected...
>>     try:
>>         while True:
>>             #Find new neighboring faces until no more meet the criteria
>>             selected_faces = get_connected_faces(selected_faces, 
>> angle_tolerance).next()
>>     except StopIteration:
>>         #Select all faces found
>>         pm.select(selected_faces)
>>         t2 = time.clock()
>>         #Report our performance
>>         print("Selected {0} faces in {1:.2f} 
>> seconds.".format(len(selected_faces), t2-t1))
>>
>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to python_inside_maya+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/python_inside_maya/cf48302d-42f0-46c5-99d7-2ce113804007%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to