天天看點

29.Silverlight碰撞測試、檢測自定義控件碰撞,雷達掃描圖之掃描雷達點狀态

     雷達掃描圖中當雷達指針轉動掃描到某一個點上的時候,判斷這個點的CPU值是否已經超過60的警戒位置如果超過将此點設定為紅色。

        在Silverlight中我們的雷達指針是一直在做圓運動的,我們要随時檢測雷達指針的位置,以及雷達是否碰撞到一個Device裝置了。如果碰撞到 了,就檢測裝置CPU值為多少?在這裡我們需要解決兩個問題。第一、如何随時觀測雷達指針的目前位置?第二、如何檢測雷達指針是否碰撞接觸到了裝置點?

        針對第一個問題,需要做以下處理:

             •在本例中使用Timer控件,每隔50毫秒檢測一次目前的雷達指針控件位置

             •雷達指針的位置根據檢測目前雷達指針旋轉角度的正餘弦函數得到左上角點的X、Y位置,分别加上寬和高得到右下角點的位置。

        針對第二個問題,我們需要做以下處理:

             •根據雷達指針的左上角和右下角的兩個點的位置構造一個Rect結構A(注意Rect結構描述矩形的寬高和原點),然後同理根據Device自定義控件構造一個Rect結構。

             •檢測者A、B兩個Rect是否重合,如果重合則進行像素級别的對比是否碰撞接觸在一起。

             •因為有很多個裝置點,是以需要循環檢測每一個裝置點在某一個時間點是否和雷達指針碰撞。

        本篇執行個體源碼基于上一節所述,本節中将雷達指針單獨制作成為一個自定義控件,另外為裝置自定義控件增加了一個屬性IsOutStrip(設定如果超過警戒值則為紅色),現在我們來看看本篇關鍵源碼:

public MainPage() 

InitializeComponent(); 

AddCanvasTransform(); 

RandarPointer rpointer = new RandarPointer(); 

public void AddCanvasTransform() 

AddDevice(); 

//設定一個50毫秒啟動一次的定時器 

time = new Timer(CheckIsContent, rpointer, 0, 50); 

private void AddDevice() 

#region 添加閃動的裝置 

LayoutRoot.Children.Clear(); 

//添加雷達指針 

LayoutRoot.Children.Add(rpointer); 

for (int i = 0; i < 15; i++) 

Device dev = new Device(); 

//設定X、Y坐标和Z層次 

dev.SetValue(Canvas.TopProperty, dev.Y); 

dev.SetValue(Canvas.LeftProperty, dev.X); 

//設定 dev.Tag為控件的左上角的點坐标和右下角的點坐标 

double DevRight = dev.X + 16; 

double DevButtom = dev.Y + 16; 

dev.SetValue(Canvas.ZIndexProperty, 600); 

dev.Tag = dev.X + "|" + dev.Y + "|" + DevRight + "|" + DevButtom; 

LayoutRoot.Children.Add(dev); 

#endregion 

//添加一個Timer定時器檢測目前的指針的位置。 

Timer time; 

public void CheckIsContent(object state) 

this.rpointer.Dispatcher.BeginInvoke(new labelDelegete(UpdateLab)); 

public delegate void labelDelegete(); 

public void UpdateLab() 

Rectangle rectangle = rpointer.FindName("rectangle") as Rectangle; 

//擷取到目前雷達指針的左上角點的位置和右下角點的位置,指派給Tag 

double top = -Math.Sin(rpointer.rTransform.Angle) * 253 + 300; 

double left = -Math.Cos(rpointer.rTransform.Angle) * 253 + 300; 

double right = 300; 

double buttom = 300; 

rpointer.Tag = left + "|" + top + "|" + right + "|" + buttom; 

//循環擷取所有的Device控件的位置和目前時間雷達指針是否碰撞 

foreach (UIElement ui in LayoutRoot.Children) 

Device device = ui as Device; 

if (device != null) 

Rectangle rectangleblue = device.Rectangleblue; 

//檢測雷達指針是否碰撞到裝置, 

if (CheckCollision(device, rectangleblue, rpointer, rectangle)) 

//檢測裝置CPU占用值是否大于60%,如果大于則報警 

if (device.Value > 60) 

//讓其顯示為紅色 

device.IsOutStrip = true; 

/// <summary> 

/// 檢查控件的位置是否碰撞在一起 

/// </summary> 

/// <param name="control1">第一使用者控件</param> 

/// <param name="controlElem1">第一使用者控件内部需要檢測是否碰撞的控件</param> 

/// <param name="control2">第二使用者控件</param> 

/// <param name="controlElem2">第二使用者控件内部需要檢測是否碰撞的控件</param> 

/// <returns></returns> 

private bool CheckCollision(FrameworkElement control1, FrameworkElement controlElem1, FrameworkElement control2, FrameworkElement controlElem2) 

// 建立兩個Rect結構 

Rect rect1 = UserControlBounds(control1); 

Rect rect2 = UserControlBounds(control2); 

//檢測這兩個Rect結構是否重合 

rect1.Intersect(rect2); 

if (rect1 == Rect.Empty) 

// no collision - GET OUT! 

return false; 

else 

bool bCollision = false; 

Point ptCheck = new Point(); 

// 更精準的像素級别的碰撞對比 

for (int x = Convert.ToInt32(rect1.X); x < Convert.ToInt32(rect1.X + rect1.Width); x++) 

for (int y = Convert.ToInt32(rect1.Y); y < Convert.ToInt32(rect1.Y + rect1.Height); y++) 

ptCheck.X = x; 

ptCheck.Y = y; 

List<UIElement> hits = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(ptCheck, control1) as List<UIElement>; 

if (hits.Contains(controlElem1)) 

// we have a hit on the first control elem, now see if the second elem has a similar hit 

List<UIElement> hits2 = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(ptCheck, control2) as List<UIElement>; 

if (hits2.Contains(controlElem2)) 

bCollision = true; 

break; 

if (bCollision) break; 

return bCollision; 

/// 根據需要檢測的控件的坐标位置,繪制出需要檢測控件的副本Rect控件 

/// <param name="control"></param> 

public Rect UserControlBounds(FrameworkElement control) 

//重新建立一個Rect結構。 

string[] PointDirect = control.Tag.ToString().Split('|'); 

Point ptTopLeft = new Point(Convert.ToDouble(PointDirect[0]), Convert.ToDouble(PointDirect[1])); 

Point ptBottomRight = new Point(Convert.ToDouble(PointDirect[2]), Convert.ToDouble(PointDirect[3])); 

return new Rect(ptTopLeft, ptBottomRight); 

<a target="_blank" href="http://blog.51cto.com/attachment/201203/180614516.jpg"></a>

本文轉自程興亮 51CTO部落格,原文連結:http://blog.51cto.com/chengxingliang/822552

繼續閱讀