1.    内容简介

本文旨在解决任意多边形切割折线,获取切割之后的折线集合。

本文实现的算法内容包括:判断两条线段是否相交,如若相交,获取交点集合、对线上的点集,按斜率方向排序、判断点是否在多边形内、获取线段和任意多边形的交点集合、中点算法、获取任意多边形裁剪折线的线段集合。

2.    效果实现

3.    算法实现

a)    本文使用到的命名空间

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Shapes;

命名空间

b)    源代码实现

 public partial class Help
{ #region 线段与多边形的交点集合,按从p1到p2的方向进行排序
/// <summary>
/// 对一线段与多边形的交点集合,按从p1到p2的方向进行排序
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="interPoints"></param>
/// <returns></returns>
public List<Point> SortPointsBySlopeOfLine(Point p1, Point p2, List<Point> interPoints)
{
List<Point> points = new List<Point>();
List<Point> newInterPoints = new List<Point>();
points.Add(p1);
if (Equals(p1.X, p2.X))//垂直线段
{
if (p1.Y > p2.Y)
{
newInterPoints = interPoints.OrderByDescending(t => t.Y).ToList();
}
else
{
newInterPoints = interPoints.OrderBy(t => t.Y).ToList();
}
}
else
{
if (Equals(p1.Y, p2.Y))//水平线段
{
if (p1.X > p2.X)
{
newInterPoints = interPoints.OrderByDescending(t => t.X).ToList();
}
else
{
newInterPoints = interPoints.OrderBy(t => t.X).ToList();
} }
else//普通斜率线段,按x或y都行
{
if (p1.X > p2.X)
{
newInterPoints = interPoints.OrderByDescending(t => t.X).ToList();
}
else
{
newInterPoints = interPoints.OrderBy(t => t.X).ToList();
} } } foreach (Point interPoint in newInterPoints)
{
points.Add(interPoint);
}
points.Add(p2);
return points;
}
#endregion #region 获取线段和线段的交点 private double eps = 1e-;
/// <summary>
/// 判断一个数值是否在误差范围内
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
private bool zero(double x)
{ return (((x) > ? (x) : -(x)) < eps);
} /// <summary>
/// 计算交叉乘积(P1-P0)x(P2-P0)
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p0"></param>
/// <returns></returns>
private double xmult(Point p1, Point p2, Point p0)
{
return (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y);
} /// <summary>
/// 判点是否在线段上,包括端点
/// </summary>
/// <param name="p"></param>
/// <param name="l1"></param>
/// <param name="l2"></param>
/// <returns></returns>
private bool dot_online_in(Point p, Point l1, Point l2)
{
return zero(xmult(p, l1, l2)) && (l1.X - p.X) * (l2.X - p.X) < eps && (l1.Y - p.Y) * (l2.Y - p.Y) < eps;
} /// <summary>
/// 判两点在线段同侧,点在线段上返回0
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="l1"></param>
/// <param name="l2"></param>
/// <returns></returns>
private bool same_side(Point p1, Point p2, Point l1, Point l2)
{
return xmult(l1, p1, l2) * xmult(l1, p2, l2) > eps;
} /// <summary>
/// 判断两直线平行
/// </summary>
/// <param name="u1"></param>
/// <param name="u2"></param>
/// <param name="v1"></param>
/// <param name="v2"></param>
/// <returns></returns>
private bool parallel(Point u1, Point u2, Point v1, Point v2)
{
return zero((u1.X - u2.X) * (v1.Y - v2.Y) - (v1.X - v2.X) * (u1.Y - u2.Y));
} /// <summary>
/// 判三点共线
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <returns></returns>
private bool dots_inline(Point p1, Point p2, Point p3)
{
return zero(xmult(p1, p2, p3));
} /// <summary>
/// 判两线段相交,包括端点和部分重合
/// </summary>
/// <param name="u1"></param>
/// <param name="u2"></param>
/// <param name="v1"></param>
/// <param name="v2"></param>
/// <returns></returns>
private bool intersect_in(Point u1, Point u2, Point v1, Point v2)
{
if (!dots_inline(u1, u2, v1) || !dots_inline(u1, u2, v2))
return !same_side(u1, u2, v1, v2) && !same_side(v1, v2, u1, u2);
return dot_online_in(u1, v1, v2) || dot_online_in(u2, v1, v2) || dot_online_in(v1, u1, u2) || dot_online_in(v2, u1, u2);
} /// <summary>
/// 计算两线段交点,请判线段是否相交(同时还是要判断是否平行!)
/// </summary>
/// <param name="u1"></param>
/// <param name="u2"></param>
/// <param name="v1"></param>
/// <param name="v2"></param>
/// <param name="ret"></param>
/// <returns></returns>
private int GetIntersectionPoint(Point u1, Point u2, Point v1, Point v2, out Point ret)
{
ret = u1;
if (parallel(u1, u2, v1, v2) || !intersect_in(u1, u2, v1, v2))
{
return ;
}
double t = ((u1.X - v1.X) * (v1.Y - v2.Y) - (u1.Y - v1.Y) * (v1.X - v2.X))
/ ((u1.X - u2.X) * (v1.Y - v2.Y) - (u1.Y - u2.Y) * (v1.X - v2.X));
ret.X += (u2.X - u1.X) * t;
ret.Y += (u2.Y - u1.Y) * t;
return ;
}
#endregion #region 多边形包含点
/// <summary>
/// 判断多边形是否包含某个点
/// </summary>
/// <param name="poly">多边形边框上每个角的点坐标数组</param>
/// <param name="p">要进行判断的点</param>
/// <returns>true:包含; false:不包含</returns>
public bool InPoly(Polygon polygon, Point p)
{ Point[] poly = polygon.Points.ToArray();
int i = , f = ;
double xi = , a = , b = , c = ;
Point ps, pe;
///遍历每一个点
/// Microsoft.VisualBasic.Information.UBound 获取最大下标,等同于 poly.Count-2
for (i = ; i <= Microsoft.VisualBasic.Information.UBound(poly, ); i++)
{
ps = poly[i]; if (i < Microsoft.VisualBasic.Information.UBound(poly, ))
{
pe = poly[i + ];
}
else
{
pe = poly[];
}
GetStdLine(ps, pe, ref a, ref b, ref c);
if (a != )
{
xi = - ((b * p.Y + c) / a);
if (xi == p.X)
{
return true;
}
else if (xi < p.X)
{
f = f + Sgn(pe.Y - p.Y) - Sgn(ps.Y - p.Y);
}
}
}
return f != ;
} /// <summary>
/// 根据两个点的坐标求经过两点的直线的标准方程参数A、B、C
/// </summary>
/// <param name="ps"></param>
/// <param name="pe"></param>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
private void GetStdLine(Point ps, Point pe, ref double a, ref double b, ref double c)
{
double xs, ys, xe, ye;
double p1, p2;
xs = ps.X;
ys = ps.Y;
xe = pe.X;
ye = pe.Y;
p1 = (xs * ye);
p2 = (xe * ys);
if (p1 == p2)
{
if (xs == )
{
if (xe == )
{
a = ;
b = ;
c = ;
}
else if (ys == )
{
a = ye;
b = - xe;
c = ;
}
}
else if (ye == )
{
if (ys == )
{
a = ;
b = ;
c = ;
}
else if (xe == )
{
a = - ys;
b = xs;
c = ;
}
}
}
else
{
a = (ys - ye) / (p1 - p2);
c = ;
if (ys == )
{
if (ye == )
{
b = ;
c = ;
}
else
{
b = - ((a * xe + ) / ye);
}
}
else
{
b = - ((a * xs + ) / ys);
}
}
}
private int Sgn(double a)
{
if (a == )
{
return ;
}
else if (a < )
{
return -;
}
else
{
return ;
}
} #endregion /// <summary>
/// 求出线段和多边形的交点,不包括p1p2
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="polygon"></param>
/// <returns></returns>
public List<Point> GetInterPoints(Point p1, Point p2, Polygon polygon)
{
List<Point> interPoints = new List<Point>();
List<Point> polygonPoints = polygon.Points.ToList();
for (int i = ; i < polygonPoints.Count; i++)
{
Point polygon1 = polygonPoints[i];
Point polygon2 = new Point();
if (i == polygonPoints.Count - )
{
polygon2 = polygonPoints[];
}
else
{
polygon2 = polygonPoints[i + ]; }
Point inter = new Point();
int interType = GetIntersectionPoint(p1, p2, polygon1, polygon2, out inter);
switch (interType)
{ case : if (!Equals(inter, p1) && !Equals(inter, p2))
{
interPoints.Add(inter);
}
break;
case :
default:
break;
}
}
return interPoints;
} /// <summary>
/// 取两个点的中点
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public Point GetCenter(Point p1, Point p2)
{
return new Point((p1.X + p2.X) / , (p1.Y + p2.Y) / );
} /// <summary>
/// 获取多边形裁剪折线形成的线段集合
/// </summary>
/// <param name="polyline"></param>
/// <param name="polygon"></param>
/// <returns></returns>
public List<Polyline> GetInterPolylines(Polyline polyline, Polygon polygon)
{
List<Polyline> list = new List<Polyline>();
//TODO: 1.遍历折线上的每相邻的两个个点,组成线段,与多边形的每一条边计算,求出此线段与多边形的边的交点
//TODO: 2.对此线段的上的交点进行排序,组成连续点的折线,判断这些线段在多边形内部的部分,加入集合 List<Point> polinePoints = polyline.Points.ToList();
List<Point> polygonPoints = polygon.Points.ToList(); for (int i = ; i < polinePoints.Count - ; i++)
{
Point one = polinePoints[i];
Point two = new Point();
if (i == polinePoints.Count - )
{ }
else
{
two = polinePoints[i + ];
}
List<Point> inters = GetInterPoints(one, two, polygon);
List<Point> sortInters = SortPointsBySlopeOfLine(one, two, inters); for (int j = ; j < sortInters.Count; j++)
{
if (j < sortInters.Count - )
{
if (InPoly(polygon, GetCenter(sortInters[j], sortInters[j + ])))
{
Polyline interPolyline = new Polyline();
interPolyline.Points.Add(sortInters[j]);
interPolyline.Points.Add(sortInters[j + ]);
list.Add(interPolyline);
}
} }
}
return list;
}
}

SourceCode

C# 实现 任意多边形切割折线算法的更多相关文章

  1. 任意多边形切割/裁剪(附C#代码实现)

    本实现主要参考了发表于2003年<软件学报>的<一个有效的多边形裁剪算法>(刘勇奎,高云,黄有群)这篇论文,所使用的理论与算法大都基于本文,对论文中部分阐述进行了详细解释,并提 ...

  2. 一种实用性较强的求IOU的算法(任意多边形之间的IOU)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  3. [NetTopologySuite](2)任意多边形求交

    任意多边形求交: private void btnPolygon_Click(object sender, EventArgs e) { , , , , , , , , , , , , , }; , ...

  4. poj1654 -- Area (任意多边形面积)

    Area Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20444   Accepted: 5567 Description ...

  5. 算法 & 数据结构——任意多边形填充

    需求 . 在计算机中,选区是一个很常见的功能,例如windows按住鼠标左键拖动划出矩形选区,Photshop通过钢笔工具任意形状选区.选区本身不过是通过线段闭合的一个几何形状,但是如何填充这个选区, ...

  6. Matlab 沿三维任意方向切割CT图的仿真计算

    一.数据来源 头部组织的数据.此处直接引用了matlab自带的mri数据.实际场景中,可以通过CT得到的数据进行转换得到 插入异物的数据.此处我假设插入异物为一根细铁丝.模拟为空间中的一条曲线.这个曲 ...

  7. unity模型任意无限切割插件

    概述 3d模型的任意切割一直是游戏开发里的一个很大的问题,模型切割的关键点就只有生成横切面的新顶点以及切口纹理的缝合,理论上解决了这两点,就近乎可以做到以假乱真的程度了.本篇文章就这两点进行描述 详细 ...

  8. js调用百度地图接口绘制任意多边形并获取每个点的经纬度等

    来自:https://blog.csdn.net/u013239236/article/details/52213977 侵删 <!DOCTYPE html> <html> & ...

  9. 最少的硬币数量组合出1到m之间的任意面值(贪心算法)

    题目描述: 你有n种不同面值的硬币,每种面值的硬币都有无限多个,为了方便购物,你希望带尽量少的硬币,并且要能组合出 1 到 m 之间(包含1和m)的所有面值. 输入描述: 第一行包含两个整数:m ,n ...

随机推荐

  1. Spring bean 实现初始化、销毁方法的方式及顺序

    Spring 允许 Bean 在初始化完成后以及销毁前执行特定的操作,常用方法有三种: 使用注解,在指定方法上加上@PostConstruct或@PreDestroy注解来制定该方法是在初始化之后还是 ...

  2. JAVA异常初步

    1,1个图.Throwable是所有异常类的老祖宗,万恶之源.Error正常是系统级错误,控制不了,Exception类又分RuntimeException及别的异常,RuntimeException ...

  3. C#多线程实现方法

    C#中实现线程应用开发的类都包含在了System.Threading命名空间中,比较常用的是Thread,ThreadPool类 Thread类构造函数作用是创建线程,有两个重载版本,一个带参数,一个 ...

  4. C/C++入门基础---指针(2)

    5,数组指针的不同含义 int a[5][10]; printf(%d, %d, %d\n", a, a+1, &a+1);  //1310392,1310432,1310592 a ...

  5. ELK日志管理之——logstash配置语法

    Logstash 设计了自己的 DSL -- 有点像 Puppet 的 DSL,或许因为都是用 Ruby 语言写的吧 -- 包括有区域,注释,数据类型(布尔值,字符串,数值,数组,哈希),条件判断,字 ...

  6. curl 模拟登录微信公众平台带验证码

    这段时间一直写个项目, 从切图到前端到后台都要搞定,真tm累. 今天下午手残,不停用错误的密码去模拟登录微信公众平台,结果后来出现验证码,瞬间悲剧(菜鸟从来没搞过带验证码的). 研究了一下,发现其实很 ...

  7. [技巧.Dotnet]轻松实现“强制.net程序以管理员身份运行”。

    使用场景: 程序中不少操作都需要特殊权限,有时为了方便,直接让程序以管理员方式运行. (在商业软件中,其实应该尽量避免以管理员身份运行.在安装或配置时,提前授予将相应权限.) 做法: 以C#项目为例: ...

  8. DQL、DML、DDL、DCL的概念与区别

    SQL(Structure Query Language)语言是数据库的核心语言. SQL的发展是从1974年开始的,其发展过程如下:1974年-----由Boyce和Chamberlin提出,当时称 ...

  9. VBA使用的Randomize和DoEvents

    Randomize private function getInt() dim n,m as integer Randomize n=1 m=3 getInt=Int((m+1-n)*rnd + n) ...

  10. city-picker 选择省市县的一个控件,好用。

    我觉得好奇怪,这么好一个插件,为什么没有设置值的方法,还是我才疏学浅?? 我看有的人做法是把,把源代码里面的自动扫描机制注释掉 // $(function () { // $('[data-toggl ...