最近由於項目須要,須要實現一個位置校對的功能,大體的需求以下:有一個圖片,有一些位置信息,可是位置信息可能和實際有些誤差,須要作簡單調整,後面會對這張圖片進行切割等,作些處理。(位置信息鏈接起來是一個個小矩形。)git
解決以上問題的大體思路以下:使用canvas進行繪製,把圖片做爲canvas的背景,在canvas上繪製矩形,相似於qq截圖同樣,矩形框能夠使用鼠標拖動調整大小。而後在記下修改後的位置,提供給後面切割圖片使用。目前的關鍵問題就是實現相似qq截圖那樣能夠拖動的矩形。github
以上是實現的demo的效果。主要由定位點和連線組成。canvas
定位點主要是定位點的一些基本屬性和基本方法,主要包括繪製方法,移動方法。
其中:AnchorPointType爲定位點的類型;this
public enum AnchorPointType
{
/// <summary>
/// 上下
/// </summary>
NS,
/// <summary>
/// 左右
/// </summary>
WE,
/// <summary>
/// 右上
/// </summary>
NE,
/// <summary>
/// 左下
/// </summary>
SW,
/// <summary>
/// 右下
/// </summary>
NW,
/// <summary>
/// 左上
/// </summary>
SE
}
draw()方法用於繪製矩形:spa
public Rectangle Draw()
{
double offset = this.Width / 2;
Rectangle retc = new Rectangle()
{
Margin = new Thickness(this.X - offset, this.Y - offset, 0, 0),
Width = this.Width,
Height = this.Height,
Fill = Brushes.LightGoldenrodYellow,
Stroke = Brushes.Black,
StrokeThickness = 1,
DataContext = this.Key
};
this.retc = retc;
return retc;
}
move()方法用戶改變定位點位置調試
public void Move(double x,double y)
{
double offset = this.Width / 2;
this.retc.Margin = new Thickness(x-offset,y-offset,0,0);
this.X = x;
this.Y = y;
}
public void Init()
{
//按x軸分類
IEnumerable<IGrouping<double, Point>> pointXs = points.GroupBy(o => o.X);
//按y周分類
IEnumerable<IGrouping<double, Point>> pointYs = points.GroupBy(o => o.Y);
//繪製豎線
DrawXLine(pointXs);
//繪製橫線
DrawYLine(pointYs);
//設置定位點
AddAnchorPoints();
//繪製定位點而且添加事件
foreach (AnchorPoint anchorPoint in anchorPoints)
{
Rectangle rec=anchorPoint.Draw();
rec.MouseLeftButtonDown += new MouseButtonEventHandler(rec_MouseLeftButtonDown);
rec.MouseMove += new MouseEventHandler(rec_MouseMove);
canvas.Children.Add(rec);
}
//canvas添加事件
canvas.MouseLeftButtonUp += new MouseButtonEventHandler(canvas_MouseLeftButtonUp);
canvas.MouseMove += new MouseEventHandler(canvas_MouseMove);
canvas.MouseLeave += new MouseEventHandler(canvas_MouseLeave);
}
如上代碼:private void MoveLines(double x, double y)
{
List<Line> moveLines = new List<Line>();
moveLines = lines.Where(o => o.Y1 == curAnchorPoint.Y
|| o.Y2 == curAnchorPoint.Y
|| o.X1 == curAnchorPoint.X
|| o.X2 == curAnchorPoint.X).ToList();
foreach (Line line in moveLines)
{
if (line.Y1 == curAnchorPoint.Y)
{
line.Y1 = y;
}
if (line.Y2 == curAnchorPoint.Y)
{
line.Y2 = y;
}
if (line.X1 == curAnchorPoint.X)
{
line.X1 = x;
}
if (line.X2 == curAnchorPoint.X)
{
line.X2 = x;
}
}
}
點的聯動,和線的聯動方法相似,可是點的聯動要比線的聯動複雜,主要在如下三個方面:一、點的移動須要聯動中點的聯動。二、在矩形的四個頂點變更時,須要聯動其餘兩個相鄰的頂點,和相鄰兩條線的中點的聯動。三、不一樣的方向點的聯動,不同,會有不少if else。
因爲代碼較長,就不粘貼了,須要源代碼能夠去獲取源代碼。
線中點聯動:線的中點聯動須要考慮,移動的點是否關聯到計算這個中點的兩個點或者一個點,關聯到中點的這兩個點若是有改變,則這個中點就須要改變。主要代碼以下:code
private void MoveRefAnchorPoint(double x, double y,AnchorPoint movedAnchorPoint)
{
foreach (AnchorPoint anchorPoint in anchorPoints)
{
if (anchorPoint.RefPoint.Length == 2)
{
if (anchorPoint.RefPoint[0].X == x && anchorPoint.RefPoint[0].Y == y)
{
anchorPoint.RefPoint[0].X = movedAnchorPoint.X;
anchorPoint.RefPoint[0].Y = movedAnchorPoint.Y;
}
else if (anchorPoint.RefPoint[1].X == x && anchorPoint.RefPoint[1].Y == y)
{
anchorPoint.RefPoint[1].X = movedAnchorPoint.X;
anchorPoint.RefPoint[1].Y = movedAnchorPoint.Y;
}
anchorPoint.X = (anchorPoint.RefPoint[0].X + anchorPoint.RefPoint[1].X) / 2;
anchorPoint.Y = (anchorPoint.RefPoint[0].Y + anchorPoint.RefPoint[1].Y) / 2;
anchorPoint.Move();
}
}
}
以上爲單個關聯點改變的狀況的代碼,兩個關聯點都變更的代碼和這個相似。orm
因爲文字表達能力有限,另外說清點和線的關係,特別是點和線的聯動,確實有點困難,若是感興趣的話,強烈建議下載代碼進行調試閱讀。
https://github.com/wangyan9110/ProjectDemos/tree/master/WPFCanvasDemoxml