Hi
hier kommt ein Tool von mir, um sich einen oder mehrere Funktionsgraphen schnell und einfach zeichnen zu lassen. Einfach die Funktionsvorschrift (z.B. x² oder 4x+3) eingeben und auf "plot" klicken. Danch kann man den Graph verschieben und zoomen, um bestimmte Stellen genauer zu betrachten.
Um den Zoom zu verbessern, würde ich die Graphen gerne auf GDIPlus-Pfaden aufbauen, allerdings habe ich nur _GDIPlus_PathWarp gefunden, um den Pfad selbst zu verändern, die Methode hat jedoch auch nach langem Rumprobieren nicht funktioniert.. Wenn da jemand mal ein funktionierendes Beispiel posten könnte, würde ich mich freuen
Gruß syne
features
Einheit Zentimeter, nicht Pixel
Verschieben des Koordinatensystems,
zoom durch Scrollen oder Feld aufspannen mit der rechten Maustaste,
verschiedene Farben für die Graphen
Code
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
#include <WinAPI.au3>
#include <Array.au3>
#include <GDIPlus.au3>
#include <Misc.au3>
Global Const $pi = 4*ATan(1), $2rad = $pi/180, $e = 2.718281828
Global Const $struct = "ptr bmp;ptr grafx"
Global Const $dpcm = _GetDPCm()
Global $width = 650, $height = 500
Global $drawW = $width-20, $drawH = $height-20-29-20-10
Global $zoom = 1, $color = 0x000000
Global $var = "x"
Global $origin[2] = [$drawW/2, $drawH/2]
Global $graphs[11] = [0]
Global $start[3] = [0, 0, False]
Global $GUI = GUICreate("Graphenzeichner", $width, $height, -1, -1)
GUISetBkColor(0xFFFFFF)
GUIRegisterMsg($WM_PAINT, "_paint")
GUIRegisterMsg($WM_LBUTTONDOWN, "_LButtonDown")
GUIRegisterMsg($WM_RBUTTONDOWN, "_RButtonDown")
GUIRegisterMsg($WM_RBUTTONUP, "_RButtonUp")
GUIRegisterMsg($WM_MOUSEWHEEL, "_mousewheel")
$p = -20
Global $beg = GUICtrlCreateLabel("f(" & $var & ") = ", 38+$p, $height-20-29+3, 59, 29)
GUICtrlSetFont(-1, 15)
Global $input = GUICtrlCreateInput("3*e^(-0.5*x²)", 97+$p, $height-20-29, 400, 29)
GUICtrlSetFont(-1, 15)
Global $plot = GUICtrlCreateButton("plot", 507+$p, $height-20-29, 100, 29)
GUICtrlSetFont(-1, 14)
Global $popup = GUICtrlCreateLabel("", $width-45, $height-49, 30, 30, $WS_BORDER)
GUICtrlSetBkColor($popup, 0x000000)
Dim $accKeys[1][2] = [["{ENTER}", $plot]]
GUISetAccelerators($accKeys)
Global $GUI2 = GUICreate("", 115, 115, $width-115-5-2, $height-115-5-2, $WS_POPUPWINDOW, BitOR($WS_EX_TOOLWINDOW, $WS_EX_MDICHILD), $GUI)
GUISetBkColor(0xFFFFFF, $GUI2)
Global $lbls[6][2] = [[0, 0x000000], [0, 0x1207B4], [0, 0x8F11B9], [0, 0xFF0000], [0, 0x12B407], [0, 0x12C0BC]]
[/autoit] [autoit][/autoit] [autoit]For $i = 0 To UBound($lbls)-1
$lbls[$i][0] = GUICtrlCreateLabel("" , 6+Mod($i, 3)*37, 6+Floor($i/3)*37, 30, 30, $WS_BORDER)
GUICtrlSetBkColor($lbls[$i][0], $lbls[$i][1])
Next
Global $choose = GUICtrlCreateLabel("Choose color", 6, 90, 80, 20)
GUICtrlSetColor($choose, 0x0000FF)
GUICtrlSetFont($choose, 10, 400, 4, "Arial")
GUICtrlSetCursor($choose, 0)
_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]Global $grafx = _GDIPlus_GraphicsCreateFromHWND($GUI)
Global $bmp = _GDIPlus_BitmapCreateFromGraphics($drawW, $drawH, $grafx)
Global $backbuffer = _GDIPlus_ImageGetGraphicsContext($bmp)
_GDIPlus_GraphicsSetSmoothingMode($backbuffer, 2)
_drawAll()
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]GUISetState(@SW_SHOW, $GUI)
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]While 1
$msg = GUIGetMsg()
Switch $msg
Case $GUI_EVENT_CLOSE
For $i = 1 To $graphs[0]
_GDIPlus_GraphicsDispose(DllStructGetData($graphs[$i], "grafx"))
_GDIPlus_ImageDispose(DllStructGetData($graphs[$i], "bmp"))
$graphs[$i] = 0
Next
_GDIPlus_GraphicsDispose($backbuffer)
_GDIPlus_ImageDispose($bmp)
_GDIPlus_GraphicsDispose($grafx)
_GDIPlus_Shutdown()
Exit
Case $plot
If $graphs[0] < 10 Then
$fct = GUICtrlRead($input)
$fct = _makeExecutable($fct)
_plotGraph($fct, $backbuffer, $color)
_GDIPlus_GraphicsDrawImageRect($grafx, $bmp, 10, 10, $drawW, $drawH)
Else
MsgBox(48, "Graphenzeichner", "Maximale Anzahl an Graphen erreicht.")
EndIf
Case $popup
GUISetState(@SW_SHOW, $GUI2)
Case $lbls[0][0] To $lbls[5][0]
For $i = 0 To UBound($lbls, 1)-1
If $msg = $lbls[$i][0] Then
$color = $lbls[$i][1]
GUICtrlSetBkColor($popup, "0x" & Hex($lbls[$i][1], 6))
GUISetState(@SW_HIDE, $GUI2)
EndIf
Next
Case $choose
$tmp = _ChooseColor(2, 0x000000, 0, $GUI)
If $tmp <> -1 Then
$color = $tmp
GUICtrlSetBkColor($popup, $color)
GUISetState(@SW_HIDE, $GUI2)
EndIf
EndSwitch
Sleep(50)
WEnd
Func _drawCoordSys($graphics)
Local $pen = _GDIPlus_PenCreate()
Local $cap = _GDIPlus_ArrowCapCreate(3, 3)
_GDIPlus_PenSetCustomEndCap($pen, $cap)
_GDIPlus_GraphicsClear($graphics, 0xFFEAEAEA)
_GDIPlus_GraphicsDrawRect($graphics, 0, 0, $drawW-1, $drawH-1)
_GDIPlus_GraphicsDrawLine($graphics, $origin[0], $drawH, $origin[0], 0, $pen)
_GDIPlus_GraphicsDrawLine($graphics, 0, $origin[1], $drawW, $origin[1], $pen)
For $i = $dpcm*$zoom To $drawW Step $dpcm*$zoom
_GDIPlus_GraphicsDrawLine($graphics, $origin[0]+$i, $origin[1]-2, $origin[0]+$i, $origin[1]+2)
_GDIPlus_GraphicsDrawLine($graphics, $origin[0]-$i, $origin[1]-2, $origin[0]-$i, $origin[1]+2)
_GDIPlus_GraphicsDrawLine($graphics, $origin[0]-2, $origin[1]+$i, $origin[0]+2, $origin[1]+$i)
_GDIPlus_GraphicsDrawLine($graphics, $origin[0]-2, $origin[1]-$i, $origin[0]+2, $origin[1]-$i)
Next
_GDIPlus_ArrowCapDispose($cap)
_GDIPlus_PenDispose($pen)
EndFunc
Func _makeExecutable($fct)
$fct = StringReplace($fct, "e", $e)
$fct = StringReplace($fct, "pi", $pi)
$fct = StringReplace($fct, "²", "^2")
$fct = StringReplace($fct, "³", "^3")
$fct = StringRegExpReplace($fct, "([x\d)])([x(])" , "$1*$2")
$fct = StringReplace($fct, $var, "$x")
Return $fct
EndFunc
Func _plotGraph($fct, $graphics, $col)
Local $tBmp = _GDIPlus_BitmapCreateFromGraphics(2*$drawW, 2*$drawH, $graphics)
Local $bb = _GDIPlus_ImageGetGraphicsContext($tBmp)
_GDIPlus_GraphicsSetSmoothingMode($bb, 2)
Local $pen = _GDIPlus_PenCreate("0xFF" & Hex($col, 6))
Local $yO, $y, $x = (-$drawW-1)/$dpcm
$yO = -1*Execute($fct)*$dpcm
If $yO = "" Then
MsgBox(48, "Graphenzeichner", "Die eingegebene Funktion konnte nicht berechnet werden.")
_GDIPlus_PenDispose($pen)
_GDIPlus_GraphicsDispose($bb)
_GDIPlus_ImageDispose($tBmp)
Return
EndIf
For $i = -$drawW To $drawW
$x = $i / $dpcm
$y = -1*Execute($fct)*$dpcm
_GDIPlus_GraphicsDrawLine($bb, $i+$drawW-1, $yO+$drawH, $i+$drawW, $y+$drawH, $pen)
$yO = $y
Next
_GDIPlus_GraphicsDrawImageRect($graphics, $tBmp, $origin[0]-$drawW*$zoom, $origin[1]-$drawH*$zoom, $drawW*2*$zoom, $drawH*2*$zoom)
$graphs[0] += 1
Local $tmp = DllStructCreate($struct)
DllStructSetData($tmp, "bmp", $tBmp)
DllStructSetData($tmp, "grafx", $bb)
$graphs[$graphs[0]] = $tmp
_GDIPlus_PenDispose($pen)
EndFunc
Func _drawAll($out = True)
_drawCoordSys($backbuffer)
For $i = 1 To $graphs[0]
_GDIPlus_GraphicsDrawImageRect($backbuffer, DllStructGetData($graphs[$i], "bmp"), $origin[0]-$drawW*$zoom, $origin[1]-$drawH*$zoom, $drawW*2*$zoom, $drawH*2*$zoom)
Next
_GDIPlus_GraphicsDrawString($backbuffer, "zoom: " & $zoom, 3, 3, "Calibri", 10)
If $out Then _GDIPlus_GraphicsDrawImageRect($grafx, $bmp, 10, 10, $drawW, $drawH)
EndFunc
Func _paint($hWnd, $msg, $wParam, $lParam)
_GDIPlus_GraphicsDrawImageRect($grafx, $bmp, 10, 10, $drawW, $drawH)
Return $GUI_RUNDEFMSG
EndFunc
Func _LButtonDown($hWnd, $msg, $wParam, $lParam)
GUISetState(@SW_HIDE, $GUI2)
Local $inf = GUIGetCursorInfo($GUI)
Local $oInf = $inf
If Not IsArray($inf) Then Return $GUI_RUNDEFMSG
If _PointInRect($inf[0], $inf[1], 10, 10, $drawW, $drawH) Then
While $inf[2]
If _PointInRect($origin[0]-($oInf[0]-$inf[0]), $origin[1]-($oInf[1]-$inf[1]), 0, 0, $drawW, $drawH) Then
$origin[0] -= $oInf[0]-$inf[0]
$origin[1] -= $oInf[1]-$inf[1]
_drawAll()
EndIf
$oInf = $inf
$inf = GUIGetCursorInfo($GUI)
WEnd
EndIf
EndFunc
Func _RButtonDown($hWnd, $msg, $wParam, $lParam)
Local $inf = GUIGetCursorInfo($GUI)
If Not IsArray($inf) Then Return $GUI_RUNDEFMSG
If _PointInRect($inf[0], $inf[1], 10, 10, $drawW, $drawH) Then
While $inf[3]
If $start[2] Then
_drawAll(False)
_GDIPlus_GraphicsDrawRect($backbuffer, $start[0]-10, $start[1]-10, $inf[0]-$start[0], $inf[1]-$start[1])
_GDIPlus_GraphicsDrawImageRect($grafx, $bmp, 10, 10, $drawW, $drawH)
Else
$start[0] = $inf[0]
$start[1] = $inf[1]
$start[2] = True
EndIf
$inf = GUIGetCursorInfo($GUI)
WEnd
EndIf
EndFunc
Func _RButtonUp($hWnd, $msg, $wParam, $lParam)
$inf = GUIGetCursorInfo($GUI)
If Not IsArray($inf) Then Return $GUI_RUNDEFMSG
$start[2] = False
[/autoit] [autoit][/autoit] [autoit]Local $w = $inf[0]-$start[0], $h = $inf[1]-$start[1]
Do
$w += 2
$h += 2
Until ($w >= $drawW Or $h >= $drawH)
$zoom = Round(Min3($w/($inf[0]-$start[0]), $h/($inf[1]-$start[1]), 3), 1)
[/autoit] [autoit][/autoit] [autoit]$origin[0] += $origin[0]-($start[0]+($inf[0]-$start[0])/2)
$origin[1] += $origin[1]-($start[1]+($inf[1]-$start[1])/2)
_drawAll()
EndFunc
Func _mousewheel($hWnd, $msg, $wParam, $lParam)
Local $inf = GUIGetCursorInfo($GUI)
If Not IsArray($inf) Then Return $GUI_RUNDEFMSG
Local $dir = BitAND($wParam, 0x800000)-1
$dir = -Abs($dir)/$dir
Switch True
Case _PointInRect($inf[0], $inf[1], 10, $height-20-29+3, 59, 29)
$var = Asc($var) - 97 + $dir
$var = Iif($var < 0, 25, Mod($var, 26)) + 97
$var = Chr($var)
GUICtrlSetData($beg, "f(" & $var & ") = ")
Case _PointInRect($inf[0], $inf[1], 10, 10, $drawW, $drawH)
$zoom += 0.1*$dir
$zoom = Round(Iif($zoom < 0.5, 0.5, Iif($zoom > 3, 3, $zoom)), 1)
_drawAll()
EndSwitch
EndFunc
Func _PointInRect($xPt, $yPt, $xTL, $yTL, $w, $h)
Return ($xPt >= $xTL And $xPt <= $xTL+$w And $yPt >= $yTL And $yPt <= $yTL+$h)
EndFunc
Func _GetDPCm()
Local $hDC = DllCall("user32.dll", "long", "GetDC", "long", 0)
Local $aRet = DllCall("gdi32.dll", "long", "GetDeviceCaps", "long", $hDC[0], "long", 90)
Local $hDC = DllCall("user32.dll", "long", "ReleaseDC", "long", 0, "long", $hDC)
Return $aRet[0]/2.54
EndFunc
Func Iif($t, $v1, $v2)
If $t Then Return $v1
Return $v2
EndFunc
Func Min($v1, $v2)
If $v1 < $v2 Then Return $v1
Return $v2
EndFunc
Func Min3($v1, $v2, $v3)
Return Min($v1, Min($v2, $v3))
EndFunc
Func Max($v1, $v2)
If $v1 > $v2 Then Return $v1
Return $v2
EndFunc