UNPKG

jsdk-offical

Version:

JSDK is the most comprehensive TypeScript framework, like JDK.

251 lines (215 loc) 10.2 kB
/** * @project JSDK * @license MIT * @website https://github.com/fengboyue/jsdk * * @version 2.5.0 * @author Frank.Feng */ /// <reference path="Segment.ts" /> module JS { export namespace math { export namespace geom { let M = Math, F = Floats, P = Point2, V = Vector2, R = Radians, S = Segment; export class CirArc implements Shape { type: ArcType; /** * sAngle is the starting radian of the sector in coordinate system with (x,y) as the origin. */ sAngle: number; /** * eAngle is the ending radian of the sector in coordinate system with (x,y) as the origin. */ eAngle: number; /** * 0 is counterclockwise; 1 is clockwise. */ dir: 1 | 0; /** * Centre point's X. */ x: number; /** * Centre point's Y. */ y: number; /** * radius of the circle. */ r: number; static toArc(type: ArcType, c: ArrayPoint2, r: number, sAngle: number, eAngle: number, dir: 1 | 0 = 1) { return new CirArc(type, c[0], c[1], r, sAngle, eAngle, dir) } constructor() constructor(type: ArcType, x: number, y: number, r: number, sAngle: number, eAngle: number, dir?: 1 | 0) constructor(type?: ArcType, x?: number, y?: number, r?: number, sAngle?: number, eAngle?: number, dir: 1 | 0 = 1) { this.type = type || ArcType.OPEN; this.x = x || 0; this.y = y || 0; this.r = r || 0; this.sAngle = sAngle || 0; this.eAngle = eAngle || 0; this.dir = dir == void 0 ? 1 : dir; } isEmpty(): boolean { return this.r <= 0 || this.sAngle === this.eAngle } center(): ArrayPoint2 center(x: number, y: number): this center(x?: number, y?: number): any { if (x == void 0) return [this.x, this.y]; this.x = x; this.y = y; return this } set(s: CirArc) { this.type = s.type; this.x = s.x; this.y = s.y; this.r = s.r; this.sAngle = s.sAngle; this.eAngle = s.eAngle; this.dir = s.dir; return this } clone() { return <this>new CirArc(this.type, this.x, this.y, this.r, this.sAngle, this.eAngle, this.dir) } equals(s: CirArc): boolean { return s.type == this.type && P.equal(s.x, s.y, this.x, this.y) && F.equal(this.r, s.r) && F.equal(this.sAngle, s.sAngle) && F.equal(this.eAngle, s.eAngle) && this.dir === s.dir } _inAngle(p: ArrayPoint2, ps: ArrayPoint2[], cache?: { va: Vector2, vb: Vector2, realRad: number, minRad: number }) { let pc = ps[0], pa = ps[1], pb = ps[2]; if (S.inSegment(pc, pa, p) || S.inSegment(pc, pb, p)) return false; let va = !cache ? V.toVector(pc, pa) : cache.va, vb = !cache ? V.toVector(pc, pb) : cache.vb, vp = V.toVector(pc, p), realAngle = !cache ? R.deg2rad(this.angle()) : cache.realRad, minAngle = !cache ? va.angle(vb) : cache.minRad, is = R.equal(minAngle, vp.angle(va) + vp.angle(vb)); return F.equal(realAngle, minAngle) ? is : !is; } inside(s: ArrayPoint2 | Segment | Rect | Triangle): boolean { if (!s || this.isEmpty()) return false; if (Types.isArray(s)) { if (this.type == ArcType.OPEN) { //在弧上且在夹角内 return (F.equal(this.r * this.r, P.distanceSq(s[0], s[1], this.x, this.y))) && this._inAngle(<ArrayPoint2>s, this.vertexes()) } else { //在圆内且在夹角内 return new Circle(this.x, this.y, this.r).inside(s) && this._inAngle(<ArrayPoint2>s, this.vertexes()) } } if ((<Shape>s).isEmpty()) return false; return (<Shape>s).vertexes().every(p => { return this.inside(p) }) } onside(p: ArrayPoint2): boolean { if (this.isEmpty()) return false; if (!F.equal(this.r * this.r, P.distanceSq(p[0], p[1], this.x, this.y))) return false; let isIn = this._inAngle(p, this.vertexes()); if (!isIn) return false; if (this.type == ArcType.OPEN) return true; //是否在两边 let ps = this.vertexes(), pc = ps[0], pa = ps[1], pb = ps[2]; return S.inSegment(pc, pa, p) || S.inSegment(pc, pb, p) } intersects(s: Segment | Line): boolean { throw new Error("Method not implemented.") } _crossByRay(rad: number) { return P.toPoint(this.center()).toward(this.r, rad).toArray(); } private _bounds(ps: ArrayPoint2[]) { let minX: number, minY: number, maxX: number, maxY: number, aX: number[] = [], aY: number[] = []; ps.forEach(p => { aX.push(p[0]); aY.push(p[1]); }) minX = M.min.apply(M, aX); maxX = M.max.apply(M, aX); minY = M.min.apply(M, aY); maxY = M.max.apply(M, aY); return new Rect(minX, minY, maxX - minX, maxY - minY) } bounds(): Rect { if (this.isEmpty()) return null; let ps = this.vertexes(); return new Triangle().set(ps[0],ps[1],ps[2]).bounds() // pc = ps[0], a = [ps[1], ps[2]], p: ArrayPoint2, // va = V.toVector(pc, ps[1]), // vb = V.toVector(pc, ps[2]), // realAngle = R.deg2rad(this.angle()), // minAngle = va.angle(vb), // cache = { // va: va, // vb: vb, // realRad: realAngle, // minRad: minAngle // } // if (this.type == ArcType.PIE) a.push(pc); // //判断圆的矩形的每条边的最短向量夹角是否在弧线角度内:是则加入边界点数据 // p = this._crossByRay(R.EAST); // if (this._inAngle(p, ps, cache)) a.push(p) // p = this._crossByRay(R.SOUTH); // if (this._inAngle(p, ps, cache)) a.push(p) // p = this._crossByRay(R.WEST); // if (this._inAngle(p, ps, cache)) a.push(p) // p = this._crossByRay(R.NORTH); // if (this._inAngle(p, ps, cache)) a.push(p) // return this._bounds(a) } arcLength() { return this.r * M.abs(this.eAngle - this.sAngle) } /** * Returns a simple approximation value that is within about 5% of the true value (so long as a is not more than 3 times longer than b) . */ perimeter(): number { return this.type == ArcType.OPEN ? this.arcLength() : 2 * this.r + this.arcLength() } area() { return this.type == ArcType.OPEN ? 0 : M.abs(this.eAngle - this.sAngle) * this.r * this.r * 0.5 } vertexes(): ArrayPoint2[] vertexes(ps: ArrayPoint2[]): this vertexes(ps?: ArrayPoint2[]): any { if (arguments.length == 0) { let pc: ArrayPoint2 = [this.x, this.y], pa = P.toPoint(P.polar2xy(this.r, this.sAngle)).translate(this.x, this.y), pb = P.toPoint(P.polar2xy(this.r, this.eAngle)).translate(this.x, this.y); return [pc, [pa.x, pa.y], [pb.x, pb.y]] } let p1 = ps[0], pa = ps[1], pb = ps[2]; this.x = p1[0]; this.y = p1[1]; this.r = P.distance(pa[0], pa[1], this.x, this.y); this.sAngle = V.toVector([this.x, this.y], pa).radian(); this.eAngle = V.toVector([this.x, this.y], pb).radian(); return this } /** * Returns the angle[0,360) in degree. */ angle() { let dif = R.positive(this.eAngle - this.sAngle), d = R.rad2deg(dif) % 360; return this.dir == 1 ? d : 360 - d } moveTo(x: number, y: number) { this.x = x; this.y = y; return this } } } } } import CirArc = JS.math.geom.CirArc;