Funktion für die Verteilung von Rechtecken in einer Fläche

  • Servus...

    Ich bräuchte mal wieder nen Lösungsansatz... :cursing:
    Ich habe eine unendliche Fläche. Darauf möchte ich eine immer unterschiedliche Anzahl von Rechtecken ( auch immer unterschiedlich in Breite und Höhe ) verteilen.
    Ich hatte erst an einfache verteilugn in X bis eine bestimmte Breit und dann eine Art Zeile weiter in Y angedacht aber das gefällt mir nicht. Sie sollen sich halt frei verteilen...
    ich hab mal nen paar Bilder gemacht wie ich es mir vorstelle...

    Lösung in Post [ offen ] Funktion für die Verteilung von Rechtecken in einer Fläche

    [Blockierte Grafik: http://img256.imageshack.us/img256/894/16105851.png
    Jetzt sollen sie verteilt werden....am besten mit einem Kollisionsabstand, den man frei wählen kann....

    [Blockierte Grafik: http://img13.imageshack.us/img13/2747/37111750.png
    Sieht schon fast gut aus... nur etwas unschön irgendwie...

    [Blockierte Grafik: http://img651.imageshack.us/img651/3111/96771349.png
    Das wäre natürlich die Beste Lösung..
    Ich dachte mir einfach, dass man es vieleicht mit Brutforce machen muss.. d.h. min. und max. Abstand zum ersten... aber keine Überschneidung

    Danke schonmal....

    MFG chris :D

  • Wenn du weißt, wie viele rechtecke es sein müssen, dann erstelle so viele x und y Koordinaten Variablen und generiere mit Random() ihren Wert dann zufällig. Genauso mit der Länge und Breite, Variablen erstellen, Random(), fertig.

    Ist nicht die Endlösung, aber könnte weiter inspirieren.
    Hoffe es hilft.

    MfG mazZ

  • Servus...

    Also ich bin etwas weiter gekommen... allerdings habe ich ein Problem mit den Überschneidungen...
    Sieht man im folgendem Bild sehr gut.. :S

    [Blockierte Grafik: http://img641.imageshack.us/img641/6298/unbenanntur.png]

    Wie kann ich jetzt am besten überprüfen wenn ich ein neues Rechteck hinzufüge ob es schon ein Rechteck gibt,
    das an dieser Stelle ist, oder ich mit dem eingefügten vieleicht ein anderes berühre...
    max die orangenen dürfen sich berühren aber nicht überschneiden.... ?(

    Spoiler anzeigen
    [autoit]

    #include <array.au3>
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $hArea = _sharing2D_SetArea(0,0,800,800)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 20
    _sharing2D_Add_2DItem($hArea,Random(40,90,1),Random(110,200,1),10 )
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _sharing2D_DEBUG($hArea)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _sharing2D_Add_2DItem( ByRef $_Sharing2D_Array,$_ItemWidth,$_ItemHeight,$_Safety_Zone = 10 )
    If UBound ( $_Sharing2D_Array ) < 2 Then
    _Array2DAdd($_Sharing2D_Array,Round(($_Sharing2D_Array[0][2]/2)-($_ItemWidth/2)-$_Safety_Zone,0)&'|'& _
    Round(($_Sharing2D_Array[0][3]/2)-($_ItemHeight/2)-$_Safety_Zone,0)&'|'& _
    Round($_ItemWidth+($_Safety_Zone*2),0)&'|'& _
    Round($_ItemHeight+($_Safety_Zone*2),0)&'|'& _
    Round($_Safety_Zone,0) )
    Else
    $_Random_X = Round(Random(0,$_Sharing2D_Array[0][2]-$_ItemWidth-$_Safety_Zone,1),0)
    $_Random_Y = Round(Random(0,$_Sharing2D_Array[0][3]-$_ItemHeight-$_Safety_Zone,1),0)
    _Array2DAdd($_Sharing2D_Array, $_Random_X&'|'& _
    $_Random_Y&'|'& _
    Round($_ItemWidth,0)&'|'& _
    Round($_ItemHeight,0)&'|'& _
    Round($_Safety_Zone,0) )
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _sharing2D_SetArea($Xin,$Yin,$Width,$Height)
    _GDIPlus_Startup()
    Global $_Sharing2D_Array[1][5]
    $_Sharing2D_Array[0][0] = $Xin
    $_Sharing2D_Array[0][1] = $Yin
    $_Sharing2D_Array[0][2] = $Width
    $_Sharing2D_Array[0][3] = $Height
    Return $_Sharing2D_Array
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _sharing2D_DEBUG($_Sharing2D_Array)
    $_hDebugGui = GUICreate("DEBUGMODE", $_Sharing2D_Array[0][2],$_Sharing2D_Array[0][3] )
    GUISetState(@SW_SHOW,$_hDebugGui)

    [/autoit] [autoit][/autoit] [autoit]

    $_hGraphic = _GDIPlus_GraphicsCreateFromHWND($_hDebugGui)
    $_hBMP = _GDIPlus_BitmapCreateFromGraphics ($_Sharing2D_Array[0][2],$_Sharing2D_Array[0][3], $_hGraphic )
    $_hBuffer = _GDIPlus_ImageGetGraphicsContext($_hBMP)

    [/autoit] [autoit][/autoit] [autoit]

    ;Rahmen
    $_hPen_Border = _GDIPlus_PenCreate ( 0xFF00FF00,4 )
    _GDIPlus_GraphicsDrawRect($_hBuffer, $_Sharing2D_Array[0][0],$_Sharing2D_Array[0][1],$_Sharing2D_Array[0][2],$_Sharing2D_Array[0][3],$_hPen_Border )

    [/autoit] [autoit][/autoit] [autoit]

    ; Mittelpunkt
    $_hPen_Middle = _GDIPlus_PenCreate ( 0xFFFF0000,1 )
    _GDIPlus_GraphicsDrawLine($_hBuffer, ($_Sharing2D_Array[0][2]/2)-5,$_Sharing2D_Array[0][3]/2,($_Sharing2D_Array[0][2]/2)+5,$_Sharing2D_Array[0][3]/2,$_hPen_Middle )
    _GDIPlus_GraphicsDrawLine($_hBuffer, ($_Sharing2D_Array[0][2]/2),($_Sharing2D_Array[0][3]/2)-5,($_Sharing2D_Array[0][2]/2),($_Sharing2D_Array[0][3]/2)+5,$_hPen_Middle )

    [/autoit] [autoit][/autoit] [autoit]

    ; Rechtecke
    $_hPen_Rect = _GDIPlus_PenCreate ( 0xFF0000FF,1 )
    $_hBrush_Rect = _GDIPlus_BrushCreateSolid('0x'&Hex(40, 2)&'0000FF' )
    $_hPen_SaftyZone = _GDIPlus_PenCreate ( 0xFFFF8C00,1 )
    For $i = 1 To UBound ( $_Sharing2D_Array )-1
    _GDIPlus_GraphicsDrawRect($_hBuffer, $_Sharing2D_Array[$i][0], _
    $_Sharing2D_Array[$i][1], _
    $_Sharing2D_Array[$i][2], _
    $_Sharing2D_Array[$i][3], _
    $_hPen_SaftyZone )
    _GDIPlus_GraphicsFillRect($_hBuffer, $_Sharing2D_Array[$i][0]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][1]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][2]-($_Sharing2D_Array[$i][4]*2), _
    $_Sharing2D_Array[$i][3]-($_Sharing2D_Array[$i][4]*2), _
    $_hBrush_Rect )
    _GDIPlus_GraphicsDrawRect($_hBuffer, $_Sharing2D_Array[$i][0]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][1]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][2]-($_Sharing2D_Array[$i][4]*2), _
    $_Sharing2D_Array[$i][3]-($_Sharing2D_Array[$i][4]*2), _
    $_hPen_Rect )
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($_hGraphic, $_hBMP, 0, 0,$_Sharing2D_Array[0][2], $_Sharing2D_Array[0][3])
    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    EndSwitch
    WEnd
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Array2DAdd(ByRef $avArray, $sValue='')
    If ( Not IsArray($avArray) ) Then
    SetError(1)
    Return 0
    EndIf
    Local $i
    Local $UBound2nd = UBound($avArray,2)
    If @error = 2 Then
    ReDim $avArray[UBound($avArray)+1]
    $avArray[UBound($avArray)-1] = $sValue
    Else
    Local $arValue
    ReDim $avArray[UBound($avArray)+1][$UBound2nd]
    If $sValue = '' Then
    For $i = 0 To $UBound2nd-2
    $sValue &= '|'
    Next
    EndIf
    $arValue = StringSplit($sValue, '|')
    If $arValue[0] <> $UBound2nd Then
    SetError(2)
    Return 0
    EndIf
    For $i = 0 To $UBound2nd-1
    $avArray[UBound($avArray)-1][$i] = $arValue[$i+1]
    Next
    EndIf
    Return -1
    EndFunc ;==>_Array2DAdd

    [/autoit]

    Hab mich schon tot gesucht bei Wikipedia nach Formeln für sowas... :cursing:
    Vieleicht hat ja jemand ne Idee....

    MFG chris :D

  • Du erstellst 1nes zufällig.
    Die Koordienaten x1, x2, y1, y2 (alle Eckpunkte) speicherst du in einem Array.

    Bei dem 2. überprüfst du, ob die x1 bzw. die x2 zwischen den x1 und x2 des 1. rechtecks liegt. Wenn ja dann überprüfst du das gleiche noch mit den y Koordienaten. Sonst spawnen.

  • Du kannst nur Rechtecke plazieren, wenn die Summer der Fläche der Rechtecke kleiner als die Fläche der GUI ist.

    Beim Positionieren musst du das Rechteck mit allen anderen Rechtecken auf Kollision testen, damit es nicht zu Überschneidungen kommt!

    Die Kollisionsberechnung von solchen Flächen ist im Prinzip relativ "einfach":

    [autoit]


    Func _RectCollision($Rect1X1,$Rect1Y1,$Rect1X2,$Rect1Y2, $Rect2X1, $Rect2Y1, $Rect2X2, $Rect2Y2)
    ; Prog@ndy
    Local Const $tagRECT = "long;long;long;long"
    Local $1 = DllStructCreate($tagRECT)
    Local $2 = DllStructCreate($tagRECT)
    Local $3 = DllStructCreate($tagRECT)
    DllStructSetData($1,1,$Rect1X1)
    DllStructSetData($1,2,$Rect1Y1)
    DllStructSetData($1,3,$Rect1X2)
    DllStructSetData($1,4,$Rect1Y2)
    DllStructSetData($2,1,$Rect2X1)
    DllStructSetData($2,2,$Rect2Y1)
    DllStructSetData($2,3,$Rect2X2)
    DllStructSetData($2,4,$Rect2Y2)
    Local $r = DllCall("User32.dll", "int", "IntersectRect", "ptr", DllStructGetPtr($3), "ptr", DllStructGetPtr($1), "ptr", DllStructGetPtr($2))
    If @error Then Return SetError(1,0,0)
    Return $r[0]<>0
    EndFunc

    [/autoit]

    Gruß,
    UEZ

    PS: ich hatte auch das Problem mit "Simple Ball Collision Simulation" bei dem Platzieren auf dem Bildschirm (mit /debug kann man zuschauen, wie zufällige Positionen auf Kollision geprüft werden)

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Hi,
    gib mal ne Hausnummer, nach welchen Kriterien sich die Rechtecke verteilen sollen.
    Möglichst kleiner Abstand der Rechtecke zueinander in einem Umkreis, oder in einer Ellypse oder auch (das ist dann ein MiniMax-Problem) der minimale "Abfall" bei Zuschnitt aus einer x*y-großen Platte.....da gibts reichlich Möglichkeiten, viele Rechtecke anzuordnen^^

  • Morgen ....

    Danke erst mal für die Version UEZ werd die dann in meiner Frühstückspause mal testen...

    Andy...
    Also am besten wäre es so... Das erste Rechteck wird im Mittelpunkt erstellt...
    die anderen sollen dann im möglichst kleinen Abstand Kreismäßig um das mittlere verteilt werden
    ohne das sich die orangenen Zonen überschreiten oder die Rechtecke gedreht oder verzogen werden.

    Wie geht man an sowas Mathematisch ran?


    MFG chris :D

  • Servus...

    Soooo habs mal eingebaut...

    [Blockierte Grafik: http://img695.imageshack.us/img695/8337/image1hm.png]

    Spoiler anzeigen
    [autoit]


    #include <array.au3>
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $hArea = _sharing2D_SetArea(0,0,800,800)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 35
    _sharing2D_Add_2DItem($hArea,Random(40,90,1),Random(110,180,1),10 )
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _sharing2D_DEBUG($hArea)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _sharing2D_Add_2DItem( ByRef $_Sharing2D_Array,$_ItemWidth,$_ItemHeight,$_Safety_Zone = 10 )
    If UBound ( $_Sharing2D_Array ) < 2 Then
    _Array2DAdd($_Sharing2D_Array,Round(($_Sharing2D_Array[0][2]/2)-($_ItemWidth/2)-$_Safety_Zone,0)&'|'& _
    Round(($_Sharing2D_Array[0][3]/2)-($_ItemHeight/2)-$_Safety_Zone,0)&'|'& _
    Round($_ItemWidth+($_Safety_Zone*2),0)&'|'& _
    Round($_ItemHeight+($_Safety_Zone*2),0)&'|'& _
    Round($_Safety_Zone,0) )
    Else
    $_Random_X = Round(Random(0,$_Sharing2D_Array[0][2]-$_ItemWidth-$_Safety_Zone,1),0)
    $_Random_Y = Round(Random(0,$_Sharing2D_Array[0][3]-$_ItemHeight-$_Safety_Zone,1),0)

    [/autoit] [autoit][/autoit] [autoit]

    $Collision = False
    For $i = 1 To UBound ( $_Sharing2D_Array ) -1

    [/autoit] [autoit][/autoit] [autoit]

    ;======================================================
    ; RecCollisions Punkte...
    ;======================================================
    ; Gibt FALSE zurück wenn die Rechtecke sich berühren
    ;
    ; 1X1/1Y1 -------
    ; | |
    ; | |
    ; | |
    ; | 2X1/2Y1--|------
    ; | | | |
    ; | | | |
    ; --------1X2/1Y2 |
    ; | |
    ; | |
    ; | |
    ; ---------2X1/2Y2
    ;
    If _RectCollision( $_Sharing2D_Array[$i][0],$_Sharing2D_Array[$i][1], _ ;1X1/1Y1
    $_Sharing2D_Array[$i][0]+$_Sharing2D_Array[$i][2],$_Sharing2D_Array[$i][1]+$_Sharing2D_Array[$i][3], _ ;1X2/1Y2
    $_Random_X,$_Random_Y, _ ;2X1/2Y1
    $_Random_X+$_ItemWidth,$_Random_Y+$_ItemHeight ) Then
    $Collision = True
    EndIf
    Next
    If $Collision Then
    _sharing2D_Add_2DItem($_Sharing2D_Array,$_ItemWidth,$_ItemHeight,$_Safety_Zone )
    Else
    _Array2DAdd($_Sharing2D_Array, $_Random_X&'|'& _
    $_Random_Y&'|'& _
    Round($_ItemWidth,0)&'|'& _
    Round($_ItemHeight,0)&'|'& _
    Round($_Safety_Zone,0) )
    EndIf
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _sharing2D_SetArea($Xin,$Yin,$Width,$Height)
    _GDIPlus_Startup()
    Global $_Sharing2D_Array[1][5]
    $_Sharing2D_Array[0][0] = $Xin
    $_Sharing2D_Array[0][1] = $Yin
    $_Sharing2D_Array[0][2] = $Width
    $_Sharing2D_Array[0][3] = $Height
    Return $_Sharing2D_Array
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _sharing2D_DEBUG($_Sharing2D_Array)
    $_hDebugGui = GUICreate("DEBUGMODE", $_Sharing2D_Array[0][2],$_Sharing2D_Array[0][3] )
    GUISetState(@SW_SHOW,$_hDebugGui)

    [/autoit] [autoit][/autoit] [autoit]

    $_hGraphic = _GDIPlus_GraphicsCreateFromHWND($_hDebugGui)
    $_hBMP = _GDIPlus_BitmapCreateFromGraphics ($_Sharing2D_Array[0][2],$_Sharing2D_Array[0][3], $_hGraphic )
    $_hBuffer = _GDIPlus_ImageGetGraphicsContext($_hBMP)

    [/autoit] [autoit][/autoit] [autoit]

    ;Rahmen
    $_hPen_Border = _GDIPlus_PenCreate ( 0xFF00FF00,4 )
    _GDIPlus_GraphicsDrawRect($_hBuffer, $_Sharing2D_Array[0][0],$_Sharing2D_Array[0][1],$_Sharing2D_Array[0][2],$_Sharing2D_Array[0][3],$_hPen_Border )

    [/autoit] [autoit][/autoit] [autoit]

    ; Mittelpunkt
    $_hPen_Middle = _GDIPlus_PenCreate ( 0xFFFF0000,1 )
    _GDIPlus_GraphicsDrawLine($_hBuffer, ($_Sharing2D_Array[0][2]/2)-5,$_Sharing2D_Array[0][3]/2,($_Sharing2D_Array[0][2]/2)+5,$_Sharing2D_Array[0][3]/2,$_hPen_Middle )
    _GDIPlus_GraphicsDrawLine($_hBuffer, ($_Sharing2D_Array[0][2]/2),($_Sharing2D_Array[0][3]/2)-5,($_Sharing2D_Array[0][2]/2),($_Sharing2D_Array[0][3]/2)+5,$_hPen_Middle )

    [/autoit] [autoit][/autoit] [autoit]

    ; Rechtecke
    $_hPen_Rect = _GDIPlus_PenCreate ( 0xFF0000FF,1 )
    $_hBrush_Rect = _GDIPlus_BrushCreateSolid('0x'&Hex(40, 2)&'0000FF' )
    $_hPen_SaftyZone = _GDIPlus_PenCreate ( 0xFFFF8C00,1 )
    For $i = 1 To UBound ( $_Sharing2D_Array )-1
    _GDIPlus_GraphicsDrawRect($_hBuffer, $_Sharing2D_Array[$i][0], _
    $_Sharing2D_Array[$i][1], _
    $_Sharing2D_Array[$i][2], _
    $_Sharing2D_Array[$i][3], _
    $_hPen_SaftyZone )
    _GDIPlus_GraphicsFillRect($_hBuffer, $_Sharing2D_Array[$i][0]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][1]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][2]-($_Sharing2D_Array[$i][4]*2), _
    $_Sharing2D_Array[$i][3]-($_Sharing2D_Array[$i][4]*2), _
    $_hBrush_Rect )
    _GDIPlus_GraphicsDrawRect($_hBuffer, $_Sharing2D_Array[$i][0]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][1]+$_Sharing2D_Array[$i][4], _
    $_Sharing2D_Array[$i][2]-($_Sharing2D_Array[$i][4]*2), _
    $_Sharing2D_Array[$i][3]-($_Sharing2D_Array[$i][4]*2), _
    $_hPen_Rect )
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($_hGraphic, $_hBMP, 0, 0,$_Sharing2D_Array[0][2], $_Sharing2D_Array[0][3])
    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    EndSwitch
    WEnd
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Array2DAdd(ByRef $avArray, $sValue='')
    If ( Not IsArray($avArray) ) Then
    SetError(1)
    Return 0
    EndIf
    Local $i
    Local $UBound2nd = UBound($avArray,2)
    If @error = 2 Then
    ReDim $avArray[UBound($avArray)+1]
    $avArray[UBound($avArray)-1] = $sValue
    Else
    Local $arValue
    ReDim $avArray[UBound($avArray)+1][$UBound2nd]
    If $sValue = '' Then
    For $i = 0 To $UBound2nd-2
    $sValue &= '|'
    Next
    EndIf
    $arValue = StringSplit($sValue, '|')
    If $arValue[0] <> $UBound2nd Then
    SetError(2)
    Return 0
    EndIf
    For $i = 0 To $UBound2nd-1
    $avArray[UBound($avArray)-1][$i] = $arValue[$i+1]
    Next
    EndIf
    Return -1
    EndFunc ;==>_Array2DAdd

    [/autoit] [autoit][/autoit] [autoit]

    Func _RectCollision($Rect1X1,$Rect1Y1,$Rect1X2,$Rect1Y2, $Rect2X1, $Rect2Y1, $Rect2X2, $Rect2Y2)
    ; Prog@ndy
    Local Const $tagRECT = "long;long;long;long"
    Local $1 = DllStructCreate($tagRECT)
    Local $2 = DllStructCreate($tagRECT)
    Local $3 = DllStructCreate($tagRECT)
    DllStructSetData($1,1,$Rect1X1)
    DllStructSetData($1,2,$Rect1Y1)
    DllStructSetData($1,3,$Rect1X2)
    DllStructSetData($1,4,$Rect1Y2)
    DllStructSetData($2,1,$Rect2X1)
    DllStructSetData($2,2,$Rect2Y1)
    DllStructSetData($2,3,$Rect2X2)
    DllStructSetData($2,4,$Rect2Y2)
    Local $r = DllCall("User32.dll", "int", "IntersectRect", "ptr", DllStructGetPtr($3), "ptr", DllStructGetPtr($1), "ptr", DllStructGetPtr($2))
    If @error Then Return SetError(1,0,0)
    Return $r[0]<>0
    EndFunc

    [/autoit]

    Funktioniert auch gut... aber....ab 30 Rechtecken kann es einen Error geben...
    ==> Recursion level has been exceeded - AutoIt will quit to prevent stack overflow.:

    schön wäre halt jetzt noch das die Rechtecke zueinander in einem Umkreis um das mittlere angeordnet werden.. wie von Andy angesprochen...

    MFG chris :D

  • Ok, kreisförmig "um das erste Rechteck" ist eine gute Hausnummer^^
    Als ersten Ansatz würde ich die Rechtecke sortieren, das größte zuerst. Wenn die Rechtecke nacheinander erstellt werden sollen, ist das aber auch nicht schlimm.
    Ich habe folgendes umgesetzt:
    -Rechteck erstellen mit zufälliger Breite und Höhe
    -vom Mittelpunkt (man könnte auch den Schwerpunkt aller Rechtecke nehmen) das Rechteck in Richtung Fenster-Rand bewegen, wenn es ein anderes Rechteck berührt, weiterbewegen.
    -Berührt es keines der anderen Rechtecke, dann ist eine potentielle Position erreicht.
    -Abstand bestimmen zum Mittelpunkt. Ist dieser Abstand minimal, dann Position merken.
    -Sind alle möglichen Positionen rund um die anderen Rechtecke abgearbeitet, Rechteck an die Position mit dem minimalen Abstand zum Mittelpunkt zeichnen.
    -Neues Rechteck erstellen uswusf

    hab das mit controls gebastelt, so wars einfacher^^ ist aber auch langsamer.
    Optimierbar ist die Schrittweite der Linienfunktion, z.B. nur jedes 2. oder 3. Pixel und der Kollisions-check
    Weiterhin würde ich den Schwerpunkt aller vorhandenen Rechtecke als neuen Startpunkt festlegen, die Rechtecke sollten so noch etwas näher zusammenrücken....

    Spoiler anzeigen
    [autoit]

    #include <GUIConstantsEx.au3>
    #include <Array.au3>
    #include <StructureConstants.au3>
    Dim $rechteck[100]
    Dim $a[4] ;$a = controlgetpos($hgui,"",$rechteck[$id])

    [/autoit] [autoit][/autoit] [autoit]

    Global $SPsx = 400 ;koordinaten Gesamt-Schwerpunkt
    Global $SPsy = 400
    Global $xmin, $ymin ;koordinaten des aktuellen rechtecks
    Global $abstand_min = 2 ^ 12 ;minimaler abstand

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("Rechtecke anordnen", 800, 800, 100, 1)
    GUISetState()
    $rechteck[0] = GUICtrlCreateGraphic(0, 0, 800, 800)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 40 ;anzahl der Rechtecke
    $a[2] = Random(1, 7, 1) * 20 ;breite
    $a[3] = Random(1, 7, 1) * 20 ;höhe
    $rechteck[$i] = GUICtrlCreateGraphic(20, 20, $a[2], $a[3])
    GUICtrlSetBkColor(-1, Random(1, 255 * 255 * 255, 1))
    GUICtrlSetColor(-1, Random(1, 255, 1))

    [/autoit] [autoit][/autoit] [autoit]

    $abstand_min = 2 ^ 12 ;zzt minimaler abstand des aktuellen Rechtecks zum Mittelpunkt
    For $x = 100 To 700 Step 20;oberer Rand von links nach rechts
    $y = 100
    line($SPsx, $SPsy, $x, $y, $i) ;auf der Linie entlang das Rechteck bewegen
    If $abstand_min = 0 Then ;gilt nur für das allererste Rechteck
    GUICtrlSetPos($rechteck[1], $xmin, $ymin)
    ContinueLoop 2 ;im mittelpunkt plazieren, nächstes Rechteck erstellen
    EndIf
    Next
    For $y = 100 To 700 Step 20;rechter Rand von oben nach unten
    $x = 700
    line($SPsx, $SPsy, $x, $y, $i)
    Next
    For $x = 700 To 100 Step -20;oberer Rand
    $y = 700
    line($SPsx, $SPsy, $x, $y, $i)
    Next
    For $y = 700 To 100 Step -20;oberer Rand
    $x = 100
    line($SPsx, $SPsy, $x, $y, $i)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    GUICtrlSetPos($rechteck[$i], $xmin, $ymin)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Do
    Until GUIGetMsg() = -3

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Line($x1, $y1, $x2, $y2, $rechteck) ;y=mx+b = geradengleichung =linienfunktion linie von x1|y1 nach x2|y2 zeichnen
    If $x2 = $x1 Then ;senkrechte linie
    Local $Step = 1
    If $y2 < $y1 Then $Step = -1
    For $yy = $y1 To $y2 Step $Step
    If _checkueberlappung($x1, $yy, $rechteck) = 0 Then Return
    Next
    Return
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $y2 = $y1 Then ;waagrechte linie
    $Step = 1
    If $x2 < $x1 Then
    $Step = -1
    EndIf
    For $xx = $x1 To $x2 Step $Step
    If _checkueberlappung($xx, $y1, $rechteck) = 0 Then Return
    Next
    Return
    Else
    Local $m = ($y2 - $y1) / ($x2 - $x1)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $b = $y1 - $m * $x1

    [/autoit] [autoit][/autoit] [autoit]

    If Abs($m) <= 1 Then
    $Step = -1
    If $x1 < $x2 Then $Step = 1

    [/autoit] [autoit][/autoit] [autoit]

    For $xx = $x1 To $x2 Step $Step
    Local $yy = Round($m * $xx + $b)
    If _checkueberlappung($xx, $yy, $rechteck) = 0 Then Return
    Next
    Else
    $Step = -1
    If $y1 < $y2 Then $Step = 1
    For $yy = $y1 To $y2 Step $Step
    Local $xx = Round(($yy - $b) / $m)
    If _checkueberlappung($xx, $yy, $rechteck) = 0 Then Return
    Next
    EndIf
    EndFunc ;==>Line

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _checkueberlappung($sxi, $syi, $id) ;kollision ermitteln
    $x1i = $sxi - ($a[2] / 2) ;aktuelles rechteck oben links
    $y1i = $syi - ($a[3] / 2)
    $x2i = $x1i + $a[2] ;unten rechts
    $y2i = $y1i + $a[3]
    GUICtrlSetPos($rechteck[$id], $x1i, $y1i) ;ausklammern....

    [/autoit] [autoit][/autoit] [autoit]

    For $m = 1 To $i - 1 ;alle vorhandenen Rechtecke prüfen
    $b = ControlGetPos($hgui, "", $rechteck[$m]) ;position des rechtecks ermitteln
    $x1m = $b[0] ;oben links
    $y1m = $b[1]
    $x2m = $b[0] + $b[2] ;unten rechts
    $y2m = $b[1] + $b[3]
    If _RectCollision($x1m, $y1m, $x2m, $y2m, $x1i, $y1i, $x2i, $y2i) Then ;wenn kollision, dann return 1
    ;MsgBox(0, "Kollision mit: ", $m)
    Return 1
    EndIf
    Next
    ;MsgBox(0, "keine kollision!", $sxi&" "&$syi)
    $abstand = Sqrt(($sxi - $SPsx) ^ 2 + ($syi - $SPsy) ^ 2) ;abstand vom Gesamt-Schwerpunkt
    If $abstand <= $abstand_min Then ;kleinster abstand zum Gesamt-Schwerpunkt gefunden
    ;MsgBox(0, "Kleinster abstand", $abstand)
    $abstand_min = $abstand
    $xmin = $x1i ;x-koordinate merken
    $ymin = $y1i ;y-koordinate merken
    EndIf
    Return 0 ;keine kollision, return 0
    EndFunc ;==>_checkueberlappung

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _RectCollision($Rect1X1, $Rect1Y1, $Rect1X2, $Rect1Y2, $Rect2X1, $Rect2Y1, $Rect2X2, $Rect2Y2)
    ; Prog@ndy
    Local Const $tagRECT = "long;long;long;long"
    Local $1 = DllStructCreate($tagRECT)
    Local $2 = DllStructCreate($tagRECT)
    Local $3 = DllStructCreate($tagRECT)
    DllStructSetData($1, 1, $Rect1X1)
    DllStructSetData($1, 2, $Rect1Y1)
    DllStructSetData($1, 3, $Rect1X2)
    DllStructSetData($1, 4, $Rect1Y2)
    DllStructSetData($2, 1, $Rect2X1)
    DllStructSetData($2, 2, $Rect2Y1)
    DllStructSetData($2, 3, $Rect2X2)
    DllStructSetData($2, 4, $Rect2Y2)
    Local $r = DllCall("User32.dll", "int", "IntersectRect", "ptr", DllStructGetPtr($3), "ptr", DllStructGetPtr($1), "ptr", DllStructGetPtr($2))
    If @error Then Return SetError(1, 0, 0)
    Return $r[0] <> 0
    EndFunc ;==>_RectCollision

    [/autoit]

    Bild hänge ich noch an....[Blockierte Grafik: http://www.abload.de/img/forum7bw3.jpg]

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (1. Juli 2010 um 18:03)

  • Servus...

    Danke erst mal Andy... :thumbup:
    war in etwas das was ich haben wollte nur halt viel zu langsam... ?(
    Ich war aber auch an einer ähnlichen Version am arbeiten,die jetzt fertig ist und die ich mal gerade hier vorstellen möchte.

    Also es sieht mit der DEBUG Version jetzt so aus... 8o

    autoit.de/wcf/attachment/10568/

    Ich habe daraus auch ne mini UDF gemacht... natürlich ohne GDI.
    Die rechnet dann 25 Rechtecke in ner 800 x 800 großen Zone in 1,7 sec.
    Beide Scripte sind im Anhang... :!:

    Vieleicht kanns ja noch jemand gebrauchen :party:

    MFG chris :D