I was considering making something which would involve a parabolic function (specifically I believe it would just be quadratic, nothing bigger polynomial wise, if it matters) and I was just wondering is it possible to draw a line like this with GDI+ over the screen based on a given function/formula? Anyone done anything like this?
[SOLVED] GDI+ parabolic line?
Started by
jpjazzy
, Dec 18 2011 03:39 AM
11 replies to this topic
A glance at the GDI+ flat API shows nothing about parabolas. I'd suggest you take the equation, plug in each x in the range, and plot the coordinate pair. In the case where this leads to a "broken" line, you could Gdip_DrawLine() between each coordinate pair. This might turn out to be too slow, in which case you could resort to GDI or some 3rd party dll...
#2
-
Posted 18 December 2011 - 03:49 AM
nimda, thank you for your response. Using a series of straight lines I can generate a parabola (based on screen dimensions and the mouse position). For the future in case anyone wants to generate a parabolic line on the screen (which is adjustable based on mouse position):
Hint: WheelUp/WheelDown alter the vertex
Thanks for the idea nimda. At first I was thinking it would be impossible with a 99 GUI limitation, but then I realized you can have more then one line drawn on a GUI in GDI+. Anyways, thanks again.
#SingleInstance, Force #NoEnv SetBatchLines, -1 SetTimer, GenerateLine, 20 ; Generates a new line every 50 ms VHeight := A_ScreenHeight ~WheelDown:: VHeight -= 10 return ~WheelUp:: VHeight += 10 return ; Uncomment if Gdip.ahk is not in your standard library ;#Include, Gdip.ahk GenerateLine: ; Generates a new line ; Start gdi+ If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } OnExit, Exit ; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap Width := A_ScreenWidth, Height := A_ScreenHeight ; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop ; Show the window Gui, 1: Show, NA ; Get a handle to this window we have created in order to update it later hwnd1 := WinExist() ; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything hbm := CreateDIBSection(Width, Height) ; Get a device context compatible with the screen hdc := CreateCompatibleDC() ; Select the bitmap into the device context obm := SelectObject(hdc, hbm) ; Get a pointer to the graphics of the bitmap, for use with drawing functions G := Gdip_GraphicsFromHDC(hdc) ; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling) Gdip_SetSmoothingMode(G, 4) ; Create a fully opaque red pen (ARGB = Transparency, red, green, blue) of width 3 (the thickness the pen will draw at) to draw a line pPen := Gdip_CreatePen(0xffff0000, 1) ;Get Current Mouse POS CoordMode, Mouse, Screen MouseGetPos, MX, MY ;~ MY -= 10 ; Minus ten pixels for mouse safety purposes CoordMode, Mouse, Relative XStepValue := 1 ; X step value ( How many lines to be drawn will be determined by this - Determines the clarity of the line ) XValue := 0 ; Starting X value While (XValue <= A_ScreenWidth) { ; a is solved assuming the point(s) ( 0 , 0 ) <--- START ( MX/2 , A_ScreenHeight ) < ---- VERTEX ( MX , MY ) <--- END a := (0-VHeight)/((0-(MX/2))**2) ; Solve stretch factor ; Y1 is the equation var. XValue is the x var. Standard vertex form: a(x-h)^2 + k Y1 := (-a*((XValue-(MX/2))**2))+VHeight-A_ScreenHeight ; Negative a because of AHKs Y Coordinate system (Higher coordinates = Lower on the screen) ;Draw Line ;Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2) Gdip_DrawLine(G, pPen, PreviousX, PreviousY, XValue, Y1) PreviousX := XValue PreviousY := Y1 XValue += XStepValue ; Next value } ; Delete the pen as it is no longer needed and wastes memory Gdip_DeletePen(pPen) ; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen ; So this will position our gui at (0,0) with the Width and Height specified earlier UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) ; Select the object back into the hdc SelectObject(hdc, obm) ; Now the bitmap may be deleted DeleteObject(hbm) ; Also the device context related to the bitmap may be deleted DeleteDC(hdc) ; The graphics may now be deleted Gdip_DeleteGraphics(G) Return ;####################################################################### ~*ESC:: Exit: ; gdi+ may now be shutdown on exiting the program Gdip_Shutdown(pToken) ExitApp Return
Hint: WheelUp/WheelDown alter the vertex
Thanks for the idea nimda. At first I was thinking it would be impossible with a 99 GUI limitation, but then I realized you can have more then one line drawn on a GUI in GDI+. Anyways, thanks again.
#3
-
Posted 18 December 2011 - 06:51 AM
>>For the future in case anyone wants to generate a parabolic line on the screen (which is adjustable based on mouse position):
Fantastic :!:
Would you please elaborate on its intended purpose?
Fantastic :!:
Would you please elaborate on its intended purpose?
#4
-
Posted 18 December 2011 - 07:31 AM
@Leef_Me For my purposes, aim visuals which will assist in games that I play. It will take into account gravity with some simple formula manipulation. With a bit more manipulation I bet I could do a couple more things in AHK with it:
[*:2i52um4d] Give new users a visual of how a screen works with coordinates and your screen is just like a graph
[*:2i52um4d] Possible formula manipulation + this to generate a graphic like function in AHK similar to that of a graphing calculator.
[*:2i52um4d] Give new users a visual of how a screen works with coordinates and your screen is just like a graph
[*:2i52um4d] Possible formula manipulation + this to generate a graphic like function in AHK similar to that of a graphing calculator.
#5
-
Posted 18 December 2011 - 07:57 AM
Yet another reason to upgrade to AHK_L: no arbitrary GUI limits.99 GUI limitation
#6
-
Posted 18 December 2011 - 03:34 PM
I'm not good with math, but for a region aproximat you can use bezier curve in a trapez or an arc in an ellipse. For example this, you will need to "move" the 4 points that will depends of what you want...
<!-- m -->http://en.wikipedia....ki/Bézier_curve<!-- m -->
more important but in french (sorry) :
<!-- m -->http://www4.ac-lille... ... spline.htm<!-- m -->
If it's just for ballistics :
<!-- m -->http://fr.wikipedia....wiki/Balistique<!-- m -->
Then use your equation and show point per point every small part of time, very more simple and visual (as kinematics)
; add this line before to delete all gdi objects w := MX, h := A_ScreenHeight, v := VHeight-A_ScreenHeight, pPen2 := Gdip_CreatePen(0xff00ff00, 1) Gdip_DrawBezier(G, pPen2, 0, h+v, w/3, -h/3+v, w/3*2, -h/3+v, w, h+v)
<!-- m -->http://en.wikipedia....ki/Bézier_curve<!-- m -->
more important but in french (sorry) :
<!-- m -->http://www4.ac-lille... ... spline.htm<!-- m -->
If it's just for ballistics :
<!-- m -->http://fr.wikipedia....wiki/Balistique<!-- m -->
Then use your equation and show point per point every small part of time, very more simple and visual (as kinematics)
#7
-
Posted 18 December 2011 - 04:48 PM
"You annoy me, therefore I exist."
Zaelia, thank you for your suggestion but I think I will stick to just drawing formula points using straight lines as it offers more control over the algebraic equation manipulations. Thank you for your advice though.
#8
-
Posted 18 December 2011 - 06:52 PM
Well.. For me, I just let the GDI+ to do the count by itself, I'm not good at math 8)
/* AutoHotkey Version: 1.x Language: English Platform: Win9x/NT Author: tomoe_uehara Script Function: Draws an arc on the screen. Date of Creation: 14/09/2011 - 01:16:10 */ #NoEnv #SingleInstance, Force SendMode Input SetWorkingDir %A_ScriptDir% CoordMode, Mouse, Screen ; ------- Configurable Section ------- CrosshairOpacity = FF CrosshairColor = FF00FF CrosshairWidth = 3 Interval = 50 ;in milisecond ; ------------------------------------ SetTimer, Check, %Interval% If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } OnExit, Exit Width := A_ScreenWidth, Height := A_ScreenHeight Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop Gui, 1: Show, NA, Gui98 WinSet, ExStyle, +0x20, Gui98 hwnd1 := WinExist() hbm := CreateDIBSection(Width, Height) hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm) G := Gdip_GraphicsFromHDC(hdc) Gdip_SetSmoothingMode(G, 4) Gdip_GraphicsClear(G) Draw: MyPen = 0x%CrosshairOpacity%%CrosshairColor% pPen := Gdip_CreatePen(MyPen, CrosshairWidth) MouseGetPos, xx, yy currentx := xx currenty := yy DrawLine: Gdip_DrawArc(G, pPen, 0, 0, xx, A_ScreenWidth, 180, 180) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) Gdip_DeletePen(pPen) return Redraw: Gdip_GraphicsClear(G) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) Goto Draw Check: MouseGetPos, xx2, yy2 if (currentx != xx2) or (currenty != yy2) { currentx := xx2 currenty := yy2 gosub Redraw } return esc:: ; Press esc to exit Exit: SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(G) Gdip_Shutdown(pToken) ExitApp ReturnThe code was taken from my basic GDI+ script, I always edit this script to make another script, what does it called, a skeleton script?
/* AutoHotkey Version: 1.x Language: English Platform: Win9x/NT Author: tomoe_uehara Script Function: Draws crosshair on the screen. Date of Creation: 14/09/2011 - 01:16:10 */ #NoEnv #SingleInstance, Force SendMode Input SetWorkingDir %A_ScriptDir% CoordMode, Mouse, Screen ; ------- Configurable Section ------- CrosshairOpacity = FF CrosshairColor = FF00FF CrosshairWidth = 4 Interval = 50 ;in milisecond ; ------------------------------------ SetTimer, UPDATEDSCRIPT,1000 SetTimer, Check, %Interval% If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } OnExit, Exit Width := A_ScreenWidth, Height := A_ScreenHeight Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop Gui, 1: Show, NA, Gui98 WinSet, ExStyle, +0x20, Gui98 hwnd1 := WinExist() hbm := CreateDIBSection(Width, Height) hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm) G := Gdip_GraphicsFromHDC(hdc) Gdip_SetSmoothingMode(G, 4) Gdip_GraphicsClear(G) Draw: MyPen = 0x%CrosshairOpacity%%CrosshairColor% pPen := Gdip_CreatePen(MyPen, CrosshairWidth) MouseGetPos, xx, yy currentx := xx currenty := yy DrawLine: ;Tooltip, x=%xx% y=%yy% Gdip_DrawLine(G, pPen, 0, yy, A_ScreenWidth, yy) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) Gdip_DrawLine(G, pPen, xx, 0, xx, A_ScreenHeight) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) Gdip_DeletePen(pPen) return Redraw: Gdip_GraphicsClear(G) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) Goto Draw Check: MouseGetPos, xx2, yy2 if (currentx != xx2) or (currenty != yy2) { currentx := xx2 currenty := yy2 gosub Redraw } return esc:: ; Press esc to exit Exit: SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(G) Gdip_Shutdown(pToken) ExitApp Return UPDATEDSCRIPT: FileGetAttrib,attribs,%A_ScriptFullPath% IfInString,attribs,A { FileSetAttrib,-A,%A_ScriptFullPath% Sleep,500 Reload } Return
#9
-
Posted 18 December 2011 - 07:36 PM
I believe it's called a template. I am going to read more on ballastics when I get home though, except in English lol.
#10
-
Posted 18 December 2011 - 10:26 PM
I'm agree with you, however if one day you need to go deeper to particular bezier curve.
<!-- m -->http://www.numerican...urve.htm#bezier<!-- m -->
<!-- m -->http://www.numerican...urve.htm#bezier<!-- m -->
#SingleInstance, Force #NoEnv SetBatchLines, -1 CoordMode, Mouse, Screen SetTimer, Update, 25 pToken := Gdip_Startup() OnExit, Exit Width := A_ScreenWidth, Height := A_ScreenHeight Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop Gui, 1: Show, NA hwnd1 := WinExist() Update: hbm := CreateDIBSection(Width, Height) ; spagheti code, very bad to recreate every time hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm) G := Gdip_GraphicsFromHDC(hdc) Gdip_SetSmoothingMode(G, 4) pPen := Gdip_CreatePen(0xff00ff00, 2), pPen0 := Gdip_CreatePen(0xff004000, 1) MouseGetPos, MX, MY w := MX , h := MY-A_ScreenHeight/2 x1 := 0 , y1 := A_ScreenHeight/2 x4 := w , y4 := A_ScreenHeight/2 x2 := 1/3*(x4-x1) , y2 := 4/3*h+y1 x3 := 2/3*(x4-x1) , y3 := 4/3*h+y1 Gdip_DrawBezier(G, pPen, x1, y1, x2, y2, x3, y3, x4, y4) Gdip_DrawLine(G, pPen0, x1, y1, x4, y4) , Gdip_DrawLine(G, pPen, x2, y2, x3, y3) ; display bezier trapezoid Gdip_DrawLine(G, pPen, x1, y1, x2, y2) , Gdip_DrawLine(G, pPen, x3, y3, x4, y4) ; // Gdip_DrawLine(G, pPen0, x2, y2, x2, y1) , Gdip_DrawLine(G, pPen0, x3, y3, x3, y4) ; proprieties Gdip_DrawLine(G, pPen0, x1, 3/4*(y2-y1)+y1, x4, 3/4*(y2-y1)+y1) Gdip_DrawLine(G, pPen0, x1, 2/4*(y2-y1)+y1, x4, 2/4*(y2-y1)+y1) Gdip_DrawLine(G, pPen0, x1, 1/4*(y2-y1)+y1, x4, 1/4*(y2-y1)+y1) ; easy for drawing , harder for equation ; ..2---3.. ; ./..5..\. ; 1-------4 (Cubic) Bezier & Quadratic equation ; simple case with double solution and screen coordinate system , y = a*x**2 + b*x + c a:=-0.02 , b:=5 , c:=500 d := b*b-4*a*c s1 := (-b-sqrt(d))/(2*a) , s2 := (-b+sqrt(d))/(2*a) x5 := -b/(2*a) , y5 := -d/(4*a) ; peak pPen2 := Gdip_CreatePen(0xffff0000, 2) Gdip_DrawBezier(G, pPen2, s2>s1 ? s1 : s2, 0, x5-1/6*abs(s2-s1), 4/3*y5, x5+1/6*abs(s2-s1), 4/3*y5, s2<s1 ? s1 : s2, 0) Gdip_DeletePen(pPen), Gdip_DeletePen(pPen0), Gdip_DeletePen(pPen2) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(G) Return esc:: Exit: Gdip_Shutdown(pToken) ExitApp
#11
-
Posted 19 December 2011 - 02:36 AM
"You annoy me, therefore I exist."
I'm agree with you, however if one day you need to go deeper to particular bezier curve.
<!-- m -->http://www.numerican...urve.htm#bezier<!-- m -->#SingleInstance, Force #NoEnv SetBatchLines, -1 CoordMode, Mouse, Screen SetTimer, Update, 25 pToken := Gdip_Startup() OnExit, Exit Width := A_ScreenWidth, Height := A_ScreenHeight Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop Gui, 1: Show, NA hwnd1 := WinExist() Update: hbm := CreateDIBSection(Width, Height) ; spagheti code, very bad to recreate every time hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm) G := Gdip_GraphicsFromHDC(hdc) Gdip_SetSmoothingMode(G, 4) pPen := Gdip_CreatePen(0xff00ff00, 2), pPen0 := Gdip_CreatePen(0xff004000, 1) MouseGetPos, MX, MY w := MX , h := MY-A_ScreenHeight/2 x1 := 0 , y1 := A_ScreenHeight/2 x4 := w , y4 := A_ScreenHeight/2 x2 := 1/3*(x4-x1) , y2 := 4/3*h+y1 x3 := 2/3*(x4-x1) , y3 := 4/3*h+y1 Gdip_DrawBezier(G, pPen, x1, y1, x2, y2, x3, y3, x4, y4) Gdip_DrawLine(G, pPen0, x1, y1, x4, y4) , Gdip_DrawLine(G, pPen, x2, y2, x3, y3) ; display bezier trapezoid Gdip_DrawLine(G, pPen, x1, y1, x2, y2) , Gdip_DrawLine(G, pPen, x3, y3, x4, y4) ; // Gdip_DrawLine(G, pPen0, x2, y2, x2, y1) , Gdip_DrawLine(G, pPen0, x3, y3, x3, y4) ; proprieties Gdip_DrawLine(G, pPen0, x1, 3/4*(y2-y1)+y1, x4, 3/4*(y2-y1)+y1) Gdip_DrawLine(G, pPen0, x1, 2/4*(y2-y1)+y1, x4, 2/4*(y2-y1)+y1) Gdip_DrawLine(G, pPen0, x1, 1/4*(y2-y1)+y1, x4, 1/4*(y2-y1)+y1) ; easy for drawing , harder for equation ; ..2---3.. ; ./..5..\. ; 1-------4 (Cubic) Bezier & Quadratic equation ; simple case with double solution and screen coordinate system , y = a*x**2 + b*x + c a:=-0.02 , b:=5 , c:=500 d := b*b-4*a*c s1 := (-b-sqrt(d))/(2*a) , s2 := (-b+sqrt(d))/(2*a) x5 := -b/(2*a) , y5 := -d/(4*a) ; peak pPen2 := Gdip_CreatePen(0xffff0000, 2) Gdip_DrawBezier(G, pPen2, s2>s1 ? s1 : s2, 0, x5-1/6*abs(s2-s1), 4/3*y5, x5+1/6*abs(s2-s1), 4/3*y5, s2<s1 ? s1 : s2, 0) Gdip_DeletePen(pPen), Gdip_DeletePen(pPen0), Gdip_DeletePen(pPen2) UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(G) Return esc:: Exit: Gdip_Shutdown(pToken) ExitApp
Teh woot! Very nice stuff! Expressing my genuine feeling - I am impressed. It just looks very fancy, even if it's "only" maths.
#12
-
Posted 19 December 2011 - 01:15 PM