Another graph drawing using vector library

Share your advanced PureBasic knowledge/code with the community.
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: Another graph drawing using vector library

Post by Sicro »

Sorry for the offtopic, but:
How can the first post have a later date than the second post? Mysterious.

Thank you for updating. I will add in shorttime the code to the CodeArchiv.
Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Another graph drawing using vector library

Post by Lunasole »

Updated 1st post to a newer version (where simple mouse interactions added).

I'd like to make completely standalone thing from that all... but well that still doesn't looks "justified" as it's not used so often ^^
So nothing to do, code needs to be slightly customized every time when used

// also hope that bug with canvas SetGadgetAttribute() on Linux fixed yet, if not -- see @Sicro fix
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
AZJIO
Addict
Addict
Posts: 1319
Joined: Sun May 14, 2017 1:48 am

Re: Another graph drawing using vector library

Post by AZJIO »

I am trying to make multiple graphs on the same field. You can set the resolution of the graph, that is, the number of points per wave (Step 10). A straight line can be specified with two points.

Image

Code: Select all

EnableExplicit


Global.d cX0, cY0
Global.d mX, mY
Global xMax2, yMax2

;{ Simple Graph }

; Еще одна штука для простых "визуальных эффектов"
;   2017         (c) Luna Sole
;    v1.0.0.4       (+ взаимодействие с мышью)         

; Рисует график с двумя линиями на заданном изображении с использованием векторной библиотеки PB
; hImgOut            Изображение PB для рисования может быть любого размера [кроме, возможно, «очень низкого» разрешения ^^]
; xMax, xMin                  максимальная и максимальная величина X графика
; yMax                  максимальная величина Y графика
; GridStepX            Шаг сетки X [вертикальные линии], измеренное в количестве GraphData (). используйте 0 для отключения
; GridStepY            Шаг сетки Y [горизонтальные линии], измеренное в значениях GraphData (). 0 для отключения
; FontSize            размер шрифта текстовых меток. используйте 0, чтобы отключить метки
; ColorGrid            цвета для элементов графика (RGB)
; RETURN:            нет, изображение изменено в случае успеха
Procedure DrawGrid(hImgOut, xMax, xMin, yMax, GridStepX = 10, GridStepY = 10, FontSize = 9, ColorGrid = $BBFFFFFF)
   Protected maxValues ; разница между xMax - xMin
   Protected t ; переменная цикла для перечисления во времени, по оси Y
   If yMax < 1
      ProcedureReturn   ; выйти, если данные из одной точки, график должен быть из нескольких точек по оси Y
   EndIf
   yMax2 = yMax   ; задаём внешний, чтобы перечислять в цикле
   
   ; сделать вещи, чтобы лучше подогнать фоновую сетку
   If GridStepY > 0
      If xMax >= 0
         xMax + GridStepY - xMax % GridStepY
      ElseIf xMax
         xMax - xMax % GridStepY
      EndIf
      If xMin > 0
         xMin  - xMin  % GridStepY
      ElseIf xMin < 0
         xMin  - (GridStepY + xMin  % GridStepY)
      EndIf
   EndIf
   maxValues = xMax - xMin
   If maxValues <= 0
      maxValues = 1
   EndIf
   
   ; минимум значений оси Х
   xMax2 = xMax
   
   ; загрузить шрифт для текстовых меток
   Protected Font
   If FontSize > 0
      Font = LoadFont(#PB_Any, "arial", FontSize)
      If Not IsFont(Font) ; и так далее
         Font = LoadFont(#PB_Any, "tahoma", FontSize)
         If Not IsFont(Font) ; и так далее.. :)
            Font = LoadFont(#PB_Any, "consolas", FontSize)
         EndIf
      EndIf
   EndIf
   
   ; рисовать данные в изображение
   If StartVectorDrawing(ImageVectorOutput(hImgOut, #PB_Unit_Pixel))
      Protected.d oX = 1.0, oY = oX
      Protected.d mtW = 1.0, mtH = mtW
      ;   временные переменные, используемые при рисовании
      Protected.d cX, cY
      Protected.d tLast
      ; [n] - определить смещения графиков / размеры текстовых меток и т. д.
      If IsFont(Font)
         VectorFont(FontID(Font), FontSize)
         If VectorTextWidth(Str(xMax)) > VectorTextWidth(Str(xMin)) ; задаём ширину текста
            oX = VectorTextWidth(Str(xMax)) + 2.0
         Else
            oX = VectorTextWidth(Str(xMin)) + 2.0
         EndIf
         oY = VectorTextHeight("0A") + 2.0
         If oX > oY
            oY = oX
         Else
            oX = oY
         EndIf
         mtW = VectorTextWidth(Str(yMax)) * 1.2
         mtH = VectorTextHeight(Str(xMax)) * 0.8
      EndIf
      ;    множители для масштабирования координат графика
      mX = (VectorOutputWidth() - oX * 2.0) / (yMax + Bool(yMax = 0))   
      mY = (VectorOutputHeight() - oY * 2.0) / maxValues
      
      ; [0] - рисовать текстовые метки и линии сетки
      VectorSourceColor(ColorGrid) ; цвет меток и сетки шкалы
                            ;   горизонтальные линии / метки
      tLast = oY + maxValues * mY + 5.0
      If GridStepY > 0
         For t = maxValues To 0 Step -1
            If t % GridStepY = 0 Or t = maxValues
               cY = oY + t * mY
               ; нарисовать текстовую метку
               If IsFont(Font) And cY < tLast
                  MovePathCursor(oX - (2.0 + VectorTextWidth(Str(xMax - t))), cY - VectorTextHeight(Str(xMax - t)) / 2)
                  DrawVectorText(Str(xMax - t))
                  tLast = cY - mtH
               EndIf
               ; нарисовать линию сетки
               MovePathCursor(oX, oY + mY * t)           
               AddPathLine(oX + yMax * mX, oY + mY * t)
            EndIf
         Next
      EndIf
      ;   вертикальные линии / метки
      tLast = 0.0
      If GridStepX > 0   
         ;GridStepX + 1
         For t = 0 To yMax
            If t % GridStepX = 0 Or t = yMax
               cX = oX + t * mX
               cY = oY + maxValues * mY
               ; нарисовать текстовую метку
               If IsFont(Font) And cX > tLast
                  MovePathCursor(cX - VectorTextWidth(Str(t)) / 2, cY + 2.0)
                  DrawVectorText(Str(t))
                  tLast = cX + mtW
               EndIf
               ; нарисовать линию сетки
               MovePathCursor(cX, oY)
               AddPathLine(cX, cY)
            EndIf
         Next
      EndIf
      ;   fin
      If GridStepX > 0 Or GridStepY > 0
         DashPath(1.0, 3.0)
      EndIf
      cX0 = oX
      cY0 = oY
      
      ;    StrokePath(LineWidth)
      
      ; очистить
      StopVectorDrawing()
   EndIf
   
   ; очистить
   If IsFont(Font)
      FreeFont(Font)
   EndIf
EndProcedure

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Тест / пример
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; используется для обработки кликов мыши по графику
; mapkey - координата X изображения графика, value - соответствующий индекс в массиве GraphData()
Global NewMap GraphGeodata()

; Размеры графика
Global W = 800, H = 600
; Изображение для рисования графика
Global tImg
; Окно и холст для отображения графика
Global tWindow, tCanvas

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; сгенерировать графические данные
; 127 определяет число точек по оси Y

; создать изображение для получения вывода
tImg = CreateImage(#PB_Any, W, H, 32, $1B1B1B) ; цвет фона тут
DrawGrid(tImg, 60, -60, 127, 10, 10, 12)
; нарисовать график на созданном изображении
; Debug mX ; = 5.9
; Debug mY ; = 4
; Debug cX0 ; = 19.34375
; Debug cY0 ; = 19.34375


Define.d tmp, LineWidth = 1
Define t, j
Global Plot_Dot.b = 0
; Color            цвет линии графика (RGB)
; LineWidth     ширина линии (в пикселях)
; Plot_Dot      показывать ли точки на графике

Procedure DrawGraph(tmp.d, t)
   ;   временные переменные, используемые при рисовании
   Protected.d cX, cY
   cX = cX0 + mX * t
   cY = cY0 + mY * (xMax2 - tmp)
   If t = 0
      MovePathCursor(cX0, cY)
   EndIf
   AddPathLine(cX, cY)         ; добавить линию
   If Plot_Dot
      AddPathCircle(cX, cY, 2.0)   ; добавить точку
   EndIf
   MovePathCursor(cX, cY)      ; восстановить позицию курсора
EndProcedure


If StartVectorDrawing(ImageVectorOutput(tImg, #PB_Unit_Pixel)) ; открываем рисование
   
   ; рисуем синусоиду (выпрямленный ток) жёлтая
   VectorSourceColor($FF00B1CB) ; задаём цвет линии (с добавлением альфа-канала слева ARGB)
   j = 45
   For t = 0 To yMax2
      tmp = 60 * Abs(Sin(Radian(j-90)))
      j+5
      DrawGraph(tmp, t)
   Next
   StrokePath(LineWidth) ; рисует график в заданном цвете
   
   
   ; рисуем поверх косинусоиду
   VectorSourceColor($FF80A800)
   j = 0
   For t = 0 To yMax2
      tmp = 60 * Cos(Radian(j-90))
      j+5
      DrawGraph(tmp, t)
   Next
   StrokePath(LineWidth)
   
   ; рисуем поверх синусоиду
   VectorSourceColor($FF9900FF) ; $00A800
   j=0
   For t = 0 To yMax2
      tmp = - 60 * Sin(Radian(j-90))
      j+5
      DrawGraph(tmp, t)
   Next
   StrokePath(LineWidth)
   
;    Plot_Dot = 1
   ; рисуем экпоненту
   VectorSourceColor($FF2A04FF)
   For t = 0 To yMax2 ; Step 6
      ;    tmp = t * 0.8 - 60 ; линия наклонная
      tmp = 60 * Exp(- t / 24) ; экпонента
      DrawGraph(tmp, t)
   Next
   StrokePath(LineWidth)

   ; рисуем линию
   VectorSourceColor($FF00A800)
   DrawGraph(- 60, 0) ; начало
   DrawGraph(127 * 0.8 - 60, 127) ; и конец линии
;    For t = 0 To yMax2 Step 127
;       tmp = t * 0.8 - 60 ; линия наклонная
;       DrawGraph(tmp, t)
;    Next
   StrokePath(LineWidth)
   
   ; рисуем треугольную
   VectorSourceColor($FFFF8C00)
   For t = 0 To yMax2
      tmp = 20 * (t/10 - 2 * Round((t/10 + 1) / 2, #PB_Round_Down)) * Pow(-1, Round((t/10 + 1) / 2, #PB_Round_Down)) - 40 ; Треугольный
      DrawGraph(tmp, t)
   Next
   StrokePath(LineWidth)
   
   
   StopVectorDrawing()
EndIf


; показать окно с графиком
tWindow = OpenWindow(#PB_Any, 0, 0, W, H, "График", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

; использовал ImageGadget вместо CanvasGadget, так заработало на Linux
CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
		tCanvas = CanvasGadget(#PB_Any, 0, 0, W, H)
		SetGadgetAttribute(tCanvas, #PB_Canvas_Image, ImageID(tImg))
    CompilerCase #PB_OS_Linux
		ImageGadget(#PB_Any, 0, 0, W, H, ImageID(tImg))
CompilerEndSelect

; освободить изображение
FreeImage(tImg)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Added to work in Linux
Last edited by AZJIO on Mon Jan 18, 2021 1:32 pm, edited 1 time in total.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Another graph drawing using vector library

Post by Kwai chang caine »

Very nice
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
Post Reply