Benutzer-Werkzeuge

Webseiten-Werkzeuge


ws1920:pmcd_25.03.2020

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
ws1920:pmcd_25.03.2020 [2020/03/25 14:39]
Zetraeder angelegt
ws1920:pmcd_25.03.2020 [2020/04/01 17:18] (aktuell)
Zetraeder
Zeile 4: Zeile 4:
 **25.03.2020** **25.03.2020**
  
-[[ws1920:​scutoids|Home]]+[[ws1920:​scutoids|Home]] | [[ws1920:​pm_25.03.2020|Text]] | [[ws1920:​pmcd_01.04.2020|>>​]]
  
 Aktuelle Programmversion Stand 14:39 Uhr Aktuelle Programmversion Stand 14:39 Uhr
Zeile 10: Zeile 10:
 <code python> <code python>
  
 +import bpy
 +from random import random, randint
 +from math import *
 +import numpy as np
 +import time
 +from bpy_extras.mesh_utils import ngon_tessellate
 +
 +
 +#
 +#
 +#
 +#   ​KLASSEN
 +
 +class Sphere(object):​
 +    #   ​Klasse,​ die spherische Objekte beschreibt, die für das Kugelkriterium ​
 +    #   der Delaunay-Tatraedisierung notwendig sind
 +    pos = np.array([0,​0,​0]) ​    # ​  ​Mittelpunkt der Sphere
 +    radius = 0                  #   ​Radius der Sphere
 +    epsilon = 0.001             # ​  ​epsilon-Bereich für das Kugelkriterium
 +    ​
 +    def __init__(self,​ pos, radius):
 +        #   eine Sphere wird immer mit einer Position und einem Radius initialisiert
 +        self.pos = pos
 +        self.radius = radius
 +        ​
 +    def punktInKugel(self,​ p):
 +        #   diese Funktion stellt fest, ob sich ein Punkt innerhalb der Sphere befindet
 +        #   ​(Funktion des Kugelkriteriums)
 +        if (abstandPunkte(self.pos,​ p) < self.radius - self.epsilon):​
 +            return True
 +        else:
 +            return False
 +    ​
 +class Tetraeder(object):​
 +    #   ​Klasse,​ die Tetraedische Objekte beschreibt, für die Delaunay-Tetraedisierung
 +    verts = []                  #   ​vertecies (Eckpunkte) des Tetraeders
 +    faces = []                  #   faces (Flächen) des Tetraeders (enthält Flächen-Listen, ​
 +                                #   die aus Ketten von Indexen der vertecie-Liste bestehen)
 +    sp = np.array([0,​0,​0]) ​     #   ​Schwerpunkt (= Mittelpunkt der Umkugel) -> Diese Punkte bilden die vertecies für das Voronoi-Diagramm!!
 +    name = "​tetraeder" ​         #   ...
 +    umkugel = Sphere(np.array([0,​0,​0]),​ 0)  #   ​Spherenobjekt,​ auf dessen Oberfläche alle vertecies des Tetraeders liegen
 +    ​
 +    def __init__(self,​ verts, name):
 +        #   Ein Tetraeder wird immer mit 4 Eckpunkten, vier Flächen und einem Namen initialisiert.
 +        #   ​Außerdem berechnet der Code hier automatisch die resultierende Umkugel und den daraus
 +        #   ​resultierenden Schwerpunkt.
 +        self.name = name
 +        self.verts = verts
 +        self.faces = [(0,​1,​2),​(1,​2,​3),​(2,​3,​0),​(3,​0,​1)] ​ #   jedes Tetraeder hat immer dieselben 4 faces...
 +        if (self.schwerpunkt()[0] != None):
 +            self.sp = self.schwerpunkt()
 +            self.umkugel = Sphere(self.sp,​abstandPunkte(self.sp,​self.verts[0]))
 +        else:
 +            self.sp = np.array([None,​None,​None])
 +            ​
 +    def schwerpunkt(self):​
 +        #   ​Funktion errechnet den Schwerpunkt des Tetraeders, indem es zwischen je
 +        #   drei Eckpunkten Dreiecke aufspannt, die Schwerpunkte dieser errechnet, dann die Flächennormalen
 +        #   an diesen Punkten ansetzt und den Schnittpunkt der darasu resultierenden Geraden berechnet.
 +        #   ​Dieser Punkt ist dann der Schwerpunkt des Tetraeders (bzw. der Mittelpunkt der Umkugel)
 +        v1 = np.subtract(self.verts[1],​self.verts[0])
 +        v2 = np.subtract(self.verts[2],​self.verts[0])
 +        v3 = np.subtract(self.verts[3],​self.verts[0])
 +        ​
 +        sp = tetraSchwerpunkt(self.verts[0],​v1,​v2,​v3)
 +        return sp           # ​  gibt den Schwerpunkt des Tetraeders zurück...
 +    ​
 +    ​
 +    def selfRender(self,​ ker, col, tetra):
 +        #   falls innerhalb der Umkugel des Tetraeders kein Zellfremder Kern enthalten ist, wird das
 +        #   ​Tetraeder als Meshobjekt generiert, in dem 3D View angezeigt und der Liste "​tetra"​ hinzugefügt.
 +        #   diese verfügt somit zum Schluss über eine Ansammlung von Referenzen aller zur Delaunay-Tetraedisierung
 +        #   ​gehörenden Tetraeder.
 +        frei = True
 +        for m in range(0, len(ker)):
 +            if (self.umkugel.punktInKugel(ker[m]) == True):
 +                frei = False
 +        if (frei == True):
 +            tetraeder = generateObj("​Tetraeder",​ t.verts, t.faces, (0,0,0), col)
 +            tetraeder.parent = grp_delaunay
 +            tetra.append(self)
 +    ​
 +class Gerade(object):​
 +    #   ​Klasse,​ die Geradenformeln mithilfe von Stützvektor/​Ortsvektor OV und
 +    #   ​Richtungsvektor RV beschreibt. Das Objektattribut Kerne beschreibt, durch welche
 +    #   ​beiden Kerne die Gerade verläuft
 +    ov = (0,0,0)
 +    rv = (0,0,0)
 +    kerne = [0,0]
 +    ​
 +    def __init__(self,​ov,​rv,​kerne = [0,0]):
 +        #   Jede Gerade wird mit einem Ortsvektor und Richtungsvektor initialisiert. Da nicht alle Funktionen
 +        #   ​Geraden durch Kerne ziehen, wird das Attribut standardmäßig auf 0,0 gessetzt
 +        self.ov = ov
 +        self.rv = rv
 +        self.kerne = kerne
 +    ​
 +    def punktAn(self,​k):​
 +        #   Gibt die Koordinaten eines Punktes auf der Geraden an, der mit der Koordinatenform berechnet wird
 +        #   (im Detail: Stützvektor + Richtungsvektor*k)
 +        punkt = np.add(self.ov,​(self.rv[0]*k,​self.rv[1]*k,​self.rv[2]*k))
 +        return punkt
 +
 +
 +#
 +#
 +#
 +#   ​FUNKTIONEN
 +
 +def dreieckSchwerpunkt(pos,​a,​b):​
 +    #   ​Berechnet mithilfe von drei Punkten den Schwerpunkt eines Dreieckes
 +    #   unter Berücksichtigung der dreidimensionalen Lage des Dreieckes
 +        ​
 +    g1 = Gerade(pos,​a)
 +    g2 = Gerade(pos,​b)
 +    ​
 +    c = kreuzProdukt(a,​b)
 +    ​
 +    d = kreuzProdukt(a,​c)
 +    e = kreuzProdukt(b,​c)
 +    ​
 +    g3 = Gerade(g1.punktAn(.5),​ np.divide(d,​ 40))
 +    g4 = Gerade(g2.punktAn(.5),​ np.divide(e,​ 40))
 +    ​
 +    schnitt = schnittPunkt(g3,​g4)
 +    return schnitt
 +
 +def tetraSchwerpunkt(pos,​ v1, v2, v3):
 +    #   ​berechnet den Schwerpunkt des Tetraeders mit Hilfe von drei Richtungsvektoren,​ die gemeinsam
 +    #   zwei Dreiecke aufspannen (ein Vektor liegt genau an der Grenze zwischen beiden Dreiecken)
 +    ​
 +    sp1 = dreieckSchwerpunkt(pos,​ v1, v2)
 +    sp2 = dreieckSchwerpunkt(pos,​ v1, v3)
 +    ​
 +    #   Es wird nach None-Type untersucht, da "​falsche Dreiecke"​ sich einschleichen könnten
 +    #   Dies sind zum Beispiel jene Dreiecke, deren Innenfläche 0 beträgt - somit wäre eine Seite gleich 0
 +    #   und es existiert kein Richtungsvektor,​ der sie beschreiben könnte
 +    if (sp1[0] != None and sp2[0] != None):
 +        g1 = Gerade(sp1, kreuzProdukt(v1,​ v2))
 +        g2 = Gerade(sp2, kreuzProdukt(v1,​ v3))
 +        ​
 +        schnitt = schnittPunkt(g1,​ g2)
 +        return schnitt
 +    else: return np.array([None,​None,​None])
 +
 +def schnittTest(g1,​g2):​
 +    #   ​testet,​ ob zwei Geraden sich schneiden und gibt gegebenfalls den Faktor aus, der in die Koordinatenform
 +    #   der einen Geraden zur Berechnung des Schnittpunktes eingesetzt werden kann
 +    a = [[g2.rv[0],​-g1.rv[0]],​[g2.rv[1],​-g1.rv[1]]]
 +    b = [[g1.ov[0]-g2.ov[0]],​[g1.ov[1]-g2.ov[1]]]
 +    ​
 +    c = [[g2.rv[2],​-g1.rv[2]],​[g2.rv[1],​-g1.rv[1]]]
 +    d = [[g1.ov[2]-g2.ov[2]],​[g1.ov[1]-g2.ov[1]]]
 +    ​
 +    e = [[g2.rv[2],​-g1.rv[2]],​[g2.rv[0],​-g1.rv[0]]]
 +    f = [[g1.ov[2]-g2.ov[2]],​[g1.ov[0]-g2.ov[0]]]
 +    ​
 +    if (np.linalg.det(a) != 0):
 +        return np.linalg.solve(a,​b)[0][0]
 +    elif (np.linalg.det(c) != 0):
 +        ​
 +        return np.linalg.solve(c,​d)[0][0]
 +    elif (np.linalg.det(e) != 0):
 +        ​
 +        return np.linalg.solve(e,​f)[0][0]
 +    else: return None
 +
 +def schnittPunkt(g1,​g2):​
 +    #   setzt das Ergebnis des Schnitttests in die Koordinatengleichung der einen Gerade ein
 +    #   ​(mithilfe der Funktion "Punkt an") und gibt den Schnittpunkt von g1 und g2 aus
 +    z = schnittTest(g1,​g2)
 +    if (z != None):
 +        return g2.punktAn(z)
 +    else: return np.array([None,​None,​None])
 +
 +def abstandPunkte(p1,​ p2):
 +    #   gibt den Abstand zweier Punkte im dreidimensionalen Raum aus (Satz des Pythagoras)
 +    a = sqrt(((p1[0]-p2[0])**2) + ((p1[1]-p2[1])**2) + ((p1[2]-p2[2])**2))
 +    return a
 +
 +def zeichnePunkt(pos,​ size = 0.2, name = "​Punkt"​):​
 +    #   ​zeichnet einen kleinen Würfel an der übergebenen Stelle, sodass dieser für Debugging-Zwecke
 +    #   ​später leicht gefunden und nachvollzogen werden kann (wird in dieser Programmversion nicht mehr benötigt)
 +    #   ​Größe kann angepasst werden
 +    ​
 +    size = size/2
 +    verts = [(size,​size,​size),​(-size,​size,​size),​(-size,​-size,​size),​(size,​-size,​size)
 +            ,​(size,​size,​-size),​(-size,​size,​-size),​(-size,​-size,​-size),​(size,​-size,​-size)]
 +    faces = [(0,​1,​2,​3),​(4,​5,​6,​7),​(0,​1,​5,​4),​(1,​2,​6,​5),​(2,​3,​7,​6),​(3,​0,​4,​7)]
 +    punkt = generateObj(name,​verts,​faces,​pos)
 +    punkt.parent = grp_kerne
 +    ​
 +def kreuzProdukt(a,​b):​
 +    #   ​Bildet das Kreuzprodukt der beiden übergebenen Parameter
 +    c = (a[1]*b[2]-a[2]*b[1] , a[2]*b[0]-a[0]*b[2] , a[0]*b[1]-a[1]*b[0])
 +    return c
 +    ​
 +def genKerne(anzahl,​ x_max, y_max, z_max):
 +    #   ​Generiert in der übergebenen Menge zufällige Punkte und gibt diese in einer Liste zurück.
 +    #   Die drei anderen Parameter sind für die Begrenzung des Raumes, in dem sich die Punkte befinden sollen
 +    ker = []
 +    ​
 +    #   ​Framing ​   ​
 +    #signum = [-1, 1]
 +    #for x in signum:
 +    #    for y in signum:
 +    #        for z in signum:
 +    #            r = randint(0,​1)
 +    #            ker.append(np.array([x*x_max*r,​y*y_max*r,​z*z_max*r]))
 +    #anzahl = anzahl - 8
 +    #if (anzahl <= 0): return ker
 +    ​
 +    for n in range(0, anzahl):
 +        x = randint(-x_max,​ x_max)*((random()/​(1+random())))
 +        y = randint(-y_max,​ y_max)*((random()/​(1+random())))
 +        z = randint(-z_max,​ z_max)*((random()/​(1+random())))
 +        if (len(ker) != 0):
 +            neu = True
 +            #   ​verhindert,​ dass kein Punkt doppelt generiert wird... hätte man auch mit if element in liste
 +            #   ​machen können, verbesserungswürdig
 +            for m in range(0, len(ker)):
 +                if (x == ker[m][0] and y == ker[m][1] and z == ker[m][2]):
 +                    neu = False
 +            if (neu == True):
 +                ker.append([x,​y,​z])
 +                zeichnePunkt(ker[n],​ 1)
 +            else:
 +                n = n-1
 +        else:
 +            ker.append([x,​y,​z])
 +            zeichnePunkt(ker[n],​ 1)
 +    return ker
 +
 +
 +#   AB HIER ERSTELLUNG DER ZELLWÄNDE
 +
 +def radianBetweenVectors(v1,​ v2, n):  ​
 +    #   ​berechnet den Zwischenwinkel zweier Vektoren unter Beachtung eines Normalenvektors
 +    #   ​(später wird für n die Flächennormale der Zellwand eingesetzt, welche die Verbindung der
 +    #   ​beiden Knotenpunkte ist, zwischen denen sich die Zellwand befindet).
 +      ​
 +    a = v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]
 +    b = v1[0]*v2[1]*n[2] + v2[0]*n[1]*v1[2] + n[0]*v1[1]*v2[2] - v1[2]*v2[1]*n[0] - v2[2]*n[1]*v1[0] - n[2]*v1[1]*v2[0]
 +    ​
 +    rad = np.arctan2(b,​ a)
 +    if (rad < 0): rad = (2*np.pi) +rad
 +    ​
 +    deg = rad*180/​np.pi
 +    ​
 +    return deg
 +
 +
 +def polySortList(v_list,​ normal):
 +    #   ​Funktion bekommt eine Liste von Punkten (mehr oder weniger in einer Ebene liegend)
 +    #   ​übergeben und sortiert diese, sodass sie im Kreis herum nacheinander ind er Liste
 +    #   ​angeordnet werden. Für die korrekte Drehrichtung braucht diese Funktion den Normalenvektor
 +    #   der Ebene, um den sie dreht.
 +    ​
 +    #   ​Könnte man wahrscheinlich deutlich kürzer schreiben, überarbeitungswürdig!
 +    ​
 +    #   Fall die Vertexliste aus 3 Elementen besteht, handelt es sich um ein Dreieck und die Reihnefolge ist egal.
 +    if (len(v_list) == 3):
 +        return v_list
 +    ​
 +    geordnet = []       # ​  ​Zielliste,​ die zum Schluss die geordneten vertecie-Koordinaten als numpy-arrays enthält
 +    ​
 +    start = v_list[0] ​  # ​  ​Funktion merkt sich, bei welchem Punkt sie anfängt -> weiß dann, wann sie einmal im Kreis herum iteriert ist
 +    aktu = start        #   aktu beinhaltet die Vertex-Daten des aktuellen Eckpunktes
 +    vv = np.subtract(v_list[0],​ v_list[1]) ​ #   ​Vergleichswinkel (zeigt immer aus dem Kreis raus), somit kann immer eine einzige Reihenfolge generiert werden
 +    ​
 +    geordnet.append(start)
 +    ​
 +    while True:
 +        #   loop start values
 +        min_angle = 360        ​
 +        min_stelle = 0
 +        ​
 +        #   suche nach nächstem Punkt
 +        for v in range(0, len(v_list)):​
 +            if (aktu[0] != v_list[v][0] or aktu[1] != v_list[v][1] or aktu[2] != v_list[v][2]): ​           ​
 +                dir = np.subtract(v_list[v],​ aktu)
 +                deg = radianBetweenVectors(vv,​ dir, normal)
 +                ​
 +                if (deg < min_angle): ​
 +                    min_angle = deg
 +                    min_stelle = v        ​
 +        ​
 +        geordnet.append(v_list[min_stelle])
 +        vv = np.subtract(v_list[min_stelle],​ aktu)
 +        ​
 +        aktu = v_list[min_stelle] ​  
 +        ​
 +        if (aktu[0] == start[0] and aktu[1] == start[1] and aktu[2] == start[2]): break
 +    return geordnet
 +
 +def genPoly(liste,​ normal):
 +    #   ​generiert aus einer Liste von durcheinander angeordneten Polygon-Koordinaten ein Mesh-Flächenobjekt
 +    #   ​VORSICHT:​ diese Funktion wird nur bei konvexen Polygonen zu sinnstiftenden Ergebnissen führen!
 +    ​
 +    geordnet = polySortList(liste,​ normal)
 +    f = []  #   ​face-Datenliste,​ die angibt, welche Eckpunkte in welcher Reihenfolge verwendet werden sollen
 +    ​
 +    for i in range(0, len(geordnet)):​
 +        f.append(i)
 +    ​
 +    #   ​Eigenart der generateObj-Funktion,​ benötigt geschachtelte Liste [[faces]], um richtig zu funktionieren
 +    facelist = []
 +    facelist.append(f)
 +    ​
 +    generateObj("​Zellwand",​ geordnet, facelist)
 +
 +def generateObj(name,​ verts = [], faces = [], loc = np.array([0,​0,​0]),​ col = ( 1.0, 1.0, 1.0, 1.0 )):
 +    #   ​generiert ein 3D-MeshObjekt mit den Übergebenen Parametern (Name, Eckpunkte, Seiten)
 +    #   und gibt dieses im 3D Viewport aus
 +    ​
 +    mymesh = bpy.data.meshes.new(name)
 +    myobject = bpy.data.objects.new(name,​mymesh)
 +         
 +    mymat = bpy.data.materials.new("​Mesh_mat"​)
 +    mymat.diffuse_color = col
 +    mymesh.materials.append(mymat)
 +    ​
 +    myobject.location = loc 
 +    bpy.context.collection.objects.link(myobject)
 +
 +    mymesh.from_pydata(verts,​[],​faces)
 +    mymesh.update(calc_edges=True)
 +    ​
 +    return myobject
 +
 +
 +#   ​ZUORDNUNG DER WÄNDE ZU KOLLEKTIONEN (funkioniert lieder noch nicht komplett...)
 +def createCollection(name):​
 +    col = bpy.data.collections.new(name)
 +    bpy.context.scene.collection.children.link(col)
 +    return col
 +
 +def linkToCollection(obj,​ col):
 +    col.objects.link(obj)
 +
 +#   ​LISTEN DURCHSUCHEN
 +def inListeAnStelle(element,​ liste):
 +    #   ​durchsucht eine Liste nach einem Vektor und gibt den entsprechenden Index aus, falls es enthalten ist
 +    if element in liste:
 +        for i in range(0, len(liste)):​
 +            if (element == liste[i]): return i
 +    return None
 +
 +def inListeAnStelleNP(element,​ liste):
 +    #   ​durchsucht eine Liste von np.arrays nach einem np.array und gibt die Stelle aus,
 +    #   falls dieser enthalten ist
 +    for i in range(0, len(liste)):​
 +        if (np.array_equal(element,​ liste[i])): return i
 +    return None   
 +
 +#   ​SCUTOID TEST!!
 +
 +def watertightTest(faces):​
 +    #   ​Testet,​ ob das Objekt mit der übergebenen Face-Liste watertight ist, also keinerlei Löcher aufweist.
 +    #   wenn jede Edge mindestens zu genau zwei Flächen zugeordnet ist, ist eine Mesh watertight (in diesem Fall)
 +    ​
 +    for face in faces:
 +        ​
 +        for a in range(0, len(face)):
 +            ​
 +            if (a == len(face)-1):​ b = 0
 +            else: b = a+1
 +                ​
 +            enthalten ​ = False                ​
 +            for face02 in faces:
 +                if (face != face02):
 +                    if ((face[a] in face02) and (face[b] in face02)): enthalten = True
 +            if (enthalten == False):
 +                return False                          ​
 +                        ​
 +    return True
 +
 +def grenzenFlächenAneinander(f1,​ f2):
 +    #   ​Funktion bekommt zwei Flächen übergeben und ermittelt, ob diese direkt aneinander grenzen.
 +    for a in range(0, len(f1)):
 +        for b in range(a+1, len(f1)):
 +            ​
 +            if ((f1[a] in f2) and (f1[b] in f2)):
 +                    return True
 +
 +def ScutoidTest(faces):​
 +    #   Diese Funktion testet, ob ein Meshobjekt ein Scutoid ist oder nicht. Hierzu bekommt es eine Liste aller
 +    #   faces übermittelt und testet, ob es eine Kombination aus zwei Flächen gibt (diese beiden dürfen sich nicht berühren,
 +    #   sind die Deckflächen des "​Prismas"​),​ an die jeweils beide jede andere Fläche anschließt ​
 +    #   (bis auf eine Fläche, diese ist die Dreiecksfläche)
 +    ​
 +    #   das kleinstmöglichste Scutoid hat eine Dreiecksgrundgläche und eine vierecksgrundfläche und hat somit 6 Seiten
 +    #if (len(faces) < 6): return False
 +    ​
 +    ​
 +    for a in range(0, len(faces)):​
 +        for b in range(a+1, len(faces)):​
 +            ​
 +            scutellum = 0
 +            #index = 0
 +            if not (grenzenFlächenAneinander(faces[a],​ faces[b])): ​               ​
 +                print("​berühren sich nicht"​)
 +                for g in faces:
 +                    if not (grenzenFlächenAneinander(g,​ faces[a]) == True and grenzenFlächenAneinander(g,​ faces[b]) == True):
 +                        #index = g
 +                        scutellum = scutellum + 1            ​
 +                     
 +                if (scutellum == 1): #and len(faces[g]) == 3):
 +                    return True
 +    ​
 +    return False
 +  ​
 +  ​
 +  ​
 +#  ​
 +#  ​
 +#    ​
 +#   CODE FÜR DIE ZELLGENERIERUNG
 +
 +
 +#   setup groups
 +grp_alles = generateObj('​Zellgeneration.000'​)
 +
 +grp_delaunay = generateObj('​Delaunay'​)
 +grp_delaunay.parent = grp_alles
 +grp_kerne = generateObj('​Kerne'​)
 +grp_kerne.parent = grp_alles
 +
 +grp_randzellen = generateObj('​Randzellen'​)
 +grp_randzellen.parent = grp_alles
 +grp_zellen = generateObj('​Zellen'​)
 +grp_zellen.parent = grp_alles
 +grp_scutoids = generateObj('​Scutoids'​)
 +grp_scutoids.parent = grp_alles
 +
 +print(">>",​ grp_alles.name)
 +
 +#   setup Größen
 +x_max = 100
 +y_max = 100
 +z_max = 100
 +anzahlKerne = 25        #   ​Minimum 8 wegen Framing
 +
 +#del_col = (1.0, 0.0, 0.0, 1)
 +tetra = []
 +
 +#   ​Kernliste wird generiert
 +ker = genKerne(anzahlKerne,​ x_max, y_max, z_max)
 +
 +#   ​Generiert auf Basis der Kernliste die Delaunay-Tetraedisierung
 +for i in range(0, len(ker)):
 +    for j in range(i+1, len(ker)):
 +        for k in range(j+1, len(ker)):
 +            for l in range(k+1, len(ker)):
 +                ​
 +                t = Tetraeder([ker[i],​ ker[j], ker[k], ker[l]],"​Tetraeder"​)
 +                ​
 +                #   ​random red color, weil es nice aussieht...
 +                green_tint = randint(0, 6)/100
 +                blue_tint = randint(0,​6)/​100
 +                del_col = (1.0, green_tint, blue_tint, 1.0)
 +                t.selfRender(ker,​ del_col, tetra)
 +
 +#   ​erstellt die notwendigen Sammellisten,​ die die entsprechenden Information über ALLE finalen Zellen enthalten
 +vertex = [[] for dummy in range(anzahlKerne)] ​    # ​  liste alle vertecies, index markiert die Zellnummer, zu der sie gehören
 +faces = [[] for dummy in range(anzahlKerne)] ​     #   liste alle faces, index markiert die Zellnummer, zu der sie gehören
 +
 +#   ​Generiert auf Basis der Delaunay-Tetraedisierung das Voronoi-Diagramm
 +for u in range(0, len(ker)):
 +    for v in range(u+1, len(ker)):
 +        z_verts = []
 +        #   Alle Vertecies, die rund um die Verbindung beider Zellkerne liegen (Eckpunkte der Zelland zwischen ihnen) werden in z_verts abgespeichert
 +        for w in range(0, len(tetra)):​
 +            if ((ker[u] in tetra[w].verts) and (ker[v] in tetra[w].verts)):​
 +                z_verts.append(tetra[w].sp)
 +        ​
 +        if (len(z_verts) > 2):      #   ​checkt,​ ob eine "​echte"​ Fläche aufgespannt wird
 +            normal = np.subtract(ker[u],​ ker[v])
 +            geordnet = polySortList(z_verts,​ normal)
 +            ​
 +            temp_face1 = []
 +            temp_face2 = []
 +            ​
 +            for i in range(0, len(geordnet)):​
 +                ​
 +                if (inListeAnStelleNP(geordnet[i],​ vertex[u]) != None):
 +                    temp_face1.append(inListeAnStelleNP(geordnet[i],​ vertex[u]))
 +                else:
 +                   ​vertex[u].append(geordnet[i])
 +                   ​temp_face1.append(inListeAnStelleNP(geordnet[i],​ vertex[u]))
 +                   
 +                if (inListeAnStelleNP(geordnet[i],​ vertex[v]) != None):
 +                    temp_face2.append(inListeAnStelleNP(geordnet[i],​ vertex[v]))
 +                else:
 +                   ​vertex[v].append(geordnet[i])
 +                   ​temp_face2.append(inListeAnStelleNP(geordnet[i],​ vertex[v]))
 +            faces[u].append(temp_face1)
 +            faces[v].append(temp_face2)
 +            ​
 +for i in range(0, anzahlKerne):​
 +    if (watertightTest(faces[i]) == True):
 +        print("​watertight"​)
 +        if (ScutoidTest(faces[i]) == True):
 +            yellow_tint = randint(10, 100)/100
 +            scu = generateObj("​Scutoid",​ vertex[i], faces[i], np.array([0,​0,​0]),​ ( 0.0, yellow_tint,​ 1.0, 1.0 ))
 +            scu.parent = grp_scutoids
 +        else:           
 +            red_tint = randint(0, 20)/100
 +            blue_tint = randint(0,​25)/​100
 +            zelle = generateObj("​Zelle",​ vertex[i], faces[i], np.array([0,​0,​0]),​ ( red_tint, 1.0, blue_tint, 1.0 ))
 +            zelle.parent = grp_zellen
 +    else: 
 +        rand = generateObj("​Randzelle",​ vertex[i], faces[i], np.array([0,​0,​0]))
 +        rand.parent = grp_randzellen
 +    ​
  
 </​code>​ </​code>​
ws1920/pmcd_25.03.2020.1585143581.txt.gz · Zuletzt geändert: 2020/03/25 14:39 von Zetraeder