!929 功能:矩形变板件,命令:c2r,r2b

pull/929/MERGE
ChenX 5 years ago
parent 1dcea0e6df
commit 85934cf911

@ -2,7 +2,7 @@
exports[`丢失线段板件 1`] = `554052.5007766776`;
exports[`丢失线段板件 2`] = `398758.87896958215`;
exports[`丢失线段板件 2`] = `398758.8789695821`;
exports[`常规板件,常规坐标系 1`] = `716404`;
@ -28,4 +28,4 @@ exports[`异型板件,非常规坐标系 3`] = `75694680.60847883`;
exports[`异型板件,非相切圆弧 1`] = `635612.2751433643`;
exports[`异型板件,非相切圆弧 2`] = `626242.2196800548`;
exports[`异型板件,非相切圆弧 2`] = `626242.2196800549`;

@ -20,7 +20,7 @@ test('直线相交,共线', () =>
expect(pts.length).toBe(0);
pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendBoth);//?
expect(pts.length).toBe(0);
expect(pts.length).toBe(4);
});

@ -342,10 +342,10 @@ exports[`连续丢圆弧后无法连接 10`] = `"574.66475"`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 1`] = `54789.24964851236`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 2`] = `54907.28173780604`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 2`] = `54907.28173780605`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 3`] = `55497.50212266886`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 3`] = `55497.50212266887`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 4`] = `56678.24106604484`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 4`] = `56678.241066044844`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 5`] = `57859.37443960544`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 5`] = `57859.37443960543`;

@ -14,7 +14,7 @@ exports[`补充bug测试#IKWGF 6`] = `0.6246933440840138`;
exports[`补充bug测试#IKWGF 7`] = `14.067113755971711`;
exports[`补充bug测试#IKWGF 8`] = `11.891017922899252`;
exports[`补充bug测试#IKWGF 8`] = `11.891017922899254`;
exports[`补充bug测试#IKWGF 9`] = `2.168984971098264`;

@ -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;
}
}

@ -14,6 +14,7 @@ export enum CheckObjectType
RLB = "rotateLayerBoard",
BBC = "boardbatchcurtail",
BBS = "lookoverboardinfos",
R2B = "rec2br",
OnlyNumber = "onlyNum",
None = "none",
}
@ -64,6 +65,10 @@ export namespace CheckoutValid
return !Object.keys(obj).every(k =>
CheckoutDrillOption(k, obj[k]) === ""
);
case CheckObjectType.R2B:
return !Object.keys(obj).every(k =>
CheckoutRec2BrOption(k, obj[k]) === ""
);
default:
return true;
}
@ -92,6 +97,8 @@ export namespace CheckoutValid
return CheckBoardBatchCurtail(k, v);
case CheckObjectType.BBS:
return CheckLookOverBoardInfos(k, v);
case CheckObjectType.R2B:
return CheckoutRec2BrOption(k, v);
case CheckObjectType.OnlyNumber:
if (!isNum(v))
return "数值不能为空且必须为数字";
@ -233,6 +240,46 @@ export namespace CheckoutValid
}
return "";
}
export function CheckoutRec2BrOption(k: string, v: string): string
{
let val = safeEval(v);
switch (k)
{
case "sealedUp":
case "sealedDown":
case "sealedLeft":
case "sealedRight":
case "knifeRadius":
case "cabinetDeep":
case "cabinetBrThick":
case "backBrThick":
if (isNaN(val))
return "数值不能为空且必须为数字";
if (!(val >= 0))
return "数值必须大于等于0";
return "";
case "cabinetCurtail":
case "backBrBiggerThanHeight":
case "backBrBiggerThanWidth":
case "backBrFrontMove":
case "backBrLeftExtend":
case "backBrRightExtend":
case "backBrUpExtend":
case "backBrDownExtend":
case "verticalBrShrink":
case "layerBrShrink":
case "bottomBrShrink":
case "topBrShrink":
case "groundLineBrShrink":
case "grooveAddLength":
case "grooveAddDepth":
case "grooveAddWidth":
if (isNaN(val))
return "数值不能为空且必须为数字";
default:
return "";
}
}
export function CheckoutArrayOption(k: string, v: string): string
{
switch (k)

@ -16,6 +16,8 @@ export abstract class CADObject
*
*/
public TempData: any;
public TempData2: any;
set Owner(owner: ObjectId)
{
this._Owner = owner;

@ -192,9 +192,7 @@ export class Circle extends Curve
GetParamAtPoint(pt?: Vector3)
{
if (!this.PtOnCurve(pt))
{
return NaN;
}
return angle(pt.clone().applyMatrix4(this.OCSInv)) / (Math.PI * 2);
}

@ -166,6 +166,10 @@ import { BuyMaterial } from './../Add-on/BuyMaterial';
import { Interfere } from './../Add-on/interfere';
import { ShowKinfeManageModal } from './../Add-on/showModal/ShowKnifeManageModal';
import { commandMachine } from './CommandMachine';
import { CreatePolyLineFromCurve } from "../Add-on/twoD2threeD/CreatePolyLineFromCurve";
import { RectConvertToBoard } from "../Add-on/twoD2threeD/RectConvertToBr";
import { Command_EraseLineAndArc } from "../Add-on/EraseLineAndArc";
import { Command_TestRegionParse } from "../Add-on/testEntity/TestRegionParse";
export function registerCommand()
{
@ -184,6 +188,7 @@ export function registerCommand()
commandMachine.RegisterCommand("dxf", new Command_DXFImport());
commandMachine.RegisterCommand("tt", new Test());
commandMachine.RegisterCommand("testRegionParse", new Command_TestRegionParse());
commandMachine.RegisterCommand("TestBoundaryBox", new Command_TestBoundaryBox());
commandMachine.RegisterCommand("insert", new Command_Insert());
@ -211,6 +216,7 @@ export function registerCommand()
commandMachine.RegisterCommand("Erase", new Command_Erase());
commandMachine.RegisterCommand("deletecurve", new DeleteCurve());
commandMachine.RegisterCommand("EraseLineArc", new Command_EraseLineAndArc());
commandMachine.RegisterCommand("c0", new DrawCircle0());
commandMachine.RegisterCommand("break", new Command_Break());
@ -460,6 +466,9 @@ export function registerCommand()
commandMachine.RegisterCommand("showknifeMg", new ShowKinfeManageModal());
commandMachine.RegisterCommand("showdoors", new Command_SwitchDoor(true));
commandMachine.RegisterCommand("hidedoors", new Command_SwitchDoor(false));
//线条变矩形
commandMachine.RegisterCommand("curve2rec", new CreatePolyLineFromCurve());
commandMachine.RegisterCommand("r2b", new RectConvertToBoard());
RegistCustomCommand();
}

@ -6,6 +6,7 @@ import { ILatticeOption, ELatticeArrayType } from "../UI/Store/LatticeInterface"
import { HandleVePos, DoorPosType, HandleHorPos, IDrawerConfigOption } from "../UI/Store/DoorInterface";
import { EBoardKeyList } from "../Common/BoardKeyList";
import { ICylMetalsOption, IExtMetalsOption, ICompHardwareOption, EMetalsType, IToplineOption } from "../UI/Components/RightPanel/RightPanelInterface";
import { Curve2RecOption } from "../Add-on/twoD2threeD/Modals/Curve2RecModal";
export const DefaultLayerBoardConfig: LayerBoardOption = {
version: 1,
@ -517,3 +518,13 @@ export const DefaultBoardProcessOption: BoardProcessOption = {
remarks: [],
};
Object.freeze(DefaultBoardProcessOption);
export const DefaultCurve2RecOption: Curve2RecOption = {
version: 1,
isSaveMax: false,
isSaveSmall: true,
width: 90,
isAnaly: true,
gap: 3
};
Object.freeze(DefaultCurve2RecOption);

@ -3,31 +3,28 @@ import { Curve } from "../DatabaseServices/Entity/Curve";
import { IntersectOption } from "../GraphicsSystem/IntersectWith";
/**
*
* 线, (33.2 线 p599)
*/
export class CurveIntersection
{
//用来缓存的曲线包围盒
private boxMap: Map<Curve, Box3> = new Map();
protected boxMap: Map<Curve, Box3> = new Map();
/**
* ,key 线 value (线Map)
*
* @type {Map<Curve, Map<Curve, Vector3[]>>}
* @memberof CurveIntersection
*/
intersect: Map<Curve, Map<Curve, Vector3[]>> = new Map();
intersect2: Map<Curve, number[]> = new Map();
/**
* @param {Curve[]} cus ,,
* @memberof CurveIntersection
*/
constructor(cus: Curve[])
constructor(cus: Curve[], parseIntersectionParam = false, intType = IntersectOption.OnBothOperands)
{
this.genBox(cus);
this.GenBox(cus);
//按x排序
this.sortCurve(cus);
this.SortCurve(cus);
let count = cus.length;
for (let i = 0; i < count; i++)
@ -48,24 +45,46 @@ export class CurveIntersection
if (c2b.min.y - c1b.max.y > 1e-6)
continue;
let pts = c1.IntersectWith(c2, IntersectOption.OnBothOperands);
if (pts.length > 0)
let ints = this.IntersectWith2(c1, c2, intType);
if (ints.length > 0)
{
let pts = ints.map(i => i.pt);
c1d.set(c2, pts);
this.GetIntersect(c2).set(c1, pts);
if (parseIntersectionParam)
{
this.AppendIntersectionParams(c1, ints.map(i => i.thisParam));
this.AppendIntersectionParams(c2, ints.map(i => i.argParam));
}
}
}
}
}
private genBox(cus: Curve[])
protected IntersectWith2(c1: Curve, c2: Curve, intType: IntersectOption)
{
return c1.IntersectWith2(c2, intType);
}
protected AppendIntersectionParams(curve: Curve, params: number[])
{
cus.forEach(c =>
let arr = this.intersect2.get(curve);
if (!arr)
{
arr = [];
this.intersect2.set(curve, arr);
}
arr.push(...params);
}
protected GenBox(cus: Curve[])
{
for (let c of cus)
this.boxMap.set(c, c.BoundingBox);
});
}
private sortCurve(cus: Curve[])
protected SortCurve(cus: Curve[])
{
cus.sort((c1, c2) =>
{

@ -55,7 +55,13 @@ export class CurveMap
return this._Vertices;
}
AddCurveToMap(curve: Curve, isArc: boolean = curve instanceof Arc, removeDuplicate: boolean = false)
/**
* @param curve
* @param [isArc=curve instanceof Arc]
* @param [removeDuplicate=false]
* @returns ?
*/
AddCurveToMap(curve: Curve, isArc: boolean = curve instanceof Arc, removeDuplicate: boolean = false): boolean
{
let sp = curve.StartPoint;
let ep = curve.EndPoint;
@ -64,7 +70,7 @@ export class CurveMap
//在面域分析中,路线指向同一个顶点已经没有意义了
if (this._RemoveSortLine && startS === endS)
return;
return false;
if (removeDuplicate)//删除重复
{
@ -77,7 +83,7 @@ export class CurveMap
return true;
}
});
if (index !== -1) return;
if (index !== -1) return false;
}
let length = curve.Length;
@ -94,6 +100,8 @@ export class CurveMap
}
startS.routes.push(routeS2E);
endS.routes.push(routeE2S);
return true;
}
/**

@ -233,7 +233,7 @@ export function IntersectLineAndArc(line: Line, arc: Arc, extType: IntersectOpti
return CheckPointOnCurve(ptArr, line, arc, extType, tolerance);
}
//直线和直线
export function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3, tolerance = 1e-6): Vector3
export function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3
{
let dx1 = p1.x - p2.x;
let dx2 = p3.x - p4.x;
@ -244,7 +244,6 @@ export function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: V
let det = (dx2 * dy1) - (dy2 * dx1);
let pt = new Vector3(0, 0, 0);
if (equaln(det, 0.0, 1e-5))
{
// if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))
@ -254,6 +253,7 @@ export function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: V
return;
}
let pt = new Vector3;
let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;
pt.x = (ratio * dx2) + p4.x;
pt.y = (ratio * dy2) + p4.y;
@ -261,6 +261,32 @@ export function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: V
return pt;
}
export function IntersectLAndLFor2D2(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3[]
{
let dx1 = p1.x - p2.x;
let dx2 = p3.x - p4.x;
let dx3 = p4.x - p2.x;
let dy1 = p1.y - p2.y;
let dy2 = p3.y - p4.y;
let dy3 = p4.y - p2.y;
let det = (dx2 * dy1) - (dy2 * dx1);
if (equaln(det, 0.0, 1e-5))
{
if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))
return [p1, p2, p3, p4];
return [];
}
let pt = new Vector3;
let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;
pt.x = (ratio * dx2) + p4.x;
pt.y = (ratio * dy2) + p4.y;
return [pt];
}
export function IntersectLine3AndLine3(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3, epsilon = 1e-6)
{
let pts = ShortestLine3AndLine3(p1, p2, p3, p4);
@ -320,43 +346,39 @@ function ShortestLine3AndLine3(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector
//直线和直线
export function IntersectLineAndLine(l1: Line, l2: Line, extType: IntersectOption, fuzz = 1e-4): IntersectResult[]
{
// if (l1.Is2D && l2.Is2D)
// {
// let p = IntersectLAndLFor2D(l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint);
// if (p) return [p];
// else return [];
// }
let [pt1, pt2, pt3, pt4] = [l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint];
let pts = ShortestLine3AndLine3(pt1, pt2, pt3, pt4);
if (!pts) return [];
let pt = pts[0];
let { closestPt: p1, param: param1 } = l1.GetClosestAtPoint(pt, true);
let { closestPt: p2, param: param2 } = l2.GetClosestAtPoint(pt, true);
if (!equalv3(pt, p1, fuzz) || !equalv3(pt, p2, fuzz))
return [];
if (!(extType & IntersectOption.ExtendThis
|| l1.ParamOnCurve(param1, 0)
|| equalv3(pt1, pt, fuzz)
|| equalv3(pt2, pt, fuzz)
))
return [];
if (!(extType & IntersectOption.ExtendArg
|| l2.ParamOnCurve(param2, 0)
|| equalv3(pt3, pt, fuzz)
|| equalv3(pt4, pt, fuzz)
))
return [];
let ipts: Vector3[];
if (equaln(pt1.z, 0, fuzz) && equaln(pt2.z, 0, fuzz) && equaln(pt3.z, 0, fuzz) && equaln(pt4.z, 0, fuzz))
{
ipts = IntersectLAndLFor2D2(pt1, pt2, pt3, pt4);
ipts.sort(comparePoint("xy"));
arrayRemoveDuplicateBySort(ipts, (p1, p2) => equalv3(p1, p2, fuzz));
}
else
{
ipts = ShortestLine3AndLine3(pt1, pt2, pt3, pt4);
if (!ipts) return [];
if (ipts.length === 2)
ipts.pop();
}
return [{
pt,
thisParam: param1,
argParam: param2
}];
let ints: IntersectResult[] = [];
for (let pt of ipts)
{
let { closestPt: p1, param: param1 } = l1.GetClosestAtPoint(pt, true);
if (!equalv3(pt, p1, fuzz)) return [];
if (!(extType & IntersectOption.ExtendThis))
if (!(l1.ParamOnCurve(param1, 0) || equalv3(pt1, pt, fuzz) || equalv3(pt2, pt, fuzz)))
return [];
let { closestPt: p2, param: param2 } = l2.GetClosestAtPoint(pt, true);
if (!equalv3(pt, p2, fuzz)) return [];
if (!(extType & IntersectOption.ExtendArg))
if (!(l2.ParamOnCurve(param2, 0) || equalv3(pt3, pt, fuzz) || equalv3(pt4, pt, fuzz)))
return [];
ints.push({ pt, thisParam: param1, argParam: param2 });
}
return ints;
}
export function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: IntersectOption, tolerance = 1e-6): IntersectResult[]

@ -40,6 +40,8 @@ export enum BoardModalType
CompMetals = "compmetals", //复合实体
ToplineMetals = "toplinemetals", //顶线五金
UserConfig = "userConfig", //用户配置
Curves2Rec = "curves2rec",//线条转矩形
Rec2Br = "rec2br"
}
export interface BoardModalProps
{

Loading…
Cancel
Save