From 65efa29eff2c50cb2c5bb3663cf8e735f1cf741d Mon Sep 17 00:00:00 2001 From: ChenX Date: Tue, 18 Feb 2020 17:12:27 +0800 Subject: [PATCH] =?UTF-8?q?!743=20=E5=BF=AB=E9=80=9F=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E6=8B=89=E4=BC=B8=E5=AE=9E=E4=BD=93=E7=BD=91=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/EdgeGeometry.test.ts.snap | 4 +- src/Add-on/testEntity/test.ts | 180 +++++++++++++++++- src/DatabaseServices/CADObject.ts | 4 + src/DatabaseServices/Entity/Entity.ts | 5 + src/DatabaseServices/Entity/Extrude.ts | 99 ++++++---- src/Geometry/ExtrudeEdgeGeometry.ts | 23 ++- src/csg/core/CAG.ts | 35 +++- src/csg/core/math/Side.ts | 14 ++ 8 files changed, 305 insertions(+), 59 deletions(-) diff --git a/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap b/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap index 0e0be51d2..abdd62a41 100644 --- a/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap +++ b/__test__/Geometry/__snapshots__/EdgeGeometry.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`EdgeGeometry生成 1`] = `432`; +exports[`EdgeGeometry生成 1`] = `114`; exports[`EdgeGeometry生成 2`] = `858`; -exports[`EdgeGeometry生成 3`] = `146`; +exports[`EdgeGeometry生成 3`] = `60`; exports[`EdgeGeometry生成2 1`] = `110`; diff --git a/src/Add-on/testEntity/test.ts b/src/Add-on/testEntity/test.ts index 6d50864c1..7d66a77fe 100644 --- a/src/Add-on/testEntity/test.ts +++ b/src/Add-on/testEntity/test.ts @@ -1,26 +1,188 @@ +import { BufferGeometry, Float32BufferAttribute, Matrix4, Mesh, Shape, ShapeUtils, Vector2 } from "three"; import { app } from "../../ApplicationServices/Application"; -import { TemplateVisualSpace } from "../../DatabaseServices/Template/ProgramTempate/TemplateVisualSpace"; +import { Contour } from "../../DatabaseServices/Contour"; +import { Board } from "../../DatabaseServices/Entity/Board"; +import { Circle } from "../../DatabaseServices/Entity/Circle"; +import { Curve } from "../../DatabaseServices/Entity/Curve"; +import { Polyline } from "../../DatabaseServices/Entity/Polyline"; import { Command } from "../../Editor/CommandMachine"; +import { PromptStatus } from "../../Editor/PromptResult"; +import { equaln } from "../../Geometry/GeUtils"; import { HotCMD } from "../../Hot/HotCommand"; -import { TemplateSplitType } from "../../DatabaseServices/Template/TemplateType"; -import { SelectTempate } from "../../DatabaseServices/Template/TemplateTest"; -import { Entity } from "../../DatabaseServices/Entity/Entity"; +import { TestDraw } from "../test/TestUtil"; @HotCMD export class Test implements Command { async exec() { + let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Board] } }); + if (enRes.Status !== PromptStatus.OK) return; + let br = enRes.Entity as Board; - let t = await SelectTempate(); - if (!t) return; + let ocsInv = br.OCSInv; + let alMatrix4 = new Matrix4(); + let frontHoles: Shape[] = []; + let backHoles: Shape[] = []; - let objs = t.Objects.map(t => t.Object).filter(o => o !== undefined && !o.IsErase) as Entity[]; + let frontCurves: Curve[] = []; + let backCurves: Curve[] = []; - for (let o of objs) + let frontHoleCurves: Curve[] = []; + let backHoleCurves: Curve[] = []; + + for (let g of br.Grooves) + { + let back = false; + let front = false; + if (equaln(g.Thickness, br.Thickness)) + { + back = true; + front = true; + } + else + { + if (equaln(g.Position.applyMatrix4(ocsInv).z, 0)) + back = true; + else + front = true; + } + + alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone); + let gContour = g.ContourCurve.Clone(); + gContour.ApplyMatrix(alMatrix4); + + if (gContour instanceof Polyline) + gContour.UpdateMatrixTo(br.ContourCurve.OCS); + + let sp: Shape; + if (gContour instanceof Circle) + { + sp = new Shape(); + let cen = gContour.Center.applyMatrix4(ocsInv); + sp.ellipse(cen.x, cen.y, gContour.Radius, gContour.Radius, 0, 2 * Math.PI, false, 0); + } + else + sp = gContour.Shape; + + gContour.Z0(); + gContour.TempData = g.Thickness; + let holeCurves: Curve[] = []; + for (let gg of g.Grooves) + { + let c = gg.ContourCurve; + c.ApplyMatrix(alMatrix4).Z0(); + c.TempData = g.Thickness; + holeCurves.push(c); + } + if (back) + { + backHoles.push(sp); + backCurves.push(gContour); + backHoleCurves.push(...holeCurves); + } + if (front) + { + frontHoles.push(sp); + frontCurves.push(gContour); + frontHoleCurves.push(...holeCurves); + } + } + + let contourShape = br.ContourCurve.Shape; + let verticesArray: number[] = []; + + //draw front + contourShape.holes = frontHoles; + DrawShapeFaces(contourShape, verticesArray, br); + + //front 孤岛 + let frontCurveContours = frontCurves.map(c => Contour.CreateContour([c])); + DrawIslandFaces(frontHoleCurves, frontCurveContours, verticesArray, br); + + //draw back + contourShape.holes = backHoles; + DrawShapeFaces(contourShape, verticesArray, br, false); + + let backCurveContours = backCurves.map(c => Contour.CreateContour([c])); + DrawIslandFaces(backHoleCurves, backCurveContours, verticesArray, br, false); + + //绘制内部造型 + //绘制边缘 + + + //geo + let geo = new BufferGeometry(); + geo.setAttribute('position', new Float32BufferAttribute(verticesArray, 3)); + + TestDraw(new Mesh(geo)); + } +} +function DrawIslandFaces(HoleCurves: Curve[], CurveContours: Contour[], verticesArray: number[], br: Board, front = true) +{ + for (let c of HoleCurves) + { + let contours = [Contour.CreateContour([c])]; + for (let hole of CurveContours) + { + if (!equaln(c.TempData as number, hole.Curve.TempData as number)) + { + let newcs: Contour[] = []; + for (let con of contours) + newcs.push(...con.SubstactBoolOperation(hole)); + contours = newcs; + } + } + for (let con of contours) + { + DrawShapeFaces(con.Curve.Shape, verticesArray, br); + } + } +} + +function DrawShapeFaces(contourShape: Shape, verticesArray: number[], br: Board, front = true) +{ + let shapePoints = contourShape.extractPoints(6); + let vertices = shapePoints.shape; + let holes = shapePoints.holes; + let reverse = !ShapeUtils.isClockWise(vertices); + if (reverse) + { + vertices = vertices.reverse(); + for (let h = 0, hl = holes.length; h < hl; h++) { - o.ApplyMatrix(o.SpaceOCSInv); + let ahole = holes[h]; + if (ShapeUtils.isClockWise(ahole)) + holes[h] = ahole.reverse(); } } + let faces = ShapeUtils.triangulateShape(vertices, holes); + for (let h of holes) + vertices.push(...h); + for (let f of faces) + { + if (front) + { + newFunction_1(vertices[f[0]]); + newFunction_1(vertices[f[1]]); + newFunction_1(vertices[f[2]]); + } + else + { + newFunction_1(vertices[f[0]]); + newFunction_1(vertices[f[2]]); + newFunction_1(vertices[f[1]]); + } + } + + function newFunction_1(v: Vector2) + { + verticesArray.push(v.x); + verticesArray.push(v.y); + if (front) + verticesArray.push(br.Thickness); + else + verticesArray.push(0); + } } diff --git a/src/DatabaseServices/CADObject.ts b/src/DatabaseServices/CADObject.ts index f6e1f41a1..e69ab7dc1 100644 --- a/src/DatabaseServices/CADObject.ts +++ b/src/DatabaseServices/CADObject.ts @@ -11,6 +11,10 @@ import { ObjectId } from './ObjectId'; export abstract class CADObject { protected _Owner: ObjectId; + /** + * 用于储存临时数据 + */ + public TempData: any; set Owner(owner: ObjectId) { this._Owner = owner; diff --git a/src/DatabaseServices/Entity/Entity.ts b/src/DatabaseServices/Entity/Entity.ts index 8c9725bd9..56a62084a 100644 --- a/src/DatabaseServices/Entity/Entity.ts +++ b/src/DatabaseServices/Entity/Entity.ts @@ -131,6 +131,11 @@ export class Entity extends CADObject return this._Matrix.clone(); } + get OCSNoClone() + { + return this._Matrix; + } + //直接设置实体的矩阵,谨慎使用该函数,没有更新实体. set OCS(mat4: Matrix4) { diff --git a/src/DatabaseServices/Entity/Extrude.ts b/src/DatabaseServices/Entity/Extrude.ts index b817dcc53..6bd3958ee 100644 --- a/src/DatabaseServices/Entity/Extrude.ts +++ b/src/DatabaseServices/Entity/Extrude.ts @@ -1,4 +1,4 @@ -import { BoxGeometry, BufferGeometry, ExtrudeGeometry, ExtrudeGeometryOptions, Geometry, Line, LineSegments, Matrix3, Matrix4, Mesh, Object3D, Vector3 } from "three"; +import { BoxGeometry, BufferGeometry, ExtrudeGeometry, ExtrudeGeometryOptions, Geometry, Line, LineSegments, Matrix3, Matrix4, Mesh, Object3D, Vector3, Path } from "three"; import { arrayClone, arrayLast, arrayRemoveIf, arraySortByNumber, arraySum } from "../../Common/ArrayExt"; import { ColorMaterial } from "../../Common/ColorPalette"; import { equalCurve } from "../../Common/CurveUtils"; @@ -10,6 +10,7 @@ import { CSG2Geometry, Geometry2CSG } from "../../csg/core/Geometry2CSG"; import { ObjectSnapMode } from "../../Editor/ObjectSnapMode"; import { boardUVGenerator } from "../../Geometry/BoardUVGenerator"; import { Box3Ext } from "../../Geometry/Box"; +import { BSPGroupParse } from "../../Geometry/BSPGroupParse"; import { FastWireframe } from "../../Geometry/CreateWireframe"; import { EdgesGeometry } from "../../Geometry/EdgeGeometry"; import { GenerateExtrudeEdgeGeometry } from "../../Geometry/ExtrudeEdgeGeometry"; @@ -28,7 +29,6 @@ import { DragPointType } from "./DragPointType"; import { Entity } from "./Entity"; import { Polyline } from "./Polyline"; import { Region } from "./Region"; -import { BSPGroupParse } from "../../Geometry/BSPGroupParse"; /** 最大的槽个数,当大于最大个数时,实体不会绘制槽,并且不会校验槽的正确性 */ const MaxGrooveCount = 15; @@ -753,15 +753,12 @@ export class ExtrudeSolid extends Entity * 当调用Draw时,可以生成bsp信息 */ private csg: CSG; - private get CSG() + get CSG() { if (this.csg) return this.csg; - //实体内保证了就算本实体不绘制也能正确的更新Geo - this.MeshGeometry; - if (!this.csg) - this.csg = Geometry2CSG(this.MeshGeometry as Geometry); + this.csg = Geometry2CSG(this.MeshGeometry); return this.csg; } @@ -1231,9 +1228,33 @@ export class ExtrudeSolid extends Entity if (this._EdgeGeometry) return this._EdgeGeometry; - if (this.grooves.length === 0) - return GenerateExtrudeEdgeGeometry(this.contourCurve.Shape.getPoints(6).map(AsVector3), this.thickness).applyMatrix4(this.contourCurve.OCS); - this.MeshGeometry; + if (this.grooves.every(g => equaln(g.thickness, this.thickness))) + { + let pts = [this.ContourCurve.Shape.getPoints(6).map(AsVector3)]; + let ocsInv = this.OCSInv; + let alMatrix4 = new Matrix4(); + for (let g of this.grooves) + { + alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone); + let gContour = g.ContourCurve.Clone(); + gContour.ApplyMatrix(alMatrix4); + + if (gContour instanceof Polyline) + gContour.UpdateMatrixTo(this.contourCurve.OCS); + + if (gContour instanceof Circle) + { + let sp = new Path(); + let cen = gContour.Center.applyMatrix4(this.contourCurve.OCSInv); + sp.ellipse(cen.x, cen.y, gContour.Radius, gContour.Radius, 0, 2 * Math.PI, false, 0); + pts.push(sp.getPoints(6).map(AsVector3)); + } + else + pts.push(gContour.Shape.getPoints(6).map(AsVector3)); + + } + return GenerateExtrudeEdgeGeometry(pts, this.thickness).applyMatrix4(this.contourCurve.OCSNoClone); + } this._EdgeGeometry = new EdgesGeometry().FromCSG(this.CSG); return this._EdgeGeometry; } @@ -1241,39 +1262,47 @@ export class ExtrudeSolid extends Entity private GeneralMeshGeometry() { this.csg = undefined; + let grooves = this.Grooves; + let gs: ExtrudeSolid[] = [];//不是全深槽 - let geo: Geometry; - if (this.isRect && false) - { - geo = FastMeshGeometry(this.width, this.height, this.thickness); - } - else + let contour = this.ContourCurve; + let holes: Contour[] = []; + + let ocsInv = this.OCSInv; + let alMatrix4 = new Matrix4(); + for (let g of grooves) { - let extrudeSettings: ExtrudeGeometryOptions = { - steps: 1, - bevelEnabled: false, - depth: this.thickness, - UVGenerator: this.UCGenerator, - }; - geo = new ExtrudeGeometry(this.ContourCurve.Shape, extrudeSettings); - geo.applyMatrix4(this.contourCurve.OCS); + if (equaln(g.Thickness, this.Thickness)) + { + alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone); + let gContour = g.ContourCurve.Clone(); + gContour.ApplyMatrix(alMatrix4); + holes.push(Contour.CreateContour(gContour)); + } + else if (g.Thickness > 0) + gs.push(g); } - this.csg = Geometry2CSG(geo); - if (this.grooves.length === 0 || this.grooves.length > MaxGrooveCount) - { - ScaleUV(geo); + let shape = new Shape(Contour.CreateContour(contour), holes); + + let extrudeSettings: ExtrudeGeometryOptions = { + steps: 1, + bevelEnabled: false, + depth: this.Thickness, + UVGenerator: this.UCGenerator, + }; + let geo = new ExtrudeGeometry(shape.Shape, extrudeSettings); + geo.applyMatrix4(contour.OCSNoClone); + ScaleUV(geo); + + if (gs.length === 0 || gs.length > MaxGrooveCount) return geo; - } - for (let g of this.grooves) - { - if (g.thickness > 0) - this.csg = this.csg.subtract(g.CSG.transform1(this.OCSInv.multiply(g.OCS))); - } + this.csg = Geometry2CSG(geo); + for (let g of gs) + this.csg = this.csg.subtract(g.CSG.transform1(this.OCSInv.multiply(g.OCSNoClone))); let bgeo = CSG2Geometry(this.csg); - ScaleUV(bgeo); return bgeo; } diff --git a/src/Geometry/ExtrudeEdgeGeometry.ts b/src/Geometry/ExtrudeEdgeGeometry.ts index bedbe5ff2..7220730b6 100644 --- a/src/Geometry/ExtrudeEdgeGeometry.ts +++ b/src/Geometry/ExtrudeEdgeGeometry.ts @@ -3,28 +3,31 @@ import { arrayLast } from "../Common/ArrayExt"; import { equalv3 } from "./GeUtils"; import { FixIndex } from "../Common/Utils"; -export function GenerateExtrudeEdgeGeometry(contourPoints: Vector3[], height: number) +export function GenerateExtrudeEdgeGeometry(contourPoints: Vector3[][], height: number) +{ + let pts: Vector3[] = []; + for (let cs of contourPoints) + pts.push(...GenerateExtrudeEdgeGeometryPoints(cs, height)); + let geo = new BufferGeometry().setFromPoints(pts); + return geo; +} + +function GenerateExtrudeEdgeGeometryPoints(contourPoints: Vector3[], height: number) { if (equalv3(contourPoints[0], arrayLast(contourPoints))) contourPoints.pop(); - let pts: Vector3[] = []; let hpts = contourPoints.map(p => new Vector3(p.x, p.y, height)); let count = contourPoints.length; for (let i = 0; i < count; i++) { - pts.push(contourPoints[i], contourPoints[FixIndex(i + 1, count)], - hpts[i], hpts[FixIndex(i + 1, count)], - contourPoints[i], hpts[i] - ); + pts.push(contourPoints[i], contourPoints[FixIndex(i + 1, count)], hpts[i], hpts[FixIndex(i + 1, count)], contourPoints[i], hpts[i]); } - - let geo = new BufferGeometry().setFromPoints(pts); - return geo; + return pts; } export function GenerateBoxEdgeGeometry(length: number, width: number, height: number) { let pts = [new Vector3(), new Vector3(length), new Vector3(length, width), new Vector3(0, width)]; - return GenerateExtrudeEdgeGeometry(pts, height); + return GenerateExtrudeEdgeGeometry([pts], height); } diff --git a/src/csg/core/CAG.ts b/src/csg/core/CAG.ts index b5738743c..cf8c1ccb4 100644 --- a/src/csg/core/CAG.ts +++ b/src/csg/core/CAG.ts @@ -1,9 +1,13 @@ -import { Matrix4 } from "three"; +import { Matrix4, Vector3 } from "three"; +import { arrayLast } from "../../Common/ArrayExt"; +import { FixIndex } from "../../Common/Utils"; +import { equalv3 } from "../../Geometry/GeUtils"; import { CSG } from "./CSG"; import { Polygon } from "./math/Polygon3"; import { Side } from "./math/Side"; import { Vector2D } from "./math/Vector2"; import { Vector3D } from "./math/Vector3"; +import { Vertex2D } from "./math/Vertex2"; import { Vertex3D } from "./math/Vertex3"; import { Tree } from "./trees"; import { canonicalizeCAG } from "./utils/canonicalize"; @@ -20,6 +24,25 @@ export class CAG constructor(public sides: Side[] = []) { } + + fromPoints(pts: Vector3[]): this + { + this.sides.length = 0; + if (equalv3(pts[0], arrayLast(pts))) + pts.pop(); + + for (let i = 0; i < pts.length; i++) + { + let p1 = pts[i]; + let p2 = pts[FixIndex(i + 1, pts)]; + + let side = new Side(new Vertex2D(new Vector2D(p1.x, p1.y)), new Vertex2D(new Vector2D(p2.x, p2.y))); + this.sides.push(side); + } + + return this; + } + flipped() { let newsides = this.sides.map(side => side.flipped()); @@ -72,7 +95,7 @@ export class CAG return new CSG(polygons); } - private toPolygons(bottom = false) + toPolygons(bottom = false): Polygon[] { let bounds = this.getBounds(); bounds[0].sub(new Vector2D(1, 1)); @@ -95,6 +118,12 @@ export class CAG b.invert(); a.clipTo(b); - return a.allPolygons(); + let polys = a.allPolygons(); + for (let poly of polys) + { + for (let p of poly.vertices) + p.uv = new Vector2D(p.pos.x, p.pos.y); + } + return polys; } } diff --git a/src/csg/core/math/Side.ts b/src/csg/core/math/Side.ts index 6c8366c38..c8362d913 100644 --- a/src/csg/core/math/Side.ts +++ b/src/csg/core/math/Side.ts @@ -15,6 +15,20 @@ export class Side new Vertex3D(this.vertex1.pos.toVector3D(z1)), new Vertex3D(this.vertex0.pos.toVector3D(z1)) ]; + if (this.vertex0.pos.y - this.vertex0.pos.y < 0.01) + { + vertices[0].uv = new Vector2D(z0 - 1, this.vertex0.pos.x); + vertices[1].uv = new Vector2D(z0 - 1, this.vertex1.pos.x); + vertices[2].uv = new Vector2D(z1 - 1, this.vertex0.pos.x); + vertices[3].uv = new Vector2D(z1 - 1, this.vertex1.pos.x); + } + else + { + vertices[0].uv = new Vector2D(z0 - 1, this.vertex0.pos.y); + vertices[1].uv = new Vector2D(z0 - 1, this.vertex1.pos.y); + vertices[2].uv = new Vector2D(z1 - 1, this.vertex0.pos.y); + vertices[3].uv = new Vector2D(z1 - 1, this.vertex1.pos.y); + } return new Polygon(vertices); }