新增polygonmesh

This commit is contained in:
YHH
2020-06-10 08:57:17 +08:00
parent 1816b16924
commit 538677575d
11 changed files with 556 additions and 2 deletions

View File

@@ -0,0 +1,54 @@
class Mesh extends Component {
private _verts: VertexPosition[];
private _primitiveCount: number;
private _triangles: number[];
private _topLeftVertPosition: Vector2;
private _width;
private _height;
public initialize() {
}
public setVertPosition(positions: Vector2[]){
let createVerts = !this._verts || this._verts.length != positions.length;
if (createVerts)
this._verts = new Array(positions.length);
for (let i = 0; i < this._verts.length; i ++){
this._verts[i] = new VertexPosition(positions[i]);
}
return this;
}
public setTriangles(triangles: number[]){
this._primitiveCount = triangles.length / 3;
this._triangles = triangles;
return this;
}
public recalculateBounds(){
this._topLeftVertPosition = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
let max = new Vector2(Number.MIN_VALUE, Number.MIN_VALUE);
for (let i = 0; i < this._verts.length; i ++){
this._topLeftVertPosition.x = Math.min(this._topLeftVertPosition.x, this._verts[i].position.x);
this._topLeftVertPosition.y = Math.min(this._topLeftVertPosition.y, this._verts[i].position.y);
max.x = Math.max(max.x, this._verts[i].position.x);
max.y = Math.max(max.y, this._verts[i].position.y);
}
this._width = max.x - this._topLeftVertPosition.x;
this._height = max.y - this._topLeftVertPosition.y;
return this;
}
}
class VertexPosition{
public position: Vector2;
constructor(position: Vector2){
this.position = position;
}
}

View File

@@ -0,0 +1,12 @@
class PolygonMesh extends Mesh {
constructor(points: Vector2[], arePointsCCW: boolean = true){
super();
let triangulator = new Triangulator();
triangulator.triangulate(points, arePointsCCW);
this.setVertPosition(points);
this.setTriangles(triangulator.triangleIndices);
this.recalculateBounds();
}
}

View File

@@ -0,0 +1,111 @@
/**
* 三角剖分
*/
class Triangulator {
/**
* 最后一次三角调用中使用的点列表的三角形列表项的索引
*/
public triangleIndices: number[] = [];
private _triPrev: number[] = new Array<number>(12);
private _triNext: number[] = new Array<number>(12);
/**
* 计算一个三角形列表该列表完全覆盖给定点集所包含的区域。如果点不是CCW则将arePointsCCW参数传递为false
* @param points 定义封闭路径的点列表
* @param arePointsCCW
*/
public triangulate(points: Vector2[], arePointsCCW: boolean = true){
let count = points.length;
// 设置前一个链接和下一个链接
this.initialize(count);
// 非三角的多边形断路器
let iterations = 0;
// 从0开始
let index = 0;
// 继续移除所有的三角形,直到只剩下一个三角形
while (count > 3 && iterations < 500){
iterations ++;
let isEar = true;
let a = points[this._triPrev[index]];
let b = points[index];
let c = points[this._triNext[index]];
if (Vector2Ext.isTriangleCCW(a, b, c)){
let k = this._triNext[this._triNext[index]];
do {
if (Triangulator.testPointTriangle(points[k], a, b, c)){
isEar = false;
break;
}
k = this._triNext[k];
} while (k != this._triPrev[index]);
}else{
isEar = false;
}
if (isEar){
this.triangleIndices.push(this._triPrev[index]);
this.triangleIndices.push(index);
this.triangleIndices.push(this._triNext[index]);
// 删除vert通过重定向相邻vert的上一个和下一个链接从而减少vertext计数
this._triNext[this._triPrev[index]] = this._triNext[index];
this._triPrev[this._triNext[index]] = this._triPrev[index];
count --;
// 接下来访问前一个vert
index = this._triPrev[index];
}else{
index = this._triNext[index];
}
}
this.triangleIndices.push(this._triPrev[index]);
this.triangleIndices.push(index);
this.triangleIndices.push(this._triNext[index]);
if (!arePointsCCW)
this.triangleIndices.reverse();
}
private initialize(count: number){
this.triangleIndices.length = 0;
if (this._triNext.length < count){
this._triNext.reverse();
this._triNext = new Array<number>(Math.max(this._triNext.length * 2, count));
}
if (this._triPrev.length < count){
this._triPrev.reverse();
this._triPrev = new Array<number>(Math.max(this._triPrev.length * 2, count));
}
for (let i = 0; i < count;i ++){
this._triPrev[i] = i - 1;
this._triNext[i] = i + 1;
}
this._triPrev[0] = count - 1;
this._triNext[count - 1] = 0;
}
public static testPointTriangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): boolean{
if (Vector2Ext.cross(Vector2.subtract(point, a), Vector2.subtract(b, a)) < 0)
return false;
if (Vector2Ext.cross(Vector2.subtract(point, b), Vector2.subtract(c, b)) < 0)
return false;
if (Vector2Ext.cross(Vector2.subtract(point, c), Vector2.subtract(a, c)) < 0)
return false;
return true;
}
}

View File

@@ -0,0 +1,20 @@
class Vector2Ext {
/**
* 检查三角形是CCW还是CW
* @param a
* @param center
* @param c
*/
public static isTriangleCCW(a: Vector2, center: Vector2, c: Vector2){
return this.cross(Vector2.subtract(center, a), Vector2.subtract(c, center)) < 0;
}
/**
* 计算二维伪叉乘点(Perp(u) v)
* @param u
* @param v
*/
public static cross(u: Vector2, v: Vector2){
return u.y * v.x - u.x * v.y;
}
}