Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[SOLVED] GDI+ parabolic line?


  • Please log in to reply
11 replies to this topic
jpjazzy
  • Members
  • 800 posts
  • Last active: Dec 17 2014 07:22 AM
  • Joined: 16 Feb 2010
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?
AutoHotkey Basic - Windows 7
Posted Image

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
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...

jpjazzy
  • Members
  • 800 posts
  • Last active: Dec 17 2014 07:22 AM
  • Joined: 16 Feb 2010
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):
#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.
AutoHotkey Basic - Windows 7
Posted Image

Leef_me
  • Moderators
  • 8510 posts
  • Last active: Sep 10 2015 05:50 AM
  • Joined: 08 Apr 2009
>>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?

jpjazzy
  • Members
  • 800 posts
  • Last active: Dec 17 2014 07:22 AM
  • Joined: 16 Feb 2010
@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.
AutoHotkey Basic - Windows 7
Posted Image

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010

99 GUI limitation

Yet another reason to upgrade to AHK_L: no arbitrary GUI limits.

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
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...
; 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)
"You annoy me, therefore I exist."

jpjazzy
  • Members
  • 800 posts
  • Last active: Dec 17 2014 07:22 AM
  • Joined: 16 Feb 2010
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.
AutoHotkey Basic - Windows 7
Posted Image

tomoe_uehara
  • Members
  • 2166 posts
  • Last active: Jun 11 2015 05:33 PM
  • Joined: 05 Sep 2009
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 
Return
The 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


jpjazzy
  • Members
  • 800 posts
  • Last active: Dec 17 2014 07:22 AM
  • Joined: 16 Feb 2010
I believe it's called a template. :) I am going to read more on ballastics when I get home though, except in English lol.
AutoHotkey Basic - Windows 7
Posted Image

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
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

"You annoy me, therefore I exist."

sumon
  • Moderators
  • 1317 posts
  • Last active: Dec 05 2016 10:14 PM
  • Joined: 18 May 2010

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.