| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- import { Vector2, ShapeUtils, Box2 } from "three";
- import { Transform } from "konva/lib/Util";
- import { rangMod, round } from "./shared.ts";
- import { IRect } from "konva/lib/types";
- export type Pos = { x: number; y: number };
- export type Size = { width: number; height: number };
- export const vector = (pos: Pos = { x: 0, y: 0 }): Vector2 => {
- return new Vector2(pos.x, pos.y);
- // if (pos instanceof Vector2) {
- // return pos;
- // } else {
- // return new Vector2(pos.x, pos.y);
- // }
- };
- export const lVector = (line: Pos[]) => line.map(vector);
- export const zeroEq = (n: number) => Math.abs(n) < 0.0001;
- export const numEq = (p1: number, p2: number) => zeroEq(p1 - p2);
- export const vEq = (v1: Pos, v2: Pos) => numEq(v1.x, v2.x) && numEq(v1.y, v2.y);
- export const vsBound = (positions: Pos[]) => {
- const box = new Box2();
- box.setFromPoints(positions.map(vector));
- return box;
- };
- /**
- * 获取线段方向
- * @param line 线段
- * @returns 方向
- */
- export const lineVector = (line: Pos[]) =>
- vector(line[1]).sub(vector(line[0])).normalize();
- /**
- * 点是否相同
- * @param p1 点1
- * @param p2 点2
- * @returns 是否相等
- */
- export const eqPoint = vEq;
- /**
- * 方向是否相同
- * @param p1 点1
- * @param p2 点2
- * @returns 是否相等
- */
- export const eqNGDire = (p1: Pos, p2: Pos) =>
- eqPoint(p1, p2) || eqPoint(p1, vector(p2).multiplyScalar(-1));
- /**
- * 获取两点距离
- * @param p1 点1
- * @param p2 点2
- * @returns 距离
- */
- export const lineLen = (p1: Pos, p2: Pos) => vector(p1).distanceTo(p2);
- export const vectorLen = (dire: Pos) => vector(dire).length();
- /**
- * 获取向量的垂直向量
- * @param dire 原方向
- * @returns 垂直向量
- */
- export const verticalVector = (dire: Pos) =>
- vector({ x: -dire.y, y: dire.x }).normalize();
- /**
- * 获取旋转指定度数后的向量
- * @param pos 远向量
- * @param angleRad 旋转角度
- * @returns 旋转后向量
- */
- export const rotateVector = (pos: Pos, angleRad: number) =>
- new Transform().rotate(angleRad).point(pos);
- /**
- * 创建线段
- * @param dire 向量
- * @param start 起始点
- * @param dis 长度
- * @returns 线段
- */
- export const getVectorLine = (
- dire: Pos,
- start: Pos = { x: 0, y: 0 },
- dis: number = 1
- ) => [start, vector(dire).multiplyScalar(dis).add(start)];
- /**
- * 获取线段的垂直方向向量
- * @param line 原线段
- * @returns 垂直向量
- */
- export const lineVerticalVector = (line: Pos[]) =>
- verticalVector(lineVector(line));
- /**
- * 获取向量的垂直线段
- * @param dire 向量
- * @param start 线段原点
- * @param len 线段长度
- */
- export const verticalVectorLine = (
- dire: Pos,
- start: Pos = { x: 0, y: 0 },
- len: number = 1
- ) => getVectorLine(verticalVector(dire), start, len);
- /**
- * 获取两向量角度(从向量a出发)
- * @param v1 向量a
- * @param v2 向量b
- * @returns 两向量夹角弧度, 逆时针为正,顺时针为负
- */
- export const vector2IncludedAngle = (v1: Pos, v2: Pos) => {
- const start = vector(v1);
- const end = vector(v2);
- const angle = start.angleTo(end);
- return start.cross(end) > 0 ? angle : -angle;
- };
- // 判断多边形方向(Shoelace Formula)
- export function getPolygonDirection(points: Pos[]) {
- let area = 0;
- const numPoints = points.length;
- for (let i = 0; i < numPoints; i++) {
- const p1 = points[i];
- const p2 = points[(i + 1) % numPoints];
- area += (p2.x - p1.x) * (p2.y + p1.y);
- }
- // 如果面积为正,是逆时针;否则是顺时针
- return area;
- }
- /**
- * 获取两线段角度(从线段a出发)
- * @param line1 线段a
- * @param line2 线段b
- * @returns 两线段夹角弧度
- */
- export const line2IncludedAngle = (line1: Pos[], line2: Pos[]) =>
- vector2IncludedAngle(lineVector(line1), lineVector(line2));
- /**
- * 获取向量与X正轴角度
- * @param v 向量
- * @returns 夹角弧度
- */
- const nXAxis = vector({ x: 1, y: 0 });
- export const vectorAngle = (v: Pos) => {
- const start = vector(v);
- return start.angleTo(nXAxis);
- };
- /**
- * 获取线段与方向的夹角弧度
- * @param line 线段
- * @param dire 方向
- * @returns 线段与方向夹角弧度
- */
- export const lineAndVectorIncludedAngle = (line: Pos[], v: Pos) =>
- vector2IncludedAngle(lineVector(line), v);
- /**
- * 获取线段中心点
- * @param line
- * @returns
- */
- export const lineCenter = (line: Pos[]) => {
- const start = vector(line[0]);
- for (let i = 1; i < line.length; i++) {
- start.add(line[i]);
- }
- return start.multiplyScalar(1 / line.length);
- };
- export const lineSpeed = (line: Pos[], step: number) => {
- const p = vector(line[0]);
- const v = vector(line[1]).sub(line[0]);
- return p.add(v.multiplyScalar(step));
- };
- export const pointsCenter = (points: Pos[]) => {
- if (points.length === 0) return { x: 0, y: 0 };
- const v = vector(points[0]);
- for (let i = 1; i < points.length; i++) {
- v.add(points[i]);
- }
- return v.multiplyScalar(1 / points.length);
- };
- export const lineJoin = (l1: Pos[], l2: Pos[]) => {
- const checks = [
- [l1[0], l2[0]],
- [l1[0], l2[1]],
- [l1[1], l2[0]],
- [l1[1], l2[1]],
- ];
- const ndx = checks.findIndex((line) => eqPoint(line[0], line[1]));
- if (~ndx) {
- return checks[ndx];
- } else {
- return false;
- }
- };
- export const isLineEqual = (l1: Pos[], l2: Pos[]) =>
- eqPoint(l1[0], l2[0]) && eqPoint(l1[1], l2[1]);
- export const isLineReverseEqual = (l1: Pos[], l2: Pos[]) =>
- eqPoint(l1[0], l2[1]) && eqPoint(l1[1], l2[0]);
- export const isLineIntersect = (l1: Pos[], l2: Pos[]) => {
- const s1 = l2[1].y - l2[0].y;
- const s2 = l2[1].x - l2[0].x;
- const s3 = l1[1].x - l1[0].x;
- const s4 = l1[1].y - l1[0].y;
- const s5 = l1[0].y - l2[0].y;
- const s6 = l1[0].x - l2[0].x;
- const denominator = s1 * s3 - s2 * s4;
- const ua = round((s2 * s5 - s1 * s6) / denominator, 6);
- const ub = round((s3 * s5 - s4 * s6) / denominator, 6);
- if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {
- return true;
- } else {
- return false;
- }
- };
- export const vectorParallel = (dire1: Pos, dire2: Pos) =>
- zeroEq(vector(dire1).cross(dire2));
- export const lineParallelRelationship = (l1: Pos[], l2: Pos[]) => {
- const dire1 = lineVector(l1);
- const dire2 = lineVector(l2);
- // 计算线段的法向量
- const normal1 = verticalVector(dire1);
- const normal2 = verticalVector(dire2);
- const startDire = lineVector([l1[0], l2[0]]);
- // 计算线段的参数方程
- const t1 = round(normal2.dot(startDire) / normal2.dot(dire1), 6);
- const t2 = round(normal1.dot(startDire) / normal1.dot(dire2), 6);
- if (t1 === 0 && t2 === 0) {
- return RelationshipEnum.Overlap;
- }
- if (eqPoint(normal1, normal2) || eqPoint(normal1, normal2.clone().negate())) {
- return lineJoin(l1, l2)
- ? RelationshipEnum.Overlap
- : RelationshipEnum.Parallel;
- }
- };
- export enum RelationshipEnum {
- // 重叠
- Overlap = "Overlap",
- // 相交
- Intersect = "Intersect",
- // 延长相交
- ExtendIntersect = "ExtendIntersect",
- // 平行
- Parallel = "Parallel",
- // 首尾连接
- Join = "Join",
- // 一样
- Equal = "Equal",
- // 反向
- ReverseEqual = "ReverseEqual",
- }
- /**
- * 获取两线段是什么关系,(重叠、相交、平行、首尾相接等)
- * @param l1
- * @param l2
- * @returns RelationshipEnum
- */
- export const lineRelationship = (l1: Pos[], l2: Pos[]) => {
- if (isLineEqual(l1, l2)) {
- return RelationshipEnum.Equal;
- } else if (isLineReverseEqual(l1, l2)) {
- return RelationshipEnum.ReverseEqual;
- }
- const parallelRelationship = lineParallelRelationship(l1, l2);
- if (parallelRelationship) {
- return parallelRelationship;
- } else if (lineJoin(l1, l2)) {
- return RelationshipEnum.Join;
- } else if (isLineIntersect(l1, l2)) {
- return RelationshipEnum.Intersect; // 两线段相交
- } else {
- return RelationshipEnum.ExtendIntersect; // 延长可相交
- }
- };
- export const createLine = (p: Pos, v: Pos, l?: number) => {
- const line = [p];
- if (l) {
- v = vector(v).multiplyScalar(l);
- }
- line[1] = vector(line[0]).add(v);
- return line;
- };
- /**
- * 获取两线段交点,可延长相交
- * @param l1 线段1
- * @param l2 线段2
- * @returns 交点坐标
- */
- export const lineIntersection = (l1: Pos[], l2: Pos[]) => {
- // 定义两条线段的起点和终点坐标
- const [line1Start, line1End] = lVector(l1);
- const [line2Start, line2End] = lVector(l2);
- // 计算线段的方向向量
- const dir1 = line1End.clone().sub(line1Start);
- const dir2 = line2End.clone().sub(line2Start);
- // 计算参数方程中的系数
- const a = dir1.x;
- const b = -dir2.x;
- const c = dir1.y;
- const d = -dir2.y;
- const e = line2Start.x - line1Start.x;
- const f = line2Start.y - line1Start.y;
- // 求解参数t和s
- const t = (d * e - b * f) / (a * d - b * c);
- // 计算交点坐标
- const p = line1Start.clone().add(dir1.clone().multiplyScalar(t));
- if (isNaN(p.x) || !isFinite(p.x) || isNaN(p.y) || !isFinite(p.y)) return null;
- return p;
- };
- /**
- * 获取点是否在线上
- * @param line 线段
- * @param position 点
- */
- export const lineInner = (line: Pos[], position: Pos) => {
- // 定义线段的起点和终点坐标
- const [A, B] = lVector(line);
- // 定义一个点的坐标
- const P = vector(position);
- // 计算向量 AP 和 AB
- const AP = P.clone().sub(A);
- const AB = B.clone().sub(A);
- // 计算叉积
- const crossProduct = AP.x * AB.y - AP.y * AB.x;
- // 如果叉积不为 0,说明点 P 不在直线 AB 上
- if (!zeroEq(crossProduct)) {
- return false;
- }
- // 检查点 P 的坐标是否在 A 和 B 的坐标范围内
- const minX = Math.min(A.x, B.x);
- const maxX = Math.max(A.x, B.x);
- const minY = Math.min(A.y, B.y);
- const maxY = Math.max(A.y, B.y);
- return (
- (minX < P.x || numEq(minX, P.x)) &&
- (P.x < maxX || numEq(maxX, P.x)) &&
- (minY < P.y || numEq(minY, P.y)) &&
- (P.y < maxY || numEq(maxY, P.y))
- );
- };
- /**
- * 获取点在线段上的投影
- * @param line 线段
- * @param position 点
- * @returns 投影信息
- */
- export const linePointProjection = (line: Pos[], position: Pos) => {
- // 定义线段的起点和终点坐标
- const [lineStart, lineEnd] = lVector(line);
- // 定义一个点的坐标
- const point = vector(position);
- // 计算线段的方向向量
- const lineDir = lineEnd.clone().sub(lineStart);
- // 计算点到线段起点的向量
- const pointToLineStart = point.clone().sub(lineStart);
- // 计算点在线段方向上的投影长度
- const t = pointToLineStart.dot(lineDir.normalize());
- // 计算投影点的坐标
- return lineStart.add(lineDir.multiplyScalar(t));
- };
- /**
- * 获取点距离线段最近距离
- * @param line 直线
- * @param position 参考点
- * @returns 距离
- */
- export const linePointLen = (line: Pos[], position: Pos) =>
- lineLen(position, linePointProjection(line, position));
- /**
- * 计算多边形是否为逆时针
- * @param points 多边形顶点
- * @returns true | false
- */
- export const isPolygonCounterclockwise = (points: Pos[]) =>
- ShapeUtils.isClockWise(points.map(vector));
- /**
- * 切割线段,返回连段切割点
- * @param line 线段
- * @param amount 切割份量
- * @param unit 一份单位大小
- * @returns 点数组
- */
- export const lineSlice = (
- line: Pos[],
- amount: number,
- unit = lineLen(line[0], line[1]) / amount
- ) =>
- new Array(unit)
- .fill(0)
- .map((_, i) => linePointProjection(line, { x: i * unit, y: i * unit }));
- /**
- * 线段是否相交多边形
- * @param polygon 多边形
- * @param line 检测线段
- * @returns
- */
- export const isPolygonLineIntersect = (polygon: Pos[], line: Pos[]) => {
- for (let i = 0; i < polygon.length; i++) {
- if (isLineIntersect([polygon[i], polygon[i + 1]], line)) {
- return true;
- }
- }
- return false;
- };
- /**
- * 线段与多边形交点
- * @param polygon 多边形
- * @param line 检测线段
- * @returns
- */
- export const polygonLineIntersect = (polygon: Pos[], line: Pos[]) => {
- const ps: Pos[] =[]
- for (let i = 0; i < polygon.length; i++) {
- const line2 = [polygon[i], polygon[(i + 1) % polygon.length]]
- const p = lineIntersection(line2, line)
- if (p && lineInner(line, p) && lineInner(line2, p)) {
- ps.push(p)
- }
- }
- return ps
- };
- /**
- * 判断点是否在多边形内部
- * @param polygon 多边形顶点数组,按顺时针或逆时针顺序排列
- * @param pos 要判断的点
- * @returns 点在多边形内返回true,否则返回false
- */
- export const isPolygonPointInner = (polygon: Pos[], pos: Pos): boolean => {
- // 如果多边形少于3个点,直接返回false
- if (polygon.length < 3) return false;
- let inside = false;
- const x = pos.x;
- const y = pos.y;
- // 使用射线法判断
- for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
- const xi = polygon[i].x;
- const yi = polygon[i].y;
- const xj = polygon[j].x;
- const yj = polygon[j].y;
- // 检查点是否在多边形的顶点上
- if ((numEq(xi, x) && numEq(yi, y)) || (numEq(xj, x) && numEq(yj, y))) {
- return true;
- }
- // 检查点是否在边的水平射线上
- const intersect =
- yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
- if (intersect) {
- inside = !inside;
- }
- }
- return inside;
- };
- /**
- * 通过角度和两个点获取两者的连接点,
- * @param p1
- * @param p2
- * @param rad
- */
- export const joinPoint = (p1: Pos, p2: Pos, rad: number) => {
- const lvector = new Vector2()
- .subVectors(p1, p2)
- .rotateAround({ x: 0, y: 0 }, rad);
- return vector(p2).add(lvector);
- };
- /**
- * 要缩放多少才能到达目标
- * @param origin 缩放原点
- * @param scaleDirection 缩放方向
- * @param p1 当前点位
- * @param p2 目标点位
- * @returns
- */
- export function calculateScaleFactor(
- origin: Pos,
- scaleDirection: Pos,
- p1: Pos,
- p2: Pos
- ) {
- const op1 = vector(p1).sub(origin);
- const op2 = vector(p2).sub(origin);
- const xZero = zeroEq(op1.x);
- const yZero = zeroEq(op1.y);
- if (zeroEq(op1.x) || zeroEq(op2.y)) return;
- if (zeroEq(scaleDirection.x)) {
- if (zeroEq(p2.x - p1.x)) {
- return zeroEq(op1.y - op2.y) ? 1 : yZero ? null : op2.y / op1.y;
- } else {
- return;
- }
- }
- if (zeroEq(scaleDirection.y)) {
- if (zeroEq(p2.y - p1.y)) {
- return zeroEq(op1.x - op2.x) ? 1 : xZero ? null : op2.x / op1.x;
- } else {
- return;
- }
- }
- if (xZero && yZero) {
- return null;
- }
- const xScaleFactor = op2.x / (op1.x * scaleDirection.x);
- const yScaleFactor = op2.y / (op1.y * scaleDirection.y);
- if (xZero) {
- return yScaleFactor;
- } else if (yZero) {
- return xScaleFactor;
- }
- if (zeroEq(xScaleFactor - yScaleFactor)) {
- return xScaleFactor;
- }
- }
- // 获取两线段的矩阵关系
- export const getLineRelationMat = (l1: [Pos, Pos], l2: [Pos, Pos]) => {
- // 提取点
- const P1 = l1[0]; // l1 的起点
- const P1End = l1[1]; // l1 的终点
- const P2 = l2[0]; // l2 的起点
- const P2End = l2[1]; // l2 的终点
- // 计算方向向量
- const d1 = { x: P1End.x - P1.x, y: P1End.y - P1.y };
- const d2 = { x: P2End.x - P2.x, y: P2End.y - P2.y };
- // 计算方向向量的长度
- const lengthD1 = Math.sqrt(d1.x ** 2 + d1.y ** 2);
- const lengthD2 = Math.sqrt(d2.x ** 2 + d2.y ** 2);
- if (lengthD1 === 0 || lengthD2 === 0) return new Transform();
- // 归一化方向向量
- const unitD1 = { x: d1.x / lengthD1, y: d1.y / lengthD1 };
- const unitD2 = { x: d2.x / lengthD2, y: d2.y / lengthD2 };
- // 计算旋转角度
- const angle = Math.atan2(unitD2.y, unitD2.x) - Math.atan2(unitD1.y, unitD1.x);
- // 计算旋转矩阵
- // 计算缩放因子
- const scale = lengthD2 / lengthD1;
- // 计算平移向量
- const translation = [P2.x - P1.x, P2.y - P1.y];
- const mat = new Transform()
- .translate(translation[0], translation[1])
- .translate(P1.x, P1.y)
- .scale(scale, scale)
- .rotate(angle)
- .translate(-P1.x, -P1.y);
- if (!eqPoint(mat.point(P1), P2)) {
- console.error("对准不正确 旋转后P1", mat.point(P1), P2);
- }
- if (!eqPoint(mat.point(P1End), P2End)) {
- console.error("对准不正确 旋转后P2", mat.point(P1End), P1End);
- }
- return mat;
- };
- // 判断两向量是否垂直
- export const isVertical = (v1: Pos, v2: Pos) => {
- return zeroEq(vector(v1).dot(v2));
- };
- /**
- * 判断rect1是否完整包含rect2
- * @param rect1
- * @param rect2
- * @returns
- */
- export const isRectContained = (rect1: IRect, rect2: IRect) => {
- // 计算 rect1 的左右边界
- const rect1Left = Math.min(rect1.x, rect1.x + rect1.width);
- const rect1Right = Math.max(rect1.x, rect1.x + rect1.width);
- // 计算 rect1 的上下边界
- const rect1Top = Math.min(rect1.y, rect1.y + rect1.height);
- const rect1Bottom = Math.max(rect1.y, rect1.y + rect1.height);
- // 计算 rect2 的左右边界
- const rect2Left = Math.min(rect2.x, rect2.x + rect2.width);
- const rect2Right = Math.max(rect2.x, rect2.x + rect2.width);
- // 计算 rect2 的上下边界
- const rect2Top = Math.min(rect2.y, rect2.y + rect2.height);
- const rect2Bottom = Math.max(rect2.y, rect2.y + rect2.height);
- // 检查 rect2 是否完全在 rect1 内
- return (
- rect2Left >= rect1Left &&
- rect2Right <= rect1Right &&
- rect2Top >= rect1Top &&
- rect2Bottom <= rect1Bottom
- );
- };
- export const getLineEdges = (points: Pos[], strokeWidth: number) => {
- const v = lineVector(points);
- const vv = verticalVector(v);
- const offset = vv.clone().multiplyScalar(strokeWidth / 2);
- const top = points.map((p) => offset.clone().add(p));
- offset.multiplyScalar(-1);
- const bottom = points.map((p) => offset.clone().add(p));
- return [...top, bottom[1], bottom[0]];
- };
- export type LEJLine = { points: Pos[]; width: number };
- export type LEJInfo = { rep: number; points: Pos[] }[];
- export const getLEJJoinNdxs = (originLine: Pos[], targetLine: Pos[]) => {
- let originNdx = -1,
- targetNdx = -1;
- for (let i = 0; i < originLine.length; i++) {
- targetNdx = targetLine.findIndex((p) => eqPoint(originLine[i], p));
- if (~targetNdx) {
- originNdx = i;
- break;
- }
- }
- return { originNdx, targetNdx };
- };
- export const getLEJLineAngle = (originLine: Pos[], targetLine: Pos[]) => {
- const { originNdx, targetNdx } = getLEJJoinNdxs(originLine, targetLine);
- const targetInvFlag = originNdx === targetNdx;
- const targetPoints = targetInvFlag ? [...targetLine].reverse() : targetLine;
- const originVector = lineVector(originLine);
- const targetVector = lineVector(targetPoints).multiplyScalar(-1);
- let angle;
- if (originNdx === targetNdx && originNdx === 0) {
- angle = vector2IncludedAngle(targetVector, originVector);
- } else {
- angle = vector2IncludedAngle(originVector, targetVector);
- }
- return {
- angle,
- norAngle: rangMod(Math.abs(angle), Math.PI),
- originNdx,
- targetNdx,
- targetPoints,
- targetInvFlag,
- };
- };
- const getLinePolygonOverdo = (polygon: Pos[], slideLine: Pos[]) => {
- const sideJoins = polygonLineIntersect(polygon, slideLine);
- // 完全穿插而过
- if (sideJoins.length > 1) {
- return -1;
- // 完全包含在多边形内
- } else if (
- sideJoins.length === 0 &&
- slideLine.some((p) => isPolygonPointInner(polygon, p))
- ) {
- return -1;
- } else if (sideJoins.length === 1) {
- return sideJoins[0];
- } else {
- return 1;
- }
- };
- /**
- * 获取两变短延伸后的平湖处理
- * @param origin
- * @param target
- * @param minAngle
- * @param palAngle
- * @returns 平滑信息,需要结合延伸使用
- */
- export const getLineEdgeJoinInfo = (
- origin: LEJLine,
- target: LEJLine,
- minAngle: number,
- palAngle: number
- ) => {
- const { originNdx, targetPoints, norAngle } = getLEJLineAngle(
- origin.points,
- target.points
- );
- // 最小可平滑处理角度
- if (norAngle < minAngle || norAngle > Math.PI - minAngle) {
- return;
- }
- const targetEdges = getLineEdges(targetPoints, target.width);
- const originEdges = getLineEdges(origin.points, origin.width);
- const center = lineCenter([...origin.points, ...target.points]);
- const originEdgesInv =
- lineLen(center, originEdges[0]) > lineLen(center, originEdges[3]);
- let originInner, originOuter;
- if (originEdgesInv) {
- originOuter = [originEdges[0], originEdges[1]];
- originInner = [originEdges[3], originEdges[2]];
- } else {
- originInner = [originEdges[0], originEdges[1]];
- originOuter = [originEdges[3], originEdges[2]];
- }
- let innerJoin: Pos | null = null;
- // 如果交点边缘在另一条线中,则交点更改为另一条线上
- const targetJoinNdxs = originNdx === 0 ? [0, 3] : [1, 2];
- const originJoinNdxs = originNdx === 0 ? [1, 2] : [0, 3];
- // let innerJoinFlag = getLinePolygonOverdo(
- // originEdges,
- // targetJoinNdxs.map((i) => targetEdges[i])
- // );
- // if (innerJoinFlag === -1) {
- // return;
- // } else if (innerJoinFlag !== 1) {
- // innerJoin = innerJoinFlag as Pos;
- // }
- // if (!innerJoin) {
- // innerJoinFlag = getLinePolygonOverdo(
- // targetEdges,
- // originJoinNdxs.map((i) => originEdges[i])
- // );
- // if (innerJoinFlag === -1) {
- // return;
- // } else if (innerJoinFlag !== 1) {
- // innerJoin = innerJoinFlag as Pos;
- // }
- // }
- if (
- originJoinNdxs.some((i) =>
- isPolygonPointInner(targetEdges, originEdges[i])
- ) ||
- targetJoinNdxs.some((i) => isPolygonPointInner(originEdges, targetEdges[i]))
- ) {
- return;
- }
- const targetEdgesInv =
- lineLen(center, targetEdges[0]) > lineLen(center, targetEdges[3]);
- let targetInner, targetOuter;
- if (targetEdgesInv) {
- targetOuter = [targetEdges[0], targetEdges[1]];
- targetInner = [targetEdges[3], targetEdges[2]];
- } else {
- targetInner = [targetEdges[0], targetEdges[1]];
- targetOuter = [targetEdges[3], targetEdges[2]];
- }
- let outerJoin = lineIntersection(targetOuter, originOuter);
- if (!outerJoin) {
- return;
- }
- if (!innerJoin) {
- innerJoin = lineIntersection(targetInner, originInner);
- if (!innerJoin) {
- return;
- }
- }
- // 如果内交点均不在两条内线上则不处理
- if (
- !lineInner(targetInner, innerJoin) &&
- !lineInner(originInner, innerJoin)
- ) {
- return;
- }
- let originInnerPoints: Pos[] = [innerJoin];
- let originOuterPoints: Pos[] = [outerJoin];
- const join = origin.points[originNdx];
- // 如果角度过于尖锐则使用平行线
- if (norAngle < palAngle) {
- const pal = getVectorLine(lineVerticalVector([join, outerJoin]), join);
- originOuterPoints = [lineIntersection(pal, originOuter)!, join];
- }
- const originRepInfos: LEJInfo = [];
- if (originNdx === 0) {
- originRepInfos.push(
- {
- rep: 0,
- points: originEdgesInv
- ? originOuterPoints.reverse()
- : originInnerPoints,
- },
- {
- rep: 3,
- points: originEdgesInv ? originInnerPoints : originOuterPoints,
- }
- );
- } else {
- originRepInfos.push(
- {
- rep: 1,
- points: originEdgesInv ? originOuterPoints : originInnerPoints,
- },
- {
- rep: 2,
- points: originEdgesInv
- ? originInnerPoints
- : originOuterPoints.reverse(),
- }
- );
- }
- return originRepInfos;
- };
|