UNPKG

@xtor/cga.js

Version:

Xtor Compute Geometry Algorithm Libary 计算几何算法库

101 lines (83 loc) 3.88 kB
import { ArrayEx } from "../data/ArrayEx"; import { v3, Vector3 } from "../../math/Vector3"; import { Segment } from "./Segment"; import { Line } from "./Line"; import { Orientation } from "./type"; import { sign, gPrecision } from "../../math/Math"; /** * 线段正反原则:右手坐标系中,所在平面为XZ平面,把指向方向看着负Z轴,x正为正方向,x负为负方向 */ export class Polyline extends ArrayEx { constructor(vs, normal = v3(0, 1, 0)) { super(); this.push(...vs); this.isCoPlanar = true; this.normal = normal; } /** * 偏移 * @param {Number} distance 偏移距离 * @param {Vector3} normal 折线所在平面法线 */ offset(distance, normal = this.normal) { var offsetSign = sign(distance) > 0 ? Orientation.Positive : Orientation.Negative; var direction = new Vector3(); var segments = [];//偏移过后的线段 for (let i = 0; i < this.length - 1; i++) { const point = this[i]; const pointNext = this[i + 1]; var binormal = direction.sub(pointNext, point).normalize().cross(this.normal).normalize(); var offsetVector = binormal.clone().multiplyScalar(distance); segments.push([offsetVector.clone().add(point), offsetVector.add(pointNext)]) } //线段两两相交 for (let i = 0; i < segments.length; i++) { const segi = segments[i]; for (let j = 0; j < segments.length; j++) { if (i === j) continue; const segj = segments[j]; var orien0 = segi.orientationSegment(segj.p0, normal) var orien1 = segi.orientationSegment(segj.fixedPoint1, normal) var orienInfo = orien0 | orien1; var disRes = segi.distanceSegment(segj); if (disRes.distance > gPrecision) { if (orienInfo !== offsetSign) { segments.splice(j, 1); j--; } } else { // 出现相交 那么就会有切割 var intersectPoit = disRes.closests[0]; //删除不要的部分 } } } return new Polyline(this); } /** * 圆角 将折线拐点圆角化 * @param {Number} useDistance 圆角段距离 * @param {Number} segments 分切割段数 */ corner(useDistance, segments = 3, normal = this.normal, threshold = 0.1) { var polyline = new Polyline(); for (let i = 0; i < this.length - 2; i++) { polyline.push(p0); const p0 = this[i]; const p1 = this[i + 1]; const p2 = this[i + 2]; var fixedPoint0 = p0.distanceTo(p1).length() <= useDistance * 2 ? p0.clone().add(p1).multiplyScalar(0.5) : p0.clone().sub(p1).normalize().multiplyScalar(useDistance).add(p1); var fixedPoint1 = p2.distanceTo(p1).length() <= useDistance * 2 ? p2.clone().add(p1).multiplyScalar(0.5) : p2.clone().sub(p1).normalize().multiplyScalar(useDistance).add(p1); polyline.push(fixedPoint0); var binormal0 = p1.clone().sub(p0).applyAxisAngle(normal, Math.PI / 2); var binormal1 = p1.clone().sub(p0).applyAxisAngle(normal, Math.PI / 2); //计算圆弧点 var line0 = new Line(fixedPoint0, binormal0.add(fixedPoint0)); var line1 = new Line(fixedPoint1, binormal1.add(fixedPoint1)); var center = line0.distanceLine(line1).closests[0];//圆心 polyline.push(fixedPoint1); } return polyline; } }