diff --git a/src/Add-on/interfere.ts b/src/Add-on/interfere.ts new file mode 100644 index 000000000..16e30b3a2 --- /dev/null +++ b/src/Add-on/interfere.ts @@ -0,0 +1,132 @@ + +import { Intent } from '@blueprintjs/core'; +import { Mesh, Vector3 } from 'three'; +import { app } from '../ApplicationServices/Application'; +import { DisposeThreeObj } from '../Common/Dispose'; +import { CylinderHole } from '../DatabaseServices/3DSolid/CylinderHole'; +import { Entity } from '../DatabaseServices/Entity/Entity'; +import { ExtrudeSolid } from '../DatabaseServices/Entity/Extrude'; +import { PromptStatus } from '../Editor/PromptResult'; +import { userConfig } from '../Editor/UserConfig'; +import { RenderType } from '../GraphicsSystem/RenderType'; +import { InterfereModal } from '../UI/Components/Modal/InterfereModal'; +import { ModalPosition } from '../UI/Components/Modal/ModalsManage'; +import { ColorMaterial } from './../Common/ColorPalette'; +import { CSG } from './../csg/core/CSG'; +import { CSG2Geometry, Geometry2CSG } from './../csg/core/Geometry2CSG'; +import { FastDrillingMeshGeometry } from './../DatabaseServices/3DSolid/CylinderHole'; +import { ExtrudeHole } from './../DatabaseServices/3DSolid/ExtrudeHole'; +import { SweepSolid } from './../DatabaseServices/3DSolid/SweepSolid'; +import { Command } from './../Editor/CommandMachine'; +import { AppToaster } from './../UI/Components/Toaster'; + +//| CylinderHole | ExtrudeHole +export type Solid3D = ExtrudeSolid | SweepSolid | ExtrudeHole; + +export class Interfere implements Command +{ + async exec() + { + const Filter = { + filterTypes: [ExtrudeHole, ExtrudeSolid, SweepSolid] + }; + + let enRes = await app.Editor.GetSelection({ + Msg: "选择检查干涉的对象", + Filter + }); + + if (enRes.Status === PromptStatus.Cancel) return; + + let ens = enRes.SelectSet.SelectEntityList as Solid3D[]; + let set1 = new Set(); + let objMap: Map = new Map(); + const csgCache: WeakMap = new WeakMap(); + + for (let i = 0; i < ens.length; i++) + { + let e1 = ens[i]; + + let c1: CSG; + if (csgCache.has(e1)) + c1 = csgCache.get(e1); + else + c1 = this.GetCSG(e1); + + let obb1 = e1.OBB; + + for (let j = i + 1; j < ens.length; j++) + { + let e2 = ens[j]; + if (!obb1.intersectsOBB(e2.OBB)) + continue; + + let c2: CSG; + if (csgCache.has(e2)) + c2 = csgCache.get(e2); + else + { + c2 = this.GetCSG(e2); + csgCache.set(e2, c2); + } + + if (!c2) + console.error("实体CSG出错"); + + let c = c1.intersect(c2.transform1(e1.OCSInv.multiply(e2.OCS))); + + if (c.polygons.length > 0) + { + set1.add(e1); + set1.add(e2); + let g = CSG2Geometry(c).applyMatrix4(e1.OCS); + g.computeBoundingBox(); + if (g.boundingBox.getSize(new Vector3).toArray().every(n => n > 1 - 1e-3)) + { + let m = new Mesh(g, ColorMaterial.GetBasicMaterial(1).clone()); + objMap.set(m, [e1, e2]); + } + } + } + } + if (objMap.size === 0) + { + AppToaster.show({ + message: "未找到干涉对象", + timeout: 2000, + intent: Intent.SUCCESS, + }); + return; + } + + for (let [o,] of objMap) + { + app.Viewer.Scene.add(o); + } + let oldType = userConfig.RenderType; + userConfig.RenderType = RenderType.Wireframe; + + app.Editor.ModalManage.RenderModeless(InterfereModal, ModalPosition.Center, { count: set1.size, data: objMap }); + + await app.Editor.ModalManage.Wait(); + + for (let [o,] of objMap) + { + DisposeThreeObj(o); + app.Viewer.Scene.remove(o); + } + + userConfig.RenderType = oldType; + } + private GetCSG(en: Solid3D) + { + if (en instanceof ExtrudeSolid) + { + return en.CSG; + } + else + { + return Geometry2CSG(en.MeshGeometry); + } + } +} diff --git a/src/DatabaseServices/3DSolid/CylinderHole.ts b/src/DatabaseServices/3DSolid/CylinderHole.ts index b2328bbec..99a47ed6c 100644 --- a/src/DatabaseServices/3DSolid/CylinderHole.ts +++ b/src/DatabaseServices/3DSolid/CylinderHole.ts @@ -94,7 +94,7 @@ export class CylinderHole extends Hole return box.applyMatrix4(this.OCS); } private _MeshGeometry: CylinderBufferGeometry; - private get MeshGeometry() + get MeshGeometry() { if (this._MeshGeometry) return this._MeshGeometry; diff --git a/src/DatabaseServices/3DSolid/ExtrudeHole.ts b/src/DatabaseServices/3DSolid/ExtrudeHole.ts index 2a9ad74e7..c9a817ce8 100644 --- a/src/DatabaseServices/3DSolid/ExtrudeHole.ts +++ b/src/DatabaseServices/3DSolid/ExtrudeHole.ts @@ -17,6 +17,7 @@ import { ExtureContourCurve } from "../Entity/Extrude"; import { Polyline } from "../Entity/Polyline"; import { Shape } from "../Shape"; import { Hole } from "./Hole"; +import { OBB } from './../../Geometry/OBB/obb'; @Factory export class ExtrudeHole extends Hole @@ -154,7 +155,7 @@ export class ExtrudeHole extends Hole return this._EdgeGeometry; } private _MeshGeometry: BufferGeometry | Geometry; - private get MeshGeometry() + get MeshGeometry() { if (this._MeshGeometry) return this._MeshGeometry; @@ -347,6 +348,11 @@ export class ExtrudeHole extends Hole obj.add(...FastWireframe2(this)); } } + get OBB(): OBB + { + let size = this.ContourCurve.BoundingBox.getSize(new Vector3).setZ(this.Height); + return new OBB(this.OCS, size.multiplyScalar(0.5)); + } ReadFile(file: CADFiler) { super.ReadFile(file); diff --git a/src/DatabaseServices/3DSolid/SweepSolid.ts b/src/DatabaseServices/3DSolid/SweepSolid.ts index 23f3231c9..698d1d7d8 100644 --- a/src/DatabaseServices/3DSolid/SweepSolid.ts +++ b/src/DatabaseServices/3DSolid/SweepSolid.ts @@ -15,6 +15,7 @@ import { Entity } from "../Entity/Entity"; import { arrayLast } from "../../Common/ArrayExt"; import { Box3Ext } from "../../Geometry/Box"; import { ObjectSnapMode } from "../../Editor/ObjectSnapMode"; +import { OBB } from './../../Geometry/OBB/obb'; @Factory export class SweepSolid extends Entity @@ -118,7 +119,7 @@ export class SweepSolid extends Entity console.log("提供的轮廓没有和路径垂直"); } private _MeshGeometry: SweepGeometry; - private get MeshGeometry() + get MeshGeometry() { if (this._MeshGeometry) return this._MeshGeometry; @@ -193,6 +194,12 @@ export class SweepSolid extends Entity { return new Box3Ext().setFromPoints(this.GetStretchPoints()); } + get OBB(): OBB + { + let s = this.Contour.BoundingBox.getSize(new Vector3); + let size = this._PathCurve.BoundingBox.getSize(new Vector3).setZ(Math.max(s.x, s.y)); + return new OBB(this.OCS, size.multiplyScalar(0.5)); + } GetObjectSnapPoints( snapMode: ObjectSnapMode, pickPoint: Vector3, diff --git a/src/DatabaseServices/Entity/Extrude.ts b/src/DatabaseServices/Entity/Extrude.ts index 9b3157086..0d0d7dc17 100644 --- a/src/DatabaseServices/Entity/Extrude.ts +++ b/src/DatabaseServices/Entity/Extrude.ts @@ -1213,7 +1213,7 @@ export class ExtrudeSolid extends Entity } private _MeshGeometry: Geometry | BufferGeometry; - private get MeshGeometry() + get MeshGeometry() { if (this._MeshGeometry) return this._MeshGeometry; diff --git a/src/Editor/CommandRegister.ts b/src/Editor/CommandRegister.ts index 76a9d00a8..4fb060f90 100644 --- a/src/Editor/CommandRegister.ts +++ b/src/Editor/CommandRegister.ts @@ -157,6 +157,7 @@ import { Text2Curve } from "../Add-on/Text2Curve"; import { DrawVisualSpaceBox } from "../Add-on/Template/DrawVisualSpaceBox"; import { Align } from './../Add-on/Align'; import { BuyMaterial } from './../Add-on/BuyMaterial'; +import { Interfere } from './../Add-on/interfere'; export function registerCommand() { @@ -432,6 +433,7 @@ export function registerCommand() commandMachine.RegisterCommand("align", new Align()); commandMachine.RegisterCommand("buymaterial", new BuyMaterial()); + commandMachine.RegisterCommand("interfere", new Interfere()); RegistCustomCommand(); } diff --git a/src/UI/Components/Modal/InterfereModal.tsx b/src/UI/Components/Modal/InterfereModal.tsx new file mode 100644 index 000000000..324728679 --- /dev/null +++ b/src/UI/Components/Modal/InterfereModal.tsx @@ -0,0 +1,112 @@ +import React, { Component } from 'react'; +import { Classes, Button } from '@blueprintjs/core'; +import { app } from '../../../ApplicationServices/Application'; +import { Card } from '@blueprintjs/core'; +import { Mesh, MeshBasicMaterial, Vector3, Box3 } from 'three'; +import { Solid3D } from '../../../Add-on/interfere'; +import { Intent } from '@blueprintjs/core'; +import { observable } from 'mobx'; +import { observer } from 'mobx-react'; +import { ColorMaterial } from './../../../Common/ColorPalette'; +import { FixIndex } from './../../../Common/Utils'; +import { CommonModal } from './ModalContainer'; + +interface IInterfereProps +{ + count: number, + data: Map; +} + +@observer +export class InterfereModal extends Component { + @observable currentIndex = -1; + + render() + { + const { count, data } = this.props; + + return ( + + } + > + +
+
共{count}个干涉对象
+
+ 找到干涉点对 + {data.size} +
+
+
+
亮显
+
+
+
+ ); + } + private close = () => + { + app.Editor.ModalManage.Clear(); + app.Editor.ModalManage.EndCmd(); + app.Viewer.OutlinePass.selectedObjects = []; + }; + private restore = (os: Mesh[]) => + { + for (let o of os) + { + let mat = o.material as MeshBasicMaterial; + mat.color = ColorMaterial.GetColor(1); + } + app.Viewer.OutlinePass.selectedObjects = []; + }; + private next = () => + { + let os = [...this.props.data.keys()]; + this.restore(os); + this.currentIndex = FixIndex(this.currentIndex + 1, os.length); + this.update(os[this.currentIndex]); + }; + private previos = () => + { + let os = [...this.props.data.keys()]; + this.restore(os); + this.currentIndex = FixIndex(this.currentIndex - 1, os.length); + this.update(os[this.currentIndex]); + }; + private update = (o: Mesh) => + { + let mat = o.material as MeshBasicMaterial; + mat.color = ColorMaterial.GetColor(3); + let box = new Box3(); + app.Viewer.OutlinePass.selectedObjects = this.props.data.get(o).map(e => + { + box.union(e.BoundingBox); + return e.DrawObject; + }); + app.Viewer.CameraCtrl.ZoomExtensBox3(box); + app.Viewer.Zoom(1, box.getCenter(new Vector3)); + }; +} diff --git a/src/UI/Components/Modal/ModalContainer.tsx b/src/UI/Components/Modal/ModalContainer.tsx index 8fff3b073..606d22cd2 100644 --- a/src/UI/Components/Modal/ModalContainer.tsx +++ b/src/UI/Components/Modal/ModalContainer.tsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react' +import React, { Component } from 'react'; import { Icon, Button, Classes, IconName } from '@blueprintjs/core'; import { UserConfig } from '../Board/UserConfig'; import { IConfigStore } from '../../Store/BoardStore'; @@ -17,6 +17,8 @@ interface IModalProps footerChildren?: JSX.Element | (JSX.Element[]), type?: BoardModalType, bodyClass?: string; + bodyStyle?: React.CSSProperties; + footerStyle?: React.CSSProperties; containerEl?: (el) => void; } @@ -30,7 +32,7 @@ export class CommonModal extends Component{ icon={this.props.icon} close={this.props.close} /> - + { this.props.children } @@ -38,13 +40,14 @@ export class CommonModal extends Component{ { this.props.footerChildren } - ) + ); } } @@ -53,7 +56,7 @@ interface IModalContainer containerEl?: (el) => void; modalId?: string; className?: string; - children?: JSX.Element | JSX.Element[] + children?: JSX.Element | JSX.Element[]; } export class ModalContainer extends Component @@ -72,7 +75,7 @@ export class ModalContainer extends Component } - ) + ); } } @@ -102,26 +105,34 @@ export class ModalHeader extends Component onClick={this.props.close} /> - ) + ); } } -export class ModalBody extends Component<{ children?: JSX.Element | JSX.Element[], className?: string }> +interface IModalBodyProps +{ + bodyStyle?: React.CSSProperties; + children?: JSX.Element | JSX.Element[]; + className?: string; +} + +export class ModalBody extends Component { static defaultProps = { className: "", - } + }; render() { return (
{ this.props.children }
- ) + ); } } @@ -138,7 +149,7 @@ export class ModalFooter extends Component { static defaultProps = { hasConfig: true - } + }; render() { return ( @@ -151,6 +162,6 @@ export class ModalFooter extends Component {this.props.children} - ) + ); } }