1、问题以及解决办法

最近因为项目需要,需要实现一个位置校对的功能,大致的需求如下:有一个图片,有一些位置信息,但是位置信息可能和实际有些偏差,需要做简单调整,后面会对这张图片进行切割等,做些处理。(位置信息连接起来是一个个小矩形。)

解决以上问题的大致思路如下:使用canvas进行绘制,把图片作为canvas的背景,在canvas上绘制矩形,类似于qq截图一样,矩形框可以使用鼠标拖动调整大小。然后在记下修改后的位置,提供给后面切割图片使用。目前的关键问题就是实现类似qq截图那样可以拖动的矩形。

2、实现的效果预览

以上是实现的demo的效果。主要由定位点和连线组成。

3、可变矩形实现

  1. 定位点

    定位点主要用于描述在矩形上的小方框,鼠标拖动的事件就是由它触发,它位置的移动会联动相关线的移动。

定位点主要是定位点的一些基本属性和基本方法,主要包括绘制方法,移动方法。

其中:AnchorPointType为定位点的类型;

    public enum AnchorPointType
{
/// <summary>
/// 上下
/// </summary>
NS,
/// <summary>
/// 左右
/// </summary>
WE,
/// <summary>
/// 右上
/// </summary>
NE,
/// <summary>
/// 左下
/// </summary>
SW,
/// <summary>
/// 右下
/// </summary>
NW,
/// <summary>
/// 左上
/// </summary>
SE
}

draw()方法用于绘制矩形:

        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;
}
  1. 可变矩形

    这部分主要实现绘制矩形功能,主要代码如下:

        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);
    }

    如上代码:

    如上代码:

    1、按x轴,y轴分类

    2、绘制竖线,横线

    3、设置定位点

    4、绘制定位点并且添加事件监听

    5、给canvas添加事件

    给每个定位点添加鼠标MouseMove和MouseLeftButtonDown事件,给canvas添加MouseMove,MouseLeave,MouseLeftButtonUp事件。

    具体代码不在粘贴了,如果需要代码,可以去下载源代码

  2. 矩形线联动

    矩形线联动,主要是以点带线,通过判断线是否和动点相关联,联动相关的线。主要代码如下:

         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;
    }
    }
    }
  3. 定位点联动

点的联动,和线的联动方法类似,但是点的联动要比线的联动复杂,主要在以下三个方面:1、点的移动需要联动中点的联动。2、在矩形的四个顶点变动时,需要联动其他两个相邻的顶点,和相邻两条线的中点的联动。3、不同的方向点的联动,不一样,会有很多if else。

由于代码较长,就不粘贴了,需要源代码可以去获取源代码。

线中点联动:线的中点联动需要考虑,移动的点是否关联到计算这个中点的两个点或者一个点,关联到中点的这两个点如果有改变,则这个中点就需要改变。主要代码如下:

        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();
}
}
}

以上为单个关联点改变的情况的代码,两个关联点都变动的代码和这个类似。

4、获取源代码

由于文字表达能力有限,另外说清点和线的关系,特别是点和线的联动,确实有点困难,如果感兴趣的话,强烈建议下载代码进行调试阅读。

https://github.com/wangyan9110/ProjectDemos/tree/master/WPFCanvasDemo

WPF使用Canvas绘制可变矩形的更多相关文章

  1. 使用canvas绘制渐变色矩形和使用按键控制人物移动

    使用canvas绘制渐变色矩形和使用按键控制人物移动 1.使用canvas绘制渐变色矩形 效果演示 相关代码: <!DOCTYPE html> <html lang="en ...

  2. HTML5 在canvas绘制一个矩形

    笔者:本笃庆军 原文地址:http://blog.csdn.net/qingdujun/article/details/32930501 一.绘制矩形 canvas使用原点(0,0)在左上角的坐标系统 ...

  3. canvas 绘制圆角矩形

    <!DOCTYPE HTML> <head> <meta charset = "utf-8"> <title>canvas</ ...

  4. canvas 绘制矩形和圆形

    canvas绘制有两神方法:1).填充(fill)填充是将图形内部填满. 2).绘制边框 (stroke)绘制边框是不把图形内部填满,只是绘制图形的外框. 当我们在绘制图形的时候,首先要设定好绘制的样 ...

  5. Canvas 绘制矩形,圆形,不规则图形(线条),渐变等图像效果

    绘制矩形: getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. fillStyle 方法将其染成红色,fill ...

  6. canvas绘制矩形

    canvas绘制矩形 方法 fillRect(x, y, width, height) 画一个实心的矩形 clearRect(x, y, width, height) 清除一块儿矩形区域 stroke ...

  7. h5学习-canvas绘制矩形、圆形、文字、动画

    绘制矩形<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...

  8. canvas绘制线和矩形

    ###canvas绘制矩形 HTML中的元素canvas只支持一种原生的图形绘制:矩形.所有其他的图形的绘制都至少需要生成一条路径 1.绘制矩形 canvas提供了三种方法绘制矩形: ----> ...

  9. canvas绘制形状

    栅格 之前简单模板中有个宽/高150px的canvas元素.如下图所示,canvas元素默认被网格所覆盖.通常来说网格中的一个单元相当于canvas元素中的一像素.栅格的起点为左上角(坐标为(0,0) ...

随机推荐

  1. Extjs的grid的单元格中加载超链接和按钮

    效果: 户型图列显示的图片实际上就是一个超链接. 添加一个Button分2个步骤:1.在列头中定义超链接列或者Button列的HTML代码,也就是Render 2.添加该Button的事件处理函数.其 ...

  2. NIO-新的io操作方式

    1.BIO带来的挑战 BIO即阻塞IO,不管是磁盘IO,还是网络IO,数据在写入OutputStream或者从InputStream读取时都有可能发生阻塞,一旦有阻塞,当前线程将会被挂起,即线程进入非 ...

  3. 多线程本地图片载入演示样例【OpenCV】【Pthread】

    Pthread barrier的简单使用演示样例: C++代码例如以下: // ThreadingLoadImages.cpp : 定义控制台应用程序的入口点. // #include "s ...

  4. 如何生成唯一的server Id,server_id为何不能重复?

    我们都知道MySQL用server-id来唯一的标识某个数据库实例,并在链式或双主复制结构中用它来避免sql语句的无限循环.这篇文章分享下我对server-id的理解,然后比较和权衡生成唯一serve ...

  5. ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

    开发说测试环境在删除表的时候,报了如下错误: SQL> drop table tke purge; drop table tke purge * ERROR at line 1: ORA-000 ...

  6. 团队工作效率分析工具gitstats

    如果你是团队领导,关心团队的开发效率和工作激情:如果你是开源软件开发者,维护者某个repo:又或者,你关心某个开源软件的开发进度,那么你可以试一试gitstats. gitstats 是一个git仓库 ...

  7. R语言编程艺术#01#数据类型向量(vector)

    R语言最基本的数据类型-向量(vector) 1.插入向量元素,同一向量中的所有的元素必须是相同的模式(数据类型),如整型.数值型(浮点数).字符型(字符串).逻辑型.复数型等.查看变量的类型可以用t ...

  8. A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets(中英双语)

    文章标题 A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets 且谈Apache Spark的API三剑客:RDD.Dat ...

  9. 【XMPP】XMPP协议之原理篇

    XMPP协议简介 XMPP协议(Extensible Messaging and Presence Protocol,可扩展消息处理现场协议)是一种基于XML的协议. 目的是为了解决及时通信标准而提出 ...

  10. linux设置开机自启动

    一..在/etc/rc.local文件中添加自启动命令 执行命令: 编辑"/etc/rc.local",添加你想开机运行的命令 运行程序脚本:然后在文件最后一行添加要执行程序的全路 ...