热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用耳切法将多边形三角化【转】

https:blog.csdn.netyiwei151articledetails87946592效果图:做法及原理可参考此链接:http:www.cnblogs.comxignz

https://blog.csdn.net/yiwei151/article/details/87946592

效果图:

技术图片

做法及原理可参考此链接:http://www.cnblogs.com/xignzou/p/3721494.html

 代码:

using System;
using System.Collections.Generic;
using UnityEngine;

namespace PolygonTool
{

#region 耳切法对简单多边形进行三角形化

///


/// 判断凹点,凸点,耳朵的比较轴
///

public enum CompareAxle
{
X,
Y,
Z
}

///
/// 对多边形处理
///

public class Triangulation
{

///
/// 判断凹凸的时候的比对轴
///

private CompareAxle _compareAxle = CompareAxle.Y;

///
/// 多边形顶点
///

private List _polygOnVertexs= new List();

///
/// 顶点序列
///

private List _vertexsSequence = new List();

///
/// 节点管理器
///

private NodeManager _nodeManager = new NodeManager();

///
/// 初始化
///

/// 多边形顶点
public Triangulation(List polygonVertexs)
{
this._polygOnVertexs= polygonVertexs;
_nodeManager.Init(polygonVertexs);
}

///
/// 设置比较轴
///

///
public void SetCompareAxle(CompareAxle compareAxle)
{
this._compareAxle = compareAxle;
}

///
/// 获取三角形的顶点序列
///

public int[] GetTriangles()
{
while (_nodeManager.LinkedListLength >= 3)
{
SplitResult sr = SplitPolygon();
//
if (sr == null)
{
Debug.Log("null");
return null;
}
}

return _vertexsSequence.ToArray();
}

///
/// 计算凹顶点,凸顶点,耳朵
///

private SplitResult SplitPolygon()
{
//凹点
List _cOncaveVertexs= new List();
//凸点
List _raisedVertexs = new List();
//耳朵
List _polygOnEars= new List();
//起始节点
Node currentNode = _nodeManager.FirstNode;

#region 计算凹顶点,凸顶点

for (int i = 0; i <_nodeManager.LinkedListLength; i++)
{
Vector3 One= currentNode.vertex - currentNode.lastNode.vertex;
Vector3 two = currentNode.nextNode.vertex - currentNode.vertex;
Vector3 crossRes = Vector3.Cross(one, two);

if (_compareAxle == CompareAxle.Y)
{
if (crossRes.y > 0)
{
_concaveVertexs.Add(currentNode);
}
else
{
_raisedVertexs.Add(currentNode);
}
}

if (_compareAxle == CompareAxle.X)
{
if (crossRes.x > 0)
{
_concaveVertexs.Add(currentNode);
}
else
{
_raisedVertexs.Add(currentNode);
}
}

if (_compareAxle == CompareAxle.Z)
{
if (crossRes.z > 0)
{
_concaveVertexs.Add(currentNode);
}
else
{
_raisedVertexs.Add(currentNode);
}
}

_polygonEars.Add(currentNode);
currentNode = currentNode.nextNode;
}

for (int i = 0; i <_concaveVertexs.Count; i++)
{
_polygonEars.Remove(_concaveVertexs[i]);
}
#endregion

#region 计算耳朵
List needRemoveIdList = new List();
for (int i = 0; i <_polygonEars.Count; i++)
{
Node earNode = _polygonEars[i];
Node compareNode = earNode.nextNode.nextNode;

while (compareNode != earNode.lastNode)
{
bool isIn = IsIn(compareNode.vertex, earNode.lastNode.vertex, earNode.vertex,
earNode.nextNode.vertex);

if (isIn == true)
{
if (_polygonEars.Contains(_polygonEars[i]))
{
needRemoveIdList.Add(_polygonEars[i].id);
}
break;
}
compareNode = compareNode.nextNode;
}
}

for (int j = 0; j {
for (int i = 0; i <_polygonEars.Count; i++)
{
if (_polygonEars[i].id == needRemoveIdList[j])
{
_polygonEars.RemoveAt(i);
}
}
}

#endregion

#region 打印初始化结果

Debug.Log("凸点");
for (int i = 0; i <_raisedVertexs.Count; i++)
{
Debug.Log(_raisedVertexs[i].id);
}

Debug.Log("凹点");
for (int i = 0; i <_concaveVertexs.Count; i++)
{
Debug.Log(_concaveVertexs[i].id);
}

Debug.Log("耳朵");
for (int i = 0; i <_polygonEars.Count; i++)
{
Debug.Log(_polygonEars[i].id);
}

Debug.Log("-----------------------------------------------");
#endregion

//耳朵为空说明不是简单多边形 多边形三角化失败
if (_polygonEars.Count == 0)
{
return null;
}

_vertexsSequence.Add(_polygonEars[0].lastNode.id);
_vertexsSequence.Add(_polygonEars[0].id);
_vertexsSequence.Add(_polygonEars[0].nextNode.id);
_nodeManager.RemoveNode(_polygonEars[0]);


return new SplitResult(_raisedVertexs, _concaveVertexs, _polygonEars);
}

///
/// 判断一点是否在三角形内
///

/// 一点
///
///
///
///
public bool IsIn(Vector3 p,Vector3 a,Vector3 b,Vector3 c)
{
Vector3 pa = p - a;
Vector3 pb = p - b;
Vector3 pc = p - c;

Vector3 t1 = Vector3.Cross(pa, pb);
Vector3 t2 = Vector3.Cross(pb, pc);
Vector3 t3 = Vector3.Cross(pc, pa);

bool isIn2 = t1.y >= 0 && t2.y >= 0 && t3.y >= 0 || t1.y <= 0 && t2.y <= 0 && t3.y <= 0;

return isIn2;
}

///
/// 管理多边形 构成一个双向链表
///

public class NodeManager
{

private List _nodeList = new List();

public int LinkedListLength
{
get { return _nodeList.Count; }
}

public Node FirstNode
{
get { return _nodeList[0]; }
}

public void Init(List vertexs)
{

for (int i = 0; i {
Node node = new Node(i, vertexs[i]);
_nodeList.Add(node);
}

for (int i = 0; i {
if (i == 0)
{
_nodeList[i].lastNode = _nodeList[LinkedListLength - 1];
_nodeList[i].nextNode = _nodeList[1];
}
else if (i == LinkedListLength - 1)
{
_nodeList[i].lastNode = _nodeList[LinkedListLength - 2];
_nodeList[i].nextNode = _nodeList[0];
}
else
{
_nodeList[i].lastNode = _nodeList[i - 1];
_nodeList[i].nextNode = _nodeList[i + 1];
}
}
}

public void RemoveNode(Node node)
{
_nodeList.Remove(node);
node.lastNode.nextNode = node.nextNode;
node.nextNode.lastNode = node.lastNode;
}
}

public class Node
{

public int id;
public Vector3 vertex;
public Node lastNode;
public Node nextNode;

public Node(int id, Vector3 vertex)
{
this.id = id;
this.vertex = vertex;
}

public Node(int id, Vector3 vertex, Node lastNode, Node nextNode)
{
this.id = id;
this.vertex = vertex;
this.lastNode = lastNode;
this.nextNode = nextNode;
}
}

public class SplitResult
{
///
/// 凸顶点
///

public List raisedVertexs;

///
/// 凹顶点
///

public List concaveVertexs;

///
/// 耳朵
///

public List polygonEars;

public SplitResult(List raisedVertexs, List concaveVertexs, List polygonEars)
{
this.raisedVertexs = raisedVertexs;
this.cOncaveVertexs= concaveVertexs;
this.polygOnEars= polygonEars;
}
}
}

#endregion
}

github地址:https://github.com/yiwei151/PolygonTriangulation

使用耳切法将多边形三角化【转】


推荐阅读
  • Git基础操作指南:掌握必备技能
    掌握 Git 基础操作是每个开发者必备的技能。本文详细介绍了 Git 的基本命令和使用方法,包括初始化仓库、配置用户信息、添加文件、提交更改以及查看版本历史等关键步骤。通过这些操作,读者可以快速上手并高效管理代码版本。例如,使用 `git config --global user.name` 和 `git config --global user.email` 来设置全局用户名和邮箱,确保每次提交时都能正确标识提交者信息。 ... [详细]
  • 为了在Fragment中直接调用Activity的方法,可以通过定义一个接口并让Activity实现该接口来实现。具体步骤包括:首先在Fragment中声明一个接口,并在Activity中实现该接口。接着,在Fragment中通过类型转换检查Activity是否实现了该接口,如果实现了则调用相应的方法。这种方法不仅提高了代码的解耦性,还增强了模块间的通信效率。此外,还可以通过ViewModel或LiveData等现代Android架构组件进一步优化这一过程,以实现更加高效和可靠的通信机制。 ... [详细]
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • PHP中元素的计量单位是什么? ... [详细]
  • 在ASP.NET MVC项目中,通过实战解决了Ajax请求500错误及多表数据查询的问题。具体而言,将页面分为两个部分,用户点击右侧导航栏时,通过Ajax请求动态加载数据,并在右侧显示相应的页面内容。最初尝试使用Partial Action方法,但遇到了500错误。通过详细排查和调试,最终成功解决了这一问题,并实现了预期功能。此外,还优化了多表数据查询的性能,确保系统的高效运行。 ... [详细]
  • 本文深入探讨了 iOS 开发中 `int`、`NSInteger`、`NSUInteger` 和 `NSNumber` 的应用与区别。首先,我们将详细介绍 `NSNumber` 类型,该类用于封装基本数据类型,如整数、浮点数等,使其能够在 Objective-C 的集合类中使用。通过分析这些类型的特性和应用场景,帮助开发者更好地理解和选择合适的数据类型,提高代码的健壮性和可维护性。苹果官方文档提供了更多详细信息,可供进一步参考。 ... [详细]
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • Spring Security 认证模块的项目构建与初始化
    本文详细介绍了如何构建和初始化Spring Security认证模块的项目。首先,通过创建一个分布式Maven聚合工程,该工程包含四个模块,分别为core、browser(用于演示)、app等,以构成完整的SeehopeSecurity项目。在项目构建过程中,还涉及日志生成机制,确保能够输出关键信息,便于调试和监控。 ... [详细]
  • jQuery Flot 数据可视化插件:高效绘制图表的专业工具
    jQuery Flot 是一款高效的数据可视化插件,专为绘制各种图表而设计。该工具支持丰富的图表类型和自定义选项,适用于多种应用场景。用户可以通过其官方网站获取示例代码和下载资源,以便快速上手和使用。 ... [详细]
  • 在进行网络编程时,准确获取本地主机的IP地址是一项基本但重要的任务。Winsock作为20世纪90年代初由Microsoft与多家公司共同制定的Windows平台网络编程接口,为开发者提供了一套高效且易用的工具。通过Winsock,开发者可以轻松实现网络通信功能,并准确获取本地主机的IP地址,从而确保应用程序在网络环境中的稳定运行。此外,了解Winsock的工作原理及其API函数的使用方法,有助于提高开发效率和代码质量。 ... [详细]
  • 使用cpphttplib构建HTTP服务器以处理带有查询参数的URL请求 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • Vuex 实战进阶:构建高效笔记本应用(第二篇)
    在上一篇文章中,我们初步探讨了 Vuex 在该项目中的应用。本文将深入解析整个项目的架构设计。首先回顾 `main.js` 的内容,然后重点分析 `App.vue` 文件,其中引入了 `Toolbar.vue` 和 `NodeList.vue` 组件,详细说明它们在应用中的作用和交互方式。通过这些组件的协同工作,我们将展示如何构建一个高效且响应迅速的笔记本应用。 ... [详细]
  • 本文首先对信息漏洞的基础知识进行了概述,重点介绍了几种常见的信息泄露途径。具体包括目录遍历、PHPINFO信息泄露以及备份文件的不当下载。其中,备份文件下载涉及网站源代码、`.bak`文件、Vim缓存文件和`DS_Store`文件等。目录遍历漏洞的详细分析为后续深入研究奠定了基础。 ... [详细]
  • 新年伊始,正是学习的最佳时机。本文全面解析了CK1957-Zookeeper的核心概念与实践技巧,旨在帮助初学者快速掌握这一深度学习工具。通过详细的理论讲解和实际操作示例,读者可以更好地理解Zookeeper的工作原理及其在分布式系统中的应用。无论是新手还是有一定基础的学习者,都能从中受益匪浅。 ... [详细]
author-avatar
大美女雪梨醒目
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有