mirror of https://gitee.com/cf-fz/WebCAD.git
!2536 优化:构建二维刀路时缓存端点的geom3,适应圆分段角度
parent
3d9babd9d3
commit
c3cfbebd38
@ -0,0 +1,500 @@
|
||||
import geom2, { Geom2 } from "@jscad/modeling/src/geometries/geom2";
|
||||
import geom3, { Geom3, transform } from "@jscad/modeling/src/geometries/geom3";
|
||||
import poly3 from "@jscad/modeling/src/geometries/poly3";
|
||||
import { Mat4 } from "@jscad/modeling/src/maths/mat4";
|
||||
import { Vec2 } from "@jscad/modeling/src/maths/vec2";
|
||||
import { Vec3 } from "@jscad/modeling/src/maths/vec3";
|
||||
import { intersect } from "@jscad/modeling/src/operations/booleans";
|
||||
import extrudeLinear from "@jscad/modeling/src/operations/extrusions/extrudeLinear";
|
||||
import extrudeRotate from "@jscad/modeling/src/operations/extrusions/extrudeRotate";
|
||||
import { retessellate } from "@jscad/modeling/src/operations/modifiers";
|
||||
import { Matrix4, Object3D, Vector3 } from "three";
|
||||
import { FaceDirection } from "../../Add-on/DrawDrilling/DrillType";
|
||||
import { arrayLast } from "../../Common/ArrayExt";
|
||||
import { MakeMirrorMtx, Vector2ApplyMatrix4, ZMirrorMatrix } from "../../Common/Matrix4Utils";
|
||||
import { FixIndex } from "../../Common/Utils";
|
||||
import { Arc } from "../../DatabaseServices/Entity/Arc";
|
||||
import { Board, I2DModeingItem } from "../../DatabaseServices/Entity/Board";
|
||||
import { Line } from "../../DatabaseServices/Entity/Line";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { RenderType } from "../../GraphicsSystem/RenderType";
|
||||
import { VData2Curve, VKnifToolPath } from "../../GraphicsSystem/ToolPath/VKnifToolPath";
|
||||
import { FuzzyFactory } from "../../csg/core/FuzzyFactory";
|
||||
import { GetArcDrawCount } from "../ExtrudeMeshGeomBuilder/SplitCurveParams";
|
||||
import { ZAxis, angle, angleTo, equalv3 } from "../GeUtils";
|
||||
import { SweepGeometrySimple } from "../SweepGeometry";
|
||||
|
||||
const HALF_PI = Math.PI / 2;
|
||||
|
||||
//根据二维刀路路径和刀截面建模
|
||||
export function Board2DModelCSGBuilder(board: Board)
|
||||
{
|
||||
let _2DPathCsgs: Geom3[] = [];
|
||||
let modelKnifePtsCache: Map<string, Vec2[]> = new Map();
|
||||
|
||||
let tempVec = new Vector3;
|
||||
//geom3缓存
|
||||
let geom3Cache: Map<string, geom3.Geom3> = new Map();
|
||||
//端点geom3缓存
|
||||
let pathGripsSet = new Set();
|
||||
|
||||
|
||||
for (let vm of board.Modeling2D)
|
||||
{
|
||||
let path = vm.path;
|
||||
let fuzzy = new FuzzyFactory;
|
||||
|
||||
//获取端点部分的csg(使用旋转建模)
|
||||
const GetGripsCsgs = (pts: Vector3[], geom3s: Geom3[], knifeGeom: Geom2, knifeId: string, rMtxs?: Matrix4[], rAngle?: number) =>
|
||||
{
|
||||
for (let i = 0; i < pts.length; i++)
|
||||
{
|
||||
let pt = pts[i];
|
||||
if (!pt) continue;
|
||||
|
||||
let key = fuzzy.lookupOrCreate([pt.x, pt.y], pt);
|
||||
if (!pathGripsSet.has(key))
|
||||
{
|
||||
let id = knifeId;
|
||||
if (rAngle && i === 1)
|
||||
id = `${knifeId}_${rAngle.toFixed(3)}`;
|
||||
|
||||
let rotateGeom = geom3Cache.get(id);
|
||||
|
||||
if (!rotateGeom)
|
||||
{
|
||||
let normalAngle = 2 * Math.PI;
|
||||
if (rAngle && i === 1)
|
||||
normalAngle = rAngle;
|
||||
rotateGeom = extrudeRotate({ segments: 8, angle: normalAngle }, knifeGeom);
|
||||
rotateGeom = retessellate(rotateGeom);
|
||||
geom3Cache.set(id, rotateGeom);
|
||||
}
|
||||
// TestDrawGeom3s([rotateGeom]);
|
||||
let rMtx: Matrix4;
|
||||
|
||||
rMtx = rMtxs[i] ?? rMtxs[0];
|
||||
|
||||
rotateGeom = transform((rMtx ?? new Matrix4).setPosition(pt).elements as Mat4, rotateGeom);
|
||||
geom3s.push(rotateGeom);
|
||||
pathGripsSet.add(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (let item of vm.items)
|
||||
{
|
||||
let tempPath = GetOffsetPath(board, path, item);
|
||||
if (tempPath)
|
||||
{
|
||||
let sweepContour = board.KnifePolylineMap.get(item.knife.id);
|
||||
if (true || !sweepContour)//如果没有轮廓的时候,我们还是依然绘制线段 (因为现在我们没有线框生成 所以强制true)
|
||||
{
|
||||
if (!board._2DPathDrawObject) board._2DPathDrawObject = new Object3D;
|
||||
|
||||
let curves = VData2Curve(VKnifToolPath(tempPath, item.depth, item.knife.angle / 2));//走刀+提刀曲线
|
||||
let pathObject = new Object3D();//走刀路径绘制线
|
||||
for (let c of curves)
|
||||
{
|
||||
c.ColorIndex = tempPath.ColorIndex;
|
||||
pathObject.add(c.GetDrawObjectFromRenderType(RenderType.Wireframe));
|
||||
}
|
||||
if (vm.dir === FaceDirection.Back)
|
||||
{
|
||||
pathObject.applyMatrix4(ZMirrorMatrix);
|
||||
pathObject.position.z = item.depth;
|
||||
}
|
||||
else
|
||||
pathObject.position.z = board.Thickness - item.depth;
|
||||
pathObject.updateMatrix();
|
||||
board._2DPathDrawObject.add(pathObject);
|
||||
}
|
||||
if (!sweepContour) continue;
|
||||
|
||||
let geom3s: Geom3[] = [];
|
||||
|
||||
//刀截面轮廓Pts
|
||||
let knifeGeomPts: Vec2[] = modelKnifePtsCache.get(item.knife.id);
|
||||
|
||||
if (!knifeGeomPts?.length)
|
||||
{
|
||||
|
||||
let shapePts = sweepContour.Shape.getPoints();
|
||||
for (let p of shapePts)
|
||||
Vector2ApplyMatrix4(sweepContour.OCSNoClone, p);
|
||||
|
||||
knifeGeomPts = shapePts.map(p => [p.x, p.y]);
|
||||
|
||||
if (sweepContour.IsClockWise) knifeGeomPts.reverse();
|
||||
}
|
||||
|
||||
//刀截面geom
|
||||
let knifeGeom = geom2.fromPoints(knifeGeomPts);
|
||||
|
||||
//分解路径
|
||||
let cus = tempPath.Explode();
|
||||
|
||||
if (item.knife.angle)
|
||||
{
|
||||
//提刀建模
|
||||
let sweepGeom = new SweepGeometrySimple(sweepContour, cus);
|
||||
|
||||
//这里我们对盖子进行精简
|
||||
let lidPolys: poly3.Poly3[] = [];
|
||||
|
||||
let fuzz = new FuzzyFactory;
|
||||
let lidVerts = sweepGeom.shapePts2d.map((p, i) =>
|
||||
{
|
||||
fuzz.lookupOrCreate([p.x, p.y], i);
|
||||
return [p.x, p.y, 0] as Vec3;
|
||||
});
|
||||
|
||||
for (let face of sweepGeom.TriFaces)
|
||||
lidPolys.push(poly3.create(face.map(index => lidVerts[index])));
|
||||
|
||||
let lidGeom3 = retessellate(geom3.create(lidPolys));
|
||||
|
||||
let hasBadIndex = false;
|
||||
let lidPolygons = lidGeom3.polygons.map(p => p.vertices.map(v =>
|
||||
{
|
||||
let index = fuzz.lookupOrCreate([v[0], v[1]], -1);
|
||||
if (index === -1)
|
||||
hasBadIndex = true;
|
||||
return index;
|
||||
}));
|
||||
//精简结束
|
||||
|
||||
//遍历每个水管
|
||||
for (let i = 0; i < sweepGeom.SidePolygons.length; i++)
|
||||
{
|
||||
let polygons = sweepGeom.SidePolygons[i];
|
||||
let polys: poly3.Poly3[] = [];
|
||||
for (let polygon of polygons)
|
||||
{
|
||||
let pts = polygon.map(i => sweepGeom.vertices[i]);//这是水管盖子的点
|
||||
|
||||
//水管前进的方向
|
||||
let dir = polygon["dir"] as Vector3;
|
||||
|
||||
//如果水管的侧面自交了,我们选择性的删掉一个无用面
|
||||
let dir1 = tempVec.subVectors(pts[3], pts[0]).normalize();
|
||||
if (!equalv3(dir, dir1))//如果反向1
|
||||
{
|
||||
let l1 = new Line(pts[0], pts[1]);
|
||||
let l2 = new Line(pts[2], pts[3]);
|
||||
let p = l1.IntersectWith(l2, 0)[0];
|
||||
|
||||
if (!p) continue;//弃用了这个多边形
|
||||
|
||||
// polys.push(poly3.create([vertices[3], p.toArray() as Vec3, vertices[0]]));//弃用了无效的自交三角形
|
||||
polys.push(poly3.create([p.toArray() as Vec3, pts[1].toArray() as Vec3, pts[2].toArray() as Vec3]));
|
||||
continue;
|
||||
}
|
||||
|
||||
let dir2 = tempVec.subVectors(pts[2], pts[1]).normalize();
|
||||
if (!equalv3(dir, dir2))//如果反向2
|
||||
{
|
||||
let l1 = new Line(pts[0], pts[1]);
|
||||
let l2 = new Line(pts[2], pts[3]);
|
||||
let p = l1.IntersectWith(l2, 0)[0];
|
||||
|
||||
if (!p) continue;//弃用了这个多边形
|
||||
|
||||
polys.push(poly3.create([pts[0].toArray() as Vec3, p.toArray() as Vec3, pts[3].toArray() as Vec3]));
|
||||
// polys.push(poly3.create([p.toArray() as Vec3, vertices[2], vertices[1]]));//弃用了无效的自交三角形
|
||||
continue;
|
||||
}
|
||||
|
||||
polys.push(poly3.create(pts.map(p => p.toArray() as Vec3)));//如果没有反向,那么我们直接返回多边形
|
||||
}
|
||||
|
||||
//构建水管的盖子
|
||||
let curVerts = sweepGeom.shapeVerts[FixIndex(i, sweepGeom.shapeVerts)];
|
||||
let nextVerts = sweepGeom.shapeVerts[FixIndex(i + 1, sweepGeom.shapeVerts)];
|
||||
let lid1: poly3.Poly3[] = [];
|
||||
let lid2: poly3.Poly3[] = [];
|
||||
if (!hasBadIndex)
|
||||
for (let lidPolygon of lidPolygons)//我们使用已经精简过的盖子索引
|
||||
{
|
||||
lid1.push(poly3.create(lidPolygon.map(index => curVerts[index].toArray() as Vec3)));
|
||||
lid2.push(poly3.create(lidPolygon.reverse().map(index => nextVerts[index].toArray() as Vec3)));
|
||||
lidPolygon.reverse();//这里偷懒了
|
||||
}
|
||||
else
|
||||
{
|
||||
for (let face of sweepGeom.TriFaces)
|
||||
{
|
||||
lid1.push(poly3.create(face.map(index => curVerts[index].toArray() as Vec3)));
|
||||
lid2.push(poly3.create(face.map(index => nextVerts[index].toArray() as Vec3).reverse()));
|
||||
}
|
||||
}
|
||||
|
||||
let lidGeom1 = geom3.create(lid1);
|
||||
let lidGeom2 = geom3.create(lid2);
|
||||
|
||||
if (hasBadIndex)
|
||||
{
|
||||
lidGeom1 = retessellate(lidGeom1);
|
||||
lidGeom2 = retessellate(lidGeom2);
|
||||
}
|
||||
|
||||
let intGeom = intersect(lidGeom1, lidGeom2);
|
||||
if (intGeom.polygons.length)
|
||||
polys.push(...intGeom.polygons);
|
||||
else
|
||||
polys.push(...lidGeom1.polygons, ...lidGeom2.polygons);
|
||||
|
||||
geom3s.push(geom3.create(polys));
|
||||
}
|
||||
|
||||
//获取端点旋转矩阵 使8段圆对齐曲线
|
||||
let rMtx1 = GetRMtxOfCurveOfAngle(cus[0]);
|
||||
let rMtx2 = GetRMtxOfCurveOfAngle(arrayLast(cus), false);
|
||||
|
||||
//提刀轮廓 未闭合路径增加圆角 端点部分
|
||||
if (!tempPath.IsClose)
|
||||
GetGripsCsgs([tempPath.StartPoint, tempPath.EndPoint], geom3s, knifeGeom, item.knife.id, [rMtx1, rMtx2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//非提刀建模
|
||||
let mt4Z = new Matrix4().makeRotationZ(HALF_PI);
|
||||
let mt4Y = new Matrix4().makeRotationY(HALF_PI);
|
||||
|
||||
for (let i = 0; i < cus.length; i++)
|
||||
{
|
||||
let cu = cus[i];
|
||||
if (cu instanceof Line)
|
||||
{
|
||||
//直线部分
|
||||
//旋转至 X为正方向
|
||||
let lineShape = extrudeLinear({ height: cu.Length }, knifeGeom);
|
||||
lineShape = retessellate(lineShape);
|
||||
lineShape = transform(mt4Z.elements as Mat4, lineShape);
|
||||
lineShape = transform(mt4Y.elements as Mat4, lineShape);
|
||||
//平移到原点为中心
|
||||
let mtx = new Matrix4().setPosition((new Vector3(-cu.Length / 2, 0, 0)));
|
||||
lineShape = transform(mtx.elements as Mat4, lineShape);
|
||||
//旋转直线正确方向
|
||||
let pt = cu.StartPoint.sub(cu.EndPoint);
|
||||
let rMtx = new Matrix4().makeRotationZ(Math.atan2(pt.y, pt.x));
|
||||
lineShape = transform(rMtx.elements as Mat4, lineShape);
|
||||
//平移到线段中点
|
||||
mtx = new Matrix4().setPosition(cu.Midpoint);
|
||||
lineShape = transform(mtx.elements as Mat4, lineShape);
|
||||
geom3s.push(lineShape);
|
||||
|
||||
let attribute = { rRange: 0, drawCircularAngle: 0 };
|
||||
let secondMtx: Matrix4;
|
||||
|
||||
let j = i + 1;
|
||||
if (j < cus.length)
|
||||
{
|
||||
let cu2 = cus[j];
|
||||
attribute = GetRMtxOfCurve(cu, cu2);
|
||||
secondMtx = new Matrix4().makeRotationZ(attribute?.rRange ?? 0);
|
||||
}
|
||||
|
||||
//闭合曲线
|
||||
if (j === cus.length && path.IsClose)
|
||||
{
|
||||
let cu2 = cus[0];
|
||||
attribute = GetRMtxOfCurve(cu, cu2);
|
||||
secondMtx = new Matrix4().makeRotationZ(attribute?.rRange ?? 0);
|
||||
}
|
||||
|
||||
let startPt = (j < cus.length && i > 0 || i === 0 && path.IsClose) ? undefined : cu.StartPoint;
|
||||
//端点部分
|
||||
GetGripsCsgs([startPt, cu.EndPoint], geom3s, knifeGeom, item.knife.id, [rMtx, secondMtx], attribute?.drawCircularAngle);
|
||||
}
|
||||
else if (cu instanceof Arc)
|
||||
{
|
||||
//弧线部分
|
||||
//获取针对弧形扫掠Geom
|
||||
let mt4 = new Matrix4().setPosition(cu.Radius, 0, 0);
|
||||
let arcKnifeGeom = geom2.transform(mt4.elements as Mat4, knifeGeom);
|
||||
let rotateGeom = extrudeRotate({ segments: GetArcDrawCount(cu.Radius), angle: cu.AllAngle }, arcKnifeGeom);
|
||||
//圆弧的旋转分量
|
||||
let extractRotation = new Matrix4().extractRotation(cu.OCSNoClone);
|
||||
rotateGeom = retessellate(rotateGeom);
|
||||
//放置Geom
|
||||
let rotateMat = new Matrix4().makeRotationZ(cu.IsClockWise ? cu.EndAngle : cu.StartAngle).setPosition(cu.Position).multiply(extractRotation);
|
||||
rotateGeom = transform(rotateMat.elements as Mat4, rotateGeom);
|
||||
geom3s.push(rotateGeom);
|
||||
let startAngleMtx = new Matrix4().makeRotationZ(cu.StartAngle).multiply(extractRotation);
|
||||
let endAngleMtx = new Matrix4().makeRotationZ(cu.EndAngle).multiply(extractRotation);
|
||||
|
||||
//夹角的端点旋转角度和圆的大小分量
|
||||
let attribute = { rRange: 0, drawCircularAngle: 0 };
|
||||
|
||||
//获取端点旋转矩阵 使8段圆对齐曲线 (非提刀部分)
|
||||
let j = i + 1;
|
||||
if (j < cus.length)
|
||||
{
|
||||
let cu2 = cus[j];
|
||||
attribute = GetRMtxOfCurve(cu, cu2);
|
||||
endAngleMtx = new Matrix4().makeRotationZ(attribute?.rRange ?? 0);
|
||||
}
|
||||
|
||||
//闭合曲线
|
||||
if (j === cus.length && path.IsClose)
|
||||
{
|
||||
let cu2 = cus[0];
|
||||
attribute = GetRMtxOfCurve(cu, cu2);
|
||||
endAngleMtx = new Matrix4().makeRotationZ(attribute?.rRange ?? 0);
|
||||
}
|
||||
|
||||
let startPt = (j < cus.length && i > 0 || i === 0 && path.IsClose) ? undefined : cu.StartPoint;
|
||||
//端点部分
|
||||
GetGripsCsgs([startPt, cu.EndPoint], geom3s, knifeGeom, item.knife.id, [startAngleMtx, endAngleMtx], attribute?.drawCircularAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//正反面设置
|
||||
let mtx: Matrix4;
|
||||
if (vm.dir === FaceDirection.Front)
|
||||
mtx = new Matrix4().setPosition(0, 0, board.Thickness - item.depth);
|
||||
else
|
||||
mtx = MakeMirrorMtx(ZAxis, new Vector3(0, 0, item.depth * 0.5));
|
||||
|
||||
for (let geom of geom3s)
|
||||
{
|
||||
geom = transform(mtx.elements as Mat4, geom);
|
||||
_2DPathCsgs.push(geom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _2DPathCsgs;
|
||||
}
|
||||
|
||||
function GetOffsetPath(br: Board, path: Polyline, item: I2DModeingItem): Polyline
|
||||
{
|
||||
if (item.offset === 0)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
let cache = br.OffsetPathCache.get(path);
|
||||
if (!cache)
|
||||
{
|
||||
cache = {};
|
||||
br.OffsetPathCache.set(path, cache);
|
||||
}
|
||||
let tempPath = cache[item.offset.toString()];
|
||||
if (!tempPath)
|
||||
{
|
||||
tempPath = path.GetOffsetCurves(item.offset)[0];
|
||||
cache[item.offset.toString()] = tempPath;
|
||||
}
|
||||
return tempPath;
|
||||
}
|
||||
}
|
||||
|
||||
//获取端点旋转矩阵 使8段圆对齐曲线 (提刀部分)
|
||||
function GetRMtxOfCurveOfAngle(cu: Line | Arc, startPt = true)
|
||||
{
|
||||
if (cu instanceof Line)
|
||||
{
|
||||
let pt1 = cu.StartPoint.sub(cu.EndPoint);
|
||||
return new Matrix4().makeRotationZ(Math.atan2(pt1.y, pt1.x));
|
||||
}
|
||||
else if (cu instanceof Arc)
|
||||
{
|
||||
let extractRotation = new Matrix4().extractRotation(cu.OCSNoClone);
|
||||
let angle = 0;
|
||||
let fuzzAngle = Math.PI / GetArcDrawCount(cu.Radius);
|
||||
if (startPt)
|
||||
angle = cu.IsClockWise ? (cu.StartAngle - fuzzAngle) : (cu.StartAngle + fuzzAngle);
|
||||
else
|
||||
angle = cu.IsClockWise ? (fuzzAngle + cu.EndAngle) : (cu.EndAngle - fuzzAngle);
|
||||
|
||||
return new Matrix4().makeRotationZ(angle).multiply(extractRotation);
|
||||
}
|
||||
};
|
||||
|
||||
//获取端点旋转矩阵 使8段圆对齐曲线 (非提刀部分)
|
||||
function GetRMtxOfCurve(cu1: Line | Arc, cu2: Line | Arc)
|
||||
{
|
||||
if (cu1 instanceof Line)
|
||||
{
|
||||
if (cu2 instanceof Line)
|
||||
{
|
||||
let v1 = cu1.StartPoint.sub(cu1.EndPoint);
|
||||
let v2 = cu2.EndPoint.sub(cu2.StartPoint);
|
||||
let angleToV = angleTo(v1, v2);
|
||||
|
||||
//补角的圆度数
|
||||
let drawCircularAngle = Math.PI - Math.abs(angleToV);
|
||||
let addAng = 0;
|
||||
let cuV1 = angle(v1);
|
||||
|
||||
if (angleToV > 0)
|
||||
addAng = Math.PI - drawCircularAngle;
|
||||
|
||||
let rRange = cuV1 + HALF_PI + addAng;
|
||||
return { rRange, drawCircularAngle };
|
||||
}
|
||||
else if (cu2 instanceof Arc)
|
||||
{
|
||||
let v1 = cu1.StartPoint.sub(cu1.EndPoint);
|
||||
let v2 = cu2.Center.sub(cu2.StartPoint).applyMatrix4(new Matrix4().makeRotationZ(-HALF_PI));
|
||||
let angleToV = angleTo(v1, v2);
|
||||
|
||||
//补角的圆度数
|
||||
let drawCircularAngle = cu2.IsClockWise ? Math.abs(angleToV) : (Math.PI - Math.abs(angleToV));
|
||||
let addAng = 0;
|
||||
let cuV1 = angle(v1);
|
||||
|
||||
if (angleToV > 0)
|
||||
addAng = cu2.IsClockWise ? HALF_PI : (-HALF_PI - drawCircularAngle);
|
||||
else
|
||||
addAng = cu2.IsClockWise ? (angleToV - HALF_PI) : HALF_PI;
|
||||
|
||||
let rRange = cuV1 + addAng;
|
||||
return { rRange, drawCircularAngle };
|
||||
}
|
||||
|
||||
}
|
||||
else if (cu1 instanceof Arc)
|
||||
{
|
||||
if (cu2 instanceof Line)
|
||||
{
|
||||
let v1 = cu1.Center.sub(cu1.EndPoint).applyMatrix4(new Matrix4().makeRotationZ(-HALF_PI));
|
||||
let v2 = cu2.EndPoint.sub(cu2.StartPoint);
|
||||
let angleToV = angleTo(v1, v2);
|
||||
|
||||
//补角的圆度数
|
||||
let drawCircularAngle = cu1.IsClockWise ? Math.PI - Math.abs(angleToV) : Math.abs(angleToV);
|
||||
let cuV2 = angle(v2);
|
||||
let addAng = 0;
|
||||
|
||||
if (angleToV > 0)
|
||||
addAng = cu1.IsClockWise ? HALF_PI : -(drawCircularAngle + HALF_PI);
|
||||
else
|
||||
addAng = cu1.IsClockWise ? -(drawCircularAngle + HALF_PI) : HALF_PI;
|
||||
|
||||
let rRange = cuV2 + addAng;
|
||||
return { rRange, drawCircularAngle };
|
||||
}
|
||||
else if (cu2 instanceof Arc)
|
||||
{
|
||||
let v1 = cu1.Center.sub(cu1.EndPoint).applyMatrix4(new Matrix4().makeRotationZ(cu1.IsClockWise ? -HALF_PI : HALF_PI));
|
||||
let v2 = cu2.Center.sub(cu1.EndPoint).applyMatrix4(new Matrix4().makeRotationZ(cu2.IsClockWise ? HALF_PI : -HALF_PI));
|
||||
let angleToV = angleTo(v1, v2);
|
||||
|
||||
//补角的圆度数
|
||||
let drawCircularAngle = Math.PI - Math.abs(angleToV);
|
||||
let addAng = 0;
|
||||
let cuV1 = angle(v1);
|
||||
|
||||
if (angleToV > 0)
|
||||
addAng = Math.PI - drawCircularAngle;
|
||||
|
||||
let rRange = cuV1 + HALF_PI + addAng;
|
||||
return { rRange, drawCircularAngle };
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in new issue