C# 实现 任意多边形切割折线算法
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# 实现 任意多边形切割折线算法的更多相关文章
- 任意多边形切割/裁剪(附C#代码实现)
本实现主要参考了发表于2003年<软件学报>的<一个有效的多边形裁剪算法>(刘勇奎,高云,黄有群)这篇论文,所使用的理论与算法大都基于本文,对论文中部分阐述进行了详细解释,并提 ...
- 一种实用性较强的求IOU的算法(任意多边形之间的IOU)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- [NetTopologySuite](2)任意多边形求交
任意多边形求交: private void btnPolygon_Click(object sender, EventArgs e) { , , , , , , , , , , , , , }; , ...
- poj1654 -- Area (任意多边形面积)
Area Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 20444 Accepted: 5567 Description ...
- 算法 & 数据结构——任意多边形填充
需求 . 在计算机中,选区是一个很常见的功能,例如windows按住鼠标左键拖动划出矩形选区,Photshop通过钢笔工具任意形状选区.选区本身不过是通过线段闭合的一个几何形状,但是如何填充这个选区, ...
- Matlab 沿三维任意方向切割CT图的仿真计算
一.数据来源 头部组织的数据.此处直接引用了matlab自带的mri数据.实际场景中,可以通过CT得到的数据进行转换得到 插入异物的数据.此处我假设插入异物为一根细铁丝.模拟为空间中的一条曲线.这个曲 ...
- unity模型任意无限切割插件
概述 3d模型的任意切割一直是游戏开发里的一个很大的问题,模型切割的关键点就只有生成横切面的新顶点以及切口纹理的缝合,理论上解决了这两点,就近乎可以做到以假乱真的程度了.本篇文章就这两点进行描述 详细 ...
- js调用百度地图接口绘制任意多边形并获取每个点的经纬度等
来自:https://blog.csdn.net/u013239236/article/details/52213977 侵删 <!DOCTYPE html> <html> & ...
- 最少的硬币数量组合出1到m之间的任意面值(贪心算法)
题目描述: 你有n种不同面值的硬币,每种面值的硬币都有无限多个,为了方便购物,你希望带尽量少的硬币,并且要能组合出 1 到 m 之间(包含1和m)的所有面值. 输入描述: 第一行包含两个整数:m ,n ...
随机推荐
- CSS 多浏览器兼容性问题及解决方案
兼容性处理要点1.DOCTYPE 影响 CSS 处理 2.FF: 设置 padding 后, div 会增加 height 和 width, 但 IE 不会, 故需要用 !important 多设一个 ...
- 配置BUG-Linux系统下ssh登陆很慢的解决办法
很多的Linux用户发现连接上Linux服务器在输入用户名之后还要再等一下才能输入密码,时间过长了,现在小编与大家分享一下如何解决ssh登陆问题的问题,希望对您有所帮助 . 1.我们平时登陆Linux ...
- C# basic
1. output Console.WriteLine("hello world"); 2. naming convention variable: start with lowe ...
- JSP开发模式2(计算器)
CalculatorBean———————————————————————————————————————————— public class CalculatorBean { private ...
- SwipeRefreshLayout嵌套ScrollView包裹复杂头布局和RecyclerView
布局如下:上面是一个描述有:头像和部分信息的布局,底部是一个RecyclerView: 想法:想实现RecyclerView向上滚动的时候,隐藏上面的头像布局信息:使用了 CoordinatorLay ...
- Hibernate SQL查询 addScalar()或addEntity()
本文完全引用自: http://www.cnblogs.com/chenyixue/p/5601285.html Hibernate除了支持HQL查询外,还支持原生SQL查询. 对原 ...
- Android用ImageView显示本地和网上的图片
ImageView是Android程序中经常用到的组件,它将一个图片显示到屏幕上. 在UI xml定义一个ImageView如下: public void onCreate(Bundle savedI ...
- [原创]迈出NIOS的第一步,HelloNIOS
Altera官方推出NIOS已经很久了,个人感觉C+V代码配合会是后面FPGA使用的一个主流,由C来完成一些对时序要求不高,对功能要求偏高的部分,比如运动控制等:由V来配合时序完成高时序要求的需求以及 ...
- 使用dom元素和jquery元素实现简单增删改的练习
软件开发实际就是数据的增删改查,javascript前端开发也不例外.今天学了jquery框架的简单使用.于是用它实现简单的增删改,接着也用原始的javascript实现同样的功能,以便看出jquer ...
- mock测试框架Mockito
无论是敏捷开发.持续交付,还是测试驱动开发(TDD)都把单元测试作为实现的基石.随着这些先进的编程开发模式日益深入人心,单元测试如今显得越来越重要了.在敏捷开发.持续交付中要求单元测试一定要快(不能访 ...