Bezier Spline curves

Share your advanced PureBasic knowledge/code with the community.
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Bezier Spline curves

Post by einander »

Ricardo asked for this many months ago.
Hope it helps.

Edited 13 march 04
********BEWARE! ********
Tested with WinXP only.
Reported crash with Win98
Any feedback and bug reports are welcome.
************************

Code: Select all

Title$ = "Bezier Spline curves - by einander - Click, move & delete points"
; march 10 -2004 -PB 3.81
; Thanks Psychophanta for the Hypotenuse ASM procedure! 
; ___________________________

; Click and create points
; Move points with Left Mousebutton
; Delete selected point with Right Mousebutton (need more than 3 points to delete one)
; To see the first spline you need at least 3 points
; Quit with ESC

Enumeration
    #IMG
    #GadIMG
EndEnumeration

Global hWnd, hDC, _X, _Y, MX, MY, MK, Vertex,MaxVertex, Segments, hDef.f
Global LineWidth.B, SplineColor, BKGcolor, PointColor, Numbers, TextColor

; *************************************************
; CHOOSE HERE YOUR PREFERENCES
LineWidth = 6
Segments = 12 ; number of lines between Vertex
MaxVertex = 200 ; maximum clicked points number
SplineColor = #Green
BKGcolor = #Black
PointColor = #Magenta
TextColor = #Yellow
ViewXpos = 1 ; 0 = Not view
; ************************************************

hDef = 1 / Segments
Dim A.f(MaxVertex)
Dim B.f(MaxVertex)
Dim C.f(MaxVertex)
Dim D.f(MaxVertex)
Dim X.l(MaxVertex)
Dim Y.l(MaxVertex)
Dim Bezier.l(MaxVertex)
Dim Indx.l(MaxVertex)
Dim XSort.l(MaxVertex)
Dim YSort.l(MaxVertex)
Dim X_Spline.l(MaxVertex * Segments )
Dim Y_Spline.l(MaxVertex * Segments )

Procedure INL(ADDR, E, Va) ; Assign value Va to element E of Array starting at ADDR
    PokeL(ADDR + E * 4, Va)
EndProcedure

Procedure Lin(DC, X, Y, X1, Y1, Width, Color)
    Pen = CreatePen_(#Ps_Solid, Width, Color)
    SelectObject_(DC, pen)
    MoveToEx_(DC, X, Y, 0) : LineTo_(DC, X1, Y1)
    DeleteObject_(pen)
EndProcedure

Procedure Text(X, Y, T$)
    FrontColor(Red(TextColor), Green(TextColor), Blue(TextColor))
    Locate(X, Y)
    DrawText(T$)
EndProcedure

Procedure ArrayCopy(SRC, DEST, DI) ; DI es la cant de elem a copiar
    CopyMemory(SRC, DEST, DI * 4)
EndProcedure

Procedure VarL(ADDR, E) ; return element E from Array starting at ADDR
    ProcedureReturn PeekL(ADDR + E * 4) 
EndProcedure

Procedure SpLin(N, AC1, AC2) ; splines calculations
    N1 = N - 1
    B(0) = (VarL(AC1, 1) - VarL( AC1, 0)) * 4
    For I = 1 To N1
        B(I ) = (VarL(AC1, 1 + I ) - VarL(AC1, I ) * 2 + VarL(AC1, I - 1)) * 3
    Next I
    B(N ) = (VarL(AC1, N1) - VarL(AC1, N )) * 4
    C(0) = B(0) / 2
    B(1) - B(0) / 4
    Dr.f = 0.5
    C(1) = B(1) / 2
    
    For I = 2 To N1
        S.f = -Dr / 2
        B(I ) - B(I - 1) / 4
        Dr = 1 / (S / 2 + 2)
        C(I ) = B(I ) * Dr
    Next I
    
    B(N ) + B(N1) * - Dr
    C(N ) = B(N) / (-Dr / 2 + 2)
    Repeat
        B.f = C(1 + N1) : C.f = B(N1) * 2
        If C : B / C : EndIf
        C(N1) * (1 - B)
        N1 - 1
    Until N1 = 0
    C(0) * (1 - C(1))
    If B(0) : C(0) / B(0) : EndIf
    For I = 1 To N
        B(I ) = VarL(AC1, I ) - VarL(AC1, I - 1) + (C(I ) * 2 + C(I - 1)) / 6
        D(I ) = (C(I ) - C(I - 1)) / 6
    Next I
    For I = 1 To N : C(I ) / 2 : Next I
    For I = 1 To N
        T.f = -1
        For j = 0 To Segments - 1
            INL(AC2, R, ((D(I ) * T + C(I )) * T + B(I )) * T + VarL(AC1, I ))
            T + hDef : R + 1
        Next j
    Next I
    INL(AC2, R, VarL(AC1, N ))
EndProcedure

Procedure.f Hypotenuse(Cateto1.f, Cateto2.f) ; this one is from Psychophanta
    ! fld dword[esp] ; push Cateto1 to FPU stack (to st0)
    ! fmul st0, st0 ; Cateto1^2
    ! fld dword[esp + 4] ; push Cateto2 value to FPU stack (to st0) (Cateto1 is now in st1)
    ! fmul st0, st0 ; Cateto2^2
    ! faddp ; Cateto1^2+Cateto2^2 and pop FPU stack
    ! fsqrt ; Sqr(Cateto1^2+Cateto2^2)
EndProcedure

Procedure Near(X, Y, ArrSize, DIR1.L, DIR2.L) ; return elem Nearest to  x,y
    MIn = $FFFFFF
    For i = 0 To ArrSize
        a = hypotenuse(X - PeekL(DIR1 + i * 4), Y - PeekL(DIR2 + i * 4))
        If A < MIn : MIn = A : J = i : EndIf
    Next i
    ProcedureReturn J
EndProcedure

Procedure Callback(0, Msg, wParam, lParam) ; control mouse & key messages
    Result = #PB_ProcessPureBasicEvents
    Select Msg
        Case #WM_MOUSEMOVE
            GetCursorPos_(p.POINT)
            ScreenToClient_(hWnd, p)
            MX = p\X
            MY = p\Y
        Case #WM_LBUTTONDOWN
            If MK = 2 : MK = 3 : Else : MK = 1 : EndIf
        Case #WM_LBUTTONUP
            If MK = 3 : MK = 2 : Else : MK = 0 : EndIf
        Case #WM_RBUTTONDOWN
            If MK = 1 : MK = 3 : Else : MK = 2 : EndIf
        Case #WM_RBUTTONUP
            If MK = 3 : MK = 1 : Else : MK = 0 : EndIf
        Case #WM_KEYDOWN
            Ev = EventwParam()
            If Ev = 27 : End
            EndIf
        Case #PB_EventCloseWindow : End
    EndSelect
    ProcedureReturn Result
EndProcedure

; _________________________________________________________________________________________
_X = GetSystemMetrics_(#SM_CXSCREEN) : _Y = GetSystemMetrics_(#SM_CYSCREEN)
HwND = OpenWindow(0, 0, 0, _X, _Y, #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE, Title$)
hDC = GetDC_(HwND)
CreateGadgetList(hWnd)
ImageGadget(#GadIMG, 0, 0, _X, _Y, 0)
Dawing = StartDrawing(WindowOutput())
    DrawingMode(1)
    Box(0, 0, WindowWidth(), WindowHeight(), BKGcolor)
    Vertex = -1
    SetWindowCallback(@Callback())
    
    Repeat
        WindowEvent()
        If POSANT
            Circle (XSort(POSANT - 1), YSort(POSANT - 1), 5, PointColor) : POSANT = 0
        EndIf
        If MK = 0   ; Find nearest vertex
            C = Near(MX, MY, Vertex, @X(), @Y())
            If Abs(mx - x(c)) < 10 And Abs(my - y(c)) < 10
                If xpos = 0
                    Xpos = X(c) : ypos = Y(c)
                    Circle(xpos, ypos, 5, #white)
                EndIf
            Else
                If xpos
                    Circle(xpos, ypos, 5, pointcolor)
                EndIf
                xpos = 0
            EndIf
            
        ElseIf MK = 1
            If xpos ; Move Vertex
                Repeat
                    WindowEvent()
                    x(c) = mx : y(c) = my
                    Gosub DrawSpline
                Until mk = 0
            Else ; create new Vertex
                Gosub SetPoints
                Repeat : WindowEvent() :Until MK = 0
                If Vertex < 2
                    Lin(hDC, Bezier(0), YSort(0), Bezier(1), YSort(1), LineWidth, SplineColor)
                Else
                    If Vertex <> Vflag
                        Gosub DrawSpline
                    EndIf
                    Vflag = Vertex
                EndIf
            EndIf
        ElseIf MK = 2
            If Vertex > 2
                If xpos
                    For i = c To Vertex
                        x(i) = x(i + 1) : y(i) = y(i + 1)
                    Next
                    Vertex - 1 : Vflag = Vertex
                    Gosub DrawSpline
                EndIf
            EndIf
        EndIf
    ForEver
End
    ; ______________________________________________
    SetPoints :
    Circle(MX, MY, 5, PointColor)
    Vertex + 1
    X(Vertex) = MX : Y(Vertex) = MY 
    Indx(Vertex) = Vertex
    Return
    ; _______________________________________________
    DrawSpline :
    ArrayCopy(@X(), Bezier(), Vertex + 1)
    For I = 0 To Vertex
        XSort(I) = Bezier(Indx(I))
    Next I
    For I = 0 To Vertex
        Bezier(I) = Y(Indx(I))
    Next I
    ArrayCopy(@Bezier(), @YSort(), Vertex + 1)
    SpLin(Vertex, @XSort(), @X_Spline())
    SpLin(Vertex, @YSort(), @Y_Spline())
    CreateImage(#IMG, _X, _Y)
    StopDrawing()
    DRAWING = StartDrawing (ImageOutput())
    If ViewXpos :
        For i = 0 To Vertex
            lin(drawing, XSort(i), 0, XSort(i), _y, 1, RGB(60, 70, 80))
        Next
    EndIf
    For i = 1 To Vertex * Segments
        Lin(drawing, X_Spline(i - 1), Y_Spline(i - 1), X_Spline(i), Y_Spline(i), LineWidth, SplineColor)
    Next
    For i = 0 To Vertex
        Circle (XSort(i), YSort(i), 5, PointColor)
        DrawingMode(1)
        Text(XSort(i) - 4, YSort(i) + 4, Str(i))
    Next
    StopDrawing()
    xpos = 0
    DRAWING = StartDrawing(WindowOutput())
    SetGadgetState(#GadIMG, UseImage(#IMG))
    Return
    
    
Best regards
Einander
Last edited by einander on Sat Mar 13, 2004 10:47 am, edited 1 time in total.
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Ah, just was was needed just when it was needed!

You are a hero. Thanks!
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Hi Einander,

did you read this?

http://msdn.microsoft.com/library/defau ... plines.asp[/url]
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

dell_jockey wrote:Hi Einander,
did you read this?
http://msdn.microsoft.com/library/defau ... plines.asp[/url]
@Dell_jockey

I need the calculations in Procedure SpLin() to modify the shape of the curves, and cant' do that with the maths of the API fuctions .
Actually, the values on Splin() procedure are my modifications from several sources found on the Net.
Is funny that most sources have different spline formulae!

Thanks for the links.

Best regards
Einander
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Hi Einander,

so you're not satisfied with the math behind the GDI either, are you? I can see why...

I happen to be looking for 3D cubic and quintic interpolating spline formulae. While 2D stuff is readily available on the net, I didn't manage to find anything pertaining to 3D.

Can you point me to resources?

thanks!
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

dell_jockey wrote: happen to be looking for 3D cubic and quintic interpolating spline formulae.
I didn't manage to find anything pertaining to 3D.
Can you point me to resources?
Here are some links :
http://hilbert.math.hr/arhive/mathgroup ... /0171.html

On the Blitz archives, look for
http://www.blitzbasic.com/Community/pos ... opic=23050

This one is for MS excel
http://www.fileboost.net/directory/educ ... 01919.html

Matrix method
http://www.cs.unc.edu/~hoff/projects/co ... tents.html

Quintic spline interpolation
http://www.ima.umn.edu/~awanou/p_awanou.ps

Rhino demo - NURBS - I'ts only a link, I dont have this demo.
http://www.ima.umn.edu/~awanou/p_awanou.ps

I'm no splines specialist, but a musician tryng to use splines to represent wave shapes.

Best regards
Einander
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Gracias, Einander!
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
TronDoc
Enthusiast
Enthusiast
Posts: 310
Joined: Wed Apr 30, 2003 3:50 am
Location: 3DoorsDown

Post by TronDoc »

I lost the error messages, but
the program caused stack faults
and crashed my PC.
w98fe 256Mb pII
Joe
peace
[pI 166Mhz 32Mb w95]
[pII 350Mhz 256Mb atir3RagePro WinDoze '98 FE & 2k]
[Athlon 1.3Ghz 160Mb XPHome & RedHat9]
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Crash report

Post by einander »

@TroncDoc:
Sorry for the crash!
It's tested with XPpro 750Mb. Can't test it with win98.

Any other hang/crash report?
Now it has a warning message.

Best Regards
Einander
TronDoc
Enthusiast
Enthusiast
Posts: 310
Joined: Wed Apr 30, 2003 3:50 am
Location: 3DoorsDown

Re: Crash report

Post by TronDoc »

einander wrote:@TroncDoc:Sorry for the crash!
no big deal.
I realized I had debug ON and was running it from the IDE.
I compiled it to an .EXEcutable with debug OFF and it
works a little better, but still exhibits some odd behaviours.
*sometimes when moving a dot it just stops
*sometimes another dot (white) appears
*once it starts acting strange then no dot can be grabbed
and each click produces another dot that isn't part of the curve.
If there's something you'd like me to change or try.. ..let me know.
Joe
peace
[pI 166Mhz 32Mb w95]
[pII 350Mhz 256Mb atir3RagePro WinDoze '98 FE & 2k]
[Athlon 1.3Ghz 160Mb XPHome & RedHat9]
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Post by oldefoxx »

To understand 2D and 3D Bezier Curves, look at:
http://www.gamedev.net/reference/articl ... le1584.asp

The program above works find on W2k Pro. I note that TronDoc only has 32MB of RAM, which could be a problem. Compiling without IDE and DEBUG merely decreases the size of the program. Need someone with W95 and more RAM to run this to verify low RAM is the probable problem.

Also look at Cardinal Curves (same link to MS as given above). These avoid sharp turns when end point same as start point.

Anybody got DrawCurve() and DrawCloseCurve() functions? Most found source code assume you are using a library that has these functions. These routines draw Quadratic Curves, and the last one just loop from the end point back to the start point.
has-been wanna-be (You may not agree with what I say, but it will make you think).
TronDoc
Enthusiast
Enthusiast
Posts: 310
Joined: Wed Apr 30, 2003 3:50 am
Location: 3DoorsDown

Post by TronDoc »

oldefoxx wrote:I note that TronDoc only has 32MB of RAM, which could
the errors I saw were on my '98 machine:256Mb. --jb
peace
[pI 166Mhz 32Mb w95]
[pII 350Mhz 256Mb atir3RagePro WinDoze '98 FE & 2k]
[Athlon 1.3Ghz 160Mb XPHome & RedHat9]
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Guess That Isn't It Then

Post by oldefoxx »

Understand. Okay, your best bet is to see if someone else with Win 95/98 expereiences the same problem. Otherwise, I might suggest using either Turbo Memory or Memory Zipper to optimize your RAM and give you some added reporting capabilities. I like Memory Zipper, as informal test have shown that it does a slightly better job, but it also consumes more RAM, which becomes a problem on Win2K or WinXP machines with only 256MB of RAM. MZ seems to work okay on Win95 PCs with 256MB of RAM, but I'm not sure about Win98 with that amount -- probably about the same.

The key to identifying and isolating a problem is to try and change its behavour by changing its environment.

Regards
has-been wanna-be (You may not agree with what I say, but it will make you think).
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Adapted for PB 4+

Post by einander »

Adapted for PB 4+

Code: Select all

;Cubic Splines - by einander
;PB 4.20 beta 5
;May 18 2008

#r175=1.75 : #O5=0.5: #O25=0.25 :#e6=0.000001

Global _Img,_ImGad ,Step_Max,_DRAWING,_MW
Global _MaxPoints=200  ; set your points limit
Global _Steps=100  ; steps between points ; increase to smooth curves 
Global _Deflect.f 

Structure VERTEX
     A.D :  b.D :  c.D
EndStructure 

Global Dim _X.l(_MaxPoints  ) 
Global Dim _Y.l(_MaxPoints  )
Global Dim _xSPL.l(_MaxPoints*_MaxPoints) 
Global Dim _ySPL.l(_MaxPoints*_MaxPoints)

Macro ArrayCopy(SRC,Dest)  ;- ArrayCopy(@SRC(),@DEST())
     CopyMemory(SRC,Dest,     PeekL( SRC-8  ) *4)
EndMacro
     
Macro STOPDRAW  ;- StopDraw
If _DRAWING:StopDrawing():_DRAWING=0:EndIf
EndMacro

Macro DrawIMG(IMG) ;- DrawIMG(IMG)
If _DRAWING:StopDrawing():EndIf
_DRAWING=StartDrawing(ImageOutput(IMG))
EndMacro

Macro GadIMG(ImGad=_ImGad,IMG=_Img,FreeIMG=0) ;-Gadimg(ImGad=_ImGad,IMG=_Img,FreeIMG=0) 
     STOPDRAW
     SetGadgetState(ImGad,ImageID(IMG))
     If FreeIMG :FreeImage(IMG):EndIf
EndMacro

Procedure  ClsImg(IMG,RGB=0) ;-ClsImg(IMG,RGB=0) 
     DrawIMG(IMG)
     Box(0,0,ImageWidth(IMG),ImageHeight(IMG),RGB)
EndProcedure 



Macro MMx :  WindowMouseX(EventWindow()) : EndMacro
Macro MMy :  WindowMouseY(EventWindow()) : EndMacro
Macro MMK
     Abs(GetAsyncKeyState_(#VK_LBUTTON) +GetAsyncKeyState_(#VK_RBUTTON)*2+GetAsyncKeyState_(#VK_MBUTTON)*3)/$8000   
EndMacro

Procedure MW(STP=1) ;Ret MouseWheel y Hace _MW
     _MW= -EventwParam()>>16/100*STP  ; a menor divisor, mayor step
     ProcedureReturn _MW
EndProcedure
  

Procedure Splin(n)
     Hsteps.D=1/_Steps   
     Num=n
     *Supp=@_X()
     *Spli=@_xSPL()
     nPoints=_MaxPoints*_MaxPoints
     Dim Vec.VERTEX(_MaxPoints)
     Dim Supp(_MaxPoints) 
     Dim Spli(nPoints )
     S.D : Dr.D : T.D
     DEFL.f=_Deflect+6
     For Loop=0 To 1  ; first loop for X, second for Y
          ArrayCopy(*Supp,@Supp())
          ArrayCopy(*Spli,@Spli())
          N1 =n-1
          Vec(0)\A = (Supp(1) - Supp(0)) * DEFL
          For i  = 1 To N1 
               Vec(i)\A = (Supp(1+i ) - Supp(i ) * 2 + Supp(i -1)) * DEFL/2
          Next i 
          Vec(n)\A = (Supp(N1) - Supp(n )) * DEFL
          Vec(0)\b = Vec(0)\A * #O5
          Vec(1)\A  -Vec(0)\A * #O25
          Dr = 1 /#r175
          Vec(1)\b = Vec(1)\A / #r175
          For i  = 2 To N1 
               S = -#O5 * Dr
               Vec(i)\A+Vec(i-1)\A * S
               Dr = 1 / (S * #O5 + 2)
               Vec(i)\b =Vec(i)\A * Dr
          Next i
          Vec(n)\A + Vec(N1)\A * -Dr
          Vec(n)\b = Vec(n)\A / (-Dr * #O5 + 2)
          i=N1
          Repeat
               If Vec(i)\A = 0 :  T =  #e6   
               Else :  T = Vec(i)\A
               EndIf
               Vec(i)\b*(1 - Vec(i+1)\b / T * #O5)
               i-1
          Until i=0
          
          If Vec(0)\A = 0 :  T = #e6   
          Else :  T = Vec(0)\A
          EndIf
          
          Vec(0)\b * (1 - Vec(1)\b / T)
          
          For i  = 1 To n 
               Vec(i)\A = Supp(i ) - Supp(i-1) + (Vec(i)\b * 2 + Vec(i-1)\b) /6
               Vec(i)\c = (Vec(i)\b -Vec(i-1)\ b) /6
          Next i 
          
          For i  = 1 To n 
               Vec(i)\b*#O5
          Next i 
          K  = 0 
          For i  = 1 To n 
               T = -1
               For j  = 0 To _Steps  - 1
                    Spli(K ) = ((Vec(i)\c * T + Vec(i)\b) * T + Vec(i)\A) * T + Supp(i )
                    T+Hsteps
                    K+1 
               Next j 
          Next i 
          Spli(K) = Supp(n )
          ArrayCopy(@Spli(),*Spli)
          ArrayCopy(@Supp(),*Supp)   
          *Supp=@_Y()
          *Spli=@_ySPL()
          n=Num
     Next
     Dim Supp(0) :Dim Spli(0):Dim Vec.VERTEX(0)
EndProcedure

Macro GetPoints(Num)
     If MMK  = 1 
          If Num=-1
               ClsImg(_Img) :  GadIMG()
          EndIf
          DrawIMG(_Img)
          Circle (MMx ,MMy ,5,#Red)
          Num+1
          _X(Num ) = MMx :  _Y(Num ) = MMy
          DrawText( MMx,MMy+ 6,Str(Num),#White,0)
          GadIMG()
          While MMK :  WaitWindowEvent() :  Wend

     EndIf
     If Num  = _MaxPoints Or MMK=2  : Stat=1 :  EndIf
EndMacro 

Procedure DrawSplin(Num,*Stat)
     If Num  < 2
          MessageRequester("","Not enough Points Selected",0) 
     ElseIf Num<_MaxPoints
          Splin(Num)
          DrawIMG(_Img)
          ClsImg(_Img)
          For i  = 1 To Num  * _Steps  
               LineXY(_xSPL(i -1),_ySPL(i -1),_xSPL(i ),_ySPL(i),#Yellow)
          Next i 
          For i=0 To Num
               Circle (_X(i) ,_Y(i) ,5,#Red)
          Next
          GadIMG()
     Else
          MessageRequester("","Maximum points reached",0)
          *Stat=0 :  Num=-1
     EndIf
     ProcedureReturn Num
EndProcedure 
;_________________________________________________________________________________________
Title$="Left MouseButton to set points ; Right MuseButton to draw spline -  Deflect (MouseWheel) = "

hwnd=OpenWindow(0,50,50,800,600,Title$,#PB_Window_MinimizeGadget |#PB_Window_Maximize)
SetWindowColor(0,0)
Wi=WindowWidth(0):He=WindowHeight(0)
CreateGadgetList(hwnd)
_Img=CreateImage(#PB_Any,Wi,He-30,32)
_ImGad=ImageGadget(#PB_Any,0,0,0,0,ImageID(_Img))
TB=TrackBarGadget(#PB_Any,0,He-25,Wi-200,22,1,600)
BtnClear=ButtonGadget(#PB_Any,Wi-190,He-25,80,22,"Clear")
BtnDefault=ButtonGadget(#PB_Any,Wi-100,He-25,80,22,"Reset Deflect")

_Deflect=0
SetGadgetState(TB,260)
SetWindowTitle(0,Title$+StrF(_Deflect,1))
Num=#PB_Any
Repeat
     If GetAsyncKeyState_(#VK_ESCAPE):End:EndIf
     Ev = WindowEvent()
     Select Ev
          Case #PB_Event_Gadget
               If EventGadget()=TB 
                    _Deflect=GetGadgetState(TB)/10.0-26
                    If Num>1:   Stat=2:EndIf
                    SetWindowTitle(0,Title$+StrF(_Deflect,1))
                    
               ElseIf EventGadget()=BtnClear
                    ClsImg(_Img) :  GadIMG()
                    Stat=0 :  Num=-1
               ElseIf EventGadget()=BtnDefault
                    _Deflect=0
                    SetGadgetState(TB,260)
                    SetWindowTitle(0,Title$+StrF(_Deflect,1))
                    
                    If Num>1:Stat=2:EndIf
               EndIf
          Case #WM_MOUSEWHEEL
               SetGadgetState(TB,GetGadgetState(TB)+MW())
               _Deflect=GetGadgetState(TB)/10.0-26
               SetWindowTitle(0,Title$+StrF(_Deflect,1))
               
               If Num>1:   Stat=2:EndIf
          Case 0:Delay(10)
     EndSelect 
     If Stat=0 And MMy<He-30
          GetPoints(Num)
     ElseIf Stat =1 Or Stat=2  
          OldNum=Num
          DrawSplin(Num,@Stat) 
          Stat=0 
          While MMK :  WaitWindowEvent() :  Wend        
     EndIf
Until Ev= #PB_Event_CloseWindow  
End  
     
Cheers
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Thanks for the update to your code. :smile:

I noticed it does not function properly when the maximum number of points is reached. May I suggest these few changes (including EnableExplicit):

Code: Select all

;-----------------------------
;declare variables at the beginning of Procedure Splin()
;-----------------------------
Procedure Splin(n)
  
  Protected Num.l = n, Loop.l, i.l, j.l, K.l, N1.l, nPoints.l
  Protected Hsteps.D = 1 / _Steps, S.D, Dr.D, T.D  
  Protected *Supp = @_X(), *Spli = @_xSPL()
  Protected DEFL.f
   
  nPoints = _MaxPoints * _MaxPoints
  Dim Vec.VERTEX(_MaxPoints)
  Dim Supp(_MaxPoints)
  Dim Spli(nPoints )
  DEFL.f = _Deflect + 6
  For Loop = 0 To 1  ; first loop for X, second for Y


;-----------------------------
;replace DrawSplin()'s definition with
;-----------------------------
Procedure DrawSplin(Num,*Stat)
  Protected i.l
  
  If Num < 2
    MessageRequester("","Not enough Points Selected",0)
    ProcedureReturn Num
  ElseIf Num >= _MaxPoints
    MessageRequester("","Maximum points reached",0)
    Num = _MaxPoints - 1
  EndIf 
  
  Splin(Num)
  DrawIMG(_Img)
  ClsImg(_Img)
  For i = 1 To Num * _Steps 
    LineXY(_xSPL(i - 1),_ySPL(i - 1),_xSPL(i),_ySPL(i),#Yellow)
  Next i
  For i = 0 To Num
    Circle (_X(i) ,_Y(i) ,5,#Red)
  Next
  GadIMG()
  
  ProcedureReturn Num
EndProcedure


;-----------------------------
;add declaration of variables at the start of your main loop
;-----------------------------
;_________________________________________________________________________________________

Define Title$ = "Left MouseButton to set points ; Right MuseButton to draw spline -  Deflect (MouseWheel) = "
Define.l hwnd, Wi, He, TB, BtnClear, BtnDefault, Num, OldNum, Ev, Stat


;-----------------------------
;change the call to DrawSplin() at the end of your event loop to
;-----------------------------
Num = DrawSplin(Num,@Stat) ;DrawSplin(Num,@Stat)
Here's an overview of the changes:
  • 1. You reused a variable name in a procedure. I used EnableExplicit and declared variables to help clarify their uses.
    2. DrawSplin() detects when maximum points have been reached. It starts the spline over when this happens and gets stuck in a loop because it's return value is not utilized in the main loop. I reordered DrawSplin() to lower the number of points and then draw the spline. It also record it's return value in the event loop.
Post Reply