diff --git a/packages/chili-core/src/visual/highlighter.ts b/packages/chili-core/src/visual/highlighter.ts index eb10fb3a..6aff5f5c 100644 --- a/packages/chili-core/src/visual/highlighter.ts +++ b/packages/chili-core/src/visual/highlighter.ts @@ -1,6 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license. -import { ShapeType } from "../shape"; +import { ShapeMeshData, ShapeType } from "../shape"; import { IVisualGeometry, VisualState } from "./visualShape"; export interface IHighlighter { @@ -9,4 +9,6 @@ export interface IHighlighter { resetState(shape: IVisualGeometry): void; addState(shape: IVisualGeometry, state: VisualState, type: ShapeType, ...index: number[]): void; removeState(shape: IVisualGeometry, state: VisualState, type: ShapeType, ...index: number[]): void; + highliteMesh(...datas: ShapeMeshData[]): number; + removeMesh(id: number): void; } diff --git a/packages/chili-three/src/threeGeometryFactory.ts b/packages/chili-three/src/threeGeometryFactory.ts new file mode 100644 index 00000000..ce14480a --- /dev/null +++ b/packages/chili-three/src/threeGeometryFactory.ts @@ -0,0 +1,60 @@ +// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license. + +import { + AlwaysDepth, + BufferGeometry, + DoubleSide, + Float32BufferAttribute, + LineBasicMaterial, + LineDashedMaterial, + LineSegments, + Mesh, + MeshLambertMaterial, + Points, + PointsMaterial, +} from "three"; +import { EdgeMeshData, FaceMeshData, LineType, VertexMeshData } from "chili-core"; + +export class ThreeGeometryFactory { + static createVertexGeometry(data: VertexMeshData) { + let buff = new BufferGeometry(); + buff.setAttribute("position", new Float32BufferAttribute(data.positions, 3)); + let color = data.color as number; + let material = new PointsMaterial({ + size: data.size, + sizeAttenuation: false, + color, + }); + material.depthFunc = AlwaysDepth; + return new Points(buff, material); + } + + static createFaceGeometry(data: FaceMeshData) { + let buff = new BufferGeometry(); + buff.setAttribute("position", new Float32BufferAttribute(data.positions, 3)); + buff.setAttribute("normal", new Float32BufferAttribute(data.normals, 3)); + buff.setAttribute("uv", new Float32BufferAttribute(data.uvs, 2)); + buff.setIndex(data.indices); + buff.computeBoundingBox(); + let material = new MeshLambertMaterial({ side: DoubleSide }); + if (typeof data.color === "number") { + material.color.set(data.color); + } else { + material.vertexColors = true; + buff.setAttribute("color", new Float32BufferAttribute(data.color, 3)); + } + + return new Mesh(buff, material); + } + + static createEdgeGeometry(data: EdgeMeshData) { + let buff = new BufferGeometry(); + buff.setAttribute("position", new Float32BufferAttribute(data.positions, 3)); + let color = data.color as number; + let material: LineBasicMaterial = + data.lineType === LineType.Dash + ? new LineDashedMaterial({ color, dashSize: 6, gapSize: 6 }) + : new LineBasicMaterial({ color }); + return new LineSegments(buff, material).computeLineDistances(); + } +} diff --git a/packages/chili-three/src/threeHighlighter.ts b/packages/chili-three/src/threeHighlighter.ts index b9d8eae9..b5cdf323 100644 --- a/packages/chili-three/src/threeHighlighter.ts +++ b/packages/chili-three/src/threeHighlighter.ts @@ -1,18 +1,29 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license. -import { IHighlighter, IVisualGeometry, ShapeType, VisualConfig, VisualState } from "chili-core"; +import { + IDisposable, + IHighlighter, + IVisualGeometry, + ShapeMeshData, + ShapeType, + VisualConfig, + VisualState, +} from "chili-core"; import { DoubleSide, + Group, LineBasicMaterial, LineSegments, Mesh, MeshBasicMaterial, MeshLambertMaterial, Object3D, + Points, Scene, } from "three"; import { ThreeGeometry } from "./threeGeometry"; import { ThreeHelper } from "./threeHelper"; +import { ThreeGeometryFactory } from "./threeGeometryFactory"; const hilightEdgeMaterial = new LineBasicMaterial({ color: ThreeHelper.fromColor(VisualConfig.highlightEdgeColor), @@ -211,9 +222,14 @@ export class GeometryState { export class ThreeHighlighter implements IHighlighter { private readonly _stateMap = new Map(); + readonly tempShapes: Group = new Group(); readonly sceneHorver: Scene = new Scene(); readonly sceneSelected: Scene = new Scene(); + constructor() { + this.sceneHorver.add(this.tempShapes); + } + clear(): void { this._stateMap.forEach((v, k) => { this.resetState(k); @@ -253,4 +269,35 @@ export class ThreeHighlighter implements IHighlighter { } return geometryState; } + + highliteMesh(...datas: ShapeMeshData[]): number { + let group = new Group(); + datas.forEach((data) => { + if (ShapeMeshData.isVertex(data)) { + group.add(ThreeGeometryFactory.createVertexGeometry(data)); + } else if (ShapeMeshData.isEdge(data)) { + group.add(ThreeGeometryFactory.createEdgeGeometry(data)); + } else if (ShapeMeshData.isFace(data)) { + group.add(ThreeGeometryFactory.createFaceGeometry(data)); + } + }); + this.tempShapes.add(group); + return group.id; + } + + removeMesh(id: number) { + let shape = this.tempShapes.getObjectById(id); + if (shape === undefined) return; + shape.children.forEach((x) => { + if (x instanceof Mesh || x instanceof LineSegments || x instanceof Points) { + x.geometry.dispose(); + x.material.dispose(); + } + if (IDisposable.isDisposable(x)) { + x.dispose(); + } + }); + shape.children.length = 0; + this.tempShapes.remove(shape); + } } diff --git a/packages/chili-three/src/threeVisualContext.ts b/packages/chili-three/src/threeVisualContext.ts index 12ea64fa..c28d372a 100644 --- a/packages/chili-three/src/threeVisualContext.ts +++ b/packages/chili-three/src/threeVisualContext.ts @@ -3,8 +3,6 @@ import { CollectionAction, CollectionChangedArgs, - EdgeMeshData, - FaceMeshData, IDisposable, IModel, INode, @@ -13,37 +11,29 @@ import { IVisualContext, IVisualGeometry, IVisualObject, - LineType, Material, MathUtils, NodeAction, NodeRecord, ShapeMeshData, ShapeType, - VertexMeshData, XYZ, } from "chili-core"; import { - AlwaysDepth, Box3, - BufferGeometry, DoubleSide, - Float32BufferAttribute, Group, - LineBasicMaterial, - LineDashedMaterial, LineSegments, Mesh, - MeshLambertMaterial, Object3D, Points, - PointsMaterial, RepeatWrapping, Scene, TextureLoader, MeshLambertMaterial as ThreeMaterial, } from "three"; import { ThreeGeometry } from "./threeGeometry"; +import { ThreeGeometryFactory } from "./threeGeometryFactory"; import { ThreeHelper } from "./threeHelper"; export class ThreeVisualContext implements IVisualContext { @@ -236,59 +226,17 @@ export class ThreeVisualContext implements IVisualContext { let group = new Group(); datas.forEach((data) => { if (ShapeMeshData.isVertex(data)) { - group.add(this.createVertexGeometry(data)); + group.add(ThreeGeometryFactory.createVertexGeometry(data)); } else if (ShapeMeshData.isEdge(data)) { - group.add(this.createEdgeGeometry(data)); + group.add(ThreeGeometryFactory.createEdgeGeometry(data)); } else if (ShapeMeshData.isFace(data)) { - group.add(this.createFaceGeometry(data)); + group.add(ThreeGeometryFactory.createFaceGeometry(data)); } }); this.tempShapes.add(group); return group.id; } - private createFaceGeometry(data: FaceMeshData) { - let buff = new BufferGeometry(); - buff.setAttribute("position", new Float32BufferAttribute(data.positions, 3)); - buff.setAttribute("normal", new Float32BufferAttribute(data.normals, 3)); - buff.setAttribute("uv", new Float32BufferAttribute(data.uvs, 2)); - buff.setIndex(data.indices); - buff.computeBoundingBox(); - let material = new MeshLambertMaterial({ side: DoubleSide }); - if (typeof data.color === "number") { - material.color.set(data.color); - } else { - material.vertexColors = true; - buff.setAttribute("color", new Float32BufferAttribute(data.color, 3)); - } - - return new Mesh(buff, material); - } - - private createEdgeGeometry(data: EdgeMeshData) { - let buff = new BufferGeometry(); - buff.setAttribute("position", new Float32BufferAttribute(data.positions, 3)); - let color = data.color as number; - let material: LineBasicMaterial = - data.lineType === LineType.Dash - ? new LineDashedMaterial({ color, dashSize: 6, gapSize: 6 }) - : new LineBasicMaterial({ color }); - return new LineSegments(buff, material).computeLineDistances(); - } - - private createVertexGeometry(data: VertexMeshData) { - let buff = new BufferGeometry(); - buff.setAttribute("position", new Float32BufferAttribute(data.positions, 3)); - let color = data.color as number; - let material = new PointsMaterial({ - size: data.size, - sizeAttenuation: false, - color, - }); - material.depthFunc = AlwaysDepth; - return new Points(buff, material); - } - removeMesh(id: number) { let shape = this.tempShapes.getObjectById(id); if (shape === undefined) return; diff --git a/packages/chili/src/commands/modify/trim.ts b/packages/chili/src/commands/modify/trim.ts index fddf440e..6b428704 100644 --- a/packages/chili/src/commands/modify/trim.ts +++ b/packages/chili/src/commands/modify/trim.ts @@ -114,7 +114,7 @@ export class PickTrimEdgeEventHandler extends SelectionHandler { let segments = findSegments(curve, edge, otherEdges, detecteds); let mesh = edge.trim(segments.deleteSegment.start, segments.deleteSegment.end).mesh.edges!; mesh.color = 0xff0000; - this.highlightedEdge = view.document.visual.context.displayMesh(mesh); + this.highlightedEdge = view.document.visual.highlighter.highliteMesh(mesh); this.highlight = { edge: detecteds[0], segments, @@ -126,7 +126,7 @@ export class PickTrimEdgeEventHandler extends SelectionHandler { protected override cleanHighlights(): void { if (this.highlightedEdge !== undefined) { - this.document.visual.context.removeMesh(this.highlightedEdge); + this.document.visual.highlighter.removeMesh(this.highlightedEdge); this.highlightedEdge = undefined; this.highlight = undefined; this.document.application.activeView?.update();