mirror of https://gitee.com/cf-fz/WebCAD.git
parent
520fb58149
commit
beb0a8982a
@ -0,0 +1,136 @@
|
|||||||
|
import { Vector3 } from "three";
|
||||||
|
import { app } from "../../ApplicationServices/Application";
|
||||||
|
import { Board } from "../../DatabaseServices/Board";
|
||||||
|
import { Line } from "../../DatabaseServices/Line";
|
||||||
|
import { Polyline } from "../../DatabaseServices/Polyline";
|
||||||
|
import { Command } from "../../Editor/CommandMachine";
|
||||||
|
import { PromptStatus } from "../../Editor/PromptResult";
|
||||||
|
import { equaln } from "../../Geometry/GeUtils";
|
||||||
|
import { RegionParse } from "../../Geometry/RegionParse";
|
||||||
|
import { IntersectOption } from "../../GraphicsSystem/IntersectWith";
|
||||||
|
import { ModalPosition, ModalState } from "../../UI/Components/Modal/ModalsManage";
|
||||||
|
import { ReferenceCuttingModal, ReferenceCuttingStore, CuttingOffset } from "./ReferenceCuttingModal";
|
||||||
|
|
||||||
|
export class ReferenceCutting implements Command
|
||||||
|
{
|
||||||
|
async exec()
|
||||||
|
{
|
||||||
|
let brRes = await app.m_Editor.GetSelection({
|
||||||
|
Once: true,
|
||||||
|
Msg: "选择被切割的板件",
|
||||||
|
Filter: { filterTypes: [Board] },
|
||||||
|
AllowNone: false
|
||||||
|
});
|
||||||
|
if (brRes.Status !== PromptStatus.OK) return;
|
||||||
|
let br = brRes.SelectSet.SelectEntityList[0] as Board;
|
||||||
|
|
||||||
|
brRes = await app.m_Editor.GetSelection({
|
||||||
|
Once: true,
|
||||||
|
Msg: "选择切割的板件",
|
||||||
|
Filter: {
|
||||||
|
filterTypes: [Board],
|
||||||
|
filterFunction: (obj, board) => br !== board
|
||||||
|
},
|
||||||
|
AllowNone: false
|
||||||
|
});
|
||||||
|
if (brRes.Status !== PromptStatus.OK) return;
|
||||||
|
let brKnife = brRes.SelectSet.SelectEntityList[0] as Board;
|
||||||
|
|
||||||
|
let brNorm = br.Normal;
|
||||||
|
let brKnifNorm = brKnife.Normal;
|
||||||
|
|
||||||
|
if (!equaln(brNorm.dot(brKnifNorm), 0))//垂直测试
|
||||||
|
{
|
||||||
|
app.m_Editor.Prompt('板件不垂直,无法切割!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//切割刀线 方向的投影
|
||||||
|
let cutLineDir = brNorm.cross(brKnifNorm).applyMatrix4(br.OCSInv.setPosition(new Vector3()));
|
||||||
|
|
||||||
|
let brContour = br.ContourCurve;
|
||||||
|
|
||||||
|
//测试能否进行切割,使用极限位置的2条线尝试求交
|
||||||
|
let knifeP1 = brKnife.Position
|
||||||
|
.applyMatrix4(br.OCSInv).setZ(0);//基点
|
||||||
|
let knifeP2 = brKnife.Position
|
||||||
|
.add(brKnifNorm.clone().multiplyScalar(brKnife.Thickness))
|
||||||
|
.applyMatrix4(br.OCSInv).setZ(0);
|
||||||
|
let l1 = new Line(knifeP1, knifeP1.clone().add(cutLineDir));
|
||||||
|
let l2 = new Line(knifeP2, knifeP2.clone().add(cutLineDir));
|
||||||
|
let pts1 = brContour.IntersectWith(l1, IntersectOption.ExtendArg);
|
||||||
|
let pts2 = brContour.IntersectWith(l2, IntersectOption.ExtendArg);
|
||||||
|
if (pts1.length < 2 && pts2.length < 2)
|
||||||
|
{
|
||||||
|
app.m_Editor.Prompt("板件与板件没有交集.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//对话框 设置参数
|
||||||
|
let referenceCuttingStore = ReferenceCuttingStore.GetInstance() as ReferenceCuttingStore;
|
||||||
|
let option = referenceCuttingStore.m_Option;
|
||||||
|
option.halfThickness = br.Thickness / 2;
|
||||||
|
option.boardType = brKnife.BoardType;
|
||||||
|
app.m_Editor.m_ModalManage.RenderModal(ReferenceCuttingModal, ModalPosition.Center, { store: referenceCuttingStore });
|
||||||
|
let state = await app.m_Editor.m_ModalManage.Wait();
|
||||||
|
|
||||||
|
if (state === ModalState.Ok)
|
||||||
|
{
|
||||||
|
let offset: number;//偏移量
|
||||||
|
switch (option.CuttingPosSelected)
|
||||||
|
{
|
||||||
|
case CuttingOffset.Front:
|
||||||
|
offset = brKnife.Thickness / 2 - option.offset;
|
||||||
|
break;
|
||||||
|
case CuttingOffset.Middle:
|
||||||
|
offset = brKnife.Thickness / 2;
|
||||||
|
break;
|
||||||
|
case CuttingOffset.Back:
|
||||||
|
offset = brKnife.Thickness / 2 + option.offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
knifeP1 = brKnife.Position
|
||||||
|
.add(brKnifNorm.clone().multiplyScalar(offset))
|
||||||
|
.applyMatrix4(br.OCSInv).setZ(0);
|
||||||
|
|
||||||
|
let cutLine = new Line(knifeP1, knifeP1.clone().add(cutLineDir));
|
||||||
|
let ipts = brContour.IntersectWith(cutLine, IntersectOption.ExtendArg);
|
||||||
|
let brCus = brContour.GetSplitCurvesByPts(ipts);
|
||||||
|
|
||||||
|
//切割线延伸
|
||||||
|
for (let p of ipts)
|
||||||
|
cutLine.Extend(cutLine.GetParamAtPoint(p));
|
||||||
|
|
||||||
|
//切割线分裂,并且过滤掉在轮廓外的线
|
||||||
|
let cutCus = cutLine.GetSplitCurvesByPts(ipts);
|
||||||
|
cutCus = cutCus.filter(c => brContour.PtInCurve(c.GetPointAtParam(0.5)));
|
||||||
|
|
||||||
|
let regionParse = new RegionParse([...brCus, ...cutCus]);
|
||||||
|
let contours = regionParse.m_RegionsInternal.map(r =>
|
||||||
|
{
|
||||||
|
let pl = new Polyline();
|
||||||
|
for (let route of r)
|
||||||
|
pl.Join(route.curve);
|
||||||
|
|
||||||
|
return pl;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (contours.length === 0)
|
||||||
|
{
|
||||||
|
//预期之外.
|
||||||
|
app.m_Editor.Prompt("切割失败了!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//造型应用
|
||||||
|
for (let i = 1; i < contours.length; i++)
|
||||||
|
{
|
||||||
|
let br2 = br.Clone();
|
||||||
|
br2.ContourCurve = contours[i];
|
||||||
|
app.m_Database.ModelSpace.Append(br2);
|
||||||
|
}
|
||||||
|
br.ContourCurve = contours[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,188 @@
|
|||||||
|
import React = require("react");
|
||||||
|
import { Classes, Button, RadioGroup, Radio } from "@blueprintjs/core";
|
||||||
|
import { app } from "../../ApplicationServices/Application";
|
||||||
|
import { CheckObjectType, CheckoutValid } from "../../Common/CheckoutVaildValue";
|
||||||
|
import { ToasterInput, AppToaster } from "../../UI/Components/Toaster";
|
||||||
|
import { observable } from "mobx";
|
||||||
|
import { DataAdapter } from "../../Common/DataAdapter";
|
||||||
|
import { Singleton } from "../../Common/Singleton";
|
||||||
|
import { inject, observer } from "mobx-react";
|
||||||
|
import { ModalState } from "../../UI/Components/Modal/ModalsManage";
|
||||||
|
import { begin } from "xaop";
|
||||||
|
import { KeyBoard } from "../../Common/KeyEnum";
|
||||||
|
import { BoardType } from "../../DatabaseServices/Board";
|
||||||
|
|
||||||
|
export enum CuttingOffset
|
||||||
|
{
|
||||||
|
Front = "front",
|
||||||
|
Middle = "middle",
|
||||||
|
Back = "back",
|
||||||
|
}
|
||||||
|
interface OffsetKeyWord
|
||||||
|
{
|
||||||
|
Front: string;
|
||||||
|
Back: string;
|
||||||
|
}
|
||||||
|
export interface ReferenceCuttingOptioins
|
||||||
|
{
|
||||||
|
boardType: BoardType;
|
||||||
|
offset: number;
|
||||||
|
halfThickness: number;
|
||||||
|
CuttingPosSelected: CuttingOffset;
|
||||||
|
}
|
||||||
|
export class ReferenceCuttingStore extends Singleton
|
||||||
|
{
|
||||||
|
protected m_UiOption;
|
||||||
|
@observable m_Option: ReferenceCuttingOptioins = {
|
||||||
|
boardType: BoardType.Layer,
|
||||||
|
offset: 0,
|
||||||
|
halfThickness: 9,
|
||||||
|
CuttingPosSelected: CuttingOffset.Middle,
|
||||||
|
};
|
||||||
|
get UIOption()
|
||||||
|
{
|
||||||
|
return this.m_UiOption = DataAdapter.ConvertUIData(this.m_Option);
|
||||||
|
}
|
||||||
|
Cancel()
|
||||||
|
{
|
||||||
|
this._Return(ModalState.Cancel);
|
||||||
|
}
|
||||||
|
OnOk()
|
||||||
|
{
|
||||||
|
this._Return(ModalState.Ok);
|
||||||
|
}
|
||||||
|
_Return(state: number)
|
||||||
|
{
|
||||||
|
app.m_Editor.m_ModalManage.m_PromisRes(state);
|
||||||
|
app.m_Editor.m_ModalManage.Clear();
|
||||||
|
}
|
||||||
|
HasInvailValue()
|
||||||
|
{
|
||||||
|
return CheckoutValid.HasInvailValue(this.m_UiOption, CheckObjectType.RC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inject("store")
|
||||||
|
@observer
|
||||||
|
export class ReferenceCuttingModal extends React.Component<{ store: ReferenceCuttingStore }, {}> {
|
||||||
|
private uiOption;
|
||||||
|
private handleChangeOffsetDir = (e) =>
|
||||||
|
{
|
||||||
|
const store = this.props.store;
|
||||||
|
store.m_Option.CuttingPosSelected = e.currentTarget.value as CuttingOffset;
|
||||||
|
if (store.m_Option.CuttingPosSelected === CuttingOffset.Middle)
|
||||||
|
{
|
||||||
|
store.m_Option.offset = 0;
|
||||||
|
this.uiOption["offset"] = "0";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
store.m_Option.offset = store.m_Option.halfThickness;
|
||||||
|
this.uiOption["offset"] = store.m_Option.halfThickness.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private getOffsetKeyWord = (): OffsetKeyWord =>
|
||||||
|
{
|
||||||
|
switch (this.props.store.m_Option.boardType)
|
||||||
|
{
|
||||||
|
case BoardType.Layer:
|
||||||
|
return { Front: "下偏", Back: "上偏" };
|
||||||
|
case BoardType.Vertical:
|
||||||
|
return { Front: "左偏", Back: "右偏" };
|
||||||
|
case BoardType.Behind:
|
||||||
|
return { Front: "前偏", Back: "后偏" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registerEvent()
|
||||||
|
{
|
||||||
|
app.m_Editor.m_ModalManage.events.push(
|
||||||
|
begin(app.m_Editor.m_ModalManage, app.m_Editor.m_ModalManage.OnKeyDown, (e: KeyboardEvent) =>
|
||||||
|
{
|
||||||
|
if (e.keyCode === KeyBoard.Enter || e.keyCode === KeyBoard.Space)
|
||||||
|
{
|
||||||
|
if ((e.target as HTMLElement).nodeName !== "INPUT")
|
||||||
|
{
|
||||||
|
this.props.store.OnOk();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.keyCode === KeyBoard.Escape)
|
||||||
|
this.props.store.Cancel();
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
componentWillMount()
|
||||||
|
{
|
||||||
|
this.uiOption = this.props.store.UIOption;
|
||||||
|
this.registerEvent();
|
||||||
|
}
|
||||||
|
render()
|
||||||
|
{
|
||||||
|
const store = this.props.store;
|
||||||
|
return (
|
||||||
|
<div id="referenceCuttingModal" className={Classes.DIALOG_CONTAINER} >
|
||||||
|
<div className={Classes.DIALOG}>
|
||||||
|
<div
|
||||||
|
className={Classes.DIALOG_HEADER}
|
||||||
|
data-id="dragArea"
|
||||||
|
>
|
||||||
|
<h4 className="bp3-heading">设置参照板件切割位置</h4>
|
||||||
|
<Button
|
||||||
|
aria-label="Close"
|
||||||
|
minimal
|
||||||
|
icon="cross"
|
||||||
|
className={Classes.DIALOG_CLOSE_BUTTON}
|
||||||
|
onClick={() => store.Cancel()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={Classes.DIALOG_BODY}>
|
||||||
|
<RadioGroup
|
||||||
|
inline={true}
|
||||||
|
selectedValue={store.m_Option.CuttingPosSelected}
|
||||||
|
onChange={e => { this.handleChangeOffsetDir(e) }}
|
||||||
|
>
|
||||||
|
<Radio label={this.getOffsetKeyWord().Front} value={CuttingOffset.Front} />
|
||||||
|
<Radio label="居中" value={CuttingOffset.Middle} />
|
||||||
|
<Radio label={this.getOffsetKeyWord().Back} value={CuttingOffset.Back} />
|
||||||
|
</RadioGroup>
|
||||||
|
<div>
|
||||||
|
<span>按中心偏移: </span>
|
||||||
|
<ToasterInput
|
||||||
|
type={CheckObjectType.RC}
|
||||||
|
optKey="offset"
|
||||||
|
isDisabled={store.m_Option.CuttingPosSelected === CuttingOffset.Middle}
|
||||||
|
option={store.m_Option}
|
||||||
|
uiOption={this.uiOption}
|
||||||
|
onChange={(e) => { store.m_Option.offset = e.currentTarget.value; }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
|
<Button
|
||||||
|
className="LeftRightBtn"
|
||||||
|
intent="success"
|
||||||
|
text="确定"
|
||||||
|
onClick={() =>
|
||||||
|
{
|
||||||
|
if (store.HasInvailValue())
|
||||||
|
AppToaster.show({ message: "存在无效数值,请修正", timeout: 1000 });
|
||||||
|
else
|
||||||
|
store.OnOk()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className="LeftRightBtn"
|
||||||
|
intent="danger"
|
||||||
|
text="取消"
|
||||||
|
onClick={() => { store.Cancel() }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
/*---参照切割---*/
|
||||||
|
#referenceCuttingModal .bp3-dialog>.bp3-dialog-footer{
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 0px 10px 10px 10px;
|
||||||
|
button{
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#referenceCuttingModal .bp3-dialog>.bp3-dialog-body{
|
||||||
|
margin:10px;
|
||||||
|
}
|
Loading…
Reference in new issue