xtorcga
Version:
Xtor Compute Geometry Algorithm Libary 计算几何算法库
279 lines (230 loc) • 7.57 kB
text/typescript
/**
* 当向量以数组的方式出现,一个计算单元库
* @Description : 向量数组
* @Author : 赵耀圣
* @QQ : 549184003
* @Date : 2021-08-02 15:09:33
* @LastEditTime : 2021-08-02 15:50:16
* @FilePath : \cga.js\src\math\VecArray.ts
*/
import { Polygon } from "../struct/3d/Polygon"
import { Polyline } from "../struct/3d/Polyline"
import { Vec2 } from "./Vec2"
import { Vec3 } from './Vec3';
import { ArrayList } from '../struct/data/ArrayList';
const ckeckVec = (vs: any, component: number) => {
if (vs.length % component !== 0)
throw ("向量组件数量不一样")
}
export class vector {
/**
* 检测相邻没有重复点
*/
static uniqueNeighbor(vs: number[], component: number = 3) {
for (let i = 0; i < vs.length; i += component) {
for (let j = i + 3; j < vs.length;) {
let lensq = 0
for (let c = 0; c < component; c++) {
lensq += (vs[i + c] - vs[j + c]) * (vs[i + c] - vs[j + c])
}
if (Math.sqrt(lensq) < 1e-5)
vs.splice(j, component)
else
break;
}
}
return vs;
}
/**
* 去除任意重复点
* @param vs 向量数组
* @param component 向量组件数量
* @returns 无重复向量数组
*/
static unique(vs: number[], component: number = 3) {
for (let i = 0; i < vs.length; i += component) {
for (let j = i + 3; j < vs.length;) {
let lensq = 0
for (let c = 0; c < component; c++) {
lensq += (vs[i + c] - vs[j + c]) * (vs[i + c] - vs[j + c])
}
if (Math.sqrt(lensq) < 1e-5)
vs.splice(j, component)
else
j += component
}
}
return vs;
}
/**
* 翻转向量数组
* @param vecs 向量数组
* @param component 组件数量
* @returns
*/
static reverse(vecs: number[], component: number = 3) {
ckeckVec(vecs, component);
const length = vecs.length;
for (let i = 0; i < length; i += component) {
vecs.unshift(...vecs.splice(i, component))
}
return vecs;
}
/**
* 点积
* @param vecs
* @returns
*/
static dot(...vecs: number[]) {
if (vecs.length % 2 !== 0)
throw ("两个向量组件数量不一样")
const len = vecs.length / 2;
let dot = 0;
for (let i = 0; i < len; i++) {
dot += vecs[i] * vecs[len + i];
}
return dot;
}
/**
* 长度平方
* @param vecs
* @returns
*/
static distanceSq(...vecs: number[]) {
if (vecs.length % 2 !== 0)
throw ("向量组件数量不一样")
const len = vecs.length / 2;
let lenSq = 0;
for (let i = 0; i < len; i++) {
var d = (vecs[i] - vecs[len + i]);
lenSq += d * d;
}
return lenSq;
}
/**
* 长度
* @param vecs
* @returns
*/
static distance(...vecs: number[]) {
return Math.sqrt(this.distanceSq(...vecs));
}
/**
* 相加
* @param vecs
* @returns
*/
static add(...vecs: number[]) {
if (vecs.length % 2 !== 0)
throw ("两个向量组件数量不一样")
if (Array.isArray(vecs[0]) && Array.isArray(vecs[1])) {
for (let i = 0; i < vecs[0].length; i++) {
vecs[0][i] += vecs[1][i];
}
return vecs[0]
}
if (vecs.length % 2 !== 0)
console.error("VecArray:distanceSq 向量错误!!!");
const len = vecs.length / 2;
let res: number[] = [];
for (let i = 0; i < len; i++) {
res[i] = res[len + i] + res[i];
}
return res;
}
/**
* 相减
* @param vecs
* @returns
*/
static sub(...vecs: number[]): number[] {
ckeckVec(vecs, 2);
if (Array.isArray(vecs[0]) && Array.isArray(vecs[1])) {
for (let i = 0; i < vecs[0].length; i++) {
vecs[0][i] -= vecs[1][i];
}
return vecs[0]
}
if (vecs.length % 2 !== 0)
console.error("VecArray:distanceSq 向量错误!!!");
const len = vecs.length / 2;
let res: number[] = [];
for (let i = 0; i < len; i++) {
res[i] = res[i] - res[len + i];
}
return res;
}
/**
* 相乘
* @param vecs
* @returns
*/
static mul(...vecs: number[]) {
ckeckVec(vecs, 2);
if (Array.isArray(vecs[0]) && Array.isArray(vecs[1])) {
for (let i = 0; i < vecs[0].length; i++) {
vecs[0][i] *= vecs[1][i];
}
return vecs[0]
}
if (vecs.length % 2 !== 0)
console.error("VecArray:distanceSq 向量错误!!!");
const len = vecs.length / 2;
let res: number[] = [];
for (let i = 0; i < len; i++) {
res[i] = res[i] * res[len + i];
}
return res;
}
/**
* 获取矢量数组的i个矢量
* @param vecs
* @param i
* @param component
* @returns
*/
static getVecAt(vecs: number[], i: number, component: number = 3): number[] {
return [vecs[3 * i], vecs[3 * i + 1], vecs[3 * i + 2]]
}
/**
* 在第 i 个位置插入一个向量
* @param vecs
* @param i
* @param vec
*/
static insertAt(vecs: number[], i: number, ...vec: number[]) {
vecs.splice(i * vecs.length, 0, ...vecs);
}
//
/**
* 是否逆时针
* counterclockwise
*/
static isCCW<T>(shape: Array<T> | ArrayList<T>, component: number = 3): boolean {
let d = 0;
if (shape instanceof Polyline || shape instanceof Polygon)
for (let i = 0; i < shape.length; i++) {
const pt = shape.get(i);
const ptnext = shape.get((i + 1) % shape.length);
d += -0.5 * (ptnext.y + pt.y) * (ptnext.x - pt.x);
}
else if (Array.isArray(shape) && shape.length > 0) {
if (shape[0] instanceof Vec3 || shape[0] instanceof Vec2) {
for (let i = 0; i < shape.length; i++) {
const pt: Vec3 | Vec2 = shape[i] as any;
const ptnext: Vec3 | Vec2 = shape[(i + 1) % shape.length] as any;
d += -0.5 * (ptnext.y + pt.y) * (ptnext.x - pt.x);
}
} else if (!isNaN(shape[0] as any)) {
for (let i = 0; i < shape.length; i += component) {
const ptx: number = shape[i] as any;
const pty: number = shape[(i + 1) % shape.length] as any;
const ptnextx = shape[(i + 3) % shape.length] as any;
const ptnexty = shape[(i + 4) % shape.length] as any;
d += -0.5 * (ptnexty + pty) * (ptnextx - ptx);
}
}
}
return d > 0;
}
}