!2536 优化:构建二维刀路时缓存端点的geom3,适应圆分段角度

pull/2551/head
林三 9 months ago committed by ChenX
parent 3d9babd9d3
commit c3cfbebd38

@ -1,14 +1,4 @@
import geom2, { Geom2 } from '@jscad/modeling/src/geometries/geom2';
import geom3, { transform } from '@jscad/modeling/src/geometries/geom3';
import Geom3 from '@jscad/modeling/src/geometries/geom3/type'; import Geom3 from '@jscad/modeling/src/geometries/geom3/type';
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/retessellate';
import { BufferGeometry, Euler, FrontSide, Frustum, Geometry, LineSegments, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Line as TLine, UVGenerator, Vector3 } from 'three'; import { BufferGeometry, Euler, FrontSide, Frustum, Geometry, LineSegments, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Line as TLine, UVGenerator, Vector3 } from 'three';
import { Board2Regions } from '../../Add-on/BoardEditor/Board2Regions'; import { Board2Regions } from '../../Add-on/BoardEditor/Board2Regions';
import { DeserializationBoard2DModeingData, DeserializationBoard3DModeingData, SerializeBoard2DModeingData, SerializeBoard3DModeingData, deserializationBoardData, serializeBoardData } from '../../Add-on/BoardEditor/SerializeBoardData'; import { DeserializationBoard2DModeingData, DeserializationBoard3DModeingData, SerializeBoard2DModeingData, SerializeBoard3DModeingData, deserializationBoardData, serializeBoardData } from '../../Add-on/BoardEditor/SerializeBoardData';
@ -22,23 +12,19 @@ import { Geom3Res } from '../../Common/CSGIntersect';
import { ColorMaterial } from '../../Common/ColorPalette'; import { ColorMaterial } from '../../Common/ColorPalette';
import { DisposeThreeObj } from '../../Common/Dispose'; import { DisposeThreeObj } from '../../Common/Dispose';
import { Log, LogType } from '../../Common/Log'; import { Log, LogType } from '../../Common/Log';
import { MakeMirrorMtx, TransformVector, Vector2ApplyMatrix4, ZMirrorMatrix, tempMatrix1 } from '../../Common/Matrix4Utils'; import { TransformVector, tempMatrix1 } from '../../Common/Matrix4Utils';
import { UpdateDraw } from '../../Common/Status'; import { UpdateDraw } from '../../Common/Status';
import { FixIndex } from '../../Common/Utils';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode'; import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { Board2DModelCSGBuilder } from '../../Geometry/Board2DModelCSG/Board2DModelCSGBuilder';
import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator'; import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator';
import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils'; import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';
import { AddCSGSubtractTask, CSGTask, TerminateCSGTask } from '../../Geometry/CSGSubtract/CSGSubtractTaskManager'; import { AddCSGSubtractTask, CSGTask, TerminateCSGTask } from '../../Geometry/CSGSubtract/CSGSubtractTaskManager';
import { EdgesGeometry } from '../../Geometry/EdgeGeometry'; import { EdgesGeometry } from '../../Geometry/EdgeGeometry';
import { GetArcDrawCount } from '../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams';
import { IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils'; import { IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils';
import { PointShapeUtils } from '../../Geometry/PointShapeUtils'; import { PointShapeUtils } from '../../Geometry/PointShapeUtils';
import { SweepGeometrySimple } from '../../Geometry/SweepGeometry';
import { GetBoardHighSeal, GetBoardSealingCurves, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing'; import { GetBoardHighSeal, GetBoardSealingCurves, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing';
import { RenderType } from '../../GraphicsSystem/RenderType'; import { RenderType } from '../../GraphicsSystem/RenderType';
import { VData2Curve, VKnifToolPath } from '../../GraphicsSystem/ToolPath/VKnifToolPath';
import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption"; import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption";
import { FuzzyFactory } from '../../csg/core/FuzzyFactory';
import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG'; import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG';
import { CylinderHole } from '../3DSolid/CylinderHole'; import { CylinderHole } from '../3DSolid/CylinderHole';
import { ExtrudeHole } from '../3DSolid/ExtrudeHole'; import { ExtrudeHole } from '../3DSolid/ExtrudeHole';
@ -57,7 +43,6 @@ import { DragPointType } from './DragPointType';
import { Entity } from './Entity'; import { Entity } from './Entity';
import { ExtrudeContourCurve, ExtrudeSolid } from './Extrude'; import { ExtrudeContourCurve, ExtrudeSolid } from './Extrude';
import { GenLocalUv } from './GenLocalUv'; import { GenLocalUv } from './GenLocalUv';
import { Line } from './Line';
import { Polyline } from './Polyline'; import { Polyline } from './Polyline';
//排钻配置名是合法的 可用的 //排钻配置名是合法的 可用的
@ -1312,11 +1297,11 @@ export class Board extends ExtrudeSolid
DisposeThreeObj(this._2DPathDrawObject); DisposeThreeObj(this._2DPathDrawObject);
this._2DPathDrawObject = undefined; this._2DPathDrawObject = undefined;
} }
this._OffsetPathCache.clear(); this.OffsetPathCache.clear();
} }
private _2DPathCsgs: Geom3[];//二维刀路的csg数组 _2DPathCsgs: Geom3[];//二维刀路的csg数组
private _2DPathDrawObject: Object3D;//二维刀路提刀线框显示对象 _2DPathDrawObject: Object3D;//二维刀路提刀线框显示对象
/** /**
* csg,_2DPathDrawObject(线) * csg,_2DPathDrawObject(线)
@ -1335,269 +1320,7 @@ export class Board extends ExtrudeSolid
if (this._2DModelingList.length === 0) if (this._2DModelingList.length === 0)
return this._2DPathCsgs; return this._2DPathCsgs;
let modelKnifePtsCache: Map<string, Vec2[]> = new Map(); this._2DPathCsgs = Board2DModelCSGBuilder(this);
let tempVec = new Vector3;
for (let vm of this._2DModelingList)
{
let path = vm.path;
let pathGripsSet = new Set();
let fuzz = new FuzzyFactory;
//获取端点部分的csg(使用旋转建模)
const GetGripsCsgs = (pts: Vector3[], geom3s: Geom3[], knifeGeom: Geom2, knifeGeomRadius: number) =>
{
for (let pt of pts)
{
let key = fuzz.lookupOrCreate([pt.x, pt.y], pt);
if (!pathGripsSet.has(key))
{
let count = Math.min(GetArcDrawCount(knifeGeomRadius), 8);
let rotateGeom = extrudeRotate({ segments: count, angle: 2 * Math.PI }, knifeGeom);
rotateGeom = retessellate(rotateGeom);
// TestDrawGeom3s([rotateGeom]);
let mat = new Matrix4().setPosition(pt);
rotateGeom = transform(mat.elements as Mat4, rotateGeom);
geom3s.push(rotateGeom);
pathGripsSet.add(key);
}
}
};
for (let item of vm.items)
{
let tempPath = this.GetOffsetPath(path, item);
if (tempPath)
{
let sweepContour = this._KnifePolylineMap.get(item.knife.id);
if (true || !sweepContour)//如果没有轮廓的时候,我们还是依然绘制线段 (因为现在我们没有线框生成 所以强制true)
{
if (!this._2DPathDrawObject) this._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 = this.thickness - item.depth;
pathObject.updateMatrix();
this._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 knifeGeomRadius = sweepContour.BoundingBox.getSize(tempVec).y / 2;
//分解路径
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));
}
//提刀轮廓 未闭合路径增加圆角 端点部分
if (!tempPath.IsClose)
GetGripsCsgs([tempPath.StartPoint, tempPath.EndPoint], geom3s, knifeGeom, knifeGeomRadius);
}
else
{
let mt4Z = new Matrix4().makeRotationZ(Math.PI / 2);
let mt4Y = new Matrix4().makeRotationY(Math.PI / 2);
for (let cu of cus)
{
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);
mtx = new Matrix4().makeRotationZ(Math.atan2(pt.y, pt.x));
lineShape = transform(mtx.elements as Mat4, lineShape);
//平移到线段中点
mtx = new Matrix4().setPosition(cu.Midpoint);
lineShape = transform(mtx.elements as Mat4, lineShape);
geom3s.push(lineShape);
//端点部分
GetGripsCsgs([cu.StartPoint, cu.EndPoint], geom3s, knifeGeom, knifeGeomRadius);
}
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);
//端点部分
GetGripsCsgs([cu.StartPoint, cu.EndPoint], geom3s, knifeGeom, knifeGeomRadius);
}
}
}
let mtx: Matrix4;
if (vm.dir === FaceDirection.Front)
mtx = new Matrix4().setPosition(0, 0, this.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);
this._2DPathCsgs.push(geom);
}
}
}
}
//del_exp2_end //del_exp2_end
return this._2DPathCsgs; return this._2DPathCsgs;
@ -1975,30 +1698,7 @@ export class Board extends ExtrudeSolid
} }
//偏移缓存 //偏移缓存
private _OffsetPathCache = new Map<Polyline, { [key: string]: Polyline; }>(); OffsetPathCache = new Map<Polyline, { [key: string]: Polyline; }>();
private GetOffsetPath(path: Polyline, item: I2DModeingItem): Polyline
{
if (item.offset === 0)
{
return path;
}
else
{
let cache = this._OffsetPathCache.get(path);
if (!cache)
{
cache = {};
this._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;
}
}
/** /**
* *
@ -2174,12 +1874,12 @@ export class Board extends ExtrudeSolid
{ {
for (let vm of this._2DModelingList) for (let vm of this._2DModelingList)
{ {
if (!this._OffsetPathCache.has(vm.path)) continue; if (!this.OffsetPathCache.has(vm.path)) continue;
for (let item of vm.items) for (let item of vm.items)
{ {
if (item.offset === 0) continue; if (item.offset === 0) continue;
let paths = this._OffsetPathCache.get(vm.path); let paths = this.OffsetPathCache.get(vm.path);
let polyline = paths[item.offset.toString()]; let polyline = paths[item.offset.toString()];
if (!polyline) continue;//多段线可能偏移失败 if (!polyline) continue;//多段线可能偏移失败

@ -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…
Cancel
Save