Bezier line graph
Bezier line graph
I am looking for simple solution to draw line bezier curve from values in 2D array. I do not need any complex library, but solution with example.
Thank you!
Lukas
Thank you!
Lukas
Re: Bezier line graph
This might help you...
Code: Select all
; English forum: http://www.purebasic.fr/english/viewtopic.php?t=6511&highlight=
; Author: ricardo (updated for PB4.00 by blbltheworm + Andre)
; Date: 12. June 2003
; OS: Windows
; Demo: No
Structure PointAPI
x.l
y.l
EndStructure
Global Dim P.PointAPI(3)
Procedure CreateBezier()
StartDrawing(WindowOutput(0))
Red = RGB(255,0,0)
Blue = RGB(0,0,255)
P(0)\x = 0
P(0)\y = 0
P(1)\x = 80
P(1)\y = 10
P(2)\x = 150
P(2)\y = 70
P(3)\x = 130
P(3)\y = 230
LineXY(P(0)\x+10,P(0)\y+10,P(1)\x+10,P(1)\y+10,Blue)
Box(P(0)\x+10,P(0)\y+10, 4, 4,Red)
Box(P(1)\x+10,P(1)\y+10, 4, 4,Red)
LineXY(P(2)\x+10,P(2)\y+10,P(3)\x+10,P(3)\y+10,Blue)
Box(P(2)\x+10,P(2)\y+10, 4, 4,Red)
Box(P(3)\x+10,P(3)\y+10, 4, 4,Red)
hDC = GetDC_(GadgetID(1))
PolyBezier_(hDC,@P(),4)
StopDrawing()
EndProcedure
If OpenWindow(0,100,150,450,300,"Create Beizer Curve",#PB_Window_SystemMenu)
ImageGadget(1,10,10,255,255,0)
ButtonGadget(3,300,140,50,25,"Curve")
Repeat
EventID=WaitWindowEvent()
Select EventID
Case #PB_Event_Gadget
Select EventGadget()
Case 3
CreateBezier()
EndSelect
EndSelect
Until EventID=#PB_Event_CloseWindow
EndIf
- It was too lonely at the top.
System : PB 6.10 LTS (x64) and Win Pro 11 (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
System : PB 6.10 LTS (x64) and Win Pro 11 (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
Re: Bezier line graph
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Re: Bezier line graph
Because I really needed solution I made tiny implementation of Centripetal Catmull–Rom spline algorithm.
Bezier Curve Chart
Source: http://www.ctvrtky.info/wp-content/uplo ... bezier.zip
Bezier Curve Chart
Source: http://www.ctvrtky.info/wp-content/uplo ... bezier.zip
Re: Bezier line graph
Please use EnableExplicit.
It is very annoying if you have to add this yourself afterwards.
This you must not declare self, it's predefined on PB as Structure "Point"
See here, Result is not "Potected"
Also use not "Define" inside Procedures, this get quick mismatch with "Global", at the same.
And again, code without EnableExplicit, has a Trapdoor
Why you refuse EnableExplicit is hard to understand, too bad - Plonk
It is very annoying if you have to add this yourself afterwards.
This you must not declare self, it's predefined on PB as Structure "Point"
Code: Select all
Structure struct_point
x.i
y.i
EndStructure
Code: Select all
Procedure Min(a, b)
If a <= b
Result = a
Else
Result = b
EndIf
ProcedureReturn Result
EndProcedure
And again, code without EnableExplicit, has a Trapdoor
Code: Select all
Procedure Min_Array(Array a(1))
Define Result
Result = a(0)
For i = 0 To ArraySize(a()) - 1
If Result >= a(i)
Result = a(i)
EndIf
Next
ProcedureReturn Result
地球上の平和
Re: Bezier line graph
Dear Saki, updated by your reccomendation, only I kept own structure for y,x points.
Can somebody check it on Windows and OSX?
THX
Lukas
Can somebody check it on Windows and OSX?
THX
Lukas
- Mindphazer
- Enthusiast
- Posts: 341
- Joined: Mon Sep 10, 2012 10:41 am
- Location: Savoie
Re: Bezier line graph
Hi Lukas,
I've just checked on OS X, it seems to work fine. Nice job !
I've just checked on OS X, it seems to work fine. Nice job !
MacBook Pro 14" M1 Pro - 16 Gb - MacOS 14 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
...and unfortunately... Windows at work...
Re: Bezier line graph
Works fine under Windows 10 and looks very nice.l1marik wrote: Can somebody check it on Windows and OSX?
THX
Lukas
I noticed that you only implemented part of Saki's suggestions. Since I don't know whether you didn't understand what he was suggesting or if you just didn't feel like it, I have modified your code as per below to work without a single global variable.
If I'm telling you something you already know, my apologies: Globals are deemed undesirable by most experienced members of the programming communities - hence a slew of new(er) languages that don't support them at all: Haskell, V etc.
Code: Select all
EnableExplicit
Structure struct_point
x.i
y.i
EndStructure
Declare Min_Array(Array a(1))
Declare Max_Array(Array a(1))
Declare Min(a, b)
Declare Max(a, b)
Declare Draw_Chart(gid, Array chart_data(1), in_width, in_height, bgcol = 0, frontcol = 0)
Declare.s catmullRom2bezier(Array points.struct_point(1))
; -----------------------------------------------------------------------------------------
Procedure Min_Array(Array a(1))
Protected result = a(0), i
For i = 0 To ArraySize(a()) - 1
If result >= a(i)
result = a(i)
EndIf
Next
ProcedureReturn result
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure Max_Array(Array a(1))
Protected result = a(0), i
Result = a(0)
For i = 0 To ArraySize(a()) - 1
If Result <= a(i)
Result = a(i)
EndIf
Next
ProcedureReturn Result
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure Min(a, b)
ProcedureReturn (a * Bool(a <= b) + b * Bool(b < a))
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure Max(a, b)
ProcedureReturn (a * Bool(a >= b) + b * Bool(b > a))
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure.s catmullRom2bezier(Array points.struct_point(1))
Protected out_string.s = "", i, j
For i = 0 To ArraySize(points()) - 2
Dim p.struct_point(4) ; no need for protected keyword here - new arrays are always local
If i > 0
p(0)\x = points(Max(i - 1, 0))\x
p(0)\y = points(Max(i - 1, 0))\y
Else
p(0)\x = points(i)\x
p(0)\y = points(i)\y
EndIf
p(1)\x = points(i)\x
p(1)\y = points(i)\y
p(2)\x = points(i + 1)\x
p(2)\y = points(i + 1)\y
p(3)\x = points(Min(i + 2, ArraySize(points()) - 1))\x
p(3)\y = points(Min(i + 2, ArraySize(points()) - 1))\y
; For j = 0 To ArraySize(p())-1
; Debug Str(p(j)\x) + "/" + Str(p(j)\y)
; Next
; Debug "-----------------------"
;Catmull-Rom To Cubic Bezier conversion matrix
; 0 1 0 0
;-1/6 1 1/6 0
; 0 1/6 1 -1/6
; 0 0 1 0
Dim bp.struct_point(3) ; no need for protected keyword here - new arrays are always local
bp(0)\x = (-p(0)\x + 6 * p(1)\x + p(2)\x) / 6
bp(0)\y = (-p(0)\y + 6 * p(1)\y + p(2)\y) / 6
bp(1)\x = (p(1)\x + 6 * p(2)\x - p(3)\x) / 6
bp(1)\y = (p(1)\y + 6 * p(2)\y - p(3)\y) / 6
bp(2)\x = p(2)\x
bp(2)\y = p(2)\y
FreeArray(p())
Out_String = Out_String + "C "
For j = 0 To ArraySize(bp()) - 1
Out_String = Out_String + Str(bp(j)\x) + " " + Str(bp(j)\y) + " "
Next
FreeArray(bp())
Next
ProcedureReturn out_string
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure Draw_Chart(gid, Array chart_data(1), in_width, in_height, bgcol = 0, frontcol = 0)
Protected x_resolution.f, y_resolution.f, y_middle.f, text.s, x.f, y.f, i
x_resolution = in_width/ArraySize(chart_data())
y_resolution = in_height/Abs(Max_Array(chart_data()) - Min_Array(chart_data()))
y_middle = Abs(Max_Array(chart_data()) - Min_Array(chart_data())) / 2
Dim chart.struct_point(ArraySize(chart_data()))
For i = 0 To ArraySize(chart_data()) - 1
chart(i)\x = ((i + 1) * x_resolution )
chart(i)\y = (-chart_data(i) * y_resolution / 2) + 2 * in_height / 3
Next
If StartVectorDrawing(CanvasVectorOutput(gid))
ScaleCoordinates(DesktopResolutionX(), DesktopResolutionY())
AddPathBox(0, 0, in_width, in_height)
VectorSourceColor(RGBA(0, 0, 0, 255))
FillPath()
ClosePath()
For i = 0 To ArraySize(chart_data())
AddPathBox(i * (x_resolution + x_resolution/500) - x_resolution/2, in_height / 11.4, x_resolution -(x_resolution / 50), in_height)
Next
VectorSourceLinearGradient(i * (x_resolution + x_resolution/500) - x_resolution / 2, in_height / 11.4, i * (x_resolution + x_resolution / 500) - x_resolution / 2, in_height)
VectorSourceGradientColor(RGBA(0, 0, 0, 0), 0)
VectorSourceGradientColor(RGBA(255, 255, 255, 0), 0.01)
VectorSourceGradientColor(RGBA(255, 255, 255, 200), 0.15)
VectorSourceGradientColor(RGBA(0, 0, 0, 0), 0.98)
ClosePath()
FillPath()
AddPathBox(0, 0, in_width, in_height)
If bgcol = 0 : bgcol = RGBA(0, 0, 0, 255):EndIf
VectorSourceColor(bgcol)
FillPath()
ClosePath()
; Chart line
MovePathCursor(0, (-chart_data(0) * y_resolution / 2) + 2 * in_height / 3)
AddPathSegments(catmullRom2bezier(chart()))
VectorSourceLinearGradient(0, 0, in_width, 0)
VectorSourceGradientColor(RGBA(0, 0, 0, 0), 0)
VectorSourceGradientColor(RGBA(255, 255, 255, 0), 0.02)
VectorSourceGradientColor(RGBA(255, 255, 255, 255), 0.10)
VectorSourceGradientColor(RGBA(255, 255, 255, 255), 0.90)
VectorSourceGradientColor(RGBA(255, 255, 255, 0), 0.98)
VectorSourceGradientColor(RGBA(0, 0, 0, 0), 1)
StrokePath(in_height / 150)
; Chart area
MovePathCursor(in_width, in_height)
AddPathLine(0, in_height)
AddPathLine(0, (-chart_data(0) * y_resolution / 2) + 2 * in_height / 3)
AddPathSegments(catmullRom2bezier(chart()))
VectorSourceLinearGradient(0, 0, in_width, 0)
VectorSourceGradientColor(RGBA(0,0,0, 0), 0)
VectorSourceGradientColor(RGBA(255, 255, 255, 0), 0.02)
VectorSourceGradientColor(RGBA(255, 255, 255, 40), 0.20)
VectorSourceGradientColor(RGBA(255, 255, 255, 40), 0.80)
VectorSourceGradientColor(RGBA(255, 255, 255, 0), 0.98)
VectorSourceGradientColor(RGBA(0, 0, 0, 0), 1)
FillPath()
; Chart headers
For i = 1 To ArraySize(chart_data()) - 1
AddPathBox(i * (x_resolution + x_resolution / 500) - x_resolution / 2, 0, x_resolution - (x_resolution / 50), in_height / 12)
Next
VectorSourceColor(RGBA(255, 255, 255, 50))
ClosePath()
FillPath()
; Chart headers labels - to be added
; Chart values
VectorSourceColor(RGBA(255, 255, 255, 200))
VectorFont(FontID(0), x_resolution / 2.5)
For i = 1 To ArraySize(chart_data()) - 1
text = StrF(chart_data(i - 1) / 10, 1)
x = i * (x_resolution + x_resolution / 500) - x_resolution / 2
x = (x + ((x_resolution - (x_resolution / 50)) / 2)) - VectorTextWidth(text) / 2
MovePathCursor(x, in_height / 8)
DrawVectorText(text)
Next
StopVectorDrawing()
EndIf
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure Resize_Window()
Protected i
Dim chart_dataset(24) ; no need for protected keyword here - new arrays are always local
For i = 0 To ArraySize(chart_dataset()) - 1
chart_dataset(i) = (Random(100, 0) - 30)
Next
ResizeGadget(0, 0, 0, WindowWidth(0), WindowHeight(0))
Draw_Chart(0, chart_dataset(), WindowWidth(0), WindowHeight(0), RGBA(Random(30, 0), Random(55, 0), Random(55, 0), Random(200, 100)))
EndProcedure
; -----------------------------------------------------------------------------------------
Procedure StartProgram()
Protected Event
If OpenWindow(0, 0, 0, 400, 200, "Bezier Curve Chart", #PB_Window_SystemMenu | #PB_Window_ScreenCentered| #PB_Window_SizeGadget| #PB_Window_MaximizeGadget)
CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0))
AddWindowTimer(0, 123, 1000)
LoadFont(0, "Ubuntu", 10, #PB_Font_HighQuality)
Resize_Window()
;
BindEvent(#PB_Event_SizeWindow, @Resize_Window(), 0)
BindEvent(#PB_Event_Timer, @Resize_Window(), 0)
;
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
EndProcedure
; -----------------------------------------------------------------------------------------
StartProgram()
PB 5.73 on Windows 10 & OS X High Sierra
Re: Bezier line graph
Looks very good! Thx for sharing!
"Daddy, I'll run faster, then it is not so far..."