Statistics
| Branch: | Revision:

testing-framework / plugin_blender / controller.py @ 1fdee286

History | View | Annotate | Download (17.838 KB)

1
import bpy
2
from math import sqrt 
3
import random       
4

    
5

    
6

    
7

    
8
class PositionenAusgeben(bpy.types.Operator):
9
    """Gibt die Distanz, Orientierung und Position im Koordinatensystem der Kamera aus"""
10
    bl_idname = "print_object.position"
11
    bl_label = "Position ausgeben"
12
    
13
    # Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist.
14
    @classmethod
15
    def poll(cls, context):
16
        return ((bpy.context.scene.markerRender.kameraID in bpy.context.scene.objects.keys()) and (bpy.context.scene.markerRender.markerID in bpy.context.scene.objects.keys() or bpy.context.scene.markerRender.markerID == "") and (bpy.context.scene.markerRender.dateipfad != ""))
17
    
18
    # Gibt die Distanz, Orientierung und Position im Koordinatensystem der Kamera aus
19
    def execute(self, context):
20
        model = bpy.context.scene.markerRender
21
        dateipfad = bpy.path.abspath(model.dateipfad)
22
        ausgabedatei= open(bpy.path.ensure_ext(dateipfad,".txt"),mode='w')
23
        csvAusgabe= open(bpy.path.ensure_ext(dateipfad,".csv"),mode='w')
24
        bildnummer = 0
25
        bpy.context.scene.frame_current = bpy.context.scene.frame_start
26
        while(bildnummer <=  (bpy.context.scene.frame_end/bpy.context.scene.frame_step)):
27
            bpy.context.scene.frame_set(bpy.context.scene.frame_start + bildnummer * bpy.context.scene.frame_step)
28
            self.bildVerarbeiten(context,csvAusgabe,ausgabedatei,(bildnummer+1))
29
            bildnummer += 1
30
        ausgabedatei.flush()
31
        ausgabedatei.close()
32
        csvAusgabe.flush()
33
        csvAusgabe.close()
34
        print("Positionen nach",bpy.path.ensure_ext(dateipfad,".txt"),"und",bpy.path.ensure_ext(dateipfad,".csv"),"ausgegeben")
35
        return {'FINISHED'}
36
        
37
    # Wird für jedes Bild einmal ausgeführt    
38
    def bildVerarbeiten(self, context, csvAusgabe, ausgabedatei, bildnummer):
39
        model = bpy.context.scene.markerRender
40
        kamera = context.scene.objects[model.kameraID]
41
        
42
        print("Bild",(bildnummer-1),file=ausgabedatei)
43
        print(" Kamera Position: (",end="",file=ausgabedatei)
44
        print(kamera.location.x, kamera.location.y, kamera.location.z,sep=",",end="",file=ausgabedatei)
45
        print(")",file=ausgabedatei)
46
        
47
        if(model.markerID == ""):
48
            zaehler = 0
49
            zuEntfernen = []
50
            for id in model.markerIDs:
51
                if(id.value in context.scene.objects.keys()):    
52
                    object = context.scene.objects[id.value]
53
                    if(not object.hide_render):
54
                        self.markerVerarbeiten(object,kamera,ausgabedatei,csvAusgabe,model,bildnummer)
55
                        zaehler += 1
56
                else:
57
                    print("INFO: Vermisse "+id.value+" in "+str(context.scene.objects.keys()))
58
                    zuEntfernen.append(zaehler)
59
            # Überflüssige Schlüssel entfernen
60
            for schluessel in zuEntfernen:   
61
                model.markerIDs.remove(schluessel)
62
        else: 
63
            object = context.scene.objects[model.markerID]
64
            self.markerVerarbeiten(object,kamera,ausgabedatei,csvAusgabe,model)
65
            
66
    def achsendatenAusgeben(self, dist,object,csvAusgabe):
67
        print(dist,sep=",",file=csvAusgabe)
68
        
69
    # wird für jeden Marker ausgeführt
70
    def markerVerarbeiten(self, object, kamera, ausgabedatei, csvAusgabe, model, bildnummer):
71
        dist = distanz(object.location.x,object.location.y,object.location.z,kamera.location.x,kamera.location.y,kamera.location.z)
72
        
73
        print(" ",object.name,"Position: (",end="",file=ausgabedatei)
74
        print(object.location.x, object.location.y, object.location.z,sep=",",end="",file=ausgabedatei)
75
        print(")",file=ausgabedatei)
76
        print(" ",object.name,"Distanz:",end=" ",file=ausgabedatei)
77
        print(dist,sep=",",file=ausgabedatei)
78
        
79
        #Testet, ob es einen einfachen Weg gibt an die Transformationsmatrix zwischen kamera und Objekt zu gelangen
80
        if(object.parent != None and object.parent == kamera):
81
            matrix = object.matrix_local 
82
        elif(object.parent != None and object.parent.parent != None and object.parent.parent == kamera):
83
            matrix = object.parent.matrix_local*object.matrix_local
84
        else:
85
            #Es gibt keinen einfachen Weg :(
86
            print("Warnung: Invertierte globale Matritzen verwendet. Das ist weniger genau. Überlege, ob die Marker Kinder der Kamera oder eines ihrer direkten Kinder werden können.")
87
            print("Warnung: Invertierte globale Matritzen verwendet. Das ist weniger genau. Überlege, ob die Marker Kinder der Kamera oder eines ihrer direkten Kinder werden können.",file=ausgabedatei)
88
            matrix = kamera.matrix_world.inverted_safe()*object.matrix_world
89
        
90
        #An diesem Punkt enthält matrix die Transformationsmatrix zwischen Marker und Kamera
91
         
92
        # Gibt nach und nach die Bildnummer, die Markerid, die Rotationsmatrix, den Translationsvektor usw. aus
93
        if(matrix != None):    
94
            print(" ",object.name,"Transformation bezüglich der Kamera:",file=ausgabedatei)
95
            if(object.marker_id != None):
96
                print(bildnummer,object.marker_id,sep=",",end=",",file=csvAusgabe)
97
            else:
98
                print(bildnummer,-1.0,sep=",",file=csvAusgabe)
99
            spalte = 0
100
            while(spalte < len(matrix[0])):
101
               line = 0
102
               print("   ",end="",file=ausgabedatei)
103
               while(line < len(matrix)):
104
                   print(matrix[line][spalte],end=", ",file=ausgabedatei)
105
                   if(not ((line%4) == 3)):
106
                       print(matrix[line][spalte],end=",",file=csvAusgabe)
107
                   line += 1
108
               print("",file=ausgabedatei)
109
               spalte += 1
110
            print("",file=ausgabedatei)
111
            print(matrix[3][3],end=",",file=csvAusgabe)
112
            self.achsendatenAusgeben(dist, object, csvAusgabe)
113
            
114

    
115
#class EulerwinkelAusgeben(PositionenAusgeben):
116
 #   """Gibt auch die Eulerwinkel für Achsenbeschriftungen aus"""
117
  #  bl_idname = "print_object.rotation"
118
   # bl_label = "Include Rotation"
119
    #
120
    #def achsendatenAusgeben(self,dist,object,csvAusgabe):
121
     #   euler = object.rotation_euler
122
      #  print(dist,euler.x,euler.y,euler.z,sep=",",file=csvAusgabe)
123
   
124
        
125
class MarkerHinzufuegen(bpy.types.Operator):
126
    """Erzeugt ein neues flaches Objekt fügt es der Szene hinzu und versieht es mit entsprechenden Texturen und Attributen"""
127
    bl_idname = "mesh.primitive_marker_add"
128
    bl_label  = "Marker hinzufügen"
129
    
130
    # Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist.
131
    @classmethod
132
    def poll(cls, context):
133
        return context.mode == "OBJECT"
134

    
135
    # Wird ausgeführt, um einen neuen Marker hinzuzufügen
136
    def execute(self, context):
137
        markerID = str (bpy.context.scene.markerRender.newMarkerID)
138
        bpy.ops.object.select_all(action="DESELECT")
139
        
140
        markerIDSuffix = ""
141
        zaehler = 1
142
        while("Marker_"+markerID+markerIDSuffix in bpy.data.objects.keys()):
143
            markerIDSuffix = ".0"+str (zaehler)
144
            zaehler += 1
145
        
146
        #Erstellt Mesh
147
        bpy.ops.mesh.primitive_cube_add(radius=0.5)
148
        context.selected_objects[0].name = "Marker_"+markerID+markerIDSuffix
149
        bildschirm = context.screen
150
        gliederungGefunden = False
151
        for bereich in bildschirm.areas:
152
            if bereich.type == 'OUTLINER':
153
                gliederungGefunden = True
154
                kontextUeberschreiben = {'screen': bildschirm, 'area': bereich}
155
                bpy.ops.outliner.parent_drop(kontextUeberschreiben,child=context.selected_objects[0].name, parent=bpy.context.scene.markerRender.kameraID)
156
                break 
157
        if(not gliederungGefunden):
158
            print("Skipped reparenting. Please activate Outliner!")
159

    
160
        context.selected_objects[0].scale[2] = 0.005
161
        plane = context.selected_objects[0].data
162
        bpy.data.objects["Marker_"+markerID+markerIDSuffix].marker_id = bpy.context.scene.markerRender.newMarkerID
163
        
164
        #Erstellt Material
165
        bpy.ops.material.new()
166
        material = bpy.data.materials[-1]
167
        bpy.data.materials[-1].name = "Marker_"+markerID+markerIDSuffix
168
        
169
        
170
        #Erstellt Texturen
171
        material = createTexture(markerID,bpy.context.scene.markerRender.kontrastErhoehen,"//BART_Marker/","Marker","BART_Marker_",'BART',material)
172
        material = createTexture(markerID,bpy.context.scene.markerRender.kontrastErhoehen,"//ALVAR_Marker/","MarkerData_","ALVAR_Marker_",'ALVAR',material)
173
        
174
        #Weist Material zu
175
        plane.materials.append(material)
176
        
177
        #In Liste einhängen
178
        knoten       = bpy.context.scene.markerRender.markerIDs.add()
179
        knoten.value = "Marker_"+markerID+markerIDSuffix
180
        
181
        #Unwrap (nur der obenliegenden Seite)
182
        bpy.ops.object.editmode_toggle()
183
        bpy.ops.mesh.select_all(action="DESELECT")
184
        bpy.ops.object.editmode_toggle() 
185
        bpy.data.objects["Marker_"+markerID+markerIDSuffix].data.polygons[5].select = True
186
        bpy.ops.object.editmode_toggle() 
187
        bpy.ops.uv.unwrap()
188
        bpy.ops.object.editmode_toggle() 
189
        
190
        if(bpy.context.scene.markerRender.incrementNewMarkerID):
191
            bpy.context.scene.markerRender.newMarkerID+=1
192
        return {'FINISHED'}
193
    
194
class MarkerRandomisieren(bpy.types.Operator):
195
    """Randomisiert die Markerid des ausgewählten Markers"""
196
    bl_idname = "mesh.randomize_marker"
197
    bl_label  = "Marker randomisieren"
198
    
199
    # Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist.
200
    @classmethod
201
    def poll(self,context):
202
        
203
        return True #context.object.marker_id > -1
204
    
205
    def execute(self, context):
206
        ursprungsbild = context.scene.frame_current
207
        #Fange beim ersten Frame an
208
        context.scene.frame_current = 1
209
        
210
        #Suche nach einem geeigneten Material
211
        object = context.object
212
        original_id = object.marker_id
213
        object.keyframe_insert("marker_id",frame=1)
214
        material_index = object.material_slots.find("Marker_"+str(original_id))
215
        if(material_index == -1):
216
            # Die ID wurde leider verändert! Suche Material.
217
            # Da der Marker nur wenige Materialien enthalten dürften, sollte dieser Test schnell sein.
218
            material = None
219
            for material_slot in object.material_slots:
220
                for texture_slot in material_slot.material.texture_slots:
221
                    if (texture_slot != None and texture_slot.texture.marker_id > -1):
222
                        material = material_slot.material
223
                        print("Warning: Using",material.name)
224
                        break
225
            if(material == None):
226
                print("Could not randomise marker. Unable to find appropriate material.")
227
                return {'CANCELLED'} 
228
        else:
229
            material = object.material_slots[material_index].material
230
        material.keyframe_insert("use_textures",options={'INSERTKEY_NEEDED'})
231
            
232
        #Finde einen unbenutzten Slot
233
        material.active_texture_index = len(context.object.active_material.texture_slots.keys())
234
        id = -1
235
        usedids = []
236
        while (context.scene.frame_current < context.scene.frame_end and material.active_texture_index < 17) :
237
            id = random.randint(original_id-50,original_id+50)
238
            if(id < 0):
239
                id += 50
240
            elif(id > 1000):
241
                id %= 1000
242

    
243
            if(id in usedids):
244
                #Die ids sollen einmalig sein, um die Streuung möglichst groß zu halten
245
                #und den Programmieraufwand beim Wechseln der Texturen zu verringern
246
                continue
247
            usedids.append(id)
248
            object.marker_id = id
249
            object.keyframe_insert("marker_id")
250
            #Workaround um zu verhindern, dass zwischen den IDs interpoliert wird
251
            object.keyframe_insert("marker_id",frame=context.scene.frame_current+1)
252
            object.keyframe_insert("marker_id",frame=context.scene.frame_current+2)
253
            object.keyframe_insert("marker_id",frame=context.scene.frame_current+3)
254
            
255
            #XXX Mit den Schlüsseln arbeiten, da Werte sonst nicht übernommen werden (keine reguläre Liste)
256
            for schluessel in range(0,len(material.use_textures)):
257
                material.use_textures[schluessel] = False
258
            
259
            # Die Textur für BART erstellen
260
            material = createTexture(str(id),False,"//BART_Marker/","Marker","BART_Marker_",'BART',material)
261
            material.use_textures[material.active_texture_index-1] = True 
262
            
263
            # Die Textur für ALVAR erstellen
264
            material = createTexture(str(id),False,"//ALVAR_Marker/","MarkerData_","ALVAR_Marker_",'ALVAR',material)
265
            material.use_textures[material.active_texture_index-1] = True 
266

    
267
            #Nach Erreichen von 17 wird nicht weiter hochgezählt, wir haben also erneut die Textur an Position 16 aktiviert und müssen das für 17 noch einmal erledigen.
268
            if(material.active_texture_index == 17):
269
                material.use_textures[17] = True
270
            material.keyframe_insert("use_textures",frame=context.scene.frame_current,options={'INSERTKEY_NEEDED'})
271
            context.scene.frame_current += 4
272
            print(id)
273
        
274
        #Mehr Texturen sind leider nicht erlaubt. Mische zwischen den vorhandenen Texturen.
275
        while(context.scene.frame_current < context.scene.frame_end):
276
            # Finde die Indizes für BART und erstelle ein Wörterbuch, das den Markernummern die Indizes von ALVAR zuordnet
277
            texturenBART = [ i for i in range(0,17) if material.texture_slots[i].texture.library == 'BART' and material.texture_slots[i].texture.marker_id != id]
278
            texturenALVAR = { material.texture_slots[i].texture.marker_id:i for i in range(0,17) if material.texture_slots[i].texture.library == 'ALVAR' and material.texture_slots[i].texture.marker_id != id}
279
            #Zufällige Reihenfolge herstellen
280
            random.shuffle(texturenBART)
281
            index = 0
282
            while (context.scene.frame_current < context.scene.frame_end and index < len(texturenBART) and index < len(texturenALVAR)) :
283
                #XXX Mit den Schlüsseln arbeiten, da Werte sonst nicht übernommen werden (keine reguläre Liste)
284
                # Nicht benötigte Texturen deaktivieren
285
                for schluessel in range(0,len(material.use_textures)):
286
                    material.use_textures[schluessel] = False
287
                slot_index = texturenBART[index]
288
                # Die ausgeloste Textur beider Bibliotheken aktivieren 
289
                id =  material.texture_slots[ slot_index ].texture.marker_id
290
                if(id in texturenALVAR):
291
                    material.use_textures[ slot_index ] = True 
292
                    material.use_textures[ texturenALVAR[id] ] = True
293
                    object.marker_id = id
294
                    object.keyframe_insert("marker_id",frame=context.scene.frame_current)
295
                    
296
                    # Workaround um zu verhindern, dass zwischen den IDs der Schlüsselbilder Interpoliert wird
297
                    object.keyframe_insert("marker_id",frame=context.scene.frame_current+1)
298
                    object.keyframe_insert("marker_id",frame=context.scene.frame_current+2)
299
                    object.keyframe_insert("marker_id",frame=context.scene.frame_current+3)
300
                    material.keyframe_insert("use_textures",frame=context.scene.frame_current,options={'INSERTKEY_NEEDED'})
301
                    print(context.scene.frame_current,object.marker_id,material.texture_slots[ slot_index ].texture.name, material.texture_slots[ slot_index ].name)
302
                else:
303
                    print("Warnung: Id",id,"wurde nicht für BART und ALVAR gefunden. Ich wähle eine andere.")
304
                    index += 1
305
                    continue
306
                
307
                # Springe zum nächsten Schlüsselbild
308
                context.scene.frame_current += 4
309
                index += 1
310
            
311
        context.scene.frame_current = ursprungsbild    
312
        return {'FINISHED'}
313
    
314
    
315
# Hilfsfunktionen
316

    
317
# Erzeugt eine Textur, für einen Marker mit der übergebenen markerID und den übergebenen Eigenschaften
318
def createTexture(markerID,kontrastErhoehen,dateipfad,dateiPrefix,idPrefix,bibliotheksID,material):
319
    if(kontrastErhoehen):
320
        idSuffix = "hC"
321
    else:
322
        idSuffix = ""
323
    if(not (idPrefix+markerID+idSuffix in bpy.data.textures.keys())):
324
        # Erstellt Textur
325
        bpy.ops.texture.new()
326
        bpy.data.textures[-1].name = idPrefix+markerID+idSuffix
327
        bpy.data.textures[idPrefix+markerID+idSuffix].type = 'IMAGE'
328
        bpy.ops.image.open(filepath=dateipfad+dateiPrefix+markerID+".png")
329
        
330
        # Sorgt für eindeutige Identifikation, für den Fall das der Benutzer bzw. die Benutzerin Texturen und Bilder verschiebt und/oder umbenennt
331
        bpy.data.textures[idPrefix+markerID+idSuffix].library = bibliotheksID
332
        bpy.data.textures[idPrefix+markerID+idSuffix].marker_id = int(markerID)
333
        
334
        bpy.data.textures[idPrefix+markerID+idSuffix].image = bpy.data.images[dateiPrefix+markerID+".png"]
335
        if(kontrastErhoehen):
336
            # Erhöht den Kontrast
337
            bpy.data.textures[idPrefix+markerID+idSuffix].intensity = 2
338
            bpy.data.textures[idPrefix+markerID+idSuffix].contrast = 3
339
    
340
    # Weist die Standard-UV-Map zu        
341
    material.active_texture   = bpy.data.textures[idPrefix+markerID+idSuffix]
342
    material.texture_slots[material.active_texture_index].texture_coords   = 'UV'
343
    material.texture_slots[material.active_texture_index].uv_layer = 'UVMap'
344
    material.active_texture_index+=1
345
    return material
346

    
347
# Berechnet den Abstand zweier Punkte 1 und 2 
348
def distanz(x1,y1,z1,x2,y2,z2):
349
    return laenge(x1-x2,y1-y2,z1-z2)
350

    
351
# Berechnet die Länge eines Vektors
352
def laenge(x,y,z):
353
    return sqrt(x*x+y*y+z*z)
354