2010-12-11 20 views
8

Jestem studentem architektury, który próbuje rozwiązać problem przestrzenny z C# w Grasshopper dla Rhino.Algorytm losowej przestrzeni graniczącej z elementami o tej samej długości.

Przestrzeń, którą próbuję stworzyć, to przestrzeń wystawiennicza na lotnisku. Przestrzeń będą składać się z elementów o podobnej długości. Chodzi o to, aby połączyć je z zawiasem, a tym samym umożliwić im tworzenie przestrzeni o różnym układzie i rozmiarze w zależności od liczby użytych elementów.

illustration

Jak widać z rysunku Chciałbym przestrzeń żeby zakończyć się otwarciem długość elementu z dala od punktu początkowego.

Pierwszą próbą było stworzenie trójkątów równobocznych w zależności od liczby segmentów (ścian). W skrócie, od punktu początkowego tworzone są trójkąty, a następnie boki trójkąta, które tworzą zewnętrzną granicę, są dodawane do listy punktów. Ta lista punktów jest zwracana do aplikacji Grasshopper, która rysuje linie między punktami. Chodzi o to, że stworzyłem kolejny trójkąt losowo albo z boku AC, albo BC z ostatniego trójkąta.

Oto przykład przestrzeniach utworzonych (na 12 - 8 - 14 - 20 elementów):

various generated shapes

Oto kod źródłowy, który tworzy wykazy punkcie:

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); 
} 

Chciałbym zróżnicować tworzenie tych kształtów, tak aby były nie tylko korytarzami, ale przypominały moje początkowe szkice. Chciałbym, aby algorytm wziął dane wejściowe segmentów (liczba i długość), a następnie zaproponował różne układy przestrzeni, które można utworzyć za pomocą tej liczby segmentów. Zgaduję, że z powodu tesselacji przestrzeń musiałaby zostać utworzona za pomocą trójkątów, kwadratów lub sześciokątów? Czy uważasz, że powinienem zajrzeć do tego algorytmu "maksymalnego obszaru": Covering an arbitrary area with circles of equal radius here on stackoverflow?

Byłbym wdzięczny za każdą pomoc dotyczącą tego algorytmu. Pozdrawiam, Eirik

+1

Wyjaśniłeś, co próbujesz zrobić. Ale czym właściwie jesteś i właściwie CHCESZ? – Dialecticus

+4

Istnieje wykładniczo duża liczba znacząco różnych kształtów, które może zaproponować algorytm, ponieważ zapewniasz tylko ** ograniczenia **. Musisz również podać parametry/cele/metryki, aby odróżnić pożądane lub niepożądane kształty. – RBarryYoung

+0

Dzięki za komentarze Dialecticus i RBarryYoung. Myślę, że to, czego chcę, można odpowiedzieć, odpowiadając na prośbę o parametry/cele. Jedną z możliwości jest utworzenie maksymalnego obszaru za pomocą podanej numer_of_sekwencji. Gdybym miał dodać drugi parametr; liczba pokoi, można sobie wyobrazić, że segmenty tworzą linię, która graniczy z kilkoma przestrzeniami, które są równe pod względem wielkości i połączone z korytarzem. W tym scenariuszu chcę algorytmu, który może utworzyć maksymalną zamkniętą przestrzeń z number_of_segments. – Eirik

Odpowiedz

1

Jeśli interesuje Cię program generujący instancje do zewnętrznej oceny (a nie wszystkie takie instancje), możesz "nadmuchać" swoją krzywą. Na przykład w 14-segmentowej instancji na drugim obrazie jest miejsce, w którym krzywa idzie do wewnątrz i podwaja się z powrotem - tak, że twoja lista punktów ma jeden punkt powtórzony. W przypadku takich krzywych można wyciąć wszystko między dwoma (identycznymi) punktami (A i B), a także jednym z otaczających punktów (A lub B), i odzyskałeś kilka punktów, aby rozwinąć swoją krzywą - prawdopodobnie powodując struktura nie-korytarzowa. Być może będziesz musiał wykonać trochę magii, aby upewnić się, że jest to "zamknięta" krzywa, ale kupuj naprzemiennie dodając segmenty z przodu iz tyłu krzywej.

Inna możliwość: jeśli potrafisz zidentyfikować wnętrze krzywej (i istnieją w tym celu algorytmy), to wtedy, gdy dwa segmenty tworzą kąt wklęsły względem twojej krzywej, możesz wydmuchać ją, tworząc obszar nie-korytarzowy . Na przykład. Drugi i trzeci segment powyżej 14-segmentowej krzywej może zostać wydmuchany w lewo.

Sukcesywne stosowanie tych dwóch metod do krzywej o kształcie korytarza powinno generować wiele kształtów, których szukasz. Powodzenia!

+0

Dzięki za świetne wejście! Jak już mówisz, dla mnie może być interesujące generowanie instancji do zewnętrznej oceny zamiast uzyskiwania tylko najbardziej wydajnej/poprawnej alternatywy. Postaram się dodać czek dla identycznych punktów przed zwróceniem listy i "nadmuchać" listę w tym miejscu. Czy mogę przejść przez listę i użyć metody FindIndex, aby to osiągnąć? – Eirik

Powiązane problemy