|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
import { Box3, BufferGeometry, Float32BufferAttribute, Matrix4, Shape as TShape, ShapeUtils, Vector3, MathUtils } from "three";
|
|
|
|
|
import { BufferGeometry, Float32BufferAttribute, MathUtils, Matrix4, Shape as TShape, ShapeUtils, Vector3 } from "three";
|
|
|
|
|
import { arrayRemoveDuplicateBySort, arraySortByNumber } from "../Common/ArrayExt";
|
|
|
|
|
import { curveLinkGroup } from "../Common/CurveUtils";
|
|
|
|
|
import { clamp, FixIndex } from "../Common/Utils";
|
|
|
|
@ -9,9 +9,10 @@ import { Circle } from "../DatabaseServices/Entity/Circle";
|
|
|
|
|
import { Curve } from "../DatabaseServices/Entity/Curve";
|
|
|
|
|
import { ExtrudeSolid, ExtureContourCurve } from "../DatabaseServices/Entity/Extrude";
|
|
|
|
|
import { Line } from "../DatabaseServices/Entity/Line";
|
|
|
|
|
import { Polyline } from "../DatabaseServices/Entity/Polyline";
|
|
|
|
|
import { Polyline, PolylineProps } from "../DatabaseServices/Entity/Polyline";
|
|
|
|
|
import { IntersectOption, IntersectResult } from "../GraphicsSystem/IntersectWith";
|
|
|
|
|
import { LinesType } from "../UI/Store/BoardInterface";
|
|
|
|
|
import { IntersectsBox } from "./Box";
|
|
|
|
|
import { AsVector2, equaln, equalv3, IdentityMtx4 } from "./GeUtils";
|
|
|
|
|
import { RegionParse } from "./RegionParse";
|
|
|
|
|
|
|
|
|
@ -22,138 +23,90 @@ export enum DepthType
|
|
|
|
|
All = 3,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Shape2
|
|
|
|
|
{
|
|
|
|
|
constructor(public contour: Contour, public holes: Contour[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Parse(contour: Contour, s: this, isOut: boolean)
|
|
|
|
|
{
|
|
|
|
|
let [res1,] = Parse(this.contour.Curve, s.contour.Curve);
|
|
|
|
|
if (!isOut)
|
|
|
|
|
[res1.reverse, res1.syntropy] = [res1.syntropy, res1.reverse];
|
|
|
|
|
if (res1.container.length > 0)
|
|
|
|
|
{
|
|
|
|
|
for (let h of s.holes)
|
|
|
|
|
{
|
|
|
|
|
let [res2,] = Parse(this.contour.Curve, h.Curve);
|
|
|
|
|
if (isOut)
|
|
|
|
|
[res2.reverse, res2.syntropy] = [res2.syntropy, res2.reverse];
|
|
|
|
|
|
|
|
|
|
res1.container = SubtractRanges(res1.container, res2.container, contour.Curve.EndParam);
|
|
|
|
|
res1.container = SubtractRanges(res1.container, res2.syntropy, contour.Curve.EndParam);
|
|
|
|
|
res1.container = SubtractRanges(res1.container, res2.reverse, contour.Curve.EndParam);
|
|
|
|
|
|
|
|
|
|
//被网洞包含等于在形状外部
|
|
|
|
|
res1.outer.push(...res2.container);
|
|
|
|
|
|
|
|
|
|
res1.syntropy.push(...res2.syntropy);
|
|
|
|
|
res1.reverse.push(...res2.reverse);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Sub(s: Shape2)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 由ExtudeWall围成的形状,包含外轮廓和网洞
|
|
|
|
|
* 槽的几何数据,包括槽的墙面和槽的盖子
|
|
|
|
|
*/
|
|
|
|
|
export class ExtudeWallShape
|
|
|
|
|
export class Groove
|
|
|
|
|
{
|
|
|
|
|
contour: ExtudeWall;
|
|
|
|
|
holes: ExtudeWall[] = [];
|
|
|
|
|
|
|
|
|
|
box: Box3;
|
|
|
|
|
shape: CurveTapeShape;
|
|
|
|
|
contourWall: ExtudeWall;//槽轮廓的墙
|
|
|
|
|
holeWalls: ExtudeWall[] = [];//槽的网洞的墙
|
|
|
|
|
private lid: CurveTapeShape;//槽的盖子
|
|
|
|
|
constructor(contour: Contour,
|
|
|
|
|
holes: Contour[],
|
|
|
|
|
public depthType: DepthType,
|
|
|
|
|
public depth: number,
|
|
|
|
|
public allDepth: number)
|
|
|
|
|
public allDepth: number,
|
|
|
|
|
private box = contour.BoundingBox
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
this.contour = new ExtudeWall(contour.Curve, depthType, depth, allDepth, DirectionType.Inner);
|
|
|
|
|
this.box = contour.BoundingBox;
|
|
|
|
|
|
|
|
|
|
this.contourWall = new ExtudeWall(contour.Curve, depthType, depth, allDepth, DirectionType.Inner);
|
|
|
|
|
for (let h of holes)
|
|
|
|
|
this.holes.push(new ExtudeWall(h.Curve, depthType, depth, allDepth, DirectionType.Outer));
|
|
|
|
|
this.holeWalls.push(new ExtudeWall(h.Curve, depthType, depth, allDepth, DirectionType.Outer));
|
|
|
|
|
|
|
|
|
|
this.shape = new CurveTapeShape(contour, holes);
|
|
|
|
|
this.lid = new CurveTapeShape(contour, holes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param shape
|
|
|
|
|
* @param groove this - groove
|
|
|
|
|
* @param [eachOther=true] 相互裁剪
|
|
|
|
|
*/
|
|
|
|
|
ClipWall(shape: ExtudeWallShape, eachOther = true)
|
|
|
|
|
ClipTo(groove: Groove, eachOther = true)
|
|
|
|
|
{
|
|
|
|
|
//相同深度和面不用操作
|
|
|
|
|
if (shape.depthType === this.depthType && shape.depth === this.depth) return;
|
|
|
|
|
if (groove.depthType === this.depthType && groove.depth === this.depth) return;
|
|
|
|
|
|
|
|
|
|
if (!this.box.intersectsBox(shape.box)) return;
|
|
|
|
|
if (!IntersectsBox(this.box, groove.box)) return;
|
|
|
|
|
|
|
|
|
|
this.ClipShape(shape);
|
|
|
|
|
shape.ClipShape(this);
|
|
|
|
|
this.ClipLid(groove);
|
|
|
|
|
groove.ClipLid(this);
|
|
|
|
|
|
|
|
|
|
//一正一反,不交集
|
|
|
|
|
if (this.depthType + shape.depthType === 3 && this.depth + shape.depth < this.allDepth)
|
|
|
|
|
if (this.depthType + groove.depthType === 3 && this.depth + groove.depth < this.allDepth)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
this.contour.Clip(shape, true);
|
|
|
|
|
for (let c of this.holes)
|
|
|
|
|
c.Clip(shape, true);
|
|
|
|
|
this.contourWall.ClipTo(groove, true);
|
|
|
|
|
for (let wall of this.holeWalls)
|
|
|
|
|
wall.ClipTo(groove, true);
|
|
|
|
|
|
|
|
|
|
if (eachOther)
|
|
|
|
|
{
|
|
|
|
|
shape.contour.Clip(this, false);
|
|
|
|
|
for (let c of shape.holes)
|
|
|
|
|
c.Clip(this, false);
|
|
|
|
|
groove.contourWall.ClipTo(this, false);
|
|
|
|
|
for (let wall of groove.holeWalls)
|
|
|
|
|
wall.ClipTo(this, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClipShape(shape: ExtudeWallShape)
|
|
|
|
|
private ClipLid(groove: Groove)
|
|
|
|
|
{
|
|
|
|
|
if (this.depthType === DepthType.All) return;
|
|
|
|
|
if (shape.depthType === DepthType.All) return;
|
|
|
|
|
if (groove.depthType === DepthType.All) return;
|
|
|
|
|
|
|
|
|
|
if (this.depthType === shape.depthType)
|
|
|
|
|
if (this.depthType === groove.depthType)
|
|
|
|
|
{
|
|
|
|
|
if (shape.depth > this.depth)
|
|
|
|
|
this.shape.ClipTo(shape.shape, true);
|
|
|
|
|
if (groove.depth > this.depth)
|
|
|
|
|
this.lid.ClipTo(groove.lid, true);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this.shape.SplitTo(shape.shape);
|
|
|
|
|
}
|
|
|
|
|
this.lid.SplitTo(groove.lid);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (this.depth + shape.depth >= this.allDepth)
|
|
|
|
|
this.shape.ClipTo(shape.shape, true);
|
|
|
|
|
if (this.depth + groove.depth >= this.allDepth)
|
|
|
|
|
this.lid.ClipTo(groove.lid, true);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this.shape.SplitTo(shape.shape);
|
|
|
|
|
}
|
|
|
|
|
this.lid.SplitTo(groove.lid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Draw(verticesArray: number[], uvArray: number[], edgeBuild: EdgeGeometryBuild, rotateUv: boolean)
|
|
|
|
|
{
|
|
|
|
|
this.contour.Draw(verticesArray, uvArray, edgeBuild);
|
|
|
|
|
for (let wall of this.holes)
|
|
|
|
|
this.contourWall.Draw(verticesArray, uvArray, edgeBuild);
|
|
|
|
|
for (let wall of this.holeWalls)
|
|
|
|
|
wall.Draw(verticesArray, uvArray, edgeBuild);
|
|
|
|
|
|
|
|
|
|
if (this.depthType === DepthType.All) return;
|
|
|
|
|
|
|
|
|
|
let isFront = this.depthType === DepthType.Front;
|
|
|
|
|
this.shape.Draw(verticesArray, uvArray, isFront, isFront ? this.allDepth - this.depth : this.depth, rotateUv);
|
|
|
|
|
this.lid.Draw(verticesArray, uvArray, isFront, isFront ? this.allDepth - this.depth : this.depth, rotateUv);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -189,18 +142,16 @@ enum DirectionType
|
|
|
|
|
Inner = 1 //内墙
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//轮廓树,用于重新确认外墙和网洞的关系
|
|
|
|
|
class ContourTree
|
|
|
|
|
{
|
|
|
|
|
parent: ContourTree;
|
|
|
|
|
constructor(public contour: Contour, public children: ContourTree[] = [])
|
|
|
|
|
//轮廓树节点,用于重新确认外墙和网洞的关系
|
|
|
|
|
export class ContourTreeNode
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
parent: ContourTreeNode;//当存在Parent时,表示它是一个洞
|
|
|
|
|
constructor(public contour: Contour, public children: ContourTreeNode[] = []) { }
|
|
|
|
|
|
|
|
|
|
SetParent(s: ContourTree)
|
|
|
|
|
SetParent(node: ContourTreeNode)
|
|
|
|
|
{
|
|
|
|
|
this.parent = s;
|
|
|
|
|
s.children.push(this);
|
|
|
|
|
this.parent = node;
|
|
|
|
|
node.children.push(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Draw(verticesArray: number[], uvArray: number[], front: boolean, z: number, rotateUv: boolean)//, depth = 1
|
|
|
|
@ -253,20 +204,20 @@ class ContourTree
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ParseContourTree(contourTrees: ContourTree[])
|
|
|
|
|
static ParseContourTree(contourNodes: ContourTreeNode[]): void
|
|
|
|
|
{
|
|
|
|
|
contourTrees.sort((c1, c2) => c1.contour.Curve.Area - c2.contour.Curve.Area);
|
|
|
|
|
for (let i = 0; i < contourTrees.length; i++)
|
|
|
|
|
contourNodes.sort((c1, c2) => c1.contour.Curve.Area - c2.contour.Curve.Area);
|
|
|
|
|
for (let i = 0; i < contourNodes.length; i++)
|
|
|
|
|
{
|
|
|
|
|
const s = contourTrees[i];
|
|
|
|
|
let p = s.contour.Curve.StartPoint;
|
|
|
|
|
for (let j = i + 1; j < contourTrees.length; j++)
|
|
|
|
|
const node1 = contourNodes[i];
|
|
|
|
|
let p = node1.contour.Curve.StartPoint;
|
|
|
|
|
for (let j = i + 1; j < contourNodes.length; j++)
|
|
|
|
|
{
|
|
|
|
|
const s2 = contourTrees[j];
|
|
|
|
|
if (s2.contour.BoundingBox.intersectsBox(s.contour.BoundingBox)
|
|
|
|
|
&& s2.contour.Curve.PtInCurve(p))
|
|
|
|
|
const node2 = contourNodes[j];
|
|
|
|
|
if (node2.contour.BoundingBox.intersectsBox(node1.contour.BoundingBox)
|
|
|
|
|
&& node2.contour.Curve.PtInCurve(p))
|
|
|
|
|
{
|
|
|
|
|
s.SetParent(s2);
|
|
|
|
|
node1.SetParent(node2);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -276,7 +227,7 @@ class ContourTree
|
|
|
|
|
|
|
|
|
|
class EdgeGeometryBuild
|
|
|
|
|
{
|
|
|
|
|
verticesArray: number[] = [];
|
|
|
|
|
lineVerticesArray: number[] = [];
|
|
|
|
|
|
|
|
|
|
frontLines: Line[] = [];
|
|
|
|
|
backLines: Line[] = [];
|
|
|
|
@ -299,19 +250,6 @@ class EdgeGeometryBuild
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param pts3d 给了首尾相等的点表
|
|
|
|
|
*/
|
|
|
|
|
AddEdgePolygon(pts3d: Vector3[])
|
|
|
|
|
{
|
|
|
|
|
for (let i = 0; i < pts3d.length - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
let p = pts3d[i];
|
|
|
|
|
let np = pts3d[i + 1];
|
|
|
|
|
this.verticesArray.push(p.x, p.y, p.z, np.x, np.y, np.z);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BuildLid(verticesArray: number[], uvArray: number[], rotateUv: boolean)
|
|
|
|
|
{
|
|
|
|
|
let arr = [this.backLines, this.frontLines];
|
|
|
|
@ -320,7 +258,7 @@ class EdgeGeometryBuild
|
|
|
|
|
{
|
|
|
|
|
let lines = arr[index];
|
|
|
|
|
let parse = new RegionParse(lines);
|
|
|
|
|
let contours: ContourTree[] = [];
|
|
|
|
|
let contourNodes: ContourTreeNode[] = [];
|
|
|
|
|
for (let routes of parse.RegionsOutline)
|
|
|
|
|
{
|
|
|
|
|
let cs: Curve[] = [];
|
|
|
|
@ -328,24 +266,27 @@ class EdgeGeometryBuild
|
|
|
|
|
cs.push(r.curve);
|
|
|
|
|
let c = Contour.CreateContour(cs, false);
|
|
|
|
|
if (c)
|
|
|
|
|
contours.push(new ContourTree(c));
|
|
|
|
|
contourNodes.push(new ContourTreeNode(c));
|
|
|
|
|
else
|
|
|
|
|
console.error("未能构建盖子");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContourTree.ParseContourTree(contours);
|
|
|
|
|
ContourTreeNode.ParseContourTree(contourNodes);
|
|
|
|
|
|
|
|
|
|
for (let j = contours.length; j--;)
|
|
|
|
|
for (let j = contourNodes.length; j--;)
|
|
|
|
|
{
|
|
|
|
|
let s = contours[j];
|
|
|
|
|
if (s.parent) continue;
|
|
|
|
|
let node = contourNodes[j];
|
|
|
|
|
if (node.parent) continue;
|
|
|
|
|
|
|
|
|
|
s.Draw(verticesArray, uvArray, index === 1, this.allDepth * index, rotateUv);
|
|
|
|
|
node.Draw(verticesArray, uvArray, index === 1, this.allDepth * index, rotateUv);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 胶带
|
|
|
|
|
*/
|
|
|
|
|
class Tape
|
|
|
|
|
{
|
|
|
|
|
constructor(
|
|
|
|
@ -405,7 +346,10 @@ class Tape
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CurveTapeShape
|
|
|
|
|
/**
|
|
|
|
|
* 二维形状,内部用曲线胶带表示(用来计算盖子差集算法)
|
|
|
|
|
*/
|
|
|
|
|
export class CurveTapeShape
|
|
|
|
|
{
|
|
|
|
|
children: CurveTapeShape[] = [];
|
|
|
|
|
contour: CurveTape;
|
|
|
|
@ -439,7 +383,7 @@ class CurveTapeShape
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//合理打断
|
|
|
|
|
//合理打断(以保证三维网格对齐(否则圆弧点将无法正确的对齐))
|
|
|
|
|
SplitTo(s: CurveTapeShape)
|
|
|
|
|
{
|
|
|
|
|
for (let c of [this.contour, ...this.holes])
|
|
|
|
@ -452,7 +396,10 @@ class CurveTapeShape
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReverseClipTo(s: CurveTapeShape): this
|
|
|
|
|
/**
|
|
|
|
|
* 只保留被包含部分
|
|
|
|
|
*/
|
|
|
|
|
private ReverseClipTo(s: CurveTapeShape): this
|
|
|
|
|
{
|
|
|
|
|
for (let c of [this.contour, ... this.holes])
|
|
|
|
|
if (c.tapes.length > 0)
|
|
|
|
@ -494,25 +441,25 @@ class CurveTapeShape
|
|
|
|
|
|
|
|
|
|
// TestDraw(polylines, z);
|
|
|
|
|
let groups = curveLinkGroup(polylines);
|
|
|
|
|
let contourTrees: ContourTree[] = [];
|
|
|
|
|
let contourNodes: ContourTreeNode[] = [];
|
|
|
|
|
for (let cus of groups)
|
|
|
|
|
{
|
|
|
|
|
let c = Contour.CreateContour(cus, false);
|
|
|
|
|
if (c)
|
|
|
|
|
contourTrees.push(new ContourTree(c));
|
|
|
|
|
contourNodes.push(new ContourTreeNode(c));
|
|
|
|
|
else
|
|
|
|
|
console.error("出错");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContourTree.ParseContourTree(contourTrees);
|
|
|
|
|
ContourTreeNode.ParseContourTree(contourNodes);
|
|
|
|
|
|
|
|
|
|
for (let j = contourTrees.length; j--;)
|
|
|
|
|
for (let j = contourNodes.length; j--;)
|
|
|
|
|
{
|
|
|
|
|
let s = contourTrees[j];
|
|
|
|
|
let node = contourNodes[j];
|
|
|
|
|
// TestDraw(s.contour.Curve.Clone(), z);
|
|
|
|
|
if (s.parent) continue;
|
|
|
|
|
if (node.parent) continue;
|
|
|
|
|
|
|
|
|
|
s.Draw(verticesArray, uvArray, front, z, rotateUv);
|
|
|
|
|
node.Draw(verticesArray, uvArray, front, z, rotateUv);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -562,11 +509,12 @@ function SplitCurveParams(cu: ExtureContourCurve): number[]
|
|
|
|
|
return xparams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 曲线胶带(一维)
|
|
|
|
|
*/
|
|
|
|
|
class CurveTape
|
|
|
|
|
{
|
|
|
|
|
type: DirectionType;
|
|
|
|
|
tapes: Range[];
|
|
|
|
|
|
|
|
|
|
splitParams: number[] = [];
|
|
|
|
|
constructor(public contour: Contour, public wallType: DirectionType)
|
|
|
|
|
{
|
|
|
|
@ -585,11 +533,9 @@ class CurveTape
|
|
|
|
|
|
|
|
|
|
let polylines: Polyline[] = [];
|
|
|
|
|
|
|
|
|
|
function TD(p: Vector3)
|
|
|
|
|
function TD(p: Vector3): PolylineProps
|
|
|
|
|
{
|
|
|
|
|
return {
|
|
|
|
|
pt: AsVector2(p), bul: 0
|
|
|
|
|
};
|
|
|
|
|
return { pt: AsVector2(p), bul: 0 };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const addPolyline = (t: Range) =>
|
|
|
|
@ -621,16 +567,19 @@ class CurveTape
|
|
|
|
|
return polylines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Parse(s: CurveTapeShape): CurveRange
|
|
|
|
|
/**
|
|
|
|
|
* 分析与另一个形状的包含关系
|
|
|
|
|
*/
|
|
|
|
|
Parse(s: CurveTapeShape): CurveParamRangeRelation
|
|
|
|
|
{
|
|
|
|
|
let [res1] = Parse(this.contour.Curve, s.contour.contour.Curve);
|
|
|
|
|
let [res1] = ParseCurveParamRangeRelation(this.contour.Curve, s.contour.contour.Curve);
|
|
|
|
|
if (this.wallType === DirectionType.Inner)
|
|
|
|
|
[res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy];
|
|
|
|
|
if (res1.container.length > 0)
|
|
|
|
|
{
|
|
|
|
|
for (let h of s.holes)
|
|
|
|
|
{
|
|
|
|
|
let [res2] = Parse(this.contour.Curve, h.contour.Curve);
|
|
|
|
|
let [res2] = ParseCurveParamRangeRelation(this.contour.Curve, h.contour.Curve);
|
|
|
|
|
if (this.wallType === DirectionType.Outer)
|
|
|
|
|
[res2.syntropy, res2.reverse] = [res2.reverse, res2.syntropy];
|
|
|
|
|
|
|
|
|
@ -663,8 +612,7 @@ class CurveTape
|
|
|
|
|
*/
|
|
|
|
|
ReverseClipTo(s: CurveTapeShape): this
|
|
|
|
|
{
|
|
|
|
|
let d = this.Parse(s);
|
|
|
|
|
this.tapes = d.container;
|
|
|
|
|
this.tapes = this.Parse(s).container;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -672,7 +620,7 @@ class CurveTape
|
|
|
|
|
class ExtudeWall
|
|
|
|
|
{
|
|
|
|
|
//胶带(立面)
|
|
|
|
|
Tape: Tape[];
|
|
|
|
|
private Tape: Tape[];
|
|
|
|
|
constructor(public curve: ExtureContourCurve,
|
|
|
|
|
public depthType: DepthType,
|
|
|
|
|
public depth: number,
|
|
|
|
@ -685,20 +633,20 @@ class ExtudeWall
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 裁剪
|
|
|
|
|
* @param shape
|
|
|
|
|
* 减去在另一个groove内的部分
|
|
|
|
|
* @param groove this - groove
|
|
|
|
|
* @param [clipSyntropy=false] 删除同向的面
|
|
|
|
|
*/
|
|
|
|
|
Clip(shape: ExtudeWallShape, clipSyntropy = false)
|
|
|
|
|
ClipTo(groove: Groove, clipSyntropy = false)
|
|
|
|
|
{
|
|
|
|
|
let [res1, res2] = Parse(this.curve, shape.contour.curve);
|
|
|
|
|
if (this.wallType !== shape.contour.wallType)
|
|
|
|
|
let [res1] = ParseCurveParamRangeRelation(this.curve, groove.contourWall.curve);
|
|
|
|
|
if (this.wallType !== groove.contourWall.wallType)
|
|
|
|
|
[res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy];
|
|
|
|
|
if (res1.container.length > 0)
|
|
|
|
|
{
|
|
|
|
|
for (let h of shape.holes)
|
|
|
|
|
for (let h of groove.holeWalls)
|
|
|
|
|
{
|
|
|
|
|
let [resh1, resh2] = Parse(this.curve, h.curve);
|
|
|
|
|
let [resh1] = ParseCurveParamRangeRelation(this.curve, h.curve);
|
|
|
|
|
|
|
|
|
|
//翻转
|
|
|
|
|
if (this.wallType !== h.wallType)
|
|
|
|
@ -726,14 +674,12 @@ class ExtudeWall
|
|
|
|
|
params.push(...res1.syntropy);
|
|
|
|
|
|
|
|
|
|
for (let c of params)
|
|
|
|
|
{
|
|
|
|
|
this.ClipFromParam(c[0], c[1], shape.depthType, shape.depth);
|
|
|
|
|
}
|
|
|
|
|
this.ClipFromParam(c[0], c[1], groove.depthType, groove.depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClipReverse(wall: this)
|
|
|
|
|
{
|
|
|
|
|
let [res1, res2] = Parse(this.curve, wall.curve);
|
|
|
|
|
let [res1] = ParseCurveParamRangeRelation(this.curve, wall.curve);
|
|
|
|
|
for (let c of res1.syntropy)
|
|
|
|
|
this.ClipFromParam(c[0], c[1], wall.depthType, wall.depth);
|
|
|
|
|
}
|
|
|
|
@ -775,17 +721,67 @@ class ExtudeWall
|
|
|
|
|
verticesArray.push(v.y);
|
|
|
|
|
verticesArray.push(v.z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let tapes: Tape[] = [];
|
|
|
|
|
this.Tape.sort((t1, t2) => t1.start - t2.start);
|
|
|
|
|
for (let tape of this.Tape)
|
|
|
|
|
tapes.push(...tape.Split(xparams));
|
|
|
|
|
for (let i = 0; i < tapes.length; i++)
|
|
|
|
|
{
|
|
|
|
|
let tapes = tape.Split(xparams);
|
|
|
|
|
for (let t of tapes)
|
|
|
|
|
let preIndex = FixIndex(i - 1, tapes);
|
|
|
|
|
let nextIndex = FixIndex(i + 1, tapes);
|
|
|
|
|
|
|
|
|
|
let tape = tapes[i];
|
|
|
|
|
let preTape = tapes[preIndex];
|
|
|
|
|
let nextTape = tapes[nextIndex];
|
|
|
|
|
|
|
|
|
|
let p1 = this.curve.GetPointAtParam(tape.start).setZ(tape.bottom);
|
|
|
|
|
let p2 = this.curve.GetPointAtParam(tape.end).setZ(tape.bottom);
|
|
|
|
|
let vs = [p1, p2, p2.clone().setZ(tape.top), p1.clone().setZ(tape.top), p1];
|
|
|
|
|
edgeBuild.AddLidLine(p1, p2, tape.bottom);
|
|
|
|
|
edgeBuild.AddLidLine(p1, p2, tape.top);
|
|
|
|
|
|
|
|
|
|
//#region 构造线框
|
|
|
|
|
{
|
|
|
|
|
let p1 = this.curve.GetPointAtParam(t.start).setZ(t.bottom);
|
|
|
|
|
let p2 = this.curve.GetPointAtParam(t.end).setZ(t.bottom);
|
|
|
|
|
let vs = [p1, p2, p2.clone().setZ(t.top), p1.clone().setZ(t.top), p1];
|
|
|
|
|
edgeBuild.AddLidLine(p1, p2, t.bottom);
|
|
|
|
|
edgeBuild.AddLidLine(p1, p2, t.top);
|
|
|
|
|
edgeBuild.AddEdgePolygon(vs);
|
|
|
|
|
let leftRanges: Range[];
|
|
|
|
|
let rightRange: Range[];
|
|
|
|
|
|
|
|
|
|
const IsInteger = (n: number) => equaln(n, Math.round(n), 1e-8);
|
|
|
|
|
|
|
|
|
|
if (!IsInteger(tape.start) && equaln(tape.start, preTape.end))
|
|
|
|
|
leftRanges = SubtractRange(tape.bottom, tape.top, preTape.bottom, preTape.top, this.allDepth);
|
|
|
|
|
else
|
|
|
|
|
leftRanges = [[tape.bottom, tape.top]];
|
|
|
|
|
|
|
|
|
|
if (equaln(tape.end, nextTape.start))
|
|
|
|
|
rightRange = SubtractRange(tape.bottom, tape.top, nextTape.bottom, nextTape.top, this.allDepth);
|
|
|
|
|
else
|
|
|
|
|
rightRange = [[tape.bottom, tape.top]];
|
|
|
|
|
|
|
|
|
|
//上下两条线
|
|
|
|
|
edgeBuild.lineVerticesArray.push(
|
|
|
|
|
p1.x, p1.y, p1.z,
|
|
|
|
|
p2.x, p2.y, p2.z,
|
|
|
|
|
|
|
|
|
|
p1.x, p1.y, tape.top,
|
|
|
|
|
p2.x, p2.y, tape.top,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
//左右线
|
|
|
|
|
for (let range of leftRanges)
|
|
|
|
|
{
|
|
|
|
|
edgeBuild.lineVerticesArray.push(
|
|
|
|
|
p1.x, p1.y, range[0],
|
|
|
|
|
p1.x, p1.y, range[1]);
|
|
|
|
|
}
|
|
|
|
|
for (let range of rightRange)
|
|
|
|
|
{
|
|
|
|
|
edgeBuild.lineVerticesArray.push(
|
|
|
|
|
p2.x, p2.y, range[0],
|
|
|
|
|
p2.x, p2.y, range[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
//和X平行平行
|
|
|
|
|
let isXPar = (vs[0].y + vs[1].y + vs[2].y) < 0.01;
|
|
|
|
@ -832,9 +828,12 @@ class ExtudeWall
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface CurveRange
|
|
|
|
|
/**
|
|
|
|
|
* 曲线参数范围关系(包含,分离,同向共线,反向共线)
|
|
|
|
|
* 用来表示某一曲线在另一个曲线内的关系
|
|
|
|
|
*/
|
|
|
|
|
interface CurveParamRangeRelation
|
|
|
|
|
{
|
|
|
|
|
outer: Range[];//外部
|
|
|
|
|
container: Range[];//被包含
|
|
|
|
@ -842,7 +841,7 @@ interface CurveRange
|
|
|
|
|
reverse: Range[];//反向
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function CloneCurveRange(r: CurveRange): CurveRange
|
|
|
|
|
function CloneCurveRange(r: CurveParamRangeRelation): CurveParamRangeRelation
|
|
|
|
|
{
|
|
|
|
|
return {
|
|
|
|
|
outer: r.outer.slice(),
|
|
|
|
@ -878,7 +877,7 @@ function binarySearch(ar: number[], el: number): number
|
|
|
|
|
return -m - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function CurveSplit(cu: Curve, range: CurveRange): CurveSegs
|
|
|
|
|
function CurveSplit(cu: Curve, range: CurveParamRangeRelation): CurveSegs
|
|
|
|
|
{
|
|
|
|
|
let segs = { outer: [], container: [], syntropy: [], reverse: [] };
|
|
|
|
|
|
|
|
|
@ -903,18 +902,14 @@ function CurveSplit(cu: Curve, range: CurveRange): CurveSegs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分析两个曲线的状态
|
|
|
|
|
* @param cu1
|
|
|
|
|
* @param cu2
|
|
|
|
|
* @param ins
|
|
|
|
|
* @returns
|
|
|
|
|
* 分析两个曲线关系(包含,分离,同向共线,反向共线)(用参数范围表示)
|
|
|
|
|
*/
|
|
|
|
|
function Parse(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse = false): [CurveRange, CurveRange]
|
|
|
|
|
function ParseCurveParamRangeRelation(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse = false): [CurveParamRangeRelation, CurveParamRangeRelation]
|
|
|
|
|
{
|
|
|
|
|
let ins = GetIntersection(cu1, cu2);
|
|
|
|
|
|
|
|
|
|
let c1Res: CurveRange = { container: [], syntropy: [], reverse: [], outer: [] };
|
|
|
|
|
let c2Res: CurveRange = { container: [], syntropy: [], reverse: [], outer: [] };
|
|
|
|
|
let c1Res: CurveParamRangeRelation = { container: [], syntropy: [], reverse: [], outer: [] };
|
|
|
|
|
let c2Res: CurveParamRangeRelation = { container: [], syntropy: [], reverse: [], outer: [] };
|
|
|
|
|
if (ins.length === 0)
|
|
|
|
|
{
|
|
|
|
|
if (cu2.PtInCurve(cu1.StartPoint))
|
|
|
|
@ -943,6 +938,9 @@ function Parse(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse =
|
|
|
|
|
let c2Curves: CurveSeg[] = [];
|
|
|
|
|
|
|
|
|
|
ins.sort((a1, a2) => a1.thisParam - a2.thisParam);
|
|
|
|
|
//点重复->下方ins会sort,导致交点对应不上,导致错误
|
|
|
|
|
arrayRemoveDuplicateBySort(ins, (i1, i2) => equalv3(i1.pt, i2.pt, 1e-4));
|
|
|
|
|
if (ins.length > 1 && equalv3(ins[0].pt, ins[ins.length - 1].pt, 1e-4)) ins.pop();
|
|
|
|
|
for (let i = 0; i < ins.length; i++)
|
|
|
|
|
{
|
|
|
|
|
let n1 = ins[i];
|
|
|
|
@ -957,7 +955,6 @@ function Parse(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse =
|
|
|
|
|
c2Curves.push({ startParam: n1.argParam, endParam: n2.argParam, startPoint: n1.pt, endPoint: n2.pt });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//分析共边关系和包含关系
|
|
|
|
|
for (let c of c1Curves)
|
|
|
|
|
{
|
|
|
|
@ -968,7 +965,7 @@ function Parse(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse =
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
let c2MidPoint = CenterPoint(cu2, c2.startParam, c2.endParam);
|
|
|
|
|
if (!equalv3(c1MidPoint, c2MidPoint))
|
|
|
|
|
if (!equalv3(c1MidPoint, c2MidPoint, 1e-4))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
c.used = true;
|
|
|
|
@ -1031,7 +1028,6 @@ function CenterPoint(cu: ExtureContourCurve, start: number, end: number)
|
|
|
|
|
return cu.GetPointAtDistance(lenStart + lenDiv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//求参数并集部分,交集部分,差集部分
|
|
|
|
|
|
|
|
|
|
//求 ab 和 cd 的并集部分
|
|
|
|
@ -1136,46 +1132,38 @@ function IntersectRange(a: number, b: number, c: number, d: number, end: number)
|
|
|
|
|
return [c1, Math.min(b1, d1)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const alMatrix4 = new Matrix4;
|
|
|
|
|
|
|
|
|
|
export class ExtrudeGeometryBuilder
|
|
|
|
|
{
|
|
|
|
|
brOcsInv: Matrix4;
|
|
|
|
|
alMatrix4: Matrix4 = new Matrix4;
|
|
|
|
|
|
|
|
|
|
contour: Contour;
|
|
|
|
|
|
|
|
|
|
shapes: ExtudeWallShape[] = [];
|
|
|
|
|
|
|
|
|
|
verticesArray: number[] = [];
|
|
|
|
|
uvArray: number[] = [];
|
|
|
|
|
verticesArray: number[] = [];//用于构建三维网格
|
|
|
|
|
uvArray: number[] = [];//uv
|
|
|
|
|
|
|
|
|
|
edgeAndLidBuilder: EdgeGeometryBuild;
|
|
|
|
|
|
|
|
|
|
constructor(private br: ExtrudeSolid)
|
|
|
|
|
{
|
|
|
|
|
this.edgeAndLidBuilder = new EdgeGeometryBuild(this.br.Thickness);
|
|
|
|
|
this.brOcsInv = br.OCSInv;
|
|
|
|
|
let rotateUv = (br instanceof Board && br.BoardProcessOption.lines === LinesType.Reverse);
|
|
|
|
|
this.contour = Contour.CreateContour(br.ContourCurve.Clone());
|
|
|
|
|
|
|
|
|
|
this.ParseGrooves();
|
|
|
|
|
|
|
|
|
|
//计算墙
|
|
|
|
|
let outerWall = new ExtudeWall(this.contour.Curve, DepthType.All, br.Thickness, br.Thickness, DirectionType.Outer);
|
|
|
|
|
for (let i = 0; i < this.shapes.length; i++)
|
|
|
|
|
//计算墙(创建轮廓取出,为了得到正确的轮廓曲线(逆时针之类的))
|
|
|
|
|
let outerWall = new ExtudeWall(Contour.CreateContour(br.ContourCurve.Clone()).Curve, DepthType.All, br.Thickness, br.Thickness, DirectionType.Outer);
|
|
|
|
|
let grooves = this.ParseGrooves();
|
|
|
|
|
for (let i = 0; i < grooves.length; i++)
|
|
|
|
|
{
|
|
|
|
|
let s1 = this.shapes[i];
|
|
|
|
|
outerWall.Clip(s1, false);
|
|
|
|
|
s1.contour.ClipReverse(outerWall);
|
|
|
|
|
for (let j = i + 1; j < this.shapes.length; j++)
|
|
|
|
|
let s1 = grooves[i];
|
|
|
|
|
outerWall.ClipTo(s1, false);
|
|
|
|
|
s1.contourWall.ClipReverse(outerWall);
|
|
|
|
|
for (let j = i + 1; j < grooves.length; j++)
|
|
|
|
|
{
|
|
|
|
|
let s2 = this.shapes[j];
|
|
|
|
|
s1.ClipWall(s2, true);
|
|
|
|
|
let s2 = grooves[j];
|
|
|
|
|
s1.ClipTo(s2, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s1.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder, rotateUv);
|
|
|
|
|
}
|
|
|
|
|
outerWall.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder);
|
|
|
|
|
|
|
|
|
|
//这里构建盖子
|
|
|
|
|
this.edgeAndLidBuilder.BuildLid(this.verticesArray, this.uvArray, rotateUv);
|
|
|
|
|
|
|
|
|
|
intCache.clear();
|
|
|
|
@ -1193,53 +1181,57 @@ export class ExtrudeGeometryBuilder
|
|
|
|
|
get EdgeGeometry()
|
|
|
|
|
{
|
|
|
|
|
let geo = new BufferGeometry();
|
|
|
|
|
geo.setAttribute('position', new Float32BufferAttribute(this.edgeAndLidBuilder.verticesArray, 3));
|
|
|
|
|
geo.setAttribute('position', new Float32BufferAttribute(this.edgeAndLidBuilder.lineVerticesArray, 3));
|
|
|
|
|
return geo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ParseGrooves()
|
|
|
|
|
{
|
|
|
|
|
let br = this.br;
|
|
|
|
|
for (let g of br.Grooves)
|
|
|
|
|
const brOcsInv = br.OCSInv;
|
|
|
|
|
let grooves: Groove[] = [];
|
|
|
|
|
for (let groove of br.Grooves)
|
|
|
|
|
{
|
|
|
|
|
//判断槽正反面
|
|
|
|
|
let type: DepthType;
|
|
|
|
|
if (equaln(g.Thickness, br.Thickness))
|
|
|
|
|
if (equaln(groove.Thickness, br.Thickness))
|
|
|
|
|
type = DepthType.All;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (equaln(g.Position.applyMatrix4(this.brOcsInv).z, 0))
|
|
|
|
|
if (equaln(groove.Position.applyMatrix4(brOcsInv).z, 0))
|
|
|
|
|
type = DepthType.Back;
|
|
|
|
|
else
|
|
|
|
|
type = DepthType.Front;
|
|
|
|
|
}
|
|
|
|
|
this.alMatrix4.multiplyMatrices(this.brOcsInv, g.OCSNoClone);
|
|
|
|
|
alMatrix4.multiplyMatrices(brOcsInv, groove.OCSNoClone);
|
|
|
|
|
//槽轮廓
|
|
|
|
|
let gContour = g.ContourCurve.Clone();
|
|
|
|
|
gContour.ApplyMatrix(this.alMatrix4);
|
|
|
|
|
gContour.Z0();
|
|
|
|
|
if (gContour instanceof Polyline) gContour.UpdateMatrixTo(IdentityMtx4);//不可能改变这个
|
|
|
|
|
let contour = Contour.CreateContour(gContour);
|
|
|
|
|
let grooveContourCurve = groove.ContourCurve.Clone();
|
|
|
|
|
grooveContourCurve.ApplyMatrix(alMatrix4);
|
|
|
|
|
grooveContourCurve.Z0();
|
|
|
|
|
if (grooveContourCurve instanceof Polyline) grooveContourCurve.UpdateMatrixTo(IdentityMtx4);//不可能改变这个
|
|
|
|
|
let grooveContour = Contour.CreateContour(grooveContourCurve);
|
|
|
|
|
|
|
|
|
|
let holes: Contour[] = [];
|
|
|
|
|
let grooveHoleContours: Contour[] = [];
|
|
|
|
|
//孤岛
|
|
|
|
|
for (let gg of g.Grooves)
|
|
|
|
|
for (let grooveChild of groove.Grooves)
|
|
|
|
|
{
|
|
|
|
|
let c = gg.ContourCurve.Clone();
|
|
|
|
|
this.alMatrix4.multiplyMatrices(this.brOcsInv, gg.OCSNoClone);
|
|
|
|
|
c.ApplyMatrix(this.alMatrix4).Z0();
|
|
|
|
|
if (c instanceof Polyline) c.UpdateMatrixTo(IdentityMtx4);
|
|
|
|
|
let contour = Contour.CreateContour(c);
|
|
|
|
|
holes.push(contour);
|
|
|
|
|
let grooveChildContourCurve = grooveChild.ContourCurve.Clone();
|
|
|
|
|
alMatrix4.multiplyMatrices(brOcsInv, grooveChild.OCSNoClone);
|
|
|
|
|
grooveChildContourCurve.ApplyMatrix(alMatrix4).Z0();
|
|
|
|
|
if (grooveChildContourCurve instanceof Polyline) grooveChildContourCurve.UpdateMatrixTo(IdentityMtx4);
|
|
|
|
|
let grooveChildContour = Contour.CreateContour(grooveChildContourCurve);
|
|
|
|
|
grooveHoleContours.push(grooveChildContour);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.shapes.push(new ExtudeWallShape(contour, holes, type, g.Thickness, br.Thickness));
|
|
|
|
|
grooves.push(new Groove(grooveContour, grooveHoleContours, type, groove.Thickness, br.Thickness));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return grooves;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let intCache = new Map<Curve, Map<Curve, IntersectResult[]>>();
|
|
|
|
|
function GetIntersection(cu1: Curve, cu2: Curve)
|
|
|
|
|
function GetIntersection(cu1: Curve, cu2: Curve): IntersectResult[]
|
|
|
|
|
{
|
|
|
|
|
let m = intCache.get(cu1);
|
|
|
|
|
if (m)
|
|
|
|
|