2010-12-11 7 views
8

Ich bin ein Architekturstudent versucht, ein räumliches Problem mit C# in Grasshopper für Rhino zu lösen.Algorithmus für einen zufälligen Raum durch Elemente gleicher Länge

Der Raum, den ich versuche zu schaffen, ist ein Ausstellungsraum in einem Flughafen. Der Raum besteht aus Elementen ähnlicher Länge. Die Idee besteht darin, sie mit einem Scharnier zu verbinden und ihnen dadurch zu ermöglichen, Räume mit unterschiedlichem Layout und unterschiedlicher Größe zu schaffen, je nachdem wie viele Elemente verwendet werden.

illustration

Wie Sie aus der Abbildung sehen kann, würde ich den Raum wie mit einer Öffnung eines Elements Länge Auswärtspunkt vom Start zu beenden.

Mein erster Versuch bestand darin, je nach Anzahl der benötigten Segmente (Wände) gleichseitige Dreiecke zu erstellen. Kurz gesagt, vom Ausgangspunkt werden Dreiecke erstellt, und dann werden die Seiten des Dreiecks, die den äußeren Rahmen bilden, zu einer Liste von Punkten hinzugefügt. Diese Punktliste wird an die Grasshopper-Anwendung zurückgegeben, die Linien zwischen den Punkten zeichnet. Ein kleiner Punkt ist, dass ich die Erstellung des nächsten Dreiecks entweder von der Seite AC oder BC aus dem letzten Dreieck zufällig gemacht habe.

Hier ist ein Beispiel der Räume erzeugt (12 - 8 - 14 bis 20 Elemente):

various generated shapes

Hier ist der Quellcode, der diese Punktlisten erstellt:

private void RunScript(double radius, int walls, ref object A) 
{ 

    // 
    List<Point3d> pointList = new List<Point3d>(); 
    List<Point3d> lastList = new List<Point3d>(); 

    bool alternate = true; 
    bool swapped = false; 
    Random turn = new Random(); 

    // set up the first part of the triangle 
    Point3d point1 = new Point3d(0, 0, 0); 
    Point3d point2 = new Point3d(0, radius, 0); 
    pointList.Add(point1); 
    pointList.Add(point2); 
    Point3d calcPoint; 

    for(int i = 0; i < walls - 1; i++) // walls - 1, is because I need one less triangle to get to the amount of walls 
    { 
    // use the method to create two similar circles and return the intersection point 
    // in order to create an equilateral triangle 
    calcPoint = FindCircleIntersections(point1.X, point1.Y, point2.X, point2.Y, radius, alternate); 

    // random generator: will decide if the new triangle should be created from side BC or AC 
    bool rotate = turn.Next(2) != 0; 
    Print("\n" + rotate); 

    // set the 2nd and 3rd point as 1st and 2nd - depending on random generator. 
    if(rotate) 
    { 
     point1 = point2; 
     if(swapped == true) 
     swapped = false; 
     else 
     swapped = true; 
    } 

    // if the direction is swapped, the next point created will not be a part of the outer border 
    if(swapped) 
     lastList.Add(calcPoint); 
    else 
     pointList.Add(calcPoint); 

    point2 = calcPoint; 

    // swap direction of intersection 
    if(rotate) 
    { 
     if(alternate) 
     alternate = false; 
     else 
     alternate = true; 
    } 

    } 

    lastList.Reverse(); 

    foreach (Point3d value in lastList) 
    { 
    pointList.Add(value); 
    } 

    A = pointList; 

} 



// Find the points where the two circles intersect. 
private Point3d FindCircleIntersections(
    double cx0, double cy0, double cx1, double cy1, double rad, bool alternate) 
{ 
    // Find the distance between the centers. 
    double dx = cx0 - cx1; 
    double dy = cy0 - cy1; 
    double dist = Math.Sqrt(dx * dx + dy * dy); 


    // Find a and h. 
    double a = (rad * rad - rad * rad + dist * dist)/(2 * dist); 
    double h = Math.Sqrt(rad * rad - a * a); 

    // Find P2. 
    double cx2 = cx0 + a * (cx1 - cx0)/dist; 
    double cy2 = cy0 + a * (cy1 - cy0)/dist; 

    // Get the points P3. 
    if(alternate) 
    return new Point3d((double) (cx2 + h * (cy1 - cy0)/dist), (double) (cy2 - h * (cx1 - cx0)/dist), 0); 
    else 
    return new Point3d((double) (cx2 - h * (cy1 - cy0)/dist), (double) (cy2 + h * (cx1 - cx0)/dist), 0); 
} 

Was ich tun möchte, ist, die Gestaltung dieser Formen zu variieren, so dass sie nicht nur Korridore sind, sondern meinen ersten Skizzen ähneln. Ich möchte, dass ein Algorithmus eine Eingabe von Segmenten (Anzahl und Länge) vornimmt und dann verschiedene Raumlayouts vorschlägt, die mit dieser Anzahl von Segmenten erstellt werden können. Ich denke, wegen der Tesselation müsste der Raum mit Dreiecken, Quadraten oder Sechsecken erstellt werden? Denkst du, ich sollte in diesen "Maximum Area" -Algorithmus schauen: Covering an arbitrary area with circles of equal radius here on stackoverflow?

Ich würde jede Hilfe bei diesem Algorithmus sehr schätzen. Prost, Eirik

+1

Sie haben erklärt, was Sie zu tun versuchen. Aber was willst du eigentlich und grundsätzlich? – Dialecticus

+4

Es gibt eine exponentiell große Anzahl von deutlich unterschiedlichen Formen, die ein Algorithmus vorschlagen könnte, da Sie nur ** Einschränkungen ** bereitstellen. Sie müssen auch einige Parameter/Ziele/Metriken angeben, um wünschenswerte gegenüber unerwünschten Formen zu unterscheiden. – RBarryYoung

+0

Danke für Ihre Kommentare Dialecticus und RBarryYoung. Ich denke, was ich will, kann beantwortet werden, indem ich auf die Anfrage nach Parametern/Zielen antworte. Eine Alternative besteht darin, die maximale Fläche mit den bereitgestellten numer_of_segments zu erstellen. Wenn ich einen zweiten Parameter hinzufügen würde; number_of_rooms kann man sich vorstellen, dass die Segmente eine Linie bilden, die an mehrere gleich große Räume grenzt, die mit einem Korridor verbunden sind. In diesem Szenario möchte ich einen Algorithmus, der den maximalen geschlossenen Raum mit einer Anzahl von Segmenten erstellen kann. – Eirik

Antwort

1

Wenn Sie lediglich an einem Programm interessiert sind, um Instanzen zu generieren, die extern ausgewertet werden sollen (und nicht alle solchen Instanzen), könnten Sie Ihre Kurve "aufblasen". Zum Beispiel in der 14-Segment-Instanz in Ihrem zweiten Bild, gibt es eine Stelle, an der die Kurve nach innen geht und doppelt zurück - so hat Ihre Liste von Punkten einen Punkt wiederholt. Für Kurven wie diese könnten Sie alles zwischen den zwei (identischen) Punkten (A und B) sowie einem der umgebenden Punkte (A oder B) ausschneiden und einige Punkte zurückgewinnen, um Ihre Kurve zu erweitern - was möglicherweise zu eine Nicht-Korridor-Struktur. Sie müssen möglicherweise etwas Magie arbeiten, um sicherzustellen, dass es sich um eine "geschlossene" Kurve handelt. Kaufen Sie jedoch abwechselnd Segmente an der Vorder- und Rückseite der Kurve. Eine weitere Möglichkeit: Wenn Sie das Innere der Kurve identifizieren können (und es gibt Algorithmen dafür), dann können Sie irgendwo, wo zwei Segmente einen konkaven Winkel in Bezug auf Ihre Kurve bilden, diese ausblasen, um einen nicht-korridorischen Bereich zu bilden . Z.B. das zweite und dritte Segment Ihrer 14-Segment-Kurve oben könnte nach links ausgeblasen werden.

Wenn Sie diese beiden Methoden nacheinander auf Ihre Korridor-ähnliche Kurve anwenden, sollten viele der von Ihnen gewünschten Formen generiert werden. Viel Glück!

+0

Danke für den tollen Input! Wie Sie sagen, könnte es für mich in generierten Fällen interessant sein, extern zu bewerten, anstatt nur die effizienteste/richtige Alternative zu erhalten. Ich werde versuchen, einen Check für identische Punkte hinzuzufügen, bevor ich die Liste zurückgebe, und die Liste an diesem Punkt "aufblasen". Kann ich die Liste durchlaufen und die FindIndex-Methode verwenden, um dies zu erreichen? – Eirik

Verwandte Themen