jsdk-offical
Version:
JSDK is the most comprehensive TypeScript framework, like JDK.
251 lines (215 loc) • 10.2 kB
text/typescript
/**
* @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;