Realign uv mapping from script

On 09/02/2017 at 01:19, xxxxxxxx wrote:

Hi,

I am trying to realign UV mapping of an object from script. I want the same result from script that I get when I press the apply button in the UV optimal mapping tool.

Here is the settings and the result when i press the apply button:

https://postimg.org/image/oh298vdzr/

Here is the code that I expect to do the same thing (I have used the code from Andreas in this post: https://plugincafe.maxon.net/topic/9738/13094_new-calluvcommand and changed the settings) :

import c4d
from c4d import utils
from c4d import gui
from c4d.modules import bodypaint

def applyRealign(doc,obj) :

for tag in obj.GetTags() :
      if type(tag) == c4d.UVWTag:
          uvwTag = tag
          doc.SetActiveObject(obj)
          doc.SetActiveTag(uvwTag)

# Retrieves active UVSet
          handle = bodypaint.GetActiveUVSet(doc, c4d.GETACTIVEUVSET_ALL)
          if not handle:
              print "No active UVSet!"
              return

settings = c4d.BaseContainer()

settings[c4d.OPTIMALMAPPING_PRESERVEORIENTATION] = 0
          settings[c4d.OPTIMALMAPPING_STRETCHTOFIT] = 0
          settings[c4d.OPTIMALMAPPING_EQUALIZEAREA] = 1
          settings[c4d.OPTIMALMAPPING_SPACING] = 0.02

# Retrieves UVW list
          uvw = handle.GetUVW()
          if uvw is None:
              return

# Calls UVCOMMAND_TRANSFORM to change UVW list
          ret = bodypaint.CallUVCommand(handle.GetPoints(), handle.GetPointCount(), handle.GetPolys(), handle.GetPolyCount(), uvw,
                                        handle.GetPolySel(), handle.GetUVPointSel(), obj, handle.GetMode(), c4d.UVCOMMAND_REALIGN, settings)
          if not ret:
              print "CallUVCommand() failed!"
              return

print "CallUVCommand() successfully called"

# Sets the transformedUVW from Texture View
          if handle.SetUVWFromTextureView(uvw, True, True, True) :
              print "UVW from Texture View successfully set"
          else:
              print "UVW from Texture View failed to be set!"

# Releases active UVSet
          bodypaint.FreeActiveUVSet(handle)

def main() :
  # Get the selected objects, including children.
  selection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
 
  if len(selection) <= 0:
      gui.MessageDialog('Must select objects!')
      return

#  doc.StartUndo()  # Start undo block.
  for i in range(0,len(selection)) :
      sel = selection      applyRealign(doc,sel)

if __name__=='__main__':
  main()

And this is the resulting uv mapping after running the script:

https://postimg.org/image/sc11xp7rr/

It seems that OPTIMALMAPPING_SPACING is not set to the specified value. It seems that the resulting spacing is around 50%. I have tried different values for OPTIMALMAPPING_SPACING but the resulting mapping always seem to use a bigger spacing than requested.

I am missing something or is this a bug?

Cheers,

Per

On 10/02/2017 at 02:13, xxxxxxxx wrote:

Hi,

The value 0.02 for OPTIMALMAPPING_SPACING is valid. The issue isn't there but in other parts of your script (please use

tags for better formatting of code snippets).

With the following loop the script doesn't run fine:

for i in range(0,len(selection)) :
    sel = selection

In fact the previous lopp isn't needed. You can call applyRealign(doc) once with just the active document.
Also don't change the active object and tag from the script. TempUVHandle.GetBaseObject() gives the object for the current UV context.

So the fixed script that gives the same result as the UI is:

import c4d
from c4d import gui
from c4d.modules import bodypaint
  
def **applyRealign(doc)** :
  
    # Retrieves active UVSet
    handle = bodypaint.GetActiveUVSet(doc, c4d.GETACTIVEUVSET_ALL)
    if not handle:
        print "No active UVSet!"
        return
    
    settings = c4d.BaseContainer()
    settings[c4d.OPTIMALMAPPING_PRESERVEORIENTATION] = **False**
    settings[c4d.OPTIMALMAPPING_STRETCHTOFIT] = **False**
    settings[c4d.OPTIMALMAPPING_EQUALIZEAREA] = **True**
    settings[c4d.OPTIMALMAPPING_SPACING] = 0.02
  
    # Retrieves UVW list
    uvw = handle.GetUVW()
    if uvw is None:
        return
    
    # Calls UVCOMMAND_TRANSFORM to change UVW list
    ret = bodypaint.CallUVCommand(handle.GetPoints(), handle.GetPointCount(), handle.GetPolys(), handle.GetPolyCount(), uvw,
                                  handle.GetPolySel(), handle.GetUVPointSel(), **handle.GetBaseObject()** , handle.GetMode(), c4d.UVCOMMAND_REALIGN, settings)
    if not ret:
        print "CallUVCommand() failed!"
        return
    
    print "CallUVCommand() successfully called"
  
    # Sets the transformedUVW from Texture View 
    if handle.SetUVWFromTextureView(uvw, True, True, True) :
        print "UVW from Texture View successfully set"
    else:
        print "UVW from Texture View failed to be set!"
    
    # Releases active UVSet
    bodypaint.FreeActiveUVSet(handle)
  
  
def main() :
    # Get the selected objects, including children.
    selection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
 
    if len(selection) <= 0:
        gui.MessageDialog('Must select objects!')
        return
    
    **applyRealign(doc)**
  
  
if __name__=='__main__':
    main()

On 13/02/2017 at 02:01, xxxxxxxx wrote:

Hi and thanks for your reply :-)

I should have described better what I want the script to do. I want the script to iterate all selected objects and automatically remap the UVs without having to manually make one active.

With your changes only one object seems to be remapped and only the active UV.

Cheers,

Per

On 13/02/2017 at 02:25, xxxxxxxx wrote:

Hi Per,

Thanks for the clarification.

I think you're just missing a call to c4d.EventAdd() after setting the active object and tag (only call SetActiveObject() once for an object in applyRealign()) so that Cinema updates all its data for the document.

Also the loop in main() should be changed to (if not done yet) :

for obj in selection:
    applyRealign(doc, obj)