Benutzer-Werkzeuge

Webseiten-Werkzeuge


ws1617:optimales_puppenhaus

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
ws1617:optimales_puppenhaus [2017/04/23 11:51]
workbench
ws1617:optimales_puppenhaus [2017/04/24 11:52] (aktuell)
workbench
Zeile 9: Zeile 9:
  
  
-Unser Projekt „Optimales Puppenhaus“ hat die dreidimensionale Generierung eines Hauses gemäß den Anforderungen des Nutzers (Baugrundfläche etc.) und gewisser Optimalitätskriterien zum Ziel. Als optimal wird beispielsweise die Ausrichtung der Fenster für einen vorteilhaften Lichteinfall,​ die Verhältnisse der Raummaße gemäß des goldenen Schnittes, aber auch ganz banale Dinge wie die Position von Schränken mit einem ausreichenden Abstand zueinander, sodass der eine Schrank nicht die Öffnung der Tür des anderen behindert, angesehen.+Unser Projekt „Optimales Puppenhaus“ hat die dreidimensionale Generierung eines Hauses gemäß den Anforderungen des Nutzers (Baugrundfläche etc.) und gewisser Optimalitätskriterien zum Ziel. Als optimal wird beispielsweise die Ausrichtung der Fenster für einen vorteilhaften Lichteinfall,​ die Verhältnisse der Raummaße gemäß des goldenen Schnittes, aber auch ganz banale Dinge((Abandoned)) ​wie die Position von Schränken mit einem ausreichenden Abstand zueinander, sodass der eine Schrank nicht die Öffnung der Tür des anderen behindert, angesehen.
 Ziel des Projekts ist der 3D-Druck eines nach unseren Maßstäben optimalen kleinen Puppenhauses. Ziel des Projekts ist der 3D-Druck eines nach unseren Maßstäben optimalen kleinen Puppenhauses.
  
Zeile 20: Zeile 20:
  
 === Projektplanung === === Projektplanung ===
-In den ersten Wochen haben wir uns unterschiedliche Teilziele definiert, wovon sich aber die meisten als unrealistisch herausgestellt haben. Schlussendlich haben wir uns die drei dimensionale Visualisierung eines nach unterschiedlichen ​kriterien ​optimierten Raumes als Endziel gesetzt. Als Zwischenziele haben wir uns die einzelnen Objekte vorgenommen,​ aus welche ein Raum sich zusammensetzt.+In den ersten Wochen haben wir uns unterschiedliche Teilziele definiert, wovon sich aber die meisten als unrealistisch herausgestellt haben. Schlussendlich haben wir uns die drei dimensionale Visualisierung eines nach unterschiedlichen ​Kriterien ​optimierten Raumes als Endziel gesetzt. Als Zwischenziele haben wir uns die einzelnen Objekte vorgenommen,​ aus welche ein Raum sich zusammensetzt.
  
-Nach einigen Wochen haben wir unsere größere Gruppe von sechs Personen, in zwei Untergruppen ​ aufgeteilt. Die Triangulisierungs-Gruppe war verantwortlich für die Konvertion eines generierten 3D-Objektes,​ in ein geometrisch vergleichbares Objekt, bestehend ausschließlich aus der Zusammensetzung flacher Dreiecke. Dadurch werden überflüssige Trennwände entfernt, wodurch es möglich wird das Objekt mittels eines 3D-Druckers auszudrucken.+Nach einigen Wochen haben wir unsere größere Gruppe von sechs Personen, in zwei Untergruppen ​ aufgeteilt. Die Triangulierungs-Gruppe war verantwortlich für die Konvertion eines generierten 3D-Objektes,​ in ein geometrisch vergleichbares Objekt, bestehend ausschließlich aus der Zusammensetzung flacher Dreiecke. Dadurch werden überflüssige Trennwände entfernt, wodurch es möglich wird das Objekt mittels eines 3D-Druckers auszudrucken.
  
-Die andere Gruppe ist Verantwortlich für die Visualisierung und den Optimierungs-Algorithmus. Die Visualisierung besteht aus einer 3-Dimensionalen Darstellung der Wände welches mittels dem Modul "​Vpython"​ ermöglicht wird. Der Optimierungs-Algorithmus soll die Maße eines Raumes unter dem Einfluss unterschiedlicher Bedingungen und Einschränkungen berechnen. Für die Optimierung benutzen wird die "​fmin_cobyla"​ Funktion aus der "​scipy.optimize" ​bibliothek. Für weitere mathematsiche Operationen benutzen wir das Modul "​numpy"​.+Die andere Gruppe ist Verantwortlich für die Visualisierung und den Optimierungs-Algorithmus. Die Visualisierung besteht aus einer 3-Dimensionalen Darstellung der Wände welches mittels dem Modul "​Vpython"​ ermöglicht wird. Der Optimierungs-Algorithmus soll die Maße eines Raumes unter dem Einfluss unterschiedlicher Bedingungen und Einschränkungen berechnen. Für die Optimierung benutzen wird die "​fmin_cobyla"​ Funktion aus der "​scipy.optimize" ​Bibliothek. Für weitere mathematsiche Operationen benutzen wir das Modul "​numpy"​.
  
 === Projektverlauf === === Projektverlauf ===
  
-== Visualisierung ​==+__**Visualisierung**__
  
 Um einen Raum 3-Dimensional darzustellen,​ haben wir die einzelnen Bestandteile eines Raumen in unabhängige Objekte eingeteilt. Das einfachste Objekt ist das "​Wall-Objekt"​ aus dem kompliziertere Objekte wie das "​Fensterwand-Objekt"​ und das "​Türwand-Objekt"​ zusammengesetzt werden. ​ Um einen Raum 3-Dimensional darzustellen,​ haben wir die einzelnen Bestandteile eines Raumen in unabhängige Objekte eingeteilt. Das einfachste Objekt ist das "​Wall-Objekt"​ aus dem kompliziertere Objekte wie das "​Fensterwand-Objekt"​ und das "​Türwand-Objekt"​ zusammengesetzt werden. ​
  
-__Wall-Objekt__+__**Wall-Objekt**__
  
 <code python> <code python>
Zeile 97: Zeile 97:
 </​code>​ </​code>​
  
-Ein Wall-Objekt ist im Prinzip nichts anderes als ein flacher Quader, welche sich die Koordinaten seiner acht Eckpunkte merkt. Beim initieren ​eines Wall-Objektes muss ein Mittelpunkt,​ eine Achse und eine Länge der Wand angegeben werden. Mithilfe dieser Informationen können die entsprechenden Eckpunkte ausgerechnet werden. Darüberhinaus besitzt jedes Wall-Objekt auch noch die Methoden push(), rotate() und getPoints(). Die push() und rotate() Methoden bewegen das Objekt im Raum und berechnet die neue Positionen der Eckpunkte. Dadurch ist sich jedes Wall-Objekt seinen eigenen Punkten zu jeder Zeit und in jeder Position bewusst. Die getPoints() Methode erlaubte uns die Koordinaten jeder der Eckpunkte abzurufen.+Ein Wall-Objekt ist im Prinzip nichts anderes als ein flacher Quader, welche sich die Koordinaten seiner acht Eckpunkte merkt. Beim initiieren ​eines Wall-Objektes muss ein Mittelpunkt,​ eine Achse und eine Länge der Wand angegeben werden. Mithilfe dieser Informationen können die entsprechenden Eckpunkte ausgerechnet werden. Darüberhinaus besitzt jedes Wall-Objekt auch noch die Methoden push(), rotate() und getPoints(). Die push() und rotate() Methoden bewegen das Objekt im Raum und berechnet die neue Positionen der Eckpunkte. Dadurch ist sich jedes Wall-Objekt seinen eigenen Punkten zu jeder Zeit und in jeder Position bewusst. Die getPoints() Methode erlaubte uns die Koordinaten jeder der Eckpunkte abzurufen.
  
-__Tuerwand-Objekt__+__**Tuerwand-Objekt**__
 <code python> <code python>
 from __future__ import division from __future__ import division
Zeile 178: Zeile 178:
 Die methode structure_wall() ist verantwortlich für das kreeiren der einzelnen Wände in den korrekten Positionen und setzt das gesamte Tuerwand-Objekt zusammen. Die methode structure_wall() ist verantwortlich für das kreeiren der einzelnen Wände in den korrekten Positionen und setzt das gesamte Tuerwand-Objekt zusammen.
  
-__Fenster-Objekt__+__**Fenster-Objekt**__
 <code python> <code python>
 from __future__ import division from __future__ import division
Zeile 276: Zeile 276:
 </​code>​ </​code>​
  
-Ähnlich wie bei dem Tuerwand-Objekt,​ wird das Fensterwand-Objekt aus 4 unterschiedlichen Wall-Objekten zusammengesetzt. Beim inizieeren ​eines Tuerwand-Objektes muss die Länge, Position und die Achse angegeben werden. Optional kann auch noch die Größe des Fensters wie auch seine Position mittel des ratio-Parameters angepasst werden. ​+Ähnlich wie bei dem Tuerwand-Objekt,​ wird das Fensterwand-Objekt aus 4 unterschiedlichen Wall-Objekten zusammengesetzt. Beim initiieren ​eines Tuerwand-Objektes muss die Länge, Position und die Achse angegeben werden. Optional kann auch noch die Größe des Fensters wie auch seine Position mittel des ratio-Parameters angepasst werden. ​
  
-__Raum-Objekt__+__**Raum-Objekt**__
  
 <code python> <code python>
Zeile 393: Zeile 393:
 </​code>​ </​code>​
  
-Nachdem die Grundbausteine eines Raumes etabliert sind, werden sie im Raum-Objekt zusammengefasst. Beim initieeren ​eines Raum-Objekts muss eine x-Länge des Raumes, eine y-Länge des Raumes und jeweils eine Angabe welche Wand ein Tüerwand-Objekt sein soll bzw. ein Fensterwand-Objekt. Die structure_room() Methode kreeirt die jeweiligen Objekt-Bausteine in den entsprechenden Positionen. ​+Nachdem die Grundbausteine eines Raumes etabliert sind, werden sie im Raum-Objekt zusammengefasst. Beim initiieren ​eines Raum-Objekts muss eine x-Länge des Raumes, eine y-Länge des Raumes und jeweils eine Angabe welche Wand ein Tüerwand-Objekt sein soll bzw. ein Fensterwand-Objekt. Die structure_room() Methode kreeirt die jeweiligen Objekt-Bausteine in den entsprechenden Positionen. ​
  
 Die Wall.getPoints() Methode dient als Schnittstelle zwischen der Visualisierungs Gruppe und der Triangulisierungs Gruppe. Die Wall.getPoints() Methode dient als Schnittstelle zwischen der Visualisierungs Gruppe und der Triangulisierungs Gruppe.
  
-__Main-Visualisierung__+__**Main-Visualisierung**__
  
-Nachdem wir uns auf ein Layout für die Grundrisse der Wohnung geeinigt haben, bemerkten wir schnell das unsere ursprüngliche Idee jeden einzelnen Raum als eigenes Raum-Objekt zu initieeren, ineffizient und unpraktisch war. Angenommen alle 5 Räume (4 Räume + Gang) würden als eigene Raum-Objekte passend im Koordinatensystem nebeneinander initialisiert werden, so würde in bestimmten Fällen mehr als eine Wand die selben Räume trennen, wodurch Wände unnötig überlappen. Deshalb entschieden wir uns den Raum aus den einzelnen Raum-Bausteinen zusammenzusetzen. So besteht ein Raum mit zwei Fenstern und einer Tür aus zwei Fensterwand-Objekte,​ ein Tuerwand-Objekt und ein Wall-Objekt.+Nachdem wir uns auf ein Layout für die Grundrisse der Wohnung geeinigt haben, bemerkten wir schnell das unsere ursprüngliche Idee jeden einzelnen Raum als eigenes Raum-Objekt zu initiieren, ineffizient und unpraktisch war. Angenommen alle 5 Räume (4 Räume + Gang) würden als eigene Raum-Objekte passend im Koordinatensystem nebeneinander initialisiert werden, so würde in bestimmten Fällen mehr als eine Wand die selben Räume trennen, wodurch Wände unnötig überlappen. Deshalb entschieden wir uns den Raum aus den einzelnen Raum-Bausteinen zusammenzusetzen. So besteht ein Raum mit zwei Fenstern und einer Tür aus zwei Fensterwand-Objekte,​ ein Tuerwand-Objekt und ein Wall-Objekt.
  
 Die getStructure() Funktion, ruft mithilfe eine Moduls namens "​subprocesses32"​ den Algorithmus auf (siehe unten) welche eine Datenstruktur liefert, in der die optimierten Maße der Wohnung gespeichert sind. Diese wird anschließend ausgelesen in der structureBuilding Funktion und die einzelnen Wände werden entsprechend initialisiert. Die getStructure() Funktion, ruft mithilfe eine Moduls namens "​subprocesses32"​ den Algorithmus auf (siehe unten) welche eine Datenstruktur liefert, in der die optimierten Maße der Wohnung gespeichert sind. Diese wird anschließend ausgelesen in der structureBuilding Funktion und die einzelnen Wände werden entsprechend initialisiert.
Zeile 500: Zeile 500:
  Wall.standard_wall_thickness = z_len + 0.2  Wall.standard_wall_thickness = z_len + 0.2
   
- boden_pos = (mp[0], -0.1, mp[2]) + boden_pos = (mp[0], -0.1, mp[2])
- sphere(pos=mp,​radius=0.1,​color=color.green) +
- sphere(pos=boden_pos,​radius=0.1,​color=color.red) +
- +
  boden = Wall(position=boden_pos,​ ax=(1,0,0), length=x_len + 0.2)  boden = Wall(position=boden_pos,​ ax=(1,0,0), length=x_len + 0.2)
   
  Wall.standard_wall_height = 3.0  Wall.standard_wall_height = 3.0
  Wall.standard_wall_thickness = 0.2  Wall.standard_wall_thickness = 0.2
-  
-arrow(pos=(0,​0,​0),​ axis=(0,​0,​5),​ shaftwidth=0.1) # z Axis 
-sphere(radius=0.1,​ pos=(0,​0,​0),​ color=color.red) 
-label(pos=(2,​0,​0),​ text="​x Axis") 
-arrow(pos=(0,​0,​0),​ axis=(10,​0,​0),​ shaftwidth=0.1,​ color=color.red) # x Axis 
-label(pos=(0,​0,​2),​ text="​z Axis") 
  
 StructureBuilding(ast.literal_eval(getStructure())) StructureBuilding(ast.literal_eval(getStructure()))
Zeile 522: Zeile 513:
 </​code>​ </​code>​
  
 +== Algorithmus ==
 +
 +Für die Optimierung bedienten wir uns der "​scipy.optimize"​ Bibliothek in der die Funktion "​fmin_cobyla"​ beinhaltet ist. fmin_cobyla minimisiert den Wert einer Funktion mittels Einschränkungen und Linearer Approxmiation (Constrained Optimization By Linear Approximation - COBYLA).
 +
 +<code python>
 +from __future__ import print_function
 +from scipy.optimize import fmin_cobyla
 +import numpy as np
 +
 +def constrains():​
 + cons = []
 + eps = 0
 + GRUND_X = 10.0
 + GRUND_Y = 5.0
 + cons.append(lambda v:v[0] - eps) #(x0, y0, x1, y1, x2, y2, x3, y3, x4, y4)
 + cons.append(lambda v:v[1] - eps) #(0,   ​1, ​ 2 ,  3,  4,  5,  6, 7,  8,  9)
 + cons.append(lambda v:v[2] - eps)
 + cons.append(lambda v:v[3] - eps)
 + cons.append(lambda v:v[4] - eps)
 + cons.append(lambda v:v[5] - eps)
 + cons.append(lambda v:v[6] - eps)
 + cons.append(lambda v:v[7] - eps)
 + cons.append(lambda v:v[8] - eps)
 + cons.append(lambda v:v[9] - eps)
 + cons.append(lambda v: -(v[1] + v[3] - GRUND_Y)) ​
 + cons.append(lambda v: -(v[9] + v[3] - GRUND_Y))
 + cons.append(lambda v: -(v[7] + v[5] - GRUND_Y))
 + cons.append(lambda v: -(v[0] + v[8] + v[6] - GRUND_X))
 + cons.append(lambda v: -(v[0] + v[8] + v[4] - GRUND_X))
 + cons.append(lambda v: -(v[2] + v[4] - GRUND_X))
 + cons.append(lambda v: -(v[3] - 1.25))
 + return cons
 +
 +def flaeche_0(v):​
 + return v[0] * v[1]
 +
 +def flaeche_1(v):​
 + return v[2] * v[3]
 +
 +def flaeche_2(v):​
 + return v[4] * v[5]
 +
 +def flaeche_3(v):​
 + return v[6] * v[7]
 +
 +def flaeche_4(v):​
 + return v[8] * v[9]
 +
 +
 +def quadratizitaet_0(v):​
 + return ((v[0] * v[1]) / (v[0]*v[0] + v[1]*v[1]))
 +
 +def quadratizitaet_1(v):​
 + return ((v[2] * v[3]) / (v[2]*v[2] + v[3]*v[3]))
 +
 +def quadratizitaet_2(v):​
 + return ((v[4] * v[5]) / (v[4]*v[4] + v[5]*v[5]))
 +
 +def quadratizitaet_3(v):​
 + return ((v[6] * v[7]) / (v[6]*v[6] + v[7]*v[7]))
 +
 +def quadratizitaet_4(v):​
 + return ((v[8] * v[9]) / (v[8]*v[8] + v[9]*v[9]))
 +
 +
 +def goldener_schnitt_0(v):​
 + g = 1 / ((1 + np.sqrt(5)) / 2)
 + return np.power(((v[0] / v[1]) - g), 2) * np.power((v[1] / v[0]) - g, 2)
 +
 +def goldener_schnitt_1(v):​
 + g = 1 / ((1 + np.sqrt(5)) / 2)
 + return np.power(((v[2] / v[3]) - g), 2) * np.power((v[3] / v[2]) - g, 2)
 +
 +def goldener_schnitt_2(v):​
 + g = 1 / ((1 + np.sqrt(5)) / 2)
 + return np.power(((v[4] / v[5]) - g), 2) * np.power((v[5] / v[4]) - g, 2)
 +
 +def goldener_schnitt_3(v):​
 + g = 1 / ((1 + np.sqrt(5)) / 2)
 + return np.power(((v[6] / v[7]) - g), 2) * np.power((v[7] / v[6]) - g, 2)
 +
 +def goldener_schnitt_4(v):​
 + g = 1 / ((1 + np.sqrt(5)) / 2)
 + return np.power(((v[8] / v[9]) - g), 2) * np.power((v[9] / v[8]) - g, 2)
 +
 +
 +def flaeche_ins(v):​
 + return -np.prod([flaeche_0(v),​ flaeche_1(v),​ flaeche_2(v),​ flaeche_3(v),​ flaeche_4(v)])
 +
 +def quadratizitaet_ins(v):​
 + return -np.prod([quadratizitaet_0(v),​ quadratizitaet_1(v),​ quadratizitaet_2(v),​ quadratizitaet_3(v),​ quadratizitaet_4(v)])
 +
 +def goldener_schnitt_ins(v):​
 + return -np.prod([goldener_schnitt_0(v),​ goldener_schnitt_1(v),​ goldener_schnitt_2(v),​ goldener_schnitt_3(v),​ goldener_schnitt_4(v)])
 +
 +def target(v):
 + w1 = 1.0/10.0 * 1 # Flaeche
 + w2 = 10.0/10.0 * 0 # Quadratizitaet // * 0 dar widerspruechlich mit Goldener Schnitt
 + w3 = 9.0/10.0 * 1 # Goldener Schnitt
 +
 + return (w1 * flaeche_ins(v) + w2 * quadratizitaet_ins(v) + w3 * goldener_schnitt_ins(v))
 +
 +def RaumAlgo():
 + cons = constrains()
 + return fmin_cobyla(target,​[2.1]*10,​cons)
 +</​code>​
 +
 +fmin_cobyla benötigt eine Hauptfunktion welche minimiert wird und Bedingungen welche die Hauptfunktion entsprechend einschränkt. ​
 +
 +Die Funktion "​constraints()"​ liefert eine Liste aller einschränkenden Bedingungen. In der constraints() Funktion wird, unter anderem, dass Intervall festgelegt in der fmin_cobyla optimieren darf. Zum Beispiel darf keiner der Räume vertikal größer werden als die Vertikal angebene Grundfläche oder der Gang darf nicht kleiner werden als die Gang Mindestgröße,​ bei uns festgelegt auf 1.25 Einheiten.
 +
 +Unsere Hauptfunktion "​target()"​ wird zusammengesetzt aus drei Optimierungskriterien bezogen auf jeden einzelnen Raum des Grundrisses. Die Optimierungskriterien bestehen aus der Größtmöglichen Fläche (Maximal mögliche Größe für jeden Raum), bestmöglichste Quadratizität (Bestmögliches Quadratisches Seitenverhältnis des Raumes) und dem goldenen Schnitt (Seitenverhältnis des goldenen Schnittes). Für jeden Raum existiert eine Funktion welche jedes dieser Kriterien für den entsprechenden Raum berechnet. Diese werden anschließend in separaten Funktionen zusammengefasst und in der Hauptfunktion "​target()"​ mit anpassbarem Gewicht, der "​RaumAlgo()"​ Funktion übergeben. "​RaumAlgo()"​ ruft den Optimierungs Algorithmus fmin_cobyla auf und gibt dessen Ergebnisse zurück.
 +
 +Die Datei "​main.py"​ in dem Algorithmus Verzeichniss dient dem Programm als Kontaktstelle zwischen dem Algorithmus und der Visualisierung.
 +<code python>
 +from __future__ import print_function
 +import numpy
 +from algo import RaumAlgo
 +import copy
 +
 +struktur = {
 + 0 : [(1, 2), (4, 3)],
 + 1 : [(4, 0), (0,4), (2, 3)],
 + 2 : [(3, 0), (4, 1), (1, 1)],
 + 3 : [(4, 1), (2, 2)],
 + 4 : [(0, 1), (1, 2), (2, 3), (3, 3)]
 + }
 +
 +def getListFromNumpyArray():​
 + raumAlgoListe = list(RaumAlgo())
 + filtered = []
 + for char in raumAlgoListe:​
 + if type(char) is numpy.float64:​
 + filtered.append(char)
 + return filtered
 +
 +def createStructure():​
 + structure = copy.deepcopy(struktur)
 + data_raw = getListFromNumpyArray()
 + data = [(data_raw[0],​ data_raw[1]),​ (data_raw[2],​ data_raw[3]),​ (data_raw[4],​ data_raw[5]),​ (data_raw[6],​ data_raw[7]),​ (data_raw[8],​ data_raw[9])]
 + for room in range(5):
 + structure[room].insert(0,​ data[room])
 + return structure
 +
 +print(createStructure())
 +</​code>​
 +
 +__**Endergebniss**__
 +
 +Ruft man die Datei "​main.py"​ in dem Visualisierungs Algorithmus auf, so erhält man eine Optimierte Visualisierung des Grundrisses. ​
  
 ==== Nützliche Quellen: ==== ==== Nützliche Quellen: ====
ws1617/optimales_puppenhaus.1492941109.txt.gz · Zuletzt geändert: 2017/04/23 11:51 von workbench