!1067 优化:拉伸实体的显示优化(线框和实体模式)

pull/1067/MERGE
ChenX 4 years ago
parent cbdcaafca5
commit 0729c1b650

@ -39,7 +39,7 @@ test('Geometry构建测试', () =>
{
let builder = new ExtrudeGeometryBuilder(br);
expect(builder.verticesArray.length).toMatchSnapshot();
expect(builder.edgeAndLidBuilder.verticesArray.length).toMatchSnapshot();
expect(builder.edgeAndLidBuilder.lineVerticesArray.length).toMatchSnapshot();
}
});
@ -53,6 +53,21 @@ test('极限共线', () =>
{
let builder = new ExtrudeGeometryBuilder(br);
expect(builder.verticesArray.length).toMatchSnapshot();
expect(builder.edgeAndLidBuilder.verticesArray.length).toMatchSnapshot();
expect(builder.edgeAndLidBuilder.lineVerticesArray.length).toMatchSnapshot();
}
});
test('盖子构建失败', () =>
{
//原因是因为交点太多
let d =
{ "file": [1, "Board", 8, 2, 110, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 4300.009279073407, 2076.9410852395504, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4300.009279073407, 2076.9410852395504, -500.99609312660925, 1], 0, 3, 555.6884165302121, 564, 18, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -500.99609312660925, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 500.99609312660925], 0, [564, 500.9960931266093], 0, [564, 1056.6845096568213], 0, [0, 1056.6845096568213], 0, true, 1, 3, 2.650032406101512, 711.383779232115, 2.7331290961030845, true, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [711.383779232115, 0], 0, [711.383779232115, 2.650032406101512], 0, [0, 2.650032406101512], 0, true, 0, 3, 0, 0, 0, 0, 0, [0, 0.7928210010759529, 0, 0, 0, 0, 0.7928210010759529, 0, 1, 0, 0, 0, 4315.276149977304, 2076.9410852395504, 6.233907470232225e-7, 1], 3, 0, 0, 0, 0, 0, 9, 1, "立板", "1", "1", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true], "basePt": { "x": 4300.009279073407, "y": 2076.9410852395504, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] };
let brs = LoadBoardsFromFileData(d);
for (let br of brs)
{
let builder = new ExtrudeGeometryBuilder(br);
expect(builder.verticesArray.length).toMatchSnapshot();
expect(builder.edgeAndLidBuilder.lineVerticesArray.length).toMatchSnapshot();
}
});

@ -2,52 +2,56 @@
exports[`EdgeGeometry生成 1`] = `114`;
exports[`EdgeGeometry生成 2`] = `360`;
exports[`EdgeGeometry生成 2`] = `206`;
exports[`EdgeGeometry生成 3`] = `60`;
exports[`EdgeGeometry生成2 1`] = `80`;
exports[`EdgeGeometry生成2 1`] = `66`;
exports[`Geometry构建测试 1`] = `540`;
exports[`Geometry构建测试 2`] = `408`;
exports[`Geometry构建测试 2`] = `372`;
exports[`Geometry构建测试 3`] = `378`;
exports[`Geometry构建测试 4`] = `288`;
exports[`Geometry构建测试 4`] = `234`;
exports[`Geometry构建测试 5`] = `1188`;
exports[`Geometry构建测试 6`] = `888`;
exports[`Geometry构建测试 6`] = `744`;
exports[`Geometry构建测试 7`] = `774`;
exports[`Geometry构建测试 8`] = `552`;
exports[`Geometry构建测试 8`] = `450`;
exports[`Geometry构建测试 9`] = `630`;
exports[`Geometry构建测试 10`] = `456`;
exports[`Geometry构建测试 10`] = `300`;
exports[`Geometry构建测试 11`] = `1548`;
exports[`Geometry构建测试 12`] = `1056`;
exports[`Geometry构建测试 12`] = `570`;
exports[`Geometry构建测试 13`] = `639`;
exports[`Geometry构建测试 14`] = `480`;
exports[`Geometry构建测试 14`] = `378`;
exports[`Geometry构建测试 15`] = `1998`;
exports[`Geometry构建测试 16`] = `1368`;
exports[`Geometry构建测试 16`] = `786`;
exports[`Geometry构建测试 17`] = `1908`;
exports[`Geometry构建测试 18`] = `1344`;
exports[`Geometry构建测试 18`] = `744`;
exports[`Geometry构建测试 19`] = `2232`;
exports[`Geometry构建测试 20`] = `1584`;
exports[`Geometry构建测试 20`] = `924`;
exports[`极限共线 1`] = `432`;
exports[`极限共线 2`] = `360`;
exports[`极限共线 2`] = `294`;
exports[`盖子构建失败 1`] = `180`;
exports[`盖子构建失败 2`] = `138`;

@ -10,9 +10,9 @@ const config: webpack.Configuration = merge(
output: { pathinfo: false },
devtool: "eval-source-map",
//https://www.webpackjs.com/configuration/stats/
stats: {
stats: "errors-only" || {
assets: false,
timings: true,
timings: false,
builtAt: false,
cachedAssets: false,

@ -1,4 +1,5 @@
import { app } from '../ApplicationServices/Application';
import { IsDev } from '../Common/Deving';
import { GetEntity } from '../Common/Utils';
import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
@ -7,8 +8,22 @@ export class Command_Erase implements Command
{
async exec()
{
if (IsDev() && app.Editor.SelectCtrl.SelectSet.SelectObjectCount)
{
for (let obj of app.Editor.SelectCtrl.SelectSet.SelectObjectList)
{
let ent = GetEntity(obj);
if (ent)
ent.Erase();
else
obj.visible = false;
}
app.Editor.SelectCtrl.Cancel();
return;
}
let ssRes = await app.Editor.GetSelection({ UseSelect: true });
if (ssRes.Status != PromptStatus.OK) return;
if (ssRes.Status !== PromptStatus.OK) return;
for (let obj of ssRes.SelectSet.SelectObjectList)
{

@ -17,35 +17,35 @@ export class Command_TestTape
let br = enRes.Entity as Board;
let geo = new ExtrudeGeometryBuilder(br);
return;
let k = 0;
let i = 1;
let testOut = true;
for (let s of geo.shapes)
{
if (testOut)
{
let m = MoveMatrix(new Vector3(0, k * 20));
for (let t of s.contour.Tape)
{
t.Curve.ApplyMatrix(m);
TestDraw(t.Curve, s.depth);
}
k++;
}
else
{
for (let w of s.holes)
{
let m = MoveMatrix(new Vector3(0, k * 20));
for (let t of w.Tape)
{
t.Curve.ApplyMatrix(m);
TestDraw(t.Curve, w.depth);
}
k++;
}
}
}
// let k = 0;
// let i = 1;
// let testOut = true;
// for (let s of geo)
// {
// if (testOut)
// {
// let m = MoveMatrix(new Vector3(0, k * 20));
// for (let t of s.contourWall.Tape)
// {
// t.Curve.ApplyMatrix(m);
// TestDraw(t.Curve, s.depth);
// }
// k++;
// }
// else
// {
// for (let w of s.holeWalls)
// {
// let m = MoveMatrix(new Vector3(0, k * 20));
// for (let t of w.Tape)
// {
// t.Curve.ApplyMatrix(m);
// TestDraw(t.Curve, w.depth);
// }
// k++;
// }
// }
// }
// let gs = br.Grooves;
// let brOcsInv = br.OCSInv;
// let alm = new Matrix4;

@ -73,7 +73,7 @@ export abstract class Curve extends Entity
get Area2(): number { return 0; }
get Length(): number { return 0; }
get IsClose(): boolean { return false; }
//曲线为顺时针
/** 曲线为顺时针 */
get IsClockWise(): boolean { return this.Area2 < 0; }
abstract get Shape(): Shape;

@ -476,7 +476,7 @@ export class Polyline extends Curve
}
//参数已经大于索引,证明参数在线外.
if (paramFloor != cuCout)
if (paramFloor !== cuCout)
{
dist += this.GetCurveAtParam(param).GetDistAtParam(param - cuCout);
}

@ -23,10 +23,7 @@ export async function ExportObj(brs: Entity[])
for (let b of brs)
{
let o: Object3D;
if (userConfig.RenderType === RenderType.Physical)
o = b.Clone().ApplyMatrix(mtx).GetDrawObjectFromRenderType(RenderType.Physical);
else
o = b.Clone().ApplyMatrix(mtx).GetDrawObjectFromRenderType(RenderType.Conceptual);
o = b.Clone().ApplyMatrix(mtx).GetDrawObjectFromRenderType(RenderType.Physical);
g.add(o);
}

@ -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
//轮廓树节点,用于重新确认外墙和网洞的关系
export class ContourTreeNode
{
parent: ContourTree;
constructor(public contour: Contour, public children: ContourTree[] = [])
{
}
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,66 +721,119 @@ 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,
//和X平行平行
let isXPar = (vs[0].y + vs[1].y + vs[2].y) < 0.01;
p1.x, p1.y, tape.top,
p2.x, p2.y, tape.top,
);
function AddUv(p: Vector3)
//左右线
for (let range of leftRanges)
{
if (isXPar)
uvArray.push((p.z - 1) * 1e-3, p.y * 1e-3);
else
uvArray.push((p.z - 1) * 1e-3, p.x * 1e-3);
edgeBuild.lineVerticesArray.push(
p1.x, p1.y, range[0],
p1.x, p1.y, range[1]);
}
if (this.wallType === DirectionType.Outer)
for (let range of rightRange)
{
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[1]);
AddUv(vs[1]);
AddVertice(vs[2]);
AddUv(vs[2]);
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[2]);
AddUv(vs[2]);
AddVertice(vs[3]);
AddUv(vs[3]);
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;
function AddUv(p: Vector3)
{
if (isXPar)
uvArray.push((p.z - 1) * 1e-3, p.y * 1e-3);
else
{
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[2]);
AddUv(vs[2]);
AddVertice(vs[1]);
AddUv(vs[1]);
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[3]);
AddUv(vs[3]);
AddVertice(vs[2]);
AddUv(vs[2]);
}
uvArray.push((p.z - 1) * 1e-3, p.x * 1e-3);
}
if (this.wallType === DirectionType.Outer)
{
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[1]);
AddUv(vs[1]);
AddVertice(vs[2]);
AddUv(vs[2]);
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[2]);
AddUv(vs[2]);
AddVertice(vs[3]);
AddUv(vs[3]);
}
else
{
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[2]);
AddUv(vs[2]);
AddVertice(vs[1]);
AddUv(vs[1]);
AddVertice(vs[0]);
AddUv(vs[0]);
AddVertice(vs[3]);
AddUv(vs[3]);
AddVertice(vs[2]);
AddUv(vs[2]);
}
}
}
}
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)

@ -5,33 +5,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<script>
if (location.hostname !== "localhost")
fetch("ver.json").then(res => {
if (!res.ok) return;
res.json().then(v => {
if (res.status)
if (v)
{
let oldVer = sessionStorage.getItem("ver");
sessionStorage.setItem("ver", v);
if (oldVer && oldVer != v)
{
document.body.style.cssText = `
text-align: center;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
flex-direction: column;
`;
document.body.textContent = "发现新版本,升级中!";
location.reload();
}
}
});
});
</script>
<script></script>
<title>WebCAD</title>
<meta itemprop="description" content="云端CAD,在线衣柜设计" />
</head>

Loading…
Cancel
Save