Fläche mit Kreisen füllen

  • Allgemein

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von bsHobbit.

    Fläche mit Kreisen füllen

    Guten Morgen,

    ich habe folgendes Problem:

    Ich habe eine Fläche gekennzeichnet durch n Punkte, die mit einander verbunden sind.
    Von dieser Fläche kenne ich nur alle Punkte P.

    (Die Fläche ist beliebig, ist nur ein Beispiel in der Grafik)

    Nun habe ich einen Kreis, von dem ich den Radius kenne, nun soll der Kreis so oft in die Fläche, das er die Fläche ausfüllt.

    Das ganze mal Grafisch dargestellt:



    Und das Ergebnis soll das hier ergeben:
    (diese Grafik entspricht nicht dem tatsächlichen ergebnis)



    Ich selber hab noch keinen Ansatz gefunden, wie ich dieses Problem lösen kann. Vielleicht kann mir hier ja jemand helfen.

    Theoretisch würd es mir schon helfen, wenn mir jemand sagen könnte, wie ich herausfinde, ob ein Punkt, innerhalb der Fläche ist.


    Gruß Hobbit

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

    Ich kann dir sagen, wie du herausfindest, ob ein Punkt innerhalb eines Dreiecks liegt. Gegeben sind: A,B,C (alles Punkte vom Dreieck) sowie Z, der irgendwo liegen kann.

    Du ziehst von Z zu A,B und C jeweils 1Linie.

    Jetzt hast du die Winkel:

    AZB, BZC und CZA. Merke: Z ist immer in der Mitte!

    Jetzt zählst du alle 3 Winkel zusammen. Entspricht das resultat ungefähr (+- 0.5 Rehcenfehler) 360 (Vollkreis), so liegt der Punkt innerhalb des Dreiecks.

    Muahaha, ich habs grad nochmal durchgelesen und nix mehr kapiert:) Bei Fragen einfach nachfragen. Falls es dir überhaupt was bringt.

    Du könntest z.B. die Fläche in Dreiecke aufteilen und dann für jedes prüfen, ob der Punkt darinliegt. Sollte das bei einem der Fall sein, liegt der Punkt innerhlab der Fläche. Die se Methode ist aber sehr, sehr, sehr langsam.
    Joa, wenn ich mein Polygon noch in einzelne Dreicke aufteil, dann kann ich ja ewig rechnen xD

    Ich hab bereits eine Annährungslösung gefunden xD

    Ich bekomms nur iwi nich genauer hin, wenn sich einer dran setzen will...

    is mit vb2005 geschrieben, einfach alles kopieren, starten glücklich sein^^

    VB.NET-Quellcode

    1. Public Class Form1
    2. private P(100) As Point
    3. Private CountEdge As Integer = 0
    4. Private CurrPoint As Point
    5. Private Px As Point
    6. Private guiCrossList As New List(Of Point)
    7. Private MinL As Integer, MaxR As Integer
    8. Private MinT As Integer, MaxB As Integer
    9. Private SpotR As Integer = 10
    10. Private Sub createCircle(ByVal middle As Point, ByVal angle As Double, ByVal radius As Integer, ByVal spotRadius As Integer, ByVal WriteToCommandList As Boolean)
    11. Dim tmpPoint As Point
    12. Dim AddToAngle As Double
    13. Dim Perimeter As Double = 2 * Math.PI * radius
    14. Dim count As Double
    15. count = Math.Round(Perimeter / (2 * spotRadius))
    16. AddToAngle = 360 / count
    17. If radius <= spotRadius Then
    18. tmpPoint.X = middle.X
    19. tmpPoint.Y = middle.Y
    20. Else
    21. tmpPoint.X = (middle.X + Math.Cos(angle * Math.PI / 180) * radius)
    22. tmpPoint.Y = (middle.Y + Math.Sin(angle * Math.PI / 180) * radius)
    23. End If
    24. If angle < 360 Then
    25. If isPointInPolygon(tmpPoint) Then
    26. guiCrossList.Add(tmpPoint)
    27. End If
    28. If radius > spotRadius Then
    29. createCircle(middle, angle + AddToAngle, radius, spotRadius, WriteToCommandList)
    30. End If
    31. Else
    32. If radius > spotRadius Then
    33. createCircle(middle, 0, radius - spotRadius, spotRadius, WriteToCommandList)
    34. End If
    35. End If
    36. End Sub
    37. Private Function isPointInPolygon(ByVal point As Point) As Boolean
    38. Dim RCross As Integer = 0
    39. Dim LCross As Integer = 0
    40. For i As Integer = 0 To CountEdge - 1
    41. Dim EdgeStart As Point = P(i)
    42. Dim EdgeEnd As Point = P(i + 1)
    43. If i = CountEdge - 1 Then
    44. EdgeEnd = P(0)
    45. End If
    46. If (point = EdgeStart) Then
    47. Return True
    48. End If
    49. If (EdgeStart.Y > point.Y) <> (EdgeEnd.Y > point.Y) Then
    50. Dim Term1 As Integer = (EdgeStart.X - point.X) * (EdgeEnd.Y - point.Y) - (EdgeEnd.X - point.X) * (EdgeStart.Y - point.Y)
    51. Dim Term2 As Integer = (EdgeEnd.Y - point.Y) - (EdgeStart.Y - EdgeEnd.Y)
    52. If ((Term1 > 0) = (Term2 >= 0)) Then
    53. RCross += 1
    54. End If
    55. End If
    56. If (EdgeStart.Y < point.Y) <> (EdgeEnd.Y < point.Y) Then
    57. Dim Term1 As Integer = (EdgeStart.X - point.X) * (EdgeEnd.Y - point.Y) - (EdgeEnd.X - point.X) * (EdgeStart.Y - point.Y)
    58. Dim Term2 As Integer = (EdgeEnd.Y - point.Y) - (EdgeStart.Y - EdgeEnd.Y)
    59. If ((Term1 < 0) = (Term2 <= 0)) Then
    60. LCross += 1
    61. End If
    62. End If
    63. Next i
    64. If ((RCross Mod 2) <> (LCross Mod 2)) Then
    65. Return True
    66. End If
    67. Return (RCross Mod 2) = 1
    68. End Function

    VB.NET-Quellcode

    1. Private Function isIn() As Boolean
    2. Dim P1 As Point = Px
    3. Dim count As Integer = 0
    4. If isPointInPolygon(P1) Then
    5. tb.Text = "Drin"
    6. Else
    7. tb.Text = ""
    8. End If
    9. End Function
    10. Private Sub pp_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pp.MouseDown
    11. If PaintPoly.Checked Then
    12. If CountEdge < 100 Then
    13. P(CountEdge).X = e.X
    14. P(CountEdge).Y = e.Y
    15. CountEdge += 1
    16. MinL = IIf(e.X < MinL, e.X, MinL)
    17. MaxR = IIf(e.X > MaxR, e.X, MaxR)
    18. MinT = IIf(e.Y < MinT, e.Y, MinT)
    19. MaxB = IIf(e.Y > MaxB, e.Y, MaxB)
    20. End If
    21. Else
    22. Px.X = e.X
    23. Px.Y = e.Y
    24. Dim Middle As New Point(pp.Width / 2, pp.Height / 2)
    25. Dim X1 As Integer = MaxR - MinL
    26. Dim x2 As Integer = MaxB - MinT
    27. Dim r As Integer = IIf(X1 > x2, X1 / 2, x2 / 2)
    28. createCircle(Middle, 0, r, SpotR, False)
    29. End If
    30. pp.Refresh()
    31. End Sub
    32. Private Sub pp_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pp.MouseMove
    33. If PaintPoly.Checked Then
    34. CurrPoint.X = e.X
    35. CurrPoint.Y = e.Y
    36. pp.Refresh()
    37. End If
    38. End Sub
    39. Private Sub pp_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles pp.Paint
    40. If CountEdge > 0 Then
    41. If PaintPoly.Checked Then
    42. e.Graphics.DrawLine(Pens.Red, P(CountEdge - 1), CurrPoint)
    43. e.Graphics.DrawLine(Pens.Red, CurrPoint, P(0))
    44. Else
    45. e.Graphics.DrawLine(Pens.White, P(CountEdge - 1), CurrPoint)
    46. e.Graphics.DrawLine(Pens.White, CurrPoint, P(0))
    47. End If
    48. End If
    49. For i As Integer = 0 To CountEdge - 2
    50. e.Graphics.DrawLine(Pens.Black, P(i), P(i + 1))
    51. Next i
    52. If CountEdge > 2 Then
    53. e.Graphics.DrawLine(Pens.Black, P(0), P(CountEdge - 1))
    54. End If
    55. 'e.Graphics.DrawLine(Pens.Blue, Px.X - 4, Px.Y, Px.X + 4, Px.Y)
    56. 'e.Graphics.DrawLine(Pens.Blue, Px.X, Px.Y - 4, Px.X, Px.Y + 4)
    57. For i As Integer = 0 To guiCrossList.Count - 1
    58. 'e.Graphics.DrawLine(Pens.Red, guiCrossList.Item(i).X - 4, guiCrossList.Item(i).Y, guiCrossList.Item(i).X + 4, guiCrossList.Item(i).Y)
    59. 'e.Graphics.DrawLine(Pens.Red, guiCrossList.Item(i).X, guiCrossList.Item(i).Y - 4, guiCrossList.Item(i).X, guiCrossList.Item(i).Y + 4)
    60. e.Graphics.DrawEllipse(Pens.Green, guiCrossList.Item(i).X - SpotR, guiCrossList.Item(i).Y - SpotR, SpotR * 2, SpotR * 2)
    61. 'e.Graphics.fillEllipse(Brushes.Green, guiCrossList.Item(i).X - SpotR, guiCrossList.Item(i).Y - SpotR, SpotR * 2, SpotR * 2)
    62. Next
    63. End Sub
    64. Private Sub PaintPoly_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PaintPoly.CheckedChanged
    65. pp.Refresh()
    66. End Sub
    67. Private Sub Delete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Delete.Click
    68. CountEdge = 0
    69. MinL = 0
    70. MinT = 0
    71. MaxR = 0
    72. MaxB = 0
    73. guiCrossList.Clear()
    74. pp.Refresh()
    75. End Sub
    76. End Class


    Edit by Agent: VB-Tag gesplittet

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

    Den Polygon in Dreiecke aufzuteilen ist definitiv die einzige sinnvolle, allgemeine Lösung! Wenn du anfangst zu schauen, ob der Punkt Rechts von der einen Linie, Links von ner anderen etc. (was allgemein nur sehr schwer zu implementieren ist), kommst du auf deutlich mehr Rechenvorgänge ;)

    Das Problem hierbei ist nur, dass das Dreieck gültig sein muss (also das das Dreieck teil der Gesamtfläche ist und nicht außerhalb liegt. Ich denke, wenn du per Hand ein paar schräge Polygone aufzeichnest, kommst du da auch auf eine Lösung :)
    Hatte den Ansatz mit den Dreiecken versucht, hab mein Polygon in zig tausend dreicecke zerhackt, aber geholfen hats mir auch nicht... xD, denn dreicke helfen bei dem Problem mal so garnich... aber das Programm läuft jetzt mit einer sehr guten annäherung *freu* hat sich also alles erledigt =)
    Die Fläche in zgitausend Dreiecke zu unterteilen ist ja auch völliger overkill. Ich nehme an, dass war übertrieben? Du musst nur (AnzahlDerPunkte - 2) Dreiecke machen. Es bringt ja nichts, ein Dreieck immer weiter zu unterteilen;)
    "Theoretisch würd es mir schon helfen, wenn mir jemand sagen könnte, wie ich herausfinde, ob ein Punkt, innerhalb der Fläche ist." Dabei helfen dir aber die Dreiecke:)
    Nein, ich hab schon einen normalen polygon triangulations algorithmus angewndet, für meine Dreiecke, aber das hat mir nicht weitergeholfen, bei dem Problem, die fläche so weit wie möglich mit kreisen zu füllen, ohne den rand zu überschneiden...