GDI+ Diffusions Demo

  • Hi,
    ich habe mal eine weitere 'nutzlose' GDI+ Demo gebaut :D. Es ist eine grafische Diffusions Demo also eine Animation wie sich Flüssigkeiten ausgleichen.

    viel Spaß damit.

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <Array.au3>
    ;Defusions Demo GDI+ by Sprenger120
    HotKeySet("{Esc}", "_Exit")
    Global $RutschBeschleunigung = 2
    Global $FallBeschleunigung = 5
    Global $iTeilchenAnzahl = InputBox("GDI+ Diffusions Demo","Wie viele Teilchen?",151)
    Global $iWidth = 470
    Global $iHeight = 768
    Global $Array_X = 0, $Array_Y = 1, $Array_Oben_Unten = 2, $Array_Status = 3, $Array_Farbe = 4, $Array_AbsObj = 5, $Array_WanderStatus = 6
    Dim $aTeilchen[$iTeilchenAnzahl + 1][7] ;X|Y|Oben/Unten|Status|Farbe|Abstand zum Objekt|Wander Status
    $aTeilchen[0][0] = False
    $aTeilchen[0][1] = 0
    $aTeilchen[0][1] = 0
    Global $iMaxTeilchenAufstiegProVg = 1
    Global $iWasserstand = 0 ;Höhe des Wasserstandes
    Global $iObenUnten = 0
    Global $iDiffusionsFortschritt = 1

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

    _GDIPlus_Startup()
    $hGUI = GUICreate("GDI+ Diffusion", $iWidth, $iHeight, -1, -1, $WS_POPUP)
    GUISetState(@SW_SHOW)
    $hGUIDC = _WinAPI_GetDC($hGUI)

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

    $hBackpufferBitmap = _WinAPI_CreateCompatibleBitmap($hGUIDC, $iWidth, $iHeight)
    $hBackpufferDC = _WinAPI_CreateCompatibleDC($hGUIDC)
    _WinAPI_SelectObject($hBackpufferDC, $hBackpufferBitmap)
    $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hBackpufferDC)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)

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

    $hPen_Wand = _GDIPlus_PenCreate(0xFF000000, 10)
    $hBrush_Rot = _GDIPlus_BrushCreateSolid(0xFFFF0000)
    $hBrush_Blau = _GDIPlus_BrushCreateSolid(0xFF0000FF)
    $hBrush_Schwarz = _GDIPlus_BrushCreateSolid(0xFF000000)
    $hBrush_Wasserblau = _GDIPlus_BrushCreateSolid(0xAA99D9EA)

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

    $hStringFormat = _GDIPlus_StringFormatCreate()
    $hFamily = _GDIPlus_FontFamilyCreate("Arial")

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

    $hFont = _GDIPlus_FontCreate($hFamily, 24, 2)
    $tLayout = _GDIPlus_RectFCreate(100, 10, 0, 0)

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

    While Sleep(10)
    _GDIPlus_GraphicsClear($hGraphics, 0xFFFFFFFF)

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

    _GDIPlus_GraphicsDrawString($hGraphics, "Zum beenden Escape drücken.", 10, 750)
    _GDIPlus_GraphicsDrawLine($hGraphics, 50 + 1, 490, 410 - 1, 490) ;Membran

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

    ;Wasser zeichnen
    If $iWasserstand > 498 Then _GDIPlus_GraphicsFillRect($hGraphics, 55, 739 - ($iWasserstand - 5), 355 - 1, $iWasserstand, $hBrush_Wasserblau)

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

    ;Becher zeichnen
    _GDIPlus_GraphicsFillRect($hGraphics, 50, 240, 10, 500) ;links
    _GDIPlus_GraphicsFillRect($hGraphics, 50, 740 - 1, 360, 10) ;unten
    _GDIPlus_GraphicsFillRect($hGraphics, 410 - 1, 240, 10, 509) ;rechts

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

    ;Trichter zeichnen
    _GDIPlus_GraphicsDrawLine($hGraphics, 0, 0, 120, 250, $hPen_Wand) ;links
    _GDIPlus_GraphicsDrawLine($hGraphics, 470, 0, 350, 250, $hPen_Wand) ;rechts

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

    Switch $iDiffusionsFortschritt
    Case 1 ;Wasser reinfüllen
    $sString = "Wasser einfüllen"
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $sString, $hFont, $tLayout, $hStringFormat)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, $sString, $hFont, $aInfo[0], $hStringFormat, $hBrush_Schwarz)
    ;Oben: 50,240,500
    ;Unten:50,240,500
    $iWasserstand += 5
    _GDIPlus_GraphicsFillRect($hGraphics, 130, 0, 20, 739 - $iWasserstand, $hBrush_Wasserblau) ;Wasserstrahl
    _GDIPlus_GraphicsFillRect($hGraphics, 60, 739 - $iWasserstand, 350 - 1, $iWasserstand, $hBrush_Wasserblau) ;Wasser
    If $iWasserstand > 498 Then $iDiffusionsFortschritt += 1
    Case 2 ;Punkte in Behälter einfügen
    ;String zeichnen
    $sString = "Teilchen dazugeben"
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $sString, $hFont, $tLayout, $hStringFormat)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, $sString, $hFont, $aInfo[0], $hStringFormat, $hBrush_Schwarz)

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

    Switch $aTeilchen[0][0]
    Case False
    For $x = 1 To $iTeilchenAnzahl
    $aTeilchen[$x][$Array_X] = Random(70, 400, 1)
    $aTeilchen[$x][$Array_Y] = Random(50, 140, 1)
    $aTeilchen[$x][$Array_Oben_Unten] = 2 ;Oben
    $aTeilchen[$x][$Array_Status] = 0 ;fallend
    $aTeilchen[$x][$Array_AbsObj] = 0
    $aTeilchen[$x][$Array_WanderStatus] = 0

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

    If $aTeilchen[0][1] > $aTeilchen[0][2] Then
    $aTeilchen[$x][$Array_Farbe] = 2
    $aTeilchen[0][2] += 1
    EndIf
    If $aTeilchen[0][1] < $aTeilchen[0][2] Then
    $aTeilchen[$x][$Array_Farbe] = 1
    $aTeilchen[0][1] += 1
    EndIf
    If $aTeilchen[0][1] = $aTeilchen[0][2] Then
    Switch Random(0, 1, 1)
    Case 0
    $aTeilchen[$x][$Array_Farbe] = 1
    $aTeilchen[0][1] += 1
    Case 1
    $aTeilchen[$x][$Array_Farbe] = 2
    $aTeilchen[0][2] += 1
    EndSwitch
    EndIf
    Next
    $aTeilchen[0][0] = True
    Case True ;es befinen sich Teilchen im Array
    ;Prüfen ob Trichter,Boden,Anderes stehendes Teilchen berührt wird
    For $x = 1 To $iTeilchenAnzahl
    For $i = 1 To $FallBeschleunigung
    ;Trichter
    If PunktAufGeraden(1, 1, 120, 250, $aTeilchen[$x][$Array_X], $aTeilchen[$x][$Array_Y] + $i) Then
    $aTeilchen[$x][$Array_AbsObj] = $i
    $aTeilchen[$x][$Array_Status] = 1 ;Rutschend links
    ExitLoop
    EndIf
    If PunktAufGeraden(350, 250, 470, 0, $aTeilchen[$x][$Array_X], $aTeilchen[$x][$Array_Y] + $i) Then
    $aTeilchen[$x][$Array_Status] = 2 ;Rutschend rechts
    $aTeilchen[$x][$Array_AbsObj] = $i
    ExitLoop
    EndIf
    ;~ If $Stapeln Then
    ;~ ;Anderes Teilchen
    ;~ For $k = 1 To $iTeilchenAnzahl
    ;~ If $k = $x Then ContinueLoop
    ;~ If $aTeilchen[$x][$Array_Y] < $aTeilchen[$k][$Array_Y] Then ContinueLoop
    ;~ If _RectCollision($aTeilchen[$x][$Array_X], $aTeilchen[$x][$Array_Y], 5, 5, $aTeilchen[$k][$Array_X], $aTeilchen[$k][$Array_Y], 5, 5) Then
    ;~ $aTeilchen[$x][$Array_Status] = 3
    ;~ $aTeilchen[$x][$Array_AbsObj] = $i
    ;~ ExitLoop 2
    ;~ EndIf
    ;~ Next
    ;~ EndIf

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

    ;Boden
    If 730 = $aTeilchen[$x][$Array_Y] + $i Then
    $aTeilchen[$x][$Array_Status] = 4 ;Boden
    $aTeilchen[$x][$Array_AbsObj] = $i
    ExitLoop
    EndIf
    Next
    Next

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

    ;Teilchen weiter setzen
    For $x = 1 To $iTeilchenAnzahl
    If $aTeilchen[$x][$Array_AbsObj] Then
    $aTeilchen[$x][$Array_Y] += $aTeilchen[$x][$Array_AbsObj]
    $aTeilchen[$x][$Array_AbsObj] = 0
    EndIf
    Switch $aTeilchen[$x][$Array_Status]
    Case 0
    $aTeilchen[$x][$Array_Y] += $FallBeschleunigung
    Case 1 ;rutschen links
    ;m=2
    ;n=10
    $aTeilchen[$x][$Array_Y] = 2 * $aTeilchen[$x][$Array_X] + 10
    $aTeilchen[$x][$Array_X] += $RutschBeschleunigung
    If $aTeilchen[$x][$Array_X] > 120 Then $aTeilchen[$x][$Array_Status] = 0
    Case 2 ;rutschen rechts
    ;m= -2
    ;n= 940
    $aTeilchen[$x][$Array_Y] = -2 * $aTeilchen[$x][$Array_X] + 940
    $aTeilchen[$x][$Array_X] -= $RutschBeschleunigung
    If $aTeilchen[$x][$Array_X] > 120 Then $aTeilchen[$x][$Array_Status] = 0
    EndSwitch
    Next
    ;~ $FallBeschleunigung = Int($FallBeschleunigung * 1.15)

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

    ;Wenn erster Schritt abgeschlossen Fortschritt +1
    $Weiter = True
    For $x = 1 To $iTeilchenAnzahl
    If $aTeilchen[$x][$Array_Status] = 0 Then
    $Weiter = False
    ExitLoop
    EndIf
    Next
    If $Weiter Then
    For $x = 1 To $iTeilchenAnzahl
    $aTeilchen[$x][$Array_Oben_Unten] = 2; Unten
    Next
    $iDiffusionsFortschritt += 1
    EndIf
    EndSwitch

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

    Case 3
    $sString = "Diffusion"
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $sString, $hFont, $tLayout, $hStringFormat)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, $sString, $hFont, $aInfo[0], $hStringFormat, $hBrush_Schwarz)

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

    $MengeOben = 0
    $MengeUnten = 0

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

    ;Mengenverähltnisse ermitteln
    ;2 = Unten
    ;1 = Oben
    For $x = 1 To $iTeilchenAnzahl
    Switch $aTeilchen[$x][$Array_Oben_Unten]
    Case 1,3;Oben
    $MengeOben += 1
    Case 2,4;Unten
    $MengeUnten += 1
    EndSwitch
    Next

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

    _GDIPlus_GraphicsDrawString($hGraphics, $MengeOben, 10, 250)
    _GDIPlus_GraphicsDrawString($hGraphics, $MengeUnten, 10, 500)

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

    ;Oben: 50,240,500
    ;Unten:50,240,500

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

    ;Wander Status
    ;1 = Nach oben
    ;2 = nach unten

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

    ;Ausgleichen
    $Aufstieg = 0
    Switch $iObenUnten
    Case 0
    If $MengeUnten > $MengeOben Then
    For $x = 1 To $iTeilchenAnzahl
    If $aTeilchen[$x][$Array_WanderStatus] = 0 And $aTeilchen[$x][$Array_Oben_Unten] = 2 Then
    $aTeilchen[$x][$Array_WanderStatus] = 1
    $MengeUnten -= 1
    $MengeOben += 1
    $aTeilchen[$x][$Array_Oben_Unten] = 3;aufdem weg nach oben
    $Aufstieg += 1
    EndIf
    If $MengeUnten = $MengeOben Or $Aufstieg = $iMaxTeilchenAufstiegProVg Then ExitLoop
    Next
    EndIf
    $iObenUnten = 1
    ;~ _ArrayDisplay($aTeilchen)
    Case 1
    ;~ #cs
    ;~ $Aufstieg = 0
    If $MengeOben > $MengeUnten Then
    For $x = 1 To $iTeilchenAnzahl
    If $aTeilchen[$x][$Array_WanderStatus] = 0 And $aTeilchen[$x][$Array_Oben_Unten] = 1 Then
    $aTeilchen[$x][$Array_WanderStatus] = 2
    $MengeUnten += 1
    $MengeOben -= 1
    $aTeilchen[$x][$Array_Oben_Unten] = 4
    $Aufstieg += 1
    EndIf
    If $MengeUnten = $MengeOben Or $Aufstieg = $iMaxTeilchenAufstiegProVg Then ExitLoop
    Next
    EndIf

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

    ;~ #ce
    $iObenUnten = 0
    EndSwitch

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

    ;Prüfen ob oben od. unten angekommen
    For $x = 1 To $iTeilchenAnzahl
    If Not $aTeilchen[$x][$Array_WanderStatus] Then ContinueLoop
    For $i = 1 To $FallBeschleunigung
    ;Oben
    If $aTeilchen[$x][$Array_Y] + $i < 254 Then
    $aTeilchen[$x][$Array_WanderStatus] = 0
    $aTeilchen[$x][$Array_Oben_Unten] = 1
    $aTeilchen[$x][$Array_Y] = 255
    ExitLoop
    EndIf
    ;Unten
    If $aTeilchen[$x][$Array_Y] > 730 + 2 Then
    $aTeilchen[$x][$Array_WanderStatus] = 0
    $aTeilchen[$x][$Array_Oben_Unten] = 2
    $aTeilchen[$x][$Array_Y] = 731
    ExitLoop
    EndIf

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

    Next
    Next

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

    ;Teilchen bewegen
    For $x = 1 To $iTeilchenAnzahl
    Switch $aTeilchen[$x][$Array_WanderStatus]
    Case 1 ;nach oben
    $aTeilchen[$x][$Array_Y] -= $FallBeschleunigung
    Case 2;nach unten
    $aTeilchen[$x][$Array_Y] += $FallBeschleunigung
    EndSwitch

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

    Next
    EndSwitch

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

    ;1 = Rot ; 2 = Blau
    ;Teilchen Zeichnen
    For $x = 1 To $iTeilchenAnzahl
    $hUseBrush = $hBrush_Rot
    If $aTeilchen[$x][$Array_Farbe] = 2 Then $hUseBrush = $hBrush_Blau
    _GDIPlus_GraphicsFillRect($hGraphics, $aTeilchen[$x][$Array_X], $aTeilchen[$x][$Array_Y], 5, 5, $hUseBrush)
    Next

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

    _WinAPI_BitBlt($hGUIDC, 0, 0, $iWidth, $iHeight, $hBackpufferDC, 0, 0, $SRCCOPY)
    WEnd

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

    Func _Exit()
    $tLayout = 0
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_StringFormatDispose($hStringFormat)
    _GDIPlus_BrushDispose($hBrush_Schwarz)
    _GDIPlus_BrushDispose($hBrush_Blau)
    _GDIPlus_BrushDispose($hBrush_Rot)
    _GDIPlus_BrushDispose($hBrush_Wasserblau)
    _GDIPlus_PenDispose($hPen_Wand)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_Shutdown()
    _WinAPI_ReleaseDC($hGUI, $hGUIDC)
    _WinAPI_DeleteDC($hBackpufferDC)
    _WinAPI_DeleteObject($hBackpufferBitmap)
    Exit
    EndFunc ;==>_Exit

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

    Func _RectCollision($iX1, $iY1, $iWidth1, $iHeight1, $iX2, $iY2, $iWidth2, $iHeight2)
    ;Author: Faweyr
    Return $iX1 + $iWidth1 > $iX2 And $iX1 < $iX2 + $iWidth2 And $iY1 + $iHeight1 > $iY2 And $iY1 < $iY2 + $iHeight2
    EndFunc ;==>_RectCollision

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

    Func PunktAufGeraden($Ax, $Ay, $Bx, $By, $Cx, $Cy)
    Local $m, $n
    ;y = mx + n
    $m = Int(($By - $Ay) / ($Bx - $Ax))
    $n = Int($By - $m * $Bx)

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

    If $m >= 0 Then
    If $Cy = $m * $Cx + $n And $Cx <= $Bx And $Cy <= $By Then
    Return True
    Else
    Return False
    EndIf
    EndIf
    If $m <= 0 Then
    If $Cy = $m * $Cx + $n And ($Cy < $Ay) Then
    Return True
    Else
    Return False
    EndIf
    EndIf
    EndFunc ;==>PunktAufGeraden

    [/autoit]
  • Fein^^
    Allerdings hat das nichts mit Diffusion zu tun, da fehlt die "Trennebene"(Membran) für den Ausgleich.
    Lass doch die Teilchen nur in den oberen Teil des Glases rutschen, der vom unteren durch eine Membran getrennt ist. (Deine waagrechte Linie wäre die Membran)
    Dann würden aus dem oberen Teil die Teilchen durch "Löcher" in den unteren Teil des Glases diffundieren.

  • Andy: Diffusion ist erst mal der Vorgang, durch den sich zwei verschiedene Flüßßigkeiten durchmischen. Also ist das schon korrekt.

    @Sprenger: Das ist schön geworden, aber warum bewegen sich deine Moleküle nicht rechts und links vom Trichter? Dort gibt es doch auch Wasser ;)