View Full Version : Virtual canvas and Canvas_Scale() question
EmbeddedMan
26-06-2017, 19:21
Once I put a canvas into virtual mode with Canvas_SetVirtual(), it appears that Canvas_Scale() has no effect - everything is always plotted 1:1 in the virtual canvas, no matter what I set the scale to.
Is that by design? Is there any way to combine custom coordinate systems on a canvas with virtual mode?
*Brian
ErosOlmi
26-06-2017, 19:41
Yes, all is reset.
Set scaling after setting virtual.
EmbeddedMan
26-06-2017, 22:38
I see.
There's no easy way to take a canvas with a bunch of lines drawn on it at one set of coordinates (say (0,0), (1000,500)) and then change the scaling (say to (0,0),(10,50)), and have all of the graphics on the canvas follow the scaling change, is there?
Here's what I'm really after, big picture. I've collected a lot of data points in a set of arrays. Let's say 100000 points. I can set up a virtual canvas that's 100000 pixels wide, and then draw my set of lines on the canvas. My viewport is only 1000 pixels wide, so the user can then scroll around the graph as much as they want, and it's lightning fast. It's really awesome.
However, I'm trying to implement horizontal scaling. I have two buttons that allow you to zoom in and zoom out, so that you can change how many points of data are displayed per pixel in the viewport. This lets you see much more of the graph at once.
But it's _so_ slow to completely redraw the whole canvas every time they change the horizontal scaling factor.
What I'd rather do is draw the whole graph, once, to the virtual canvas, and then re-scale the virtual canvas to compress or expand the image visible through the viewport.
Right now, it appears that when you set Canvas_Scale(), it applies to all graphic elements that you draw after that point, but it does not do anything to the existing canvas.
Can you think of any way I can do my 'rapid scaling'?
*Brian
ErosOlmi
26-06-2017, 23:49
Scaling is just a way to create a new coordinates system.
What you mean is a kind of zooming,
I suppose it can be done capturing your canvas into a bitmap, stretching the bitmap, changing the scale and then putting the stretched bitmap back to the canvas.
But this is just theory, I need to put together an example and see how it works.
Do not know if I will have time this week. Maybe next week-end
EmbeddedMan
27-06-2017, 02:20
Eros,
Nah, don't worry about it. If there isn't an easy way built into TB, it's not worth spending time on concocting a complex example. It's just a way to make something that's working properly now, work faster. That's all.
Thanks, as always for the awesome language. :-)
*Brian
ErosOlmi
27-06-2017, 09:46
hmmm anyway worth to investigate.
I will let your know if I will get something
Petr Schreiber
28-06-2017, 17:49
I love Canvas and I use it for lot of monitoring gfx at AVG/Avast, but I would recommend you to take a peek at TBGL for this kinds of advanced wizardry, if I may :)
Let me know, if this is something interesting for you - I will be glad to give you hand when needed.
Petr
EmbeddedMan
28-06-2017, 20:36
Petr,
Yeah, I figured you'd say that. :-) And of course you're absolutely right - TBGL is clearly the way to get the best performance. My only reason for not diving into TBGL and learning how to use it for this application is time. Canvas is simpler and I already know it, where as TBGL will need time spent learning how to use it right.
*Brian
Petr Schreiber
28-06-2017, 22:49
Brian,
I don't want to push you - but if you can paste here your rendering code for the data plot, I will convert it for you to TBGL.
I am pretty sure you will find it very canvasish ;)
Not speaking of memory consumption. Let's presume your virtual canvas is 10 000 * 1 000. That means 10 000 000 pixels * 4 bytes per each = 40 MB in memory.
In TBGL it is all vector data + framebuffer.
Petr
Hi Petr
this is a very interesting subject, the subject of very wide graphics.
here is a wide plotting with a horizontal scroll bar, when the scroll bar reach the far right we can continue to scroll with right arrow keys if the canvas in focus.
Uses "UI"
Dim x,y As Double
Begin ControlID
%ID_Canvas
End ControlID
Function TBMain() As Long
Local hDlg As DWord '---Used to store window handle of main dialog
hDlg = Dialog_New Pixels, 0, "very wide graphics ", -1, -1, 1200, 775,
%WS_DLGFRAME |
%DS_CENTER |
%WS_CAPTION |
%WS_SYSMENU |
%WS_OVERLAPPEDWINDOW
Dialog Show Modal hDlg, Call cbDialog
End Function
CallBack Function cbDialog() As Long
Select Case CBMSG
Case %WM_INITDIALOG
Control Add Canvas, CBHNDL, %ID_Canvas, "", 50, 10,1000, 400, %WS_BORDER | %WS_CHILD | %WS_VISIBLE
Canvas_Attach(CBHNDL, %ID_Canvas, %FALSE)
Canvas_SetVirtual(100000, 380)
Canvas_SetView(0,0)
Canvas_Width(2)
Canvas_Clear %BLACK
Canvas_SetView(10000,0)
'Canvas_Scale(-20, -5, 20, 20)
For x = 0 To 20000 Step 0.1
y = Sin(x)*20* Rndf(1, 2)*Cos(x/3)^2
Canvas_Width(3)
Canvas_Line( (x*10, y +100), (x*10, y +100) , Rgb(255, 255, 0) )
Canvas_Redraw
Next
End Select
End Function
i see your TBGL example here http://www.thinbasic.com/community/showthread.php?9561-Plotting-Slowly&p=72282&viewfull=1#post72282 may be it is a candidate, not sure, seems even we can move the Form with the mouse while plotting continue as if it is not affected, Eros may add this example to the official examples. but how we scroll to the right and allow continuous viewing of the heart pulses until 100000 on x. also is it possible with the same animated feature like in the hospital .
i never thought before about wide canvas, so thanks for EmbeddedMan for casting light on this issue.
Petr Schreiber
29-06-2017, 23:00
Hi,
I prepared a code skeleton for you, Brian.
It allows you to render any 2D function, move over it and zoom in/out.
To change what is drawn, just edit buildGraphicsAs function.
uses "UI", "TBGL"
begin const
%MAIN_WIDTH = 640 ' -- Default dialog size
%MAIN_HEIGHT = 480
%timeOut = 20 ' -- Determines graphics refresh rate in milliseconds
%myCoolChart = 1 ' -- "Nickname" for geometry cache
end const
' -- ID numbers of controls
begin controlId
%lCanvas
%bZoomIn, %bZoomOut, %bClose
%hScroll, %vScroll
%myTimer
end controlId
type GraphicView
private
position as tbgl_tVector3f
cachedGraphics as long
minDistance as single
maxDistance as single
public
function _Create()
me.minDistance = 1
me.maxDistance = 140
end function
' Camera controls
function ZoomIn(zoomStep as single)
me.position.z -= zoomStep
if me.position.z < me.minDistance then me.position.z = me.minDistance
end function
function ZoomOut(zoomStep as single)
me.position.z += zoomStep
if me.position.z > me.maxDistance then me.position.z = me.maxDistance
end function
function SetZoom(z as single)
z = minmax(z, me.minDistance, me.maxDistance)
me.position.z = z
end function
function SetPosition(x as single, y as single)
me.position.x = x
me.position.y = y
end function
' Rendering controls
function SetGraphics(cachedGraphics as long)
me.cachedGraphics = cachedGraphics
end function
function UpdateScreen()
tbgl_clearFrame
tbgl_camera me.position.x, me.position.y, me.position.z, me.position.x, me.position.y, 0
tbgl_pushStateProtect %TBGL_DEPTH ' -- Disable depth tests, make draw order matter
tbgl_callList me.cachedGraphics
tbgl_popStateProtect
tbgl_drawFrame
end function
end type
dim graphView as GraphicView()
function tbMain()
dWord hDlg
dialog new pixels, 0, "Function plotting in TBGL",-1,-1, %MAIN_WIDTH, %MAIN_HEIGHT, %WS_POPUP | %WS_VISIBLE | %WS_CLIPCHILDREN | %WS_CAPTION | %WS_SYSMENU | %WS_MINIMIZEBOX | %WS_MAXIMIZEBOX | %WS_THICKFRAME To hDlg
control add Label, hDlg, %lCanvas, "", 5, 5, %MAIN_WIDTH-20, %MAIN_HEIGHT-60
control set color hDlg, %lCanvas, %BLACK, %BLACK
control set resize hDlg, %lCanvas, 1, 1, 1, 1
control add scrollbar hDlg, %hScroll, "", 5, 5+%MAIN_HEIGHT-60, %MAIN_WIDTH-20, 15, %SBS_HORZ
scrollbar_setrange(hDlg, %hScroll, -10000, 10000)
scrollbar_setpos(hDlg, %hScroll, 0)
control set resize hDlg, %hScroll, 1, 1, 0, 1
control add scrollbar hDlg, %vScroll, "", %MAIN_WIDTH-15, 5, 15, %MAIN_HEIGHT-60, %SBS_vert
scrollbar_setrange(hDlg, %vScroll, -10000, 10000)
scrollbar_setpos(hDlg, %vScroll, 0)
control set resize hDlg, %vScroll, 0, 1, 1, 1
control add button, hDlg, %bZoomIn, "Zoom in", 5, %MAIN_HEIGHT-30, 100, 25
control set resize hDlg, %bZoomIn, 1, 0, 0, 1
control add button, hDlg, %bZoomOut, "Zoom out", 105, %MAIN_HEIGHT-30, 100, 25
control set resize hDlg, %bZoomOut, 1, 0, 0, 1
control add button, hDlg, %bClose, "Close", %MAIN_WIDTH-105, %MAIN_HEIGHT-30, 100, 25
control set resize hDlg, %bClose, 0, 1, 0, 1
dialog set minsize hDlg, 320, 230
dialog show modal hDlg, call dlgCallback
end function
callback function dlgCallback()
static myCanvas as dword
static positionX, positionY as single
select case callback_message
case %WM_INITDIALOG
dialog set timer callback_handle, %myTimer, %timeOut, %NULL
control handle cbhndl, %lCanvas to myCanvas
tbgl_bindCanvas(myCanvas)
buildGraphicsAs %myCoolChart
graphView.setGraphics(%myCoolChart)
graphView.setZoom(25)
case %WM_SIZE, %WM_SIZING
tbgl_updateCanvasProportions(myCanvas)
graphView.setPosition(positionX, positionY)
if tbgl_canvasBound(myCanvas) then
graphView.UpdateScreen()
end if
case %WM_HSCROLL
positionX = HandleScrollBarEvents(cbhndl, %hScroll, LoWrd(cbwParam))
case %WM_vSCROLL
positionY = -HandleScrollBarEvents(cbhndl, %vScroll, LoWrd(cbwParam))
case %WM_TIMER
graphView.setPosition(positionX, positionY)
if tbgl_canvasBound(myCanvas) then
graphView.UpdateScreen()
end if
case %WM_CLOSE
tbgl_releaseCanvas(myCanvas)
dialog kill timer callback_handle, %myTimer
case %WM_COMMAND
select case callback_control
case %bClose : if callback_control_message = %BN_CLICKED then dialog end callback_handle
case %bZoomIn : if callback_control_message = %BN_CLICKED then graphView.zoomIn(1)
case %bZoomOut : if callback_control_message = %BN_CLICKED then graphView.zoomOut(1)
end select
end select
end function
' -- Build the graphics in this function
function buildGraphicsAs(listSlot as long)
single i
' Everything between newList/endList will get stored under listSlot
tbgl_newList listSlot
' Grid, built line by line
for i = -10000 to 10000
tbgl_line i, -10000, i, 10000
tbgl_line -10000, i, 10000, i
next
' Main axes in yellow
tbgl_pushColor 255, 255, 0
tbgl_pushLineWidth 3
tbgl_line -10000, 0, 10000, 0
tbgl_line 0, -10000, 0, 10000
tbgl_popLineWidth
tbgl_popColor
' Some function to draw
tbgl_pushColor 255, 0, 0
tbgl_pushPointSize 3
for i = -10000 to 10000 step 0.1
tbgl_point(i, sin(i/10)*2)
next
tbgl_popPointSize
tbgl_popColor
tbgl_endList
end function
' -- Helper function for scroll bar events
function HandleScrollBarEvents(hDlg as dword, scrollbarId as long, operation as dword) as long
long position
select case operation
case %SB_TOP
position = scrollBar_getRangeLow(hDlg, scrollbarId)
scrollBar_setPos(hDlg, scrollbarId, position)
case %SB_BOTTOM
position = scrollBar_getRangehi(hDlg, scrollbarId)
scrollBar_setPos(hDlg, scrollbarId, position)
case %SB_LINEUP
position = scrollBar_getpos(hDlg, scrollbarId) - 1
scrollBar_setPos(hDlg, scrollbarId, position)
case %SB_LINEDOWN
position = scrollBar_getpos(hDlg, scrollbarId) + 1
scrollBar_setPos(hDlg, scrollbarId, position)
case %SB_PAGEUP
position = scrollBar_getpos(hDlg, scrollbarId) - scrollBar_getPageSize(hDlg, scrollbarId)
scrollBar_setPos(hDlg, scrollbarId, position)
case %SB_PAGEDOWN
position = scrollBar_getpos(hDlg, scrollbarId) + scrollBar_getPageSize(hDlg, scrollbarId)
scrollBar_setPos(hDlg, scrollbarId, position)
case %SB_THUMBTRACK
position = scrollBar_getTrackPos(hDlg, scrollbarId)
scrollBar_setPos(hDlg, scrollbarId, position)
end select
return scrollbar_getpos(hDlg, scrollbarId)
end function
Petr
Thanks Petr , as always the example is full of hints, tips and tricks, and all in One example.
i see you have used Lists to capture and build the data list. which is suitable for plotting the data
but i don't understand the TBGL_PushStateProtect and its sister TBGL_PopStateProtect
Petr Schreiber
30-06-2017, 19:44
Hi Primo,
PushStateProtect and PopStateProtect are functions to protect piece of graphic code from being affected by specified TBGL state.
By default, when you draw graphics primitives, TBGL uses depth testing. That allows you to draw primitives in any order and they will be sorted correctly.
However.
For edge cases, such as 2D graphics, which overlay one over each other, this can be an issue - depending on implementation and moon phase, artifacts could pop up.
That is why I recommend to disable depth testing in order to be able to paint like painter, one thing after another, in order dependent way.
Here is example to demonstrate the issue in obvious way:
uses "TBGL"
function tbMain()
double FrameRate
' -- Create and show window
dWord hWnd = tbgl_createWindowEx("Depth testing artifacts - press ESC to quit", 640, 240, 32, %tbgl_WS_WINDOWED | %tbgl_WS_CLOSEBOX)
tbgl_showWindow
' -- Resets status of all keys
tbgl_resetKeyState()
single angle
' -- Main loop
while tbgl_IsWindow(hWnd)
FrameRate = tbgl_getFrameRate
angle += 45/FrameRate
tbgl_clearFrame
tbgl_camera(0, 0, 5, 0, 0, 0)
tbgl_pushMatrix
tbgl_translate -2, 0, 0
tbgl_rotate angle, 0, 1, 0
tbgl_color 255, 255, 0
tbgl_rect(-1, -1, 1, 1)
tbgl_color 255, 0, 0
tbgl_ngon(0, 0, 1, 180)
tbgl_popMatrix
tbgl_pushStateProtect %TBGL_DEPTH
tbgl_pushMatrix
tbgl_translate 2, 0, 0
tbgl_rotate -angle, 0, 1, 0
tbgl_color 255, 255, 0
tbgl_rect(-1, -1, 1, 1)
tbgl_color 255, 0, 0
tbgl_ngon(0, 0, 1, 180)
tbgl_popMatrix
tbgl_popStateProtect
tbgl_drawFrame
' -- ESCAPE key to exit application
if tbgl_getWindowKeyState(hWnd, %VK_ESCAPE) then exit while
wend
tbgl_destroyWindow
end function
Petr