restructure project

On 20/02/2013 at 07:40, xxxxxxxx wrote:

Hi all,

I try to reduce data in a C4D File by combining Polygon-objects with the same material following in the structure dirctly after another.

Running thrue the structure works!
Finding materials works.
But when I find two objekts with equal material the plugin stops.
It seams to lose the actual objekt ?!?

Here is my code:

  
def walk(obj) :   
    if not obj: return   
    elif obj.GetDown() :   
        return obj.GetDown()   
    while obj.GetUp() and not obj.GetNext() :   
        obj = obj.GetUp()   
  
    print 'klick'   
    return obj.GetNext()   
  
def walk_thrue_projekt(doc) :   
    print 'walk_thrue_projekt START'      
    obj = doc.GetFirstObject()   
    zaehler = 0   
    c4d.CallCommand(13324)                            # Alles deselektieren   
    material1 = 'Leer'   
    print material1   
    gui.MessageDialog('Stop1')   
    while obj:   
        zaehler = zaehler + 1   
        print zaehler   
        print c4d.BaseObject.GetName(obj)                         # Objektname lesen und ausgeben   
        obj.SetBit(c4d.BIT_ACTIVE)   
        textureTag = obj.GetTag(c4d.Ttexture)                     # Lesen TextureTag des aktuellen Objektes   
        if not textureTag:                                        # wenn Material nicht vorhanden dann   
            print 'Kein Material-Tag gefunden'                    # nix tun   
            obj.DelBit(c4d.BIT_ACTIVE)                            # Wenn kein Material vorhanden dann deaktivieren   
        else:                                                     # wenn Material vorhanden dann   
            material2 = textureTag.GetMaterial()                  # Materialnamen auslesen   
            print material2                                       # Materialnamen ausgeben   
            print material1                                       # Materialnamen ausgeben   
            obj.SetBit(c4d.BIT_ACTIVE)                            # Objekt aktivieren   
            gui.MessageDialog('Stop2')   
            if material1 == material2:                            # Wenn material1 = maderial 2 dann:   
               gui.MessageDialog('zwei gleiche gefunden')   
               c4d.CallCommand(16768)                            # Objekte verbinden + Löschen   
               #return   
            else:                                                 # Wenn material1 != maderial 2 dann:   
#               c4d.CallCommand(13324)                            # Alles deselektieren   
               gui.MessageDialog('zwei ungleiche hintereinander gefunden')                 
               obj.DelBit(c4d.BIT_ACTIVE)                        # aktuelles Objekt aktivieren   
               material1 = material2   
        obj = walk(obj)   

To test the Plugin here is a testfile:
http://www.vision4d.de/downloads/001 Testscene klein.c4d

Can anybody help my please

Thanks a lot

On 20/02/2013 at 11:10, xxxxxxxx wrote:

calling connect and delete on your object will cause you object reference to become None
and therefor the walk method will return none which will cause your main method to break
the loop.

On 21/02/2013 at 01:02, xxxxxxxx wrote:

OK Thanks to littledevil.

But how can I solve the problem?
I'm a try-and-error-Coder!
Do you know anybody how can help me!
(I would pay for the solution!)

Thanks again

On 21/02/2013 at 10:04, xxxxxxxx wrote:

hm,

there are multiple problems with your approach. here is how i would do it :

http://codepad.org/DpEBjT7O

i am taking a selection based approach, as this makes things a bit easier (and faster)
and also adds the possibility to exclude objects from the process. simply select all objects
manually or programmatically if you want to run it over the whole document.

edit, the code, the codepad link won't last forever:

import c4d
  
# --- connect & delete all objects of the current selection, which have the same material
# --- assigned to them. objects which have multiple materials assigend to them will be skipped.
# --- objects with multiple material tags holding the same material will be connected.
# ------------------------------------------------------------------------------------------------
def main() :
    selection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
    dic = buildDict(selection)
    for key in dic:
        connect(dic[key]) 
  
# --- connect & delete a object list
# ------------------------------------------------------------------------------------------------
def connect(objlist) :
    if len(objlist) > 1:
        for i in xrange(len(objlist)) :
            if i == 0:
                doc.SetActiveObject(objlist[i], c4d.SELECTION_NEW)
            else:
                doc.SetActiveObject(objlist[i], c4d.SELECTION_ADD)
        c4d.CallCommand(16768)
  
# --- get material used by this baseobjct. returns none for multiple materials.
# --> BaseMaterial | None
# ------------------------------------------------------------------------------------------------
def getMaterial(obj) :
    material = None
    if isinstance(obj, c4d.BaseObject) :
        taglist  = obj.GetTags()
        for tag in taglist:
            if tag.GetType() == c4d.Ttexture:
                # single tag
                if material == None:
                    material = tag.GetMaterial()
                # multiple tags of the same material
                elif material == tag.GetMaterial() :
                    pass
                # multiple tags
                else: return None
    return material
  
# --- build a dict of all materials in the given selection. each key contains a list
# --- with the objects which carry only this material in their texturetag(s).
# --> dict
# ------------------------------------------------------------------------------------------------
def buildDict(selection) :
    result = {}
    for objA in selection:
        matA = getMaterial(objA)
        for objB in selection:
            if objA is not objB:
                matB = getMaterial(objB)
                if matA == matB and matA and matB:
                    mkey = matA.GetName()
                    if mkey in result:
                        if objA not in result[mkey]:
                            result[mkey].append(objA)
                        if objB not in result[mkey]:
                            result[mkey].append(objB)
                    else:
                        result[mkey] = []
                        result[mkey].append(objA)
                        result[mkey].append(objB)
    return result
  
if __name__=='__main__':
    main()
  

edit : using the material name as a dict key isn't really a brilliant idea, as it would merge
different material objects with the same name into one object. you should change the 
dict key to a string repr of the material object ...  mkey = str(matA)

On 22/02/2013 at 02:17, xxxxxxxx wrote:

   
You are my Hero!!!
BUT:

My eyplanation of my problem wasn't exact enought:

I wantet to change form this structure

Würleh0 Material-1
Würfel1 Material-2
Würfel2 Material-1
Würfel3 Material-3 #merge and the next
Würfel4 Material-3        +
Würfel14 Material-1 #merge and the next
Würfel15 Material-1        +
Null
|-- Würfel4 Material-1
|-- Würfel2 Material-2
Null1
     |-- Würfel6 Material-2 #merge and the next
     |-- Würfel7 Material-2        +
     Null2
     | |-- Würfel8 Material-1
     |   |-- Würfel9 Material-2 #merge and the next
     |   |-- Würfel10 Material-2        +
     |
     |-- Würfel11 Material-3 #merge and the next
     |-- Würfel12 Material-2          +

to the folowing:

Würleh0 Material-1
Würfel1 Material-2
Würfel2 Material-1
Würfel3 Material-3 #merged objects
Würfel14 Material-1 #merged objects
Null
|-- Würfel4 Material-1
|-- Würfel2 Material-2
Null1
     |-- Würfel6 Material-2 #merged objects
     Null2
     | |-- Würfel8 Material-1
     |   |-- Würfel9 Material-2 merged objects
     |
     |-- Würfel11 Material-3 merged objects

I uploaded the result-File here:

http://www.vision4d.de/downloads/001%20Testscene%20klein%20-%20after%20restructure.c4d

Mayby you can hlep me by this problem???
Thanks a Lot lot lot lot............lot lot lot

On 22/02/2013 at 05:49, xxxxxxxx wrote:

ah ok, i thought this behaviour of your code was unintended. you could stick 
more ore less with orginal code, but instead of merging the objects from within 
your loop you would build up a result list. you could use the python tuple feature 
to make things easier.

result = []
  
if current_material == last_material:
	result.append((last_object, current_object))
  
...
  
for obja, objb in result:
	merge(obja,objb)

On 22/02/2013 at 06:27, xxxxxxxx wrote:

Hi LittleDevil;

It seams for me that it is very easy vor you to change the first code.

What shall I change?
Could you pleas make th changes?

Thanks a lot

On 22/02/2013 at 08:08, xxxxxxxx wrote:

as your pm sounded kind of desperate, i did the work for you ;) this does now exactly what you
wanted it to do. for more you will have to dig yourself through python or hire someone as you suggested.

import c4d
  
def main() :
    connectList(buildList())
  
def buildList() :
    result           = []
    current_object   = doc.GetFirstObject()
    last_object      = None
    current_material = None 
    last_material    = None
  
    while current_object:
        current_material = getMaterial(current_object)
        if current_material != None and last_object != None:
            if current_material == last_material:
                result.append((last_object, current_object))
        last_material = current_material
        last_object   = current_object
        current_object = walk(current_object)
    return result
  
def connectList(objlist) :
    for objA, objB in objlist:
        doc.SetActiveObject(objA, c4d.SELECTION_NEW)
        doc.SetActiveObject(objB, c4d.SELECTION_ADD)
        c4d.CallCommand(16768)
  
def getMaterial(obj) :
    material = None
    if isinstance(obj, c4d.BaseObject) :
        taglist  = obj.GetTags()
        for tag in taglist:
            if tag.GetType() == c4d.Ttexture:
                if material == None:
                    material = tag.GetMaterial()
                elif material == tag.GetMaterial() :
                    pass
                else: return None
    return material
  
def walk(obj) :
    if not obj: return
    elif obj.GetDown() :
        return obj.GetDown()
    while obj.GetUp() and not obj.GetNext() :
        obj = obj.GetUp()
    return obj.GetNext()
  
if __name__=='__main__':
    main()

On 23/02/2013 at 03:10, xxxxxxxx wrote:

Hello at all,

and first of all my thanks to littledevil.

The problem seams to be not as easy.
The code above works with the postetd (reducesd) testscene well!
But with my original scene not.
It analysed it and it seams for me that the varriable result[] looses informations. (I did a print result)

Here is a new testscene:

http://www.vision4d.de/downloads/002_Testscene_klein.c4d

For that I can help me by my own, I need help at the following problem:
I try to explane in words:

goto first objekt                                         (no problem)
step throug the scene                               (no problem)
test if the actual object is a null-objekt     (no problem)
if yes:                                                        (no problem)
   is a part of the name is "wand"              Problem starts here!
       if yes:
       merge all polygonal objekts in this null-objekt with the same
       material to one object

The problem for me ist to find "all" polygon-objekts in a null-object and merge them to one!!!

Because:
when I find two following to each other and mergin them, the aktual objekt is not the merged on.
So i'm loosing my aktual position in the project.
How can I merge them and than place my aktual objekt pointer to the mergesd on?

Thanks a lot to all good ideas.

On 23/02/2013 at 09:35, xxxxxxxx wrote:

1. finding a substring in a string is pretty asy in python. str.find will return the index of 
the first occurance of the given substring. it will return -1 for no mtach.
'I am a string'.find('I am')

2. for changing the object count in the document and looping through the content - you
could use other methods, but the easiest approach would be to build up a list of objects
which have to be merged and do the merging after you have looped through all the objects.
like i did it in my examples.

On 24/02/2013 at 05:26, xxxxxxxx wrote:

@ ferdinand:
But why does your way stuggle with the biger scene I posted?

I looking for a way to build a list of all Polygonal objects listet in a Null-object whitch have the same material and combine them and then continue!.

The question is:
How could I store the next object to continue with this object after combining the collected objects?

Thanks a lot for your patience

On 24/02/2013 at 12:00, xxxxxxxx wrote:

ok, now I found the problem:
The code only works when:
not more than two objact following have the same material!!!
and:
when nor the first 2 objekts have the same material!!!

So, has anybody out there a idea how to bild the list for varriable amout of objekts with same material following to each other?

Thanks a lot!

On 25/02/2013 at 10:41, xxxxxxxx wrote:

you have just to build up a longer list instead of pairs, like in my first example. but as you do not 
care for earlier occurances of sequences of the current material you do not have to use a dict, you 
can just build up a list of lists.

import c4d
  
def main() :
    connectList(buildList())
  
def buildList() :
    result           = []
    templist         = []
    current_object   = doc.GetFirstObject()
    last_object      = None
    current_material = None 
    last_material    = None
  
    while current_object:
        current_material = getMaterial(current_object)
        if current_material != None:
            if current_material == last_material and last_object != None:
                templist.append((current_object))
            else:
                if len(templist) > 1:
                    result.append(templist)
                templist = []
                templist.append(current_object)
        last_material = current_material
        last_object   = current_object
        current_object = walk(current_object)
    return result
  
def connectList(objlist) :
    for sublist in objlist:
        for i in xrange(len(sublist)) :
            if i == 0: doc.SetActiveObject(sublist[i], c4d.SELECTION_NEW)
            else: doc.SetActiveObject(sublist[i], c4d.SELECTION_ADD)
        c4d.CallCommand(16768)
  
def getMaterial(obj) :
    material = None
    if isinstance(obj, c4d.BaseObject) :
        taglist  = obj.GetTags()
        for tag in taglist:
            if tag.GetType() == c4d.Ttexture:
                if material == None:
                    material = tag.GetMaterial()
                elif material == tag.GetMaterial() :
                    pass
                else: return None
    return material
  
def walk(obj) :
    if not obj: return
    elif obj.GetDown() :
        return obj.GetDown()
    while obj.GetUp() and not obj.GetNext() :
        obj = obj.GetUp()
    return obj.GetNext()
  
if __name__=='__main__':
    main()