Anordnung von Quadraten, in Rechtecke zusammenfassen.

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von φConst.

    Anordnung von Quadraten, in Rechtecke zusammenfassen.

    Hallo,
    gegeben sei folgendes Kachel-Feld:



    Wie würdet ihr vorgehen, um am effektivsten die rot markierten Kacheln entsprechend in optimal große Rechtecke zu unterteilen? (Mit anderen Worten: Die Kacheln optimal in Rechtecke zusammenfassen).

    Mir kam ein Ansatz mit genetischen Algorithmus in den Sinn, dessen Fitness-Funktion exemplarisch ANZAHL_KACHELN_IM_RECHTECK/(A*B), wobei jeweils A und B die Seiten des Rechtecks repräsentieren, sein könnte..
    Gäbe es aber vielleicht eine idealere Herangehensweise?

    Danke!
    Und Gott alleine weiß alles am allerbesten und besser.
    ich trau dem genetischen Hype nicht so - ich würde erstma was "konventionelles" versuchen:
    Ich würde alle möglichen grössten Rechtecke ermitteln, dabei Dubletten eliminieren.
    Dann überlappen sich die Rechtecke noch, aber da würdich einen Algo anwenden, der bei Überlappung eines der beiden Rechtecke beschneidet. Beim Beschneiden gibts immer genau 2 sinnvolle Möglichkeiten, und da kann man testen, welche die günstigere ist.
    Ich denke, der Algo müsste ein optimales Ergebnis generieren.

    Spasseshalber kannste mal hier gugge: codeproject.com/Articles/1209269/Not-Levenshtein
    Dort tritt ein entfernt vergleichbares Problem mit Diagonalen auf (Abschnitt "Eliminate overlapping matches"), bei denen auftreten kann, dass nur entweder die eine oder die annere in voller Länge gültig sein kann, und mein Algo sorgt dafür, dass die längere Diagonale bevorzugt wird. Also da tätige ich ähnlich verschrobene Gedankengänge.

    PS: der von mir skizzierte Algo ergäbe aus deim Beispiel eine Aufteilung in 7 Rechtecke - findest du eine bessere Lösung?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @φConst Wenn es vorrangig um die Darstellung geht, gugst Du Region: docs.microsoft.com/de-de/dotne…N&view=netframework-4.7.2
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Was genau meinst du?
    Es geht eher um die strukturelle Partitionierung: Die roten Felder sollen einfach jeweils in Rechtecke zerteilt werden,
    sodass alle Kacheln in Rechtecken zusammengefasst sind.
    Idealerweise sollen aber alle Rechtecke optimal groß sein, das heißt, jedes Rechteck soll optimal viele Kacheln halten.

    Im obigen Beispiel:

    1. Rechteck: 12 Kacheln
    2. Rechteck: 1 Kachel
    3. Rechteck: 1 Kachel
    4. Rechteck: 3 Kacheln
    5. Rechteck: 1 Kachel
    6: Rechteck: 1 Kachel
    7. Rechteck: 1 Kachel

    ErfinderDesRades schrieb:

    PS: der von mir skizzierte Algo ergäbe aus deim Beispiel eine Aufteilung in 7 Rechtecke - findest du eine bessere Lösung?

    Ja, 7 wären optimal.

    Addendum: Ich hatte folgende Idee jetzt:
    Im Grunde betrachtet man die Kacheln-Form, als ein Polygon. Man verbinde alle Ecken jeweils miteinander.
    Existieren zwei schneidende Diagonalen, mit derselben Länge, handelt es sich um ein Rechteck.

    Hättet ihr eine alternative Idee?
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „φConst“ ()

    φConst schrieb:

    Was genau meinst du?
    So was:
    UserControl mit einer zur Laufzeit anpassbaren Form
    Das ist wahrscheinlich nicht das, wonach Du suchst.
    Vielleicht eine solche Herangehensweise:
    Nimm einen inneren Punkt und finde alle Nachbarn, die ein Rechteck ergeben (etwa eine "Spirale" drum herum legen, jede Seite im eine Reihe / Spalte erweitern).
    Wenn Du am Ende bist, nimmst Du einen nächsten noch nicht erwischten inneren Punkt ...
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo φConst,
    du kannst aus deinem Kachel-Feld eine Region erstellen. Jede Region
    wird als eine Liste von Rechtecken gespeichert. Diese Liste kann man
    auslesen. Ich habe sowas vor einigen Jahren mal in VBA programmiert. Hier
    der an dein Kachel-Feld angepasste Code, lauffähig z.B. unter MS-Word:

    Visual Basic-Quellcode

    1. Private Type RECT
    2. Left As Long
    3. Top As Long
    4. Right As Long
    5. Bottom As Long
    6. End Type
    7. Private Const RGN_OR = 2
    8. Private Declare Function CreateRectRgn Lib "gdi32" (ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long) As Long
    9. Private Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
    10. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    11. Private Declare Function GetRegionData Lib "gdi32" (ByVal hRgn As Long, ByVal dwCount As Long, lpRgnData As Any) As Long
    12. Private Sub UserForm_Activate()
    13. Dim i As Long, j As Long, Fd(5) As String
    14. Dim Rgn1 As Long, Rgn2 As Long, Rgn3 As Long, Field As Long
    15. Dim x1 As Long, y1 As Long, N1 As Long, N2 As Long, Buffer() As RECT
    16. Dim x2 As Long, y2 As Long, flg1 As Boolean, Out As String
    17. Fd(0) = " ## "
    18. Fd(1) = " ### ## "
    19. Fd(2) = " ## # "
    20. Fd(3) = " ##### "
    21. Fd(4) = " ## "
    22. Fd(5) = " ### "
    23. Field = 20 ' Feldgröße
    24. Rgn1 = CreateRectRgn(0, 0, 0, 0)
    25. Rgn2 = CreateRectRgn(0, 0, 0, 0)
    26. For i = 0 To UBound(Fd)
    27. For j = 0 To Len(Fd(i)) - 1
    28. If Mid$(Fd(i), j + 1, 1) = "#" Then
    29. x1 = j * Field
    30. y1 = i * Field
    31. Rgn3 = CreateRectRgn(x1, y1, x1 + Field, y1 + Field)
    32. Call CombineRgn(Rgn1, Rgn1, Rgn3, RGN_OR)
    33. Call DeleteObject(Rgn3)
    34. Rgn3 = CreateRectRgn(y1, x1, y1 + Field, x1 + Field)
    35. Call CombineRgn(Rgn2, Rgn2, Rgn3, RGN_OR)
    36. Call DeleteObject(Rgn3)
    37. End If
    38. Next j
    39. Next i
    40. N1 = GetRegionData(Rgn1, 0, ByVal 0)
    41. N2 = GetRegionData(Rgn2, 0, ByVal 0)
    42. If N2 < N1 Then
    43. flg1 = True
    44. ReDim Buffer(N2 / 16 - 1)
    45. Call GetRegionData(Rgn2, N2, Buffer(0))
    46. Else
    47. flg1 = False
    48. ReDim Buffer(N1 / 16 - 1)
    49. Call GetRegionData(Rgn1, N1, Buffer(0))
    50. End If
    51. Call DeleteObject(Rgn1)
    52. Call DeleteObject(Rgn2)
    53. Out = CStr(UBound(Buffer) - 1) & " Rechteck(e)" & vbCr & vbCr
    54. For i = 2 To UBound(Buffer)
    55. With Buffer(i)
    56. If flg1 = True Then
    57. x1 = .Top
    58. y1 = .Left
    59. x2 = .Bottom
    60. y2 = .Right
    61. Else
    62. x1 = .Left
    63. y1 = .Top
    64. x2 = .Right
    65. y2 = .Bottom
    66. End If
    67. End With
    68. Out = Out & "Rechteck " & CStr(i - 1) & ": x1=" & CStr(x1) & _
    69. " y1=" & CStr(y1) & " x2=" & CStr(x2) & " y2=" & CStr(y2) & vbCr
    70. Next i
    71. MsgBox Out
    72. End Sub
    Gruss,

    Neptun
    @Neptun Jetzt musst Du da nur noch .NET draus machen. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!