合并代码
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46d78284a685f31429f5bd981c1f86c1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 查询贝塞尔点算法
|
||||
/// </summary>
|
||||
public class AlgorithmFindBezier : ModuleAlgorithm<DataFindBezier> {
|
||||
public readonly float FindRange = 0.01f;
|
||||
|
||||
protected override void Awake() => ModuleCore.AlgorithmFindBezier = this;
|
||||
|
||||
public override void Compute(DataFindBezier findBezier) {
|
||||
List<DataPlate> datas = findBezier.datas;
|
||||
for (int i = 0; i < datas.Count; i++) {
|
||||
if (FindPlatePoint(datas[i], findBezier)) { return; }
|
||||
}
|
||||
}
|
||||
/// <summary> 查询匹配的点 </summary>
|
||||
private bool FindPlatePoint(DataPlate plate, DataFindBezier findBezier) {
|
||||
List<DataPoint> points = plate.points;
|
||||
Vector3 position = findBezier.position - plate.position;
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
float f = Vector3.Distance(points[i].frontBezier, position);
|
||||
if (f <= FindRange && points[i].isCurveFront) {
|
||||
findBezier.isFront = true;
|
||||
findBezier.plate = plate;
|
||||
findBezier.point = points[i];
|
||||
return true;
|
||||
}
|
||||
float a = Vector3.Distance(points[i].afterBezier, position);
|
||||
if (a <= FindRange && points[i].isCurveAfter) {
|
||||
findBezier.plate = plate;
|
||||
findBezier.point = points[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ecc5cf619be47744b8ac06557518014
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd2aff163a310544886809b5b8590bb2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 查询点算法
|
||||
/// 转角法判断点是否在多边形内
|
||||
/// </summary>
|
||||
public class AlgorithmFindPoint : ModuleAlgorithm<DataFindPoint> {
|
||||
public readonly float FindRange = 0.01f;
|
||||
|
||||
protected override void Awake() => ModuleCore.AlgorithmFindPoint = this;
|
||||
|
||||
public override void Compute(DataFindPoint findPoint) {
|
||||
List<DataPlate> datas = findPoint.datas;
|
||||
for (int i = 0; i < datas.Count; i++) {
|
||||
if (FindPlatePoint(datas[i], findPoint)) { return; }
|
||||
if (FindPlateInside(datas[i], findPoint)) { findPoint.plate = datas[i]; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> 查询匹配的点 </summary>
|
||||
private bool FindPlatePoint(DataPlate plate, DataFindPoint findPoint) {
|
||||
List<DataPoint> points = plate.points;
|
||||
Vector3 position = findPoint.position - plate.position;
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
float distance = Vector3.Distance(points[i].position, position);
|
||||
if (distance > FindRange) { continue; }
|
||||
findPoint.plate = plate;
|
||||
findPoint.point = points[i];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary> 转角法查询位置是否在板片内 </summary>
|
||||
private bool FindPlateInside(DataPlate plate, DataFindPoint findPoint) {
|
||||
DataPoint[] points = plate.points.ToArray();
|
||||
double angles = 0;
|
||||
Vector3 position = findPoint.position - plate.position;
|
||||
for (int i = 0; i < points.Length; i++) {
|
||||
Vector3 a = points.LoopIndex(i + 0).position - position;
|
||||
Vector3 b = points.LoopIndex(i + 1).position - position;
|
||||
float angle = Vector2.SignedAngle(a, b);
|
||||
angles += angle;
|
||||
}
|
||||
int normal = (int)(angles * 1000);
|
||||
return normal > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 159a37d73c0c32e4cbb41b0767597000
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce9e6ecaa5ce98843abd7070cf9adb82
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 插入点算法
|
||||
/// </summary>
|
||||
public class AlgorithmInsertPoint : ModuleAlgorithm<DataInsertPoint> {
|
||||
public class Segment {
|
||||
public DataPlate plate;
|
||||
public DataPoint aPoint;
|
||||
public DataPoint bPoint;
|
||||
public float distance = float.MaxValue;
|
||||
}
|
||||
|
||||
protected override void Awake() => ModuleCore.AlgorithmInsertPoint = this;
|
||||
|
||||
public override void Compute(DataInsertPoint insertPoint) {
|
||||
List<DataPlate> datas = insertPoint.datas;
|
||||
List<Segment> segments = new List<Segment>();
|
||||
Vector3 position = insertPoint.position;
|
||||
|
||||
for (int i = 0; i < datas.Count; i++) {
|
||||
if (!FindSegment(datas[i], position, out Segment temp)) { continue; }
|
||||
segments.Add(temp);
|
||||
}
|
||||
|
||||
if (segments.Count <= 0) { return; }
|
||||
Segment segment = segments[0];
|
||||
for (int i = 0; i < segments.Count; i++) {
|
||||
if (segment.distance < segments[i].distance) { continue; }
|
||||
segment = segments[i];
|
||||
}
|
||||
insertPoint.plate = segment.plate;
|
||||
insertPoint.aPoint = segment.aPoint;
|
||||
insertPoint.bPoint = segment.bPoint;
|
||||
}
|
||||
/// <summary> 查询匹配的线 </summary>
|
||||
private bool FindSegment(DataPlate plate, Vector3 position, out Segment segment) {
|
||||
List<DataPoint> points = plate.points;
|
||||
Vector3 c = position - plate.position;
|
||||
segment = new Segment();
|
||||
segment.plate = plate;
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
Vector3 a = points.LoopIndex(i + 0).position;
|
||||
Vector3 b = points.LoopIndex(i + 1).position;
|
||||
float distance = ProjectDistance(a, b, c);
|
||||
if (segment.distance < distance) { continue; }
|
||||
segment.aPoint = points.LoopIndex(i + 0);
|
||||
segment.bPoint = points.LoopIndex(i + 1);
|
||||
segment.distance = distance;
|
||||
}
|
||||
return segment.distance != float.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向量投影法
|
||||
/// 计算点c到线段ab最近的点
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="c"></param>
|
||||
/// <returns>如果不在线段上返回 float.MaxValue</returns>
|
||||
private float ProjectDistance(Vector3 a, Vector3 b, Vector3 c) {
|
||||
Vector3 ab = b - a;
|
||||
Vector3 ac = c - a;
|
||||
Vector3 p = Vector3.Project(ac, ab);
|
||||
//Debug.Log($"{a} , {b} , {c} , {p} , {ab.normalized} , {p.normalized} , {ab.normalized != p.normalized} , {ab.magnitude < p.magnitude}");
|
||||
if (ab.normalized != p.normalized) { return float.MaxValue; }
|
||||
if (ab.magnitude < p.magnitude) { return float.MaxValue; }
|
||||
//Debug.Log($"{a} , {b} , {c} , {Vector3.Distance(c, p)}");
|
||||
return Vector3.Distance(c, p + a);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6693b5fb3f035aa42bf27141ab05b01d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c315b7d2a7530784ab66ef5cc7d4d8b1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,131 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 多边形耳切法
|
||||
/// </summary>
|
||||
public class AFAuriculareCutting : ModuleAlgorithmFunction<DataPolygon> {
|
||||
public class Auriculare {
|
||||
public int index;
|
||||
public Vector3 aPoint;//+0
|
||||
public Vector3 bPoint;//-1
|
||||
public Vector3 cPoint;//+1
|
||||
}
|
||||
|
||||
/// <summary> 多边形耳切法 </summary>
|
||||
public AFAuriculareCutting() { }
|
||||
|
||||
public override void Compute(DataPolygon data) {
|
||||
List<Vector3> edgePoints = new List<Vector3>(data.edgePoints);
|
||||
List<DataTriangle> triangles = new List<DataTriangle>();
|
||||
Vector3[] allArray = edgePoints.ToArray();
|
||||
bool isClockWise = IsClockWise(allArray);
|
||||
//耳切法生成三角形
|
||||
ComputeAuriculare(triangles, edgePoints, allArray, isClockWise);
|
||||
data.triangles = triangles;
|
||||
}
|
||||
|
||||
#region 函数
|
||||
/// <summary> 循环计算有效的耳点 </summary>
|
||||
public static void ComputeAuriculare(List<DataTriangle> triangles, List<Vector3> edgePoints, Vector3[] allArray, bool isClockWise) {
|
||||
List<DataTriangle> temp = ComputeAuriculare(edgePoints, allArray, isClockWise);
|
||||
if (temp.Count == 0) { return; }
|
||||
triangles.AddRange(temp);
|
||||
ComputeAuriculare(triangles, edgePoints, allArray, isClockWise);
|
||||
}
|
||||
/// <summary> 计算一个有效的耳点 </summary>
|
||||
public static List<DataTriangle> ComputeAuriculare(List<Vector3> edgePoints, Vector3[] allArray, bool isClockWise) {
|
||||
Vector3[] array = edgePoints.ToArray();
|
||||
List<DataTriangle> polygons = new List<DataTriangle>();
|
||||
for (int i = 0; i < array.Length; i++) {
|
||||
Auriculare auriculare = CreateAuriculare(i, array);
|
||||
// 等于180,大于180,不可能为耳点
|
||||
if (!GetAngleType(auriculare, isClockWise)) { continue; }
|
||||
// 包含其他点,不可能为耳点
|
||||
if (IsInsideTriangle(auriculare, allArray)) { continue; }
|
||||
// 包含其他耳点,不可能成为耳点
|
||||
if (!IsInsideAuriculare(auriculare, edgePoints)) { continue; }
|
||||
edgePoints.Remove(auriculare.aPoint);
|
||||
polygons.Add(CreateAuriculareToTriangle(auriculare));
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
/// <summary> 创建点 </summary>
|
||||
public static Auriculare CreateAuriculare(int index, Vector3[] array) {
|
||||
Auriculare auriculare = new Auriculare();
|
||||
auriculare.index = index;
|
||||
auriculare.bPoint = array.LoopIndex(index - 1);
|
||||
auriculare.aPoint = array.LoopIndex(index);
|
||||
auriculare.cPoint = array.LoopIndex(index + 1);
|
||||
return auriculare;
|
||||
}
|
||||
/// <summary> 计算三角形内是否包含其他点 </summary>
|
||||
public static bool IsInsideTriangle(Auriculare auriculare, Vector3[] array) {
|
||||
for (int i = 0; i < array.Length; i++) {
|
||||
if (array[i] == auriculare.aPoint) { continue; }
|
||||
if (array[i] == auriculare.bPoint) { continue; }
|
||||
if (array[i] == auriculare.cPoint) { continue; }
|
||||
if (IsInsideTriangle(auriculare, array[i])) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary> 计算三角形内是否包含其他点 </summary>
|
||||
public static bool IsInsideAuriculare(Auriculare auriculare, List<Vector3> edgePoints) {
|
||||
if (!edgePoints.Contains(auriculare.aPoint)) { return false; }
|
||||
if (!edgePoints.Contains(auriculare.bPoint)) { return false; }
|
||||
if (!edgePoints.Contains(auriculare.cPoint)) { return false; }
|
||||
return true;
|
||||
}
|
||||
/// <summary> 从节点创建三角形 </summary>
|
||||
public static DataTriangle CreateAuriculareToTriangle(Auriculare auriculare) {
|
||||
DataTriangle triangle = new DataTriangle();
|
||||
triangle.a = auriculare.aPoint;
|
||||
triangle.b = auriculare.bPoint;
|
||||
triangle.c = auriculare.cPoint;
|
||||
return triangle;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 算法
|
||||
/// <summary> 当前的点方向是否为顺时针 </summary>
|
||||
public static bool IsClockWise(Vector3[] array) {
|
||||
// 通过计算叉乘来确定方向
|
||||
float sum = 0f;
|
||||
double count = array.Length;
|
||||
Vector3 va, vb;
|
||||
for (int i = 0; i < array.Length; i++) {
|
||||
va = array[i];
|
||||
vb = (i == count - 1) ? array[0] : array[i + 1];
|
||||
sum += va.x * vb.y - va.y * vb.x;
|
||||
}
|
||||
return sum < 0;
|
||||
}
|
||||
/// <summary> 判断角的类型 </summary>
|
||||
public static bool GetAngleType(Auriculare auriculare, bool isClockWise) {
|
||||
// 角度是否小于180
|
||||
// oa & ob 之间的夹角,(右手法则)
|
||||
// 逆时针顺序是相反的
|
||||
Vector2 a = auriculare.aPoint;
|
||||
Vector2 b = auriculare.bPoint;
|
||||
Vector2 c = auriculare.cPoint;
|
||||
float f = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
||||
bool flag = isClockWise ? f > 0 : f < 0;
|
||||
if (f == 0) { return false;/*平角*/ }
|
||||
else if (flag) { return true;/*劣角*/ }
|
||||
else { return false;/*优角*/ }
|
||||
}
|
||||
/// <summary> p点是否在点a,b,c组成的三角形内,或边上 </summary>
|
||||
public static bool IsInsideTriangle(Auriculare auriculare, Vector2 p) {
|
||||
// p点是否在abc三角形内
|
||||
Vector2 a = auriculare.aPoint;
|
||||
Vector2 b = auriculare.bPoint;
|
||||
Vector2 c = auriculare.cPoint;
|
||||
float c1 = (b.x - a.x) * (p.y - b.y) - (b.y - a.y) * (p.x - b.x);
|
||||
float c2 = (c.x - b.x) * (p.y - c.y) - (c.y - b.y) * (p.x - c.x);
|
||||
float c3 = (a.x - c.x) * (p.y - a.y) - (a.y - c.y) * (p.x - a.x);
|
||||
return (c1 > 0f && c2 >= 0f && c3 >= 0f) || (c1 < 0f && c2 <= 0f && c3 <= 0f);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9b83b680d622b5409fb9f74a1eaaebf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 三阶贝塞尔曲线计算边缘点
|
||||
/// </summary>
|
||||
public class AFEdgePoint : ModuleAlgorithmFunction<DataPolygon> {
|
||||
|
||||
/// <summary> 三阶贝塞尔曲线计算边缘点 </summary>
|
||||
public AFEdgePoint() { }
|
||||
|
||||
public override void Compute(DataPolygon data) {
|
||||
List<DataPoint> points = new List<DataPoint>(data.points);
|
||||
List<Vector3> edgePoints = new List<Vector3>();
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
DataPoint current = points.LoopIndex(i);
|
||||
DataPoint next = points.LoopIndex(i + 1);
|
||||
edgePoints.AddRange(CreateLine(current, next, data.edgeSmooth));
|
||||
}
|
||||
data.edgePoints = edgePoints;
|
||||
}
|
||||
|
||||
#region 函数
|
||||
public List<Vector3> CreateLine(DataPoint current, DataPoint next, float edgeSmooth) {
|
||||
List<Vector3> edgePoints = new List<Vector3>();
|
||||
//方向,距离
|
||||
Vector2 direction = (next.position - current.position).normalized;
|
||||
float distance = Vector2.Distance(next.position, current.position);
|
||||
//求余,得商数
|
||||
int quotient = Quotient(distance, edgeSmooth);
|
||||
//点位间距
|
||||
float segment = distance / quotient;
|
||||
//贝塞尔曲线点
|
||||
Vector3 ap = current.position;
|
||||
Vector3 bp = current.isCurveAfter ? current.afterBezier : current.position;
|
||||
Vector3 cp = next.isCurveFront ? next.frontBezier : next.position;
|
||||
Vector3 dp = next.position;
|
||||
for (int i = 0; i < quotient; i++) {
|
||||
float t = segment * i / distance;
|
||||
Vector2 position = ComputeBezier(ap, bp, cp, dp, t);
|
||||
edgePoints.Add(position);
|
||||
}
|
||||
return edgePoints;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 算法
|
||||
/// <summary> 商数 </summary>
|
||||
public static int Quotient(float distance, float edgeSmooth) {
|
||||
int a = (int)(distance * 1000);
|
||||
int b = (int)(edgeSmooth * 1000);
|
||||
return Math.DivRem(a, b, out int remainder);
|
||||
}
|
||||
/// <summary>
|
||||
/// 三阶贝塞尔算法
|
||||
/// </summary>
|
||||
/// <param name="a">起点</param>
|
||||
/// <param name="b">起点的贝塞尔点</param>
|
||||
/// <param name="c">终点的贝塞尔点</param>
|
||||
/// <param name="d">终点</param>
|
||||
/// <param name="t">进度</param>
|
||||
/// <returns>当前进度的曲线点</returns>
|
||||
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) {
|
||||
Vector3 aa = a + (b - a) * t;
|
||||
Vector3 bb = b + (c - b) * t;
|
||||
Vector3 cc = c + (d - c) * t;
|
||||
|
||||
Vector3 aaa = aa + (bb - aa) * t;
|
||||
Vector3 bbb = bb + (cc - bb) * t;
|
||||
return aaa + (bbb - aaa) * t;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e88d537872f0dba44ae4bda829b08c42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 合并三角形
|
||||
/// </summary>
|
||||
public class AFMergeTriangles : ModuleAlgorithmFunction<DataPolygon> {
|
||||
public override void Compute(DataPolygon data) {
|
||||
List<DataTriangle> triangles = new List<DataTriangle>(data.triangles);
|
||||
index = 0;
|
||||
MergeTriangles(triangles);
|
||||
data.triangles = triangles;
|
||||
ModuleCore.I.VisualPolygon.UpdateVisual(data);
|
||||
}
|
||||
private int index;
|
||||
private int maxIndex;
|
||||
/// <summary> 取一个三角形出来 匹配剩下的三角形 符合条件则合并 </summary>
|
||||
private void MergeTriangles(List<DataTriangle> triangles) {
|
||||
if (index > triangles.Count) { return; }
|
||||
|
||||
DataTriangle aT = triangles[0];
|
||||
triangles.Remove(aT);
|
||||
|
||||
maxIndex = triangles.Count;
|
||||
for (int i = 0; i < triangles.Count; i++) {
|
||||
DataTriangle bT = triangles[i];
|
||||
//ab同边
|
||||
if (MergeConditions(bT.a, bT.b, bT, ref aT)) { triangles.Remove(bT); continue; }
|
||||
//bc同边
|
||||
if (MergeConditions(bT.b, bT.c, bT, ref aT)) { triangles.Remove(bT); continue; }
|
||||
//ca同边
|
||||
if (MergeConditions(bT.c, bT.a, bT, ref aT)) { triangles.Remove(bT); continue; }
|
||||
}
|
||||
index = maxIndex == triangles.Count ? index + 1 : 0;
|
||||
Debug.Log($"{index} , {maxIndex} , {triangles.Count}");
|
||||
|
||||
triangles.Add(aT);
|
||||
MergeTriangles(triangles);
|
||||
}
|
||||
/// <summary> 匹配三角形 符合条件则合并 无法合并则返回 true </summary>
|
||||
private bool MergeTriangles(List<DataTriangle> triangles, DataTriangle aT) {
|
||||
for (int i = 0; i < triangles.Count; i++) {
|
||||
DataTriangle bT = triangles[i];
|
||||
//ab同边
|
||||
if (MergeConditions(bT.a, bT.b, bT, ref aT)) { triangles.Remove(bT); }
|
||||
//bc同边
|
||||
if (MergeConditions(bT.b, bT.c, bT, ref aT)) { triangles.Remove(bT); }
|
||||
//ca同边
|
||||
if (MergeConditions(bT.c, bT.a, bT, ref aT)) { triangles.Remove(bT); }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/// <summary> 计算三角形内是否包含其他点 </summary>
|
||||
private bool IsInsideTriangle(DataTriangle triangle, Vector3 point) {
|
||||
if (triangle.a == point) { return true; }
|
||||
if (triangle.b == point) { return true; }
|
||||
if (triangle.c == point) { return true; }
|
||||
return false;
|
||||
}
|
||||
//检测合并条件是否满足
|
||||
private bool MergeConditions(Vector3 a, Vector3 b, DataTriangle bT, ref DataTriangle aT) {
|
||||
if (!IsInsideTriangle(aT, a, b, out Vector3 o)) { return false; }
|
||||
if (!IsInsideTriangle(bT, a, b, out Vector3 c)) { return false; }
|
||||
if (IsInsideTriangle(aT, c)) { return true; }
|
||||
Vector3 oa = (o - a).normalized;
|
||||
Vector3 ob = (o - b).normalized;
|
||||
Vector3 oc = (o - c).normalized;
|
||||
if (oc == oa) { aT.a = o; aT.b = b; aT.c = c; return true; }
|
||||
if (oc == ob) { aT.a = o; aT.b = a; aT.c = c; return true; }
|
||||
return false;
|
||||
}
|
||||
/// <summary> 计算三角形内是否包含其他点 </summary>
|
||||
private bool IsInsideTriangle(DataTriangle triangle, Vector3 a, Vector3 b, out Vector3 o) {
|
||||
if (triangle.a == a && triangle.b == b) { o = triangle.c; return true; }
|
||||
if (triangle.a == b && triangle.b == a) { o = triangle.c; return true; }
|
||||
if (triangle.a == a && triangle.c == b) { o = triangle.b; return true; }
|
||||
if (triangle.a == b && triangle.c == a) { o = triangle.b; return true; }
|
||||
if (triangle.b == a && triangle.c == b) { o = triangle.a; return true; }
|
||||
if (triangle.b == b && triangle.c == a) { o = triangle.a; return true; }
|
||||
o = a; return false;
|
||||
}
|
||||
|
||||
/// <summary> p点是否在点a,b,c组成的三角形内,或边上 </summary>
|
||||
public static bool IsInsideTriangle(DataTriangle auriculare, Vector2 p) {
|
||||
// p点是否在abc三角形内
|
||||
Vector2 a = auriculare.a;
|
||||
Vector2 b = auriculare.b;
|
||||
Vector2 c = auriculare.c;
|
||||
float c1 = (b.x - a.x) * (p.y - b.y) - (b.y - a.y) * (p.x - b.x);
|
||||
float c2 = (c.x - b.x) * (p.y - c.y) - (c.y - b.y) * (p.x - c.x);
|
||||
float c3 = (a.x - c.x) * (p.y - a.y) - (a.y - c.y) * (p.x - a.x);
|
||||
return (c1 > 0f && c2 >= 0f && c3 >= 0f) || (c1 < 0f && c2 <= 0f && c3 <= 0f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45d3c753563f5be468680173acf8b1e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class AFSubdivision : ModuleAlgorithmFunction<DataPolygon> {
|
||||
public override void Compute(DataPolygon data) {
|
||||
List<DataTriangle> triangles = new List<DataTriangle>(data.triangles);
|
||||
List<DataTriangle> subdivision = new List<DataTriangle>();
|
||||
for (int i = 0; i < triangles.Count; i++) {
|
||||
subdivision.AddRange(Subdivision(triangles[i]));
|
||||
}
|
||||
//subdivision.AddRange(Subdivision(triangles[121], data.edgeSmooth));
|
||||
|
||||
data.triangles = subdivision;
|
||||
}
|
||||
private List<DataTriangle> Subdivision(DataTriangle triangle) {
|
||||
float ab = Vector3.Distance(triangle.a, triangle.b);
|
||||
float bc = Vector3.Distance(triangle.b, triangle.c);
|
||||
float ca = Vector3.Distance(triangle.c, triangle.a);
|
||||
if (ab > bc && ab > ca && ab > 0.02f) { return Subdivision(triangle.c, triangle.a, triangle.b); }
|
||||
if (bc > ab && bc > ca && bc > 0.02f) { return Subdivision(triangle.a, triangle.b, triangle.c); }
|
||||
if (ca > bc && ca > ab && ca > 0.02f) { return Subdivision(triangle.b, triangle.c, triangle.a); }
|
||||
|
||||
return new List<DataTriangle> { triangle };
|
||||
}
|
||||
private List<DataTriangle> Subdivision(Vector3 a, Vector3 b, Vector3 c) {
|
||||
Vector3 direction = b - c;
|
||||
Vector3 d = c + direction * 0.5f;
|
||||
|
||||
DataTriangle aT = new DataTriangle { a = a, b = d, c = c };
|
||||
DataTriangle bT = new DataTriangle { a = a, b = b, c = d };
|
||||
return new List<DataTriangle> { aT, bT, };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb4aa74668cf2134eb322b3a40d74c29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 三角形转换网格
|
||||
/// </summary>
|
||||
public class AFTriangleMesh : ModuleAlgorithmFunction<DataPolygon> {
|
||||
public override void Compute(DataPolygon data) {
|
||||
List<DataTriangle> polygons = new List<DataTriangle>(data.triangles);
|
||||
//创建数据容器
|
||||
List<Vector3> vertices = new List<Vector3>();
|
||||
List<Vector2> uv = new List<Vector2>();
|
||||
List<int> triangles = new List<int>();
|
||||
//三角形合并
|
||||
for (int i = 0; i < polygons.Count; i++) {
|
||||
triangles.Add(AddIndexOf(vertices, polygons[i].a));
|
||||
triangles.Add(AddIndexOf(vertices, polygons[i].b));
|
||||
triangles.Add(AddIndexOf(vertices, polygons[i].c));
|
||||
}
|
||||
Debug.Log(vertices.Count);
|
||||
//展开uv (顶点去掉z坐标就是未缩放的平面UV)
|
||||
for (int i = 0; i < vertices.Count; i++) { uv.Add(vertices[i]); }
|
||||
//附加数据
|
||||
data.polygon = new Mesh();
|
||||
data.polygon.vertices = vertices.ToArray();
|
||||
data.polygon.uv = uv.ToArray();
|
||||
data.polygon.triangles = triangles.ToArray();
|
||||
data.polygon.RecalculateBounds();
|
||||
data.polygon.RecalculateNormals();
|
||||
}
|
||||
//顶点列表不包含则添加点,获得索引
|
||||
private int AddIndexOf(List<Vector3> vertices, Vector3 a) {
|
||||
if (!vertices.Contains(a)) { vertices.Add(a); }
|
||||
return vertices.IndexOf(a);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e215bacbb6d0216408afb679ae863360
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 散列点生成多边形算法
|
||||
/// </summary>
|
||||
public class AlgorithmPolygon : ModuleAlgorithm<DataPlate> {
|
||||
private ModuleAlgorithmFunction<DataPolygon> EdgePoint = new AFEdgePoint();
|
||||
private ModuleAlgorithmFunction<DataPolygon> Cutting = new AFAuriculareCutting();
|
||||
private ModuleAlgorithmFunction<DataPolygon> Subdivision = new AFSubdivision();
|
||||
private ModuleAlgorithmFunction<DataPolygon> TriangleMesh = new AFTriangleMesh();
|
||||
|
||||
protected override void Awake() => ModuleCore.AlgorithmPolygon = this;
|
||||
|
||||
public override void Compute(DataPlate data) {
|
||||
DataPolygon polygon = new DataPolygon(data);
|
||||
//计算边缘点
|
||||
EdgePoint.Compute(polygon);
|
||||
//切割三角形
|
||||
Cutting.Compute(polygon);
|
||||
//合并三角形
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
Subdivision.Compute(polygon);
|
||||
//三角形转换网格
|
||||
TriangleMesh.Compute(polygon);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef8ce839dfa79ff4d825f55925c48e7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user