Я делаю приложение, которое будет показывать линейную диаграмму измерителя ускорения. Диаграмма должна сдвинуться в сторону, чтобы показать новые результаты. Для рисования я использую графическую библиотеку CocoSharp.
Первая попытка заключалась в том, чтобы перерисовывать всю диаграмму при каждом обновлении, но этого было недостаточно быстро, и почему-то вы не можете рисовать прозрачными, это не стирает ранее нарисованные пиксели, поэтому моя диаграмма просто заполнено.
Вторая попытка заключалась в том, чтобы сделать диаграмму в 4 раза шире экрана и отрисовать последнее обновление только в 2-х позициях: в позиции, которую мы рисуем, и в 2-х ширинах экрана назад (вне экрана). Перед рисованием линии я рисую черную линию вместо прозрачной, чтобы стереть предыдущий результат.
Затем я перемещаю весь слой влево, получая красивую диаграмму прокрутки. Затем, когда позиция превышает 2 ширины экрана, я сбрасываю позицию обратно на 0, но поскольку мы рисуем в двух позициях, график уже нарисован так же, как и в том месте, где мы оставили, что делает его плавным прокруткой навсегда.
Это работает очень хорошо, но через несколько минут рисования можно заметить, что экран начинает отставать в частоте кадров. Я исследовал все, но мой поток рисования работает отлично, выкачивая полное обновление каждые 16 мс, поэтому я думаю, что это библиотека CocoSharp.
Как я уже говорил ранее, когда вы рисуете прозрачным, пиксели не стираются, что заставляет меня думать, что каждое обновление отрисовки каким-то образом сохраняется в памяти, через некоторое время замедляя работу графического процессора. Это могло быть правильно? И если да, то как мне это исправить?
using CocosSharp;
using JumpMeter.Shared;
using JumpMeter.Shared.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace JumpMeter
{
public class ChartLayer
{
public ChartLayer(CCScene scene, float x, float y, float width, float height)
{
List = new ConcurrentQueue<CalculationLog>();
RasterLayer = new CCLayer();
RasterNode = new CCDrawNode();
GraphLayer = new CCLayer();
GraphNode = new CCDrawNode();
// Add the background layer
RasterLayer.AddChild(RasterNode);
// Draw the "zero lines"
RasterNode.DrawLine(new CCPoint(0, height / 2), new CCPoint(width, height / 2), 0.1f, CCColor4B.White);
RasterNode.DrawLine(new CCPoint(0, 2), new CCPoint(width, 2), 0.1f, CCColor4B.White);
scene.AddLayer(RasterLayer);
// Add the graphics layer
GraphLayer.AddChild(GraphNode);
scene.AddLayer(GraphLayer);
Width = width;
Height = height;
RasterLayer.PositionX = x;
RasterLayer.PositionY = y;
GraphLayer.PositionY = y;
}
public CCLayer RasterLayer { get; }
public CCDrawNode RasterNode { get; }
public CCLayer GraphLayer { get; }
public CCDrawNode GraphNode { get; }
float Width { get; }
float Height { get; }
// Buffer for the drawn items
ConcurrentQueue<CalculationLog> List { get; }
// Current position of the graph
float Position { get; set; }
// Here we get the new values for the graph
public void AddValue(CalculationLog value)
{
List.Enqueue(value);
}
// This function will be called every 16ms
public bool Draw()
{
while (List.TryDequeue(out CalculationLog value))
{
Position += Constants.GraphSpeed; // = 0.1f
// If the position is bigger than 2 screen widths (* 1000 for ultra slow speeds)
if (Convert.ToInt32(Position * 1000) >= Convert.ToInt32(Width * 2 * 1000))
Position = 0;
// Calculate real positions
var x = Position + RasterLayer.PositionX;
var y = Convert.ToSingle(value.AccelerationUp / Constants.Scale) * (Height / 2) + Height / 2;
if (y > Height) y = Height;
if (y < 0) y = 0;
var y2 = Convert.ToSingle(value.Height / Constants.Scale * 2) * (Height / 2) + 1;
if (y2 > Height) y2 = Height;
if (y2 < 0) y2 = 0;
// Then draw them
GraphNode.DrawLine(new CCPoint(x, 0), new CCPoint(x, Height), Constants.GraphSpeed, CCColor4B.Black);
GraphNode.DrawLine(new CCPoint(x, Height / 2), new CCPoint(x, y), Constants.GraphSpeed, CCColor4B.White);
GraphNode.DrawLine(new CCPoint(x, y2), new CCPoint(x, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
GraphNode.DrawLine(new CCPoint(x - Width * 2, 0), new CCPoint(x - Width * 2, Height), Constants.GraphSpeed, CCColor4B.Black);
GraphNode.DrawLine(new CCPoint(x - Width * 2, Height / 2), new CCPoint(x - Width * 2, y), Constants.GraphSpeed, CCColor4B.White);
GraphNode.DrawLine(new CCPoint(x - Width * 2, y2), new CCPoint(x - Width * 2, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
}
// Move the position of the graph layer
GraphLayer.PositionX = Convert.ToInt32(Width - Position);
return true;
}
}
}
(на самом деле я рисую 2 графика в 1 графике, я забыл об этом в своем общем описании)