C# 如何在WPF中使用圆绘制相机的视野?

C# 如何在WPF中使用圆绘制相机的视野?,c#,wpf,C#,Wpf,我正在尝试使用WPF绘制一个圆弧,但不知怎么搞不清楚如何做到这一点。我已经搜索了很多,并通过WPF的路径属性找到了它,但我发现在我的例子中这还不够好。 我的要求是在wpf上显示闭路电视摄像机的视野 用户有以下输入: 1.圆心。 2.圆的半径。 3.角度(0-360) 我想让用户画一个圆或一个完整的圆区域,可以通过改变角度和半径来改变区域。 注: 1.中心是画布上的固定位置。 2.用户可以动态更改图形(区域) 假设用户提供45度的角度,则圆将如下图所示: 这里有一个简单的方法。当然,您需要使用自己

我正在尝试使用WPF绘制一个圆弧,但不知怎么搞不清楚如何做到这一点。我已经搜索了很多,并通过WPF的路径属性找到了它,但我发现在我的例子中这还不够好。 我的要求是在wpf上显示闭路电视摄像机的视野

用户有以下输入: 1.圆心。 2.圆的半径。 3.角度(0-360)

我想让用户画一个圆或一个完整的圆区域,可以通过改变角度和半径来改变区域。 注: 1.中心是画布上的固定位置。 2.用户可以动态更改图形(区域)

假设用户提供45度的角度,则圆将如下图所示:
这里有一个简单的方法。当然,您需要使用自己的代码使其动态化,但这很容易控制:在我的示例中,我放置了两个不同的图形,因此您将有两个“视野”:


这里有一个简单的方法。当然,您需要使用自己的代码使其动态化,但这很容易控制:在我的示例中,我放置了两个不同的图形,因此您将有两个“视野”:


在花了一些时间阅读我的旧代数课本之后,我为您找到了一个完全可行的解决方案

这使用Nuget软件包(免责声明:我是此软件包的作者)提供
INotifyPropertyChanged
支持,但是您应该能够轻松地更改您想要的任何事件系统。完整解决方案可从下载

XAML:

<Window
    x:Class="ViewingAngle.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:local="clr-namespace:ViewingAngle"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="525"
    Height="350"
    d:DataContext="{d:DesignInstance local:MainWindowVm}"
    mc:Ignorable="d">
    <DockPanel Margin="4">
        <StackPanel DockPanel.Dock="Bottom">
            <TextBlock Margin="4,4,4,0" Text="{Binding Path=FieldOfView, StringFormat='Field of View: {0}'}" />
            <Slider
                Margin="4"
                Maximum="360"
                Minimum="0"
                TickFrequency="5"
                TickPlacement="Both"
                Value="{Binding Path=FieldOfView}" />
            <TextBlock Margin="4,4,4,0" Text="{Binding Path=TargetAngle, StringFormat='Target Angle: {0}'}" />
            <Slider
                Margin="4"
                Maximum="360"
                Minimum="0"
                TickFrequency="5"
                TickPlacement="Both"
                Value="{Binding Path=TargetAngle}" />
        </StackPanel>

        <Viewbox Margin="4" Stretch="Uniform">
            <Canvas Width="500" Height="500">
                <Path
                    Fill="Blue"
                    Stroke="Blue"
                    StrokeThickness="1">
                    <Path.Data>
                        <PathGeometry>
                            <PathGeometry.Figures>
                                <PathFigure StartPoint="250,250">
                                    <LineSegment Point="{Binding Path=StartPoint}" />
                                    <ArcSegment
                                        IsLargeArc="{Binding Path=IsLargeArc}"
                                        Point="{Binding Path=EndPoint}"
                                        Size="250,250"
                                        SweepDirection="Clockwise" />
                                    <LineSegment Point="250,250" />
                                </PathFigure>
                            </PathGeometry.Figures>
                        </PathGeometry>
                    </Path.Data>
                </Path>
            </Canvas>
        </Viewbox>
    </DockPanel>
</Window>
所有的魔法都发生在
recreactearc
中,每当
TargetAngle
FieldOfView
发生更改时,就会调用它。所有的数学运算都必须以弧度为单位,所以它要做的第一件事就是转换值。它使用一些相当简单的涉及正弦和余弦的代数来计算
弧段的新
StartPoint
EndPoint
值(尽管我仍然需要查找数学,因为高中毕业后谁还记得这些东西?)

在XAML中,我放置了一些绑定到
TargetAngle
FieldOfView
的滑块,以允许您控制角度。它还包含绘制图形的
画布
,它位于
视图框
内,只是为了让指示器填满可用空间


画布
包含一个
路径
,该路径由一个
路径图
组成。
路径图
从250250开始(500 x 500
画布的中心
),将
线段
绘制到弧的起点,该起点绑定到
起点
。然后添加一个
弧段
,该弧段结束于
端点
IsLargeArc
仅用于让绘图系统知道要绘制的弧的“一半”。另一个位于中间的
线段
被添加以完成
路径图

在花了一些时间阅读我的旧代数教科书之后,我为您提供了一个完全可行的解决方案

这使用Nuget软件包(免责声明:我是此软件包的作者)提供
INotifyPropertyChanged
支持,但是您应该能够轻松地更改您想要的任何事件系统。完整解决方案可从下载

XAML:

<Window
    x:Class="ViewingAngle.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:local="clr-namespace:ViewingAngle"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="525"
    Height="350"
    d:DataContext="{d:DesignInstance local:MainWindowVm}"
    mc:Ignorable="d">
    <DockPanel Margin="4">
        <StackPanel DockPanel.Dock="Bottom">
            <TextBlock Margin="4,4,4,0" Text="{Binding Path=FieldOfView, StringFormat='Field of View: {0}'}" />
            <Slider
                Margin="4"
                Maximum="360"
                Minimum="0"
                TickFrequency="5"
                TickPlacement="Both"
                Value="{Binding Path=FieldOfView}" />
            <TextBlock Margin="4,4,4,0" Text="{Binding Path=TargetAngle, StringFormat='Target Angle: {0}'}" />
            <Slider
                Margin="4"
                Maximum="360"
                Minimum="0"
                TickFrequency="5"
                TickPlacement="Both"
                Value="{Binding Path=TargetAngle}" />
        </StackPanel>

        <Viewbox Margin="4" Stretch="Uniform">
            <Canvas Width="500" Height="500">
                <Path
                    Fill="Blue"
                    Stroke="Blue"
                    StrokeThickness="1">
                    <Path.Data>
                        <PathGeometry>
                            <PathGeometry.Figures>
                                <PathFigure StartPoint="250,250">
                                    <LineSegment Point="{Binding Path=StartPoint}" />
                                    <ArcSegment
                                        IsLargeArc="{Binding Path=IsLargeArc}"
                                        Point="{Binding Path=EndPoint}"
                                        Size="250,250"
                                        SweepDirection="Clockwise" />
                                    <LineSegment Point="250,250" />
                                </PathFigure>
                            </PathGeometry.Figures>
                        </PathGeometry>
                    </Path.Data>
                </Path>
            </Canvas>
        </Viewbox>
    </DockPanel>
</Window>
所有的魔法都发生在
recreactearc
中,每当
TargetAngle
FieldOfView
发生更改时,就会调用它。所有的数学运算都必须以弧度为单位,所以它要做的第一件事就是转换值。它使用一些相当简单的涉及正弦和余弦的代数来计算
弧段的新
StartPoint
EndPoint
值(尽管我仍然需要查找数学,因为高中毕业后谁还记得这些东西?)

在XAML中,我放置了一些绑定到
TargetAngle
FieldOfView
的滑块,以允许您控制角度。它还包含绘制图形的
画布
,它位于
视图框
内,只是为了让指示器填满可用空间


画布
包含一个
路径
,该路径由一个
路径图
组成。
路径图
从250250开始(500 x 500
画布的中心
),将
线段
绘制到弧的起点,该起点绑定到
起点
。然后添加一个
弧段
,该弧段结束于
端点
IsLargeArc
仅用于让绘图系统知道要绘制的弧的“一半”。添加另一个位于中间的
线段
,以结束
路径图

您丢失了一条信息。从您的图片中,
Angle
确定切片的“宽度”,但我看不出您在哪里提供切片的“方向”。什么决定视野是朝向、向右、向左、向上、向下等?@BradleyUffner;事实上,在圆的中心,会有一个摄像机的图像,它是根据图面向东北方向的。因此,图中的视场是朝上的,角度是逆时针的。我现在不想计算三角,但我很确定你可以通过结合多边形和椭圆来实现
using System;
using System.Windows;
using AgentOctal.WpfLib;

namespace ViewingAngle
{
    class MainWindowVm : ViewModel
    {
        private const int Radius = 250;
        private const int CenterX = 250;
        private const int CenterY = 250;


        public MainWindowVm()
        {
            FieldOfView = 45;
            TargetAngle = 90;
        }

        private int _fieldOfView;
        public int FieldOfView
        {
            get { return _fieldOfView; }
            set
            {
                SetValue(ref _fieldOfView, value);
                RecalculateArc();
            }
        }

        private int _targetAngle;
        public int TargetAngle
        {
            get { return _targetAngle; }
            set
            {
                SetValue(ref _targetAngle, value);
                RecalculateArc();
            }
        }

        private double GetRadians(int angle)
        {
            return angle * Math.PI / 180;
        }

        private void RecalculateArc()
        {
            var targetAngle = GetRadians(_targetAngle);
            var fieldOfView = GetRadians(_fieldOfView);
            var halfFieldOfView = fieldOfView / 2;

            var startAngle = targetAngle - halfFieldOfView;
            var endAngle = targetAngle + halfFieldOfView;
            double angleDiff = endAngle - startAngle;
            IsLargeArc = angleDiff >= Math.PI;

            StartPoint = new Point(CenterX + Radius * Math.Cos(startAngle), CenterY + Radius * Math.Sin(startAngle));
            EndPoint = new Point(CenterX + Radius * Math.Cos(endAngle), CenterY + Radius * Math.Sin(endAngle));
        }

        private Point _startPoint;
        public Point StartPoint
        {
            get { return _startPoint; }
            set { SetValue(ref _startPoint, value); }
        }

        private Point _endPoint;
        public Point EndPoint
        {
            get { return _endPoint; }
            set { SetValue(ref _endPoint, value); }
        }

        private bool _isLargeArc;
        public bool IsLargeArc
        {
            get { return _isLargeArc; }
            set { SetValue(ref _isLargeArc, value); }
        }
    }
}