!2349 功能:二维刀路分段建模

pull/2416/head
林三 1 year ago committed by ChenX
parent 7823774661
commit 31bb5bfa6d

@ -101,7 +101,7 @@
"@blueprintjs/popover2": "^0.12.9",
"@blueprintjs/table": "^3.10.0",
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": "^0.5.1",
"@jscad/modeling": "^2.11.0",
"@jscad/modeling": "^2.12.0",
"blueimp-md5": "^2.19.0",
"detect-browser": "^5.3.0",
"dwg2dxf": "^1.0.0",

@ -0,0 +1,77 @@
import geom3 from "@jscad/modeling/src/geometries/geom3";
import poly3 from "@jscad/modeling/src/geometries/poly3";
import { Matrix4, Vector3 } from "three";
import { app } from "../../ApplicationServices/Application";
import { Log } from "../../Common/Log";
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
import { Region } from "../../DatabaseServices/Entity/Region";
import { GroupRecord } from "../../DatabaseServices/GroupTableRecord";
import { ObjectId } from "../../DatabaseServices/ObjectId";
import { AsVector2 } from "../../Geometry/GeUtils";
import { Orbit } from "../../Geometry/Orbit";
/**
* geom3()
* ,线
*
*/
export function TestDrawGeom3s(geoms: geom3.Geom3[])
{
for (let i = 0; i < geoms.length; i++)
{
let geom = geoms[i];
let polygons = geom.polygons;
let entitys: ObjectId[] = [];
for (let polygon of polygons)
{
let plane = poly3.plane(polygon);
let z = new Vector3().fromArray(plane);
let x = new Vector3();
let y = new Vector3();
Orbit.ComputUpDirection(z, y, x);
let mtx = new Matrix4().makeBasis(x, y, z).setPosition(z.multiplyScalar(plane[3]));
let mtxInv = new Matrix4().getInverse(mtx);
if (geom.transforms)
mtx.multiplyMatrices(new Matrix4().fromArray(geom.transforms), mtx);
let pts = polygon.vertices.map(v => new Vector3().fromArray(v).applyMatrix4(mtxInv));
let polyline = new Polyline(pts.map(p =>
{
return { pt: AsVector2(p), bul: 0 };
}));
polyline.CloseMark = true;
if (polyline.IsIntersectSelf())
{
polyline.ColorIndex = i + 1;
app.Database.ModelSpace.Append(polyline);
Log("存在无法自交多边形");
}
else
{
let reg = Region.CreateFromCurves(polyline.Explode());
if (reg)
{
reg.ApplyMatrix(mtx);
reg.ColorIndex = i + 1;
app.Database.ModelSpace.Append(reg);
entitys.push(reg.Id);
}
else
console.error();
}
}
let group = new GroupRecord;
app.Database.GroupTable.Add(group);
group.Entitys = entitys;
}
}

@ -1,7 +1,14 @@
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 poly3, { measureArea } from '@jscad/modeling/src/geometries/poly3';
import { Mat4 } from '@jscad/modeling/src/maths/mat4';
import subtract from '@jscad/modeling/src/operations/booleans/subtract';
import union from '@jscad/modeling/src/operations/booleans/union';
import { Vec2 } from '@jscad/modeling/src/maths/vec2';
import { Vec3 } from '@jscad/modeling/src/maths/vec3';
import { intersect, subtract, union } 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 { Board2Regions } from '../../Add-on/BoardEditor/Board2Regions';
import { DeserializationBoard2DModeingData, DeserializationBoard3DModeingData, SerializeBoard2DModeingData, SerializeBoard3DModeingData, deserializationBoardData, serializeBoardData } from '../../Add-on/BoardEditor/SerializeBoardData';
@ -14,19 +21,23 @@ import { EBoardKeyList } from '../../Common/BoardKeyList';
import { Geom3Res } from '../../Common/CSGIntersect';
import { ColorMaterial } from '../../Common/ColorPalette';
import { DisposeThreeObj } from '../../Common/Dispose';
import { MakeMirrorMtx, TransformVector, ZMirrorMatrix, tempMatrix1 } from '../../Common/Matrix4Utils';
import { MakeMirrorMtx, TransformVector, Vector2ApplyMatrix4, ZMirrorMatrix, tempMatrix1 } from '../../Common/Matrix4Utils';
import { UpdateDraw } from '../../Common/Status';
import { FixIndex } from '../../Common/Utils';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator';
import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';
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 { PointShapeUtils } from '../../Geometry/PointShapeUtils';
import { SweepGeometry } from '../../Geometry/SweepGeometry';
import { SweepGeometrySimple } from '../../Geometry/SweepGeometry';
import { GetBoardHighSeal, GetBoardSealingCurves, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { VData2Curve, VKnifToolPath } from '../../GraphicsSystem/ToolPath/VKnifToolPath';
import { Max } from '../../Nest/Common/Util';
import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption";
import { FuzzyFactory } from '../../csg/core/FuzzyFactory';
import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG';
import { CylinderHole } from '../3DSolid/CylinderHole';
import { ExtrudeHole } from '../3DSolid/ExtrudeHole';
@ -45,6 +56,7 @@ import { DragPointType } from './DragPointType';
import { Entity } from './Entity';
import { ExtrudeContourCurve, ExtrudeSolid } from './Extrude';
import { GenLocalUv } from './GenLocalUv';
import { Line } from './Line';
import { Polyline } from './Polyline';
//排钻配置名是合法的 可用的
@ -1301,8 +1313,11 @@ export class Board extends ExtrudeSolid
}
private _2DPathCsgs: Geom3[];//二维刀路的csg数组
private _2DPathDrawObject: Object3D;
//获取二维刀路的csg数组
private _2DPathDrawObject: Object3D;//二维刀路提刀线框显示对象
/**
* csg,_2DPathDrawObject(线)
*/
private Get2DPathCsgs(): Geom3[]
{
if (this._2DPathCsgs)
@ -1314,63 +1329,240 @@ export class Board extends ExtrudeSolid
if (this._2DModelingList.length === 0)
return this._2DPathCsgs;
let modelKnifePtsCache: Map<string, Vec2[]> = new Map();
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 rotateGeom = extrudeRotate({ segments: GetArcDrawCount(knifeGeomRadius), 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 o = 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;
o.add(c.GetDrawObjectFromRenderType(RenderType.Wireframe));
pathObject.add(c.GetDrawObjectFromRenderType(RenderType.Wireframe));
}
if (vm.dir === FaceDirection.Back)
{
o.applyMatrix4(ZMirrorMatrix);
o.position.z = item.depth;
pathObject.applyMatrix4(ZMirrorMatrix);
pathObject.position.z = item.depth;
}
else
o.position.z = this.thickness - item.depth;
o.updateMatrix();
this._2DPathDrawObject.add(o);
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]);
// continue;
if (sweepContour.IsClockWise) knifeGeomPts.reverse();
}
if (!sweepContour) continue;
//刀截面geom
let knifeGeom = geom2.fromPoints(knifeGeomPts);
let knifeGeomRadius = sweepContour.BoundingBox.getSize(tempVec).y / 2;
const geometry = new SweepGeometry(sweepContour, tempPath);
let csg = Geometry2CSG2(geometry);
if (vm.dir === FaceDirection.Front)
//分解路径
let cus = tempPath.Explode();
if (item.knife.angle)
{
let mtx = new Matrix4().setPosition(0, 0, this.thickness - item.depth);
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 lidPolygons = lidGeom3.polygons.map(p => p.vertices.map(v => fuzz.lookupOrCreate([v[0], v[1]], -1)));
//精简结束
//遍历每个水管
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[] = [];
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();//这里偷懒了
}
// let edge = geometry.EdgeGeom.applyMatrix4(mtx);
// this._2DPathDrawObject.add(new LineSegments(edge, ColorMaterial.GetLineMaterial(this.ColorIndex)));
let lidGeom1 = geom3.create(lid1);
let lidGeom2 = geom3.create(lid2);
csg.transforms = mtx.toArray() as Mat4;
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 mtx = MakeMirrorMtx(ZAxis, new Vector3(0, 0, item.depth * 0.5));
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);
rotateGeom = retessellate(rotateGeom);
//放置Geom
let rotateMat = new Matrix4().makeRotationZ(cu.IsClockWise ? cu.EndAngle : cu.StartAngle).setPosition(cu.Position);
rotateGeom = transform(rotateMat.elements as Mat4, rotateGeom);
geom3s.push(rotateGeom);
//端点部分
GetGripsCsgs([cu.StartPoint, cu.EndPoint], geom3s, knifeGeom, knifeGeomRadius);
}
}
}
// let edge = geometry.EdgeGeom.applyMatrix4(mtx);
// this._2DPathDrawObject.add(new LineSegments(edge, ColorMaterial.GetLineMaterial(this.ColorIndex)));
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));
csg.transforms = mtx.toArray() as Mat4;
for (let geom of geom3s)
{
geom = transform(mtx.elements as Mat4, geom);
this._2DPathCsgs.push(geom);
}
this._2DPathCsgs.push(csg);
}
}
}
@ -1387,19 +1579,89 @@ export class Board extends ExtrudeSolid
override UpdateMeshGeom(geo: Geometry): BufferGeometry
{
let path2dCsgs = this.Get2DPathCsgs();
if (path2dCsgs.length === 0 || !HostApplicationServices.show2DPathObject)
if (!path2dCsgs.length || !HostApplicationServices.show2DPathObject)
{
if (geo instanceof Geometry)
return new BufferGeometry().fromGeometry(geo);
return geo;
}
// TestDrawGeom3s(path2dCsgs);
let gemUnion = path2dCsgs[0];
for (let i = 1; i < path2dCsgs.length; i++)
gemUnion = union(gemUnion, path2dCsgs[i]);
let geomSub = union(path2dCsgs);
let geom = Geometry2CSG2(geo);
let newGeom = subtract(geom, geomSub);
this._EdgeGeometry = new EdgesGeometry().FromCSG(newGeom as unknown as Geom3Res);
let newGeom = subtract(geom, gemUnion);
//删除小面积(只留一个)
{
let fuzz = new FuzzyFactory;
let vmap = new Map;
for (let poly of newGeom.polygons)
{
for (let v of poly.vertices)
{
let key = fuzz.lookupOrCreate(v, v);
let arr = vmap.get(key);
if (!arr)
{
arr = [];
vmap.set(key, arr);
}
arr.push(poly);
v["__key__"] = key;
}
}
let polys = newGeom.polygons.concat();
let polyGroups = [];
let calcs = new Set;
while (polys.length)
{
let poly1 = polys.pop();
calcs.add(poly1);
let polyGroup = [poly1];
polyGroups.push(polyGroup);
for (let i = 0; i < polyGroup.length; i++)
{
let poly = polyGroup[i];
for (let v of poly.vertices)
{
let key = v["__key__"];
let arr = vmap.get(key);
for (let vpoly of arr)
{
if (calcs.has(vpoly)) continue;
calcs.add(vpoly);
polyGroup.push(vpoly);
}
}
}
// arrayRemoveIf(polys, poly => !calcs.has(poly)); //加上这个无法提高性能
}
let areas = polyGroups.map(polys =>
{
let area = 0;
for (let poly of polys)
area += measureArea(poly);
});
let maxIndex = Max(areas, (t1, t2) => t2 > t1);
newGeom.polygons = polyGroups[maxIndex];
}
this._EdgeGeometry = new EdgesGeometry().FromCSG(newGeom as unknown as Geom3Res);
const geometry = CSG2Geometry2(newGeom);
const bufferGeometry = new BufferGeometry().fromGeometry(geometry);

@ -29,12 +29,13 @@ export const ARC_DRAW_CONFIG = {
*/
//del_exp_end
export function GetArcDrawCount(arc: Arc | Circle): number
export function GetArcDrawCount(arc: Arc | Circle | number): number
{
let splitCount = arc.Radius / ARC_DRAW_CONFIG.ARC_SplitLength;
let radius = typeof arc === "number" ? arc : arc.Radius;
let splitCount = radius / ARC_DRAW_CONFIG.ARC_SplitLength;
//保证是偶数(避免奇数和Shape2计算方式一致导致的干涉)
splitCount = clamp(Math.floor(splitCount * 0.5) * 2, ARC_DRAW_CONFIG.Arc_MinSplitCount, ARC_DRAW_CONFIG.ARC_MaxSplitCount);
if (arc.Radius > ARC_DRAW_CONFIG.ARC_RADIUS_MIN)
if (radius > ARC_DRAW_CONFIG.ARC_RADIUS_MIN)
splitCount = Math.max(36, splitCount);
return splitCount;
}

@ -14,6 +14,7 @@ import { PlaneExt } from "./Plane";
export class SweepGeometry extends Geometry
{
edgePts: number[] = [];
polygonIndexes = [];
ShapeMaterialSlotData: number[];//[0,0,0,1,2,3,0] 指定多段线轮廓的材质槽索引 每个顶点指定一个材质槽位置
constructor(contour: Polyline, path: Curve[] | Curve, ShapeMaterialSlotData?: number[])
{
@ -167,7 +168,30 @@ export class SweepGeometry extends Geometry
if (!isClosePath) this.BuildLid(shapePts2d, verts);
}
private BuildSideFaces(shapePts2d: Vector2[], pathPts2d: Vector2[], pathPts: Vector3[], verts: Vector3[][])
/**
* 使4
* @param a
* @param b
* @param c
* @param d
* @param uvs
* @param [materialIndex]
*/
protected BuildFace4(a: number, b: number, c: number, d: number, uvs: Vector2[], materialIndex?: number)
{
let f1 = new Face3(a, b, c, undefined, undefined, materialIndex);
let f2 = new Face3(b, d, c, undefined, undefined, materialIndex);
this.faces.push(f1, f2);
this.faceVertexUvs[0].push([uvs[0].clone(), uvs[1].clone(), uvs[2].clone()], [uvs[1].clone(), uvs[3].clone(), uvs[2].clone()]);
}
/**
*
* @param dir ()
*/
protected SideStartMark(dir: Vector3) { }
protected BuildSideFaces(shapePts2d: Vector2[], pathPts2d: Vector2[], pathPts: Vector3[], verts: Vector3[][])
{
let addCount = 0; //补充个数
shapePts2d[0]["_mask_"] = true;
@ -181,13 +205,6 @@ export class SweepGeometry extends Geometry
}
let sumCount = addCount + shapePts2d.length; //实际个数
const f4 = (a: number, b: number, c: number, d: number, uvs: Vector2[], materialIndex?: number) =>
{
let f1 = new Face3(a, b, c, undefined, undefined, materialIndex);
let f2 = new Face3(b, d, c, undefined, undefined, materialIndex);
this.faces.push(f1, f2);
this.faceVertexUvs[0].push([uvs[0].clone(), uvs[1].clone(), uvs[2].clone()], [uvs[1].clone(), uvs[3].clone(), uvs[2].clone()]);
};
let vs: number[] = [0]; //vs 对应 y轴
for (let i = 1; i < shapePts2d.length; i++)
vs.push((vs[i - 1] + shapePts2d[i].distanceTo(shapePts2d[i - 1]) * 1e-3));
@ -203,6 +220,7 @@ export class SweepGeometry extends Geometry
let p1 = pathPts[pathIndex];
let p2 = pathPts[FixIndex(pathIndex + 1, pathPts.length)];
let p1Dir = p2.clone().sub(p1).normalize();
this.SideStartMark(p1Dir);
let tempStartX = 0;
@ -247,7 +265,8 @@ export class SweepGeometry extends Geometry
new Vector2(v1, x3),
new Vector2(v2, x4),
];
f4(curIndex, nextIndex, curIndex2, nextIndex2, uvs, lastMaterialIndex);
this.BuildFace4(curIndex, nextIndex, curIndex2, nextIndex2, uvs, lastMaterialIndex);
}
this.vertices.push(p1);
}
@ -270,7 +289,7 @@ export class SweepGeometry extends Geometry
}
}
private BuildLid(shapePts2d: Vector2[], verts: Vector3[][])
protected BuildLid(shapePts2d: Vector2[], verts: Vector3[][])
{
//轮廓三角网格索引
let faces = ShapeUtils.triangulateShape(shapePts2d, []);
@ -321,13 +340,13 @@ export function ProjectionToPlane(contourPts: Vector3[], normal: Vector3, curP:
let pts: Vector3[];
if (!preP && nextP)
{
let mat = ContourTransfromToPath(curP, normal, nextP.clone().sub(curP));
pts = contourPts.map(p => p.clone().applyMatrix4(mat));
let mtx = ContourTransfromToPath(curP, normal, nextP.clone().sub(curP));
pts = contourPts.map(p => p.clone().applyMatrix4(mtx));
}
else if (!nextP && preP)
{
let mat = ContourTransfromToPath(curP, normal, curP.clone().sub(preP));
pts = contourPts.map(p => p.clone().applyMatrix4(mat));
let mtx = ContourTransfromToPath(curP, normal, curP.clone().sub(preP));
pts = contourPts.map(p => p.clone().applyMatrix4(mtx));
}
else if (nextP && preP)
{
@ -344,8 +363,8 @@ export function ProjectionToPlane(contourPts: Vector3[], normal: Vector3, curP:
//角平分线的平面
let plane = new PlaneExt(norm, curP);
let mat = ContourTransfromToPath(preP, normal, dir);
pts = contourPts.map(p => p.clone().applyMatrix4(mat));
let mtx = ContourTransfromToPath(preP, normal, dir);
pts = contourPts.map(p => p.clone().applyMatrix4(mtx));
pts = pts.map(p => plane.intersectLine(new Line3(p, p.clone().add(dir)), new Vector3(), true));
}
return pts;
@ -370,3 +389,54 @@ function ContourTransfromToPath(pt: Vector3, norm: Vector3, dir: Vector3): Matri
mat.setPosition(pt);
return mat;
}
//用索引来定义
type Polygon = number[];
export class SweepGeometrySimple extends SweepGeometry
{
SidePolygons: (Polygon[])[];//所有侧面的多边形
private _curSidePolygons: Polygon[];//
private _curDir: Vector3;
TriFaces: (number[])[];//截面的三角面索引
shapeVerts: Vector3[][];//所有的截面点在节点位置
shapePts2d: Vector2[];
override computeVertexNormals() { }
override computeFaceNormals() { }
override BuildFace4(a: number, b: number, c: number, d: number, uvs: Vector2[], materialIndex?: number)
{
let polygon = [a, b, d, c];
polygon["dir"] = this._curDir;
this._curSidePolygons.push(polygon);
}
protected override SideStartMark(dir: Vector3)
{
this._curDir = dir;
if (this._curSidePolygons?.length)
this.SidePolygons.push(this._curSidePolygons);
this._curSidePolygons = [];
}
protected override BuildSideFaces(shapePts2d: Vector2[], pathPts2d: Vector2[], pathPts: Vector3[], verts: Vector3[][])
{
this.shapeVerts = verts;
this.shapePts2d = shapePts2d;
pathPts2d[0]["_mask_"] = true;
if (!this.TriFaces)
this.TriFaces = ShapeUtils.triangulateShape(shapePts2d, []);
if (!this.SidePolygons) this.SidePolygons = [];
super.BuildSideFaces(shapePts2d, pathPts2d, pathPts, verts);
if (this._curSidePolygons?.length)
this.SidePolygons.push(this._curSidePolygons);
}
protected override BuildLid(shapePts2d: Vector2[], verts: Vector3[][]) { }
}

@ -1,7 +1,8 @@
import { Button, ContextMenu, Intent, Menu, MenuItem } from '@blueprintjs/core';
import { IObservableValue, observable } from 'mobx';
import { IObservableValue, observable, toJS } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Vector3 } from 'three';
import { app } from '../../../../ApplicationServices/Application';
import { DataAdapter } from '../../../../Common/DataAdapter';
import { ToplineUrls } from '../../../../Common/HostUrl';
@ -143,6 +144,9 @@ export class KnifeList extends React.Component<IKnifeListProps, { isContextMenuO
if (pl)
{
let topline_id = this.props.info.id;
let props = this.props.info.props;
props.radius = parseFloat((pl.BoundingBox.getSize(new Vector3).x / 2).toFixed(2));
let vf = new CADFiler();
pl.WriteFile(vf);
@ -153,6 +157,7 @@ export class KnifeList extends React.Component<IKnifeListProps, { isContextMenuO
logo,
file: deflate(fileJson),
zip_type: "gzip",
props: JSON.stringify(toJS(props))
});
AppToaster.clear();
if (data.err_code === RequestStatus.Ok)

@ -1,15 +1,15 @@
import { Button, Intent } from '@blueprintjs/core';
import { observable } from 'mobx';
import { observable, toJS } from 'mobx';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { Matrix4 } from 'three';
import { Matrix4, Vector3 } from 'three';
import { buildTopline as buildKnife } from '../../../../Add-on/DrawTopline';
import { GetCloseContour } from '../../../../Add-on/Sweep';
import { app } from '../../../../ApplicationServices/Application';
import { ToplineUrls } from '../../../../Common/HostUrl';
import { inflateBase64 } from "../../../../Common/inflate";
import { DirectoryId, PostJson, RequestStatus } from '../../../../Common/Request';
import { deflate, getPolylineSVG, toplineFileIn } from '../../../../Common/SerializeMaterial';
import { inflateBase64 } from "../../../../Common/inflate";
import { CADFiler } from '../../../../DatabaseServices/CADFiler';
import { Polyline } from '../../../../DatabaseServices/Entity/Polyline';
import { CommandWrap } from '../../../../Editor/CommandMachine';
@ -38,7 +38,7 @@ export class KnifeManage extends Component<IKnifeManageProps, IKnifeManageState>
@observable private currentInfo = {
id: "",
name: "",
props: { radius: 3, angle: 45 }
props: { radius: 3, angle: 0 }
};
constructor(props)
{
@ -191,6 +191,8 @@ export class KnifeManage extends Component<IKnifeManageProps, IKnifeManageState>
pl.ApplyMatrix(MoveMatrix(ptRes.Point.negate()))
.ApplyMatrix(new Matrix4().extractRotation(pl.OCSInv));
this.currentInfo.props.radius = parseFloat((pl.BoundingBox.getSize(new Vector3).x / 2).toFixed(2));
let vf = new CADFiler();
pl.WriteFile(vf);
pl.Erase();
@ -218,13 +220,14 @@ export class KnifeManage extends Component<IKnifeManageProps, IKnifeManageState>
logo,
file: deflate(fileJson),
zip_type: "gzip",
props: JSON.stringify(toJS(this.currentInfo.props))
});
}
if (data.err_code === RequestStatus.Ok)
{
AppToaster.show({
message: "刀具创建成功,默认半径3,夹角45°",
message: `刀具创建成功,半径${this.currentInfo.props.radius},默认夹角${this.currentInfo.props.angle}°`,
timeout: 3000,
intent: Intent.SUCCESS
});

Loading…
Cancel
Save