Что нового

Как ускорить построение графика?

Rem

Новичок
Сообщения
9
Репутация
1
Добрый день!

На основе GraphGDIPlus.au3 из массива построен некий график (например, синусоиды):

Код:
#include "GraphGDIPlus.au3"

$GUI = GUICreate("График",650,340)
Dim $arrGraph[10000][2]

For $i = 0 To UBound($arrGraph) - 1
    $arrGraph[$i][0] = $i
    $arrGraph[$i][1] = 600 * Sin($arrGraph[$i][0] / 200)
Next

$Graph = _GraphGDIPlus_Create($GUI,45,10,550,250,0xFF000000,0xFFFFFFFF)
_ViewGraph()

GUISetState ()

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = -3
            Exit
    EndSelect
WEnd

Func _ViewGraph()

Local $Ymin, $Ymax, $Ymin1, $Ymax1, $ShagY
    For $i = 1 To UBound($arrGraph) - 1
        If $arrGraph[$i][1] < $Ymin Then
            $Ymin = $arrGraph[$i][1]
        Else
            If $arrGraph[$i][1] > $Ymax Then
                $Ymax = $arrGraph[$i][1]
            EndIf
        EndIf
    Next
	

$Ymin1=$Ymin-100 ; отступы от min/max
$Ymax1=$Ymax+100
$ShagY=($Ymax1-$Ymin1)/10 ; шаг шкалы Y

;----- шкала по оси XY
_GraphGDIPlus_Set_RangeX($Graph,0,UBound($arrGraph),10,1,0)
_GraphGDIPlus_Set_RangeY($Graph,$Ymin1,$Ymax1,10,1)
;----- сетка по оси XY
_GraphGDIPlus_Set_GridX($Graph,UBound($arrGraph)/10,0xFF000000)
_GraphGDIPlus_Set_GridY($Graph,$ShagY,0xFF000000)
_GraphGDIPlus_Set_PenSize($Graph,2) ; тольщина линии графика
_Draw_Graph(0xFF339966) ; цвет графика
_GraphGDIPlus_Refresh($Graph)
EndFunc

Func _Draw_Graph($ColorGr)
    _GraphGDIPlus_Set_PenColor($Graph,$ColorGr)
	For $i = 0 To UBound($arrGraph) - 1
        _GraphGDIPlus_Plot_Line($Graph,$i,$arrGraph[$i][1])
    Next
EndFunc

Скорость обработки и вывода графика не выдерживает ни какой критики.
Пытался прикрутить к нему структуру и Bitmap, да руки коротки... Бьюсь уже несколько дней. ничего не выходит.
Помогите, пожалуйста, разобраться с этой темой и таки построить суперскоростной болид.
 

Mr. Anderson

Новичок
Сообщения
122
Репутация
4
Может лучше построение графиков во флеш использовать, составить html с флешем и отобразить его в окне как IE?
 

dwerf

Использует ArchLinux
Сообщения
478
Репутация
219
Зачем для графика шириной в 550 пикселей 10000 значений y?
Код:
#include "GraphGDIPlus.au3"

$GUI = GUICreate("График",650,340)
Dim $arrGraph[550][2]

For $i = 0 To UBound($arrGraph) - 1
    $arrGraph[$i][0] = $i
    $arrGraph[$i][1] = 600 * Sin($arrGraph[$i][0] / 11)
Next

$Graph = _GraphGDIPlus_Create($GUI,45,10,550,250,0xFF000000,0xFFFFFFFF)
_ViewGraph()

GUISetState ()

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = -3
            Exit
    EndSelect
WEnd

Func _ViewGraph()

Local $Ymin, $Ymax, $Ymin1, $Ymax1, $ShagY
    For $i = 1 To UBound($arrGraph) - 1
        If $arrGraph[$i][1] < $Ymin Then
            $Ymin = $arrGraph[$i][1]
        Else
            If $arrGraph[$i][1] > $Ymax Then
                $Ymax = $arrGraph[$i][1]
            EndIf
        EndIf
    Next


$Ymin1=$Ymin-100 ; отступы от min/max
$Ymax1=$Ymax+100
$ShagY=($Ymax1-$Ymin1)/10 ; шаг шкалы Y

;----- шкала по оси XY
_GraphGDIPlus_Set_RangeX($Graph,0,UBound($arrGraph),10,1,0)
_GraphGDIPlus_Set_RangeY($Graph,$Ymin1,$Ymax1,10,1)
;----- сетка по оси XY
_GraphGDIPlus_Set_GridX($Graph,UBound($arrGraph)/10,0xFF000000)
_GraphGDIPlus_Set_GridY($Graph,$ShagY,0xFF000000)
_GraphGDIPlus_Set_PenSize($Graph,2) ; тольщина линии графика
_Draw_Graph(0xFF339966) ; цвет графика
_GraphGDIPlus_Refresh($Graph)
EndFunc

Func _Draw_Graph($ColorGr)
    _GraphGDIPlus_Set_PenColor($Graph,$ColorGr)
	For $i = 0 To UBound($arrGraph) - 1
        _GraphGDIPlus_Plot_Line($Graph,$i,$arrGraph[$i][1])
    Next
EndFunc
 
Автор
R

Rem

Новичок
Сообщения
9
Репутация
1
dwerf сказал(а):
Зачем для графика шириной в 550 пикселей 10000 значений y?

Значения взяты как пример малой скорости работы. Если программа работает и выводит примерно такой, что в примере график, плюс там ведутся определенные расчеты, то это приводит к уменьшению скорости работы всей программы.
К примеру, обработка 10 млн. итераций (с расчетами) без этого графика занимает примерно 1 минуту, но для потребителя программы ОБЯЗАТЕЛЬНО нужно видеть КАК ведется расчет, т.е. нужна визуализация, которая осуществляется через график. С выводом графика уже 9 минут уходит на весь процесс. Если расчеты более сложные, и итераций больше, то потребитель просто не сможет часами ждать результат.
 

dwerf

Использует ArchLinux
Сообщения
478
Репутация
219
Окно с графиком имеет определённую ширину. Учитывая разрешения современных экранов она вряд ли будет привышать 5000 пикселей. Больше значений в окно запихнуть не получится.

Имхо логично запихивать не все значения, а какие то средние значения из частей графика, лишь бы картинка была похожа.

А вообще AutoIt довольно медленен сам по себе. Если сильно нужны быстрые вычисления то лучше использовать чтото другое.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Автор
R

Rem

Новичок
Сообщения
9
Репутация
1
Yashied сказал(а):

К сожалению, в этом примере нет ни шкалы по осям XY, ни сетки, ось Y не статична ... не ясно с настройками окна диаграммы (601х601)...

Вобщем нужен полноценный график с возможностями регулировки (хотя бы такой как я приводил вначале темы), но со скоростью, как в примере уважаемого Yashied.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Rem, во-первых, хорошо бы приводить ссылку на этот чертов GraphGDIPlus UDF, а во-вторых, просто закомментируй следующую строчку в этом UDF:

Код:
; #FUNCTION# =============================================================================
; Name...........: _GraphGDIPlus_Plot_Line
; Description ...: draws straight line to x,y from previous point / starting point
; Syntax.........: _GraphGDIPlus_Plot_Line(ByRef $aGraphArray,$iX,$iY)
; Parameters ....:   $aGraphArray - the array returned from _GraphGDIPlus_Create
;                    $iX - x value to draw to
;                    $iY - y value to draw to
; ========================================================================================
Func _GraphGDIPlus_Plot_Line(ByRef $aGraphArray, $iX, $iY)
	If IsArray($aGraphArray) = 0 Then Return
	;----- Draw line from previous point to new point -----
	$iX = _GraphGDIPlus_Reference_Pixel("x", $iX, $aGraphArray[6], $aGraphArray[7], $aGraphArray[4])
	$iY = _GraphGDIPlus_Reference_Pixel("y", $iY, $aGraphArray[8], $aGraphArray[9], $aGraphArray[5])
	_GDIPlus_GraphicsDrawLine($aGraphArray[17], $aGraphArray[18], $aGraphArray[19], $iX, $iY, $aGraphArray[20])
;	_GraphGDIPlus_RedrawRect($aGraphArray) ; <= ЗДЕСЬ!
	;----- save current as last coords -----
	$aGraphArray[18] = $iX
	$aGraphArray[19] = $iY
EndFunc   ;==>_GraphGDIPlus_Plot_Line


И будет намного быстрее...

P.S

А что бы совсем все было хорошо, не нужно делать лишних вычислений. Определи для начала минимально необходимый шаг по оси X для заданного масштаба. Т.е. такой шаг, при котором DX будет соответствовать 1 (одному!) пикселу. Далее с этим шагом и рисуй график.
 
Автор
R

Rem

Новичок
Сообщения
9
Репутация
1
Итак, обобщу здесь все примеры и советы, а также собственные наработки по скорости построения графика.
Путем сравнительного анализа выяснилось, что использование структуры как массива данных чрезвычайно тормозит построение графика.... но обо всем по порядку:

Последнее четвертое место по скорости занимает использование DllStruct... - 3 сек.:

Код:
#include "GraphGDIPlusPlus.au3" 
$GUI = GUICreate("График",650,340)

Global $N = 1000
Global $str = "int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int;int"
Global $a = DllStructCreate($str)
if @error Then
    MsgBox(0,"","Error in DllStructCreate " & @error)
    exit
endif

For $i = 1 To $N
    DllStructSetData($a,$i,60*Sin($i/12)) 
Next

$Graph = _GraphGDIPlus_Create($GUI,45,10,550,250,0xFF000000,0xFFFFFFFF)

_ViewGraph()

GUISetState ()

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = -3
            Exit
    EndSelect
WEnd

Func _ViewGraph()

;----- шкала по оси XY
_GraphGDIPlus_Set_RangeX($Graph,0,$N,10,1,0)
_GraphGDIPlus_Set_RangeY($Graph,-80,80,8,1)
;----- сетка по оси XY
_GraphGDIPlus_Set_GridX($Graph,$N/10,0xFF000000)
_GraphGDIPlus_Set_GridY($Graph,20,0xFF000000)
_GraphGDIPlus_Set_PenSize($Graph,2) ; тольщина линии графика
_Draw_Graph(0xFF339966) ; цвет графика
_GraphGDIPlus_Refresh($Graph)
EndFunc

Func _Draw_Graph($ColorGr)
    _GraphGDIPlus_Set_PenColor($Graph,$ColorGr)
	For $i = -1 To $N
        _GraphGDIPlus_Plot_Line($Graph,$i,DllStructGetData($a,$i))
    Next
$a=0
EndFunc

Как видите, я так и не нашел, как покороче обозначить переменную $str. Если знаете как, пожалуйста, подскажите. Да и вообще - внимательно выслушаю критику и советы по использованию структур.

На третье место по скорости выбился изначальный код с GraphGDIPlus.au3 - 0,6 сек. Его я немного изменил для сравнительной характеристики, но суть та же:

Код:
#include "GraphGDIPlus.au3" 

$GUI = GUICreate("График",650,340)

Dim $arrGraph[1000][2]
For $i = 0 To UBound($arrGraph) - 1
    $arrGraph[$i][0] = $i
    $arrGraph[$i][1] = 60 * Sin($arrGraph[$i][0]/12)
Next

$Graph = _GraphGDIPlus_Create($GUI,45,10,550,250,0xFF000000,0xFFFFFFFF)

_ViewGraph()

GUISetState ()

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = -3
            Exit
    EndSelect
WEnd

Func _ViewGraph()

Local $Ymin, $Ymax, $Ymin1, $Ymax1, $ShagY
    For $i = 1 To UBound($arrGraph) - 1
        If $arrGraph[$i][1] < $Ymin Then
            $Ymin = $arrGraph[$i][1]
        Else
            If $arrGraph[$i][1] > $Ymax Then
                $Ymax = $arrGraph[$i][1]
            EndIf
        EndIf
    Next
	

$Ymin1=$Ymin-10 ; отступы от min/max
$Ymax1=$Ymax+10
$ShagY=($Ymax1-$Ymin1)/10 ; шаг шкалы Y

;----- шкала по оси XY
_GraphGDIPlus_Set_RangeX($Graph,0,UBound($arrGraph),10,1,0)
_GraphGDIPlus_Set_RangeY($Graph,$Ymin1,$Ymax1,10,1)
;----- сетка по оси XY
_GraphGDIPlus_Set_GridX($Graph,UBound($arrGraph)/10,0xFF000000)
_GraphGDIPlus_Set_GridY($Graph,$ShagY,0xFF000000)
_GraphGDIPlus_Set_PenSize($Graph,2) ; тольщина линии графика
_Draw_Graph(0xFF339966) ; цвет графика
_GraphGDIPlus_Refresh($Graph)
EndFunc

Func _Draw_Graph($ColorGr)
    _GraphGDIPlus_Set_PenColor($Graph,$ColorGr)
	For $i = 0 To UBound($arrGraph) - 1
        _GraphGDIPlus_Plot_Line($Graph,$i,$arrGraph[$i][1])
    Next
EndFunc

Почетное второе место занимает модификация UDF GraphGDIPlus.au3 - 0,31 сек., сделанная по совету Yashied. Спасибо - оказалось все очень просто и вместе с тем суперэффективно.

GraphGDIPlusPlus.au3 - см. во вложении.

Код:
#include "GraphGDIPlusPlus.au3"

$GUI = GUICreate("График",650,340)
Dim $arrGraph[1000][2]

For $i = 0 To UBound($arrGraph) - 1
    $arrGraph[$i][0] = $i
    $arrGraph[$i][1] = 60 * Sin($arrGraph[$i][0] / 12)
Next

$Graph = _GraphGDIPlus_Create($GUI,45,10,550,250,0xFF000000,0xFFFFFFFF)

_ViewGraph()

GUISetState ()

While 1
    $msg = GUIGetMsg()
    Select
        Case $msg = -3
            Exit
    EndSelect
WEnd

Func _ViewGraph()

Local $Ymin, $Ymax, $Ymin1, $Ymax1, $ShagY
    For $i = 1 To UBound($arrGraph) - 1
        If $arrGraph[$i][1] < $Ymin Then
            $Ymin = $arrGraph[$i][1]
        Else
            If $arrGraph[$i][1] > $Ymax Then
                $Ymax = $arrGraph[$i][1]
            EndIf
        EndIf
    Next
	

$Ymin1=$Ymin-10 ; отступы от min/max
$Ymax1=$Ymax+10
$ShagY=($Ymax1-$Ymin1)/10 ; шаг шкалы Y

;----- шкала по оси XY
_GraphGDIPlus_Set_RangeX($Graph,0,UBound($arrGraph),10,1,0)
_GraphGDIPlus_Set_RangeY($Graph,$Ymin1,$Ymax1,10,1)
;----- сетка по оси XY
_GraphGDIPlus_Set_GridX($Graph,UBound($arrGraph)/10,0xFF000000)
_GraphGDIPlus_Set_GridY($Graph,$ShagY,0xFF000000)
_GraphGDIPlus_Set_PenSize($Graph,2) ; тольщина линии графика
_Draw_Graph(0xFF339966) ; цвет графика
_GraphGDIPlus_Refresh($Graph)
EndFunc

Func _Draw_Graph($ColorGr)
    _GraphGDIPlus_Set_PenColor($Graph,$ColorGr)
	For $i = 0 To UBound($arrGraph) - 1
        _GraphGDIPlus_Plot_Line($Graph,$i,$arrGraph[$i][1])
    Next
EndFunc

Ну и первое место занимает пример Yashied из этой темы: http://autoit-script.ru/index.php/topic,1043.0.html. Замер скорости показал - 0,18 сек. на моем ПК.
Для сравнительной характеристики и замера времени я с заочного позволения автора заменил пару цифр:
Код:
#Include <GDIPlus.au3>
#Include <GUIConstantsEx.au3>
#Include <Math.au3>
#Include <WinAPI.au3>

Opt('MustDeclareVars', 1)

Dim $aPoints[1000][2]

For $i = 0 To UBound($aPoints) - 1
    $aPoints[$i][0] = $i ;($i - 150) / 1.7
    $aPoints[$i][1] = 60 * Sin($aPoints[$i][0] / 12); * Sin($aPoints[$i][0] / 2)
Next

_ViewGraph($aPoints)

Func _ViewGraph($aPoints)

    Local $hForm, $Pic, $hPic
    Local $Scale, $Xi, $Yi, $Xp, $Yp, $XOffset, $YOffset, $Xmin = $aPoints[0][0], $Ymin = $aPoints[0][1], $Xmax = $Xmin, $Ymax = $Ymin
    Local $hBitmap, $hObj, $hGraphic, $hImage, $hBrush, $hPen

    For $i = 1 To UBound($aPoints) - 1
        If $aPoints[$i][0] < $Xmin Then
            $Xmin = $aPoints[$i][0]
        Else
            If $aPoints[$i][0] > $Xmax Then
                $Xmax = $aPoints[$i][0]
            EndIf
        EndIf
        If $aPoints[$i][1] < $Ymin Then
            $Ymin = $aPoints[$i][1]
        Else
            If $aPoints[$i][1] > $Ymax Then
                $Ymax = $aPoints[$i][1]
            EndIf
        EndIf
    Next

    $Scale = 600 / _Max($Xmax - $Xmin, $Ymax - $Ymin)
    $XOffset = Floor(($Xmin + $Xmax) * $Scale / 2)
    $YOffset = Floor(($Ymin + $Ymax) * $Scale / 2)

    _GDIPlus_Startup()
    $hBitmap = _WinAPI_CreateBitmap(601, 601, 1, 32)
    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    _WinAPI_DeleteObject($hBitmap)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)
    $hBrush = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) ; цвет графика
    $hPen = _GDIPlus_PenCreate(0xFFFF0000) ; цвет осей
    _GDIPlus_GraphicsFillRect($hGraphic, 0, 0, 601, 601, $hBrush)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphic, 2)
    If Abs($XOffset) <= 300 Then
        _GDIPlus_GraphicsDrawLine($hGraphic, 300 - $XOffset, 0, 300 - $XOffset, 601, $hPen)
    EndIf
    If Abs($YOffset) <= 300 Then
        _GDIPlus_GraphicsDrawLine($hGraphic, 0, 300 + $YOffset, 601, 300 + $YOffset, $hPen)
    EndIf
    _GDIPlus_PenDispose($hPen)
    $hPen = _GDIPlus_PenCreate(0xFF000000)
    For $i = 0 To UBound($aPoints) - 1
        $Xi = 300 - $XOffset + $Scale * $aPoints[$i][0]
        $Yi = 300 + $YOffset - $Scale * $aPoints[$i][1]
        If $i Then
            _GDIPlus_GraphicsDrawLine($hGraphic, $Xp, $Yp, $Xi, $Yi, $hPen)
        EndIf
        $Xp = $Xi
        $Yp = $Yi
    Next
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_Shutdown()

    $hForm = GUICreate('My Graph', 601, 601)
    $Pic = GUICtrlCreatePic('', 0, 0, 601, 601)
    $hPic = GUICtrlGetHandle(-1)

    _WinAPI_DeleteObject(_SendMessage($hPic, 0x0172, 0, $hBitmap))
    $hObj = _SendMessage($hPic, 0x0173)
    If $hObj <> $hBitmap Then
        _WinAPI_DeleteObject($hBitmap)
    EndIf

    GUISetState(@SW_SHOW, $hForm)

    Do
    Until GUIGetMsg() = -3

    GUIDelete($hForm)

EndFunc   ;==>_ViewGraph

Однако, этот пример надо еще дорабатывать - делать сетку, устанавливать значения по осям XY, изменять положение осей и другое... Кто справиться с помощью _WinAPI_CreateBitmap сделает полноценный график, тому смело можно обращаться к господину Jonathan Bennett о зачислении его в штат :smile:
 

Luke

Знающий
Сообщения
64
Репутация
14
Вывод графика с помощью GraphGDIPlus UDF, даже с модификацией предложенной Yashied, замедляет работу скрипта в 4 раза. Нужно как то изменить эту UDF чтобы график создавался в опер.памяти и выводился на экран только по команде, возможно это ускорит работу.

Попробовал отрисовывать по этому методу:
А что бы совсем все было хорошо, не нужно делать лишних вычислений. Определи для начала минимально необходимый шаг по оси X для заданного масштаба. Т.е. такой шаг, при котором DX будет соответствовать 1 (одному!) пикселу. Далее с этим шагом и рисуй график.

В результате с графика пропадают все резкие выпады :(
 

Luke

Знающий
Сообщения
64
Репутация
14
Выше мы (надеюсь все) именно про эту UDF и говорили.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Luke [?]
В результате с графика пропадают все резкие выпады
не, подгонять вычислительный шаг под сетку не надо. надо рисовать лишь те точки из массива выходных данных, расстояние между которыми больше 1 пкс. подгон вычислений под визуализацию – это даже не моветон, это нонсенс :smile: а вот подгон визуализации под монитор работа на твердую четверку ;)
 

Luke

Знающий
Сообщения
64
Репутация
14
Kaster [?]
надо рисовать лишь те точки из массива выходных данных, расстояние между которыми больше 1 пкс.
Вот при такой формулировке и не получается. Пример: массив данных больше 1 млн, на 1 пкс по x приходится больше 100 значений по y.
1 отрисовываем первое значение x=f(y)
2 если при следующем расчетном x , экранный x изменился меньше чем на один пиксель - то не выводим f(y) (даже если он посчитан). Тут и ошибка- выводится только 1 из 100 y , а если выводим - то нет ускорения.

Вообщем переформулировал условие так - выводим любое значение которое не равно предыдущему (в экранных целых x,y)
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Luke [?]
Тут и ошибка- выводится только 1 из 100 y , а если выводим - то нет ускорения.
это не ошибка, это реалии. ни один монитор тебе не выведет тебе эти 100 точек. даже если и выведет, ты этого не заметишь, как правило, расстояние между пикселями очень маленькое для разлечения глазом. поэтому, даже если там происходит какие-то жуткие осцилляции, ты этого не увидишь. и тут ни ЯП, ни графика, ни что-либо еще не при чем. все дело в самом мониторе. если эти точки все же надо увидеть, то надо предусмотреть зуминг. так вот это, задача на пятерку. но я тебе вот что скажу, я занимался примерно этим же, визуализацией расчетов с помощью AutoIt, когда только начинал изучать этот ЯП, но потом забросил, т.к. игра не стоит свеч. потом я перешел на matlab для этих целей, и с тех пор горя не знаю, чего и тебе желаю
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если на один пиксел по оси X приходится несколько значений Y, то нужно брать то значение Y, которое соответствует среднему значению X в пределах этого пиксела или увеличивать масштаб. Например, в заданном масштабе на один пиксел приходится 100 значений X (X[1] - X[100]), тогда нужно взять значение Y, соответствующее X[50]. Если построение графика осуществляется на основе функци, а не из массива, то нужно просто взять такой шаг по оси X в абсолютных единицах, который будет соответствовать 1 пикселу или больше.
 

Luke

Знающий
Сообщения
64
Репутация
14
Как говорится лучше 1 раз увидеть. Вот нужный мне график с полным выводом (не все значения примерно 100000)
Из него хорошо видно где и насколько проседает (в 1-2 пикселя толщиной но видно отлично)
если брать 1 из 100 значений по y - то получается просто почти прямая линия
если брать от средней x то думаю получится что линии выпадов укоротятся (не пробовал)
Вот хотелось бы быстро получать подобный график для 1 млн и больше значений.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Luke
ты же понимаешь бесполезность этих выпадов, правда? единственное о чем они говорят, какое максимальное значение будет в этих 100 точках уместившихся в один пиксель по х. если тебе так важно именно это значение, то его и рисуй из всех этих 100
 

Luke

Знающий
Сообщения
64
Репутация
14
Простое решение.
При выводе графика поставить такое условие:

Код:
If Round(_GraphGDIPlus_Reference_Pixel("y", $iY, $Grafik[8], $Grafik[9], $Grafik[5]))<>Round($Grafik[19]) Then
		_GraphGDIPlus_Plot_Line($Grafik, $iX, $iY)
	EndIf

где $Grafik - массив возвращаемый _GraphGDIPlus_Create

С таким условием график отрисовывается в точности такой же как и без пропуска значений, при этом работает в разы быстрей.
 
Верх