中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

WPF怎么實現雷達掃描圖的繪制

發布時間:2022-05-10 16:21:17 來源:億速云 閱讀:174 作者:iii 欄目:開發技術

這篇文章主要介紹了WPF怎么實現雷達掃描圖的繪制的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇WPF怎么實現雷達掃描圖的繪制文章都會有所收獲,下面我們一起來看看吧。

制作思路

  • 繪制圓形(或者稱之輪)

  • 繪制分割線

  • 繪制掃描范圍

  • 添加掃描點

具體實現

首先我們使用自定義的控件。你可以使用vs自動添加,也可以手動創建類。注意手動創建時要創建Themes/Generic.xaml的文件路徑哦。

控件繼承自itemscontrol,取名叫做Radar。

我們第一步思考如何實現圓形或者輪,特別是等距的輪。

我們可以使用簡單的itemscontrol的WPF控件,通過自定義ItemTemplate就可以簡單的創建了。

因為要顯示圓,所以使用Ellipse是最簡單的事情。

又因為要在同一個區域內,顯示同心圓,我們將面板改為Grid,利用疊加的特性去構造同心圓。

既然我們用了itemscontrol 來承載圈輪,直接讓這個圈可自定義呢?

所以,我們構造一個集合依賴屬性。

/// <summary>
        /// 每圈的大小
        /// </summary>
        public FreezableCollection<RadarSize> RadarCircle
        {
            get { return (FreezableCollection<RadarSize>)GetValue(RadarCircleProperty); }
            set { SetValue(RadarCircleProperty, value); }
        }

        /// <summary>
        /// 每圈的大小
        /// </summary>
        public static readonly DependencyProperty RadarCircleProperty =
            DependencyProperty.Register("RadarCircle", typeof(FreezableCollection<RadarSize>), typeof(Radar), new PropertyMetadata(new PropertyChangedCallback(OnRadarCircelValueChanged)));

對應泛型類可以參考源代碼,基本元素就是綁定ellipse的參數

<ItemsControl Grid.ColumnSpan="2" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="ic"  ItemsSource="{TemplateBinding RadarCircle }">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Grid IsItemsHost="True"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Ellipse Width="{Binding  Width}" Height="{Binding Height}"  Stroke="{Binding Color}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
    </ItemsControl>

哇啦,圖像就出來了。

WPF怎么實現雷達掃描圖的繪制

同理,我們創建分割線也是同樣的過程。

對于分割線的切割算法,我們使用圓上點的坐標可以通過( rcos,rsin)=》(x,y) ,也就是極坐標。

關于此部分代碼是放在布局塊內ArrangeOverride,也可以放置在OnReader。

下面是局部代碼,完整可以參考源代碼

var angle = 180.0 / 6;
            circlesize = size.Height > size.Width ? size.Width : size.Height;
            RadarFillWidth = circlesize;
            var midx = circlesize / 2.0;
            var midy = circlesize / 2.0;
            circlesize = circlesize / 2;
            RadarRadius = circlesize;
            //默認為6個
            for (int i = 0; i < 6; i++)
            {
                var baseangel = angle * i;
                var l1 = new Point(midx + circlesize * Math.Cos(Rad(baseangel)), midy - circlesize * Math.Sin(Rad(baseangel)));
                var half = baseangel + 180;
                var l2 = new Point(midx + circlesize * Math.Cos(Rad(half)), midy - circlesize * Math.Sin(Rad(half)));
                RadarLineSize radarLine = new RadarLineSize();
                radarLine.Start = l1;
                radarLine.End = l2;
                radarLine.Color = RadarLineColor;
                RadarLine.Add(radarLine);
            }
            return size;

依賴屬性

/// <summary>
        /// 雷達圖的分割線,目前固定為6,可以自行修改
        /// </summary>
        public FreezableCollection<RadarLineSize> RadarLine
        {
            get { return (FreezableCollection<RadarLineSize>)GetValue(RadarLineProperty); }
            set { SetValue(RadarLineProperty, value); }
        }

        /// <summary>
        /// 雷達圖的分割線,目前固定為6,可以自行修改
        /// </summary>
        public static readonly DependencyProperty RadarLineProperty =
            DependencyProperty.Register("RadarLine", typeof(FreezableCollection<RadarLineSize>), typeof(Radar));

xaml代碼

<ItemsControl Grid.ColumnSpan="2" Grid.RowSpan="2"  VerticalAlignment="Center" HorizontalAlignment="Center"  x:Name="ic2"   ItemsSource="{TemplateBinding RadarLine }">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Grid IsItemsHost="True"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Line X1="{Binding Start.X}" Y1="{Binding Start.Y}" X2="{Binding End.X}" Y2="{Binding End.Y}"  Stroke="{Binding Color}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>

WPF怎么實現雷達掃描圖的繪制

下一步就是扇形掃描了。

我們使用一個完整的圓,將其內部顏色填充為線性刷就可以得到一個效果不錯的掃描了。

/// <summary>
        /// 雷達掃描的顏色
        /// </summary>
        public Brush RadarColor
        {
            get { return (Brush)GetValue(RadarColorProperty); }
            set { SetValue(RadarColorProperty, value); }
        }

        /// <summary>
        /// 雷達掃描的顏色
        /// </summary>
        public static readonly DependencyProperty RadarColorProperty =
            DependencyProperty.Register("RadarColor", typeof(Brush), typeof(Radar));

為了更好的定義這個圓,我們將radar的template使用grid面板等距分成四個區域(其實沒啥用,主要是為了扇形掃描時做圓心選擇的line,也可以不分成四個)。

在考慮動畫,只需要做圓形360的選擇就可以了。為了更好應用,我們創一個paly的依賴屬性來播放動畫。

/// <summary>
        /// 是否播放動畫
        /// </summary>
        public bool Play
        {
            get { return (bool)GetValue(PlayProperty); }
            set { SetValue(PlayProperty, value); }
        }

        /// <summary>
        /// 是否播放動畫
        /// </summary>
        public static readonly DependencyProperty PlayProperty =
            DependencyProperty.Register("Play", typeof(bool), typeof(Radar), new PropertyMetadata(false));

xaml代碼( 部分)

<Style.Resources>
            <LinearGradientBrush x:Key="radarcolor" StartPoint="0,0" EndPoint="0,1">
                <GradientStop Offset="0" Color="Lime" />
                <GradientStop Offset="0.5" Color="Transparent" />
            </LinearGradientBrush>
        </Style.Resources>
  <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:Radar}">
                    <Grid x:Name="grid"   >
                        <Grid.RowDefinitions>
                            <RowDefinition Height="2*"/>
                            <RowDefinition Height="2*"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="2*"/>
                            <ColumnDefinition Width="2*"/>
                        </Grid.ColumnDefinitions>
                        <ItemsControl Grid.ColumnSpan="2" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="ic"  ItemsSource="{TemplateBinding RadarCircle }">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Grid IsItemsHost="True"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Ellipse Width="{Binding  Width}" Height="{Binding Height}"  Stroke="{Binding Color}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                        <ItemsControl Grid.ColumnSpan="2" Grid.RowSpan="2"  VerticalAlignment="Center" HorizontalAlignment="Center"  x:Name="ic2"   ItemsSource="{TemplateBinding RadarLine }">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Grid IsItemsHost="True"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Line X1="{Binding Start.X}" Y1="{Binding Start.Y}" X2="{Binding End.X}" Y2="{Binding End.Y}"  Stroke="{Binding Color}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                        <Ellipse Fill="{TemplateBinding RadarColor}"   Grid.ColumnSpan="2" Grid.RowSpan="2"  x:Name="ep" RenderTransformOrigin="0.5,0.5" Width="{TemplateBinding RadarFillWidth}" Height="{TemplateBinding RadarFillWidth}">
                            <Ellipse.RenderTransform>
                                <RotateTransform x:Name="rtf" />
                            </Ellipse.RenderTransform>
                        </Ellipse>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Play" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard  x:Name="bs" >
                                    <Storyboard >
                                        <DoubleAnimation Storyboard.TargetName="rtf" Storyboard.TargetProperty="Angle"   From="0" To="360" Duration="0:0:2" RepeatBehavior="Forever"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                        </Trigger>
                        <Trigger Property="Play" Value="False">
                            <Trigger.EnterActions>
                                <RemoveStoryboard BeginStoryboardName="bs"/>
                            </Trigger.EnterActions>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>

效果

WPF怎么實現雷達掃描圖的繪制

那么剩下就是掃描點的操作。

因為我們的控件是繼承ItemsControl,我們到現在還沒有利用ItemsSource這個屬性。

所以我們要制作一個子控件來呈現掃描點。

由于子控件較為簡單,只不過是一個圓而已。我們就讓子控件繼承Control就好了。

一切從簡,我們不弄布局這一套了,直接在父控件中使用Canvas面板,子控件增加屬性Left,Top這兩個依賴屬性。

重點說一下,子控件中存在一個linscar的方法,是為了將點如果在雷達外側時,按照同角度縮放到最外層的方法。就是通過半徑重新計算一邊極坐標。

/// <summary>
        /// 線性縮放
        /// </summary>
        /// <param name="size">半徑</param>
        internal void LineScar(double size)
        {
            var midpoint = new Vector(size, size);
            var vp = new Vector(Left, Top);
            var sub = vp - midpoint;
            var angle = Vector.AngleBetween(sub, new Vector(size, 1));
            angle = angle > 0 ? angle : angle + 360;
            //距離大于半徑,根據半徑重新繪制
            if (sub.Length >= size)
            {
                Top = size - size * Math.Sin(Rad(angle)) - Width / 2;
                Left = size + size * Math.Cos(Rad(angle)) - Width / 2;
            }
        }

那么在父項中如何擺放呢?

我們剛才說父項使用canvas繪圖,所以我們在radar中修改itempanel的面板屬性,下面代碼存在于父項xaml

<Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <Canvas IsItemsHost="True"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>

子項代碼如下,比較少就貼了

xaml代碼

<Style TargetType="local:RadarItem">
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="Margin" Value="0" />
        <Setter Property="Canvas.Top" Value="{Binding RelativeSource={RelativeSource Mode=Self},Path=Top}" />
        <Setter Property="Canvas.Left" Value="{Binding RelativeSource={RelativeSource Mode=Self},Path=Left}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:RadarItem">
                    <Border  >
                        <Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Fill="{TemplateBinding Color}" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

radarItem

/// <summary>
    /// 雷達子項 
    /// </summary>
    public class RadarItem : Control
    {

        static RadarItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RadarItem), new FrameworkPropertyMetadata(typeof(RadarItem)));
        }
        public RadarItem()
        {

        }

        /// <summary>
        /// 轉弧度
        /// </summary>
        /// <param name="val">角度</param>
        /// <returns>弧度制</returns>
        double Rad(double val)
        {
            return val * Math.PI / 180;
        }
        /// <summary>
        /// 線性縮放
        /// </summary>
        /// <param name="size">半徑</param>
        internal void LineScar(double size)
        {
            var midpoint = new Vector(size, size);
            var vp = new Vector(Left, Top);
            var sub = vp - midpoint;
            var angle = Vector.AngleBetween(sub, new Vector(size, 1));
            angle = angle > 0 ? angle : angle + 360;
            //距離大于半徑,根據半徑重新繪制
            if (sub.Length >= size)
            {
                Top = size - size * Math.Sin(Rad(angle)) - Width / 2;
                Left = size + size * Math.Cos(Rad(angle)) - Width / 2;
            }
        }

        /// <summary>
        /// 頂部距離,用canvas.top繪制
        /// </summary>
        public double Top
        {
            get { return (double)GetValue(TopProperty); }
            set { SetValue(TopProperty, value); }
        }

        /// <summary>
        /// 頂部距離,用canvas.top繪制
        /// </summary>
        public static readonly DependencyProperty TopProperty =
            DependencyProperty.Register("Top", typeof(double), typeof(RadarItem), new PropertyMetadata(0.0));


        /// <summary>
        /// 左側距離,用于canvas.left繪制
        /// </summary>
        public double Left
        {
            get { return (double)GetValue(LeftProperty); }
            set { SetValue(LeftProperty, value); }
        }

        /// <summary>
        /// 左側距離,用于canvas.left繪制
        /// </summary>
        public static readonly DependencyProperty LeftProperty =
            DependencyProperty.Register("Left", typeof(double), typeof(RadarItem), new PropertyMetadata(0.0));


        /// <summary>
        /// 填充顏色
        /// </summary>
        public Brush Color
        {
            get { return (Brush)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        /// <summary>
        /// 填充顏色
        /// </summary>
        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Brush), typeof(RadarItem), new PropertyMetadata(new SolidColorBrush(Colors.Red)));
    }

于是乎我們就得到了一個雷達掃描圖

WPF怎么實現雷達掃描圖的繪制

關于“WPF怎么實現雷達掃描圖的繪制”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“WPF怎么實現雷達掃描圖的繪制”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

wpf
AI

白城市| 鹤岗市| 鞍山市| 高清| 大姚县| 兴义市| 台前县| 徐州市| 霸州市| 个旧市| 建阳市| 湟源县| 乌兰察布市| 中牟县| 资中县| 兴安县| 余庆县| 贡觉县| 周至县| 蛟河市| 杭锦旗| 安义县| 龙井市| 横峰县| 邵武市| 奉化市| 呼和浩特市| 海盐县| 霸州市| 彭山县| 霍邱县| 宜君县| 东乌珠穆沁旗| 闸北区| 靖边县| 启东市| 九龙城区| 新蔡县| 景谷| 临沭县| 万山特区|