using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; using System.ComponentModel; using Microsoft.Expression.Shapes; namespace FLY.ControlLibrary { /// /// UserControl1.xaml 的交互逻辑 /// public partial class GraphScanCircular : UserControl, IGraphScanCircular, INotifyPropertyChanged { #region 私有成员变量 /// /// 中心 /// Point Center; /// /// 总半径 /// double Radius; /// /// 分区环,宽度 /// double BoltNoRingThickness; /// /// 最内环,宽度 /// double InnerRingThickness; /// /// 图表,宽度 /// double GraphThickness; double Avg; private string calstate_max = "null"; public string CalState_Max { get { return calstate_max; } set { if (calstate_max != value) { calstate_max = value; NotifyPropertyChanged("CalState_Max"); } } } private string calstate_min= "null"; public string CalState_Min { get { return calstate_min; } set { if (calstate_min != value) { calstate_min = value; NotifyPropertyChanged("CalState_Min"); } } } private string calstate_avg = "null"; public string CalState_Avg { get { return calstate_avg; } set { if (calstate_avg != value) { calstate_avg = value; NotifyPropertyChanged("CalState_Avg"); } } } private string calstate_2sigma = "null"; public string CalState_2Sigma { get { return calstate_2sigma; } set { if (calstate_2sigma != value) { calstate_2sigma = value; NotifyPropertyChanged("CalState_2Sigma"); } } } List BoltArc = new List(); #endregion #region IGraphScanCircular public static readonly DependencyProperty BoltCntProperty = DependencyProperty.Register("BoltCnt", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 88, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("BoltCnt"); }))); public int BoltCnt { get { return (int)GetValue(BoltCntProperty); } set { SetValue(BoltCntProperty, value); } } public static readonly DependencyProperty ManualCntProperty = DependencyProperty.Register("ManualCnt", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 8, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("ManualCnt"); }))); public int ManualCnt { get { return (int)GetValue(ManualCntProperty); } set { SetValue(ManualCntProperty, value); } } public static readonly DependencyProperty MPIsRightProperty = DependencyProperty.Register("MPIsRight", typeof(bool), typeof(GraphScanCircular), new PropertyMetadata( true, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("MPIsRight"); }))); public bool MPIsRight { get { return (bool)GetValue(MPIsRightProperty); } set { SetValue(MPIsRightProperty, value); } } public static readonly DependencyProperty OrgBoltNoProperty = DependencyProperty.Register("OrgBoltNo", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 1, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("OrgBoltNo"); }))); public int OrgBoltNo { get { return (int)GetValue(OrgBoltNoProperty); } set { SetValue(OrgBoltNoProperty, value); } } public static readonly DependencyProperty BoltNoWithManual1stProperty = DependencyProperty.Register("BoltNoWithManual1st", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 1, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("BoltNoWithManual1st"); }))); public int BoltNoWithManual1st { get { return (int)GetValue(BoltNoWithManual1stProperty); } set { SetValue(BoltNoWithManual1stProperty, value); } } public static readonly DependencyProperty AlarmProperty = DependencyProperty.Register("Alarm", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 1000, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("Alarm"); }))); public int Alarm { get { return (int)GetValue(AlarmProperty); } set { SetValue(AlarmProperty, value); } } public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 10000, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("Target"); }))); public int Target { get { return (int)GetValue(TargetProperty); } set { SetValue(TargetProperty, value); } } public static readonly DependencyProperty EmptyValueProperty = DependencyProperty.Register("EmptyValue", typeof(int), typeof(GraphScanCircular), new PropertyMetadata( 99999998, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("EmptyValue"); }))); public int EmptyValue { get { return (int)GetValue(EmptyValueProperty); } set { SetValue(EmptyValueProperty, value); } } public static readonly DependencyProperty MultiProperty = DependencyProperty.Register("Multi", typeof(double), typeof(GraphScanCircular), new PropertyMetadata( 100.0, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("Multi"); }))); public double Multi { get { return (double)GetValue(MultiProperty); } set { SetValue(MultiProperty, value); } } public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(GraphScanCircular), new PropertyMetadata( "Title", new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("Title"); }))); public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly DependencyProperty Title2Property = DependencyProperty.Register("Title2", typeof(string), typeof(GraphScanCircular), new PropertyMetadata( "Title2", new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScanCircular).NotifyPropertyChanged("Title2"); }))); public string Title2 { get { return (string)GetValue(Title2Property); } set { SetValue(Title2Property, value); } } ObservableCollection dataSource; public ObservableCollection DataSource { get { return dataSource; } set { if (dataSource != value) { if(dataSource!=null) dataSource.CollectionChanged-=_dataSource_CollectionChanged; dataSource = value; dataSource.CollectionChanged += _dataSource_CollectionChanged; NotifyPropertyChanged("DataSource"); } } } System.Collections.Specialized.NotifyCollectionChangedEventHandler _dataSource_CollectionChanged; public event EventHandler ShowSettingDialogEvent; #endregion public GraphScanCircular() { InitializeComponent(); _dataSource_CollectionChanged = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(dataSource_CollectionChanged); this.PropertyChanged += new PropertyChangedEventHandler(GraphScanCircular_PropertyChanged); this.run_title.DataContext = this; this.run_title2.DataContext = this; this.run_calstate.DataContext = this; Init(); DataBindAll_Init(); } void GraphScanCircular_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Target" || e.PropertyName == "Alarm") { Draw(); } else if ( (new string[]{ "BoltCnt", "OrgBoltNo", "ManualCnt", "MPIsRight", "BoltNoWithManual1st" }).Contains(e.PropertyName)) { Draw(); } } void dataSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { double multi = Multi; int emptyvalue = EmptyValue; //根据修改, 操作mYVal, 与 IsEmpty switch (e.Action) { case System.Collections.Specialized.NotifyCollectionChangedAction.Reset: { DataBindAll(); } break; case System.Collections.Specialized.NotifyCollectionChangedAction.Remove://修改X. 永远不执行 { DataBindAll(); } break; case System.Collections.Specialized.NotifyCollectionChangedAction.Replace://修改Y { DataBindAll(); } break; case System.Collections.Specialized.NotifyCollectionChangedAction.Add://添加 X,Y { DataBindAll(); } break; } } void Init() { Center = new Point(LayoutRoot.Width / 2, LayoutRoot.Width / 2); Radius = LayoutRoot.Width / 2; BoltNoRingThickness = 20; InnerRingThickness = (Radius - BoltNoRingThickness) / 5; GraphThickness = (Radius - InnerRingThickness - BoltNoRingThickness); } void Draw() { Clear(); UpdateCalState(); Draw_Background(); Draw_Manual(); Draw_BoltNo(); Draw_Datas(); Draw_Alarm(); } double TransformDegrees(double degrees) { if (MPIsRight) return -degrees + 90; else return -degrees - 90; } void Draw_BoltNo() { double startAngle; double endAngle; SolidColorBrush brush_line = new SolidColorBrush(Color.FromRgb(208, 208, 208)); Arc arc_org = null; TextBlock t_org = null; for (int i = 0; i < BoltCnt; i++) { startAngle = TransformDegrees((i + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt); endAngle = TransformDegrees((i + 1 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt); if (startAngle > endAngle) { double tmp = endAngle; endAngle = startAngle; startAngle = tmp; } Arc arc = new Arc() { ArcThickness = BoltNoRingThickness, ArcThicknessUnit = Microsoft.Expression.Media.UnitType.Pixel, StartAngle = startAngle, EndAngle = endAngle, Stretch = System.Windows.Media.Stretch.None, Stroke = System.Windows.Media.Brushes.White, Fill = System.Windows.Media.Brushes.Black, Width = Radius * 2, Height = Radius * 2 }; Point p = Polar.ToPoint( new Polar() { Degrees = (endAngle + startAngle) / 2, Radius = Radius - BoltNoRingThickness / 2 }, Center); TextBlock t = new TextBlock() { TextWrapping = System.Windows.TextWrapping.NoWrap, TextAlignment = System.Windows.TextAlignment.Center, Width = 20, Height = 15, Text = (i + 1).ToString(), FontFamily = new System.Windows.Media.FontFamily("Trebuchet MS"), FontWeight = System.Windows.FontWeights.Bold, Foreground = System.Windows.Media.Brushes.White }; t.SetValue(Canvas.LeftProperty, p.X - t.Width / 2); t.SetValue(Canvas.TopProperty, p.Y - t.Height / 2); if ((i + 1) == (int)OrgBoltNo) { //凸显!!!!!! arc_org = arc; t_org = t; } else { LayoutRoot.Children.Add(arc); LayoutRoot.Children.Add(t); } } if (arc_org != null) { double w = arc_org.EndAngle - arc_org.StartAngle; arc_org.Fill = Brushes.White;// new SolidColorBrush(Color.FromRgb(0x57, 0x9a, 0xab)); arc_org.Stroke = Brushes.Black; arc_org.Width += arc_org.ArcThickness; arc_org.ArcThickness *= 2; arc_org.Height = arc_org.Width; arc_org.Margin = new Thickness(Radius - arc_org.Width / 2); arc_org.StartAngle -= w / 2; arc_org.EndAngle += w / 2; LayoutRoot.Children.Add(arc_org); t_org.Foreground = Brushes.Black; LayoutRoot.Children.Add(t_org); } } void Draw_Manual() { double startAngle; double endAngle; for (int i = 0; i < ManualCnt; i++) { int start_boltindex = (i + 0) * BoltCnt / ManualCnt + BoltNoWithManual1st - 1; int end_boltindex = (i + 1) * BoltCnt / ManualCnt + BoltNoWithManual1st - 1; startAngle = TransformDegrees((start_boltindex + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt); endAngle = TransformDegrees((end_boltindex + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt); Point p1 = Polar.ToPoint( new Polar() { Degrees = startAngle, Radius = InnerRingThickness + GraphThickness }, Center); Point p2 = Polar.ToPoint( new Polar() { Degrees = startAngle, Radius = InnerRingThickness }, Center); Line l = new Line() { X1 = p1.X, Y1 = p1.Y, X2 = p2.X, Y2 = p2.Y, Stroke = new SolidColorBrush(Color.FromRgb(208, 208, 208)) }; //Point p = Polar.ToPoint( // new Polar() { Degrees = (endAngle + startAngle) / 2, Radius = InnerRingThickness + GraphThickness*3.5/4}, // Center); ////new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold); ////FontFamily="Trebuchet MS" FontSize="12" FontWeight="Bold" //TextBlock t = new TextBlock() //{ // TextWrapping = System.Windows.TextWrapping.NoWrap, // TextAlignment = System.Windows.TextAlignment.Center, // Width = 20, // Height = 15, // Text = (i + 1).ToString(), // FontFamily = new System.Windows.Media.FontFamily("Trebuchet MS"), // FontWeight = System.Windows.FontWeights.Bold //}; //t.SetValue(Canvas.LeftProperty, p.X - t.Width / 2); //t.SetValue(Canvas.TopProperty, p.Y - t.Height / 2); LayoutRoot.Children.Add(l); //LayoutRoot.Children.Add(t); } } void Draw_Background() { SolidColorBrush brush_line = new SolidColorBrush(Color.FromRgb(208, 208, 208)); SolidColorBrush brush_alarm = new SolidColorBrush(Color.FromRgb(0xff,0xc1,0xc1)); double r = InnerRingThickness; //最里面的圆 Ellipse ellipse_inner = new Ellipse() { Width = r * 2, Height = r * 2, Stroke = Brushes.Black, Margin = new Thickness(Radius - r) }; //-公差线 r = InnerRingThickness + GraphThickness / 4; Ellipse ellipse_alarm1 = new Ellipse() { Width = r * 2, Height = r * 2, Stroke = brush_alarm, Margin = new Thickness(Radius - r), StrokeThickness=2 }; //目标线 r = InnerRingThickness + GraphThickness * 2 / 4; Ellipse ellipse_target = new Ellipse() { Width = r * 2, Height = r * 2, Stroke = brush_line, Margin = new Thickness(Radius - r), }; //-公差线 r = InnerRingThickness + GraphThickness * 3 / 4; Ellipse ellipse_alarm2 = new Ellipse() { Width = r * 2, Height = r * 2, Stroke = brush_alarm, Margin = new Thickness(Radius - r), StrokeThickness = 2 }; LayoutRoot.Children.Add(ellipse_inner); LayoutRoot.Children.Add(ellipse_alarm1); LayoutRoot.Children.Add(ellipse_target); LayoutRoot.Children.Add(ellipse_alarm2); } void Draw_Datas()//初始化所有 BoltArc { double startAngle; double endAngle; if (BoltArc.Count > 0) { foreach (Arc arc in BoltArc) LayoutRoot.Children.Remove(arc); BoltArc.Clear(); } double percent = (double)Alarm / Target; if (percent < 0.01) percent = 0.01; for (int i = 0; i < BoltCnt ; i++) { startAngle = TransformDegrees((i + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt); endAngle = TransformDegrees((i + 1 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt); if (startAngle > endAngle) { double tmp = endAngle; endAngle = startAngle; startAngle = tmp; } double r; if (DataSource != null && i < DataSource.Count && DataSource[i] != EmptyValue) { r = ((DataSource[i] - Avg) / Avg) / (4 * percent) * GraphThickness; } else { r = 0; } double target_r = InnerRingThickness + GraphThickness / 2; Arc arc = new Arc() { ArcThicknessUnit = Microsoft.Expression.Media.UnitType.Pixel, StartAngle = startAngle, EndAngle = endAngle, Stretch = System.Windows.Media.Stretch.None, Fill = System.Windows.Media.Brushes.Green, Stroke = System.Windows.Media.Brushes.Black, StrokeThickness = 2 }; //-------------------------------------------------------------- //限制 if (r > GraphThickness / 2) { r = GraphThickness / 2; } else if (r < -GraphThickness / 2) { r = -GraphThickness / 2; } //-------------------------------------------------------------- //改变颜色 if (r > GraphThickness / 4) { arc.Fill = System.Windows.Media.Brushes.Orange; } else if (r < -GraphThickness / 4) { arc.Fill = System.Windows.Media.Brushes.Red; } else { arc.Fill = System.Windows.Media.Brushes.Green; } if (r > 0) { arc.Width = (target_r + r) * 2; } else { arc.Width = target_r * 2; } arc.ArcThickness = Math.Abs(r); arc.Height = arc.Width; arc.Margin = new Thickness(Radius - arc.Width / 2); LayoutRoot.Children.Add(arc); BoltArc.Add(arc); } } void Draw_Alarm() { double startAngle = TransformDegrees(0); double percent = (double)Alarm / Target; if (percent < 0.01) percent = 0.01; //负公差 Draw_Marker(new Polar() { Degrees = startAngle, Radius = InnerRingThickness + GraphThickness / 4 }, (-100 * percent).ToString() + "%"); //正公差 Draw_Marker(new Polar() { Degrees = startAngle, Radius = InnerRingThickness + GraphThickness * 3 / 4 }, (100 * percent).ToString() + "%"); } void Draw_Marker(Polar polar, string s) { Point p1 = Polar.ToPoint( polar, Center); SolidColorBrush brush_alarm = new SolidColorBrush(Color.FromRgb(0xff, 0xc1, 0xc1)); SolidColorBrush brush_line = new SolidColorBrush(Color.FromRgb(208, 208, 208)); double r = 15; //底 Ellipse ellipse_background = new Ellipse() { Width = r * 2, Height = r * 2, Fill = System.Windows.Media.Brushes.Red, Stroke = System.Windows.Media.Brushes.Black, StrokeThickness = 1 }; ellipse_background.SetValue(Canvas.LeftProperty, p1.X - ellipse_background.Width / 2); ellipse_background.SetValue(Canvas.TopProperty, p1.Y - ellipse_background.Width / 2); TextBlock t = new TextBlock() { TextWrapping = System.Windows.TextWrapping.NoWrap, TextAlignment = System.Windows.TextAlignment.Center, Width = 20, Height = 12, Text = s, FontFamily = new System.Windows.Media.FontFamily("Trebuchet MS"), FontWeight = System.Windows.FontWeights.Bold, Foreground = System.Windows.Media.Brushes.White, FontSize = 10 }; t.SetValue(Canvas.LeftProperty, p1.X - t.Width / 2); t.SetValue(Canvas.TopProperty, p1.Y - t.Height / 2); LayoutRoot.Children.Add(ellipse_background); LayoutRoot.Children.Add(t); } void Clear() { LayoutRoot.Children.Clear(); BoltArc.Clear(); } /// /// 与 Multi,EmptyValue,DataFirst,DataLast 相关 /// void UpdateCalState() { int emptyvalue = EmptyValue; double multi = Multi; if (DataSource == null) { goto _err; } List datlist; if (BoltCnt >= DataSource.Count()) { datlist = DataSource.ToList(); } else { datlist = DataSource.ToList().GetRange(0, BoltCnt); } var dats = from data in datlist where data != emptyvalue select data; if (dats.Count() == 0) { goto _err; } else { Avg = dats.Average(); double avg = dats.Average() / multi; double max = dats.Max() / multi; double min = dats.Min() / multi; double sum = 0; foreach (int dat in dats) { sum += Math.Pow(avg - (double)dat / multi, 2); } sum /= (dats.Count() - 1); double sigma = Math.Sqrt(sum); CalState_Max = "+"+(100.0 * (max - avg) / avg).ToString("N1") + "%"; CalState_Min = (100.0 * (min- avg) / avg).ToString("N1") + "%"; CalState_Avg = (avg).ToString("N1"); CalState_2Sigma = (200* sigma / avg).ToString("N1") + "%"; } return; _err: CalState_Max = "null"; CalState_Min = "null"; CalState_Avg = "null"; CalState_2Sigma = "null"; } void Update_OneData(int index) { if (index >= BoltArc.Count) return; double percent = (double)Alarm / Target; if (percent < 0.01) percent = 0.01; double r; if (DataSource != null && index < DataSource.Count && DataSource[index] != EmptyValue) { r = ((DataSource[index] - Avg) / Avg) / (4 * percent) * GraphThickness; } else { r = 0; } double target_r = InnerRingThickness + GraphThickness / 2; Arc arc = BoltArc[index]; //-------------------------------------------------------------- //限制 if (r > GraphThickness / 2) { r = GraphThickness / 2; } else if (r < -GraphThickness / 2) { r = -GraphThickness / 2; } //-------------------------------------------------------------- //改变颜色 if (r > GraphThickness / 4) { arc.Fill = System.Windows.Media.Brushes.Orange; } else if (r < -GraphThickness / 4) { arc.Fill = System.Windows.Media.Brushes.Red; } else { arc.Fill = System.Windows.Media.Brushes.Green; } arc.ArcThickness = Math.Abs(r); if (r > 0) { arc.Width = (target_r + r) * 2; } else { arc.Width = target_r * 2; } arc.Height = arc.Width; arc.Margin = new Thickness(Radius - arc.Width / 2); } void Update_Datas() { UpdateCalState(); for (int i = 0; i < BoltCnt; i++) Update_OneData(i); } #region INotifyPropertyChanged 成员 public void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; #endregion private void UserControl_Loaded(object sender, RoutedEventArgs e) { Draw(); } public void Button_Click(object sender, RoutedEventArgs e) { if (ShowSettingDialogEvent != null) ShowSettingDialogEvent(this, new EventArgs()); } bool batabindall_flag = false; System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer(); void DataBindAll_Init() { timer = new System.Windows.Threading.DispatcherTimer(); timer.Tick += new EventHandler(delegate(object sender, EventArgs e) { if (batabindall_flag) { batabindall_flag = false; Update_Datas(); } }); timer.Interval = TimeSpan.FromSeconds(0.2); timer.Start(); } void DataBindAll() { batabindall_flag = true; } } public interface IGraphScanCircular { /// /// 分区数 /// int BoltCnt { get; set; } /// /// 手动螺栓数 /// int ManualCnt { get; set; } /// /// 测厚仪测量点位置方向:Left, Right (也就是三角形在左还是右) /// bool MPIsRight { get; set; } /// /// 复位分区号,也就是三角形对应的 分区号 /// int OrgBoltNo { get; set; } /// /// 第1个手动螺栓 对应于 分区号 /// int BoltNoWithManual1st { get; set; } /// /// 工艺值 /// int Alarm { get; set; } /// /// 只能是自动目标值, target 与 alarm 组合使用,工艺% /// int Target { get; set; } /// /// 空的数据,定义某个值为空,默认为 99999998 /// int EmptyValue { get; set; } /// /// 放大倍数, 目标值= Target/放大倍数 /// double Multi { get; set; } /// /// 标题 /// string Title { get; set; } /// /// 副标题 /// string Title2 { get; set; } /// /// 数据源 /// ObservableCollection DataSource { get; set; } /// /// 弹出设置界面 /// event EventHandler ShowSettingDialogEvent; } /// /// Polar 12点方向=0°,3点方向=90°,6点方向=180°,9点方向=270° /// Point 左上角 x=0,y=0; 右上角 x=100, y=0; 左下角 x=0,y=100; /// class Polar { public double Degrees;//角度制!!! public double Radius; public static Point ToPoint(Polar polar, Point center) { Point p = new Point(); Vector v = new Vector(); v.Y = -polar.Radius * Math.Cos(DegreesToRadians(polar.Degrees)); v.X = polar.Radius * Math.Sin(DegreesToRadians(polar.Degrees)); p = center + v; return p; } public static double DegreesToRadians(double degrees) { double radians = Math.PI / 180 * degrees; return radians; } } }