mirror of https://gitee.com/cf-fz/WebCAD.git
!929 功能:矩形变板件,命令:c2r,r2b
parent
1dcea0e6df
commit
85934cf911
@ -0,0 +1,17 @@
|
||||
import { app } from "../ApplicationServices/Application";
|
||||
import { Arc } from "../DatabaseServices/Entity/Arc";
|
||||
import { Line } from "../DatabaseServices/Entity/Line";
|
||||
import { Command } from "../Editor/CommandMachine";
|
||||
import { PromptStatus } from "../Editor/PromptResult";
|
||||
|
||||
export class Command_EraseLineAndArc implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let ssRes = await app.Editor.GetSelection({ UseSelect: true, Msg: "选择要被删除的直线和圆弧:", Filter: { filterTypes: [Line, Arc] } });
|
||||
if (ssRes.Status !== PromptStatus.OK) return;
|
||||
let ents = ssRes.SelectSet.SelectEntityList;
|
||||
for (let e of ents)
|
||||
e.Erase();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { Line } from "../../DatabaseServices/Entity/Line";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { RegionParse } from "../../Geometry/RegionParse";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { TestDraw } from "../test/TestUtil";
|
||||
|
||||
export class Command_TestRegionParse implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let ssRes = await app.Editor.GetSelection({ Filter: { filterTypes: [Line] } });
|
||||
if (ssRes.Status !== PromptStatus.OK) return;
|
||||
let ents = ssRes.SelectSet.SelectEntityList as Line[];
|
||||
|
||||
let region = new RegionParse(ents);
|
||||
for (let rs of [...region.RegionsOutline, ...region.RegionsInternal])
|
||||
{
|
||||
let pl = Polyline.Combine(rs.map(r => r.curve));
|
||||
TestDraw(pl);
|
||||
}
|
||||
|
||||
for (let e of ents)
|
||||
e.Erase();
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
import { Matrix4, Vector3 } from "three";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { ComputerCurvesNormalOCS } from "../../Common/CurveUtils";
|
||||
import { matrixIsCoplane } from "../../Common/Matrix4Utils";
|
||||
import { Arc } from "../../DatabaseServices/Entity/Arc";
|
||||
import { Curve } from "../../DatabaseServices/Entity/Curve";
|
||||
import { Line } from "../../DatabaseServices/Entity/Line";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { CurveIntersection } from "../../Geometry/CurveIntersection";
|
||||
import { Route } from "../../Geometry/CurveMap";
|
||||
import { equaln, IdentityMtx4 } from "../../Geometry/GeUtils";
|
||||
import { RegionParse } from "../../Geometry/RegionParse";
|
||||
import { IntersectOption } from "../../GraphicsSystem/IntersectWith";
|
||||
import { Curve2RecModal, Curve2RecModalStore } from "./Modals/Curve2RecModal";
|
||||
|
||||
//这里认为最大的板厚可能有50,当多段线的宽度小于50时,我们认为它是一个板
|
||||
//这个参数以后可能开放
|
||||
const MaxBoardThickness = 50;
|
||||
|
||||
export class CreatePolyLineFromCurve implements Command
|
||||
{
|
||||
IsSaveMax: boolean;//保留最大
|
||||
|
||||
IsOnlySaveSmall: boolean;//只保留小于指定宽度的矩形
|
||||
SmallWidth: number;//矩形的最小宽度
|
||||
|
||||
BreakCurve: boolean;//打断曲线(分析相交区域)
|
||||
ExtendsMinDist: number;//最小延伸范围
|
||||
|
||||
async exec()
|
||||
{
|
||||
let store = Curve2RecModalStore.GetInstance() as Curve2RecModalStore;
|
||||
app.Editor.ModalManage.RenderModal(Curve2RecModal, { store: store });
|
||||
|
||||
app.Editor.ModalManage.SetCallback(async () =>
|
||||
{
|
||||
this.IsSaveMax = store.option.isSaveMax;
|
||||
this.IsOnlySaveSmall = store.option.isSaveSmall;
|
||||
this.BreakCurve = store.option.isAnaly;
|
||||
this.SmallWidth = store.option.width;
|
||||
this.ExtendsMinDist = store.option.gap;
|
||||
let ss = await app.Editor.GetSelection({
|
||||
Msg: "请选择曲线:",
|
||||
UseSelect: true,
|
||||
Filter: { filterTypes: [Curve] }
|
||||
});
|
||||
if (ss.Status === PromptStatus.OK)
|
||||
{
|
||||
let ens = ss.SelectSet.SelectEntityList as Curve[];
|
||||
this.Doit(ens);
|
||||
}
|
||||
});
|
||||
}
|
||||
Doit(selectedCurs: Curve[])
|
||||
{
|
||||
let extendsMinDistSq = this.ExtendsMinDist ^ 2;
|
||||
|
||||
let groups = this.GroupCurves(selectedCurs);
|
||||
let ocsInv = new Matrix4;
|
||||
for (let group of groups)
|
||||
{
|
||||
ocsInv.getInverse(group.ocs);
|
||||
|
||||
//->wcs z0
|
||||
for (let c of group.cus)
|
||||
c.ApplyMatrix(ocsInv).Z0();
|
||||
|
||||
let intersect = new CurveIntersection(group.cus, false, IntersectOption.ExtendBoth);
|
||||
|
||||
let curves2: Curve[] = [];
|
||||
|
||||
//延伸+打断
|
||||
for (let [cu, pmap] of intersect.intersect)
|
||||
{
|
||||
let sp = cu.StartPoint;
|
||||
let ep = cu.EndPoint;
|
||||
|
||||
let epExtend: Vector3;
|
||||
let epDist = Infinity;
|
||||
let spExtend: Vector3;
|
||||
let spDist = Infinity;
|
||||
|
||||
let ipts: Vector3[] = [];
|
||||
for (let [, pts] of pmap)
|
||||
{
|
||||
ipts.push(...pts);
|
||||
for (let p of pts)
|
||||
{
|
||||
let d = p.distanceToSquared(ep);
|
||||
if (d < epDist)
|
||||
{
|
||||
epDist = d;
|
||||
epExtend = p;
|
||||
}
|
||||
d = p.distanceToSquared(sp);
|
||||
if (d < spDist)
|
||||
{
|
||||
spDist = d;
|
||||
spExtend = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//延伸
|
||||
if (epDist < extendsMinDistSq)
|
||||
{
|
||||
let param = cu.GetParamAtPoint(epExtend);
|
||||
cu.Extend(param);
|
||||
}
|
||||
if (spDist < extendsMinDistSq)
|
||||
{
|
||||
let param = cu.GetParamAtPoint(spExtend);
|
||||
cu.Extend(param);
|
||||
}
|
||||
|
||||
//打断
|
||||
let curves: Curve[];
|
||||
if (this.BreakCurve)
|
||||
curves = cu.GetSplitCurvesByPts(ipts);
|
||||
else
|
||||
curves = [cu];
|
||||
|
||||
for (let c of curves)
|
||||
{
|
||||
if (c instanceof Polyline)
|
||||
curves2.push(...c.Explode());
|
||||
else
|
||||
curves2.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
let parse = new RegionParse(curves2);
|
||||
|
||||
for (let rs of parse.RegionsInternal)
|
||||
this.Draw(rs, group.ocs, true);
|
||||
|
||||
if (this.IsSaveMax)
|
||||
for (let rs of parse.RegionsOutline)
|
||||
this.Draw(rs, group.ocs, false, 3);
|
||||
}
|
||||
|
||||
for (let e of selectedCurs)
|
||||
e.Erase();
|
||||
}
|
||||
//曲线按所在平面分组
|
||||
GroupCurves(curs: Curve[]): { ocs: Matrix4, cus: Curve[]; }[]
|
||||
{
|
||||
let curveGroup: { ocs: Matrix4, cus: Curve[]; }[] = [];
|
||||
|
||||
while (curs.length)
|
||||
{
|
||||
let ocs = ComputerCurvesNormalOCS(curs);
|
||||
let ocsInv = new Matrix4().getInverse(ocs);
|
||||
|
||||
let cus: Curve[] = [];
|
||||
curs = curs.filter(cu =>
|
||||
{
|
||||
if (CurveInOCS(cu, ocs, ocsInv))
|
||||
{
|
||||
cus.push(cu);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
curveGroup.push({ ocs, cus });
|
||||
}
|
||||
return curveGroup;
|
||||
}
|
||||
|
||||
Draw(routes: Route[], ocs: Matrix4, isOnlySaveSmall: boolean, color?: number)
|
||||
{
|
||||
let curves = routes.map(r => r.curve);
|
||||
let polyline = Polyline.Combine(curves);
|
||||
if (polyline && polyline.IsClose)
|
||||
{
|
||||
if (polyline.Area < 10) return;
|
||||
if (isOnlySaveSmall)
|
||||
{
|
||||
let size = polyline.BoundingBox.getSize(new Vector3);
|
||||
if (size.x > this.SmallWidth && size.y > this.SmallWidth)
|
||||
{
|
||||
//都大于最小宽度,不绘制
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (color === undefined)
|
||||
{
|
||||
//解析类型
|
||||
let size = polyline.BoundingBox.getSize(new Vector3);
|
||||
if (size.x > MaxBoardThickness && size.y > MaxBoardThickness)
|
||||
color = 3;
|
||||
else if (size.x <= MaxBoardThickness)
|
||||
color = 1;
|
||||
else if (size.y <= MaxBoardThickness)
|
||||
color = 2;
|
||||
else color = 7;
|
||||
}
|
||||
polyline.UpdateMatrixTo(IdentityMtx4);
|
||||
polyline.ApplyMatrix(ocs);
|
||||
polyline.ColorIndex = color;
|
||||
app.Database.ModelSpace.Append(polyline);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.warn("未预料到的错误,连接后的多段线不是闭合的");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function CurveInOCS(curve: Curve, Ocs: Matrix4, OcsInv: Matrix4): boolean
|
||||
{
|
||||
if (curve instanceof Line)
|
||||
{
|
||||
let p = curve.StartPoint.applyMatrix4(OcsInv);
|
||||
if (!equaln(p.z, 0)) return false;
|
||||
p = curve.EndPoint.applyMatrix4(OcsInv);
|
||||
if (!equaln(p.z, 0)) return false;
|
||||
return true;
|
||||
}
|
||||
else if (curve instanceof Arc)
|
||||
{
|
||||
return matrixIsCoplane(curve.OCS, Ocs);
|
||||
}
|
||||
else if (curve instanceof Polyline)
|
||||
{
|
||||
if (matrixIsCoplane(curve.OCS, Ocs))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
let cus = curve.Explode();
|
||||
return cus.every(c =>
|
||||
{
|
||||
return this.CurveInOCS(c, Ocs, OcsInv);
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
.curve2rec {
|
||||
.bp3-input {
|
||||
width: 100px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.checkbox-input-group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.checkbox-analy {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bp3-dialog-footer {
|
||||
padding: 10px 0 0 0 !important;
|
||||
|
||||
.bp3-dialog-footer-actions {
|
||||
width: 100%;
|
||||
|
||||
.bp3-label.bp3-inline {
|
||||
margin: 0 auto !important;
|
||||
|
||||
.cf-select {
|
||||
padding-bottom: 5px;
|
||||
|
||||
.bp3-input-group.input-select {
|
||||
width: 100px !important;
|
||||
|
||||
>input {
|
||||
width: inherit !important;
|
||||
height: inherit !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
import React from "react";
|
||||
import { app } from "../../../ApplicationServices/Application";
|
||||
import { KeyBoard } from "../../../Common/KeyEnum";
|
||||
import { Classes, Card, Intent, Button, Checkbox, Divider } from "@blueprintjs/core";
|
||||
import { ModalHeader, ModalFooter } from "../../../UI/Components/Modal/ModalContainer";
|
||||
import { UserConfig, IConfigOption } from "../../../UI/Components/Board/UserConfig";
|
||||
import { IConfigStore } from "../../../UI/Store/BoardStore";
|
||||
import { BoardModalType } from "../../../UI/Components/Board/BoardModal";
|
||||
import { observable, toJS } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { safeEval } from "../../../Common/eval";
|
||||
import '../Modals/Curve2Rec.less';
|
||||
import { begin } from "xaop";
|
||||
import { ToasterInput, AppToaster } from "../../../UI/Components/Toaster";
|
||||
import { CheckObjectType } from "../../../Common/CheckoutVaildValue";
|
||||
import { IBaseOption } from "../../../UI/Store/BoardInterface";
|
||||
import { DataAdapter } from "../../../Common/DataAdapter";
|
||||
import { DefaultCurve2RecOption } from "../../../Editor/DefaultConfig";
|
||||
import { Singleton } from "../../../Common/Singleton";
|
||||
|
||||
export interface Curve2RecOption extends IBaseOption
|
||||
{
|
||||
isSaveMax: boolean; //保留最大轮廓
|
||||
isSaveSmall: boolean; //保留小于width的轮廓
|
||||
width: number; //保留轮廓的宽度
|
||||
isAnaly: boolean; //分析相交区域
|
||||
gap: number; //最小间隙
|
||||
}
|
||||
export class Curve2RecModalStore extends Singleton implements IConfigStore
|
||||
{
|
||||
@observable configName = "默认";
|
||||
@observable configsNames: string[] = [];
|
||||
@observable option: Curve2RecOption = { ...DefaultCurve2RecOption };
|
||||
protected uiOption;
|
||||
get UIOption()
|
||||
{
|
||||
if (!this.uiOption)
|
||||
this.uiOption = DataAdapter.ConvertUIData(this.option);
|
||||
return this.uiOption;
|
||||
}
|
||||
InitOption = () =>
|
||||
{
|
||||
this.option = {
|
||||
isSaveMax: false,
|
||||
isSaveSmall: true,
|
||||
width: 90,
|
||||
isAnaly: true,
|
||||
gap: 3
|
||||
};
|
||||
if (this.uiOption)
|
||||
Object.assign(this.uiOption, DataAdapter.ConvertUIData(this.option));
|
||||
};
|
||||
SaveConfig = () =>
|
||||
{
|
||||
let newConfig: IConfigOption = {};
|
||||
newConfig.option = toJS(this.option);
|
||||
return newConfig;
|
||||
};
|
||||
UpdateOption = (cof: IConfigOption) =>
|
||||
{
|
||||
Object.assign(this.option, cof.option);
|
||||
if (this.uiOption)
|
||||
Object.assign(this.uiOption, DataAdapter.ConvertUIData(cof.option));
|
||||
};
|
||||
HasInvailValue = () =>
|
||||
{
|
||||
//如果为空或NaN: 有非法值
|
||||
return (this.uiOption.gap === "" || isNaN(this.uiOption.gap)) || (this.uiOption.width === "" || isNaN(this.uiOption.width));
|
||||
};
|
||||
Cancel()
|
||||
{
|
||||
app.Editor.ModalManage.Destory();
|
||||
}
|
||||
OnOk()
|
||||
{
|
||||
let invail = this.HasInvailValue();
|
||||
if (invail)
|
||||
AppToaster.show({ message: "存在无效数值,请修正!", timeout: 1000, intent: "danger" });
|
||||
else
|
||||
app.Editor.ModalManage.DestoryAndExec();
|
||||
}
|
||||
}
|
||||
@observer
|
||||
export class Curve2RecModal extends React.Component<{ store: Curve2RecModalStore; }, {}>{
|
||||
private removeFuncs: Function[] = []; //移除注入
|
||||
componentDidMount()
|
||||
{
|
||||
this.removeFuncs.push(
|
||||
begin(app.Editor.ModalManage, app.Editor.ModalManage.OnKeyDown, (e: KeyboardEvent) =>
|
||||
{
|
||||
if (e.keyCode === KeyBoard.Enter || e.keyCode === KeyBoard.Space)
|
||||
this.props.store.OnOk();
|
||||
e.stopPropagation();
|
||||
return true;
|
||||
})
|
||||
);
|
||||
}
|
||||
render()
|
||||
{
|
||||
const store = this.props.store;
|
||||
const option = store.option;
|
||||
return (
|
||||
<div className={Classes.DIALOG_CONTAINER}>
|
||||
<div className={Classes.DIALOG + " curve2rec"}>
|
||||
<ModalHeader title="线条变矩形" close={() => { this.props.store.Cancel(); }} />
|
||||
<Card style={{ padding: "5px 10px" }}>
|
||||
<div style={{ padding: 5, fontSize: 15 }}>
|
||||
<Checkbox
|
||||
checked={option.isSaveMax}
|
||||
label="保留最大轮廓"
|
||||
onChange={() => { this.props.store.option.isSaveMax = !this.props.store.option.isSaveMax; }}
|
||||
>
|
||||
</Checkbox>
|
||||
<div className="checkbox-input-group">
|
||||
<Checkbox checked={option.isSaveSmall} onChange={() => { this.props.store.option.isSaveSmall = !this.props.store.option.isSaveSmall; }}>
|
||||
</Checkbox>
|
||||
<div>
|
||||
只保留宽度小于
|
||||
<ToasterInput
|
||||
inputClassName={Classes.INPUT}
|
||||
type={CheckObjectType.OnlyNumber}
|
||||
option={option}
|
||||
uiOption={store.UIOption}
|
||||
optKey={"width"}
|
||||
onChange={(e) =>
|
||||
{
|
||||
console.log(e.target.value.trim());
|
||||
if (e.target.value === "")
|
||||
{
|
||||
this.props.store.option.width = 0;
|
||||
return;
|
||||
}
|
||||
let num = safeEval(e.target.value.trim());
|
||||
this.props.store.option.width = (!isNaN(num)) ? num : undefined;
|
||||
}}
|
||||
/>
|
||||
的轮廓
|
||||
</div>
|
||||
</div>
|
||||
<div className="checkbox-analy">
|
||||
<Checkbox
|
||||
checked={option.isAnaly}
|
||||
onChange={() => { this.props.store.option.isAnaly = !this.props.store.option.isAnaly; }}
|
||||
>
|
||||
</Checkbox>
|
||||
<div>
|
||||
<div>分析相交区域</div>
|
||||
<div>
|
||||
删除重复线和延伸最小间隙
|
||||
<ToasterInput
|
||||
inputClassName={Classes.INPUT}
|
||||
type={CheckObjectType.OnlyNumber}
|
||||
option={option}
|
||||
uiOption={store.UIOption}
|
||||
optKey={"gap"}
|
||||
onChange={(e) =>
|
||||
{
|
||||
let num = safeEval(e.target.value.trim());
|
||||
this.props.store.option.gap = (!isNaN(num)) ? num : undefined;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ModalFooter hasConfig={false} style={{ display: "flex", flexDirection: "column" }}>
|
||||
{/* 配置 */}
|
||||
<div style={{ display: "flex", width: "100%", justifyContent: "space-around" }}>
|
||||
<Button style={{ width: "50%" }} intent={Intent.SUCCESS} text="确定" onClick={() => { this.props.store.OnOk(); }} />
|
||||
<Button style={{ width: "50%" }} intent={Intent.DANGER} text="取消" onClick={() => { this.props.store.Cancel(); }} />
|
||||
</div>
|
||||
<Divider />
|
||||
<UserConfig store={this.props.store} type={BoardModalType.Curves2Rec} />
|
||||
</ModalFooter>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
@noteInputHeight: 2.5rem;
|
||||
|
||||
#rec2Br {
|
||||
.boardSize {
|
||||
.bp3-input {
|
||||
width: 4rem;
|
||||
}
|
||||
}
|
||||
.undefined.br-set{
|
||||
>span:first-child{
|
||||
width: 4.5rem;
|
||||
}
|
||||
}
|
||||
.select-drillType
|
||||
{
|
||||
width: 9rem;
|
||||
}
|
||||
.note-card {
|
||||
padding: 10px !important;
|
||||
|
||||
/* 备注信息 */
|
||||
.notes {
|
||||
width: 20vmin;
|
||||
|
||||
.bp3-input {
|
||||
height: @noteInputHeight;
|
||||
}
|
||||
|
||||
.bp3-label {
|
||||
line-height: @noteInputHeight;
|
||||
}
|
||||
|
||||
>div {
|
||||
display: flex;
|
||||
|
||||
input:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
>label {
|
||||
height: @noteInputHeight;
|
||||
line-height: @noteInputHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.boardModel {
|
||||
display: inline-block;
|
||||
width: 35px;
|
||||
height: 50px;
|
||||
border: 1px solid #000;
|
||||
vertical-align: middle;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 备注信息 */
|
||||
#rec2Br .notes>div>label:first-child,
|
||||
#rec2Br .notes>div>input:first-child {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
#rec2Br .notes>div>label:last-child,
|
||||
#rec2Br .notes>div>input:last-child {
|
||||
width: 70%;
|
||||
}
|
@ -0,0 +1,519 @@
|
||||
import { Button, Card, Checkbox, Classes, H5, HTMLSelect, Radio, RadioGroup } from '@blueprintjs/core';
|
||||
import { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import { Vector3 } from 'three';
|
||||
import { begin } from 'xaop';
|
||||
import { app } from '../../../ApplicationServices/Application';
|
||||
import { EBoardKeyList } from '../../../Common/BoardKeyList';
|
||||
import { CheckObjectType } from '../../../Common/CheckoutVaildValue';
|
||||
import { KeyBoard } from '../../../Common/KeyEnum';
|
||||
import { ToFixed } from '../../../Common/Utils';
|
||||
import { Board } from '../../../DatabaseServices/Entity/Board';
|
||||
import { TemplateRecord } from '../../../DatabaseServices/Template/TemplateRecord';
|
||||
import { PromptStatus } from '../../../Editor/PromptResult';
|
||||
import { userConfig } from '../../../Editor/UserConfig';
|
||||
import { Input5Or4Component, Notes, SetBoardDataBlock, SetBoardDataItem } from '../../../UI/Components/Board/BoardCommon';
|
||||
import { BoardModalType } from '../../../UI/Components/Board/BoardModal';
|
||||
import { ModalFooter, ModalHeader } from '../../../UI/Components/Modal/ModalContainer';
|
||||
import { ModalState } from '../../../UI/Components/Modal/ModalInterface';
|
||||
import { ToasterInput } from '../../../UI/Components/Toaster';
|
||||
import { GoodsList, IGoodInfo } from '../../../UI/MaterialEditor/GoodsList';
|
||||
import '../Modals/Rec2Br.less';
|
||||
import { Rec2BrStore } from '../Rec2BrStore';
|
||||
enum GetOptionState
|
||||
{
|
||||
GetDistance = 0,
|
||||
GetBoard = 1,
|
||||
GetTemplate = 2,
|
||||
}
|
||||
@observer
|
||||
export class Rec2BrModal extends React.Component<{ store: Rec2BrStore; }, {}>
|
||||
{
|
||||
private showShops = observable.box(false);
|
||||
private startSelect = observable.box(false);
|
||||
private m_ScaleParameter = [
|
||||
["knifeRadius", "刀半径"],
|
||||
["grooveAddLength", "槽加长"], ["grooveAddWidth", "槽加宽"], ["grooveAddDepth", "槽加深"]
|
||||
];
|
||||
private matPars = [
|
||||
["boardMatName", "板材名"], ["material", "材料"], ["color", "颜色"]
|
||||
];
|
||||
private removeFuncs: Function[] = []; //移除注入
|
||||
componentDidMount()
|
||||
{
|
||||
this.removeFuncs.push(
|
||||
begin(app.Editor.ModalManage, app.Editor.ModalManage.OnKeyDown, (e: KeyboardEvent) =>
|
||||
{
|
||||
if (e.keyCode === KeyBoard.Enter || e.keyCode === KeyBoard.Space)
|
||||
this.props.store.OnOk(ModalState.Ok);
|
||||
e.stopPropagation();
|
||||
return true;
|
||||
})
|
||||
);
|
||||
}
|
||||
componentWillUnmount()
|
||||
{
|
||||
for (let f of this.removeFuncs)
|
||||
f();
|
||||
this.removeFuncs.length = 0;
|
||||
}
|
||||
//拾取 距离 板件 模板
|
||||
private getOption = async (state: GetOptionState) =>
|
||||
{
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.Clear();
|
||||
switch (state)
|
||||
{
|
||||
case GetOptionState.GetBoard:
|
||||
let enRes1 = await app.Editor.GetEntity({
|
||||
Msg: "选择板件",
|
||||
Filter: { filterTypes: [Board] }
|
||||
});
|
||||
if (enRes1.Status === PromptStatus.OK)
|
||||
{
|
||||
const data = (enRes1.Entity as Board).BoardProcessOption;
|
||||
this.props.store.m_Option.roomName = data[EBoardKeyList.RoomName];
|
||||
this.props.store.UIOption.roomName = data[EBoardKeyList.RoomName];
|
||||
}
|
||||
break;
|
||||
case GetOptionState.GetDistance:
|
||||
let basept: Vector3;
|
||||
let ptRes = await app.Editor.GetPoint({ Msg: "点取距离或者输入" });
|
||||
if (ptRes.Status === PromptStatus.OK)
|
||||
basept = ptRes.Point;
|
||||
|
||||
let enRes2 = await app.Editor.GetDistance({
|
||||
Msg: "点取距离或者输入",
|
||||
BasePoint: basept,
|
||||
Default: 1
|
||||
});
|
||||
if (enRes2.Status === PromptStatus.OK)
|
||||
{
|
||||
let dis = ToFixed(enRes2.Distance, 2);
|
||||
this.props.store.m_Option.cabinetDeep = parseFloat(dis);
|
||||
this.props.store.UIOption.cabinetDeep = dis;
|
||||
}
|
||||
break;
|
||||
case GetOptionState.GetTemplate:
|
||||
let enRes3 = await app.Editor.GetSelection({
|
||||
Msg: "选择模板",
|
||||
Once: true,
|
||||
Filter: { filterFunction: (obj, ent) => { return ent.Template !== undefined; } }
|
||||
});
|
||||
if (enRes3.Status === PromptStatus.OK)
|
||||
{
|
||||
let ens = enRes3.SelectSet.SelectEntityList;
|
||||
|
||||
let template = ens[0].Template.Object as TemplateRecord;
|
||||
this.props.store.m_Option.backBrTemplate = template.Root;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
app.Editor.MaskManage.ShowMask();
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
};
|
||||
private startSelectTemplate = () =>
|
||||
{
|
||||
this.startSelect.set(true);
|
||||
};
|
||||
private selectGoods = (good: IGoodInfo) =>
|
||||
{
|
||||
this.props.store.m_Option.boardMatName = good.name;//是否需要更新UIOption
|
||||
this.props.store.m_Option.material = good.material;
|
||||
this.props.store.m_Option.color = good.color;
|
||||
this.showShops.set(false);
|
||||
};
|
||||
render()
|
||||
{
|
||||
const store = this.props.store;
|
||||
const selectOptions = userConfig.DrillConfigs.size > 0 ? [...userConfig.DrillConfigs.keys(), "不排"] : [];
|
||||
return (
|
||||
<div
|
||||
className={Classes.DIALOG_CONTAINER}
|
||||
id="rec2Br"
|
||||
>
|
||||
<div className={Classes.DIALOG}>
|
||||
<ModalHeader
|
||||
title={"矩形变板件"}
|
||||
icon="blank"
|
||||
close={() => { store.OnOk(ModalState.Cancel); }}
|
||||
/>
|
||||
<div
|
||||
className={Classes.DIALOG_BODY + " rec2br"}
|
||||
>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Card>
|
||||
<H5>柜体参数</H5>
|
||||
<div>
|
||||
<div className="flex br-mat">
|
||||
<div>
|
||||
<SetBoardDataItem
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="cabinetDeep"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}//style={{ display: "inline-flex", width: "65%" }}
|
||||
title="柜深"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
style={{
|
||||
minHeight: 18,
|
||||
height: 18,
|
||||
padding: 0,
|
||||
fontSize: 8
|
||||
}}
|
||||
className="bp3-button bp3-intent-success"
|
||||
onClick={() => this.getOption(GetOptionState.GetDistance)}
|
||||
>拾取</button>
|
||||
</div>
|
||||
<SetBoardDataItem
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="cabinetCurtail"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
title="柜体内缩"
|
||||
/>
|
||||
</div>
|
||||
<H5>背板规则</H5>
|
||||
<div className="flex" style={{ flexDirection: "column" }}>
|
||||
<SetBoardDataBlock
|
||||
type={CheckObjectType.R2B}
|
||||
className="flexWrap"
|
||||
pars={[["backBrThick", "板厚"]]}
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
/>
|
||||
<SetBoardDataBlock
|
||||
type={CheckObjectType.R2B}
|
||||
className="flexWrap"
|
||||
pars={[["backBrBiggerThanHeight", "大于高"], ["backBrBiggerThanWidth", "大于宽"]]}
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
/>
|
||||
<SetBoardDataItem
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="backBrFrontMove"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
title="背板前移"
|
||||
/>
|
||||
<SetBoardDataBlock
|
||||
type={CheckObjectType.R2B}
|
||||
className="flexWrap"
|
||||
pars={[["backBrLeftExtend", "左延伸"], ["backBrRightExtend", "右延伸"], ["backBrUpExtend", "上延伸"], ["backBrDownExtend", "下延伸"]]}
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
/>
|
||||
</div>
|
||||
<H5>前缩</H5>
|
||||
<div className="flex" style={{}}>
|
||||
<SetBoardDataBlock
|
||||
type={CheckObjectType.R2B}
|
||||
className="flexWrap"
|
||||
pars={[["verticalBrShrink", "立板"], ["layerBrShrink", "层板"], ["topBrShrink", "顶板"], ["bottomBrShrink", "底板"], ["groundLineBrShrink", "地脚"]]}
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
/>
|
||||
</div>
|
||||
<H5>解析板件名称与板件内缩</H5>
|
||||
<div className="flex" style={{ flexDirection: "column" }}>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.isfarLeftVerticalBrName}
|
||||
label={"最左侧立板"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.isfarLeftVerticalBrName = !store.m_Option.isfarLeftVerticalBrName;
|
||||
store.UIOption.isfarLeftVerticalBrName = store.m_Option.isfarLeftVerticalBrName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="farLeftVerticalBrName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.isfarRightVerticalBrName}
|
||||
label={"最右侧立板"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.isfarRightVerticalBrName = !store.m_Option.isfarRightVerticalBrName;
|
||||
store.UIOption.isfarRightVerticalBrName = store.m_Option.isfarRightVerticalBrName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="farRightVerticalBrName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.istopMostLayerBrName}
|
||||
label={"最顶层板"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.istopMostLayerBrName = !store.m_Option.istopMostLayerBrName;
|
||||
store.UIOption.istopMostLayerBrName = store.m_Option.istopMostLayerBrName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="topMostLayerBrName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.isbottomMostLayerBrName}
|
||||
label={"最底层板"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.isbottomMostLayerBrName = !store.m_Option.isbottomMostLayerBrName;
|
||||
store.UIOption.isbottomMostLayerBrName = store.m_Option.isbottomMostLayerBrName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="bottomMostLayerBrName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.isbottomMostBackBrName}
|
||||
label={"最底背板"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.isbottomMostBackBrName = !store.m_Option.isbottomMostBackBrName;
|
||||
store.UIOption.isbottomMostBackBrName = store.m_Option.isbottomMostBackBrName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="bottomMostBackBrName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.isstripeBrName}
|
||||
label={"收口条"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.isstripeBrName = !store.m_Option.isstripeBrName;
|
||||
store.UIOption.isstripeBrName = store.m_Option.isstripeBrName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="stripeBrName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
根据背板区分柜体
|
||||
</div>
|
||||
<RadioGroup
|
||||
inline
|
||||
selectedValue={store.m_Option.isMultiBackBr ? "1" : "0"}
|
||||
onChange={(e) =>
|
||||
{
|
||||
store.m_Option.isMultiBackBr = e.currentTarget.value === "1";
|
||||
store.UIOption.isMultiBackBr = store.m_Option.isMultiBackBr;
|
||||
}}
|
||||
>
|
||||
|
||||
<Radio label="多背板" value={"1"} />
|
||||
<Radio label="单背板" value={"0"} />
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.iscabinetName}
|
||||
label={"修改柜名"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.iscabinetName = !store.m_Option.iscabinetName;
|
||||
store.UIOption.iscabinetName = store.m_Option.iscabinetName;
|
||||
}}
|
||||
/>
|
||||
<ToasterInput
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="cabinetName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<H5>材料信息</H5>
|
||||
<div>
|
||||
<SetBoardDataBlock
|
||||
type={CheckObjectType.R2B}
|
||||
pars={this.m_ScaleParameter}
|
||||
option={store.m_Option.grooveOption}
|
||||
uiOption={store.UIOption.grooveOption}
|
||||
className="flexWrap"
|
||||
/>
|
||||
<div className="flex br-mat">
|
||||
<div>
|
||||
<SetBoardDataItem
|
||||
type={CheckObjectType.R2B}
|
||||
optKey="roomName"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
title="房间名"
|
||||
placeHolder="输入房间名"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
style={{
|
||||
minHeight: 18,
|
||||
height: 18,
|
||||
padding: 0,
|
||||
fontSize: 8
|
||||
}}
|
||||
className="bp3-button bp3-intent-success"
|
||||
onClick={() => this.getOption(GetOptionState.GetBoard)}
|
||||
>拾取</button>
|
||||
</div>
|
||||
<div className="flex br-mat">
|
||||
<SetBoardDataBlock
|
||||
type={CheckObjectType.R2B}
|
||||
pars={this.matPars}
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
isInline={true}
|
||||
/>
|
||||
<button
|
||||
style={{ width: "2rem" }}
|
||||
className="bp3-button bp3-intent-success"
|
||||
onClick={() => this.showShops.set(true)}
|
||||
>选择</button>
|
||||
{
|
||||
this.showShops.get() && <GoodsList
|
||||
open={this.showShops}
|
||||
select={this.selectGoods}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<label className="bp3-label bp3-inline .modifier">
|
||||
<span>排钻</span>
|
||||
<HTMLSelect
|
||||
className="select-drillType"
|
||||
value={store.m_Option.drillType}
|
||||
style={{
|
||||
padding: "0 5px",
|
||||
width: "100%",
|
||||
// outline: this.state.isDanger && "1px red solid"
|
||||
}}
|
||||
options={selectOptions}
|
||||
onChange={(e) =>
|
||||
{
|
||||
store.m_Option.drillType = e.target.value;
|
||||
store.UIOption.drillType = store.m_Option.drillType;
|
||||
}}
|
||||
// onFocus={() => { if (this.props.onFocus) this.props.onFocus(); }}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<H5>封边</H5>
|
||||
<div>
|
||||
{
|
||||
<Input5Or4Component
|
||||
type={CheckObjectType.R2B}
|
||||
showDirectionIcon={true}
|
||||
hasCenter={false}
|
||||
optKey=""
|
||||
upKey="sealedUp"
|
||||
downKey="sealedDown"
|
||||
leftKey="sealedLeft"
|
||||
rightKey="sealedRight"
|
||||
option={store.m_Option}
|
||||
uiOption={store.UIOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<H5>备注</H5>
|
||||
<div className={Classes.CARD + " note-card"} style={{ height: 250, overflow: "auto" }}>
|
||||
<Notes remarks={store.m_Option.remarks} />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", paddingTop: 10 }}>
|
||||
<Checkbox
|
||||
checked={store.m_Option.backBrUseTemplate}
|
||||
label={"背板使用模板"}
|
||||
onChange={() =>
|
||||
{
|
||||
store.m_Option.backBrUseTemplate = !store.m_Option.backBrUseTemplate;
|
||||
store.UIOption.backBrUseTemplate = store.m_Option.backBrUseTemplate;
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
style={{
|
||||
minHeight: 18,
|
||||
height: 18,
|
||||
padding: 0,
|
||||
fontSize: 8,
|
||||
width: "8rem"
|
||||
}}
|
||||
className="bp3-button bp3-intent-success"
|
||||
onClick={() => this.getOption(GetOptionState.GetTemplate)}
|
||||
>选择模板</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Card>
|
||||
{/* <Card>
|
||||
|
||||
</Card> */}
|
||||
</div>
|
||||
</div>
|
||||
<ModalFooter store={store} type={BoardModalType.Rec2Br}>
|
||||
<Button
|
||||
className="LeftRightBtn bp3-intent-success"
|
||||
text="确定"
|
||||
onClick={() =>
|
||||
{
|
||||
if (this.props.store.m_Option.drillType === "")
|
||||
this.props.store.m_Option.drillType = selectOptions[0];
|
||||
store.OnOk(ModalState.Ok);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className="LeftRightBtn bp3-intent-danger" text="取消"
|
||||
onClick={() => store.OnOk(ModalState.Cancel)}
|
||||
/>
|
||||
</ModalFooter>
|
||||
</div>
|
||||
{/* {
|
||||
this.startSelect.get() &&
|
||||
<TemplateSelect
|
||||
open={this.startSelect}
|
||||
// store={this.props.store}
|
||||
/>
|
||||
} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Board, BoardType } from "../../DatabaseServices/Entity/Board";
|
||||
import { Matrix4, Vector3, Box3 } from "three";
|
||||
import { BoardGetFace } from "../../Geometry/DrillParse/BoardGetFace";
|
||||
|
||||
export class ParseBoardData
|
||||
{
|
||||
pl: Polyline;
|
||||
faceList: BoardGetFace;//
|
||||
board: Board;
|
||||
constructor(br: Board, fontMatInv?: Matrix4)
|
||||
{
|
||||
if (!fontMatInv)
|
||||
//求前视图的正矩阵和逆矩阵//?
|
||||
fontMatInv = br.SpaceOCSInv;
|
||||
this.Parse(br, fontMatInv);
|
||||
}
|
||||
IsCollisionTo(br: ParseBoardData)
|
||||
{
|
||||
let faceList = this.faceList.IntersectFace(br.faceList);
|
||||
return !(faceList.length === 0);
|
||||
}
|
||||
isIntersectOrContain(br: ParseBoardData)
|
||||
{
|
||||
let box1 = this.pl.BoundingBox;
|
||||
let box2 = br.pl.BoundingBox;
|
||||
if (box1.intersectsBox(box2))
|
||||
{
|
||||
let unionBoxs = new Box3();//?
|
||||
unionBoxs.union(box1);
|
||||
unionBoxs.union(box2);
|
||||
let vec = unionBoxs.max.clone().sub(unionBoxs.min);
|
||||
return vec.x > 1 && vec.y > 1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
private Parse(br: Board, fontMatInv: Matrix4)
|
||||
{
|
||||
this.board = br;
|
||||
this.faceList = new BoardGetFace(br);//?
|
||||
let brminpt = br.MinPoint;
|
||||
brminpt.applyMatrix4(fontMatInv);
|
||||
brminpt.setZ(0);
|
||||
let addVec: Vector3;
|
||||
switch (br.BoardType)
|
||||
{
|
||||
case BoardType.Layer:
|
||||
addVec = new Vector3(br.Height, br.Thickness);//?
|
||||
break;
|
||||
case BoardType.Vertical:
|
||||
addVec = new Vector3(br.Thickness, br.Height);//?
|
||||
break;
|
||||
case BoardType.Behind:
|
||||
addVec = new Vector3(br.Width, br.Height);//?
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.pl = new Polyline().RectangleFrom2Pt(brminpt, brminpt.clone().add(addVec));
|
||||
}
|
||||
}
|
@ -0,0 +1,482 @@
|
||||
import { Board, BoardType } from "../../DatabaseServices/Entity/Board";
|
||||
import { Vector3, Matrix4, Box3 } from "three";
|
||||
import { equaln, isParallelTo } from "../../Geometry/GeUtils";
|
||||
import { ParseBoardData } from "./ParseBoardData";
|
||||
import { EBoardKeyList } from "../../Common/BoardKeyList";
|
||||
import { DrillType, LinesType, FaceDirection } from "../../UI/Store/BoardInterface";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { Rec2BrStore } from "./Rec2BrStore";
|
||||
|
||||
/*解析板件名称 根据板件的位置.
|
||||
可能出现 顶底板.
|
||||
地脚线.
|
||||
左侧版
|
||||
右侧板.
|
||||
*/
|
||||
interface BrLocDataValue
|
||||
{
|
||||
vec: Vector3;
|
||||
br: Board;
|
||||
}
|
||||
enum SortType
|
||||
{
|
||||
x = "x",
|
||||
xdesc = "X",
|
||||
y = "y",
|
||||
ydesc = "Y",
|
||||
z = "z",
|
||||
zdesc = "Z",
|
||||
}
|
||||
enum ParseType //解析类型. 整体解析 根据背板
|
||||
{
|
||||
ParseAll = 0,
|
||||
ParseFormBackBoard = 1
|
||||
}
|
||||
export class ParseBoardNameUtil
|
||||
{
|
||||
isParseLeftBr: boolean;//左侧版.
|
||||
isParseRightBr: boolean;//右侧版.
|
||||
isParseTopBr: boolean;//顶板
|
||||
isParseDownBr: boolean;//底板.
|
||||
isParseGroundLineBr: boolean;//地脚.
|
||||
isParseStripeBr: boolean;//收口条
|
||||
isChangeCabinetName: boolean;//修改柜体名称
|
||||
leftBrName: string;
|
||||
rightBrName: string;
|
||||
topBrName: string;
|
||||
downBrName: string;
|
||||
groundLineBrName: string;
|
||||
stripeBrName: string;
|
||||
cabinetName: string;//柜体名称
|
||||
roomName: string;//房间名称
|
||||
topBrShrink: number;//顶底板 立板层板前缩
|
||||
downBrShrink: number;
|
||||
verticalBrShrink: number;
|
||||
layerBrShrink: number;
|
||||
groundLineBrMoveBack: number;//地脚线往后面移动
|
||||
//背板大小
|
||||
backBrLength: number;
|
||||
backBrWidth: number;
|
||||
parseType: ParseType;
|
||||
constructor(store: Rec2BrStore)
|
||||
{
|
||||
this.InitData(store);
|
||||
}
|
||||
InitData(store: Rec2BrStore)
|
||||
{
|
||||
let option = store.m_Option;
|
||||
this.isParseLeftBr = option.isfarLeftVerticalBrName;
|
||||
this.leftBrName = option.farLeftVerticalBrName;
|
||||
this.isParseRightBr = option.isfarRightVerticalBrName;
|
||||
this.rightBrName = option.farRightVerticalBrName;
|
||||
this.isParseTopBr = option.istopMostLayerBrName;
|
||||
this.topBrName = option.topMostLayerBrName;
|
||||
this.isParseDownBr = option.isbottomMostLayerBrName;
|
||||
this.downBrName = option.bottomMostLayerBrName;
|
||||
this.isParseStripeBr = option.isstripeBrName;
|
||||
this.stripeBrName = option.stripeBrName;
|
||||
this.isParseGroundLineBr = option.isbottomMostBackBrName;
|
||||
this.groundLineBrName = option.bottomMostBackBrName;
|
||||
this.roomName = option.roomName;
|
||||
this.backBrLength = option.backBrBiggerThanHeight;//
|
||||
this.backBrWidth = option.backBrBiggerThanWidth;//
|
||||
this.parseType = option.isMultiBackBr ? ParseType.ParseFormBackBoard : ParseType.ParseAll;
|
||||
this.verticalBrShrink = option.verticalBrShrink;
|
||||
this.layerBrShrink = option.layerBrShrink;
|
||||
this.isChangeCabinetName = option.iscabinetName;
|
||||
this.cabinetName = option.cabinetName;
|
||||
this.topBrShrink = option.topBrShrink;
|
||||
this.downBrShrink = option.bottomBrShrink;
|
||||
this.groundLineBrMoveBack = option.groundLineBrShrink;
|
||||
}
|
||||
ParseBoardNameFormLocation(brarr: Board[])
|
||||
{
|
||||
if (brarr.length < 1)
|
||||
return;
|
||||
//板件位置数据.
|
||||
let boardLocData: Map<number, BrLocDataValue[]> = new Map();
|
||||
let brSpcMatInv = brarr[0].SpaceOCSInv;
|
||||
//构建数据
|
||||
for (let br of brarr)
|
||||
{
|
||||
if (br.BoardType === BoardType.Behind)
|
||||
{
|
||||
if (br.Height > this.backBrLength && br.Width > this.backBrWidth)
|
||||
{
|
||||
this.ChangeBeiBan(br);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let basePt = br.Position;
|
||||
basePt.applyMatrix4(brSpcMatInv);
|
||||
let arr = boardLocData.get(br.BoardType);
|
||||
if (!arr)
|
||||
boardLocData.set(br.BoardType, [{ vec: basePt, br: br }]);
|
||||
else
|
||||
{
|
||||
arr.push({ vec: basePt, br: br });
|
||||
boardLocData.set(br.BoardType, arr);
|
||||
}
|
||||
}
|
||||
//解析与设置柜体名称.
|
||||
let FuncParseBrName = (bool: boolean, name: string, sortType: SortType, boardType: BoardType) =>
|
||||
{
|
||||
if (bool)
|
||||
{
|
||||
let br = this.FindBr(boardLocData, sortType, boardType);
|
||||
if (br)
|
||||
br.Name = name;
|
||||
}
|
||||
};
|
||||
FuncParseBrName(this.isParseLeftBr, this.leftBrName, SortType.x, BoardType.Vertical);
|
||||
//左侧版修改孔面
|
||||
if (this.isParseLeftBr && (boardLocData.get(BoardType.Vertical)?.length > 0))
|
||||
this.ChangeZuoCeBan(boardLocData.get(BoardType.Vertical)[0].br);
|
||||
FuncParseBrName(this.isParseRightBr, this.rightBrName, SortType.xdesc, BoardType.Vertical);
|
||||
//右侧版修改孔面
|
||||
if (this.isParseRightBr && (boardLocData.get(BoardType.Vertical)?.length > 0))
|
||||
this.ChangeYouCeBan(boardLocData.get(BoardType.Vertical)[0].br);
|
||||
FuncParseBrName(this.isParseTopBr, this.topBrName, SortType.zdesc, BoardType.Layer);
|
||||
//顶版修改孔面
|
||||
if (this.isParseTopBr && (boardLocData.get(BoardType.Layer)?.length > 0))
|
||||
{
|
||||
let arr = boardLocData.get(BoardType.Layer);
|
||||
let z = arr[0].vec.z;
|
||||
for (let data of arr)
|
||||
{
|
||||
if (equaln(z, data.vec.z, 1e-2))
|
||||
this.ChangeDingBan(data.br);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
FuncParseBrName(this.isParseDownBr, this.downBrName, SortType.z, BoardType.Layer);
|
||||
//底板
|
||||
if (this.isParseDownBr && (boardLocData.get(BoardType.Layer)?.length > 0))
|
||||
{
|
||||
let arr = boardLocData.get(BoardType.Layer);
|
||||
let z = arr[0].vec.z;
|
||||
for (let data of arr)
|
||||
{
|
||||
if (equaln(z, data.vec.z, 1e-2))
|
||||
this.ChangeDiBan(data.br);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
//地脚
|
||||
FuncParseBrName(this.isParseGroundLineBr, this.groundLineBrName, SortType.z, BoardType.Behind);
|
||||
//地脚线处理
|
||||
if (this.isParseGroundLineBr && (boardLocData.get(BoardType.Behind)?.length > 0))
|
||||
{
|
||||
let arr = boardLocData.get(BoardType.Behind);
|
||||
let z = arr[0].vec.z;
|
||||
for (let data of arr)
|
||||
{
|
||||
if (equaln(z, data.vec.z, 1e-2))
|
||||
{
|
||||
let br = data.br;
|
||||
if (br.Height < br.Width)
|
||||
this.ChangeDiJiao(br);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.CurtailBoard(boardLocData, brarr);
|
||||
}
|
||||
//分堆 来自背板
|
||||
//解析板件数组.
|
||||
ParseBoardArrFormBackBoard(arr: Board[][], brarr: Board[])
|
||||
{
|
||||
if (brarr.length === 0)
|
||||
return;
|
||||
|
||||
let parseBrData: ParseBoardData[] = [];
|
||||
let backBrData: ParseBoardData[] = [];
|
||||
for (let br of brarr)
|
||||
{
|
||||
let data = new ParseBoardData(br, brarr[0].SpaceOCSInv);
|
||||
if (br.BoardType === BoardType.Behind && br.Width > this.backBrWidth && br.Height > this.backBrLength)
|
||||
{
|
||||
backBrData.push(data);
|
||||
}
|
||||
else
|
||||
parseBrData.push(data);
|
||||
}
|
||||
for (let bdata of backBrData)
|
||||
{
|
||||
let ar: Board[] = [];
|
||||
ar.push(bdata.board);//加入背板???
|
||||
for (let pdata of parseBrData)
|
||||
{
|
||||
if (bdata.isIntersectOrContain(pdata) || bdata.IsCollisionTo(pdata))
|
||||
{
|
||||
ar.push(pdata.board);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
arr.push(ar);
|
||||
}
|
||||
}
|
||||
Doit(brarr: Board[])
|
||||
{
|
||||
this.InitBoardName(brarr);
|
||||
let boardarrHeap: Board[][] = [];
|
||||
this.ParseBoardArrFormBackBoard(boardarrHeap, brarr);
|
||||
// console.log(boardarrHeap, brarr);
|
||||
if (boardarrHeap.length === 0)
|
||||
boardarrHeap.push(brarr);
|
||||
this.ParseShouKouTiao(brarr, boardarrHeap);
|
||||
switch (this.parseType)
|
||||
{
|
||||
case ParseType.ParseAll://?单背板柜子
|
||||
let calbrarr: Board[] = [];
|
||||
for (let brarr of boardarrHeap)
|
||||
{
|
||||
calbrarr.push(...brarr);
|
||||
}
|
||||
this.ParseBoardNameFormLocation(calbrarr);
|
||||
for (let br of calbrarr)
|
||||
{
|
||||
br.BoardProcessOption[EBoardKeyList.CabinetName] = this.cabinetName;
|
||||
br.BoardProcessOption[EBoardKeyList.RoomName] = this.roomName;
|
||||
}
|
||||
break;
|
||||
case ParseType.ParseFormBackBoard://?多背板柜子
|
||||
let index = 1;
|
||||
for (let brarr of boardarrHeap)
|
||||
{
|
||||
this.ParseBoardNameFormLocation(brarr);
|
||||
for (let br of brarr)
|
||||
{
|
||||
br.BoardProcessOption[EBoardKeyList.CabinetName] = this.cabinetName + index;//?
|
||||
br.BoardProcessOption[EBoardKeyList.RoomName] = this.roomName;//
|
||||
}
|
||||
index++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
private FindBr(map: Map<Number, BrLocDataValue[]>, sortType: SortType, boardType: BoardType)//
|
||||
{
|
||||
let arr = map.get(boardType);
|
||||
if (arr && arr.length > 0)
|
||||
{
|
||||
switch (sortType.toUpperCase())
|
||||
{
|
||||
case "X":
|
||||
arr.sort((a, b) => sortType === SortType.x ? a.vec.x - b.vec.x : b.vec.x - a.vec.x);
|
||||
break;
|
||||
case "Y":
|
||||
arr.sort((a, b) => sortType === SortType.y ? a.vec.y - b.vec.y : b.vec.y - a.vec.y);
|
||||
break;
|
||||
case "Z":
|
||||
arr.sort((a, b) => sortType === SortType.z ? a.vec.z - b.vec.z : b.vec.z - a.vec.z);
|
||||
break;
|
||||
}
|
||||
return arr[0].br;
|
||||
}
|
||||
}
|
||||
//修改地脚线 前缩和改变纹路
|
||||
private ChangeDiJiao(br: Board)
|
||||
{
|
||||
br.Name = this.groundLineBrName;
|
||||
br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Back;
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Reverse;
|
||||
let n = br.Normal.clone().multiplyScalar(this.groundLineBrMoveBack);
|
||||
let moveMatrix = new Matrix4().setPosition(br.Normal.clone().sub(n));
|
||||
br.ApplyMatrix(moveMatrix);
|
||||
}
|
||||
//左侧板
|
||||
private ChangeZuoCeBan(br: Board)
|
||||
{
|
||||
br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Front;
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
}
|
||||
//右侧板
|
||||
private ChangeYouCeBan(br: Board)
|
||||
{
|
||||
br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Back;
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
}
|
||||
//顶板
|
||||
private ChangeDingBan(br: Board)
|
||||
{
|
||||
br.Name = this.topBrName;
|
||||
br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Front;
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
}
|
||||
//底板
|
||||
private ChangeDiBan(br: Board)
|
||||
{
|
||||
br.Name = this.downBrName;
|
||||
br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Back;
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
}
|
||||
//背板
|
||||
private ChangeBeiBan(br: Board)
|
||||
{
|
||||
br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Back;
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
}
|
||||
private CurtailBoard(map: Map<Number, BrLocDataValue[]>, brarr: Board[])//
|
||||
{
|
||||
//todo地脚
|
||||
let cbarr: Board[] = [];
|
||||
let lbarr: Board[] = [];
|
||||
let map1 = map.get(BoardType.Vertical);
|
||||
let map0 = map.get(BoardType.Layer);
|
||||
if (map1)
|
||||
for (let lb of map1)
|
||||
{
|
||||
if (lb.br.Name === "立板")
|
||||
{
|
||||
lb.br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
lb.br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Back;
|
||||
// lb.br//纹路 正
|
||||
//孔面 反
|
||||
lbarr.push(lb.br);
|
||||
}
|
||||
}
|
||||
let topbrarr: Board[] = [];
|
||||
let downbrarr: Board[] = [];
|
||||
if (map0)
|
||||
for (let cb of map0)
|
||||
{
|
||||
let name = cb.br.Name;
|
||||
switch (name)
|
||||
{
|
||||
case "层板":
|
||||
cb.br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
cb.br.BoardProcessOption[EBoardKeyList.BigHole] = FaceDirection.Back;
|
||||
//正纹
|
||||
//孔面 反
|
||||
cbarr.push(cb.br);
|
||||
break;
|
||||
case "顶板":
|
||||
topbrarr.push(cb.br);
|
||||
break;
|
||||
case "底板":
|
||||
downbrarr.push(cb.br);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.FrontCurtailBrs(topbrarr, this.topBrShrink, "顶板");
|
||||
this.FrontCurtailBrs(downbrarr, this.downBrShrink, "底板");
|
||||
this.FrontCurtailBrs(lbarr, this.verticalBrShrink, "立板");
|
||||
this.FrontCurtailBrs(cbarr, this.layerBrShrink, "层板");
|
||||
}
|
||||
//计算收口条
|
||||
private ParseShouKouTiao(brarr: Board[], calbrarr: Board[][])
|
||||
{
|
||||
if (!this.isParseStripeBr)
|
||||
return;
|
||||
for (let calbrs of calbrarr)//boardHeap
|
||||
{
|
||||
for (let calbr of calbrs)
|
||||
{
|
||||
let index = brarr.findIndex((br) => br.Id.Index === calbr.Id.Index);
|
||||
brarr.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (let br of brarr)
|
||||
{
|
||||
br.Name = this.stripeBrName;
|
||||
br.BoardProcessOption[EBoardKeyList.DrillType] = DrillType.None;
|
||||
if (br.Height > br.Width)
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Positive;
|
||||
else
|
||||
br.BoardProcessOption[EBoardKeyList.Lines] = LinesType.Reverse;
|
||||
}
|
||||
}
|
||||
private InitBoardName(brarr: Board[])
|
||||
{
|
||||
for (let br of brarr)
|
||||
{
|
||||
switch (br.BoardType)
|
||||
{
|
||||
case BoardType.Layer:
|
||||
br.Name = "层板";
|
||||
break;
|
||||
case BoardType.Vertical:
|
||||
br.Name = "立板";
|
||||
break;
|
||||
case BoardType.Behind:
|
||||
br.Name = "背板";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//前缩
|
||||
private FrontCurtailBrs(brs: Board[], curtailNum: number, promptMsg: string)
|
||||
{
|
||||
if (brs.length < 1)
|
||||
return;
|
||||
let sizeBox = new Box3();
|
||||
let spaceOcsInv = brs[0].SpaceOCSInv;
|
||||
let boardBoxCache = new Map<Board, { box: Box3, size: Vector3; }>();
|
||||
for (let br of brs)
|
||||
{
|
||||
let box = br.BoundingBoxInOCS;
|
||||
box.applyMatrix4(spaceOcsInv.clone().multiply(br.OCS));
|
||||
boardBoxCache.set(br, { box, size: box.getSize(new Vector3) });
|
||||
sizeBox.union(box);
|
||||
}
|
||||
|
||||
//构造前缩盒子
|
||||
const GenCurtailBox = (sizeBox: Box3): Box3 =>
|
||||
{
|
||||
let size = sizeBox.getSize(new Vector3);
|
||||
let v = new Vector3(1, 1, 1);
|
||||
let frontBox = new Box3(sizeBox.min.clone().sub(v), sizeBox.max.clone().sub(new Vector3(-1, size.y / 2, -1)));
|
||||
return frontBox;
|
||||
};
|
||||
|
||||
let curBox = GenCurtailBox(sizeBox);
|
||||
|
||||
let index = 1;
|
||||
let allowDist = 0;
|
||||
let minDist = Infinity;
|
||||
for (let br of brs)
|
||||
{
|
||||
let boxData = boardBoxCache.get(br);
|
||||
if (boxData.box.intersectsBox(curBox)
|
||||
&& !curBox.containsBox(boxData.box)
|
||||
&& !isParallelTo(br.Normal, new Vector3().setComponent(index, 1))
|
||||
)
|
||||
{
|
||||
minDist = Math.min(minDist, boxData.box.max.getComponent(index) - boxData.box.min.getComponent(index));
|
||||
}
|
||||
allowDist = minDist - 1;
|
||||
}
|
||||
if (curtailNum > allowDist)
|
||||
{
|
||||
app.Editor.Prompt(`${promptMsg}的前缩值不得超过${allowDist}`);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let br of brs)
|
||||
{
|
||||
//逐板计算拉伸盒子
|
||||
let curBox2 = GenCurtailBox(br.BoundingBox);
|
||||
let pts = br.GetStretchPoints();
|
||||
let curtailVec = new Vector3(0, curtailNum);
|
||||
let curtailIndexs = [];
|
||||
//获取索引
|
||||
for (let i = 0, length = pts.length; i < length; i++)
|
||||
{
|
||||
if (curBox2.containsPoint(pts[i]))
|
||||
curtailIndexs.push(i);
|
||||
}
|
||||
if (!isParallelTo(curtailVec, br.Normal))
|
||||
br.MoveStretchPoints(curtailIndexs, curtailVec);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
import { BoardStore } from "../../UI/Store/BoardStore";
|
||||
import { IBaseOption, IGrooveOption } from "../../UI/Store/BoardInterface";
|
||||
import { CheckoutValid, CheckObjectType } from "../../Common/CheckoutVaildValue";
|
||||
import { DataAdapter } from "../../Common/DataAdapter";
|
||||
import { TemplateRecord } from "../../DatabaseServices/Template/TemplateRecord";
|
||||
import { observable } from "mobx";
|
||||
|
||||
export class Rec2BrStore extends BoardStore
|
||||
{
|
||||
@observable m_Option: IRec2BrOption;
|
||||
protected m_UiOption;
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
this.InitOption();
|
||||
}
|
||||
private GetDefaultOption()
|
||||
{
|
||||
let originOption: IRec2BrOption = {
|
||||
cabinetDeep: 400,
|
||||
cabinetBrThick: 18,
|
||||
cabinetCurtail: 0,
|
||||
backBrThick: 18,
|
||||
backBrBiggerThanHeight: 200,
|
||||
backBrBiggerThanWidth: 200,
|
||||
backBrFrontMove: 0,
|
||||
backBrLeftExtend: 0,
|
||||
backBrRightExtend: 0,
|
||||
backBrUpExtend: 0,
|
||||
backBrDownExtend: 0,
|
||||
verticalBrShrink: 0,
|
||||
layerBrShrink: 0,
|
||||
topBrShrink: 0,
|
||||
bottomBrShrink: 0,
|
||||
groundLineBrShrink: 0,
|
||||
farLeftVerticalBrName: "左侧板",
|
||||
farRightVerticalBrName: "右侧板",
|
||||
topMostLayerBrName: "顶板",
|
||||
bottomMostLayerBrName: "底板",
|
||||
bottomMostBackBrName: "地脚线",
|
||||
stripeBrName: "收口条",
|
||||
cabinetName: "",
|
||||
isfarLeftVerticalBrName: true,//最左侧立板名称
|
||||
isfarRightVerticalBrName: true,
|
||||
istopMostLayerBrName: true,
|
||||
isbottomMostLayerBrName: true,
|
||||
isbottomMostBackBrName: true,
|
||||
isstripeBrName: true,
|
||||
iscabinetName: false,//修改柜名
|
||||
isMultiBackBr: false,
|
||||
grooveOption: {
|
||||
grooveAddLength: "0",
|
||||
grooveAddWidth: "0",
|
||||
grooveAddDepth: "0",
|
||||
knifeRadius: "3",
|
||||
},
|
||||
roomName: "",
|
||||
boardMatName: "",
|
||||
material: "",
|
||||
color: "",
|
||||
drillType: "",
|
||||
sealedDown: "1",
|
||||
sealedLeft: "1",
|
||||
sealedRight: "1",
|
||||
sealedUp: "1",
|
||||
backBrUseTemplate: false,
|
||||
backBrTemplate: null,
|
||||
remarks: Array.from({ length: 12 }, () => ["", ""]),
|
||||
};
|
||||
return originOption;
|
||||
}
|
||||
InitOption()
|
||||
{
|
||||
this.m_Option = this.GetDefaultOption();
|
||||
if (this.m_UiOption)
|
||||
Object.assign(this.m_UiOption, DataAdapter.ConvertUIData(this.m_Option));
|
||||
}
|
||||
HasInvailValue()
|
||||
{
|
||||
return CheckoutValid.HasInvailValue(this.m_Option, CheckObjectType.R2B);//
|
||||
}
|
||||
// OnOk = () =>
|
||||
// {
|
||||
|
||||
// //检查option 封边排钻等是否有效
|
||||
// };
|
||||
}
|
||||
|
||||
|
||||
interface IRec2BrOption extends IBaseOption
|
||||
{
|
||||
//柜体参数
|
||||
cabinetDeep: number;//柜深
|
||||
cabinetBrThick: number;//板厚
|
||||
cabinetCurtail: number;//柜体内缩
|
||||
//背板规则
|
||||
backBrThick: number;//背板厚
|
||||
backBrBiggerThanHeight: number;//背板大于高
|
||||
backBrBiggerThanWidth: number;//背板大于宽
|
||||
backBrFrontMove: number;//背板前移
|
||||
backBrLeftExtend: number;//背板上下左右延伸
|
||||
backBrRightExtend: number;
|
||||
backBrUpExtend: number;
|
||||
backBrDownExtend: number;
|
||||
//前缩
|
||||
verticalBrShrink: number;//立板 层板 底板 顶板 地脚线前缩
|
||||
layerBrShrink: number;
|
||||
bottomBrShrink: number;
|
||||
topBrShrink: number;
|
||||
groundLineBrShrink: number;
|
||||
//解析板件名
|
||||
farLeftVerticalBrName: string;//最左侧立板名称
|
||||
farRightVerticalBrName: string;
|
||||
topMostLayerBrName: string;
|
||||
bottomMostLayerBrName: string;
|
||||
bottomMostBackBrName: string;
|
||||
stripeBrName: string;
|
||||
cabinetName: string;//修改柜名
|
||||
//以上的checkbox是否选择
|
||||
isfarLeftVerticalBrName: boolean;//最左侧立板名称
|
||||
isfarRightVerticalBrName: boolean;
|
||||
istopMostLayerBrName: boolean;
|
||||
isbottomMostLayerBrName: boolean;
|
||||
isbottomMostBackBrName: boolean;
|
||||
isstripeBrName: boolean;
|
||||
iscabinetName: boolean;//修改柜名
|
||||
isMultiBackBr: boolean;//是否多背板柜子
|
||||
backBrUseTemplate: boolean;
|
||||
backBrTemplate: TemplateRecord;//背板模板
|
||||
//材料信息
|
||||
//刀半径
|
||||
//槽加长
|
||||
//槽加深
|
||||
//槽加宽
|
||||
grooveOption: IGrooveOption;
|
||||
roomName: string;//房间名
|
||||
boardMatName: string;//板材名
|
||||
material: string;//材料
|
||||
color: string;//颜色
|
||||
drillType: string;//排钻
|
||||
//封边
|
||||
sealedDown: string,
|
||||
sealedLeft: string,
|
||||
sealedRight: string,
|
||||
sealedUp: string,
|
||||
//备注
|
||||
remarks: [string, string][];
|
||||
}
|
@ -0,0 +1,517 @@
|
||||
import { Box3, Matrix4, Vector3 } from "three";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { arrayRemoveIf } from "../../Common/ArrayExt";
|
||||
import { IsDev } from "../../Common/Deving";
|
||||
import { safeEval } from "../../Common/eval";
|
||||
import { matrixSetVector } from "../../Common/Matrix4Utils";
|
||||
import { Board, BoardType } from "../../DatabaseServices/Entity/Board";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { TemplateRecord } from "../../DatabaseServices/Template/TemplateRecord";
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { equaln } from "../../Geometry/GeUtils";
|
||||
import { IntersectOption } from "../../GraphicsSystem/IntersectWith";
|
||||
import { HotCMD } from "../../Hot/HotCommand";
|
||||
import { CurveInOCS } from "./CreatePolyLineFromCurve";
|
||||
import { Rec2BrModal } from "./Modals/Rec2Br";
|
||||
import { Rec2BrStore } from "./Rec2BrStore";
|
||||
|
||||
//已经实现:矩形转板件 位置正确 切割正常
|
||||
//已处理名称解析,前缩部分,根据背板区分柜体部分 材料信息 备注部分. 未测试
|
||||
|
||||
/*
|
||||
前期
|
||||
pl.TempData = size;
|
||||
pl.TempData2 = box;
|
||||
|
||||
后期
|
||||
pl.TempData = br;
|
||||
*/
|
||||
|
||||
@HotCMD
|
||||
export class RectConvertToBoard implements Command
|
||||
{
|
||||
store = Rec2BrStore.GetInstance() as Rec2BrStore;
|
||||
SpaceOCS: Matrix4;
|
||||
SpaceOCSInv: Matrix4;
|
||||
async exec()
|
||||
{
|
||||
if (!IsDev())
|
||||
alert("收费功能免费试用中!截至至2020年6月1日!");
|
||||
app.Editor.ModalManage.RenderModal(Rec2BrModal, { store: this.store });
|
||||
|
||||
app.Editor.ModalManage.SetCallback(async () =>
|
||||
{
|
||||
this.InitData(this.store);
|
||||
|
||||
let ss = await app.Editor.GetSelection({
|
||||
Msg: "请选择曲线:",
|
||||
UseSelect: true,
|
||||
Filter: { filterTypes: [Polyline] }
|
||||
});
|
||||
if (ss.Status === PromptStatus.Cancel) return;
|
||||
|
||||
let ens = ss.SelectSet.SelectEntityList as Polyline[];
|
||||
this.Doit(ens);
|
||||
});
|
||||
};
|
||||
boardThick: number; //板件厚度.
|
||||
boardDepth: number; //板件的深度
|
||||
fontDis: number; //前距
|
||||
// 刀半径
|
||||
knifeRadius: number;
|
||||
// 槽加长
|
||||
grooveLength: number;
|
||||
// 槽加深
|
||||
grooveDepth: number;
|
||||
// 槽加宽
|
||||
grooveWidth: number;
|
||||
// 背板数据
|
||||
// 上下左右延伸
|
||||
backLeftExtend: number; backRightExtend: number; backTopExtend: number; backDownExtend: number;
|
||||
//背板厚度
|
||||
backBoardThick: number;
|
||||
//需要移动的背板的大小
|
||||
moveBackLen: number; moveBackWidth: number;
|
||||
//背板移动的距离
|
||||
backBoardMoveDis: number;
|
||||
//背板是模板
|
||||
backIsTemplate: boolean;
|
||||
//背板模板
|
||||
backTemplate: TemplateRecord;
|
||||
//使用板名设置属性
|
||||
isUseBoardNameToAttr: boolean;
|
||||
//多背板柜子
|
||||
isMultiBackCab: boolean = false;
|
||||
//板名设置属性配置
|
||||
strBoardNameConfig: string;//?
|
||||
boardData;//?
|
||||
InitData(store: Rec2BrStore)
|
||||
{
|
||||
let option = store.m_Option;
|
||||
this.boardThick = option.cabinetBrThick;//18;
|
||||
this.boardDepth = option.cabinetDeep;//300;
|
||||
this.fontDis = option.cabinetCurtail;//0;
|
||||
this.backBoardThick = option.backBrThick;//18;
|
||||
this.backIsTemplate = option.backBrUseTemplate;//false;
|
||||
// this.backTemplate = option.backBrTemplate;
|
||||
this.backBoardMoveDis = option.backBrFrontMove;//0;
|
||||
this.isUseBoardNameToAttr = false;
|
||||
this.moveBackLen = option.backBrBiggerThanHeight;
|
||||
this.moveBackWidth = option.backBrBiggerThanWidth;//
|
||||
this.backLeftExtend = option.backBrLeftExtend;//0;
|
||||
this.backRightExtend = option.backBrRightExtend;
|
||||
this.backTopExtend = option.backBrUpExtend;
|
||||
this.backDownExtend = option.backBrDownExtend;//0;
|
||||
this.isMultiBackCab = option.isMultiBackBr;
|
||||
//材料信息
|
||||
this.knifeRadius = safeEval(option.grooveOption.knifeRadius);
|
||||
this.grooveDepth = safeEval(option.grooveOption.grooveAddDepth);
|
||||
this.grooveLength = safeEval(option.grooveOption.grooveAddLength);
|
||||
this.grooveWidth = safeEval(option.grooveOption.grooveAddWidth);
|
||||
}
|
||||
//绘制 传入曲线id表
|
||||
Doit(pls: Polyline[])
|
||||
{
|
||||
//默认认为用户传进来的pls都平行,都在一个平面内
|
||||
if (!pls || pls.length === 0) return;
|
||||
|
||||
let pl0 = pls[0];
|
||||
//希望根据当前的ucs进行绘制,避免坐标系没有对齐的问题
|
||||
let ucs = app.Editor.UCSMatrix;
|
||||
//对齐到pl0点
|
||||
matrixSetVector(ucs, 3, pl0.Position);
|
||||
let ucsinv = new Matrix4().getInverse(ucs);
|
||||
pls = pls.filter(pl => CurveInOCS(pl, ucs, ucsinv));
|
||||
for (let pl of pls)
|
||||
pl.Erase();
|
||||
|
||||
let backPls: Polyline[] = [];//背板 //下面会处理成带孩子们
|
||||
let facePls: Polyline[] = [];//条子或者地脚
|
||||
let otherPls: Polyline[] = [];//层板立板//下面会过滤掉被背板包含的
|
||||
for (let pl of pls)
|
||||
{
|
||||
pl.ApplyMatrix(ucsinv);
|
||||
let box = pl.BoundingBox;
|
||||
let size = box.getSize(new Vector3);
|
||||
pl.TempData = size;
|
||||
pl.TempData2 = box;
|
||||
if (this.IsBackBoard(size))
|
||||
backPls.push(pl);
|
||||
else if (this.IsFaceBoard(size))
|
||||
facePls.push(pl);
|
||||
else
|
||||
otherPls.push(pl);
|
||||
}
|
||||
|
||||
let backAndChildrens: Polyline[][] = [];//背板带着孩子们 [back,x,x,x,x][]
|
||||
for (let pl of backPls)
|
||||
{
|
||||
let g = [pl];
|
||||
otherPls = otherPls.filter(pln =>
|
||||
{
|
||||
if (this.IsPolyLineContain(pl, pln))
|
||||
{
|
||||
g.push(pln);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
backAndChildrens.push(g);
|
||||
}
|
||||
|
||||
//此时被剩下的otherpls 黄金圣斗士 孤立无援
|
||||
|
||||
//绘制空间坐标系
|
||||
this.SpaceOCS = ucs.clone();
|
||||
let y = new Vector3().setFromMatrixColumn(this.SpaceOCS, 1);
|
||||
let z = new Vector3().setFromMatrixColumn(this.SpaceOCS, 2);
|
||||
matrixSetVector(this.SpaceOCS, 1, z.negate());
|
||||
matrixSetVector(this.SpaceOCS, 2, y);
|
||||
|
||||
let allBoards: Board[] = [];
|
||||
|
||||
let layerVerBoards: Board[] = this.DrawBoard(otherPls);
|
||||
let tzdj = this.DrawBoard(facePls, false, 4);//条子或地脚板
|
||||
allBoards.push(...tzdj);
|
||||
|
||||
let backBoards: Board[] = [];
|
||||
for (let g of backAndChildrens)
|
||||
{
|
||||
let brs = this.DrawBoard(g, true);
|
||||
let br = brs.shift();
|
||||
backBoards.push(br);
|
||||
layerVerBoards.push(...brs);
|
||||
}
|
||||
|
||||
allBoards.push(...backBoards, ...layerVerBoards);
|
||||
|
||||
let m = new Matrix4;
|
||||
const CurtailFunc = (br: Board, curtail: number, changeWidth: boolean = true) =>
|
||||
{
|
||||
if (changeWidth)
|
||||
br.Width -= curtail;
|
||||
m.setPosition(0, curtail, 0);
|
||||
br.ApplyMatrix(m);
|
||||
};
|
||||
|
||||
//切割
|
||||
for (let br of layerVerBoards)
|
||||
{
|
||||
br.Subtract(backBoards);
|
||||
//柜体内缩
|
||||
CurtailFunc(br, this.fontDis);
|
||||
}
|
||||
for (let br of tzdj)
|
||||
{
|
||||
CurtailFunc(br, this.fontDis, false);
|
||||
}
|
||||
|
||||
//修改材料数据,封边数据,备注数据
|
||||
let storeOption = this.store.m_Option;
|
||||
allBoards.forEach((b) =>
|
||||
{
|
||||
b.KnifeRadius = this.knifeRadius;
|
||||
b.GroovesAddDepth = this.grooveDepth;
|
||||
b.GroovesAddWidth = this.grooveWidth;
|
||||
b.GroovesAddLength = this.grooveLength;
|
||||
b.BoardProcessOption.material = storeOption.material;
|
||||
b.BoardProcessOption.color = storeOption.color;
|
||||
b.BoardProcessOption.boardName = storeOption.boardMatName;
|
||||
b.BoardProcessOption.roomName = storeOption.roomName;
|
||||
b.BoardProcessOption.drillType = storeOption.drillType;
|
||||
b.BoardProcessOption.sealedUp = storeOption.sealedUp;
|
||||
b.BoardProcessOption.sealedDown = storeOption.sealedDown;
|
||||
b.BoardProcessOption.sealedLeft = storeOption.sealedLeft;
|
||||
b.BoardProcessOption.sealedRight = storeOption.sealedRight;
|
||||
let remarks: [string, string][] = [];
|
||||
for (let d of storeOption.remarks)
|
||||
{
|
||||
if (d[0] && d[1])
|
||||
remarks.push([d[0], d[1]]);
|
||||
}
|
||||
b.BoardProcessOption.remarks = remarks;
|
||||
});
|
||||
|
||||
let cabGroup: Board[][] = [];
|
||||
|
||||
if (!this.isMultiBackCab)
|
||||
{
|
||||
//这里我们开始分柜子,共有几个柜子?
|
||||
//1.将背板的范围拉大
|
||||
for (let pl of backPls)
|
||||
{
|
||||
let box = pl.TempData2 as Box3;
|
||||
let [x1, y1, x2, y2] = [box.min.x, box.min.y, box.max.x, box.max.y];
|
||||
let pts = [
|
||||
new Vector3(x1 - 50, y1),
|
||||
new Vector3(x1, y1 - 50),
|
||||
|
||||
new Vector3(x2 + 50, y2),
|
||||
new Vector3(x2, y2 + 50),
|
||||
];
|
||||
for (let p of pts)
|
||||
{
|
||||
let boxTemp = box.clone();
|
||||
boxTemp.expandByPoint(p);
|
||||
|
||||
//如果不相交则延伸成功
|
||||
if (!backPls.some(pl2 => { return pl2 !== pl && boxTemp.intersectsBox(pl2.TempData2); }))
|
||||
box = boxTemp;
|
||||
}
|
||||
pl.TempData2 = box;
|
||||
}
|
||||
|
||||
for (let pl of backPls)
|
||||
{
|
||||
let group: Polyline[] = [pl];
|
||||
let box1 = pl.TempData2 as Box3;
|
||||
pls = pls.filter(pln =>
|
||||
{
|
||||
if (pln === pl) return false;
|
||||
let box2 = pln.TempData2 as Box3;
|
||||
if (box1.intersectsBox(box2))
|
||||
{
|
||||
group.push(pln);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
cabGroup.push(group.map(pl => pl.TempData));
|
||||
}
|
||||
}
|
||||
else
|
||||
cabGroup = [allBoards];
|
||||
|
||||
let spaceInv = new Matrix4().getInverse(this.SpaceOCS);
|
||||
for (let i = 0; i < cabGroup.length; i++)
|
||||
{
|
||||
let group = cabGroup[i];
|
||||
|
||||
//改柜名
|
||||
if (storeOption.iscabinetName)
|
||||
{
|
||||
group.forEach((br) => { br.BoardProcessOption.cabinetName = storeOption.cabinetName + (this.isMultiBackCab ? "" : (i + 1)); });
|
||||
}
|
||||
//#region 这里我们开始解析板件类型
|
||||
//此时我们分析收口条和地脚线
|
||||
let skts: Board[] = [];//收口条
|
||||
let djxs: Board[] = [];//地脚
|
||||
|
||||
let topBoards: Board[] = [];//顶部的板
|
||||
let downBoards: Board[] = [];//底部的板
|
||||
|
||||
let leftBoards: Board[] = [];//左侧的立板
|
||||
let rightBoards: Board[] = [];//右侧的立板
|
||||
|
||||
let ordinarylays: Board[] = [];//普通的层板
|
||||
let ordinaryvers: Board[] = [];//普通的立板
|
||||
|
||||
let layers = group.filter(br => br.BoardType === BoardType.Layer);
|
||||
let vers = group.filter(br => br.BoardType === BoardType.Vertical);
|
||||
let backs = group.filter(br => br.BoardType === BoardType.Behind);
|
||||
|
||||
//左右侧板
|
||||
let left = Infinity;
|
||||
let right = - Infinity;
|
||||
for (let br of vers)
|
||||
{
|
||||
let p = br.MinPoint.applyMatrix4(spaceInv);
|
||||
if (p.x < left)
|
||||
left = p.x;
|
||||
if (p.x > right)
|
||||
right = p.x;
|
||||
}
|
||||
|
||||
for (let br of vers)
|
||||
{
|
||||
let p = br.MinPoint.applyMatrix4(spaceInv);
|
||||
if (equaln(p.x, left))
|
||||
leftBoards.push(br);
|
||||
else if (equaln(p.x, right))
|
||||
rightBoards.push(br);
|
||||
else
|
||||
ordinaryvers.push(br);
|
||||
}
|
||||
|
||||
//顶底板
|
||||
let top = -Infinity;
|
||||
let down = Infinity;
|
||||
for (let br of layers)
|
||||
{
|
||||
let p = br.MinPoint.applyMatrix4(spaceInv);
|
||||
if (p.z > top) top = p.z;
|
||||
if (p.z < down) down = p.z;
|
||||
}
|
||||
|
||||
for (let br of layers)
|
||||
{
|
||||
let p = br.MinPoint.applyMatrix4(spaceInv);
|
||||
if (equaln(p.z, top))
|
||||
topBoards.push(br);
|
||||
else if (equaln(p.z, down))
|
||||
downBoards.push(br);
|
||||
else
|
||||
ordinarylays.push(br);
|
||||
}
|
||||
|
||||
//收口条
|
||||
skts = backs.filter(br => br.ColorIndex === 4);
|
||||
|
||||
down = Infinity;
|
||||
for (let br of skts)
|
||||
{
|
||||
let p = br.MinPoint.applyMatrix4(spaceInv);
|
||||
if (p.z < down) down = p.z;
|
||||
}
|
||||
//地脚线
|
||||
arrayRemoveIf(skts, br =>
|
||||
{
|
||||
let isdjx = br.Width > br.Height && equaln(br.MinPoint.applyMatrix4(spaceInv).z, down);
|
||||
if (isdjx)
|
||||
djxs.push(br);
|
||||
return isdjx;
|
||||
});
|
||||
|
||||
//修改板名和前缩
|
||||
let curtail = 0;
|
||||
let leftrightbrs = [...leftBoards, ...rightBoards];//左右侧
|
||||
for (let i = 0; i < leftrightbrs.length; i++)
|
||||
{
|
||||
let br = leftrightbrs[i];
|
||||
if (i < leftrightbrs.length - 1)
|
||||
{
|
||||
if (storeOption.isfarLeftVerticalBrName)
|
||||
br.Name = storeOption.farLeftVerticalBrName;
|
||||
}
|
||||
else
|
||||
if (storeOption.isfarRightVerticalBrName)
|
||||
br.Name = storeOption.farRightVerticalBrName;
|
||||
br.ColorIndex = 1;
|
||||
}
|
||||
for (let br of ordinaryvers)//普通立板
|
||||
{
|
||||
CurtailFunc(br, storeOption.verticalBrShrink);
|
||||
}
|
||||
|
||||
let topbottombrs = [...topBoards, ...downBoards];//顶底板
|
||||
for (let i = 0; i < topbottombrs.length; i++)
|
||||
{
|
||||
let br = topbottombrs[i];
|
||||
if (i < topBoards.length)
|
||||
{
|
||||
if (storeOption.topMostLayerBrName)
|
||||
br.Name = storeOption.topMostLayerBrName;
|
||||
curtail = storeOption.topBrShrink;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (storeOption.bottomMostLayerBrName)
|
||||
br.Name = storeOption.bottomMostLayerBrName;
|
||||
curtail = storeOption.bottomBrShrink;
|
||||
}
|
||||
CurtailFunc(br, curtail);
|
||||
br.ColorIndex = 7;
|
||||
}
|
||||
for (let br of ordinarylays)//普通层板
|
||||
{
|
||||
CurtailFunc(br, storeOption.layerBrShrink);
|
||||
}
|
||||
|
||||
//地脚和收口条
|
||||
for (let br of djxs)
|
||||
{
|
||||
if (storeOption.bottomMostBackBrName)
|
||||
br.Name = storeOption.bottomMostBackBrName;
|
||||
CurtailFunc(br, storeOption.groundLineBrShrink, false);
|
||||
br.ColorIndex = 5;
|
||||
}
|
||||
for (let br of skts)
|
||||
{
|
||||
if (storeOption.isstripeBrName)
|
||||
br.Name = storeOption.stripeBrName;
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
DrawBoard(pls: Polyline[], isBack = false, color?: number): Board[]
|
||||
{
|
||||
let depth = this.boardDepth;
|
||||
if (isBack)
|
||||
depth -= this.backBoardMoveDis + this.backBoardThick;
|
||||
|
||||
let brs: Board[] = [];
|
||||
|
||||
for (let pl of pls)
|
||||
{
|
||||
let size = pl.TempData as Vector3;
|
||||
if (size.x < 1 || size.y < 1)
|
||||
{
|
||||
console.log("奇怪的矩形");
|
||||
continue;
|
||||
}
|
||||
let box = pl.TempData2 as Box3;
|
||||
let minp = box.min.clone();
|
||||
let br: Board;
|
||||
if (size.x > size.y && size.y < 50) //层板
|
||||
{
|
||||
br = Board.CreateBoard(size.x, depth, size.y, BoardType.Layer);
|
||||
[minp.x, minp.y, minp.z] = [minp.x + size.x, minp.z, minp.y];
|
||||
}
|
||||
else if (size.x < size.y && size.x < 50)//立板
|
||||
{
|
||||
br = Board.CreateBoard(size.y, depth, size.x, BoardType.Vertical);
|
||||
[minp.x, minp.y, minp.z] = [minp.x, minp.z, minp.y];
|
||||
}
|
||||
else
|
||||
{
|
||||
[minp.x, minp.y, minp.z] = [minp.x, minp.z + this.backBoardThick, minp.y];
|
||||
if (isBack)
|
||||
{
|
||||
minp.y += this.boardDepth - this.backBoardThick - this.backBoardMoveDis;//移动到后面
|
||||
|
||||
minp.x -= this.backLeftExtend;
|
||||
minp.z -= this.backDownExtend;
|
||||
|
||||
size.x += this.backLeftExtend + this.backRightExtend;
|
||||
size.y += this.backTopExtend + this.backDownExtend;
|
||||
}
|
||||
br = Board.CreateBoard(size.y, size.x, this.backBoardThick, BoardType.Behind);
|
||||
}
|
||||
let m = new Matrix4().setPosition(minp);
|
||||
br.ApplyMatrix(m);
|
||||
br.ApplyMatrix(this.SpaceOCS);
|
||||
if (color !== undefined) br.ColorIndex = color;
|
||||
app.Database.ModelSpace.Append(br);
|
||||
|
||||
brs.push(br);
|
||||
pl.TempData = br;
|
||||
}
|
||||
|
||||
return brs;
|
||||
}
|
||||
|
||||
//pl1是否包含pl2
|
||||
IsPolyLineContain(pl1: Polyline, pl2: Polyline)
|
||||
{
|
||||
let box1 = pl1.TempData2 as Box3;
|
||||
let box2 = pl2.TempData2 as Box3;
|
||||
let box = box1.clone().intersect(box2);
|
||||
let s = box.getSize(new Vector3);
|
||||
if (s.x < 1 || s.y < 1) return false;
|
||||
let int = pl1.IntersectWith(pl2, IntersectOption.OnBothOperands);
|
||||
return int.length > 0 || pl1.PtInCurve(pl2.StartPoint);
|
||||
}
|
||||
|
||||
//是否为一个背板的尺寸大小
|
||||
private IsBackBoard(size: Vector3): boolean
|
||||
{
|
||||
return size.x >= this.moveBackWidth && size.y >= this.moveBackLen;
|
||||
}
|
||||
|
||||
private IsFaceBoard(size: Vector3): boolean
|
||||
{
|
||||
return size.x >= 50 && size.y >= 50;
|
||||
}
|
||||
}
|
Loading…
Reference in new issue