Я написал этот компонент для рендеринга потоковой передачи с камеры. Над потоковой передачей пользователь может нарисовать одну или несколько фигур (управляемых через интерфейс). Доступные фигуры:
Точка
Прямоугольник
Эллипс
Эллипс
Прямоугольник
Эллипс
Прямоугольник
Эллипс li>
Ломаная линия
Помимо рисования фигур, пользователь может выбрать одну и изменить ее размер и положение. Пользователь также может видеть самую горячую точку изображения, которая затем будет постоянно перемещаться внутри изображения.
Изображение постоянно обновляется и обрабатывается событием: UpdateRadiometricImage
Это мой полный код компонента:
using Imager.IRBinding;
using Imager.Services;
using Imager.Shapes;
using Imager.Types;
using Imager.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Web.UI.WebControls.Expressions;
using System.Windows.Forms;
namespace Imager.Components
{
public class RadiometricImage : PictureBox, IDisposable
{
// -------- PER IL DISEGNO
internal string Serial { get; set; }
internal List Shapes = new List(); // Forme permanenti
internal List SelectedShapes { get; set; } = new List(); // Forme selezionate
public ShapeType ShapeToDraw { get; set; } = ShapeType.None;
public ModeType CurrentMode { get; set; } = ModeType.None;
public PolylineShape CurrentPolyline { get; set; } = null; // Polilinea temporanea
public bool IsDrawingPolyline { get; set; } = false; // Flag per il disegno polilinea
private Point currentCursorPoint; // Posizione corrente del cursore
private Point? startPoint = null; // Punto iniziale del disegno
private IShape tempShape = null; // Forma temporanea
private Point? selectedHandler = null; // Handler selezionato per modifica
private bool isDragging = false; // Flag per indicare il trascinamento
private Point dragStartPoint; // Punto iniziale del trascinamento
private Point? activeResizeHandler = null; // Handler attivo per il resize
private int selectedResizeHandler; // Handler selezionato per il resize
// --------
// ------------ AREA DI MISURA PANNELLO
public event EventHandler ShapeChanged;
public event EventHandler ThermalImageUpdated;
// -----------
// --------- MOSTRA PUNTO CALDO GLOBALE
public bool ShowHotSpot { get; set; } = false;
private readonly PointShape _hotSpot = new PointShape();
// ---------
private bool _disposed = false;
private Rectangle _imageBounds;
private readonly ToolTip _toolTip = new ToolTip();
private Bitmap _paletteImage = null;
public Bitmap PaletteImage
{
get => _paletteImage;
set
{
Image = _paletteImage = value;
CalculateImageBounds();
}
}
public ushort[,] ThermalImage { get; set; } = null;
public EvoIRFrameMetadata Metadata { get; set; }
public RadiometricImage()
{
Console.WriteLine("RadiometricImage created.");
BackColor = Color.Black;
Dock = DockStyle.Fill;
DoubleBuffered = true;
SizeMode = PictureBoxSizeMode.Zoom;
Resize += (s, e) =>
{
Console.WriteLine("Resize event triggered.");
CalculateImageBounds();
};
MouseMove += RadiometricImage_MouseMove;
MouseLeave += RadiometricImage_MouseLeave;
MouseDown += RadiometricImage_MouseDown;
MouseUp += RadiometricImage_MouseUp;
Paint += RadiometricImage_Paint;
}
internal void UpdateRadiometricImage(ThermalPaletteImage img)
{
PaletteImage = img.PaletteImage;
Metadata = img.IRFrameMetadata;
ThermalImage = img.ThermalImage;
ThermalImageUpdated?.Invoke(this, EventArgs.Empty); // Notifica il cambiamento
}
private void RadiometricImage_MouseLeave(object sender, EventArgs e)
{
Console.WriteLine("Mouse fouri dall'immagine, nascondo tooltip");
_toolTip.Hide(this);
}
private void RadiometricImage_Paint(object sender, PaintEventArgs e)
{
if (ShowHotSpot)
{
int maxI = 0, maxJ = 0;
ushort max = ThermalImage[0, 0];
for (int i = 0; i < ThermalImage.GetLength(0); ++i)
{
for (int j = 0; j < ThermalImage.GetLength(1); ++j)
{
if (ThermalImage[i, j] > max)
{
max = ThermalImage[i, j];
maxI = i;
maxJ = j;
}
}
}
_hotSpot.Position = new Point(maxJ, maxI);
_hotSpot.Name = $"{Conversion.RealTemperatureValue(max)} °C";
_hotSpot.Draw(e.Graphics, FromImageToContainer, Color.Black);
DrawShapeName(e.Graphics, _hotSpot, Color.Black);
}
foreach (var shape in Shapes)
{
Console.WriteLine("shape");
shape.Draw(e.Graphics, FromImageToContainer);
DrawShapeName(e.Graphics, shape);
if (SelectedShapes.Contains(shape))
{
DrawShapeHandlers(e.Graphics, shape);
}
}
if (ShapeToDraw == ShapeType.Polyline && CurrentPolyline != null)
{
Console.WriteLine("polyline shape");
CurrentPolyline.Draw(e.Graphics, FromImageToContainer);
DrawPolylinePreview(e.Graphics);
DrawShapeHandlers(e.Graphics, CurrentPolyline);
}
tempShape?.Draw(e.Graphics, FromImageToContainer);
}
internal void RadiometricImage_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
if (SelectedShapes.Any())
{
foreach (var shape in SelectedShapes.ToList())
{
RemoveShape(shape);
}
SelectedShapes.Clear();
Invalidate();
}
}
else if (e.KeyCode == Keys.Escape)
{
ResetDrawingState();
Invalidate();
}
if (SelectedShapes.Any())
{
const int moveStep = 1;
switch (e.KeyCode)
{
case Keys.Left:
MoveSelectedShapes(new Point(-moveStep, 0), true);
break;
case Keys.Right:
MoveSelectedShapes(new Point(moveStep, 0), true);
break;
case Keys.Up:
MoveSelectedShapes(new Point(0, -moveStep), true);
break;
case Keys.Down:
MoveSelectedShapes(new Point(0, moveStep), true);
break;
}
}
}
private void RadiometricImage_MouseUp(object sender, MouseEventArgs e)
{
Console.WriteLine($"MouseUp at {e.Location}");
if (isDragging)
{
isDragging = false;
Cursor = Cursors.Default;
}
else if (activeResizeHandler.HasValue)
{
activeResizeHandler = null;
Cursor = Cursors.Default;
}
else if ((ShapeToDraw == ShapeType.Rectangle || ShapeToDraw == ShapeType.Ellipse) && tempShape != null)
{
tempShape.Name = $"Area {Shapes.Count + 1}";
AddShape(tempShape);
tempShape = null;
startPoint = null;
}
selectedHandler = null;
Cursor = Cursors.Default;
// Invalidate();
}
private void RadiometricImage_MouseMove(object sender, MouseEventArgs e)
{
Console.WriteLine($"MouseMove at {e.Location}");
if (CurrentMode == ModeType.None && _imageBounds.Contains(e.Location))
{
var position = FromContainerToImage(e.Location);
double temperature = CameraService.GetPixelValue(ThermalImage, position);
_toolTip.Show($"{temperature} °C", this, e.X + 10, e.Y + 10);
}
else
{
_toolTip.Hide(this);
}
currentCursorPoint = e.Location;
if (activeResizeHandler.HasValue && SelectedShapes.Count == 1 && activeResizeHandler.Value != e.Location)
{
Console.WriteLine($"Active Handler: {activeResizeHandler.Value}");
var shape = SelectedShapes.First();
if (_imageBounds.Contains(e.Location))
{
shape.Resize(FromContainerToImage(activeResizeHandler.Value), FromContainerToImage(e.Location)); // Ridimensiona la forma
var aux = shape.GetHandlers();
activeResizeHandler = FromImageToContainer(aux.ElementAt(selectedResizeHandler)); // Aggiorna la posizione dell'handler
Invalidate();
}
}
else if (isDragging && SelectedShapes.Any())
{
MoveSelectedShapes(e.Location);
dragStartPoint = e.Location;
}
else
{
foreach (var shape in SelectedShapes)
{
var pos = FromContainerToImage(e.Location);
bool onHandler = false;
if (shape is PolylineShape polyline)
{
foreach (var handler in polyline.GetHandlers())
{
if (DrawHelper.IsCloseToPoint(e.Location, FromImageToContainer(handler)))
{
Cursor = Cursors.Hand;
onHandler = true;
break;
}
}
}
else if (!(shape is PointShape point))
{
foreach (var handler in shape.GetHandlers())
{
if (DrawHelper.IsCloseToPoint(e.Location, FromImageToContainer(handler)))
{
Cursor = DrawHelper.GetResizeCursor(handler, shape); // Ottieni il cursore corretto
onHandler = true;
break;
}
}
}
if (!onHandler)
{
Cursor = Cursors.Default;
}
}
}
if (CurrentMode == ModeType.Draw)
{
if (ShapeToDraw == ShapeType.Polyline && selectedHandler.HasValue) MovePolylineHandler(FromContainerToImage(e.Location));
if ((ShapeToDraw == ShapeType.Rectangle || ShapeToDraw == ShapeType.Ellipse) && startPoint.HasValue) UpdateTemporaryShape(e.Location);
Invalidate();
}
}
private void RadiometricImage_MouseDown(object sender, MouseEventArgs e)
{
Console.WriteLine($"MouseDown at {e.Location}");
if (CurrentMode == ModeType.Select)
{
HandleSelectionMouseDown(e.Location);
if (SelectedShapes.Any() && isDragging)
{
Cursor = Cursors.SizeAll;
}
}
if (CurrentMode == ModeType.Draw)
{
if (_imageBounds.Contains(e.Location))
{
switch (ShapeToDraw)
{
case ShapeType.Point:
AddPointShape(e.Location);
break;
case ShapeType.Rectangle:
case ShapeType.Ellipse:
startPoint = FromContainerToImage(e.Location);
break;
case ShapeType.Polyline:
HandlePolylineMouseDown(e);
break;
default:
break;
}
}
}
}
public void AddShape(IShape shape)
{
Shapes.Add(shape);
OnShapeAdded(shape);
Invalidate(); // Per ridisegnare shape.GetRegion(FromImageToContainer)
}
public void RemoveShape(IShape shape)
{
if (Shapes.Remove(shape))
{
OnShapeRemoved(shape);
Invalidate(); // Per ridisegnare shape.GetRegion(FromImageToContainer)
}
}
#region HELPERS
private Point FromContainerToImage(Point src)
{
if (Image == null) return Point.Empty;
float xRatio = (float)(src.X - _imageBounds.Left) / _imageBounds.Width;
float yRatio = (float)(src.Y - _imageBounds.Top) / _imageBounds.Height;
return new Point((int)(xRatio * Image.Width), (int)(yRatio * Image.Height));
}
private Point FromImageToContainer(Point src)
{
if (Image == null) return Point.Empty;
float xRatio = (float)src.X / Image.Width;
float yRatio = (float)src.Y / Image.Height;
return new Point((int)(xRatio * _imageBounds.Width + _imageBounds.Left), (int)(yRatio * _imageBounds.Height + _imageBounds.Top));
}
private void CalculateImageBounds()
{
if (Image == null)
{
_imageBounds = new Rectangle(0, 0, 0, 0);
return;
}
float xRatio = (float)Width / Image.Width;
float yRatio = (float)Height / Image.Height;
float ratio = Math.Min(xRatio, yRatio);
int width = (int)(Image.Width * ratio);
int height = (int)(Image.Height * ratio);
_imageBounds = new Rectangle((Width - width) / 2, (Height - height) / 2, width, height);
}
private void DrawHandler(Graphics g, Point point)
{
const int size = 10;
var rect = new Rectangle(point.X - size / 2, point.Y - size / 2, size, size);
using (var brush = new SolidBrush(SystemColors.Highlight))
{
g.FillRectangle(brush, rect);
}
}
private void DrawShapeHandlers(Graphics g, IShape shape)
{
foreach (var handler in shape.GetHandlers().Select(x => FromImageToContainer(x)))
{
DrawHandler(g, handler);
}
}
private void ResetDrawingState()
{
if (ShapeToDraw == ShapeType.Polyline && IsDrawingPolyline)
{
CurrentPolyline = null;
IsDrawingPolyline = false;
}
else if ((ShapeToDraw == ShapeType.Rectangle || ShapeToDraw == ShapeType.Ellipse) && tempShape != null)
{
tempShape = null;
startPoint = null;
}
else if (SelectedShapes.Any())
{
SelectedShapes.Clear();
}
// CurrentMode = ModeType.None;
}
private void HandlePolylineMouseDown(MouseEventArgs e)
{
if (CurrentPolyline != null)
{
var point = FromContainerToImage(e.Location);
if (CurrentPolyline.Points.Count > 0 && DrawHelper.IsCloseToPoint(point, CurrentPolyline.Points[0]))
{
CurrentPolyline.ClosePolyline();
CurrentPolyline.IsClosed = true;
CurrentPolyline.Name = $"Area {Shapes.Count + 1}";
AddShape(CurrentPolyline);
CurrentPolyline = null;
IsDrawingPolyline = true;
}
else
{
CurrentPolyline.Points.Add(point);
}
}
}
private void AddPointShape(Point location)
{
var pointShape = new PointShape() { Name = $"Area {Shapes.Count + 1}", Position = FromContainerToImage(location) };
AddShape(pointShape);
}
private void UpdateTemporaryShape(Point location)
{
if (startPoint.HasValue && _imageBounds.Contains(location))
{
var rect = DrawHelper.GetRectangleFromPoints(startPoint.Value, FromContainerToImage(location));
switch (ShapeToDraw)
{
case ShapeType.Rectangle:
tempShape = new RectangleShape { Rect = rect };
break;
case ShapeType.Ellipse:
tempShape = new EllipseShape { Bounds = rect };
break;
}
}
}
private void MoveSelectedShapes(Point location, bool keyboard = false)
{
var bounds = new Rectangle(0, 0, Image.Width, Image.Height);
if (keyboard)
{
foreach (var shape in SelectedShapes)
{
shape.Move(bounds, location);
}
}
else
{
var convertedLocation = FromContainerToImage(location);
var convartedStartPoint = FromContainerToImage(dragStartPoint);
var deltaX = convertedLocation.X - convartedStartPoint.X;
var deltaY = convertedLocation.Y - convartedStartPoint.Y;
foreach (var shape in SelectedShapes)
{
shape.Move(bounds, new Point(deltaX, deltaY));
}
dragStartPoint = location;
}
}
private void MovePolylineHandler(Point location)
{
if (CurrentPolyline != null && selectedHandler.HasValue)
{
var index = CurrentPolyline.Points.IndexOf(selectedHandler.Value);
if (index >= 0)
{
CurrentPolyline.Points[index] = location;
}
}
}
private void DrawShapeName(Graphics g, IShape shape, Color color = default)
{
var center = shape.NamePosition(FromImageToContainer, Image.Height);
if (color == default) color = Color.White;
using (var font = new Font("Arial", 14))
{
using (var brush = new SolidBrush(color))
{
g.DrawString(shape.Name, font, brush, center);
}
}
}
private void HandleSelectionMouseDown(Point location)
{
SelectedShapes.Clear();
activeResizeHandler = null; // Resetta l'handler attivo
foreach (var shape in Shapes)
{
if (!(shape is PointShape point))
{
int i = 0;
foreach (var handler in shape.GetHandlers())
{
var h = FromImageToContainer(handler);
if (DrawHelper.IsCloseToPoint(location, h))
{
SelectedShapes.Add(shape);
activeResizeHandler = h; // Memorizza l'handler attivo per il resize
selectedResizeHandler = i;
Console.WriteLine($"Handler: {h}");
return;
}
i++;
}
}
if (shape.PointOnBound(FromContainerToImage(location)))
{
SelectedShapes.Add(shape);
dragStartPoint = location;
isDragging = true;
Invalidate();
return;
}
}
}
private void DrawPolylinePreview(Graphics g)
{
if (CurrentPolyline != null && CurrentPolyline.Points.Count > 0)
{
var lastPoint = CurrentPolyline.Points.Last();
if (DrawHelper.IsCloseToPoint(FromContainerToImage(currentCursorPoint), CurrentPolyline.Points[0]))
{
g.DrawLine(Pens.White, FromImageToContainer(lastPoint), FromImageToContainer(CurrentPolyline.Points[0]));
}
else
{
g.DrawLine(Pens.Gray, FromImageToContainer(lastPoint), currentCursorPoint);
}
}
}
#endregion
#region AREA_DI_MISURA
private void OnShapeAdded(IShape shape)
{
ShapeChanged?.Invoke(this, new ShapeChangedEventArgs(shape, AreaOperation.Added));
}
private void OnShapeRemoved(IShape shape)
{
ShapeChanged?.Invoke(this, new ShapeChangedEventArgs(shape, AreaOperation.Removed));
}
#endregion
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (PaletteImage != null)
{
PaletteImage.Dispose();
PaletteImage = null;
}
if (Shapes != null)
{
Shapes.Clear();
Shapes = null;
}
if (SelectedShapes != null)
{
SelectedShapes.Clear();
SelectedShapes = null;
}
if (ThermalImage != null) ThermalImage = null;
if (CurrentPolyline != null) CurrentPolyline = null;
Resize -= (s, e) => CalculateImageBounds();
MouseMove -= RadiometricImage_MouseMove;
MouseDown -= RadiometricImage_MouseDown;
MouseUp -= RadiometricImage_MouseUp;
Paint -= RadiometricImage_Paint;
}
}
base.Dispose(disposing);
_disposed = true;
}
}
}
Код работает, но когда потоковая передача с камеры ведется в высоком разрешении или нарисовано много фигур, все приложение тормозит, вызывая неудобства для пользователя. Есть ли у вас какие-либо советы и предложения по оптимизации этого компонента в лучшем случае?
Я написал этот компонент для рендеринга потоковой передачи с камеры. Над потоковой передачей пользователь может нарисовать одну или несколько фигур (управляемых через интерфейс). Доступные фигуры: [list] [*]Точка [*]Прямоугольник [*]Эллипс [*]Эллипс [*]Прямоугольник [*]Эллипс [*]Прямоугольник [*]Эллипс li> Ломаная линия [/list] Помимо рисования фигур, пользователь может выбрать одну и изменить ее размер и положение. Пользователь также может видеть самую горячую точку изображения, которая затем будет постоянно перемещаться внутри изображения. Изображение постоянно обновляется и обрабатывается событием: UpdateRadiometricImage Это мой полный код компонента: [code]using Imager.IRBinding; using Imager.Services; using Imager.Shapes; using Imager.Types; using Imager.Utils; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Web.UI.WebControls.Expressions; using System.Windows.Forms;
namespace Imager.Components { public class RadiometricImage : PictureBox, IDisposable { // -------- PER IL DISEGNO internal string Serial { get; set; } internal List Shapes = new List(); // Forme permanenti
internal List SelectedShapes { get; set; } = new List(); // Forme selezionate
public ShapeType ShapeToDraw { get; set; } = ShapeType.None; public ModeType CurrentMode { get; set; } = ModeType.None; public PolylineShape CurrentPolyline { get; set; } = null; // Polilinea temporanea public bool IsDrawingPolyline { get; set; } = false; // Flag per il disegno polilinea
private Point currentCursorPoint; // Posizione corrente del cursore private Point? startPoint = null; // Punto iniziale del disegno private IShape tempShape = null; // Forma temporanea private Point? selectedHandler = null; // Handler selezionato per modifica private bool isDragging = false; // Flag per indicare il trascinamento private Point dragStartPoint; // Punto iniziale del trascinamento private Point? activeResizeHandler = null; // Handler attivo per il resize private int selectedResizeHandler; // Handler selezionato per il resize // --------
// ------------ AREA DI MISURA PANNELLO public event EventHandler ShapeChanged; public event EventHandler ThermalImageUpdated; // -----------
// --------- MOSTRA PUNTO CALDO GLOBALE public bool ShowHotSpot { get; set; } = false; private readonly PointShape _hotSpot = new PointShape(); // ---------
private void RadiometricImage_MouseMove(object sender, MouseEventArgs e) { Console.WriteLine($"MouseMove at {e.Location}");
if (CurrentMode == ModeType.None && _imageBounds.Contains(e.Location)) { var position = FromContainerToImage(e.Location); double temperature = CameraService.GetPixelValue(ThermalImage, position); _toolTip.Show($"{temperature} °C", this, e.X + 10, e.Y + 10); } else { _toolTip.Hide(this); }
currentCursorPoint = e.Location;
if (activeResizeHandler.HasValue && SelectedShapes.Count == 1 && activeResizeHandler.Value != e.Location) { Console.WriteLine($"Active Handler: {activeResizeHandler.Value}"); var shape = SelectedShapes.First(); if (_imageBounds.Contains(e.Location)) {
shape.Resize(FromContainerToImage(activeResizeHandler.Value), FromContainerToImage(e.Location)); // Ridimensiona la forma var aux = shape.GetHandlers(); activeResizeHandler = FromImageToContainer(aux.ElementAt(selectedResizeHandler)); // Aggiorna la posizione dell'handler Invalidate(); }
} else if (isDragging && SelectedShapes.Any()) { MoveSelectedShapes(e.Location); dragStartPoint = e.Location; } else { foreach (var shape in SelectedShapes) { var pos = FromContainerToImage(e.Location); bool onHandler = false; if (shape is PolylineShape polyline) { foreach (var handler in polyline.GetHandlers()) { if (DrawHelper.IsCloseToPoint(e.Location, FromImageToContainer(handler))) { Cursor = Cursors.Hand; onHandler = true; break; } } } else if (!(shape is PointShape point)) { foreach (var handler in shape.GetHandlers()) { if (DrawHelper.IsCloseToPoint(e.Location, FromImageToContainer(handler))) { Cursor = DrawHelper.GetResizeCursor(handler, shape); // Ottieni il cursore corretto onHandler = true; break; } } } if (!onHandler) { Cursor = Cursors.Default; } } } if (CurrentMode == ModeType.Draw) { if (ShapeToDraw == ShapeType.Polyline && selectedHandler.HasValue) MovePolylineHandler(FromContainerToImage(e.Location)); if ((ShapeToDraw == ShapeType.Rectangle || ShapeToDraw == ShapeType.Ellipse) && startPoint.HasValue) UpdateTemporaryShape(e.Location);
Invalidate(); } }
private void RadiometricImage_MouseDown(object sender, MouseEventArgs e) { Console.WriteLine($"MouseDown at {e.Location}");
if (CurrentMode == ModeType.Select) { HandleSelectionMouseDown(e.Location); if (SelectedShapes.Any() && isDragging) { Cursor = Cursors.SizeAll; } }
if (CurrentMode == ModeType.Draw) { if (_imageBounds.Contains(e.Location)) { switch (ShapeToDraw) { case ShapeType.Point: AddPointShape(e.Location); break; case ShapeType.Rectangle: case ShapeType.Ellipse: startPoint = FromContainerToImage(e.Location); break; case ShapeType.Polyline: HandlePolylineMouseDown(e); break; default: break; } } } }
public void AddShape(IShape shape) { Shapes.Add(shape); OnShapeAdded(shape); Invalidate(); // Per ridisegnare shape.GetRegion(FromImageToContainer) }
public void RemoveShape(IShape shape) { if (Shapes.Remove(shape)) { OnShapeRemoved(shape); Invalidate(); // Per ridisegnare shape.GetRegion(FromImageToContainer) } }
#region HELPERS
private Point FromContainerToImage(Point src) { if (Image == null) return Point.Empty;
private void AddPointShape(Point location) { var pointShape = new PointShape() { Name = $"Area {Shapes.Count + 1}", Position = FromContainerToImage(location) }; AddShape(pointShape); }
private void UpdateTemporaryShape(Point location) { if (startPoint.HasValue && _imageBounds.Contains(location)) { var rect = DrawHelper.GetRectangleFromPoints(startPoint.Value, FromContainerToImage(location)); switch (ShapeToDraw) { case ShapeType.Rectangle: tempShape = new RectangleShape { Rect = rect }; break; case ShapeType.Ellipse: tempShape = new EllipseShape { Bounds = rect }; break; } } }
private void MoveSelectedShapes(Point location, bool keyboard = false) { var bounds = new Rectangle(0, 0, Image.Width, Image.Height); if (keyboard) { foreach (var shape in SelectedShapes) { shape.Move(bounds, location); } } else { var convertedLocation = FromContainerToImage(location); var convartedStartPoint = FromContainerToImage(dragStartPoint);
var deltaX = convertedLocation.X - convartedStartPoint.X; var deltaY = convertedLocation.Y - convartedStartPoint.Y;
foreach (var shape in SelectedShapes) { shape.Move(bounds, new Point(deltaX, deltaY)); } dragStartPoint = location; } }
private void MovePolylineHandler(Point location) { if (CurrentPolyline != null && selectedHandler.HasValue) { var index = CurrentPolyline.Points.IndexOf(selectedHandler.Value); if (index >= 0) { CurrentPolyline.Points[index] = location; } } }
private void DrawShapeName(Graphics g, IShape shape, Color color = default) { var center = shape.NamePosition(FromImageToContainer, Image.Height);
if (color == default) color = Color.White;
using (var font = new Font("Arial", 14)) { using (var brush = new SolidBrush(color)) { g.DrawString(shape.Name, font, brush, center); } } }
_disposed = true; } } } [/code] Код работает, но когда потоковая передача с камеры ведется в высоком разрешении или нарисовано много фигур, все приложение тормозит, вызывая неудобства для пользователя. Есть ли у вас какие-либо советы и предложения по оптимизации этого компонента в лучшем случае?