!2031 功能:绘制门窗

pull/1921/MERGE
ChenX 2 years ago
parent 2bc2b2f56b
commit c38e8a2275

@ -180,7 +180,7 @@ exports[`精度不一致导致的错误 4`] = `"55.04455"`;
exports[`精度不一致导致的错误: 走刀数量 1`] = `4`;
exports[`超级复杂造型01 1`] = `"23338.03269"`;
exports[`超级复杂造型01 1`] = `"23338.03271"`;
exports[`超级复杂造型01 2`] = `"11855.39981"`;
@ -260,7 +260,7 @@ exports[`超级复杂造型01 39`] = `"34.11041"`;
exports[`超级复杂造型01 40`] = `"3.00516"`;
exports[`超级复杂造型01 41`] = `"3.00517"`;
exports[`超级复杂造型01 41`] = `"3.00516"`;
exports[`超级复杂造型01 42`] = `"15.55863"`;

@ -150,8 +150,9 @@ test('直线和圆相切', () =>
test("圆弧相交精度调整", () =>
{
let data = { "file": [2, "Arc", 8, 2, 134, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -30.303763742321802, 350.79539874943686, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -30.303763742321802, 350.79539874943686, 0, 1], 0, 2, 3.0000000000000084, 0, 1.686785963338877, false, "Arc", 8, 2, 135, false, 1, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.303763742321621, 213.47228144573236, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.303763742321621, 213.47228144573236, 0, 1], 0, 2, 141.25208333333353, 1.6629607907756918, 2.5287104082377034, false], "basePt": { "x": -129.84704567597646, "y": 294.72436477906575, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] };
let data =
{ "file": [2, "Arc", 8, 2, 134, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -30.303763742321802, 350.79539874943686, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -30.303763742321802, 350.79539874943686, 0, 1], 0, 2, 3.0000000000000084, 0, 1.686785963338877, false, "Arc", 8, 2, 135, false, 1, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.303763742321621, 213.47228144573236, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.303763742321621, 213.47228144573236, 0, 1], 0, 2, 141.25208333333353, 1.6629607907756918, 2.5287104082377034, false], "basePt": { "x": -129.84704567597646, "y": 294.72436477906575, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] };
let cus = LoadEntityFromFileData(data) as Array<Curve>;
let pts = cus[0].IntersectWith(cus[1], 0);
expect(pts.length).toBe(2);
let pts = cus[0].IntersectWith(cus[1], 0, 1e-5);
expect(pts.length).toBe(1);
});

@ -88,11 +88,11 @@ exports[`圆求交错误导致的线丢失 1`] = `4148.655275462343`;
exports[`圆求交错误导致的线丢失 2`] = `4425.280774659384`;
exports[`圆求交错误导致的线丢失 3`] = `4021.9003146960804`;
exports[`圆求交错误导致的线丢失 3`] = `4021.9003160283755`;
exports[`圆求交错误导致的线丢失 4`] = `4581.224228650708`;
exports[`圆求交错误导致的线丢失 5`] = `3900.6078799293005`;
exports[`圆求交错误导致的线丢失 5`] = `3900.6078808627653`;
exports[`圆求交错误导致的线丢失 6`] = `4757.468532252447`;
@ -100,17 +100,17 @@ exports[`圆求交错误导致的线丢失 7`] = `3783.7486269392593`;
exports[`圆求交错误导致的线丢失 8`] = `4972.012479701948`;
exports[`圆求交错误导致的线丢失 9`] = `1148.662629878697`;
exports[`圆求交错误导致的线丢失 9`] = `1148.6626298787855`;
exports[`圆求交错误导致的线丢失 10`] = `5979.881803017036`;
exports[`圆求交错误导致的线丢失 10`] = `5979.881810920421`;
exports[`圆求交错误导致的线丢失 11`] = `1049.9590630921507`;
exports[`圆求交错误导致的线丢失 11`] = `1049.959063092209`;
exports[`圆求交错误导致的线丢失 12`] = `6051.226633493529`;
exports[`圆求交错误导致的线丢失 12`] = `6051.226641876335`;
exports[`圆求交错误导致的线丢失 13`] = `722.4732418587947`;
exports[`圆求交错误导致的线丢失 14`] = `6316.980878376697`;
exports[`圆求交错误导致的线丢失 14`] = `6316.98088721295`;
exports[`复杂圆盘选点 1`] = `1`;
@ -184,7 +184,7 @@ exports[`简单图形因为点在线内算法错误导致的丢失 3`] = `7.1494
exports[`简单图形因为点在线内算法错误导致的丢失 4`] = `6.693604273021893`;
exports[`精度过高导致无法连接 1`] = `"6723.54634"`;
exports[`精度过高导致无法连接 1`] = `"6723.54642"`;
exports[`精度过高导致的曲线丢失 1`] = `1`;
@ -196,11 +196,11 @@ exports[`精度过高导致的曲线丢失 4`] = `"97661.61008"`;
exports[`精度过高导致直连失败 1`] = `1`;
exports[`精度过高导致直连失败 2`] = `"32040.01389"`;
exports[`精度过高导致直连失败 2`] = `"32040.01390"`;
exports[`精度过高导致直连失败 3`] = `1`;
exports[`精度过高导致直连失败 4`] = `"32045.24857"`;
exports[`精度过高导致直连失败 4`] = `"32045.24858"`;
exports[`精度过高导致连接失败 1`] = `1`;

@ -33,7 +33,6 @@
"@rollup/plugin-typescript": "^8.3.2",
"@types/blueimp-md5": "^2.18.0",
"@types/flatbush": "^3.3.0",
"@types/html-webpack-plugin": "^3.2.6",
"@types/jest": "^27.5.2",
"@types/jsdom": "^20.0.0",
"@types/node": "^17.0.41",

@ -6,6 +6,7 @@ import { HostApplicationServices } from '../../ApplicationServices/HostApplicati
import { arrayLast } from '../../Common/ArrayExt';
import { Draw } from '../../Common/Draw';
import { RoomHolePolyline } from '../../DatabaseServices/Room/Entity/Wall/Hole/RoomHolePolyline';
import { RoomWallArc } from '../../DatabaseServices/Room/Entity/Wall/RoomWallArc';
import { RoomWallBase, WallFaceType } from "../../DatabaseServices/Room/Entity/Wall/RoomWallBase";
import { RoomWallLine } from '../../DatabaseServices/Room/Entity/Wall/RoomWallLine';
import { ParseWallRange, RoomWallPlaceIHoleHelper } from '../../DatabaseServices/Room/ParseService/Hole/RoomWallPlaceIHoleHelper';
@ -19,6 +20,7 @@ import { PromptStatus } from '../../Editor/PromptResult';
import { Route } from '../../Geometry/CurveMap';
import { equalv3, midPoint } from '../../Geometry/GeUtils';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { ModalState } from '../../UI/Components/Modal/ModalInterface';
import { AppToaster } from '../../UI/Components/Toaster';
import { DynamicInputManage } from '../../UI/DynamicPrompt/DynamicInputManage';
import { PromptBlock } from '../../UI/DynamicPrompt/PromptBlock';
@ -76,13 +78,24 @@ export class Command_DrawHole implements Command
let dyn = new PromptBlock(DynamicInputManage.GetManage());
await this.do(dyn);
let state = await this.BeferDrawHole(this._DrawType);
if (state === ModalState.Ok)
{
let hole = await this.do(dyn);
if (hole) await this.AfterDrawHole(hole, this._DrawType);
}
dyn.Destroy();
app.Editor.GetPointServices.snapServices.Disabled = bak;
}
async do(dyn: PromptBlock)
//绘制洞之前,重载这个呼出对话框
async BeferDrawHole(drawHoleType: DrawHoleType): Promise<ModalState> { return ModalState.Ok; }
//绘制洞之后,设置
async AfterDrawHole(hole: RoomHolePolyline, drawHoleType: DrawHoleType) { }
async do(dyn: PromptBlock): Promise<RoomHolePolyline>
{
if (this._DrawType === DrawHoleType.I)//直线洞
{
@ -127,6 +140,9 @@ export class Command_DrawHole implements Command
{
preWall = d.wall;
//弧形墙不能画门
if (this._HoleIType === IHoleType.Door && preWall instanceof RoomWallArc) return;
let { wall, getParam, range } = d;
let wallLength = wall.Length;
let length = (range[1] - range[0]) * wallLength;
@ -249,6 +265,7 @@ export class Command_DrawHole implements Command
{
Draw(hole);
d.wall.RelevancyHoles.push(hole.Id);
return hole;
}
return;
}
@ -504,6 +521,8 @@ export class Command_DrawHole implements Command
wall.RelevancyHoles.push(hole.Id);
hole.RelevancyWalls.push(wall.Id);
}
return hole;
}
return;
}
@ -747,6 +766,7 @@ export class Command_DrawHole implements Command
wall.RelevancyHoles.push(hole.Id);
hole.RelevancyWalls.push(wall.Id);
}
return hole;
}
return;
}

@ -0,0 +1,74 @@
import { app } from "../../ApplicationServices/Application";
import { DuplicateRecordCloning } from "../../Common/Status";
import { RoomHolePolyline } from "../../DatabaseServices/Room/Entity/Wall/Hole/RoomHolePolyline";
import { DrawDoorWindowPanel } from "../../DatabaseServices/Room/Entity/Wall/Hole/Window/DrawWindowPanel";
import { DoorWindowPanelStore } from "../../DatabaseServices/Room/Entity/Wall/Hole/Window/WindowPanelStore";
import { TemplateRoomDoorRecord } from "../../DatabaseServices/Template/ProgramTempate/TemplateRoomDoorRecord";
import { GetOnlineTemplate } from "../../DatabaseServices/Template/TempateUtils";
import { TemplateRecord } from "../../DatabaseServices/Template/TemplateRecord";
import { ModalState } from "../../UI/Components/Modal/ModalInterface";
import { Command_DrawHole, DrawHoleType, IHoleType } from "./DrawHole";
export class Command_DrawRoomDoor extends Command_DrawHole
{
constructor(drawType: DrawHoleType, holeIType: IHoleType, private _IsOneKeyDraw: boolean = false)
{
super(drawType, holeIType);
}
//一键画门配置
async SetStoreParam(store: DoorWindowPanelStore) { }
override async BeferDrawHole(drawHoleType: DrawHoleType): Promise<ModalState>
{
//呼出对话框
let store = DoorWindowPanelStore.GetSingleInstance();
store.m_Option.Height = 2200;
store.m_Option.Length = 800;
if (this._IsOneKeyDraw)
{
store.InitOption();
this.SetStoreParam(store);
}
else
{
app.Editor.ModalManage.RenderModal(DrawDoorWindowPanel, { store, drawHoleType, holeIType: IHoleType.Door });
let state = await app.Editor.ModalManage.Wait();
if (state.Status !== ModalState.Ok)
return ModalState.Cancel;
}
this.holeLength = store.m_Option.Length;
this.holeHeight = store.m_Option.Height;
return ModalState.Ok;
}
override async AfterDrawHole(hole: RoomHolePolyline): Promise<void>
{
let store = DoorWindowPanelStore.GetSingleInstance();
let tr = new TemplateRoomDoorRecord();//顶层节点
tr.HoleObjectId = hole.Id;
tr.InitBaseParams();
tr.InitHoleParams();
tr.GetParam("L").expr = store.m_Option.Length;
tr.GetParam("H").expr = store.m_Option.Height;
tr.DoorLogo = store.currentDoorWindowsInfo?.temp?.logo;
app.Database.TemplateTable.Add(tr);
hole.Template = tr.Id;
let doorTr = await GetOnlineTemplate(store.currentDoorWindowsInfo?.temp?.id || "11777"); //窗户模板 默认ID:11777
for (let w of hole.FakerWalls)
{
let template = app.Database.WblockCloneObejcts([doorTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
tr.Children.push(template.Id);
}
await tr.UpdateTemplateTree();
}
}

@ -0,0 +1,148 @@
import { app } from "../../ApplicationServices/Application";
import { DuplicateRecordCloning } from "../../Common/Status";
import { RoomHolePolyline } from "../../DatabaseServices/Room/Entity/Wall/Hole/RoomHolePolyline";
import { DrawDoorWindowPanel } from "../../DatabaseServices/Room/Entity/Wall/Hole/Window/DrawWindowPanel";
import { DoorWindowPanelStore } from "../../DatabaseServices/Room/Entity/Wall/Hole/Window/WindowPanelStore";
import { RoomWallArc } from "../../DatabaseServices/Room/Entity/Wall/RoomWallArc";
import { TemplateArcWindowRecord } from "../../DatabaseServices/Template/ProgramTempate/TemplateArcWindowRecord";
import { TemplateWindowRecord } from "../../DatabaseServices/Template/ProgramTempate/TemplateWindowRecord";
import { GetOnlineTemplate } from "../../DatabaseServices/Template/TempateUtils";
import { TemplateRecord } from "../../DatabaseServices/Template/TemplateRecord";
import { ModalState } from "../../UI/Components/Modal/ModalInterface";
import { Command_DrawHole, DrawHoleType, IHoleType } from "./DrawHole";
export class Command_DrawRoomWindow extends Command_DrawHole
{
constructor(drawType: DrawHoleType, holeIType: IHoleType, private _IsOneKeyDraw: boolean = false)
{
super(drawType, holeIType);
}
//一键绘制窗户配置
async SetStoreParam(store: DoorWindowPanelStore) { }
override async BeferDrawHole(drawHoleType: DrawHoleType): Promise<ModalState>
{
//呼出对话框
let store = DoorWindowPanelStore.GetSingleInstance();
if (this._IsOneKeyDraw)
{
store.InitOption();
this.SetStoreParam(store);
}
else
{
app.Editor.ModalManage.RenderModal(DrawDoorWindowPanel, { store, drawHoleType, holeIType: IHoleType.Window });
let state = await app.Editor.ModalManage.Wait();
if (state.Status !== ModalState.Ok)
return ModalState.Cancel;
}
this.holeLength = store.m_Option.Length;
this.holeHeight = store.m_Option.Height;
this.offGround = store.m_Option.WindowOffGround;
return ModalState.Ok;
}
override async AfterDrawHole(hole: RoomHolePolyline, drawHoleType: DrawHoleType): Promise<void>
{
let store = DoorWindowPanelStore.GetSingleInstance();
let tr = new TemplateWindowRecord();//顶层节点
tr.HoleObjectId = hole.Id;
tr.InitBaseParams();
tr.InitHoleParams();
tr.GetParam("WZ").expr = 25;//位置
tr.GetParam("L").expr = store.m_Option.Length;
tr.GetParam("H").expr = store.m_Option.Height;
if (drawHoleType === DrawHoleType.I)
{
if (store.m_Option.BayDist <= 1)
store.m_Option.IsBayWindow = false;
tr.GetParam("WP").expr = store.m_Option.IsBayWindow ? store.m_Option.BayDist : 0;
}
else if (drawHoleType === DrawHoleType.L)
{
store.m_Option.IsBayWindow = store.m_Option.IsBayWindow && hole.FakerWalls.every(wall => !(wall instanceof RoomWallArc));
tr.GetParam("ZWP").expr = store.m_Option.IsBayWindow ? store.m_Option.BayLeftDist : 0;
tr.GetParam("YWP").expr = store.m_Option.IsBayWindow ? store.m_Option.BayRightDist : 0;
}
else if (drawHoleType === DrawHoleType.U)
{
store.m_Option.IsBayWindow = store.m_Option.IsBayWindow && hole.FakerWalls.every(wall => !(wall instanceof RoomWallArc));
tr.GetParam("ZWP").expr = store.m_Option.IsBayWindow ? store.m_Option.BayLeftDist : 0;
tr.GetParam("MWP").expr = store.m_Option.IsBayWindow ? store.m_Option.BayMiddleDist : 0;
tr.GetParam("YWP").expr = store.m_Option.IsBayWindow ? store.m_Option.BayRightDist : 0;
}
tr.GetParam("CTS").expr = store.m_Option.HasWindowStone ? 1 : 0;
if (store.m_Option.HasWindowStone)
{
tr.GetParam("CTSH").expr = store.m_Option.StoneThick;
tr.GetParam("CTSTC").expr = store.m_Option.StoneBulge;
tr.GetParam("CTSZYTC").expr = store.m_Option.StoneLeftRightBulge;
}
tr.LeftIsWall = store.m_Option.IsBayWindow ? store.m_Option.BayLeftIsWall : true;
tr.RightIsWall = store.m_Option.IsBayWindow ? store.m_Option.BayRightIsWall : true;
tr.WindowLogo = store.currentDoorWindowsInfo?.temp?.logo;
app.Database.TemplateTable.Add(tr);
hole.Template = tr.Id;
let windowTr = await GetOnlineTemplate(store.currentDoorWindowsInfo?.temp?.id || "11777"); //窗户模板 默认ID:11777
//左飘窗
if (store.m_Option.IsBayWindow)
{
let leftWindowTemplateId = store.currentLeftBayWindowsInfo?.temp?.id || "11777";//窗户模板 默认ID:11777
tr.LeftWindowLogo = store.currentLeftBayWindowsInfo?.temp?.logo;
tr.LeftWindowTemplateId = leftWindowTemplateId;
if (!tr.LeftIsWall)
{
let leftWindowTr = await GetOnlineTemplate(leftWindowTemplateId);
let template = app.Database.WblockCloneObejcts([leftWindowTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
tr.Children.push(template.Id);
}
}
for (let i = 0; i < hole.FakerWalls.length; i++)
{
if (hole.FakerWalls[i] instanceof RoomWallArc)
{
let template = new TemplateArcWindowRecord();
template.InitBaseParams();
app.Database.TemplateTable.Add(template);
template.InitWindowFrame(hole, i);
tr.Children.push(template.Id);
}
else
{
let template = app.Database.WblockCloneObejcts([windowTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
tr.Children.push(template.Id);
}
}
//右飘窗
if (store.m_Option.IsBayWindow)
{
let rightWindowTemplateId = store.currentRightBayWindowsInfo?.temp?.id || "11777";//窗户模板 默认ID:11777
tr.RightWindowLogo = store.currentRightBayWindowsInfo?.temp?.logo;
tr.RightWindowTemplateId = rightWindowTemplateId;
if (!tr.RightIsWall)
{
let rightWindowTr = await GetOnlineTemplate(rightWindowTemplateId);
let template = app.Database.WblockCloneObejcts([rightWindowTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
tr.Children.push(template.Id);
}
}
await tr.UpdateTemplateTree();
}
}

@ -0,0 +1,74 @@
import { DoorWindowPanelStore } from "../../DatabaseServices/Room/Entity/Wall/Hole/Window/WindowPanelStore";
import { Command_DrawRoomDoor } from "./DrawRoomDoor";
import { Command_DrawRoomWindow } from "./DrawRoomWindow";
export class Command_OneKeyDrawYZCWindow extends Command_DrawRoomWindow
{
override async SetStoreParam(store: DoorWindowPanelStore): Promise<void>
{
//一字窗
store.m_Option.Length = 1800;
store.m_Option.Height = 1500;
store.m_Option.Thick = 280;
store.m_Option.IsBayWindow = false;
}
}
export class Command_OneKeyDrawLDCWindow extends Command_DrawRoomWindow
{
override async SetStoreParam(store: DoorWindowPanelStore): Promise<void>
{
//落地窗
store.m_Option.Length = 3000;
store.m_Option.Height = 2000;
store.m_Option.Thick = 280;
store.m_Option.WindowOffGround = 0;
store.m_Option.IsBayWindow = false;
}
}
export class Command_OneKeyDrawPCWindow extends Command_DrawRoomWindow
{
override async SetStoreParam(store: DoorWindowPanelStore): Promise<void>
{
//飘窗
store.m_Option.Length = 1900;
store.m_Option.Height = 1750;
store.m_Option.BayDist = 600;
store.m_Option.IsBayWindow = true;
}
}
export class Command_OneKeyDrawZJCWindow extends Command_DrawRoomWindow
{
override async SetStoreParam(store: DoorWindowPanelStore): Promise<void>
{
//转角窗
store.m_Option.Height = 1500;
store.m_Option.IsBayWindow = false;
store.m_Option.BayLeftIsWall = true;
store.m_Option.BayRightIsWall = true;
}
}
export class Command_OneKeyDrawZJPCWindow extends Command_DrawRoomWindow
{
override async SetStoreParam(store: DoorWindowPanelStore): Promise<void>
{
//转角飘窗
store.m_Option.Height = 1500;
store.m_Option.IsBayWindow = true;
store.m_Option.BayLeftDist = 600;
store.m_Option.BayRightDist = 600;
}
}
export class Command_OneKeyDrawYJHMWindow extends Command_DrawRoomDoor
{
override async SetStoreParam(store: DoorWindowPanelStore): Promise<void>
{
//一键画门
store.m_Option.Height = 2200;
store.m_Option.Length = 800;
}
}

@ -1,4 +1,9 @@
import { app } from "../../ApplicationServices/Application";
import { Entity } from "../../DatabaseServices/Entity/Entity";
import { RoomHolePolyline } from "../../DatabaseServices/Room/Entity/Wall/Hole/RoomHolePolyline";
import { TemplateArcWindowRecord } from "../../DatabaseServices/Template/ProgramTempate/TemplateArcWindowRecord";
import { Command } from "../../Editor/CommandMachine";
import { PromptStatus } from "../../Editor/PromptResult";
import { HotCMD } from "../../Hot/HotCommand";
@ -7,5 +12,14 @@ export class Test implements Command
{
async exec()
{
let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Entity] } });
if (enRes.Status !== PromptStatus.OK) return;
let hole = enRes.Entity as RoomHolePolyline;
let tr = new TemplateArcWindowRecord();//顶层节点
tr.InitBaseParams();
app.Database.TemplateTable.Add(tr);
await tr.UpdateTemplateTree();
}
}

@ -312,7 +312,20 @@ export enum CommandNames
DrawIHole = "DRAWIHOLE",
DrawLHole = "DRAWLHOLE",
DrawUHole = "DRAWUHOLE",
DrawIDoor = "DRAWIDOOR",//画门
DrawIWindow = "DRAWIWINDOW",
DrawLWindow = "DRAWLWINDOW",
DrawUWindow = "DRAWUWINDOW",//弧形U型窗
DrawUWindow2 = "DRAWUWINDOW2",//圆角U型窗
DrawDoorHole = "DRAWDOORHOLE", //画门洞
//一键画门窗
YZC = "YZC",//一字窗
LDC = "LDC",//落地窗
PC = "PC",//飘窗
ZJC = "ZJC",//转角窗
ZJPC = "ZJPC", //转角飘窗
YJHM = "YJHM",//一键画门
Gallery = "GALLERY", //打开画廊
}

@ -6,7 +6,7 @@ import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { Box3Ext } from '../../Geometry/Box';
import { angle, AsVector3, clampRad, equaln, equalv2, equalv3, MoveMatrix, polar, ZeroVec } from '../../Geometry/GeUtils';
import { Orbit } from '../../Geometry/Orbit';
import { IntersectArcAndArc, IntersectCircleAndArc, IntersectEllipseAndCircleOrArc, IntersectLineAndArc, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';
import { IntersectArcAndArc, IntersectCircleAndArc, IntersectEllipseAndCircleOrArc, IntersectLineAndArc, IntersectOption, IntersectPolylineAndCurve, IntersectResult, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';
import { Factory } from '../CADFactory';
import { CADFiler } from '../CADFiler';
import { Shape2 } from '../Shape2';
@ -491,11 +491,11 @@ export class Arc extends Curve
return this;
}
IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-4)
IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-4): IntersectResult[]
{
if (curve instanceof Arc || curve.constructor.name === "RoomWallArc")
{
return IntersectArcAndArc(this, curve as Arc, intType);
return IntersectArcAndArc(this, curve as Arc, intType, tolerance);
}
if (curve instanceof Line || curve.constructor.name === "RoomWallLine")
{

@ -215,26 +215,26 @@ export class Circle extends Curve
return [];
}
override IntersectWith2(curve: Curve, intType: IntersectOption): IntersectResult[]
override IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-5): IntersectResult[]
{
if (curve instanceof Arc)
{
return IntersectCircleAndArc(this, curve, intType);
return IntersectCircleAndArc(this, curve, intType, tolerance);
}
if (curve instanceof Line)
{
return SwapParam(IntersectLineAndCircle(curve, this, reverseIntersectOption(intType)));
return SwapParam(IntersectLineAndCircle(curve, this, reverseIntersectOption(intType), tolerance));
}
if (curve instanceof Circle)
{
return IntersectCircleAndCircle(this, curve);
return IntersectCircleAndCircle(this, curve, tolerance);
}
if (curve instanceof Ellipse)
{
return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));
}
if (curve instanceof Polyline)
return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType)));
return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));
return [];
}
//******************** Curve function end*****************//

@ -1,18 +1,21 @@
import { Face3, Geometry, LineSegments, Matrix3, Mesh, Object3D, ShapeUtils, Vector2, Vector3 } from "three";
import { arrayPushArray } from "../../../../../Common/ArrayExt";
import { arrayLast, arrayPushArray } from "../../../../../Common/ArrayExt";
import { ColorMaterial } from "../../../../../Common/ColorPalette";
import { ObjectSnapMode } from "../../../../../Editor/ObjectSnapMode";
import { Box3Ext } from "../../../../../Geometry/Box";
import { CreatePolylinePath } from "../../../../../Geometry/CreatePolylinePath";
import { AsVector3, equalv2, ZAxis } from "../../../../../Geometry/GeUtils";
import { IntersectOption } from "../../../../../GraphicsSystem/IntersectWith";
import { RenderType } from "../../../../../GraphicsSystem/RenderType";
import { Factory } from "../../../../CADFactory";
import { CADFiler } from "../../../../CADFiler";
import { CADObject } from "../../../../CADObject";
import { Arc } from "../../../../Entity/Arc";
import { Curve } from "../../../../Entity/Curve";
import { Line } from "../../../../Entity/Line";
import { Polyline } from "../../../../Entity/Polyline";
import { LEFT_ROTATE_MTX2 } from "../../../ParseService/GetCurveParam";
import { RoomWallArc } from "../RoomWallArc";
import { RoomWallBase } from "../RoomWallBase";
import { RoomWallLine } from "../RoomWallLine";
import { RoomHoleBase } from "./RoomHoleBase";
@ -34,6 +37,11 @@ export class RoomHolePolyline extends RoomHoleBase
//虽然使用了三维的点,但是我们实际使用的是二维的点 z总是等于0
private _Points: Vector3[] = [];
private _FakerWalls: RoomWallBase[] = [];
private _WpDists: number[];//外飘距离
private _WpLeftWall = false;
private _WpRightWall = false;
get FakerWalls(): RoomWallBase[] { return this._FakerWalls; }
public set FakerWalls(_FakerWalls: RoomWallBase[])
{
this._FakerWalls = _FakerWalls;
@ -44,16 +52,141 @@ export class RoomHolePolyline extends RoomHoleBase
arrayPushArray(this.LidCurves, w.LidCurves);
if (w.Region)
this.Regions.push(w.Region);
w.OCSNoClone.elements[14] = this._Matrix.elements[14];
w.Z = this.Z;
w.Height = this.Height;
if (w instanceof RoomWallLine && w.Length > 1e-6)
w.UpdateOCSToMinBox();
}
this.UpdateWpDraw();
}
get FakerWalls(): RoomWallBase[] { return this._FakerWalls; }
constructor() { super(); }
set WpDist(wpdists: number[])
{
this.WriteAllObjectRecord();
this._WpDists = wpdists;
this.FakerWalls = this._FakerWalls;//这样是保险的 为了避免wpdist = undefine
this.Update();
}
get WpDist() { return this._WpDists; }
get WpLeftWall() { return this._WpLeftWall; }
get WpRightWall() { return this._WpRightWall; }
set WpLeftWall(v)
{
if (v === this._WpLeftWall) return;
this.WriteAllObjectRecord();
this._WpLeftWall = v;
this.Update();
}
set WpRightWall(v)
{
if (v === this._WpRightWall) return;
this.WriteAllObjectRecord();
this._WpRightWall = v;
this.Update();
}
UpdateWpDraw()
{
//外飘
if (this._WpDists?.length === this._FakerWalls.length)
{
this.LidCurves = this.LidCurves.map(c => c.Clone());//拷贝一份 避免修改源数据
if (this._WpLeftWall)
this.LidCurves[0].StartPoint = this.LidCurves[0].GetPointAtDistance(-this._WpDists[0]);
if (this._WpRightWall)
this.LidCurves[1].EndPoint = this.LidCurves[1].GetPointAtDistance(this._WpDists[this._WpDists.length - 1] + this.LidCurves[1].Length);
this.Regions = [this.GetWpRegion(this._WpDists)];
}
}
/**
*
*
* @param wpdists
* @cts
*/
GetWpRegion(wpdists: number[], cts: number = 0, ctszytc: number = 0): Polyline
{
let leftCurves: Curve[] = [];
let rightCurves: Curve[] = [];
let wallCurves = this._FakerWalls.map((w: (RoomWallLine | RoomWallArc)) => w instanceof RoomWallLine ? new Line(w.StartPoint, w.EndPoint) : new Arc(w.Center, w.Radius, w.StartAngle, w.EndAngle, w.IsClockWise));
if (ctszytc)//窗台石左右延伸
{
wallCurves[0].StartPoint = wallCurves[0].GetPointAtDistance(-ctszytc);
let lastW = arrayLast(this._FakerWalls);
let lastC = arrayLast(wallCurves);
lastC.EndPoint = lastC.GetPointAtDistance(lastW.Length + ctszytc);
}
for (let i = 0; i < this._FakerWalls.length; i++)
{
let w = this._FakerWalls[i] as (RoomWallLine | RoomWallArc);
let c = wallCurves[i];//曲线
let d = wpdists[i];//外飘距离
if (w instanceof RoomWallArc && d > 0)
{
//弧形墙凸出的一边为窗外
leftCurves.push(c.GetOffsetCurves((w.Thickness * 0.5 + cts) * (w.IsClockWise ? 1 : -1))[0]);
rightCurves.push(c.GetOffsetCurves((w.Thickness * 0.5 + d) * (w.IsClockWise ? -1 : 1))[0]);
}
else
{
leftCurves.push(c.GetOffsetCurves((w.Thickness * 0.5 + cts))[0]);
rightCurves.push(c.GetOffsetCurves(-(w.Thickness * 0.5 + d))[0]);
}
}
//获取合适相交点
const getMinDistPoint = (pts: Vector3[], refer: Vector3) =>
{
let pt = pts[0];
let length = refer.distanceTo(pt);
for (let y = 1; y < pts.length; y++)
{
if (refer.distanceTo(pts[y]) < length)
pt = pts[y];
}
return pt;
};
for (let i = 1; i < leftCurves.length; i++)
{
let pre = leftCurves[i - 1];
let now = leftCurves[i];
let iPt = getMinDistPoint(pre.IntersectWith(now, IntersectOption.ExtendBoth), now.StartPoint);
pre.EndPoint = iPt;
now.StartPoint = iPt;
}
for (let i = 1; i < rightCurves.length; i++)
{
let pre = rightCurves[i - 1];
let now = rightCurves[i];
let iPt = getMinDistPoint(pre.IntersectWith(now, IntersectOption.ExtendBoth), now.StartPoint);
pre.EndPoint = iPt;
now.StartPoint = iPt;
}
let curves: Curve[] = [new Line(rightCurves[0].StartPoint, leftCurves[0].StartPoint)];
arrayPushArray(curves, leftCurves);
curves.push(new Line(arrayLast(leftCurves).EndPoint, arrayLast(rightCurves).EndPoint));
arrayPushArray(curves, rightCurves.reverse());
let polyline = Polyline.Combine(curves, 1e-3);
return polyline;
}
override get BoundingBoxInOCS(): Box3Ext
{
@ -65,6 +198,8 @@ export class RoomHolePolyline extends RoomHoleBase
return new Box3Ext().copy(this.BoundingBox).applyMatrix4(this.OCSInv);
}
get PointsCount() { return this._Points.length; }
get Points() { return this._Points.map(p => p.clone().applyMatrix4(this.OCSNoClone)); }
set Points(pts: Vector3[])
{
@ -435,11 +570,27 @@ export class RoomHolePolyline extends RoomHoleBase
let p = new Vector3(file.Read(), file.Read(), 0);
this._Points.push(p);
}
if (ver > 1)
{
this._WpDists = [];
count = file.Read();
for (let i = 0; i < count; i++)
this._WpDists.push(file.Read());
}
if (ver > 2)
{
let wpLeftRightWall = file.Read() as number;
this._WpLeftWall = (wpLeftRightWall & 1) !== 0;
this._WpRightWall = (wpLeftRightWall & 2) !== 0;
}
}
//对象将自身数据写入到文件.
override WriteFile(file: CADFiler)
{
file.Write(1);
file.Write(3);
super.WriteFile(file);
file.Write(this._Points.length);
@ -448,6 +599,16 @@ export class RoomHolePolyline extends RoomHoleBase
file.Write(p.x);
file.Write(p.y);
}
file.Write(this._WpDists?.length ?? 0);
if (this._WpDists)
for (let d of this._WpDists)
file.Write(d);
let wpLeftRightWall = 0;
if (this._WpLeftWall) wpLeftRightWall = 1;
if (this._WpRightWall) wpLeftRightWall += 2;
file.Write(wpLeftRightWall);
}
//局部撤销
ApplyPartialUndo(undoData: CADObject)

@ -0,0 +1,295 @@
import { Button, Checkbox, Classes, Collapse, Divider, Icon } from "@blueprintjs/core";
import { observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import ReactDOM from "react-dom";
import { DrawHoleType, IHoleType } from "../../../../../../Add-on/Room/DrawHole";
import { app } from "../../../../../../ApplicationServices/Application";
import { ModalState } from "../../../../../../UI/Components/Modal/ModalInterface";
import { Location } from "../../../../../../UI/Components/ToolBar/ModifyModel/RoomBaseParams";
import { DoorWindowPanelStore, DoorWindowParamsNames } from "./WindowPanelStore";
import { WindowParamsComponent } from "./WindowParamsComponent";
import { DrawWindowTempInfo } from "./WindowTempInfo";
import { WindowTempSelect } from "./WindowTempSelect";
export enum Visibility
{
Visible = "visible",
Hidden = "hidden",
}
@observer
export class DrawDoorWindowPanel extends React.Component<{ store: DoorWindowPanelStore; drawHoleType: DrawHoleType; holeIType: IHoleType; }>
{
private _CameraStateContainer: HTMLElement;
private startLocation = observable.box(Location.Middle);
constructor(props)
{
super(props);
this._CameraStateContainer = document.createElement('div');
this._CameraStateContainer.id = 'template-select';
this._CameraStateContainer.style.zIndex = "99";
document.getElementById('modal').appendChild(this._CameraStateContainer);
if (window.screen.width <= 1450)
this._CameraStateContainer.style.left = '120px';
else
this._CameraStateContainer.style.left = `calc(50vw - 650px)`;
if (window.screen.height <= 750)
this._CameraStateContainer.style.top = `0px`;
else
this._CameraStateContainer.style.top = `calc(50vh - 425px)`;
this._CameraStateContainer.style.visibility = Visibility.Hidden;
ReactDOM.render(<WindowTempSelect
selectDiv={this._CameraStateContainer}
store={this.props.store}
filter={["门窗"]}
location={this.startLocation}
/>, this._CameraStateContainer);
}
componentWillUnmount()
{
document.getElementById('modal').removeChild(this._CameraStateContainer);
this._CameraStateContainer = undefined;
}
private startSelectTemplate(style: Visibility)
{
this._CameraStateContainer.style.visibility = style;
};
render()
{
let store = this.props.store;
return (
<div id="commonModal" className={Classes.DIALOG_CONTAINER}>
<div id="DrawWindowPanel" className={Classes.DIALOG} style={{ height: "100%" }}>
<div className={Classes.DIALOG_HEADER} data-id="dragArea">
<Icon icon="widget" iconSize={18} />
<h4 className={Classes.HEADING}></h4>
<Button
icon="cross"
aria-label="Close"
minimal={true}
onClick={() => { app.Editor.ModalManage.Destory(); }}
/>
</div>
<div className={Classes.DIALOG_BODY}>
<div className='windowInfo'>
<DrawWindowTempInfo
store={store}
logo={this.props.store.currentDoorWindowsInfo?.temp?.logo}
showSizeInfo
startLocation={this.startLocation}
location={Location.Middle}
interactive
selectDiv={this._CameraStateContainer}
/>
</div>
<div className='paramsSize'>
{
this.props.drawHoleType === DrawHoleType.I &&
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.Length}
sliderMin={100}
sliderMax={5000}
title={"宽度"}
/>
}
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.Height}
sliderMin={100}
sliderMax={5000}
title={"高度"}
/>
{
this.props.holeIType === IHoleType.Window && <WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.WindowOffGround}
sliderMin={0}
sliderMax={5000}
title={"离地"}
/>
}
</div>
{
this.props.holeIType === IHoleType.Window && <div>
<Divider />
<div className="bayWindow">
<Checkbox
label="飘窗"
checked={this.props.store.m_Option.IsBayWindow}
onChange={() =>
{
this.props.store.m_Option.IsBayWindow = !this.props.store.m_Option.IsBayWindow;
}}
/>
<Collapse isOpen={this.props.store.m_Option.IsBayWindow}>
<div className="bayWindowParam">
<Checkbox
label="飘窗左侧是墙"
checked={this.props.store.m_Option.BayLeftIsWall}
onChange={() =>
{
this.props.store.m_Option.BayLeftIsWall = !this.props.store.m_Option.BayLeftIsWall;
}}
/>
<Checkbox
label="飘窗右侧是墙"
checked={this.props.store.m_Option.BayRightIsWall}
onChange={() =>
{
this.props.store.m_Option.BayRightIsWall = !this.props.store.m_Option.BayRightIsWall;
}}
/>
</div>
<div style={{ display: "flex", justifyContent: "space-around" }}>
<DrawWindowTempInfo
store={store}
logo={store.currentLeftBayWindowsInfo?.temp?.logo}
interactive={!store.m_Option.BayLeftIsWall}
selectDiv={this._CameraStateContainer}
startLocation={this.startLocation}
location={Location.Left}
/>
<DrawWindowTempInfo
store={store}
logo={store.currentRightBayWindowsInfo?.temp?.logo}
interactive={!store.m_Option.BayRightIsWall}
selectDiv={this._CameraStateContainer}
startLocation={this.startLocation}
location={Location.Right}
/>
</div>
<div className='paramsSize'>
{
this.props.drawHoleType === DrawHoleType.I &&
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.BayDist}
sliderMin={100}
sliderMax={2000}
title={"外飘距离"}
/>
}
{
this.props.drawHoleType !== DrawHoleType.I &&
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.BayLeftDist}
sliderMin={100}
sliderMax={2000}
title={"左飘距离"}
/>
}
{
this.props.drawHoleType === DrawHoleType.U &&
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.BayMiddleDist}
sliderMin={100}
sliderMax={2000}
title={"中飘距离"}
/>
}
{
this.props.drawHoleType !== DrawHoleType.I &&
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.BayRightDist}
sliderMin={100}
sliderMax={2000}
title={"右飘距离"}
/>
}
</div>
</Collapse>
</div>
</div>
}
{
this.props.holeIType === IHoleType.Window && <div>
<Divider />
<div className="stone">
<Checkbox
label="窗台石"
checked={this.props.store.m_Option.HasWindowStone}
onChange={() =>
{
this.props.store.m_Option.HasWindowStone = !this.props.store.m_Option.HasWindowStone;
}}
/>
<Collapse isOpen={this.props.store.m_Option.HasWindowStone}>
<div className='paramsSize'>
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.StoneThick}
sliderMin={0}
sliderMax={200}
title={"台面厚度"}
/>
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.StoneBulge}
sliderMin={0}
sliderMax={200}
title={"台面凸出"}
/>
<WindowParamsComponent
store={this.props.store}
sizeKey={DoorWindowParamsNames.StoneLeftRightBulge}
sliderMin={0}
sliderMax={200}
title={"侧面凸出"}
/>
</div>
</Collapse>
</div>
</div>
}
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<div className="foot_right">
<Button
className="LeftRightBtn bp3-intent-success"
text="选择模板"
onClick={() =>
{
this.startLocation.set(Location.All);
this.startSelectTemplate(Visibility.Visible);
}}
/>
<Button
intent="success"
text="确定"
onClick={() =>
{
app.Editor.ModalManage.m_PromisRes({ Status: ModalState.Ok });
app.Editor.ModalManage.Destory();
}}
/>
<Button
intent="danger"
text="取消"
onClick={() =>
{
app.Editor.ModalManage.m_PromisRes({ Status: ModalState.Cancel });
app.Editor.ModalManage.Destory();
}}
/>
</div>
</div>
</div>
</div >
</div >
);
}
}

@ -0,0 +1,72 @@
import { observable, toJS } from "mobx";
import { DefaultWindowPanelOption as DefaultDoorWindowPanelOption } from "../../../../../../Editor/DefaultConfig";
import { IConfigOption } from "../../../../../../UI/Components/Board/UserConfig";
import { WindowPanelConfigOption as DoorWindowPanelConfigOption } from "../../../../../../UI/Store/BoardInterface";
import { IConfigStore } from "../../../../../../UI/Store/BoardStore";
import { ISelectTempInfo } from "../../../../../../UI/Store/DoorInterface";
import { TemplateWindowRecord } from "../../../../../Template/ProgramTempate/TemplateWindowRecord";
export enum DoorWindowParamsNames
{
Length = "Length",
Height = "Height",
Thick = "Thick",
WindowOffGround = "WindowOffGround",
IsBayWindow = "IsBayWindow",
BayLeftIsWall = "BayLeftIsWall",
BayRightIsWall = "BayRightIsWall",
BayDist = "BayDist",
BayLeftDist = "BayLeftDist",
BayMiddleDist = "BayMiddleDist",
BayRightDist = "BayRightDist",
HasWindowStone = "HasWindowStone",
StoneThick = "StoneThick",
StoneBulge = "StoneBulge",
StoneLeftRightBulge = "StoneLeftRightBulge",
}
export class DoorWindowPanelStore implements IConfigStore
{
@observable configName = "默认";
@observable m_Option: DoorWindowPanelConfigOption = { ...DefaultDoorWindowPanelOption };
@observable configsNames: string[] = [];
@observable selectTemplateInfo: ISelectTempInfo = { temp: { id: "", name: "", logo: "" } };
@observable currentDoorWindowsInfo: ISelectTempInfo; //应用的门窗信息
@observable currentLeftBayWindowsInfo: ISelectTempInfo; //应用的左飘窗信息
@observable currentRightBayWindowsInfo: ISelectTempInfo; //应用的右飘窗信息
SaveConfig()
{
let newConfig: IConfigOption = {};
newConfig.option = toJS(this.m_Option);
return newConfig;
};
InitOption()
{
Object.assign(this.m_Option, DefaultDoorWindowPanelOption);
this.currentDoorWindowsInfo = undefined;
this.currentLeftBayWindowsInfo = undefined;
this.currentRightBayWindowsInfo = undefined;
}
InitCurrentWindowOption(windowTemp: TemplateWindowRecord)
{
if (!windowTemp) return;
this.m_Option.BayLeftIsWall = windowTemp.LeftIsWall;
this.m_Option.BayRightIsWall = windowTemp.RightIsWall;
}
UpdateOption(cof: IConfigOption<DoorWindowPanelConfigOption>)
{
this.m_Option = cof.option;
}
private static _SingleInstance: DoorWindowPanelStore;
static GetSingleInstance(): DoorWindowPanelStore
{
if (this._SingleInstance) return this._SingleInstance;
this._SingleInstance = new DoorWindowPanelStore;
return this._SingleInstance;
}
}

@ -0,0 +1,101 @@
import { Intent, NumericInput, Position, Slider, Tooltip } from "@blueprintjs/core";
import { observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { safeEval } from "../../../../../../Common/eval";
import { KeyBoard } from "../../../../../../Common/KeyEnum";
import { DoorWindowPanelStore } from "./WindowPanelStore";
interface SizeComponentProps
{
store: DoorWindowPanelStore;
title: string; //标题提示字符串
sizeKey: string; //字段
sliderMin: number;
sliderMax: number;
}
@observer
export class WindowParamsComponent extends React.Component<SizeComponentProps>
{
@observable _Value: number = parseInt(this.props.store.m_Option[this.props.sizeKey]);
@observable _IsPopoverOpen: boolean = false;
_SizeRef = React.createRef<NumericInput>();
render()
{
let store = this.props.store;
return (
<div className='windowParamsSlider'>
<span>{this.props.title}</span>
<Slider
min={this.props.sliderMin}
max={this.props.sliderMax}
value={this._Value}
onChange={(value) =>
{
this._Value = value;
this._SizeRef.current.inputElement.value = value.toString();
}}
onRelease={(value) =>
{
store.m_Option[this.props.sizeKey] = value;
}}
/>
<Tooltip
content={"仅限" + this.props.sliderMin + "-" + this.props.sliderMax + "间的数字!"}
position={Position.TOP}
intent={Intent.WARNING}
isOpen={this._IsPopoverOpen}
>
<NumericInput
min={this.props.sliderMin}
max={this.props.sliderMax}
defaultValue={this._Value}
ref={this._SizeRef}
onValueChange={(s, n, e) =>
{
let val = safeEval(e.value);
if (!isNaN(val))
{
if (val < this.props.sliderMin || val > this.props.sliderMax)
this._IsPopoverOpen = true;
else
this._IsPopoverOpen = false;
}
else
this._IsPopoverOpen = true;
}}
onKeyDown={(e) =>
{
if (e.keyCode === KeyBoard.Enter)
{
this._SizeRef.current.inputElement.blur();
}
else if (e.keyCode === KeyBoard.Escape)
{
this._SizeRef.current.inputElement.value = store.m_Option[this.props.sizeKey].toFixed();
this._SizeRef.current.inputElement.blur();
}
e.stopPropagation();
}}
onBlur={(e) =>
{
if (this._IsPopoverOpen)
{
e.target.value = store.m_Option[this.props.sizeKey];
this._IsPopoverOpen = false;
}
else
{
this._Value = parseFloat(e.currentTarget.value);
store.m_Option[this.props.sizeKey] = parseFloat(e.currentTarget.value);
}
}}
/>
</Tooltip>
</div>
);
}
}

@ -0,0 +1,180 @@
import { Card, Elevation, Icon } from "@blueprintjs/core";
import { IObservableValue, observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { app } from "../../../../../../ApplicationServices/Application";
import { CURRENT_HOST } from "../../../../../../Common/HostUrl";
import { DuplicateRecordCloning } from "../../../../../../Common/Status";
import { CommandWrap } from "../../../../../../Editor/CommandMachine";
import { ModalState } from "../../../../../../UI/Components/Modal/ModalInterface";
import { Location } from "../../../../../../UI/Components/ToolBar/ModifyModel/RoomBaseParams";
import { TemplateArcWindowRecord } from "../../../../../Template/ProgramTempate/TemplateArcWindowRecord";
import { TemplateRoomDoorRecord } from "../../../../../Template/ProgramTempate/TemplateRoomDoorRecord";
import { TemplateWindowRecord } from "../../../../../Template/ProgramTempate/TemplateWindowRecord";
import { DeleteTempate, GetOnlineTemplate, ReplaceTemplate } from "../../../../../Template/TempateUtils";
import { TemplateRecord } from "../../../../../Template/TemplateRecord";
import { RoomHolePolyline } from "../RoomHolePolyline";
import { Visibility } from "./DrawWindowPanel";
import { DoorWindowPanelStore } from "./WindowPanelStore";
import { WindowTempSelect } from "./WindowTempSelect";
interface WindowTempInfoProps
{
store: DoorWindowPanelStore;
doorWindowTemp?: TemplateWindowRecord | TemplateRoomDoorRecord;
logo?: string;
startLocation?: IObservableValue<string>;
location?: string;
showSizeInfo?: boolean;
interactive?: boolean;
selectDiv?: HTMLElement;
}
@observer
export class WindowTempInfo extends React.Component<WindowTempInfoProps>
{
@observable logo: string = this.props.logo;
render()
{
let store = this.props.store;
return (
<div id='WindowTempInfo'>
<Card className="windowImg"
interactive
elevation={Elevation.TWO}
onClick={this.startSelectTemplate}
>
{
this.logo ? <img
src={`${CURRENT_HOST}/${this.logo}`}
/> : <Icon iconSize={30} icon="add-to-artifact" />
}
<Icon iconSize={11} icon="swap-horizontal" className="changeLogo" />
</Card>
<div className="windowParamInfo">
<span>{this.props.doorWindowTemp?.Name || "默认"}</span>
<span>{store.m_Option.Length}*{store.m_Option.Height}*{store.m_Option.Thick}</span>
</div>
</div>
);
}
private startSelectTemplate = async () =>
{
this.props.store.selectTemplateInfo.temp = { id: "", name: "", logo: this.logo };
app.Editor.ModalManage.RenderModal(WindowTempSelect, { store: this.props.store, filter: ["门窗"] });
let state = await app.Editor.ModalManage.Wait();
if (state.Status === ModalState.Ok)
{
CommandWrap(async () =>
{
for (let index of this.getWindowLocation())
{
let oldTr = this.props.doorWindowTemp.Children[index].Object as TemplateRecord;
if (oldTr instanceof TemplateArcWindowRecord) continue; //弧形窗
let selectWindowTr = await GetOnlineTemplate(this.props.store.currentDoorWindowsInfo.temp.id || "11777");
let newTr = app.Database.WblockCloneObejcts([selectWindowTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
//记录左右飘窗Tr.id
if (this.props.location === Location.Right)
(this.props.doorWindowTemp as TemplateWindowRecord).RightWindowTemplateId = this.props.store.currentDoorWindowsInfo.temp.id || "11777";
else if (this.props.location === Location.Left)
(this.props.doorWindowTemp as TemplateWindowRecord).LeftWindowTemplateId = this.props.store.currentDoorWindowsInfo.temp.id || "11777";
await ReplaceTemplate(oldTr, newTr, false, true);
DeleteTempate(oldTr);
}
await this.props.doorWindowTemp.UpdateTemplateTree();
});
}
};
/**
* @private
* @return {*} {number[]} object
* @memberof WindowTempInfo
*/
private getWindowLocation(): number[]
{
let strs = [];
this.logo = this.props.store.currentDoorWindowsInfo.temp.logo;
if (this.props.doorWindowTemp instanceof TemplateWindowRecord)
{
//窗
let isBayWindow = this.props.doorWindowTemp.WpDists.every(x => x !== 0);
//object[] => strs[]
if (isBayWindow && !this.props.doorWindowTemp.LeftIsWall)
strs.push(Location.Left);
let hole = this.props.doorWindowTemp.HoleObjectId.Object as RoomHolePolyline;
for (let w of hole.FakerWalls)
strs.push(Location.Middle);
if (isBayWindow && !this.props.doorWindowTemp.RightIsWall)
strs.push(Location.Right);
//return [对应下标]
if (this.props.location === Location.Middle)
{
this.props.doorWindowTemp.WindowLogo = this.props.store.currentDoorWindowsInfo.temp.logo;
let indexs = [];
for (let i = 0; i < hole.FakerWalls.length; i++)
indexs.push(strs.indexOf(this.props.location) + i);
return indexs;
}
else if (this.props.location === Location.Right)
this.props.doorWindowTemp.RightWindowLogo = this.props.store.currentDoorWindowsInfo.temp.logo;
else if (this.props.location === Location.Left)
this.props.doorWindowTemp.LeftWindowLogo = this.props.store.currentDoorWindowsInfo.temp.logo;
return [strs.indexOf(this.props.location)];
}
else
{
//门
this.props.doorWindowTemp.DoorLogo = this.props.store.currentDoorWindowsInfo.temp.logo;
return [0];
}
};
}
@observer
export class DrawWindowTempInfo extends React.Component<WindowTempInfoProps>
{
render()
{
let store = this.props.store;
return (
<div id='WindowTempInfo'>
<Card className="windowImg"
interactive={this.props.interactive}
elevation={Elevation.TWO}
onClick={this.startSelectTemplate}
>
{
this.props.logo ? <img
src={`${CURRENT_HOST}/${this.props.logo}`}
/> : <Icon iconSize={30} icon="add-to-artifact" />
}
</Card>
{
this.props.showSizeInfo &&
<div className="windowParamInfo">
<span></span>
<span>{store.m_Option.Length}*{store.m_Option.Height}*{store.m_Option.Thick}</span>
</div>
}
</div>
);
}
private startSelectTemplate = () =>
{
if (!this.props.interactive) return;
this.props.startLocation.set(this.props.location);
this.props.selectDiv.style.visibility = Visibility.Visible;
};
}

@ -0,0 +1,200 @@
import { Button, Classes } from "@blueprintjs/core";
import { IObservableValue, observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { app } from "../../../../../../ApplicationServices/Application";
import { TemplateUrls } from "../../../../../../Common/HostUrl";
import { KeyBoard } from "../../../../../../Common/KeyEnum";
import { DirectoryId } from "../../../../../../Common/Request";
import { ModalFooter, ModalHeader } from "../../../../../../UI/Components/Modal/ModalContainer";
import { ModalState } from "../../../../../../UI/Components/Modal/ModalInterface";
import { CommonPanel } from "../../../../../../UI/Components/SourceManage/CommonPanel";
import { TemplateList } from "../../../../../../UI/Components/Template/TemplateList";
import { Location } from "../../../../../../UI/Components/ToolBar/ModifyModel/RoomBaseParams";
import { IDrawerDoorTempInfo } from "../../../../../../UI/Store/DoorInterface";
import { ITemplateParam } from "../../../../../../UI/Store/RightPanelStore/ITemplateParam";
import { Visibility } from "./DrawWindowPanel";
import { DoorWindowPanelStore } from "./WindowPanelStore";
export interface IWindowTempSelectProps
{
selectDiv?: HTMLElement;
store: DoorWindowPanelStore;
filter: string[],
location?: IObservableValue<string>;
}
@observer
export class WindowTempSelect extends React.Component<IWindowTempSelectProps, {}> {
@observable private currentProps: ITemplateParam[] = [];
@observable private currentInfo: IDrawerDoorTempInfo = { id: "", name: "" };
private container: HTMLElement;
constructor(props)
{
super(props);
}
componentDidMount()
{
this.container.addEventListener("keydown", e =>
{
if (e.keyCode === KeyBoard.Escape)
{
this.handleClose(ModalState.Cancel);
}
else if (e.keyCode === KeyBoard.Space || e.keyCode === KeyBoard.Enter)
{
this.applySelectTemp();
this.handleClose(ModalState.Ok);
}
e.stopPropagation();
});
this.container.focus();
if (!this.props.store.selectTemplateInfo)
{
if (this.props.store instanceof DoorWindowPanelStore)
{
this.props.store.selectTemplateInfo = {
temp: { id: "", name: "", logo: "", title: "选择窗户" },
};
}
}
}
public render()
{
return (
<div
className={Classes.DIALOG + " template-select"}
ref={el => this.container = el}
tabIndex={-1}
>
<ModalHeader
icon="bold"
title="模板"
close={() => { this.handleClose(ModalState.Cancel); }}
/>
<div
className={Classes.DIALOG_BODY}
>
<CommonPanel
loadCacheDirKey={"selectWindow"}
defaultDirId={DirectoryId.TemplateDir}
canDelete={false}
getUrl={TemplateUrls.list}
deleteUrl={TemplateUrls.delete}
clickTree={() =>
{
this.currentProps.length = 0;
}}
dirNameFilter={this.props.filter}
>
<TemplateList
currentProps={this.currentProps}
currentInfo={this.currentInfo}
forbidDelete={true}
hideSelectBox={true}
selectInfo={this.props.store.selectTemplateInfo}
isShowDetail={false}
/>
</CommonPanel>
</div>
<ModalFooter hasConfig={false} style={{ width: "100%" }}>
<Button
className={Classes.INTENT_SUCCESS}
text="应用"
onClick={() =>
{
this.applySelectTemp();
this.handleClose(ModalState.Ok);
}}
/>
<Button
className={Classes.INTENT_DANGER}
text="取消"
onClick={() => { this.handleClose(ModalState.Cancel); }}
/>
</ModalFooter>
</div>
);
}
private handleClose = (modalState: ModalState) =>
{
if (this.props.selectDiv)
this.props.selectDiv.style.visibility = Visibility.Hidden;
else
{
app.Editor.ModalManage.m_PromisRes({ Status: modalState });
app.Editor.ModalManage.Destory();
}
};
private applySelectTemp()
{
switch (this.props.location?.get())
{
case Location.Middle:
this.props.store.currentDoorWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
break;
case Location.Left:
this.props.store.currentLeftBayWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
break;
case Location.Right:
this.props.store.currentRightBayWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
break;
case Location.All:
this.props.store.currentDoorWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
this.props.store.currentLeftBayWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
this.props.store.currentRightBayWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
break;
default:
this.props.store.currentDoorWindowsInfo = {
temp: {
name: "",
id: this.props.store.selectTemplateInfo.temp.id,
logo: this.props.store.selectTemplateInfo.temp.logo
}
};
break;
}
};
}

@ -9,7 +9,7 @@ import { Positioning } from "./Positioning";
@Factory
export class PositioningBoardSpace extends Positioning
{
@AutoRecord ObjectId: ObjectId;
@AutoRecord ObjectId: ObjectId<Board>;
/**
*
*/
@ -30,7 +30,7 @@ export class PositioningBoardSpace extends Positioning
ReadFile(file: CADFiler): void
{
let ver = file.Read();
this.ObjectId = file.ReadObjectId();
this.ObjectId = file.ReadObjectId() as ObjectId<Board>;
}
WriteFile(file: CADFiler): void

@ -0,0 +1,38 @@
import { Matrix4, Vector3 } from "three";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { Positioning } from "./Positioning";
@Factory
export class PositioningFixed extends Positioning
{
override async Positioning()
{
}
//#region File
ReadFile(file: CADFiler): void
{
let ver = file.Read();
if (!this.SpaceCS) this.SpaceCS = new Matrix4;
if (!this.SpaceSize) this.SpaceSize = new Vector3;
for (let i = 0; i < 16; i++)
this.SpaceCS.elements[i] = file.Read();
this.SpaceSize.set(file.Read(), file.Read(), file.Read());
}
WriteFile(file: CADFiler): void
{
file.Write(1);
for (let e of this.SpaceCS.elements)
file.Write(e);
file.Write(this.SpaceSize.x);
file.Write(this.SpaceSize.y);
file.Write(this.SpaceSize.z);
}
//#endregion
}

@ -0,0 +1,280 @@
import { MathUtils, Matrix4, Vector3 } from "three";
import { app } from "../../../ApplicationServices/Application";
import { equaln, ZAxis } from "../../../Geometry/GeUtils";
import { BoardType } from "../../../UI/Store/BoardInterface";
import { AutoRecord } from "../../AutoRecord";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { CADObject } from "../../CADObject";
import { Arc } from "../../Entity/Arc";
import { Board } from "../../Entity/Board";
import { Line } from "../../Entity/Line";
import { Polyline } from "../../Entity/Polyline";
import { HardwareCompositeEntity } from "../../Hardware/HardwareCompositeEntity";
import { DefaultParamMap, SetMaterialParams } from "../../IMaterialDefaultParam";
import { ObjectId } from "../../ObjectId";
import { PhysicalMaterialRecord } from "../../PhysicalMaterialRecord";
import { RoomHolePolyline } from "../../Room/Entity/Wall/Hole/RoomHolePolyline";
import { RoomWallArc } from "../../Room/Entity/Wall/RoomWallArc";
import { TemplateRecord } from "../TemplateRecord";
/**
*
*/
@Factory
export class TemplateArcWindowRecord extends TemplateRecord
{
constructor()
{
super();
this.name = "弧形窗(自动)";
}
@AutoRecord HoleObjectId: ObjectId<RoomHolePolyline>;
@AutoRecord ArcWallIndex: number;
InitWindowFrame(hole: RoomHolePolyline, arcWallIndex: number)
{
if (!hole.objectId) return;
this.HoleObjectId = hole.objectId;
this.ArcWallIndex = arcWallIndex;
//下边框
let bottomFrame = Board.CreateBoard(50, 50, 50, BoardType.Layer);
bottomFrame.ApplyMatrix(bottomFrame.OCSInv);
bottomFrame.ColorIndex = 8;
//玻璃
let glass = bottomFrame.Clone();
glass.ColorIndex = 7;
//其余边框
let leftFrame = bottomFrame.Clone();
let rightFrame = bottomFrame.Clone();
let topFrame = bottomFrame.Clone();
let windowModel = new HardwareCompositeEntity();
windowModel.Entitys.push(leftFrame, rightFrame, topFrame, bottomFrame, glass);
app.Database.ModelSpace.Append(windowModel);
this.Objects.push(windowModel.Id);
//边框材质
let frameMaterial = app.Database.MaterialTable.GetAt("弧形窗边框");
if (!frameMaterial)
{
frameMaterial = new PhysicalMaterialRecord();
SetMaterialParams(frameMaterial, DefaultParamMap.);
frameMaterial.Name = "弧形窗边框";
frameMaterial.type = "金属";
frameMaterial.color = "#333333";
frameMaterial.roughness = 0.4;//粗糙度
frameMaterial.specular = 0.5;//高光
frameMaterial.Update();
app.Database.MaterialTable.Add(frameMaterial);
}
windowModel.Material = frameMaterial.Id;
//玻璃材质
let glassMaterial = app.Database.MaterialTable.GetAt("弧形窗玻璃");
if (!glassMaterial)
{
glassMaterial = new PhysicalMaterialRecord();
SetMaterialParams(glassMaterial, DefaultParamMap.);
glassMaterial.Name = "弧形窗玻璃";
glassMaterial.type = "玻璃";
glassMaterial.transparent = true;
glassMaterial.opacity = 0.4;
glassMaterial.Update();
app.Database.MaterialTable.Add(glassMaterial);
}
glass.Material = glassMaterial.Id;
}
protected async Update()
{
await super.Update();
let [windowModelId] = this.Objects;
if (!windowModelId || windowModelId.IsErase) return;
let hole = this.HoleObjectId?.Object;
let arcWall = hole?.FakerWalls[this.ArcWallIndex] as RoomWallArc;
if (!hole || !arcWall) return;
let windowModel = windowModelId.Object as HardwareCompositeEntity;
let leftFrame = windowModel.Entitys[0] as Board;
let rightFrame = windowModel.Entitys[1] as Board;
let topFrame = windowModel.Entitys[2] as Board;
let bottomFrame = windowModel.Entitys[3] as Board;
let glass = windowModel.Entitys[4] as Board;
bottomFrame.ApplyMatrix(bottomFrame.OCSInv);
let wpdist = hole.WpDist[0] !== 0 ? hole.WpDist[0] + arcWall.Thickness / 2 + 25 : 0;//外飘时考虑 墙厚 + 边框厚 + 外飘距离
const radius = arcWall.Radius;
let leftArc = arcWall.LeftCurves[0] as Arc;
let rightArc = arcWall.RightCurves[0] as Arc;
//弧形窗角度
let allAngle = arcWall.AllAngle;
let midAngle = allAngle / 2;
let midDistance = (leftArc.EndPoint.distanceTo(leftArc.StartPoint) + rightArc.EndPoint.distanceTo(rightArc.StartPoint)) / 4;
let maxThanPI = allAngle > Math.PI;
//弧形圆点
let center: Vector3;
if (equaln(allAngle, Math.PI, 1e-7))
center = new Vector3(radius);
else if (allAngle < Math.PI)
center = new Vector3(midDistance, - Math.sqrt(radius * radius - midDistance * midDistance));
else if (maxThanPI) //弧形大于Π时,会翻转
{
let radian = 2 * Math.PI / 360 * MathUtils.radToDeg(Math.PI - midAngle);
center = new Vector3(radius + wpdist, Math.cos(radian) * (radius + wpdist));
}
// let reduceAngle = MathUtils.degToRad(25 * 180 / (Math.PI * radius));
let startAngle = Math.PI / 2 + midAngle;
let endAngle = Math.PI / 2 - midAngle;
//内缩
// if (hole.FakerWalls.length === 2)
// {
// if (equalv3(arcWall.StartPoint.clone().applyMatrix4(hole.OCSInv), new Vector3(0)))
// startAngle = startAngle + reduceAngle * (maxThanPI ? 1 : -1);
// else
// endAngle = endAngle + reduceAngle * (maxThanPI ? -1 : 1);;
// }
//下边框弧形轮廓
let bottomArc1 = new Arc(center, radius - 25 + wpdist, startAngle, endAngle);
let bottomArc2 = new Arc(center, radius + 25 + wpdist, startAngle, endAngle);
let bottomCloseLine1 = new Line(bottomArc1.StartPoint, bottomArc2.StartPoint);
let bottomCloseLine2 = new Line(bottomArc1.EndPoint, bottomArc2.EndPoint);
let bottomContourCurve = Polyline.Combine([bottomArc1, bottomCloseLine1, bottomArc2, bottomCloseLine2]);
bottomFrame.ContourCurve = bottomContourCurve;
//玻璃弧长50 的角度
let glassAngle1 = MathUtils.degToRad(50 * 180 / (Math.PI * (radius - 2)));
let glassAngle2 = MathUtils.degToRad(50 * 180 / (Math.PI * (radius + 2)));
//玻璃
let glassArc1 = new Arc(center, radius - 2 + wpdist, startAngle - glassAngle1, endAngle + glassAngle1);
let glassArc2 = new Arc(center, radius + 2 + wpdist, startAngle - glassAngle2, endAngle + glassAngle2);
let glassCloseLine1 = new Line(glassArc1.StartPoint, glassArc2.StartPoint);
let glassCloseLine2 = new Line(glassArc1.EndPoint, glassArc2.EndPoint);
let glassContourCurve = Polyline.Combine([glassArc1, glassCloseLine1, glassArc2, glassCloseLine2]);
glass.Thickness = hole.Height - 100;
glass.ApplyMatrix(glass.OCSInv);
glass.ContourCurve = glassContourCurve;
glass.Position = glass.Position.add(new Vector3(0, 0, 50));
//上边框
topFrame.CopyFrom(bottomFrame);
topFrame.Position = bottomFrame.Position.add(new Vector3(0, 0, hole.Height - 50));
//边框弧长50 的角度
let angle1 = MathUtils.degToRad(50 * 180 / (Math.PI * (radius - 25)));
let angle2 = MathUtils.degToRad(50 * 180 / (Math.PI * (radius + 25)));
//左边框弧形轮廓
let leftArc1 = bottomArc1.Clone();
let leftArc2 = bottomArc2.Clone();
if (maxThanPI)
{
leftArc1.StartAngle = leftArc1.EndAngle + angle1;
leftArc2.StartAngle = leftArc2.EndAngle + angle2;
}
else
{
leftArc1.EndAngle = leftArc1.StartAngle - angle1;
leftArc2.EndAngle = leftArc2.StartAngle - angle2;
}
let leftCloseLine1 = new Line(leftArc1.StartPoint, leftArc2.StartPoint);
let leftCloseLine2 = new Line(leftArc1.EndPoint, leftArc2.EndPoint);
let leftFrameContourCurve = Polyline.Combine([leftArc1, leftCloseLine1, leftArc2, leftCloseLine2]);
leftFrame.Thickness = hole.Height - 100;
leftFrame.ApplyMatrix(leftFrame.OCSInv);
leftFrame.ContourCurve = leftFrameContourCurve;
leftFrame.Position = leftFrame.Position.add(new Vector3(0, 0, 50));
//右边框弧形轮廓
let rightArc1 = bottomArc1.Clone();
let rightArc2 = bottomArc2.Clone();
if (maxThanPI)
{
rightArc1.EndAngle = rightArc1.StartAngle - angle1;
rightArc2.EndAngle = rightArc2.StartAngle - angle2;
}
else
{
rightArc1.StartAngle = rightArc1.EndAngle + angle1;
rightArc2.StartAngle = rightArc2.EndAngle + angle2;
}
let rightCloseLine1 = new Line(rightArc1.StartPoint, rightArc2.StartPoint);
let rightCloseLine2 = new Line(rightArc1.EndPoint, rightArc2.EndPoint);
let rightFrameContourCurve = Polyline.Combine([rightArc1, rightCloseLine1, rightArc2, rightCloseLine2]);
rightFrame.Thickness = hole.Height - 100;
rightFrame.ApplyMatrix(rightFrame.OCSInv);
rightFrame.ContourCurve = rightFrameContourCurve;
rightFrame.Position = rightFrame.Position.add(new Vector3(0, 0, 50));
//定位
let pos = arcWall.IsClockWise ? arcWall.StartPoint.clone() : arcWall.EndPoint.clone();
let x = arcWall.EndPoint.sub(arcWall.StartPoint).normalize().multiplyScalar(arcWall.IsClockWise ? 1 : -1);
let z = ZAxis;
let y = new Vector3().crossVectors(ZAxis, x);
if (maxThanPI)
{
//外飘时基点外移
let v = arcWall.Center.clone().sub(pos).normalize();
pos.subVectors(pos, v.multiplyScalar(wpdist));
//边框处在第一象限
let scalar = (rightArc1.StartPoint.x + rightArc2.StartPoint.x) / 2;
pos.subVectors(pos, x.clone().multiplyScalar(scalar));
}
windowModel.OCS = new Matrix4().makeBasis(x, y, z).setPosition(pos);
windowModel.Update();
}
//#region -------------------------File-------------------------
//对象从文件中读取数据,初始化自身
override ReadFile(file: CADFiler)
{
let ver = file.Read();
super.ReadFile(file);
this.HoleObjectId = file.ReadObjectId() as any;
this.ArcWallIndex = file.Read();
}
//对象将自身数据写入到文件.
override WriteFile(file: CADFiler)
{
file.Write(1);
super.WriteFile(file);
file.WriteObjectId(this.HoleObjectId);
file.Write(this.ArcWallIndex);
}
//局部撤销
override ApplyPartialUndo(undoData: CADObject)
{
super.ApplyPartialUndo(undoData);
}
//#endregion
}

@ -0,0 +1,93 @@
import { Vector3 } from "three";
import { AutoRecord } from "../../AutoRecord";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { CADObject } from "../../CADObject";
import { ObjectId } from "../../ObjectId";
import { RoomHolePolyline } from "../../Room/Entity/Wall/Hole/RoomHolePolyline";
import { PositioningFixed } from "../Positioning/PositioningFixed";
import { TemplateRecord } from "../TemplateRecord";
/**
*
* 使()
*
* ()
* ?(?)
*
*/
@Factory
export class TemplateRoomDoorRecord extends TemplateRecord
{
@AutoRecord HoleObjectId: ObjectId<RoomHolePolyline>;
@AutoRecord DoorLogo: string;
constructor()
{
super();
}
InitHoleParams()
{
let hole = this.HoleObjectId?.Object;
if (!hole) return;
return this;
}
protected override async Update()
{
super.Update();
let hole = this.HoleObjectId?.Object;
if (!hole) return;
if (!this.Children[0]?.Object) return;
let tr = this.Children[0].Object as TemplateRecord;
let pos = new PositioningFixed;
pos.SpaceCS = hole.FakerWalls[0].OCS;
let yDir = new Vector3().setFromMatrixColumn(pos.SpaceCS, 1);
pos.SpaceCS.elements[12] -= yDir.x * hole.FakerWalls[0].Thickness * 0.5;
pos.SpaceCS.elements[13] -= yDir.y * hole.FakerWalls[0].Thickness * 0.5;
pos.SpaceCS.elements[14] -= yDir.z * hole.FakerWalls[0].Thickness * 0.5;
let wall = hole.FakerWalls[0];
pos.SpaceSize = new Vector3(wall.Length, wall.Thickness, wall.Height);
tr.Positioning = pos;
}
//#region -------------------------File-------------------------
//对象从文件中读取数据,初始化自身
override ReadFile(file: CADFiler)
{
let ver = file.Read();
super.ReadFile(file);
this.HoleObjectId = file.ReadObjectId() as any;
if (ver > 1)
{
this.DoorLogo = file.Read();
}
}
//对象将自身数据写入到文件.
override WriteFile(file: CADFiler)
{
file.Write(2);
super.WriteFile(file);
file.WriteObjectId(this.HoleObjectId);
file.Write(this.DoorLogo);
}
//局部撤销
override ApplyPartialUndo(undoData: CADObject)
{
super.ApplyPartialUndo(undoData);
}
//#endregion
}

@ -0,0 +1,394 @@
import { Matrix4, Vector3 } from "three";
import { arrayLast } from "../../../Common/ArrayExt";
import { EntityUpdateWrap } from "../../../Common/EntityUpdateWrap";
import { ZAxis } from "../../../Geometry/GeUtils";
import { IntersectOption } from "../../../GraphicsSystem/IntersectWith";
import { AutoRecord } from "../../AutoRecord";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { CADObject } from "../../CADObject";
import { Curve } from "../../Entity/Curve";
import { ObjectId } from "../../ObjectId";
import { RoomHolePolyline } from "../../Room/Entity/Wall/Hole/RoomHolePolyline";
import { RoomWallArc } from "../../Room/Entity/Wall/RoomWallArc";
import { RoomWallLine } from "../../Room/Entity/Wall/RoomWallLine";
import { TemplateParam } from "../Param/TemplateParam";
import { PositioningFixed } from "../Positioning/PositioningFixed";
import { TemplateRecord } from "../TemplateRecord";
/**
* :
* I()
* L(,2,4) (?) (?) (?)
* U(,2,6) (?) (?)
*
* V
*
* ?
*
* :
*
*
*
* ? ? ?
*
* I = W/2
* L
* U ?
*/
//窗台石默认参数
const DefaultCTSarams: [string, string, string][] = [
["CTS", "窗台石?", "1"],
["CTSH", "窗石厚", "30"],
["CTSTC", "窗石凸", "30"],
["CTSZYTC", "左右凸出", "30"],
["WZ", "窗位置", "25"],//在外飘未启用之前
["HD", "窗厚度", "50"],//在外飘未启用之前
];
const DefaultIWindowParams: [string, string, string][] = [
["WP", "外飘", "500"],
];
const DefaultLWindowParams: [string, string, string][] = [
["ZWP", "左外飘", "500"],
["YWP", "右外飘", "500"],
];
const DefaultUWindowParams: [string, string, string][] = [
["ZWP", "左外飘", "500"],
["MWP", "中外飘", "500"],
["YWP", "右外飘", "500"],
];
function InitParam(tr: TemplateRecord, paramD: [string, string, string])
{
let [name, description, expr] = paramD;
let param = tr.GetParam(name);
if (param) return;
param = new TemplateParam();
param.name = name;
param.expr = expr;
param.value = 0;
param.description = description;
tr.Params.push(param);
}
@Factory
export class TemplateWindowRecord extends TemplateRecord
{
@AutoRecord HoleObjectId: ObjectId<RoomHolePolyline>;
@AutoRecord CTSId: ObjectId;//窗台石id
@AutoRecord LeftIsWall = false;
@AutoRecord RightIsWall = false;
@AutoRecord WindowLogo: string;
@AutoRecord LeftWindowLogo: string;
@AutoRecord RightWindowLogo: string;
@AutoRecord LeftWindowTemplateId: string;//飘窗左侧窗
@AutoRecord RightWindowTemplateId: string;//飘窗右侧窗
constructor()
{
super();
}
InitHoleParams()
{
let hole = this.HoleObjectId?.Object;
if (!hole) return;
//初始化窗台石参数
for (let p of DefaultCTSarams) InitParam(this, p);
let holePtsCount = hole.PointsCount;
if (holePtsCount === 2)
{
for (let p of DefaultIWindowParams) InitParam(this, p);
}
else if (holePtsCount === 3)
{
for (let p of DefaultLWindowParams) InitParam(this, p);
}
else if (holePtsCount === 4)
{
for (let p of DefaultUWindowParams) InitParam(this, p);
}
return this;
}
set WpDist(v: number[])
{
let count = this.HoleObjectId?.Object?.PointsCount;
if (!count) return;
if (count === 2)
this.GetParam("WP").expr = v[0];
else if (count === 3)
{
this.GetParam("ZWP").expr = v[0];
this.GetParam("YWP").expr = v[1];
}
else
{
this.GetParam("ZWP").expr = v[0];
this.GetParam("MWP").expr = v[1];
this.GetParam("YWP").expr = v[2];
}
}
get WpDists(): number[]
{
let hole = this.HoleObjectId?.Object;
if (!hole) return;
let wpdists: number[] = [];
let walls = hole.FakerWalls;
if (walls.length === 1)
{
let wp = this.GetParam("WP").value as number;
wpdists.push(wp);
}
else if (walls.length === 2)
{
let zwp = this.GetParam("ZWP").value as number;
let ywp = this.GetParam("YWP").value as number;
wpdists.push(zwp, ywp);
}
else if (walls.length === 3)
{
let zwp = this.GetParam("ZWP").value as number;
let mwp = this.GetParam("MWP").value as number;
let ywp = this.GetParam("YWP").value as number;
wpdists.push(zwp, mwp, ywp);
}
return wpdists;
}
protected override async Update()
{
super.Update();
let hole = this.HoleObjectId?.Object;
if (!hole) return;
let ctsParam = this.GetParam("CTS");
//#region 计算窗台石轮廓
let ctstc = this.GetParam("CTSTC").value as number;//窗台石凸出
let ctszytc = this.GetParam("CTSZYTC").value as number;//窗台石左右凸出
let wpdists = this.WpDists;
let polyline = hole.GetWpRegion(wpdists, ctstc, ctszytc);
if (ctsParam.value)//1 使用窗台石?
{
// Draw(polyline);
}
EntityUpdateWrap(hole, () =>
{
hole.WpDist = wpdists;
hole.WpLeftWall = this.LeftIsWall;
hole.WpRightWall = this.RightIsWall;
});
if (wpdists.every(d => d === 0))//没有外飘
{
let wzParam = this.GetParam("WZ");
let fakerWalls = hole.FakerWalls;
if (wzParam.value !== 0)
{
fakerWalls = fakerWalls.map(w => w.GetOffsetCurves(wzParam.value as number)[0] as any);
//窗户相交最近点
const getMinDistPoint = (pts: Vector3[], curve: Vector3) =>
{
let pt: Vector3 = pts[0];
let length = curve.distanceTo(pt);
for (let y = 1; y < pts.length; y++)
{
if (curve.distanceTo(pts[y]) < length)
pt = pts[y];
}
return pt;
};
for (let i = 0; i < fakerWalls.length - 1; i++)
{
let pre = fakerWalls[i];
let next = fakerWalls[i + 1];
let pt = getMinDistPoint(pre.IntersectWith(next, IntersectOption.ExtendBoth), pre.EndPoint);
pre.EndPoint = pt;
next.StartPoint = pt;
}
for (let w of fakerWalls)
{
if (w instanceof RoomWallLine)
w.UpdateOCSToMinBox();
}
}
for (let i = 0; i < this.Children.length; i++)
{
if (i > hole.PointsCount) break;
let wall = fakerWalls[i];
let ctemplate = this.Children[i].Object as TemplateRecord;
if (!ctemplate) continue;
let pos = new PositioningFixed;
pos.SpaceCS = wall.OCS;
pos.SpaceSize = new Vector3(wall.Length, ctemplate.WParam.value as number, wall.Height);
ctemplate.Positioning = pos;
}
}
else
{
//根据外飘偏移
let wpCurves: Curve[] = [];
for (let i = 0; i < hole.FakerWalls.length; i++)
{
let w = hole.FakerWalls[i] as (RoomWallLine | RoomWallArc);
let d = wpdists[i];//外飘距离
if (w instanceof RoomWallArc)
wpCurves.push(w.GetOffsetCurves((w.Thickness * 0.5 + d) * (w.IsClockWise ? -1 : 1))[0]);
else
wpCurves.push(w.GetOffsetCurves(-(w.Thickness * 0.5 + d))[0]);
}
//求交连接
for (let i = 1; i < wpCurves.length; i++)
{
let pre = wpCurves[i - 1];
let now = wpCurves[i];
let iPt = pre.IntersectWith(now, IntersectOption.ExtendBoth)[0];
pre.EndPoint = iPt;
now.StartPoint = iPt;
}
//左侧非墙
let templateIndex = 0;
if (!this.LeftIsWall)
{
templateIndex++;
let sp = hole.LidCurves[0].StartPoint.setZ(hole.Z);
let x = hole.LidCurves[0].GetFistDeriv(0).normalize().negate();
let z = ZAxis;
let y = new Vector3().crossVectors(ZAxis, x);
let tr = this.Children[0].Object as TemplateRecord;
if (!tr) return;
let pos = new PositioningFixed;
pos.SpaceCS = new Matrix4().makeBasis(x, y, z).setPosition(sp);
pos.SpaceSize = new Vector3(wpdists[0], 50, hole.Height);
tr.Positioning = pos;
}
for (let i = 0; i < wpCurves.length; i++)
{
let c = wpCurves[i];
let tr = this.Children[templateIndex]?.Object as TemplateRecord;
if (!tr) return;
let sp = c.StartPoint;
let x = c.GetFistDeriv(0).normalize();
let z = ZAxis;
let y = new Vector3().crossVectors(ZAxis, x);
let pos = new PositioningFixed;
pos.SpaceCS = new Matrix4().makeBasis(x, y, z).setPosition(sp);
pos.SpaceSize = new Vector3(c.Length, 50, hole.Height);
tr.Positioning = pos;
templateIndex++;
}
if (!this.RightIsWall && arrayLast(wpdists) > 0)
{
let tr = this.Children[templateIndex]?.Object as TemplateRecord;
if (!tr) return;
let sp = arrayLast(wpCurves).EndPoint;
let w = arrayLast(hole.FakerWalls);
let x = w.EndPoint.sub(sp).normalize();
let z = ZAxis;
let y = new Vector3().crossVectors(ZAxis, x);
let pos = new PositioningFixed;
pos.SpaceCS = new Matrix4().makeBasis(x, y, z).setPosition(sp);
pos.SpaceSize = new Vector3(arrayLast(wpdists), 50, hole.Height);
tr.Positioning = pos;
}
}
}
//#region -------------------------File-------------------------
//对象从文件中读取数据,初始化自身
override ReadFile(file: CADFiler)
{
let ver = file.Read();
super.ReadFile(file);
if (ver > 1)
{
let wallFlag = file.Read() as number;
this.LeftIsWall = (wallFlag & 1) === 1;
this.RightIsWall = (wallFlag & 2) === 2;
}
if (ver > 2)
this.HoleObjectId = file.ReadObjectId() as any;
if (ver > 3)
{
this.WindowLogo = file.Read();
this.LeftWindowLogo = file.Read();
this.RightWindowLogo = file.Read();
this.LeftWindowTemplateId = file.Read();
this.RightWindowTemplateId = file.Read();
}
}
//对象将自身数据写入到文件.
override WriteFile(file: CADFiler)
{
file.Write(4);
super.WriteFile(file);
let wallFlag = 0;
if (this.LeftIsWall) wallFlag = 1;
if (this.RightIsWall) wallFlag += 2;
file.Write(wallFlag);
file.WriteObjectId(this.HoleObjectId);
file.Write(this.WindowLogo);
file.Write(this.LeftWindowLogo);
file.Write(this.RightWindowLogo);
file.Write(this.LeftWindowTemplateId);
file.Write(this.RightWindowTemplateId);
}
//局部撤销
override ApplyPartialUndo(undoData: CADObject)
{
super.ApplyPartialUndo(undoData);
}
//#endregion
}

@ -172,7 +172,10 @@ import { Command_Reverse } from "../Add-on/Reverse";
import { Command_Curve2Wall } from "../Add-on/Room/Curve2Wall";
import { Command_DrawHole, DrawHoleType, IHoleType } from "../Add-on/Room/DrawHole";
import { Command_DrawRectWall } from "../Add-on/Room/DrawRectWall";
import { Command_DrawRoomDoor } from "../Add-on/Room/DrawRoomDoor";
import { Command_DrawRoomWindow } from "../Add-on/Room/DrawRoomWindow";
import { Command_DrawWall, Command_DrawWallInside } from "../Add-on/Room/DrawWall";
import { Command_OneKeyDrawLDCWindow, Command_OneKeyDrawPCWindow, Command_OneKeyDrawYJHMWindow, Command_OneKeyDrawYZCWindow, Command_OneKeyDrawZJCWindow, Command_OneKeyDrawZJPCWindow } from "../Add-on/Room/OneKeyDrawWindow";
import { Command_ParseRoomWall } from "../Add-on/Room/ParseRoomWall";
import { Command_SetWallThick } from "../Add-on/Room/SetWallThick";
import { Command_Rotate, Command_RotateRefer } from "../Add-on/Rotate";
@ -780,6 +783,19 @@ export function registerCommand()
commandMachine.RegisterCommand(CommandNames.DrawLHole, new Command_DrawHole(DrawHoleType.L));
commandMachine.RegisterCommand(CommandNames.DrawUHole, new Command_DrawHole(DrawHoleType.U));
commandMachine.RegisterCommand(CommandNames.DrawIWindow, new Command_DrawRoomWindow(DrawHoleType.I, IHoleType.Window));
commandMachine.RegisterCommand(CommandNames.DrawLWindow, new Command_DrawRoomWindow(DrawHoleType.L, IHoleType.Window));
commandMachine.RegisterCommand(CommandNames.DrawUWindow, new Command_DrawRoomWindow(DrawHoleType.U, IHoleType.Window));
commandMachine.RegisterCommand(CommandNames.DrawIDoor, new Command_DrawRoomDoor(DrawHoleType.I, IHoleType.Door));
commandMachine.RegisterCommand(CommandNames.YZC, new Command_OneKeyDrawYZCWindow(DrawHoleType.I, IHoleType.Window, true));//一字窗
commandMachine.RegisterCommand(CommandNames.LDC, new Command_OneKeyDrawLDCWindow(DrawHoleType.I, IHoleType.Window, true));//落地窗
commandMachine.RegisterCommand(CommandNames.PC, new Command_OneKeyDrawPCWindow(DrawHoleType.I, IHoleType.Window, true));//飘窗
commandMachine.RegisterCommand(CommandNames.ZJC, new Command_OneKeyDrawZJCWindow(DrawHoleType.L, IHoleType.Window, true));//转角窗
commandMachine.RegisterCommand(CommandNames.ZJPC, new Command_OneKeyDrawZJPCWindow(DrawHoleType.L, IHoleType.Window, true));//转角飘窗
commandMachine.RegisterCommand(CommandNames.YJHM, new Command_OneKeyDrawYJHMWindow(DrawHoleType.I, IHoleType.Door, true));//一键画门
if (IsTest())
commandMachine.RegisterCommand("ParseWall", new Command_ParseRoomWall());
//画廊命令

@ -6,7 +6,7 @@ import { IUpdateBoardInfosOption } from "../UI/Components/Board/UpdateBoardInfoi
import { EMetalsType, ICompHardwareOption, ICylMetalsOption, IExtMetalsOption, IToplineOption } from "../UI/Components/RightPanel/RightPanelInterface";
import { IKuGangDrawOption } from "../UI/Components/Template/TemplateInterface";
import { ECompareType, IBoardFindOption } from "../UI/Store/BoardFindInterface";
import { BehindBoardOption, BehindHeightPositon, BoardProcessOption, BoardType, BrRelativePos, ClosingStripOption, CommonPanelConfigOption, ComposingType, CurtailType, FaceDirection, IAutoDimBrsOption, IBatchModifyPanelOption, IBoardBatchCurtailOption, KJLImportConfigOption, LayerBoardOption, LayerNailOption, LinesType, ModifyTextsConfigOption, PointLightOption, RadioType, RectAreaLightOption, RightPlaneLightOption, SideBoardOption, SingleBoardOption, SpotLightOption, StripType, TBBoardOption, VerticalBoardOption, Viewport2ConfigOption, Viewport3ConfigOption, Viewport4ConfigOption, ViewportConfigOption } from "../UI/Store/BoardInterface";
import { BehindBoardOption, BehindHeightPositon, BoardProcessOption, BoardType, BrRelativePos, ClosingStripOption, CommonPanelConfigOption, ComposingType, CurtailType, FaceDirection, IAutoDimBrsOption, IBatchModifyPanelOption, IBoardBatchCurtailOption, KJLImportConfigOption, LayerBoardOption, LayerNailOption, LinesType, ModifyTextsConfigOption, PointLightOption, RadioType, RectAreaLightOption, RightPlaneLightOption, SideBoardOption, SingleBoardOption, SpotLightOption, StripType, TBBoardOption, VerticalBoardOption, Viewport2ConfigOption, Viewport3ConfigOption, Viewport4ConfigOption, ViewportConfigOption, WindowPanelConfigOption } from "../UI/Store/BoardInterface";
import { DoorPosType, HandleHorPos, HandleVePos, IDoorConfigOption, IDrawerConfigOption, IHingeConfigOption } from "../UI/Store/DoorInterface";
import { IHSOption } from "../UI/Store/HSInterface";
import { ELatticeArrayType, ILatticeOption } from "../UI/Store/LatticeInterface";
@ -882,3 +882,23 @@ export const DefaultAutoDimBrsOption: IAutoDimBrsOption = {
useParseGroups: "0"
};
Object.freeze(DefaultAutoDimBrsOption);
export const DefaultWindowPanelOption: WindowPanelConfigOption = {
Length: 1100,
Height: 1500,
Thick: 280,
WindowOffGround: 900,
IsBayWindow: false,
BayLeftIsWall: false,
BayRightIsWall: false,
BayDist: 500,
BayLeftDist: 600,
BayMiddleDist: 600,
BayRightDist: 600,
HasWindowStone: false,
StoneThick: 50,
StoneBulge: 50,
StoneLeftRightBulge: 50,
};
Object.freeze(DefaultWindowPanelOption);

@ -74,12 +74,12 @@ function CheckPointOnCurve(intRes: IntersectResult[], c1: Curve, c2: Curve, extT
return true;
});
}
export function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc): IntersectResult[]
export function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc, tolerance = 1e-4): IntersectResult[]
{
if (!cu1.IsCoplaneTo(cu2)) return [];
let c1OcsInv = cu1.OCSInv;
let c1Ocs = cu1.OCS;
let c1Ocs = cu1.OCSNoClone;
let center1 = cu1.Center.applyMatrix4(c1OcsInv);
let center2 = cu2.Center.applyMatrix4(c1OcsInv);
@ -92,7 +92,7 @@ export function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc):
if (dist < Math.abs(radius1 - radius2) - 1e-3
|| dist > (radius1 + radius2 + 1e-3))
return pts;
if (equaln(dist, 0, 1e-6)) return pts;
if (equaln(dist, 0, tolerance)) return pts;
let dstsqr = dist * dist;
let r1sqr = radius1 * radius1;
@ -123,7 +123,7 @@ export function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc):
thisParam: cu1.GetParamAtPoint(p1),
argParam: cu2.GetParamAtPoint(p1),
});
if (!equalv3(p1, p2))//防止点重复
if (!equalv3(p1, p2, tolerance))//防止点重复
pts.push({
pt: p2,
thisParam: cu1.GetParamAtPoint(p2),
@ -158,7 +158,7 @@ export function IntersectCircleAndArc(circle: Circle, arc: Arc, extType: Interse
*/
export function IntersectArcAndArc(arc1: Arc, arc2: Arc, extType: IntersectOption, tolerance = 1e-5)
{
let pts = IntersectCircleAndCircle(arc1, arc2);
let pts = IntersectCircleAndCircle(arc1, arc2, tolerance);
return CheckPointOnCurve(pts, arc1, arc2, extType, tolerance);
}
@ -176,7 +176,7 @@ export function IntersectEllipseAndLine(l: Line, el: Ellipse, extType: Intersect
* @param {(Circle | Arc)} circle
* @returns
*/
function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc): IntersectResult[]
function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc, tolerance = 1e-6): IntersectResult[]
{
let lineOrg = line.StartPoint;
let lineDirection = line.EndPoint.sub(lineOrg);
@ -189,7 +189,7 @@ function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc): Intersec
let a1 = lineDirection.dot(diff);
let discr = a1 ** 2 - a0;
if (equaln(discr, 0, 1e-7))
if (equaln(discr, 0, tolerance))
{
let pt = lineOrg.add(lineDirection.multiplyScalar(-a1));
@ -223,13 +223,13 @@ function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc): Intersec
//直线和圆
export function IntersectLineAndCircle(line: Line, circle: Circle, extType: IntersectOption, tolerance = 1e-6)
{
let ptArr = IntersectLineAndCircleOrArc(line, circle);
let ptArr = IntersectLineAndCircleOrArc(line, circle, tolerance);
return CheckPointOnCurve(ptArr, line, circle, extType | IntersectOption.ExtendArg);
}
//直线和圆弧
export function IntersectLineAndArc(line: Line, arc: Arc, extType: IntersectOption, tolerance = 1e-6)
{
let ptArr = IntersectLineAndCircleOrArc(line, arc);
let ptArr = IntersectLineAndCircleOrArc(line, arc, tolerance);
return CheckPointOnCurve(ptArr, line, arc, extType, tolerance);
}
//直线和直线

@ -113,7 +113,7 @@ export class RelevanceCuttingReactor
}
let objects = createEntitys.concat(changeEntitys).concat(deleteEntitys);
UpdateRelevanceWallHole(objects);
UpdateRelevanceWallHole(objects, true);
//不等待这个,因为这个方法不需要改变实体,只需要改变绘制
UpdateRelevanceGroove(objects);
});
@ -161,7 +161,7 @@ export class RelevanceCuttingReactor
}
let objects = createEntitys.concat(changeEntitys).concat(deleteEntitys);
UpdateRelevanceWallHole(objects);
UpdateRelevanceWallHole(objects, true);
//不等待这个,因为这个方法不需要改变实体,只需要改变绘制
UpdateRelevanceGroove(objects);
});
@ -208,7 +208,8 @@ export class RelevanceCuttingReactor
if (ExtrudeConfig.DisableRefCut) return;
let objects = changeObjects.concat(createObjects);
UpdateRelevanceWallHole(objects);
await UpdateRelevanceWallHole(objects);
//不等待这个,因为这个方法不需要改变实体,只需要改变绘制
UpdateRelevanceGroove(objects);
});

@ -10,6 +10,7 @@ import { RoomWallLine } from "../DatabaseServices/Room/Entity/Wall/RoomWallLine"
import { CreateGetCurveParam } from "../DatabaseServices/Room/ParseService/GetCurveParam";
import { FindBestRange, ParseWallRange } from "../DatabaseServices/Room/ParseService/Hole/RoomWallPlaceIHoleHelper";
import { RoomWallParse } from "../DatabaseServices/Room/ParseService/RoomWallParse";
import { TemplateRecord } from "../DatabaseServices/Template/TemplateRecord";
import { CurveMap } from "../Geometry/CurveMap";
import { equalv2 } from "../Geometry/GeUtils";
@ -17,12 +18,12 @@ import { equalv2 } from "../Geometry/GeUtils";
/**
*
*/
export async function UpdateRelevanceWallHole(ents: CADObject[])
export async function UpdateRelevanceWallHole(ents: CADObject[], isUndoRedo = false)
{
let updated = new Set<RoomWallBase | RoomHolePolyline>();
//更新墙,顺便更新洞
const UpdateWall = (wall: RoomWallBase) =>
const UpdateWall = async (wall: RoomWallBase) =>
{
if (updated.has(wall)) return;
updated.add(wall);//避免重入
@ -36,14 +37,14 @@ export async function UpdateRelevanceWallHole(ents: CADObject[])
if (wall.IsErase)
hole.Erase();
UpdateHole(hole);//这里如果只更新洞,那么有可能关联的其他的墙会逃逸
await UpdateHole(hole);//这里如果只更新洞,那么有可能关联的其他的墙会逃逸
}
UpdateWallHolesDataAndUpdateDraw(wall);
};
//更新洞,顺便更新关联的墙?
const UpdateHole = (hole: RoomHolePolyline) =>
const UpdateHole = async (hole: RoomHolePolyline) =>
{
if (updated.has(hole)) return;
updated.add(hole);//避免重入
@ -58,7 +59,13 @@ export async function UpdateRelevanceWallHole(ents: CADObject[])
let wall = wallId.Object as RoomWallBase;
if (updated.has(wall)) continue;
UpdateWall(wall);
await UpdateWall(wall);
}
if (!isUndoRedo && hole.Template?.IsErase === false)
{
let tr = hole.Template.Object as TemplateRecord;
await tr.UpdateTemplateTree();
}
};
@ -66,9 +73,9 @@ export async function UpdateRelevanceWallHole(ents: CADObject[])
for (let en of ents)
{
if (en instanceof RoomWallBase)
UpdateWall(en);
await UpdateWall(en);
else if (en instanceof RoomHolePolyline)
UpdateHole(en);
await UpdateHole(en);
}
}

@ -101,11 +101,13 @@ export class DoorModal extends React.Component<{ store: DoorDrawerStore, type: B
updateParams={this.props.store.currentTempProp}
disableKeys={DisableChangeParName}
onBlur={(n, v) => this.changeTemplateProps(n, v)}
isShowDetail={true}
/>
<H5></H5>
<TemplateDetail
updateParams={this.props.store.currentHandleProp}
disableKeys={DisableChangeParName}
isShowDetail={true}
/>
{
// isDoor &&

@ -26,8 +26,11 @@
}
.modal-container {
position: fixed;
outline : none;
position : fixed;
outline : none;
align-items : center;
display : flex;
justify-content: center;
.bp3-dialog-container {
outline: none;

@ -437,7 +437,9 @@
}
}
#commonModal .template-select {
#commonModal .template-select,
#template-select .template-select,
#modal .template-select{
position: absolute;
z-index: 30;
@ -489,3 +491,7 @@
min-width: 200px;
max-height: 70vh;
}
#template-select{
position: absolute;
}

@ -37,6 +37,7 @@ export interface ITemplateDetailProps
onBlur?: (name: string, val: string) => void;
isShowTag?: boolean;
currentDir?: IDirectoryProps;
isShowDetail?: boolean;
}
const POSITION_PAR = ["PX", "PY", "PZ"];
@ -169,40 +170,42 @@ export class TemplateDetail extends React.Component<ITemplateDetailProps> {
<Button text="移除标签" intent={Intent.DANGER} onClick={this.removeTag} />
</Label>
}
<ul onKeyDown={e => e.stopPropagation()}>
<li>
<span></span>
<span></span>
<span></span>
<span></span>
</li>
{
this.props.updateParams.map((par, index) =>
{
this.props.isShowDetail && <ul onKeyDown={e => e.stopPropagation()}>
<li>
<span></span>
<span></span>
<span></span>
<span></span>
</li>
{
if (!POSITION_PAR.includes(par.name) && !ROTATION_PAR.includes(par.name))
return (
<li key={index}>
<span title={par.name}>{par.name}</span>
<span>{FixedNotZero(par.value, 2)}</span>
<span title={par.description}>{par.description}</span>
<input
className={Classes.INPUT}
value={par.expr as string}
onChange={e => par.expr = e.target.value}
disabled={disabledKeys.includes(par.name) || par.isLock}
onBlur={e =>
{
if (this.props.onBlur)
this.props.updateParams.map((par, index) =>
{
if (!POSITION_PAR.includes(par.name) && !ROTATION_PAR.includes(par.name))
return (
<li key={index}>
<span title={par.name}>{par.name}</span>
<span>{FixedNotZero(par.value, 2)}</span>
<span title={par.description}>{par.description}</span>
<input
className={Classes.INPUT}
value={par.expr as string}
onChange={e => par.expr = e.target.value}
disabled={disabledKeys.includes(par.name) || par.isLock}
onBlur={e =>
{
this.props.onBlur(par.name, e.target.value);
}
}}
/>
</li>
);
})
}
</ul>
if (this.props.onBlur)
{
this.props.onBlur(par.name, e.target.value);
}
}}
/>
</li>
);
})
}
</ul>
}
{
!this.props.showSelectTemp && this.props.params && this.props.updateParams.length > 0 &&
<>

@ -48,6 +48,7 @@ export interface ITemplateListProps
insert?: (bool: boolean) => void;
searchStr?: string;
searchDir?: boolean;
isShowDetail?: boolean;
}
export interface ITempItemBack
@ -110,6 +111,7 @@ export class TemplateList extends React.Component<ITemplateListProps> {
isUpload={!this.props.forbidDelete}
disableKeys={!this.props.forbidDelete ? undefined : DisableChangeParName}
currentDir={this.props.currentDir}
isShowDetail={this.props.isShowDetail}
/>
</div>
);

@ -111,6 +111,7 @@ export class TemplateSelect extends React.Component<ITemplateselectProps, {}> {
forbidDelete={true}
hideSelectBox={true}
selectInfo={this.props.store.selectTemplateInfo}
isShowDetail={true}
/>
</CommonPanel>
</div>

@ -0,0 +1,246 @@
import { Card, ContextMenu, Icon, Intent, Menu, MenuItem } from '@blueprintjs/core';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ITempTagProps, templateTagCommand } from '../../../Add-on/Template/TemplateTagCommand';
import { CURRENT_HOST, TemplateUrls } from '../../../Common/HostUrl';
import { inflateBase64 } from "../../../Common/inflate";
import { MouseKey } from '../../../Common/KeyEnum';
import { PostJson, RequestStatus } from '../../../Common/Request';
import { TemplateParamsIn } from '../../../Common/SerializeMaterial';
import { TemplateParam } from '../../../DatabaseServices/Template/Param/TemplateParam';
import { IDrawerDoorTempInfo } from '../../Store/DoorInterface';
import { ITemplateParam } from "../../Store/RightPanelStore/ITemplateParam";
import { HandleDirComponent } from '../SourceManage/HandleDirComponent';
import { Pagination } from '../SourceManage/Pagination';
import { IGetRoomInfo } from './GetRoomCabName';
import { TemplateDetail } from './TemplateDetail';
export interface ITemplateTagComProps
{
currentTag: ITempTagProps;
currentTemplateInfo: IDrawerDoorTempInfo;
currentProps: ITemplateParam[];
cabOption: IGetRoomInfo;
insert: (isByBasePt: boolean) => void;
}
@observer
export class TemplateTagCom extends React.Component<ITemplateTagComProps> {
@observable private params: TemplateParam[] = [];
@observable private dataList = [];
@observable private pageData = {
count: 0,
currentPage: 1,
pageCount: 16,
};
@observable private currentTag: ITempTagProps = { tagName: "", dirId: "", description: "" };
private canInput = observable.box(false);
private isDesc = true;
async UNSAFE_componentWillMount()
{
Object.assign(this.currentTag, this.props.currentTag);
await this.readTemplateInfo();
}
public render()
{
return (
<Card tabIndex={-1} className="flex" style={{ height: "100%", outline: "none" }}>
<ul className="tag-name-list">
{
templateTagCommand.TagList.map(tag =>
{
return (
<li className={tag.dirId === this.currentTag?.dirId ? "active" : ""} data-id={tag.tagName} onMouseDown={this.selectTemplateTag} >
<Icon icon="tag" />
{tag.tagName} | {tag.description}</li>
);
})
}
</ul>
<div className="tag-list" style={{ overflow: "scroll" }}>
{
this.dataList.map(d =>
{
return (
<div
className={this.props.currentTemplateInfo.id === d.mid ? "active tag-img" : "tag-img"}
onClick={() => this.selectTemp(d)}
onDoubleClick={() => { if (this.props.insert) this.props.insert(false); }}
>
<div style={{ height: 0, paddingBottom: "100%", textAlign: "center" }}>
<img src={d.logo} style={{ height: "auto", width: "80%" }} alt="" />
</div>
<p className="data-title">{d.name}</p>
</div>
);
})
}
{
this.pageData.count > this.pageData.pageCount && <Pagination
pageData={this.pageData}
getImgListFun={this.readTemplateInfo}
/>
}
</div>
<TemplateDetail
className="tag-temp-detail"
updateParams={this.props.currentProps}
currentInfo={this.props.currentTemplateInfo}
showSelectTemp={false}
isUpload={true}
disableKeys={undefined}
isShowTag={false}
params={this.params}
isShowDetail={true}
/>
{
this.canInput.get() && <HandleDirComponent
defualtValue={this.isDesc ? this.currentTag.description : this.currentTag.tagName}
isReset={false}
isOpen={this.canInput}
title={this.isDesc ? "备注" : "标签名"}
handleFunc={this.addTagDesc}
/>
}
</Card>
);
}
private readTemplateInfo = async (pageData?: { curr_page: number; }) =>
{
if (pageData)
this.pageData.currentPage = pageData.curr_page;
let data = await PostJson(TemplateUrls.list, { dir_id: this.currentTag.dirId, page_count: this.pageData.pageCount, curr_page: this.pageData.currentPage });
if (data.err_code === RequestStatus.Ok && data.modules)
{
this.pageData.count = Number(data.count);
let tempData = data.modules;
observable(this.dataList).replace(tempData.map(d =>
{
return {
logo: CURRENT_HOST + "/" + d.logo,
mid: d.module_id,
name: d.name,
props: d.props,
};
}));
if (this.dataList.length === 1)
{
this.selectTemp(this.dataList[0]);
}
}
else
this.dataList.length === 0;
};
private selectTemplateTag = async (e: React.MouseEvent<HTMLLIElement>) =>
{
if (e.button === MouseKey.Right)
{
this.showContextMenu(e);
}
let tagName = e.currentTarget.getAttribute('data-id');
Object.assign(this.currentTag, templateTagCommand.GetTagByName(tagName));
await this.readTemplateInfo();
};
private _propsCache = new Map<string, TemplateParam[]>();
private selectTemp(data: { mid: string, name: string, props: string; })
{
const { mid, name, props } = data;
this.props.currentTemplateInfo.id = mid;
this.props.currentTemplateInfo.name = name;
this.props.currentTemplateInfo.isHandle = this.currentTag.description.includes("拉手");
this.props.currentTemplateInfo.isHinge = this.currentTag.description.includes("铰链");
this.props.currentTemplateInfo.isKuGan = this.currentTag.description.includes("裤杆");
if (!this.props.cabOption.useCabName)
{
this.props.cabOption.cabName = data.name;
this.props.cabOption.originCabName = data.name;
this.props.cabOption.cabIndex = 0;
}
let pars: TemplateParam[];
if (this._propsCache.has(props))
{
pars = this._propsCache.get(props);
}
else
pars = TemplateParamsIn(JSON.parse(inflateBase64(props)));
observable(this.params).replace(pars);
observable(this.props.currentProps).replace(pars.map(p =>
{
return {
name: p.name,
value: p.value,
description: p.description,
expr: p.expr,
};
}));
}
//展示右键菜单
private showContextMenu = (e: React.MouseEvent<HTMLElement>) =>
{
let tagName = e.currentTarget.getAttribute('data-id');
ContextMenu.show(
<Menu>
<MenuItem
icon="annotation"
text="修改标签"
onClick={() =>
{
this.isDesc = false;
this.canInput.set(true);
}}
/>
<MenuItem
icon="comment"
text="编辑描述"
onClick={() =>
{
this.isDesc = true;
this.canInput.set(true);
}}
/>
<MenuItem
icon="trash"
text="移除标签"
intent={Intent.DANGER}
onClick={() => this.removeTag(tagName)}
/>
</Menu>,
{ left: e.clientX, top: e.clientY },
() => this.setState({ isContextMenuOpen: false }),
);
this.setState({ isContextMenuOpen: true });
e.stopPropagation();
e.preventDefault();
};
private removeTag = (tagName: string) =>
{
if (confirm("确定移除标签?"))
{
this.dataList.length = 0;
templateTagCommand.RemoveTag(tagName);
}
};
private addTagDesc = (val: string) =>
{
if (this.isDesc)
{
templateTagCommand.ModifyTagName(this.currentTag.tagName, undefined, val);
this.currentTag.description = val;
}
else
{
templateTagCommand.ModifyTagName(this.currentTag.tagName, val.toUpperCase());
this.currentTag.tagName = val.toUpperCase();
}
this.canInput.set(false);
};
}

@ -283,6 +283,16 @@
}
}
}
.BayWindowParam{
.BayWindowLeftRightWall{
margin-top: 10px;
}
}
}
}
.bp3-icon.bp3-icon-add-to-artifact{
padding: 20px;
}
}

@ -1,31 +1,66 @@
import { Divider } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component, RefObject } from 'react';
import { app } from '../../../../ApplicationServices/Application';
import { RoomBase } from '../../../../DatabaseServices/Room/Entity/RoomBase';
import { DoorWindowPanelStore } from '../../../../DatabaseServices/Room/Entity/Wall/Hole/Window/WindowPanelStore';
import { TemplateRoomDoorRecord } from '../../../../DatabaseServices/Template/ProgramTempate/TemplateRoomDoorRecord';
import { TemplateWindowRecord } from '../../../../DatabaseServices/Template/ProgramTempate/TemplateWindowRecord';
import './ModifyModel.less';
import ModifyModelStore from './ModifyModelStore';
import ModuleBaseParams from './ModuleBaseParams';
import RoomBaseParams from './RoomBaseParams';
import RoomBaseParamsStore from './RoomBaseParamsStore';
@observer
export default class ModifyModelPanel extends Component
{
ModifyModelPanelRef: RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>();
ModifyModelStore: ModifyModelStore = ModifyModelStore.GetSingleInstance();
_ModifyModelPanelRef: RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>();
_ModifyModelStore: ModifyModelStore = ModifyModelStore.GetSingleInstance();
_RoomBaseParamsStore: RoomBaseParamsStore = RoomBaseParamsStore.GetSingleInstance();
_DoorWindowPanelStore: DoorWindowPanelStore = DoorWindowPanelStore.GetSingleInstance();
_RoomBasseEnts: RoomBase[] = [];
_DoorWindowTemp: TemplateWindowRecord | TemplateRoomDoorRecord;
render()
{
this._RoomBasseEnts = this._RoomBaseParamsStore._EntityIds.map(id => app.Database.GetObjectId(id)?.Object) as RoomBase[];
let roomBasseEnt = this._RoomBasseEnts[0];
let temp = roomBasseEnt?.Template?.Object;
if (temp && this._DoorWindowTemp?.Id !== temp.Id)
{
if (temp instanceof TemplateWindowRecord)
{
this._DoorWindowTemp = temp;
this._DoorWindowPanelStore.InitCurrentWindowOption(this._DoorWindowTemp);
}
else if (temp instanceof TemplateRoomDoorRecord)
this._DoorWindowTemp = temp;
}
else
this._DoorWindowTemp = undefined;
return (
<div className='ModifyModelPanel' id='ModifyModelPanel' ref={this.ModifyModelPanelRef}>
<div className='ModifyModelPanel' id='ModifyModelPanel' ref={this._ModifyModelPanelRef}>
<main className='ModifyModelPanelWrapper'>
<div className='ModifyModulePanelTitle'>
<div className='TitleInfo'>
<div>
{this.ModifyModelStore.name}
{this._ModifyModelStore.name}
</div>
</div>
</div>
<Divider />
<ModuleBaseParams />
<RoomBaseParams />
<ModuleBaseParams
ModifyModelStore={this._ModifyModelStore}
RoomBaseParamsStore={this._RoomBaseParamsStore}
/>
<RoomBaseParams
RoomBaseParamsStore={this._RoomBaseParamsStore}
DoorWindowPanelStore={this._DoorWindowPanelStore}
RoomBasseEnts={this._RoomBasseEnts}
DoorWindowTemp={this._DoorWindowTemp}
/>
</main>
</div>
);

@ -17,19 +17,24 @@ export enum ModuleAxis
y = 'y',
z = 'z',
}
@observer
export default class ModuleBaseParams extends Component<{}, {}>
interface ModuleBaseParamsProps
{
ModifyModelStore: ModifyModelStore = ModifyModelStore.GetSingleInstance();
RoomBaseParamsStore: RoomBaseParamsStore = RoomBaseParamsStore.GetSingleInstance();
ModifyModelStore: ModifyModelStore;
RoomBaseParamsStore: RoomBaseParamsStore;
}
@observer
export default class ModuleBaseParams extends Component<ModuleBaseParamsProps, {}>
{
render()
{
const { ModifyModelStore } = this;
const { ModifyModelStore, RoomBaseParamsStore } = this.props;
let ents = ModifyModelStore._EntityIds.map(id => app.Database.GetObjectId(id)?.Object).filter(en => en && !en.IsErase && en instanceof Entity) as Entity[];
return (
<div className='ModuleBaseParams'
style={{ display: ents.length < 1 || this.RoomBaseParamsStore._EntityIds.length > 0 ? 'none' : "block" }}
style={{ display: ents.length < 1 || RoomBaseParamsStore._EntityIds.length > 0 ? 'none' : "block" }}
>
<div className='CollapseOpenTitle'
onClick={() => { ModifyModelStore.isCollapseOpened = !ModifyModelStore.isCollapseOpened; }}
@ -65,17 +70,17 @@ export default class ModuleBaseParams extends Component<{}, {}>
<div className='CollapseContent'>
<div className='ParamsSize'>
<SizeComponent
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
sizeKey={"module_Length"}
title={"长度"}
/>
<SizeComponent
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
sizeKey={"module_Width"}
title={"宽度"}
/>
<SizeComponent
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
sizeKey={"module_Height"}
title={"高度"}
/>
@ -109,17 +114,17 @@ export default class ModuleBaseParams extends Component<{}, {}>
<div className='ParamsPosition'>
<span></span>
<PositionInput
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
postionKey={"positionX"}
type={ModuleAxis.x}
/>
<PositionInput
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
postionKey={"positionY"}
type={ModuleAxis.y}
/>
<PositionInput
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
postionKey={"positionZ"}
type={ModuleAxis.z}
/>
@ -128,17 +133,17 @@ export default class ModuleBaseParams extends Component<{}, {}>
<div className='ParamsRotate'>
<span></span>
<RotateInput
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
rotateKey={"rotateX"}
type={AxisType.X}
/>
<RotateInput
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
rotateKey={"rotateY"}
type={AxisType.Y}
/>
<RotateInput
store={this.ModifyModelStore}
store={this.props.ModifyModelStore}
rotateKey={"rotateZ"}
type={AxisType.Z}
/>

@ -1,51 +1,72 @@
import { Collapse, Icon } from '@blueprintjs/core';
import { Checkbox, Collapse, Divider, Icon } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { app } from '../../../../ApplicationServices/Application';
import { DuplicateRecordCloning } from '../../../../Common/Status';
import { RoomBase } from '../../../../DatabaseServices/Room/Entity/RoomBase';
import { RoomHoleBase } from '../../../../DatabaseServices/Room/Entity/Wall/Hole/RoomHoleBase';
import { RoomHolePolyline } from '../../../../DatabaseServices/Room/Entity/Wall/Hole/RoomHolePolyline';
import { DoorWindowPanelStore } from '../../../../DatabaseServices/Room/Entity/Wall/Hole/Window/WindowPanelStore';
import { WindowTempInfo } from '../../../../DatabaseServices/Room/Entity/Wall/Hole/Window/WindowTempInfo';
import { RoomWallBase } from '../../../../DatabaseServices/Room/Entity/Wall/RoomWallBase';
import { TemplateRoomDoorRecord } from '../../../../DatabaseServices/Template/ProgramTempate/TemplateRoomDoorRecord';
import { TemplateWindowRecord } from '../../../../DatabaseServices/Template/ProgramTempate/TemplateWindowRecord';
import { GetOnlineTemplate } from '../../../../DatabaseServices/Template/TempateUtils';
import { TemplateRecord } from '../../../../DatabaseServices/Template/TemplateRecord';
import { CommandWrap } from '../../../../Editor/CommandMachine';
import RoomBaseParamsStore, { RoomBaseParamsNames } from "./RoomBaseParamsStore";
import { RoomParamsComPonent } from './RoomWallParams';
@observer
export default class RoomBaseParams extends Component<{}, {}>
export enum Location
{
Left = "left",
Middle = "middle",
Right = "right",
All = "all",
}
interface RoomBaseParamsProps
{
roomBaseParamsStore: RoomBaseParamsStore = RoomBaseParamsStore.GetSingleInstance();
RoomBaseParamsStore: RoomBaseParamsStore;
DoorWindowPanelStore: DoorWindowPanelStore;
RoomBasseEnts: RoomBase[];
DoorWindowTemp: TemplateWindowRecord | TemplateRoomDoorRecord;
}
@observer
export default class RoomBaseParams extends Component<RoomBaseParamsProps, {}>
{
render()
{
const RoomBaseParamStore = this.roomBaseParamsStore;
let roomBasseEnts = RoomBaseParamStore._EntityIds.map(id => app.Database.GetObjectId(id)?.Object) as RoomBase[];
let roomBasseEnt = roomBasseEnts[0];
const { RoomBaseParamsStore, DoorWindowPanelStore } = this.props;
let roomBasseEnt = this.props.RoomBasseEnts[0];
return (
<div className='ModuleBaseParams'>
{
roomBasseEnts[0] instanceof RoomWallBase && <div>
roomBasseEnt instanceof RoomWallBase && <div>
<div className='CollapseOpenTitle'
onClick={() => { RoomBaseParamStore.isRoomWallParamsOpen = !RoomBaseParamStore.isRoomWallParamsOpen; }}
onClick={() => { RoomBaseParamsStore.isRoomWallParamsOpen = !RoomBaseParamsStore.isRoomWallParamsOpen; }}
>
<div>
<Icon icon={RoomBaseParamStore.isRoomWallParamsOpen ? 'chevron-up' : "chevron-down"} />
<Icon icon={RoomBaseParamsStore.isRoomWallParamsOpen ? 'chevron-up' : "chevron-down"} />
</div>
</div>
<Collapse isOpen={RoomBaseParamStore.isRoomWallParamsOpen}>
<Collapse isOpen={RoomBaseParamsStore.isRoomWallParamsOpen}>
<div className='CollapseContent'>
<div className='ParamsSize'>
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.WallThick}
sliderMin={10}
sliderMax={300}
sliderMax={500}
title={"墙厚"}
/>
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.WallHeight}
sliderMin={100}
sliderMin={500}
sliderMax={10000}
title={"墙高"}
/>
@ -55,78 +76,224 @@ export default class RoomBaseParams extends Component<{}, {}>
</div>
}
{
roomBasseEnt instanceof RoomHoleBase && <div>
roomBasseEnt instanceof RoomHoleBase &&
<div>
{
this.props.DoorWindowTemp &&
<WindowTempInfo
store={this.props.DoorWindowPanelStore}
logo={this.props.DoorWindowTemp instanceof TemplateWindowRecord ? this.props.DoorWindowTemp.WindowLogo : this.props.DoorWindowTemp.DoorLogo}
doorWindowTemp={this.props.DoorWindowTemp}
location={Location.Middle}
/>
}
<div className='CollapseOpenTitle'
onClick={() => { RoomBaseParamStore.isRoomHoleParamsOpen = !RoomBaseParamStore.isRoomHoleParamsOpen; }}
onClick={() => { RoomBaseParamsStore.isRoomHoleParamsOpen = !RoomBaseParamsStore.isRoomHoleParamsOpen; }}
>
<div>
<Icon icon={RoomBaseParamStore.isRoomHoleParamsOpen ? 'chevron-up' : "chevron-down"} />
<Icon icon={RoomBaseParamsStore.isRoomHoleParamsOpen ? 'chevron-up' : "chevron-down"} />
</div>
</div>
<Collapse isOpen={RoomBaseParamStore.isRoomHoleParamsOpen}>
<Collapse isOpen={RoomBaseParamsStore.isRoomHoleParamsOpen}>
<div className='CollapseContent'>
<div className='ParamsSize'>
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.HoleHeight}
sliderMin={100}
sliderMax={RoomBaseParamStore.holeMaxHightDist}
sliderMin={200}
sliderMax={RoomBaseParamsStore.holeMaxHightDist}
title={"高度"}
/>
{
(roomBasseEnt as RoomHolePolyline).Points.length < 3 &&
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.HoleLength}
sliderMin={100}
sliderMax={RoomBaseParamStore.holeMaxLengthDist}
sliderMin={200}
sliderMax={RoomBaseParamsStore.holeMaxLengthDist}
title={"宽度"}
/>
}
{
RoomBaseParamStore.holeLeftDistSliderMax !== 0 &&
RoomBaseParamsStore.holeLeftDistSliderMax !== 0 &&
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.HoleLeftDist}
sliderMin={RoomBaseParamStore.holeLeftDistSliderMin}
sliderMax={RoomBaseParamStore.holeLeftDistSliderMax}
sliderMin={RoomBaseParamsStore.holeLeftDistSliderMin}
sliderMax={RoomBaseParamsStore.holeLeftDistSliderMax}
title={"左距"}
/>
}
{
RoomBaseParamStore.holeRightDistSliderMax !== 0 &&
RoomBaseParamsStore.holeRightDistSliderMax !== 0 &&
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.HoleRightDist}
sliderMin={RoomBaseParamStore.holeRightDistSliderMin}
sliderMax={RoomBaseParamStore.holeRightDistSliderMax}
sliderMin={RoomBaseParamsStore.holeRightDistSliderMin}
sliderMax={RoomBaseParamsStore.holeRightDistSliderMax}
title={"右距"}
/>
}
{
RoomBaseParamStore.holeTopDistSliderMax !== 0 &&
RoomBaseParamsStore.holeTopDistSliderMax !== 0 &&
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.HoleTopDist}
sliderMin={0}
sliderMax={RoomBaseParamStore.holeTopDistSliderMax}
sliderMax={RoomBaseParamsStore.holeTopDistSliderMax}
title={"上距"}
/>
}
{
RoomBaseParamStore.holeBottomDistSliderMax !== 0 &&
RoomBaseParamsStore.holeBottomDistSliderMax !== 0 &&
<RoomParamsComPonent
store={RoomBaseParamStore}
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.HoleBottomDist}
sliderMin={0}
sliderMax={RoomBaseParamStore.holeBottomDistSliderMax}
sliderMax={RoomBaseParamsStore.holeBottomDistSliderMax}
title={"下距"}
/>
}
</div>
</div>
</Collapse>
{
this.props.DoorWindowTemp && this.props.DoorWindowTemp instanceof TemplateWindowRecord && this.props.DoorWindowTemp.WpDists && !(this.props.DoorWindowTemp.WpDists.every(d => d === 0)) &&
<div className='BayWindowParam'>
<Divider />
<div className='CollapseOpenTitle'
onClick={() => { RoomBaseParamsStore.isBayWindowOpen = !RoomBaseParamsStore.isBayWindowOpen; }}
>
<div>
<Icon icon={RoomBaseParamsStore.isBayWindowOpen ? 'chevron-up' : "chevron-down"} />
</div>
</div>
<Collapse isOpen={RoomBaseParamsStore.isBayWindowOpen}>
<div className='BayWindowLeftRightWall'>
<Checkbox
label="飘窗左侧是墙"
checked={DoorWindowPanelStore.m_Option.BayLeftIsWall}
onChange={() =>
{
DoorWindowPanelStore.m_Option.BayLeftIsWall = !DoorWindowPanelStore.m_Option.BayLeftIsWall;
CommandWrap(async () =>
{
let windowTr = this.props.DoorWindowTemp as TemplateWindowRecord;
windowTr.LeftIsWall = DoorWindowPanelStore.m_Option.BayLeftIsWall;
if (!DoorWindowPanelStore.m_Option.BayLeftIsWall)
{
let leftWindowTr = await GetOnlineTemplate(windowTr.LeftWindowTemplateId);
let template = app.Database.WblockCloneObejcts([leftWindowTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
windowTr.Children.unshift(template.Id);
}
else
{
let tr = windowTr.Children[0].Object as TemplateRecord;
for (let en of tr.Entitys) en.Erase();
tr.GoodBye();
windowTr.Children.shift();
}
await this.props.DoorWindowTemp.UpdateTemplateTree();
}, "修改属性");
}}
/>
<Collapse isOpen={!DoorWindowPanelStore.m_Option.BayLeftIsWall}>
<WindowTempInfo
store={this.props.DoorWindowPanelStore}
logo={this.props.DoorWindowTemp.LeftWindowLogo}
doorWindowTemp={this.props.DoorWindowTemp}
location={Location.Left}
/>
<Divider />
</Collapse>
</div>
<div className='BayWindowLeftRightWall'>
<Checkbox
label="飘窗右侧是墙"
checked={DoorWindowPanelStore.m_Option.BayRightIsWall}
onChange={() =>
{
DoorWindowPanelStore.m_Option.BayRightIsWall = !DoorWindowPanelStore.m_Option.BayRightIsWall;
CommandWrap(async () =>
{
let windowTr = this.props.DoorWindowTemp as TemplateWindowRecord;
windowTr.RightIsWall = DoorWindowPanelStore.m_Option.BayRightIsWall;
if (!DoorWindowPanelStore.m_Option.BayRightIsWall)
{
let rightWindowTr = await GetOnlineTemplate(windowTr.RightWindowTemplateId);
let template = app.Database.WblockCloneObejcts([rightWindowTr], app.Database.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord;
windowTr.Children.push(template.Id);
}
else
{
let tr = windowTr.Children[windowTr.Children.length - 1].Object as TemplateRecord;
for (let en of tr.Entitys) en.Erase();
tr.GoodBye();
windowTr.Children.pop();
}
await this.props.DoorWindowTemp.UpdateTemplateTree();
}, "修改属性");
}}
/>
<Collapse isOpen={!DoorWindowPanelStore.m_Option.BayRightIsWall}>
<WindowTempInfo
store={this.props.DoorWindowPanelStore}
logo={this.props.DoorWindowTemp.RightWindowLogo}
doorWindowTemp={this.props.DoorWindowTemp}
location={Location.Right}
/>
<Divider />
</Collapse>
</div>
<div className='CollapseContent'>
<div className='ParamsSize'>
{
this.props.DoorWindowTemp.WpDists?.length === 1 && <RoomParamsComPonent
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.BayDist}
sliderMin={RoomBaseParamsStore.bayMinDist}
sliderMax={RoomBaseParamsStore.bayMaxDist}
title={"外飘"}
/>
}
{
this.props.DoorWindowTemp.WpDists?.length > 1 && <RoomParamsComPonent
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.BayLeftDist}
sliderMin={RoomBaseParamsStore.bayMinDist}
sliderMax={RoomBaseParamsStore.bayMaxDist}
title={"左飘"}
/>
}
{
this.props.DoorWindowTemp.WpDists?.length === 3 && < RoomParamsComPonent
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.BayMiddleDist}
sliderMin={RoomBaseParamsStore.bayMinDist}
sliderMax={RoomBaseParamsStore.bayMaxDist}
title={"中飘"}
/>
}
{
this.props.DoorWindowTemp.WpDists?.length > 1 && <RoomParamsComPonent
store={RoomBaseParamsStore}
sizeKey={RoomBaseParamsNames.BayRightDist}
sliderMin={RoomBaseParamsStore.bayMinDist}
sliderMax={RoomBaseParamsStore.bayMaxDist}
title={"右飘"}
/>
}
</div>
</div>
</Collapse>
</div>
}
</div>
}
</div>

@ -9,6 +9,9 @@ import { RoomHolePolyline } from "../../../../DatabaseServices/Room/Entity/Wall/
import { RoomWallBase } from "../../../../DatabaseServices/Room/Entity/Wall/RoomWallBase";
import { RoomIHoleParseAndModify, RoomLHoleParseAndModify } from "../../../../DatabaseServices/Room/ParseService/Hole/RoomIHoleParseAndModify";
import { RoomWallParse } from "../../../../DatabaseServices/Room/ParseService/RoomWallParse";
import { TemplateRoomDoorRecord } from "../../../../DatabaseServices/Template/ProgramTempate/TemplateRoomDoorRecord";
import { TemplateWindowRecord } from "../../../../DatabaseServices/Template/ProgramTempate/TemplateWindowRecord";
import { TemplateRecord } from "../../../../DatabaseServices/Template/TemplateRecord";
import { commandMachine } from "../../../../Editor/CommandMachine";
import { CommandState } from "../../../../Editor/CommandState";
import { UpdateHoleFakerWallsAndUpdateDraw } from "../../../../Reactor/RoomHoleReactor";
@ -24,12 +27,17 @@ export enum RoomBaseParamsNames
HoleRightDist = "holeRightDist",
HoleTopDist = "holeTopDist",
HoleBottomDist = "holeBottomDist",
BayDist = "bayDist",
BayLeftDist = "bayLeftDist",
BayMiddleDist = "bayMiddleDist",
BayRightDist = "bayRightDist",
}
export default class RoomBaseParamsStore
{
@observable isRoomWallParamsOpen: boolean = true;
@observable isRoomHoleParamsOpen: boolean = true;
@observable isBayWindowOpen: boolean = true;
@observable wallThick: number = 10;
@observable wallHeight: number = 1000;
@observable holeHeight: number = 500;
@ -46,6 +54,12 @@ export default class RoomBaseParamsStore
@observable holeRightDistSliderMax: number = 0;
@observable holeTopDistSliderMax: number = 0;
@observable holeBottomDistSliderMax: number = 0;
@observable bayDist: number = 0; //外飘距离
@observable bayLeftDist: number = 0; //左飘距离
@observable bayMiddleDist: number = 0; //中飘距离
@observable bayRightDist: number = 0; //右飘距离
@observable bayMinDist: number = 100;
@observable bayMaxDist: number = 2000;
@observable _EntityIds: number[] = [];
private constructor()
@ -56,7 +70,25 @@ export default class RoomBaseParamsStore
if (selectCtrl.SelectSet.SelectObjectCount > 50)
observable(this._EntityIds).replace([]);
else
observable(this._EntityIds).replace(selectCtrl.SelectSet.SelectEntityList.filter(e => e.Id && e instanceof RoomBase).map(e => e.Id.Index));
{
let entIds = [];
for (let en of selectCtrl.SelectSet.SelectEntityList)
{
if (en.Id)
{
if (en instanceof RoomBase)
{
entIds.push(en.Id.Index);
continue;
}
let temp = en.Template?.Object as TemplateRecord;
if (!temp) continue;
if (temp.Parent?.Object instanceof TemplateWindowRecord || temp.Parent?.Object instanceof TemplateRoomDoorRecord)
entIds.push(temp.Parent?.Object?.HoleObjectId?.Index);
}
}
observable(this._EntityIds).replace(entIds);
}
this.UpdateUIData();
});
@ -165,6 +197,26 @@ export default class RoomBaseParamsStore
this.holeTopDistSliderMax = m.MaxTopDist;
this.holeBottomDistSliderMax = m.MaxBottomDist;
}
let temp = ent.Template?.Object as TemplateRecord;
if (temp && temp instanceof TemplateWindowRecord)
{
if (temp.WpDists.length === 1)
{
this.bayDist = temp.WpDists[0];
}
else if (temp.WpDists.length === 2)
{
this.bayLeftDist = temp.WpDists[0];
this.bayRightDist = temp.WpDists[1];
}
else if (temp.WpDists.length === 3)
{
this.bayLeftDist = temp.WpDists[0];
this.bayMiddleDist = temp.WpDists[1];
this.bayRightDist = temp.WpDists[2];
}
}
}
}
@ -212,14 +264,16 @@ export default class RoomBaseParamsStore
{
let mIHole = ent.Points.length === 2 ? new RoomIHoleParseAndModify(ent) : null;
let mLHole = ent.Points.length > 2 ? new RoomLHoleParseAndModify(ent) : null;
if (size_key === RoomBaseParamsNames.HoleHeight)
let windowTemp = ent.Template?.Object as TemplateWindowRecord;
if (size_key === RoomBaseParamsNames.HoleHeight) //宽度
{
if (ent.Points.length === 2)
mIHole.Height = this.holeHeight;
else
mLHole.Height = this.holeHeight;
}
else if (size_key === RoomBaseParamsNames.HoleLength)
else if (size_key === RoomBaseParamsNames.HoleLength) //长度
{
if (ent.Points.length === 2)
{
@ -227,7 +281,7 @@ export default class RoomBaseParamsStore
UpdateHoleFakerWallsAndUpdateDraw(ent);
}
}
else if (size_key === RoomBaseParamsNames.HoleLeftDist)
else if (size_key === RoomBaseParamsNames.HoleLeftDist) //左距
{
if (ent.Points.length === 2)
mIHole.LeftDist = this.holeLeftDist;
@ -235,7 +289,7 @@ export default class RoomBaseParamsStore
mLHole.LeftDist = this.holeLeftDist;
UpdateHoleFakerWallsAndUpdateDraw(ent);
}
else if (size_key === RoomBaseParamsNames.HoleRightDist)
else if (size_key === RoomBaseParamsNames.HoleRightDist) //右距
{
if (ent.Points.length === 2)
mIHole.RightDist = this.holeRightDist;
@ -243,20 +297,32 @@ export default class RoomBaseParamsStore
mLHole.RightDist = this.holeRightDist;
UpdateHoleFakerWallsAndUpdateDraw(ent);
}
else if (size_key === RoomBaseParamsNames.HoleTopDist)
else if (size_key === RoomBaseParamsNames.HoleTopDist) //上距
{
if (ent.Points.length === 2)
mIHole.TopDist = this.holeTopDist;
else
mLHole.TopDist = this.holeTopDist;
}
else if (size_key === RoomBaseParamsNames.HoleBottomDist)
else if (size_key === RoomBaseParamsNames.HoleBottomDist) //下距
{
if (ent.Points.length === 2)
mIHole.BottomDist = this.holeBottomDist;
else
mLHole.BottomDist = this.holeBottomDist;
}
else if (size_key === RoomBaseParamsNames.BayDist) //窗户外飘
{
windowTemp.WpDist = [this.bayDist];
await windowTemp.UpdateTemplateTree();
}
else if (size_key === RoomBaseParamsNames.BayLeftDist
|| size_key === RoomBaseParamsNames.BayMiddleDist
|| size_key === RoomBaseParamsNames.BayRightDist)
{
windowTemp.WpDist = windowTemp.WpDists.length === 2 ? [this.bayLeftDist, this.bayRightDist] : [this.bayLeftDist, this.bayMiddleDist, this.bayRightDist];
await windowTemp.UpdateTemplateTree();
}
this.UpdateUIData();
}
}

@ -24,12 +24,18 @@ export class RoomDesignPanel extends React.Component<{ store: ToolsBlockStore; }
execFun={execFun}
btnTitile="画墙洞"
/>
{/* <ToolsBlock
<ToolsBlock
blockId={"roomDesign"}
list={iconList.roomWindow}
execFun={execFun}
btnTitile="画窗"
/> */}
/>
<ToolsBlock
blockId={"roomDesign"}
list={iconList.oneKeyDrawDoorWindow}
execFun={execFun}
btnTitile="一键画门窗"
/>
</div>
);
}

@ -25,6 +25,8 @@ export class ToolsBlockStore extends Singleton
gallery: [],
roomWall: [],
roomHole: [],
roomWindow: [],
oneKeyDrawDoorWindow: [],
};
//记录每个tab面板的工具块id和图标总数
blocksData: TopToolBarBlockData =

@ -202,12 +202,19 @@ export class TopToolBar extends React.Component<{}, {}>
{ svg: IconEnum.RoomLHole, title: "L型洞", command: CommandNames.DrawLHole },
{ svg: IconEnum.RoomUHole, title: "U型洞", command: CommandNames.DrawUHole },
];
// store.iconList.roomWindow = [
// { svg: IconEnum.DrawWindow, title: "画窗", command: CommandNames.DrawIHole },
// { svg: IconEnum.DrawLWindow, title: "L型窗", command: CommandNames.DrawLHole },
// { svg: IconEnum.DrawUWindow, title: "弧形U型窗", command: CommandNames.DrawUHole },
// { svg: IconEnum.DrawUWindow2, title: "圆角U型窗", command: CommandNames.DrawUHole },
// ];
store.iconList.roomWindow = [
{ svg: IconEnum.DrawWindow, title: "画窗", command: CommandNames.DrawIWindow },
{ svg: IconEnum.DrawLWindow, title: "L型窗", command: CommandNames.DrawLWindow },
{ svg: IconEnum.DrawUWindow2, title: "U型窗", command: CommandNames.DrawUWindow },
{ svg: IconEnum.DrawDoor, title: "门", command: CommandNames.DrawIDoor },
];
store.iconList.oneKeyDrawDoorWindow = [
{ svg: IconEnum.DrawWindow, title: "一字窗", command: CommandNames.YZC },
{ svg: IconEnum.DrawWindow, title: "落地窗", command: CommandNames.LDC },
{ svg: IconEnum.DrawLWindow, title: "转角窗", command: CommandNames.ZJC },
{ svg: IconEnum.DrawPWindow, title: "飘窗", command: CommandNames.PC },
{ svg: IconEnum.DrawLWindow, title: "转角飘窗", command: CommandNames.ZJPC },
];
store.calcIconNumInTabs();
let topStore = DownPanelStore.GetInstance() as DownPanelStore;

@ -25,7 +25,8 @@ export interface ToolsBlockOption
gallery: ICommandIconInfo[];
roomWall: ICommandIconInfo[];
roomHole: ICommandIconInfo[];
// roomWindow: ICommandIconInfo[];
roomWindow: ICommandIconInfo[];
oneKeyDrawDoorWindow: ICommandIconInfo[];
}
export interface TopToolBarBlockDataItem
{

@ -1264,10 +1264,10 @@ img {
}
input{
margin-top : -5px;
margin-top : -5px;
}
}
}
.bp3-dialog-footer{
@ -1278,3 +1278,108 @@ img {
background-color: white;
}
}
#DrawWindowPanel{
.bp3-dialog-body{
padding : 10px 25px 20px 20px;
background-color: white;
.paramsSize {
>div {
width : 100%;
height : 35px;
display : flex;
align-items : center;
justify-content: space-between;
>span {
width : 53px;
line-height: 35px;
font-size : 13px;
text-align : center;
}
.bp3-input {
width : 50px;
height : 27px;
font-size : 12px;
margin-top: 2px;
}
.bp3-slider {
min-width : 10px;
width : 140px;
height : 27px;
margin : 10px 15px 0 15px;
.bp3-slider-axis {
display: none;
}
.bp3-slider-handle {
transform : scale(80%);
border-radius: 50px;
}
.bp3-slider-label {
display: none;
}
}
.bp3-button-group {
display: none;
}
}
}
.stone{
margin-top: 10px;
.paramsSize{
margin-top: -10px;
}
}
.bayWindow{
.bayWindowParam{
display : flex;
justify-content: space-around;
}
}
.bp3-control.bp3-checkbox{
width: fit-content;
}
}
.bp3-dialog-footer{
display: unset;
}
}
#WindowTempInfo{
height : 95px;
padding : 5px;
display : flex;
border-radius: 3px;
.windowImg{
width : 80px;
height : 80px;
text-align: center;
.bp3-icon.bp3-icon-add-to-artifact{
margin: 3px 0 0 10px
}
.changeLogo{
position: absolute;
margin : 64px 0 0 -15px;
color : #a1a1a1;
}
}
.windowParamInfo{
margin-left: 20px;
display : grid;
}
}

@ -501,3 +501,23 @@ export interface IAutoDimBrsOption extends IBaseOption
noShowAppointSizes: string;
useParseGroups: string;
}
export interface WindowPanelConfigOption
{
Length: number; //窗宽
Height: number; //窗高
Thick: number; //窗厚
WindowOffGround: number; //离地
IsBayWindow: boolean; //窗户外飘
BayLeftIsWall?: boolean;//飘窗左侧是墙
BayRightIsWall?: boolean;//飘窗右侧是墙
BayDist?: number;//外飘距离
BayLeftDist?: number;//左外飘距离
BayMiddleDist?: number;//中外飘距离
BayRightDist?: number;//右外飘距离
HasWindowStone: boolean; //是否有窗台石
StoneThick?: number; //窗台石厚度
StoneBulge?: number; //窗台石凸出
StoneLeftRightBulge?: number; //窗台石左右凸出
}

@ -146,11 +146,16 @@ export interface IDrawerDoorTempInfo
diy_logo?: string;
}
/**选择的模板信息,temp-抽屉或门板,handletemp-拉手模板,其他是铰链模板 */
export interface IWindowTempInfo
{
logo?: string;
}
/**选择的模板信息,temp-抽屉或门板,handletemp-拉手模板,windowTemp-窗户模板,其他是铰链模板 */
export interface ISelectTempInfo
{
temp: IDrawerDoorTempInfo;
handleTemp: IDrawerDoorTempInfo;
handleTemp?: IDrawerDoorTempInfo;
hingeTemp?: IDrawerDoorTempInfo;
[key: string]: IDrawerDoorTempInfo;
}

Loading…
Cancel
Save