WPF使用Direct2D绘制曲线

wpf使用Direct2D绘制曲线

···
Install-Package SharpDX
Install-Package SharpDX.Direct2D1
Install-Package SharpDX.DXGI
Install-Package SharpDX.Direct3D11

···
在这里插入图片描述

<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Image Name="DxImage"/>
    </Grid>
</Window>


using System;
using System.Windows;
using System.Windows.Interop;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using Device = SharpDX.Direct3D11.Device;
using Factory = SharpDX.Direct2D1.Factory;
using AlphaModeD2D = SharpDX.Direct2D1.AlphaMode;
using PixelFormat = SharpDX.Direct2D1.PixelFormat;
using SolidColorBrush = SharpDX.Direct2D1.SolidColorBrush;
using SharpDX.DirectWrite;
using System.Windows.Media;
using TextAlignment = SharpDX.DirectWrite.TextAlignment;
using FactoryType = SharpDX.Direct2D1.FactoryType;
using TextAntialiasMode = SharpDX.Direct2D1.TextAntialiasMode;
using System.Numerics;
using DashStyle = SharpDX.Direct2D1.DashStyle;
using PathGeometry = SharpDX.Direct2D1.PathGeometry;
using static System.Net.Mime.MediaTypeNames;
using SharpDX.Mathematics.Interop;


using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using System.Security.Cryptography.Xml;
using System.Windows.Media.Media3D;

namespace WpfApp2
{
	public partial class MainWindow : Window
	{
		private Device device;
		private SwapChain swapChain;
		private RenderTarget renderTarget;
		private Factory factory;
		private SharpDX.DirectWrite.Factory writeFactory;
		private TextFormat textFormat;
		private bool isResizing = false;
		private StrokeStyle strokeStyle;

		public MainWindow()
		{
			InitializeComponent();
			Loaded += OnLoaded;
			Unloaded += OnUnloaded;
			SizeChanged += OnSizeChanged;
		}

		private void OnLoaded(object sender, RoutedEventArgs e)
		{
			InitializeSharpDX();
			CompositionTarget.Rendering += OnRendering;
		}

		private void OnUnloaded(object sender, RoutedEventArgs e)
		{
			CompositionTarget.Rendering -= OnRendering;
			DisposeResources();
		}

		private void InitializeSharpDX()
		{
			factory = new Factory(FactoryType.SingleThreaded);
			writeFactory = new SharpDX.DirectWrite.Factory();

			var swapChainDescription = new SwapChainDescription
			{
				BufferCount = 1,
				ModeDescription = new ModeDescription((int)ActualWidth, (int)ActualHeight, new Rational(60, 1), Format.B8G8R8A8_UNorm),
				IsWindowed = true,
				OutputHandle = new WindowInteropHelper(this).Handle,
				SampleDescription = new SampleDescription(1, 0),
				SwapEffect = SwapEffect.Discard,
				Usage = Usage.RenderTargetOutput
			};

			Device.CreateWithSwapChain(SharpDX.Direct3D.DriverType.Hardware, DeviceCreationFlags.BgraSupport, swapChainDescription, out device, out swapChain);

			UpdateTextFormat();
			CreateRenderTarget();
			CreateStrokeStyle();
		}

		private void UpdateTextFormat()
		{
			textFormat?.Dispose();
			float fontSize = (float)(Math.Min(ActualWidth, ActualHeight) * 0.02);
			textFormat = new TextFormat(writeFactory, "Arial", fontSize)
			{
				TextAlignment = TextAlignment.Center,
				ParagraphAlignment = ParagraphAlignment.Center
			};
		}

		private void CreateRenderTarget()
		{
			using (var surface = swapChain.GetBackBuffer<Surface>(0))
			{
				var properties = new RenderTargetProperties(new PixelFormat(Format.Unknown, AlphaModeD2D.Premultiplied));
				renderTarget = new RenderTarget(factory, surface, properties)
				{
					AntialiasMode = AntialiasMode.PerPrimitive,
					TextAntialiasMode = TextAntialiasMode.Cleartype
				};
			}
		}

		private void CreateStrokeStyle()
		{
			strokeStyle?.Dispose();
			strokeStyle = new StrokeStyle(factory, new StrokeStyleProperties
			{
				DashStyle = DashStyle.Solid,
				LineJoin = LineJoin.Round,
				StartCap = CapStyle.Round,
				EndCap = CapStyle.Round
			});
		}

		private void OnSizeChanged(object sender, SizeChangedEventArgs e)
		{
			if (swapChain != null && !isResizing)
			{
				isResizing = true;
				try
				{
					renderTarget?.Dispose();
					swapChain.ResizeBuffers(1, (int)ActualWidth, (int)ActualHeight, Format.B8G8R8A8_UNorm, SwapChainFlags.None);
					CreateRenderTarget();
					UpdateTextFormat();
				}
				finally
				{
					isResizing = false;
				}
			}
		}

		private void OnRendering(object sender, EventArgs e)
		{
			if (renderTarget == null || isResizing)
				return;

			renderTarget.BeginDraw();
			DrawScene();
			renderTarget.EndDraw();
			swapChain.Present(1, PresentFlags.None);
		}



		private void DrawScene()
		{
			renderTarget.Clear(new RawColor4(1, 1, 1, 1));

			using (var axisBrush = new SolidColorBrush(renderTarget, new RawColor4(0, 0, 0, 1)))
			using (var lineBrush = new SolidColorBrush(renderTarget, new RawColor4(1, 0, 0, 1)))
			using (var textBrush = new SolidColorBrush(renderTarget, new RawColor4(0, 0, 0, 1)))
			{
				float width = (float)renderTarget.Size.Width;
				float height = (float)renderTarget.Size.Height;
				float margin = Math.Min(width, height) * 0.1f;
				float axisLength = Math.Min(width, height) * 0.8f;
				float lineWidth = 1.5f;

				// Draw X-axis
				renderTarget.DrawLine(
					AlignToPixel(new RawVector2(margin, height / 2)),
					AlignToPixel(new RawVector2(width - margin, height / 2)),
					axisBrush, lineWidth, strokeStyle);

				// Draw Y-axis
				renderTarget.DrawLine(
					AlignToPixel(new RawVector2(width / 2, margin)),
					AlignToPixel(new RawVector2(width / 2, height - margin)),
					axisBrush, lineWidth, strokeStyle);

				// Draw X-axis ticks and labels
				for (int i = -4; i <= 4; i++)
				{
					float x = width / 2 + i * axisLength / 8;
					renderTarget.DrawLine(
						AlignToPixel(new RawVector2(x, height / 2 - 5)),
						AlignToPixel(new RawVector2(x, height / 2 + 5)),
						axisBrush, 1.0f, strokeStyle);

					using (var textLayout = new TextLayout(writeFactory, i.ToString(), textFormat, 50, 20))
					{
						renderTarget.DrawTextLayout(new RawVector2(x - 25, height / 2 + 10), textLayout, textBrush);
					}
				}

				// Draw Y-axis ticks and labels
				for (int i = -4; i <= 4; i++)
				{
					float y = height / 2 - i * axisLength / 8;
					renderTarget.DrawLine(
						AlignToPixel(new RawVector2(width / 2 - 5, y)),
						AlignToPixel(new RawVector2(width / 2 + 5, y)),
						axisBrush, 1.0f, strokeStyle);

					using (var textLayout = new TextLayout(writeFactory, i.ToString(), textFormat, 50, 20))
					{
						renderTarget.DrawTextLayout(new RawVector2(width / 2 + 10, y - 10), textLayout, textBrush);
					}
				}

				// Draw a line using geometry for better quality
				var startPoint = AlignToPixel(new RawVector2(margin, margin));
				var endPoint = AlignToPixel(new RawVector2(width - margin, height - margin));

				using (var lineGeometry = new PathGeometry(factory))
				{
					var sink = lineGeometry.Open();
					sink.BeginFigure(startPoint, FigureBegin.Hollow);
					sink.AddLine(endPoint);
					sink.EndFigure(FigureEnd.Open);
					sink.Close();

					//	使用 SharpDX.Matrix3x2.Identity 而不是 System.Numerics.Matrix3x2.Identity
					//var transform = SharpDX.Matrix3x2.Identity;
					var transform = new RawMatrix3x2() { M11 = 1, M22 = 1 };
					using (var transformedGeometry = new TransformedGeometry(factory, lineGeometry, transform))
					{
						renderTarget.DrawGeometry(transformedGeometry, lineBrush, lineWidth, strokeStyle);
					}
				}
			}
		}





		private RawVector2 AlignToPixel(RawVector2 point)
		{
			return new RawVector2(
				(float)Math.Round(point.X) + 0.5f,
				(float)Math.Round(point.Y) + 0.5f
			);
		}

		private void DisposeResources()
		{
			renderTarget?.Dispose();
			swapChain?.Dispose();
			device?.Dispose();
			textFormat?.Dispose();
			writeFactory?.Dispose();
			factory?.Dispose();
			strokeStyle?.Dispose();
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值