Jump to content
Sign in to follow this  
Alek

Bézier

Recommended Posts

Alek

Bin working on some bezier UDFs, wanted to be able to get coords along a bezier curve.

here is a example of what i came up with.

just click around on the GUI and see what happens :)

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinApi.au3>

Opt("GUIOnEventMode", 1)

; Create GUI
$hGUI = GUICreate("GDI+", 800, 600, -1, -1, $WS_SIZEBOX)

; Draw a cardinal spline
_GDIPlus_Startup ()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND ($hGUI)
$BackBuffer = _GDIPlus_BitmapCreateFromGraphics(400, 300, $hGraphic)
$MainGraphic = _GDIPlus_ImageGetGraphicsContext($BackBuffer)
_GDIPlus_GraphicsClear($MainGraphic, 0xFFFFFFFF)

_GDIPlus_GraphicsSetSmoothingMode($MainGraphic, 2)

Global $Bezier
Global $MovePoint = -1


GUIRegisterMsg($WM_SIZE, "WM_SIZE")

GUISetOnEvent($GUI_EVENT_MOUSEMOVE, "GUI_EVENT_MOUSEMOVE")
GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "GUI_EVENT_PRIMARYDOWN")
GUISetOnEvent($GUI_EVENT_PRIMARYUP, "GUI_EVENT_PRIMARYUP")
GUISetOnEvent($GUI_EVENT_CLOSE, "GUI_EVENT_CLOSE")
GUISetState()

While True
    Sleep(10)
    _Draw()
WEnd

Func GUI_EVENT_MOUSEMOVE()
    Local $ginfo = GUIGetCursorInfo()
    If $MovePoint > -1 Then
        _Bezier_SetControlPoint($Bezier, $MovePoint, $ginfo)
    EndIf

EndFunc

Func GUI_EVENT_PRIMARYDOWN()
    Local $ginfo = GUIGetCursorInfo()

    If UBound($Bezier) = 0 Then
        Local $point[2]
        $point[0] = $ginfo[0]
        $point[1] = $ginfo[1]
        $Bezier = _Bezier_Create($point)
        Return
    EndIf

    For $t = 0 To _Bezier_GetPointCount($Bezier)
        $P = _Bezier_GetControlPoint($Bezier, $t)
        If _InRange($ginfo, $P, 3) Then
            $MovePoint = $t
            Return
        EndIf
    Next

    $MovePoint = _Bezier_AddControlPoint($Bezier, $ginfo)
EndFunc

Func GUI_EVENT_PRIMARYUP()
    $MovePoint = -1
EndFunc

Func GUI_EVENT_CLOSE()
    _GDIPlus_GraphicsDispose ($hGraphic)
    _GDIPlus_Shutdown ()
    Exit
EndFunc


Func _InRect($point, $rectp1, $rectp2)
    If $point[0] > $rectp1[0] And $point[0] < $rectp2[0] And $point[1] > $rectp1[1] And $point[1] < $rectp2[1] Then
        Return True
    EndIf

    Return False
EndFunc

Func _InRange($point1, $point2, $range)
    If Sqrt(($point1[0] - $point2[0])^2 + ($point1[1] - $point2[1])^2) < $range Then
        Return True
    EndIf
    Return False
EndFunc


Func _Draw()
    Local $timer = TimerInit()
    _GDIPlus_GraphicsClear($MainGraphic, 0xFFFFFFFF)
    If UBound($Bezier) <> 0 Then
        _Bezier_Draw($MainGraphic, $Bezier, 40)
    EndIf
    _GDIPlus_GraphicsDrawImage($hGraphic, $BackBuffer, 0, 0)
    WinSetTitle($hGUI, "", "FPS: " & Round(1000 / TimerDiff($timer), 2))
EndFunc

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose ($BackBuffer)
    _GDIPlus_BitmapDispose($BackBuffer)
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND ($hGUI)
    ConsoleWrite($lParam & @CRLF)
    $BackBuffer = _GDIPlus_BitmapCreateFromGraphics(_WinAPI_LoWord($lParam), _WinAPI_HiWord($lParam), $hGraphic)
    $MainGraphic = _GDIPlus_ImageGetGraphicsContext($BackBuffer)
    _GDIPlus_GraphicsSetSmoothingMode($MainGraphic, 2)
    _Draw()
EndFunc

Func _Bezier_Draw($Graphics, $B, $subdivid = 25)
    Local $oldPoint = _Bezier_GetPoint($B, 0)
    Local $point
    For $x = 0 To 1 Step 1/$subdivid
        $point = _Bezier_GetPoint($B, $x)
        _GDIPlus_GraphicsDrawLine($Graphics, $oldPoint[0], $oldPoint[1], $point[0], $point[1])
        $oldPoint = $point
    Next

    $point = _Bezier_GetPoint($B, 1)
    _GDIPlus_GraphicsDrawLine($Graphics, $oldPoint[0], $oldPoint[1], $point[0], $point[1])
    Local $pen = _GDIPlus_PenCreate()
    _GDIPlus_PenSetDashStyle($pen, $GDIP_DASHSTYLEDASH)

    ;_GDIPlus_GraphicsDrawLine($Graphics, $B[0][0], $B[0][1], $B[1][0], $B[1][1], $pen)
    ;_GDIPlus_GraphicsDrawLine($Graphics, $B[2][0], $B[2][1], $B[3][0], $B[3][1], $pen)
    Local $oldPoint = _Bezier_GetControlPoint($B, 0)
    Local $point
    For $x = 0 To UBound($B) - 1
        $point = _Bezier_GetControlPoint($B, $x)
        _GDIPlus_GraphicsDrawLine($Graphics, $oldPoint[0], $oldPoint[1], $point[0], $point[1], $pen)
        $oldPoint = $point
        _GDIPlus_GraphicsFillEllipse($Graphics, $B[$x][0] - 3, $B[$x][1] - 3, 6, 6)
    Next
EndFunc

#cs
This is where the real bezier UDF start
#ce
Func _Bezier_GetPoint($B, $t)
    Local $n = UBound($B) - 1
    For $k = 1 To $n
        For $i = 0 To $n - $k
            $B[$i][0] = (1 - $t) * $B[$i][0] + $t * $B[$i + 1][0]
            $B[$i][1] = (1 - $t) * $B[$i][1] + $t * $B[$i + 1][1]
        Next
    Next
    Local $ret[2]
    $ret[0] = $B[0][0]
    $ret[1] = $B[0][1]
    Return $ret
EndFunc

Func _Bezier_Create($points)
    If Mod(UBound($points), 2) <> 0 Then
        Return SetError(1, 0, -1)
    EndIf

    Local $B[UBound($points) / 2][2]
    For $x = 0 To UBound($B) - 1
        $B[$x][0] = $points[$x * 2]
        $B[$x][1] = $points[($x * 2)  + 1]
    Next


    Return $B
EndFunc

Func _Bezier_GetPointCount($B)
    Return UBound($B) - 1
EndFunc

Func _Bezier_GetControlPoint($B, $point)
    If $point > UBound($B) - 1 Then
        Return SetError(1, 0, -1)
    EndIf

    Local $ret[2]
    $ret[0] = $B[$point][0]
    $ret[1] = $B[$point][1]

    Return $ret
EndFunc

Func _Bezier_SetControlPoint(ByRef $B, $point, $newpoint)
    If $point > UBound($B) - 1 Then
        Return SetError(1, 0, -1)
    EndIf
    $B[$point][0] = $newpoint[0]
    $B[$point][1] = $newpoint[1]

    Return $B
EndFunc

Func _Bezier_AddControlPoint(ByRef $B, $point)
    ReDim $B[UBound($B) + 1][UBound($B, 2)]

    $B[UBound($B) - 1][0] = $point[0]
    $B[UBound($B) - 1][1] = $point[1]

    Return UBound($B) - 1
EndFunc
Edited by Alek

[font="Impact"]Never fear, I is here.[/font]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×