ShadowEditor/THREE/Math/Triangle.cs
2018-12-08 07:56:02 +08:00

390 lines
8.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace THREE
{
/// <summary>
/// @author bhouston / http://clara.io
/// @author mrdoob / http://mrdoob.com/
/// </summary>
public class Triangle
{
function Triangle(a, b, c )
{
this.a = (a !== undefined) ? a : new Vector3();
this.b = (b !== undefined) ? b : new Vector3();
this.c = (c !== undefined) ? c : new Vector3();
}
getNormal: function()
{
var v0 = new Vector3();
return function getNormal(a, b, c, target) {
if (target === undefined)
{
console.warn('THREE.Triangle: .getNormal() target is now required');
target = new Vector3();
}
target.subVectors(c, b);
v0.subVectors(a, b);
target.cross(v0);
var targetLengthSq = target.lengthSq();
if (targetLengthSq > 0)
{
return target.multiplyScalar(1 / Math.sqrt(targetLengthSq));
}
return target.set(0, 0, 0);
};
}
(),
// static/instance method to calculate barycentric coordinates
// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
getBarycoord: function()
{
var v0 = new Vector3();
var v1 = new Vector3();
var v2 = new Vector3();
return function getBarycoord(point, a, b, c, target) {
v0.subVectors(c, a);
v1.subVectors(b, a);
v2.subVectors(point, a);
var dot00 = v0.dot(v0);
var dot01 = v0.dot(v1);
var dot02 = v0.dot(v2);
var dot11 = v1.dot(v1);
var dot12 = v1.dot(v2);
var denom = (dot00 * dot11 - dot01 * dot01);
if (target === undefined)
{
console.warn('THREE.Triangle: .getBarycoord() target is now required');
target = new Vector3();
}
// collinear or singular triangle
if (denom === 0)
{
// arbitrary location outside of triangle?
// not sure if this is the best idea, maybe should be returning undefined
return target.set(-2, -1, -1);
}
var invDenom = 1 / denom;
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// barycentric coordinates must always sum to 1
return target.set(1 - u - v, v, u);
};
}
(),
containsPoint: function()
{
var v1 = new Vector3();
return function containsPoint(point, a, b, c) {
Triangle.getBarycoord(point, a, b, c, v1);
return (v1.x >= 0) && (v1.y >= 0) && ((v1.x + v1.y) <= 1);
};
}
(),
getUV: function()
{
var barycoord = new Vector3();
return function getUV(point, p1, p2, p3, uv1, uv2, uv3, target) {
this.getBarycoord(point, p1, p2, p3, barycoord);
target.set(0, 0);
target.addScaledVector(uv1, barycoord.x);
target.addScaledVector(uv2, barycoord.y);
target.addScaledVector(uv3, barycoord.z);
return target;
};
}
()
} );
Object.assign(Triangle.prototype, {
set: function(a, b, c )
{
this.a.copy(a);
this.b.copy(b);
this.c.copy(c);
return this;
},
setFromPointsAndIndices: function(points, i0, i1, i2 )
{
this.a.copy(points[i0]);
this.b.copy(points[i1]);
this.c.copy(points[i2]);
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(triangle )
{
this.a.copy(triangle.a);
this.b.copy(triangle.b);
this.c.copy(triangle.c);
return this;
},
getArea: function()
{
var v0 = new Vector3();
var v1 = new Vector3();
return function getArea() {
v0.subVectors(this.c, this.b);
v1.subVectors(this.a, this.b);
return v0.cross(v1).length() * 0.5;
};
}
(),
getMidpoint: function(target )
{
if (target === undefined)
{
console.warn('THREE.Triangle: .getMidpoint() target is now required');
target = new Vector3();
}
return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3);
},
getNormal: function(target )
{
return Triangle.getNormal(this.a, this.b, this.c, target);
},
getPlane: function(target )
{
if (target === undefined)
{
console.warn('THREE.Triangle: .getPlane() target is now required');
target = new Vector3();
}
return target.setFromCoplanarPoints(this.a, this.b, this.c);
},
getBarycoord: function(point, target )
{
return Triangle.getBarycoord(point, this.a, this.b, this.c, target);
},
containsPoint: function(point )
{
return Triangle.containsPoint(point, this.a, this.b, this.c);
},
getUV: function(point, uv1, uv2, uv3, result )
{
return Triangle.getUV(point, this.a, this.b, this.c, uv1, uv2, uv3, result);
},
intersectsBox: function(box )
{
return box.intersectsTriangle(this);
},
closestPointToPoint: function()
{
var vab = new Vector3();
var vac = new Vector3();
var vbc = new Vector3();
var vap = new Vector3();
var vbp = new Vector3();
var vcp = new Vector3();
return function closestPointToPoint(p, target) {
if (target === undefined)
{
console.warn('THREE.Triangle: .closestPointToPoint() target is now required');
target = new Vector3();
}
var a = this.a, b = this.b, c = this.c;
var v, w;
// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
// under the accompanying license; see chapter 5.1.5 for detailed explanation.
// basically, we're distinguishing which of the voronoi regions of the triangle
// the point lies in with the minimum amount of redundant computation.
vab.subVectors(b, a);
vac.subVectors(c, a);
vap.subVectors(p, a);
var d1 = vab.dot(vap);
var d2 = vac.dot(vap);
if (d1 <= 0 && d2 <= 0)
{
// vertex region of A; barycentric coords (1, 0, 0)
return target.copy(a);
}
vbp.subVectors(p, b);
var d3 = vab.dot(vbp);
var d4 = vac.dot(vbp);
if (d3 >= 0 && d4 <= d3)
{
// vertex region of B; barycentric coords (0, 1, 0)
return target.copy(b);
}
var vc = d1 * d4 - d3 * d2;
if (vc <= 0 && d1 >= 0 && d3 <= 0)
{
v = d1 / (d1 - d3);
// edge region of AB; barycentric coords (1-v, v, 0)
return target.copy(a).addScaledVector(vab, v);
}
vcp.subVectors(p, c);
var d5 = vab.dot(vcp);
var d6 = vac.dot(vcp);
if (d6 >= 0 && d5 <= d6)
{
// vertex region of C; barycentric coords (0, 0, 1)
return target.copy(c);
}
var vb = d5 * d2 - d1 * d6;
if (vb <= 0 && d2 >= 0 && d6 <= 0)
{
w = d2 / (d2 - d6);
// edge region of AC; barycentric coords (1-w, 0, w)
return target.copy(a).addScaledVector(vac, w);
}
var va = d3 * d6 - d5 * d4;
if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0)
{
vbc.subVectors(c, b);
w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
// edge region of BC; barycentric coords (0, 1-w, w)
return target.copy(b).addScaledVector(vbc, w); // edge region of BC
}
// face region
var denom = 1 / (va + vb + vc);
// u = va * denom
v = vb * denom;
w = vc * denom;
return target.copy(a).addScaledVector(vab, v).addScaledVector(vac, w);
};
}
(),
equals: function(triangle )
{
return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c);
}
}
}