UNPKG

jsdk-offical

Version:

JSDK is the most comprehensive TypeScript framework, like JDK.

253 lines (214 loc) 9.6 kB
/** * @project JSDK * @license MIT * @website https://github.com/fengboyue/jsdk * * @version 2.5.0 * @author Frank.Feng */ /// <reference path="Shape.ts" /> module JS { export namespace math { export namespace geom { let P = Point2, V = Vector2, N = Numbers, S = Segment; export class Triangle implements Shape { x1: number; y1: number; x2: number; y2: number; x3: number; y3: number; static toTri(p1: ArrayPoint2, p2: ArrayPoint2, p3: ArrayPoint2) { return new Triangle().set(p1, p2, p3) } constructor() constructor(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number) constructor(x1?: number, y1?: number, x2?: number, y2?: number, x3?: number, y3?: number) { this.x1 = x1 || 0; this.y1 = y1 || 0; this.x2 = x2 || 0; this.y2 = y2 || 0; this.x3 = x3 || 0; this.y3 = y3 || 0; } isEmpty(): boolean { return Line.isCollinear(this.p1(), this.p2(), this.p3()); } p1(): ArrayPoint2 p1(x: number, y: number): this p1(x?: number, y?: number): any { if (x == void 0) return [this.x1, this.y1]; this.x1 = x; this.y1 = y; return this } p2(): ArrayPoint2 p2(x: number, y: number): this p2(x?: number, y?: number): any { if (x == void 0) return [this.x2, this.y2]; this.x2 = x; this.y2 = y; return this } p3(): ArrayPoint2 p3(x: number, y: number): this p3(x?: number, y?: number): any { if (x == void 0) return [this.x3, this.y3]; this.x3 = x; this.y3 = y; return this } set(t: Triangle): this set(p1: ArrayPoint2, p2: ArrayPoint2, p3: ArrayPoint2): this set(p1: ArrayPoint2 | Triangle, p2?: ArrayPoint2, p3?: ArrayPoint2) { if (arguments.length == 1) return this.vertexes((<Triangle>p1).vertexes()); return this.vertexes([<ArrayPoint2>p1, p2, p3]) } vertexes(): ArrayPoint2[] vertexes(ps: ArrayPoint2[]): this vertexes(ps?: ArrayPoint2[]): any { let T = this; if (arguments.length == 0) return [[T.x1, T.y1], [T.x2, T.y2], [T.x3, T.y3]] let p1 = ps[0], p2 = ps[1], p3 = ps[2]; this.x1 = p1[0]; this.y1 = p1[1]; this.x2 = p2[0]; this.y2 = p2[1]; this.x3 = p3[0]; this.y3 = p3[1]; return this } clone() { let T = this; return <this>new Triangle(T.x1, T.y1, T.x2, T.y2, T.x3, T.y3) } equals(s: Triangle): boolean { if (this.isEmpty() && s.isEmpty()) return true; return Arrays.same(this.vertexes(), s.vertexes(), (p1, p2) => { return P.equal(p1, p2) }) } inside(s: ArrayPoint2 | Segment | Rect | Circle): boolean { let T = this; if (!s || T.isEmpty()) return false; if (Types.isArray(s)) return Shapes.inShape(<ArrayPoint2>s, this); if ((<Shape>s).isEmpty()) return false; if(s instanceof Circle) { //处理圆 let c = <Circle>s; //圆心必须在三角形内 if(!Shapes.inShape([c.x,c.y], this)) return false; //计算圆心到边的距离 let rr = c.r*c.r; return this.edges().every(b=>{ return Floats.greaterEqual(Line.distanceSqToPoint(b.p1(),b.p2(),[c.x,c.y]),rr) }) } return (<Shape>s).vertexes().every(p => { return T.inside(p) || T.onside(p) }) } onside(p: ArrayPoint2): boolean { return !this.isEmpty() && Shapes.onShape(p, this) } private _addPoint(a: ArrayPoint2[], p: ArrayPoint2) { if (p && a.findIndex(b => { return P.equal(b, p) }) < 0) a.push(p) } intersects(s: Segment | Line | Rect): boolean { let T = this; if (!s || T.isEmpty() || s.isEmpty()) return false; if (s instanceof Rect) { //如果矩形在内部则必定相交 if (T.inside(s)) return true; //求所有矩形边与三角型边的有效交点 let ps: ArrayPoint2[] = []; T.edges().forEach(b => { let cps = Shapes.crossPoints(b, s); cps.forEach(it => { T._addPoint(ps, it) }) }) return ps.length >= 2 } let ps = Shapes.crossPoints(s, T), len = ps.length; if (len == 0) return false; if (len >= 2) return true; if (!(s instanceof S)) return false; //是线段且只有一个交点:判断是否有一个顶点在三角形内部 let p1 = s.p1(), p2 = s.p2(); return T.inside(p1) || T.inside(p2) } bounds(): Rect { let T = this, minX = N.min(T.x1, T.x2, T.x3), minY = N.min(T.y1, T.y2, T.y3), maxX = N.max(T.x1, T.x2, T.x3), maxY = N.max(T.y1, T.y2, T.y3), w = maxX - minX, h = maxY - minY, x = minX, y = minY; return new Rect(x, y, w, h) } edges() { let ps = this.vertexes(), p1 = ps[0], p2 = ps[1], p3 = ps[2], a = new S(p1[0], p1[1], p2[0], p2[1]), b = new S(p2[0], p2[1], p3[0], p3[1]), c = new S(p3[0], p3[1], p1[0], p1[1]); return [a, b, c] } private _sides() { let ps = this.vertexes(), p1 = ps[0], p2 = ps[1], p3 = ps[2], a = P.distance(p1[0], p1[1], p2[0], p2[1]), b = P.distance(p2[0], p2[1], p3[0], p3[1]), c = P.distance(p3[0], p3[1], p1[0], p1[1]); return [a, b, c] } perimeter(): number { if (this.isEmpty()) return 0; let s = this._sides(); return s[0] + s[1] + s[2] } /** * Returns three degree angles. */ angles(): number[] { let T = this; if (T.isEmpty()) return []; let a1 = new V().set(T.p1(), T.p2()).angle(new V().set(T.p1(), T.p3())), a2 = new V().set(T.p2(), T.p1()).angle(new V().set(T.p2(), T.p3())), d1 = Radians.rad2deg(a1), d2 = Radians.rad2deg(a2), d3 = 180 - d1 - d2; return [d1, d2, d3] } angleType(): AngleType { if (this.isEmpty()) return AngleType.UNKNOWN; let as = this.angles(), d1 = as[0] - 90, d2 = as[1] - 90, d3 = as[2] - 90; if (d1 == 0 || d2 == 0 || d3 == 0) return AngleType.RIGHT; if (d1 < 0 || d2 < 0 || d3 < 0) return AngleType.ACUTE; return AngleType.OBTUSE } area() { if (this.isEmpty()) return 0; let s = this._sides(), a = s[0], b = s[1], c = s[2], p = (a + b + c) / 2; return Math.sqrt(p * (p - a) * (p - b) * (p - c)); } /** * Returns the center of gravity. * 求三角形的重心 */ gravityPoint(): ArrayPoint2 { let T = this; if (T.isEmpty()) return null; let p1 = T.p1(), p2 = T.p2(), p3 = T.p3(); return [(p1[0] + p2[0] + p3[0]) / 3, (p1[1] + p2[1] + p3[1]) / 3] } } } } } import Triangle = JS.math.geom.Triangle;