mirror of https://gitee.com/cf-fz/WebCAD.git
!2303 功能:吊顶,线条支持拾取天花板和地板
parent
4ca28cee2b
commit
f2435f2d0e
@ -1,25 +1,18 @@
|
||||
import { CADFiler } from "../../DatabaseServices/CADFiler";
|
||||
import { Region } from "../../DatabaseServices/Entity/Region";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { Entity } from "../../DatabaseServices/Entity/Entity";
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { BoolOpeartionType } from "../../GraphicsSystem/BoolOperateUtils";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { HotCMD } from "../../Hot/HotCommand";
|
||||
import { TestDraw } from "../test/TestUtil";
|
||||
|
||||
@HotCMD
|
||||
export class Test implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let d = { "file": [2, "Region", 10, 2, 110, 0, 1, 7, 71, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 863.9997678387444, -200, 0, 1], 0, 0, 1, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 863.9997678387444, -200, 0, 1], 0, 0, 1, 1, 1, 1, 1, "Polyline", 10, 2, 0, 0, 0, 1, 71, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 863.9997678387444, -200, 0, 1], 0, 0, 1, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 863.9997678387444, -200, 0, 1], 0, 0, 1, 2, 4, [100, 0], 0, [400, 0], 0, [400, 864], 0, [100, 864], 0, true, 0, "Region", 10, 2, 111, 0, 1, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 1, 1, 1, 1, "Polyline", 10, 2, 0, 0, 0, 2, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -614.9118387909318, -117.20906801007538, 0, 1], 0, 0, 1, 2, 4, [0, 0], 0, [1728.0001196034718, 0], 0, [1728.0001196034718, 9.5], 0, [0, 9.5], 0, true, 0], "basePt": { "x": -0.00023216125555336475, "y": -100, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] };
|
||||
let f = new CADFiler(d.file);
|
||||
let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Entity] } });
|
||||
if (enRes.Status !== PromptStatus.OK) return;
|
||||
let pl = enRes.Entity as Entity;
|
||||
console.log(pl);
|
||||
|
||||
f.Read();
|
||||
let el1 = f.ReadObject() as Region;
|
||||
let el2 = f.ReadObject() as Region;
|
||||
|
||||
TestDraw(el1.Clone());
|
||||
TestDraw(el2.Clone());
|
||||
|
||||
el1.BooleanOper(el2, BoolOpeartionType.Intersection);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,541 @@
|
||||
import { BufferAttribute, BufferGeometry, Float32BufferAttribute, InstancedInterleavedBuffer, InterleavedBufferAttribute, Intersection, LineSegments, Material, Mesh, Object3D, ShapeBufferGeometry, Vector3 } from "three";
|
||||
import { Line2 } from "three/examples/jsm/lines/Line2";
|
||||
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
|
||||
import { ColorMaterial } from "../../../../Common/ColorPalette";
|
||||
import { DisposeThreeObj, Object3DRemoveAll } from "../../../../Common/Dispose";
|
||||
import { BufferGeometryUtils } from "../../../../Geometry/BufferGeometryUtils";
|
||||
import { ContourTreeNode } from "../../../../Geometry/ExtrudeMeshGeomBuilder/ExtrudeEdgeGeometry2";
|
||||
import { AsVector3, equaln } from "../../../../Geometry/GeUtils";
|
||||
import { SweepGeometry } from "../../../../Geometry/SweepGeometry";
|
||||
import { RenderType } from "../../../../GraphicsSystem/RenderType";
|
||||
import { AutoRecord } from "../../../AutoRecord";
|
||||
import { Factory } from "../../../CADFactory";
|
||||
import { CADFiler } from "../../../CADFiler";
|
||||
import { Contour } from "../../../Contour";
|
||||
import { Curve } from "../../../Entity/Curve";
|
||||
import { Entity } from "../../../Entity/Entity";
|
||||
import { Polyline } from "../../../Entity/Polyline";
|
||||
import { ObjectId } from "../../../ObjectId";
|
||||
import { PhysicalMaterialRecord } from "../../../PhysicalMaterialRecord";
|
||||
import { Shape } from "../../../Shape";
|
||||
import { TemplateRecord } from "../../../Template/TemplateRecord";
|
||||
import { RoomFlatBase } from "../Flat/RoomFlatBase";
|
||||
|
||||
export enum BulkheadCeiling_ContourType
|
||||
{
|
||||
Hole = 0,
|
||||
Land = 1,
|
||||
Sweep = 2,//放样线条(不影响岛的建模)
|
||||
}
|
||||
|
||||
export interface BulkheadCeiling_ContourData
|
||||
{
|
||||
ContourType: BulkheadCeiling_ContourType;//洞 还是岛
|
||||
Path: Curve;//轮廓(可能闭合 可能是一条直线)
|
||||
SweepShapeTempalteId: ObjectId<TemplateRecord>;//放样形状的模块id
|
||||
Materials: ObjectId<PhysicalMaterialRecord>[];
|
||||
Contour: Polyline; //截面轮廓
|
||||
ContourId: number; //截面轮廓ID
|
||||
ShapeMaterialSlotData: number[];
|
||||
OverWriteMaterial?: Map<number, ObjectId<PhysicalMaterialRecord>>;//替代材质
|
||||
}
|
||||
|
||||
/**
|
||||
* 吊顶(灯带)
|
||||
*/
|
||||
@Factory
|
||||
export class BulkheadCeiling extends Entity
|
||||
{
|
||||
constructor() { super(); }
|
||||
private _ContourData: BulkheadCeiling_ContourData[] = [];
|
||||
private _GemoIdMap = new Map<number, number>();
|
||||
|
||||
get ContourData(): BulkheadCeiling_ContourData[]
|
||||
{
|
||||
return this._ContourData;
|
||||
}
|
||||
set ContourData(value: BulkheadCeiling_ContourData[])
|
||||
{
|
||||
this.WriteAllObjectRecord();
|
||||
this._ContourData = value;
|
||||
this.Update();
|
||||
}
|
||||
|
||||
private _Height = 300;//吊顶高度
|
||||
|
||||
get Height()
|
||||
{
|
||||
return this._Height;
|
||||
}
|
||||
set Height(value: number)
|
||||
{
|
||||
this.WriteAllObjectRecord();
|
||||
if (!equaln(value, this._Height))
|
||||
{
|
||||
this._Height = value;
|
||||
this.Update();
|
||||
}
|
||||
}
|
||||
|
||||
@AutoRecord RelativeRoomFlatTop: ObjectId<RoomFlatBase>;
|
||||
|
||||
private _EdgeGeometrys: BufferGeometry[];
|
||||
get EdgeGeometrys(): BufferGeometry[]
|
||||
{
|
||||
if (!this._EdgeGeometrys)
|
||||
this.MeshGeometry;
|
||||
|
||||
return this._EdgeGeometrys;
|
||||
}
|
||||
|
||||
|
||||
private _LineGeometry: LineGeometry[] = [];
|
||||
get LineGeometry()
|
||||
{
|
||||
if (this._LineGeometry.length !== 0)
|
||||
return this._LineGeometry;
|
||||
|
||||
this.MeshGeometry;
|
||||
return this._LineGeometry;
|
||||
}
|
||||
|
||||
private _FaceGeometry: BufferGeometry; //底面
|
||||
get FaceGeometry()
|
||||
{
|
||||
if (this._FaceGeometry)
|
||||
return this._FaceGeometry;
|
||||
|
||||
this.MeshGeometry;
|
||||
return this._FaceGeometry;
|
||||
}
|
||||
|
||||
private _MeshGeometry: SweepGeometry[] = [];
|
||||
get MeshGeometry()
|
||||
{
|
||||
if (this._MeshGeometry.length !== 0) return this._MeshGeometry;
|
||||
|
||||
//绘制底面start
|
||||
|
||||
//#region //分析包含关系
|
||||
let contours: ContourTreeNode[] = [];
|
||||
let contour_data_Map = new Map<ContourTreeNode, BulkheadCeiling_ContourData>();
|
||||
for (let con_data of this._ContourData)
|
||||
{
|
||||
if (!con_data.Path?.IsClose || con_data.ContourType === BulkheadCeiling_ContourType.Sweep) continue;
|
||||
let contour = Contour.CreateContour(con_data.Path as Polyline);
|
||||
if (!contour) continue;
|
||||
|
||||
let contourNode = new ContourTreeNode(contour);
|
||||
contours.push(contourNode);
|
||||
contour_data_Map.set(contourNode, con_data);
|
||||
}
|
||||
ContourTreeNode.ParseContourTree(contours);
|
||||
//#endregion
|
||||
|
||||
let faceGeoms: BufferGeometry[] = [];
|
||||
this._EdgeGeometrys = [];
|
||||
this._GemoIdMap.clear();
|
||||
|
||||
for (let contourNode of contours)
|
||||
{
|
||||
let con_data = contour_data_Map.get(contourNode);
|
||||
|
||||
if (con_data.ContourType === BulkheadCeiling_ContourType.Land)//Land 岛
|
||||
{
|
||||
//#region 绘制平面
|
||||
if (contourNode.parent && contour_data_Map.get(contourNode.parent).ContourType === BulkheadCeiling_ContourType.Land)//上级也是岛 不需要在绘制平面了
|
||||
continue;
|
||||
|
||||
let holes: Contour[] = [];
|
||||
for (let chiNode of contourNode.children)
|
||||
{
|
||||
let chi_con_data = contour_data_Map.get(chiNode);
|
||||
if (chi_con_data.ContourType === BulkheadCeiling_ContourType.Hole)
|
||||
holes.push(chiNode.contour.Clone());
|
||||
}
|
||||
|
||||
let shape = new Shape(contourNode.contour, holes);
|
||||
let geom = new ShapeBufferGeometry(shape.Shape, 30);
|
||||
|
||||
geom.applyMatrix4(shape.Outline.Curve.OCSNoClone);
|
||||
|
||||
{
|
||||
const indices = Array.from(geom.getIndex().array);
|
||||
|
||||
// 翻转面片索引的顺序
|
||||
const flippedIndices = [];
|
||||
for (let i = 0; i < indices.length; i += 3)
|
||||
flippedIndices.push(indices[i], indices[i + 2], indices[i + 1]);
|
||||
|
||||
// 创建新的面片索引属性
|
||||
const newIndices = new BufferAttribute(new Uint16Array(flippedIndices), 1);
|
||||
|
||||
// 更新面片索引属性
|
||||
geom.setIndex(newIndices);
|
||||
}
|
||||
|
||||
faceGeoms.push(geom);
|
||||
//#endregion
|
||||
}
|
||||
}
|
||||
//绘制底面end
|
||||
|
||||
//Sweep
|
||||
let i = 0;
|
||||
for (; i < this._ContourData.length; i++)
|
||||
{
|
||||
let contour = this._ContourData[i].Contour;
|
||||
|
||||
if (contour)
|
||||
{
|
||||
let path = this._ContourData[i].Path;
|
||||
if (this._ContourData[i].ContourType === BulkheadCeiling_ContourType.Hole)
|
||||
path = path.Clone().Reverse();
|
||||
|
||||
let sweepGeo = new SweepGeometry(contour, path, this._ContourData[i].ShapeMaterialSlotData);
|
||||
|
||||
this._GemoIdMap.set(sweepGeo.id, i);
|
||||
|
||||
this._MeshGeometry.push(sweepGeo);
|
||||
|
||||
//line geo
|
||||
this.GetLineGeometry(sweepGeo.edgePts);
|
||||
//edge geo
|
||||
let edgeGeom = new BufferGeometry().setAttribute('position', new Float32BufferAttribute(sweepGeo.edgePts, 3));
|
||||
this._EdgeGeometrys.push(edgeGeom);
|
||||
|
||||
sweepGeo.edgePts = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this._FaceGeometry = BufferGeometryUtils.MergeBufferGeometries(faceGeoms);
|
||||
this._GemoIdMap.set(this._FaceGeometry.id, i);
|
||||
|
||||
return this._MeshGeometry;
|
||||
}
|
||||
|
||||
GetLineGeometry(pts: number[])
|
||||
{
|
||||
let lineGeo = new LineGeometry();
|
||||
let lineSegments = new Float32Array(pts);
|
||||
var instanceBuffer = new InstancedInterleavedBuffer(lineSegments, 6, 1);
|
||||
lineGeo.setAttribute('instanceStart', new InterleavedBufferAttribute(instanceBuffer, 3, 0));
|
||||
lineGeo.setAttribute('instanceEnd', new InterleavedBufferAttribute(instanceBuffer, 3, 3));
|
||||
this._LineGeometry.push(lineGeo);
|
||||
}
|
||||
|
||||
InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
|
||||
{
|
||||
let obj = new Object3D();
|
||||
this.UpdateDrawObject(renderType, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载:更新绘制的实体
|
||||
* @param {RenderType} renderType
|
||||
* @param {Object3D} obj
|
||||
*/
|
||||
UpdateDrawObject(renderType: RenderType, obj: Object3D)
|
||||
{
|
||||
DisposeThreeObj(obj);
|
||||
Object3DRemoveAll(obj);
|
||||
|
||||
if (renderType === RenderType.Wireframe || renderType === RenderType.Jig)
|
||||
{
|
||||
for (let edgeGeo of this.EdgeGeometrys)
|
||||
obj.add(new LineSegments(edgeGeo, ColorMaterial.GetLineMaterial(this.ColorIndex)));
|
||||
}
|
||||
else if (renderType === RenderType.Conceptual)
|
||||
{
|
||||
let material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
|
||||
|
||||
obj.add(new Mesh(this.FaceGeometry, material));
|
||||
|
||||
for (let meshGeo of this.MeshGeometry)
|
||||
{
|
||||
obj.add(new Mesh(meshGeo, material));
|
||||
}
|
||||
|
||||
for (let edgeGeo of this.EdgeGeometrys)
|
||||
obj.add(new LineSegments(edgeGeo, ColorMaterial.GetLineMaterial(this.ColorIndex)));
|
||||
}
|
||||
else if (renderType === RenderType.Physical)
|
||||
{
|
||||
obj.add(new Mesh(this.FaceGeometry, (this.Material?.Object as PhysicalMaterialRecord)?.Material ?? this.MeshMaterial));
|
||||
|
||||
for (let meshGeo of this.MeshGeometry)
|
||||
obj.add(new Mesh(meshGeo, this.GetMaterials(this._GemoIdMap.get(meshGeo.id))));
|
||||
}
|
||||
// else if (renderType === RenderType.Physical2)
|
||||
// {
|
||||
// obj.add(new Mesh(this.FaceGeometry, (this.Material?.Object as PhysicalMaterialRecord)?.Material ?? this.MeshMaterial));
|
||||
|
||||
// for (let meshGeo of this.MeshGeometry)
|
||||
// obj.add(new Mesh(meshGeo, this.GetMaterials(this._GemoIdMap.get(meshGeo.id))));
|
||||
|
||||
// for (let edgeGeo of this.EdgeGeometrys)
|
||||
// obj.add(new LineSegments(edgeGeo, ColorMaterial.GetPhysical2EdgeMaterial()));
|
||||
// }
|
||||
else if (renderType === RenderType.Print)
|
||||
{
|
||||
for (let lineGeo of this.LineGeometry)
|
||||
obj.add(new Line2(lineGeo, ColorMaterial.PrintLineWhiterMatrial));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
SetMaterial(mtl: ObjectId<PhysicalMaterialRecord>, intersection: Intersection)
|
||||
{
|
||||
let id = intersection.object["geometry"]?.id;
|
||||
if (id)
|
||||
{
|
||||
this.WriteAllObjectRecord();
|
||||
let contourIndex = this._GemoIdMap.get(id);
|
||||
if (contourIndex === undefined)
|
||||
this.Material = mtl;
|
||||
else
|
||||
{
|
||||
//因为这个索引是底部面的索引
|
||||
if (contourIndex === this._ContourData.length)
|
||||
{
|
||||
this.Material = mtl;
|
||||
}
|
||||
else
|
||||
{
|
||||
let contourData = this._ContourData[contourIndex];
|
||||
if (!contourData.OverWriteMaterial)
|
||||
contourData.OverWriteMaterial = new Map;
|
||||
|
||||
contourData.OverWriteMaterial.set(intersection.face.materialIndex, mtl);
|
||||
}
|
||||
}
|
||||
this.Update();
|
||||
}
|
||||
}
|
||||
|
||||
//获取Sweep实体的材质列表
|
||||
GetMaterials(index: number): Material[]
|
||||
{
|
||||
let contourData = this._ContourData[index];
|
||||
return contourData.Materials.map((mtl, index) =>
|
||||
{
|
||||
return contourData.OverWriteMaterial?.get(index)?.Object?.Material ?? mtl?.Object?.Material ?? this.MeshMaterial as Material;
|
||||
});
|
||||
}
|
||||
|
||||
UpdateDrawObjectMaterial(renderType: RenderType, obj: Object3D, material?: Material)
|
||||
{
|
||||
if (renderType === RenderType.Physical)
|
||||
obj.traverse(o =>
|
||||
{
|
||||
if (o instanceof Mesh)
|
||||
{
|
||||
let index = this._GemoIdMap.get(o.geometry.id);
|
||||
if (index !== undefined)
|
||||
{
|
||||
if (Array.isArray(o.material))
|
||||
{
|
||||
let materials = this.GetMaterials(index);
|
||||
o.material = materials;
|
||||
}
|
||||
}
|
||||
else
|
||||
o.material = this.MeshMaterial;
|
||||
}
|
||||
});
|
||||
else if (renderType === RenderType.Conceptual)
|
||||
{
|
||||
let material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
|
||||
let face = obj.children[0] as Mesh;//
|
||||
face.material = material;
|
||||
for (let i = 1; i < obj.children.length; i++)
|
||||
{
|
||||
let chiObj = obj.children[i];
|
||||
if (chiObj instanceof Mesh)
|
||||
chiObj.material = material;
|
||||
else if (chiObj instanceof LineSegments)
|
||||
chiObj.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
|
||||
}
|
||||
}
|
||||
else if (renderType === RenderType.Wireframe)
|
||||
{
|
||||
for (let lineSeg of obj.children as LineSegments[])
|
||||
lineSeg.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
override UpdateDrawGeometry()
|
||||
{
|
||||
for (let gemo of this._MeshGeometry)
|
||||
gemo.dispose();
|
||||
this._MeshGeometry = [];
|
||||
|
||||
for (let gemo of this._LineGeometry)
|
||||
gemo.dispose();
|
||||
this._LineGeometry = [];
|
||||
|
||||
if (this._FaceGeometry)
|
||||
this._FaceGeometry.dispose();
|
||||
this._FaceGeometry = undefined;
|
||||
}
|
||||
|
||||
GetGripPoints(): Array<Vector3>
|
||||
{
|
||||
let pts = [];
|
||||
for (let data of this._ContourData)
|
||||
pts.push(...data.Path.Clone().ApplyMatrix(this.OCSNoClone).GetGripPoints());
|
||||
return pts;
|
||||
}
|
||||
|
||||
GetStretchPoints(): Vector3[]
|
||||
{
|
||||
let pts: Vector3[] = [];
|
||||
let lineData = (this.ContourData[0].Path as Polyline).LineData;
|
||||
for (let data of lineData)
|
||||
{
|
||||
let p = AsVector3(data.pt).applyMatrix4(this.ContourData[0].Path.OCS).applyMatrix4(this.OCSNoClone);
|
||||
pts.push(p);
|
||||
}
|
||||
return pts;
|
||||
}
|
||||
|
||||
MoveStretchPoints(indexList: Array<number>, vec: Vector3)
|
||||
{
|
||||
this.WriteAllObjectRecord();
|
||||
let path = this.ContourData[0].Path;
|
||||
path.ApplyMatrix(this.OCS);
|
||||
path.MoveStretchPoints(indexList, vec);
|
||||
path.ApplyMatrix(this.OCSInv);
|
||||
this.Update();
|
||||
}
|
||||
|
||||
MoveGripPoints(indexList: number[], moveVec: Vector3)
|
||||
{
|
||||
this.WriteAllObjectRecord();
|
||||
|
||||
for (let i = 0; i < this._ContourData.length; i++)
|
||||
{
|
||||
let path = this._ContourData[i].Path.Clone();
|
||||
let newIndexlist = [];
|
||||
let dataIndexList = [];
|
||||
let ptLength = path.GetGripPoints().length;
|
||||
for (let index of indexList)
|
||||
{
|
||||
if (ptLength < (index + 1))
|
||||
newIndexlist.push(index - ptLength);
|
||||
else
|
||||
dataIndexList.push(index);
|
||||
}
|
||||
if (dataIndexList.length !== 0)
|
||||
{
|
||||
path.ApplyMatrix(this.OCS);
|
||||
path.MoveGripPoints(dataIndexList, moveVec);
|
||||
path.ApplyMatrix(this.OCSInv);
|
||||
this.ContourData[i].Path = path;
|
||||
}
|
||||
|
||||
indexList = newIndexlist;
|
||||
}
|
||||
this.Update();
|
||||
}
|
||||
|
||||
//#region -------------------------File-------------------------
|
||||
//对象从文件中读取数据,初始化自身
|
||||
protected override _ReadFile(file: CADFiler)
|
||||
{
|
||||
let ver = file.Read();
|
||||
super._ReadFile(file);
|
||||
|
||||
this.ContourData = [];
|
||||
let contourDataCount = file.Read();
|
||||
for (let i = 0; i < contourDataCount; i++)
|
||||
{
|
||||
let data: BulkheadCeiling_ContourData = {
|
||||
ContourType: null,
|
||||
Path: null,
|
||||
SweepShapeTempalteId: null,
|
||||
Materials: [],
|
||||
Contour: null,
|
||||
ContourId: null,
|
||||
ShapeMaterialSlotData: [],
|
||||
OverWriteMaterial: null,
|
||||
};
|
||||
|
||||
data.ContourType = file.Read();
|
||||
data.Contour = file.ReadObject();
|
||||
data.ContourId = file.Read();
|
||||
data.Path = file.ReadObject();
|
||||
data.SweepShapeTempalteId = file.ReadObjectId() as ObjectId<TemplateRecord>;
|
||||
|
||||
//覆盖材质
|
||||
let overwriteMtlSize = file.Read() as number;
|
||||
if (overwriteMtlSize) data.OverWriteMaterial = new Map;
|
||||
else data.OverWriteMaterial = undefined;
|
||||
for (let i = 0; i < overwriteMtlSize; i++)
|
||||
{
|
||||
let index = file.Read();
|
||||
let mtlId = file.ReadObjectId() as ObjectId<PhysicalMaterialRecord>;
|
||||
data.OverWriteMaterial.set(index, mtlId);
|
||||
}
|
||||
|
||||
//原始材质
|
||||
let mtlCount = file.Read();
|
||||
for (let i = 0; i < mtlCount; i++)
|
||||
data.Materials.push(file.ReadObjectId() as ObjectId<PhysicalMaterialRecord>);
|
||||
|
||||
//材质槽
|
||||
let materialCount = file.Read();
|
||||
data.ShapeMaterialSlotData = file.ReadArray(materialCount);
|
||||
|
||||
this.ContourData.push(data);
|
||||
}
|
||||
|
||||
this.RelativeRoomFlatTop = file.ReadObjectId() as ObjectId<RoomFlatBase>;
|
||||
}
|
||||
|
||||
|
||||
//对象将自身数据写入到文件.
|
||||
override WriteFile(file: CADFiler)
|
||||
{
|
||||
file.Write(1);
|
||||
super.WriteFile(file);
|
||||
|
||||
file.Write(this.ContourData.length);
|
||||
|
||||
for (let data of this.ContourData)
|
||||
{
|
||||
file.Write(data.ContourType);
|
||||
file.WriteObject(data.Contour);
|
||||
file.Write(data.ContourId);
|
||||
file.WriteObject(data.Path);
|
||||
file.WriteObjectId(data.SweepShapeTempalteId);
|
||||
|
||||
//覆盖材质
|
||||
if (data.OverWriteMaterial)
|
||||
{
|
||||
file.Write(data.OverWriteMaterial.size);
|
||||
for (let [index, mtlId] of data.OverWriteMaterial)
|
||||
{
|
||||
file.Write(index);
|
||||
file.WriteObjectId(mtlId);
|
||||
}
|
||||
}
|
||||
else
|
||||
file.Write(0);
|
||||
|
||||
//原始材质
|
||||
file.Write(data.Materials.length);
|
||||
for (let material of data.Materials)
|
||||
file.WriteObjectId(material);
|
||||
|
||||
//材质槽
|
||||
file.Write(data.ShapeMaterialSlotData.length);
|
||||
for (let matData of data.ShapeMaterialSlotData)
|
||||
file.Write(matData);
|
||||
}
|
||||
|
||||
file.WriteObjectId(this.RelativeRoomFlatTop);
|
||||
}
|
||||
//#endregion
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
import { CADFiler } from "../../../CADFiler";
|
||||
import { ISerialize } from "../../../ISerialize";
|
||||
|
||||
/**
|
||||
* 吊顶轮廓拓展数据(材质槽信息) (保存到服务端)
|
||||
*/
|
||||
export class BulkheadCeilingShapeTemplateExtendData implements ISerialize
|
||||
{
|
||||
//颜色与材质信息映射(为了这个模块能正常流通,这个模块还是成为内嵌模块吧)
|
||||
Color_MaterialId: Map<number, number> = new Map();
|
||||
|
||||
constructor() { }
|
||||
|
||||
ReadFile(file: CADFiler): void
|
||||
{
|
||||
let ver = file.Read();
|
||||
let size = file.Read();
|
||||
this.Color_MaterialId.clear();
|
||||
for (let i = 0; i < size; i++)
|
||||
{
|
||||
let color = file.Read();
|
||||
let templateId = file.Read();
|
||||
this.Color_MaterialId.set(color, templateId);
|
||||
}
|
||||
}
|
||||
|
||||
WriteFile(file: CADFiler): void
|
||||
{
|
||||
file.Write(1);
|
||||
file.Write(this.Color_MaterialId.size);
|
||||
for (let [color, templateId] of this.Color_MaterialId)
|
||||
{
|
||||
file.Write(color);
|
||||
file.Write(templateId);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
#BulkheadCeilingConfig {
|
||||
.bp3-dialog-body {
|
||||
width : 430px;
|
||||
min-height : 495px;
|
||||
padding : 10px;
|
||||
overflow : auto;
|
||||
max-height : 600px;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
margin : 0;
|
||||
|
||||
.firstLi {
|
||||
height: 25px;
|
||||
|
||||
:first-child {
|
||||
border-radius: 5px 0px 0px 0px;
|
||||
}
|
||||
|
||||
:last-child {
|
||||
border-radius: 0px 5px 0px 0px;
|
||||
}
|
||||
|
||||
.bp3-label {
|
||||
line-height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
height : 30px;
|
||||
display : flex;
|
||||
font-size : 13px;
|
||||
text-align: center;
|
||||
|
||||
.bp3-label {
|
||||
margin : 0;
|
||||
line-height : 2.2rem;
|
||||
border-right: 1.5px solid #AAAAAA;
|
||||
border-top : 1.5px solid #AAAAAA;
|
||||
border-left : 1.5px solid #AAAAAA;
|
||||
|
||||
&>div {
|
||||
margin: 1px;
|
||||
height: -webkit-fill-available;
|
||||
}
|
||||
}
|
||||
|
||||
&>:first-child {
|
||||
width : 50px;
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
&>:nth-child(2) {
|
||||
width : 70px;
|
||||
border-right: 0px
|
||||
}
|
||||
|
||||
&>:last-child {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bp3-html-select {
|
||||
margin: 1px;
|
||||
|
||||
select {
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.bp3-icon-caret-down {
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&>:last-child {
|
||||
&>:first-child {
|
||||
border-radius: 0px 0px 0px 5px;
|
||||
}
|
||||
|
||||
&>:last-child {
|
||||
border-radius: 0px 0px 5px 0px;
|
||||
}
|
||||
|
||||
.bp3-label {
|
||||
border-bottom: 1.5px solid #AAAAAA;
|
||||
}
|
||||
}
|
||||
|
||||
.material_detail {
|
||||
display : flex;
|
||||
white-space : nowrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.detail_name{
|
||||
width : 70%;
|
||||
display: flex;
|
||||
|
||||
.materialName{
|
||||
width : 110px;
|
||||
overflow : hidden;
|
||||
text-align : left;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.detail_type{
|
||||
width : 100px;
|
||||
display: flex;
|
||||
|
||||
.materialType{
|
||||
width : 65px;
|
||||
overflow : hidden;
|
||||
text-align : left;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contour_detail {
|
||||
position: relative;
|
||||
display : flex;
|
||||
|
||||
.detail_logo {
|
||||
height: 100%;
|
||||
width : 38%;
|
||||
|
||||
display : flex;
|
||||
align-items : center;
|
||||
justify-content: space-evenly;
|
||||
svg {
|
||||
margin : -19px;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.detail_name {
|
||||
width : 62%;
|
||||
display : flex;
|
||||
align-items:center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.itemContour {
|
||||
display : flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&>div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bp3-button {
|
||||
width : 50px;
|
||||
padding : 0px;
|
||||
margin : 1px 2px;
|
||||
font-size : 12px;
|
||||
min-height: unset;
|
||||
|
||||
.bp3-button-text{
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contourLi {
|
||||
height: 65px;
|
||||
|
||||
:nth-child(1) {
|
||||
display : flex;
|
||||
align-items : center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.backgroudColor {
|
||||
height: 28px;
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
.bp3-html-select {
|
||||
.bp3-icon-caret-down {
|
||||
top: 23px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail_name {
|
||||
span{
|
||||
width: 65px;
|
||||
}
|
||||
}
|
||||
|
||||
.materialName{
|
||||
width : 110px;
|
||||
overflow : hidden;
|
||||
text-align : left;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bp3-dialog-footer {
|
||||
.bp3-dialog-footer-actions {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.bp3-button {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.headCeilingContourManage{
|
||||
.bp3-dialog-body{
|
||||
width: 1000px;
|
||||
height: 700px;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
import { ContextMenu, Intent, Menu, MenuItem } from '@blueprintjs/core';
|
||||
import { IObservableValue } from 'mobx';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { ToplineUrls } from '../../../Common/HostUrl';
|
||||
import { PostJson, RequestStatus } from '../../../Common/Request';
|
||||
import { inflateBase64 } from '../../../Common/inflate';
|
||||
import { CADFiler } from '../../../DatabaseServices/CADFiler';
|
||||
import { Database } from '../../../DatabaseServices/Database';
|
||||
import { Arc } from '../../../DatabaseServices/Entity/Arc';
|
||||
import { Line } from '../../../DatabaseServices/Entity/Line';
|
||||
import { Polyline } from '../../../DatabaseServices/Entity/Polyline';
|
||||
import { DataList } from '../Common/Datalist';
|
||||
import { IDirectoryProps } from '../SourceManage/CommonPanel';
|
||||
|
||||
export interface HeadCeilingListProps
|
||||
{
|
||||
deleteFun?: (topline?: { topline_id; }) => void;
|
||||
dataList?: any[];
|
||||
select?: (e: React.FormEvent<HTMLInputElement>, data: any) => void;
|
||||
// draw: (id: string) => void;
|
||||
getData?: () => void;
|
||||
selectIds?: Set<string>;
|
||||
showInfos?: boolean;
|
||||
isRename: IObservableValue<boolean>;
|
||||
editorCeilingContour?: (curves: (Polyline | Line | Arc)[], name?: string, currentDir?: IDirectoryProps, database?: Database) => void;
|
||||
currentHeadCeilingInfo: { id: string, name: string; };
|
||||
}
|
||||
|
||||
@observer
|
||||
export class HeadCeilingContourList extends React.Component<HeadCeilingListProps, { isContextMenuOpen: boolean; }> {
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
isContextMenuOpen: false
|
||||
};
|
||||
}
|
||||
_HandleMounseDown = (e: React.MouseEvent<HTMLElement>, tpline: any) =>
|
||||
{
|
||||
this.props.currentHeadCeilingInfo.id = tpline.topline_id;
|
||||
this.props.currentHeadCeilingInfo.name = tpline.name;
|
||||
};
|
||||
|
||||
_HandleEditor = async () =>
|
||||
{
|
||||
let data = await PostJson(ToplineUrls.detail, { topline_id: this.props.currentHeadCeilingInfo.id });
|
||||
|
||||
if (data.err_code === RequestStatus.Ok)
|
||||
{
|
||||
let json = inflateBase64(data.toplines.file);
|
||||
let f = new CADFiler(JSON.parse(json));
|
||||
let saveDb = new Database(false, false, true);
|
||||
saveDb.FileRead(f);
|
||||
let curves = saveDb.ModelSpace.Entitys as (Polyline | Line | Arc)[];
|
||||
this.props.editorCeilingContour(curves, null, null, saveDb);
|
||||
}
|
||||
};
|
||||
|
||||
//展示右键菜单
|
||||
_ShowContextMenu = (e: React.MouseEvent<HTMLElement>, tpline) =>
|
||||
{
|
||||
if (!tpline) return;
|
||||
ContextMenu.show(
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon="folder-new"
|
||||
text="重命名"
|
||||
onClick={() => this.props.isRename.set(true)}
|
||||
/>
|
||||
<MenuItem
|
||||
icon="folder-new"
|
||||
text="编辑"
|
||||
onClick={this._HandleEditor}
|
||||
/>
|
||||
<MenuItem
|
||||
icon="trash"
|
||||
text="删除"
|
||||
intent={Intent.DANGER}
|
||||
onClick={() => { this.props.deleteFun(); }}
|
||||
/>
|
||||
</Menu>,
|
||||
{ left: e.clientX, top: e.clientY },
|
||||
() => this.setState({ isContextMenuOpen: false }),
|
||||
);
|
||||
this.setState({ isContextMenuOpen: true });
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
public render()
|
||||
{
|
||||
return (
|
||||
<DataList
|
||||
dataList={this.props.dataList}
|
||||
idKey={"topline_id"}
|
||||
select={this.props.select}
|
||||
showContextMenu={this._ShowContextMenu}
|
||||
showInfos={this.props.showInfos}
|
||||
selectData={this.props.selectIds}
|
||||
handleMounseDown={this._HandleMounseDown}
|
||||
isSvg
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,483 @@
|
||||
import { Button, Classes, Intent, MenuItem } from '@blueprintjs/core';
|
||||
import { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { Matrix4, Vector3 } from 'three';
|
||||
import { ViewChange } from '../../../Add-on/ViewChange';
|
||||
import { app } from '../../../ApplicationServices/Application';
|
||||
import { MaterialUrls, ToplineUrls } from '../../../Common/HostUrl';
|
||||
import { DirectoryId, PostJson, RequestStatus } from '../../../Common/Request';
|
||||
import { deflate, getPolylineSVG } from '../../../Common/SerializeMaterial';
|
||||
import { DuplicateRecordCloning } from '../../../Common/Status';
|
||||
import { GetEntity } from '../../../Common/Utils';
|
||||
import { CADFiler } from '../../../DatabaseServices/CADFiler';
|
||||
import { Contour } from '../../../DatabaseServices/Contour';
|
||||
import { Database } from '../../../DatabaseServices/Database';
|
||||
import { Arc } from '../../../DatabaseServices/Entity/Arc';
|
||||
import { Line } from '../../../DatabaseServices/Entity/Line';
|
||||
import { Polyline } from '../../../DatabaseServices/Entity/Polyline';
|
||||
import { ObjectId } from '../../../DatabaseServices/ObjectId';
|
||||
import { BulkheadCeilingShapeTemplateExtendData } from '../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeilingShapeExtendData';
|
||||
import { TemplateRecord } from '../../../DatabaseServices/Template/TemplateRecord';
|
||||
import { WblockCloneFiler } from '../../../DatabaseServices/WblockCloneFiler';
|
||||
import { CommandWrap } from '../../../Editor/CommandMachine';
|
||||
import { CommandState } from '../../../Editor/CommandState';
|
||||
import { PromptStatus } from '../../../Editor/PromptResult';
|
||||
import { TempEditor } from '../../../Editor/TempEditor';
|
||||
import { ZAxisN } from '../../../Geometry/GeUtils';
|
||||
import { HeadCeilingProfileMaterialStore, NONE_MATERIAL_ID } from '../../Store/HeadCeilingStore/HeadCeilingMaterialStore';
|
||||
import { BoardModalType } from '../Board/BoardModalType';
|
||||
import { DialogUserConfig } from '../Board/UserConfigComponent';
|
||||
import { ModalContainer, ModalHeader } from '../Modal/ModalContainer';
|
||||
import { ModalPosition } from '../Modal/ModalInterface';
|
||||
import { CommonPanel, IDirectoryProps } from '../SourceManage/CommonPanel';
|
||||
import { HandleDirComponent } from '../SourceManage/HandleDirComponent';
|
||||
import { AppToaster } from '../Toaster';
|
||||
import './HeadCeiling.less';
|
||||
import { HeadCeilingContourList } from './HeadCeilingContourList';
|
||||
import { HeadCeilingInfoConfigPanel } from './HeadCeilingInfoConfigPanel';
|
||||
|
||||
|
||||
/**
|
||||
* 吊顶轮廓管理界面
|
||||
*/
|
||||
@observer
|
||||
export class HeadCeilingContourManage extends React.Component<{}> {
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
defaultDirName: ""
|
||||
};
|
||||
}
|
||||
_CanCreateCeilingContour = observable.box(false);
|
||||
_CameraFiler: CADFiler;
|
||||
_BulkheadCeilingStore = HeadCeilingProfileMaterialStore.GetInstance();
|
||||
@observable _CurrentHeadCeilingInfo = { id: "", name: "" };
|
||||
|
||||
//创建吊顶轮廓
|
||||
_CreateCeilingContour = async (name: string, currentDir: IDirectoryProps, callback: Function) =>
|
||||
{
|
||||
if (!name.trim())
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "名称不能为空",
|
||||
intent: Intent.DANGER,
|
||||
timeout: 1000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._CurrentHeadCeilingInfo.id)
|
||||
{
|
||||
await this._RenameBulkheadCeiling(name);
|
||||
await callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!currentDir)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "未知错误,请重试",
|
||||
timeout: 1000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!app.Viewer.CameraCtrl.Direction.equals(new Vector3(0, 0, -1)))
|
||||
{
|
||||
await new ViewChange(ZAxisN, true).exec();
|
||||
AppToaster.show({
|
||||
message: "自动切换至俯视视角!",
|
||||
timeout: 5000,
|
||||
intent: Intent.PRIMARY,
|
||||
});
|
||||
}
|
||||
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.Clear();
|
||||
|
||||
//选择吊顶轮廓
|
||||
let contourEnts = await this._SelectCeilingContour();
|
||||
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.ShowMask();
|
||||
|
||||
if (contourEnts.length === 0) return;
|
||||
//对选择的吊顶轮廓进行编辑后上传
|
||||
this._EditorCeilingContour(contourEnts, name, currentDir);
|
||||
}
|
||||
};
|
||||
|
||||
//选择吊顶轮廓
|
||||
async _SelectCeilingContour(): Promise<(Polyline | Line | Arc)[]>
|
||||
{
|
||||
let ents: (Polyline | Line | Arc)[] = [];
|
||||
|
||||
await CommandWrap(async () =>
|
||||
{
|
||||
let ssRes = await app.Editor.GetSelection({ Filter: { filterTypes: [Polyline, Line, Arc] } });
|
||||
if (ssRes.Status !== PromptStatus.OK) return [];
|
||||
ents = ssRes.SelectSet.SelectEntityList as (Polyline | Line | Arc)[];
|
||||
|
||||
let contour = Contour.CreateContour(ents, true);
|
||||
if (!contour)
|
||||
{
|
||||
//警告错误 无法组成封闭的轮廓
|
||||
AppToaster.show({
|
||||
message: "无法组成封闭的轮廓",
|
||||
intent: Intent.DANGER,
|
||||
timeout: 3000,
|
||||
});
|
||||
ents = [];
|
||||
}
|
||||
}, "选择吊顶轮廓");
|
||||
|
||||
return ents;
|
||||
};
|
||||
|
||||
//对选择的吊顶轮廓进行编辑
|
||||
_EditorCeilingContour = async (curves: (Polyline | Line | Arc)[], name?: string, currentDir?: IDirectoryProps, database?: Database) =>
|
||||
{
|
||||
if (TempEditor.EditorIng || CommandState.CommandIng)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "当前正处于编辑模式下",
|
||||
timeout: 3000,
|
||||
intent: Intent.WARNING,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
app.Editor.ModalManage.DestoryAll();
|
||||
|
||||
TempEditor.Start();
|
||||
|
||||
if (!app.Viewer.CameraCtrl.Direction.equals(new Vector3(0, 0, -1)))
|
||||
app.Viewer.CameraCtrl.LookAt(new Vector3(0, 0, -1));
|
||||
|
||||
let config = new DialogUserConfig(this._BulkheadCeilingStore, BoardModalType.HeadCeilingProfileMaterial);
|
||||
await config.LoadAndInitConfig(true);
|
||||
|
||||
//呼出吊顶材质对应的颜色面板
|
||||
app.Editor.ModalManage.RenderModeless(
|
||||
HeadCeilingInfoConfigPanel,
|
||||
{ store: this._BulkheadCeilingStore, directoryId: DirectoryId.MaterialDir, configType: BoardModalType.HeadCeilingProfileMaterial, isNotUpdateStore: true, noClose: true },
|
||||
{ position: ModalPosition.RightMid, canMinimize: false }
|
||||
);
|
||||
|
||||
let extData = new BulkheadCeilingShapeTemplateExtendData;
|
||||
if (database?.ExtendedData)
|
||||
{
|
||||
let f = new CADFiler(database.ExtendedData);
|
||||
extData.ReadFile(f);
|
||||
|
||||
await this._BulkheadCeilingStore.InitEditorMaterialItems(extData);
|
||||
}
|
||||
|
||||
await CommandWrap(async () =>
|
||||
{
|
||||
let newCurves: (Polyline | Arc | Line)[] = [];
|
||||
|
||||
for (let curve of curves)
|
||||
{
|
||||
let cu = curve.Clone();
|
||||
cu.ColorIndex = extData.Color_MaterialId.get(cu.ColorIndex);
|
||||
|
||||
app.Database.ModelSpace.Append(cu);
|
||||
newCurves.push(cu);
|
||||
}
|
||||
|
||||
app.Database.hm.lockIndex++;//禁止初始化动作被撤销
|
||||
this._CameraFiler = new CADFiler;
|
||||
app.Viewer.CameraCtrl.WriteFile(this._CameraFiler);
|
||||
|
||||
app.Viewer.ZoomtoEntitys(newCurves);
|
||||
|
||||
AppToaster.show({
|
||||
message: this._RenderToasterMessage(name, currentDir, database),
|
||||
intent: Intent.PRIMARY,
|
||||
timeout: 0,
|
||||
onDismiss: this._ExitEditor
|
||||
}, "编辑吊顶轮廓");
|
||||
|
||||
}, "编辑吊顶轮廓");
|
||||
};
|
||||
|
||||
_RenderToasterMessage = (name: string, currentDir: IDirectoryProps, database?: Database) =>
|
||||
{
|
||||
return (
|
||||
<div className="flex-between toaster-message">
|
||||
<span>正在编辑吊顶轮廓,请确保轮廓为闭合多段线</span>
|
||||
<div>
|
||||
<Button text="保存" minimal onClick={() => { this._AddCeilingContourToDb(name, currentDir, database); }} />
|
||||
<Button text="取消" minimal onClick={() => { AppToaster.clear(); }} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
//退出轮廓编辑
|
||||
_ExitEditor = async () =>
|
||||
{
|
||||
app.Editor.ModalManage.DestoryAll();
|
||||
await app.Editor.ModalManage.EndExecingCmd();
|
||||
if (!this._CameraFiler) return;
|
||||
app.Viewer.CameraCtrl.ReadFile(this._CameraFiler);
|
||||
TempEditor.End();
|
||||
this._CameraFiler = undefined;
|
||||
app.Editor.ModalManage.RenderModal(HeadCeilingContourManage);
|
||||
};
|
||||
|
||||
//上传吊顶轮廓(点击上方保存)
|
||||
async _AddCeilingContourToDb(name: string, currentDir: IDirectoryProps, database?: Database): Promise<void>
|
||||
{
|
||||
let finalCurve: (Polyline | Line | Arc)[] = [];
|
||||
//因为临时编辑器会新建一个场景,只需要遍历这个场景内的对象就可以了
|
||||
for (let obj of app.Viewer.Scene.children)
|
||||
{
|
||||
if (obj.visible)
|
||||
{
|
||||
let en = GetEntity(obj);
|
||||
|
||||
if (en && en.Id?.Object && en.Visible && !en.IsErase && (en instanceof Polyline || en instanceof Line || en instanceof Arc))
|
||||
finalCurve.push(en);
|
||||
}
|
||||
}
|
||||
|
||||
let contour = Contour.CreateContour(finalCurve, true);
|
||||
if (!contour)
|
||||
{
|
||||
//警告错误 无法组成封闭的轮廓
|
||||
AppToaster.show({
|
||||
message: "无法组成封闭的轮廓",
|
||||
intent: Intent.DANGER,
|
||||
timeout: 3000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
//拓展数据(材质槽信息)
|
||||
let extData = new BulkheadCeilingShapeTemplateExtendData();
|
||||
|
||||
for (let curve of finalCurve)
|
||||
{
|
||||
if (extData.Color_MaterialId.has(curve.ColorIndex)) continue;
|
||||
|
||||
//根据UI面板对照获取材质id
|
||||
let material_id = this._BulkheadCeilingStore.m_Option.Item[curve.ColorIndex - 1]?.example?.id;
|
||||
if (material_id && material_id !== NONE_MATERIAL_ID)
|
||||
{
|
||||
//验证材质是否可用
|
||||
let mtlData = await PostJson(MaterialUrls.detail, { material_id: material_id.toString() });
|
||||
if (mtlData.err_code === RequestStatus.Ok)
|
||||
extData.Color_MaterialId.set(curve.ColorIndex, material_id);
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
extData.Color_MaterialId.set(curve.ColorIndex, NONE_MATERIAL_ID);
|
||||
}
|
||||
|
||||
let f = new CADFiler;
|
||||
extData.WriteFile(f);
|
||||
|
||||
|
||||
let tempaltes = new Set<ObjectId>;
|
||||
for (let e of finalCurve)
|
||||
tempaltes.add((e.Template?.Object as TemplateRecord)?.Root?.objectId);
|
||||
|
||||
if (tempaltes.size > 1)
|
||||
{
|
||||
let keyRes = await app.Editor.GetKeyWords({
|
||||
Msg: "选择的图形中来自不同的模块,忽略所有模块信息并继续?",
|
||||
KeyWordList: [
|
||||
{
|
||||
key: "1",
|
||||
msg: "好"
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
msg: "算了"
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
if (keyRes.StringResult !== "1")
|
||||
return;
|
||||
}
|
||||
|
||||
AppToaster.show({
|
||||
message: "请点选该轮廓基点!",
|
||||
timeout: 3000,
|
||||
intent: Intent.PRIMARY,
|
||||
}, "getPoint");
|
||||
|
||||
let res = await app.Editor.GetPoint({
|
||||
Msg: "指定基点"
|
||||
});
|
||||
|
||||
if (res.Status === PromptStatus.Cancel)
|
||||
return;
|
||||
|
||||
let point = res.Point.negate();
|
||||
|
||||
let saveDb = new Database(false, false, true);
|
||||
if (database)
|
||||
{
|
||||
saveDb = database;
|
||||
saveDb.ModelSpace.Destroy();
|
||||
saveDb.TemplateTable.Destroy();
|
||||
saveDb.MaterialTable.Destroy();
|
||||
}
|
||||
|
||||
if (tempaltes.size > 1 || [...tempaltes][0] === undefined)
|
||||
{
|
||||
let template = new TemplateRecord;
|
||||
saveDb.TemplateTable.Add(template);
|
||||
for (let e of finalCurve)
|
||||
{
|
||||
let newE = e.Clone().ApplyMatrix(new Matrix4().setPosition(point));
|
||||
saveDb.ModelSpace.Append(newE);
|
||||
template.Objects.push(newE.Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
let template = [...tempaltes][0];
|
||||
saveDb.WblockCloneObejcts([template.Object], saveDb.TemplateTable, new Map, DuplicateRecordCloning.Ignore, new WblockCloneFiler);
|
||||
}
|
||||
|
||||
saveDb.ExtendedData = f.Data;
|
||||
|
||||
let logo = getPolylineSVG(contour.Curve as Polyline);
|
||||
let fileJson = saveDb.FileWrite().ToString();
|
||||
|
||||
let data: { err_code: RequestStatus; };
|
||||
if (this._CurrentHeadCeilingInfo.id)
|
||||
{
|
||||
data = await PostJson(ToplineUrls.update, {
|
||||
topline_id: this._CurrentHeadCeilingInfo.id,
|
||||
logo,
|
||||
file: deflate(fileJson),
|
||||
zip_type: "gzip",
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
data = await PostJson(ToplineUrls.create, {
|
||||
dir_id: currentDir.id,
|
||||
name,
|
||||
logo,
|
||||
file: deflate(fileJson),
|
||||
zip_type: "gzip",
|
||||
});
|
||||
}
|
||||
|
||||
AppToaster.dismiss("编辑吊顶轮廓");
|
||||
|
||||
if (data.err_code === RequestStatus.Ok)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: this._CurrentHeadCeilingInfo.id ? "编辑成功!" : "添加成功!",
|
||||
timeout: 2000,
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//吊顶轮廓重命名
|
||||
_RenameBulkheadCeiling = async (name: string) =>
|
||||
{
|
||||
let data = await PostJson(ToplineUrls.update, {
|
||||
topline_id: this._CurrentHeadCeilingInfo.id,
|
||||
name
|
||||
});
|
||||
if (data.code === RequestStatus.Ok)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "重命名成功",
|
||||
timeout: 1000
|
||||
});
|
||||
}
|
||||
this._CanCreateCeilingContour.set(false);
|
||||
};
|
||||
|
||||
_StartCreateHeadCeilingContour = () =>
|
||||
{
|
||||
this._CurrentHeadCeilingInfo.id = "";
|
||||
this._CurrentHeadCeilingInfo.name = "";
|
||||
this._CanCreateCeilingContour.set(true);
|
||||
};
|
||||
|
||||
_RenderNav = () =>
|
||||
{
|
||||
return (
|
||||
<Button
|
||||
icon="cloud-upload"
|
||||
style={{ marginRight: 10 }}
|
||||
text="新增轮廓模板"
|
||||
intent={Intent.SUCCESS}
|
||||
onClick={this._StartCreateHeadCeilingContour}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_RenderMenuItems = () =>
|
||||
{
|
||||
return (
|
||||
<MenuItem icon="cloud-upload" text="新增轮廓模板"
|
||||
onClick={this._StartCreateHeadCeilingContour}
|
||||
/>
|
||||
);
|
||||
};
|
||||
public render()
|
||||
{
|
||||
return (
|
||||
<ModalContainer className="headCeilingContourManage">
|
||||
<ModalHeader
|
||||
title="吊顶截面轮廓"
|
||||
icon="bold"
|
||||
close={() => app.Editor.ModalManage.Destory()}
|
||||
/>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<CommonPanel
|
||||
defaultDirId={DirectoryId.CeilingContour}
|
||||
renderNav={this._RenderNav}
|
||||
renderMenuItems={this._RenderMenuItems}
|
||||
getUrl={ToplineUrls.get}
|
||||
deleteUrl={ToplineUrls.delete}
|
||||
handleDirComponent={
|
||||
this._CanCreateCeilingContour.get() && <HandleDirComponent
|
||||
defualtValue={this._CurrentHeadCeilingInfo.name}
|
||||
isReset={false}
|
||||
isOpen={this._CanCreateCeilingContour}
|
||||
handleFunc={this._CreateCeilingContour}
|
||||
title="吊顶截面轮廓模板名称:"
|
||||
/>
|
||||
}
|
||||
clickTree={() =>
|
||||
{
|
||||
this._CurrentHeadCeilingInfo.id = "";
|
||||
}}
|
||||
>
|
||||
<HeadCeilingContourList
|
||||
isRename={this._CanCreateCeilingContour}
|
||||
editorCeilingContour={this._EditorCeilingContour}
|
||||
currentHeadCeilingInfo={this._CurrentHeadCeilingInfo}
|
||||
/>
|
||||
</CommonPanel>
|
||||
</div>
|
||||
<div className={Classes.DIALOG_FOOTER} >
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button
|
||||
className={Classes.INTENT_DANGER}
|
||||
text="取消"
|
||||
onClick={() => app.Editor.ModalManage.Destory()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ModalContainer >
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { app } from "../../../ApplicationServices/Application";
|
||||
import { Command } from "../../../Editor/CommandMachine";
|
||||
import { HeadCeilingContourManage } from "./HeadCeilingContourManage";
|
||||
|
||||
export class Command_HeadCeilingContourManage implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
app.Editor.ModalManage.RenderModal(HeadCeilingContourManage);
|
||||
}
|
||||
}
|
@ -0,0 +1,247 @@
|
||||
import { Button, Classes, Icon, Label } from "@blueprintjs/core";
|
||||
import { observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { begin } from "xaop";
|
||||
import { app } from "../../../ApplicationServices/Application";
|
||||
import { KeyBoard } from "../../../Common/KeyEnum";
|
||||
import { Log } from "../../../Common/Log";
|
||||
import { DirectoryId } from "../../../Common/Request";
|
||||
import { MaterialIn } from "../../../Common/SerializeMaterial";
|
||||
import { PhysicalMaterialRecord } from "../../../DatabaseServices/PhysicalMaterialRecord";
|
||||
import { TEMPLATE_SELECT_ID } from "../../../DatabaseServices/Room/Entity/Wall/Hole/Window/DrawWindowPanel";
|
||||
import { GetCeilingContourDate, HeadCeilingInfoStore, NONE_CONTOUR_ID } from "../../Store/HeadCeilingStore/HeadCeilingInfoStore";
|
||||
import { HeadCeilingProfileMaterialStore, NONE_MATERIAL_ID } from "../../Store/HeadCeilingStore/HeadCeilingMaterialStore";
|
||||
import { BulkheadCeilingOption, BulkheadCeilingProfileMaterialOption } from "../../Store/OptionInterface/BulkheadCeilingOption";
|
||||
import { BoardModalType } from "../Board/BoardModalType";
|
||||
import { Config_ModalType, UserConfigComponent } from "../Board/UserConfigComponent";
|
||||
import { ModalState } from "../Modal/ModalInterface";
|
||||
import { OnlySelectPanelStore } from "../OnlySelectManage/OnlySelectPanelStore";
|
||||
import { OnlySelectManagePanel } from "../OnlySelectManage/SelectManagePanel";
|
||||
import { GetMtlJson } from "../SourceManage/MaterialList";
|
||||
import './HeadCeiling.less';
|
||||
import { HeadCeilingInfoItem } from "./HeadCeilingInfoItem";
|
||||
|
||||
export enum Display
|
||||
{
|
||||
Block = "block",
|
||||
None = "none",
|
||||
}
|
||||
|
||||
interface HeadCeilingInfoConfigPanelProps
|
||||
{
|
||||
store: HeadCeilingInfoStore | HeadCeilingProfileMaterialStore;
|
||||
directoryId: DirectoryId;
|
||||
configType: BoardModalType;
|
||||
noClose?: boolean;
|
||||
isNotUpdateStore?: boolean;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class HeadCeilingInfoConfigPanel extends React.Component<HeadCeilingInfoConfigPanelProps, {}>
|
||||
{
|
||||
@observable _Display = Display.None;
|
||||
_Event: Function;
|
||||
_Title: string = "吊顶截面轮廓";
|
||||
_CameraStateContainer: HTMLElement;
|
||||
_SelectStore: OnlySelectPanelStore = OnlySelectPanelStore.GetSingleInstance(); //独立的材质选择Store
|
||||
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
|
||||
if (!this.props.configType) Log("无效configType");
|
||||
this._Title += this.props.store instanceof HeadCeilingInfoStore ? "对照表" : "材质对照表";
|
||||
|
||||
//选择材质的UI放在 #modal 里有效居中
|
||||
this._CameraStateContainer = document.createElement('div');
|
||||
this._CameraStateContainer.id = TEMPLATE_SELECT_ID;
|
||||
this._CameraStateContainer.style.zIndex = "35";
|
||||
document.getElementById('modal').appendChild(this._CameraStateContainer);
|
||||
|
||||
if (window.screen.width <= 1450)
|
||||
this._CameraStateContainer.style.left = '120px';
|
||||
else
|
||||
this._CameraStateContainer.style.left = `calc(50vw - 500px)`;
|
||||
|
||||
if (window.screen.height <= 750)
|
||||
this._CameraStateContainer.style.top = `0px`;
|
||||
else
|
||||
this._CameraStateContainer.style.top = `calc(50vh - 395px)`;
|
||||
|
||||
this._CameraStateContainer.style.display = Display.None;
|
||||
|
||||
ReactDOM.render(<OnlySelectManagePanel
|
||||
dataStore={this.props.store}
|
||||
selectStore={this._SelectStore}
|
||||
directoryId={this.props.directoryId}
|
||||
setDisplay={this._OpenSelectTemplate}
|
||||
dispaly={this._Display}
|
||||
return={this._Return}
|
||||
/>, this._CameraStateContainer);
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
this._Event = begin(app.Editor.ModalManage, app.Editor.ModalManage.OnKeyDown, (e: KeyboardEvent) =>
|
||||
{
|
||||
if (e.keyCode === KeyBoard.Escape)
|
||||
{
|
||||
if (this._CameraStateContainer.style.display === Display.Block)
|
||||
{
|
||||
this._OpenSelectTemplate(Display.None);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.props.noClose)
|
||||
app.Editor.ModalManage.stopKeyDownEvent = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
this._Event();
|
||||
this._Event = null;
|
||||
document.getElementById('modal').removeChild(this._CameraStateContainer);
|
||||
this._CameraStateContainer = undefined;
|
||||
}
|
||||
|
||||
_Return = async (status: ModalState) =>
|
||||
{
|
||||
if (status === ModalState.Ok)
|
||||
{
|
||||
if (this.props.directoryId === DirectoryId.MaterialDir)
|
||||
{
|
||||
let material_id = "";
|
||||
this._SelectStore.currentSelectId.forEach((e) => { material_id = e; });
|
||||
|
||||
let option = this.props.store.m_Option as BulkheadCeilingProfileMaterialOption;
|
||||
let material = option.Item[this._SelectStore.itemIndex].example;
|
||||
|
||||
if (material_id)
|
||||
{
|
||||
let json = await GetMtlJson({ material_id });
|
||||
if (json)
|
||||
{
|
||||
let mtl = MaterialIn(JSON.parse(json)) as PhysicalMaterialRecord;
|
||||
if (mtl)
|
||||
{
|
||||
material.id = parseInt(material_id);
|
||||
material.name = this._SelectStore.dataName ?? mtl.Name;
|
||||
material.type = mtl.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
material.id = NONE_MATERIAL_ID;
|
||||
material.name = '';
|
||||
material.type = '';
|
||||
}
|
||||
}
|
||||
else if (this.props.directoryId === DirectoryId.CeilingContour)
|
||||
{
|
||||
let contour_id = "";
|
||||
this._SelectStore.currentSelectId.forEach((e) => { contour_id = e; });
|
||||
|
||||
let option = this.props.store.m_Option as BulkheadCeilingOption;
|
||||
let contour = option.Item[this._SelectStore.itemIndex].example;
|
||||
|
||||
if (contour_id)
|
||||
{
|
||||
let date = await GetCeilingContourDate(contour_id);
|
||||
if (date)
|
||||
{
|
||||
contour.id = parseInt(contour_id);
|
||||
contour.name = date.toplines.name;
|
||||
contour.logo = date.toplines.logo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contour.id = NONE_CONTOUR_ID;
|
||||
contour.name = '';
|
||||
contour.logo = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//开关选择材质的面板
|
||||
_OpenSelectTemplate = (style: Display) =>
|
||||
{
|
||||
if (style === Display.Block)
|
||||
{
|
||||
this._SelectStore.Clear();
|
||||
app.Editor.ModalManage.stopKeyDownEvent = true;
|
||||
}
|
||||
this._CameraStateContainer.style.display = style;
|
||||
this._Display = style;
|
||||
};
|
||||
|
||||
//窗口最小化
|
||||
_Minimize()
|
||||
{
|
||||
app.Editor.ModalManage.CurrentModal.canMinimize = true;
|
||||
app.Editor.ModalManage.CurrentModal.Minimize();
|
||||
app.Editor.ModalManage.CurrentModal.canMinimize = false;
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
return (
|
||||
<div id="BulkheadCeilingConfig" className={Classes.DIALOG_CONTAINER}>
|
||||
<div className={Classes.DIALOG} >
|
||||
<div className={Classes.DIALOG_HEADER} data-id="dragArea">
|
||||
<Icon icon="th" iconSize={18} />
|
||||
<h4 className={Classes.HEADING}>{this._Title}</h4>
|
||||
<Button
|
||||
icon="minus"
|
||||
aria-label="Close"
|
||||
minimal={true}
|
||||
onClick={() => { this._Minimize(); }}
|
||||
/>
|
||||
<Button
|
||||
icon="cross"
|
||||
aria-label="Close"
|
||||
minimal={true}
|
||||
onClick={() => { app.Editor.ModalManage.Destory(); }}
|
||||
/>
|
||||
</div>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<ul>
|
||||
<li className="firstLi">
|
||||
<Label>颜色</Label>
|
||||
<Label>洞/岛</Label>
|
||||
<Label>截面轮廓</Label>
|
||||
</li>
|
||||
{
|
||||
this.props.store.m_Option.Item.map((item, index) =>
|
||||
{
|
||||
return <HeadCeilingInfoItem
|
||||
item={item}
|
||||
display={this._OpenSelectTemplate}
|
||||
itemIndex={index}
|
||||
selectStore={this._SelectStore}
|
||||
configType={this.props.configType}
|
||||
/>;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={Classes.DIALOG_FOOTER} style={{ display: "unset" }}>
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<div className="foot_left">
|
||||
<UserConfigComponent store={this.props.store} type={this.props.configType} configType={Config_ModalType.UserConfigModal} isNotUpdateStore={this.props.isNotUpdateStore} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { app } from "../../../ApplicationServices/Application";
|
||||
import { DirectoryId } from "../../../Common/Request";
|
||||
import { Command } from "../../../Editor/CommandMachine";
|
||||
import { HeadCeilingInfoStore } from "../../Store/HeadCeilingStore/HeadCeilingInfoStore";
|
||||
import { HeadCeilingProfileMaterialStore } from "../../Store/HeadCeilingStore/HeadCeilingMaterialStore";
|
||||
import { BoardModalType } from "../Board/BoardModalType";
|
||||
import { HeadCeilingInfoConfigPanel } from "./HeadCeilingInfoConfigPanel";
|
||||
|
||||
export class Command_HeadCeilingMaterialPanel implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let store = HeadCeilingProfileMaterialStore.GetInstance();
|
||||
app.Editor.ModalManage.RenderModeless(HeadCeilingInfoConfigPanel,
|
||||
{ store, directoryId: DirectoryId.MaterialDir, configType: BoardModalType.HeadCeilingProfileMaterial },
|
||||
{ canMinimize: false }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Command_HeadCeilingInfoConfigPanel implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let store = HeadCeilingInfoStore.GetInstance();
|
||||
app.Editor.ModalManage.RenderModeless(HeadCeilingInfoConfigPanel,
|
||||
{ store, directoryId: DirectoryId.CeilingContour, configType: BoardModalType.BulkheadCeilingContour },
|
||||
{ canMinimize: false }
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
import { Button, HTMLSelect, Icon } from "@blueprintjs/core";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import { ColorMaterial } from "../../../Common/ColorPalette";
|
||||
import { BulkheadCeiling_ContourType } from "../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeiling";
|
||||
import { ICeilingProfileMaterialItem } from "../../Store/HeadCeilingStore/HeadCeilingMaterialStore";
|
||||
import { ICeilingItem } from "../../Store/OptionInterface/BulkheadCeilingOption";
|
||||
import { BoardModalType } from "../Board/BoardModalType";
|
||||
import { OnlySelectPanelStore } from "../OnlySelectManage/OnlySelectPanelStore";
|
||||
import './HeadCeiling.less';
|
||||
import { Display } from "./HeadCeilingInfoConfigPanel";
|
||||
|
||||
interface ItemPorps
|
||||
{
|
||||
item: ICeilingItem | ICeilingProfileMaterialItem;
|
||||
itemIndex: number;
|
||||
selectStore: OnlySelectPanelStore;
|
||||
configType: BoardModalType;
|
||||
display: (display: Display) => void;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class HeadCeilingInfoItem extends React.Component<ItemPorps, {}>
|
||||
{
|
||||
_IsMaterial = this.props.configType === BoardModalType.HeadCeilingProfileMaterial;
|
||||
|
||||
render()
|
||||
{
|
||||
let item = this.props.item as any;
|
||||
return (
|
||||
<li className={this._IsMaterial ? "" : "contourLi"}>
|
||||
<div className="bp3-label">
|
||||
<div className="backgroudColor" style={{ background: ColorMaterial.GetColor(this.props.item.color).getStyle() }}>
|
||||
{item.color}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bp3-label">
|
||||
<HTMLSelect
|
||||
options={[{ value: 0, label: "洞" }, { value: 1, label: "岛" }]}
|
||||
value={item.example.contourType ?? BulkheadCeiling_ContourType.Hole}
|
||||
onChange={(e) =>
|
||||
{
|
||||
item.example.contourType = parseInt(e.currentTarget.value);
|
||||
}}
|
||||
iconProps={{ icon: "caret-down" }}
|
||||
disabled={this._IsMaterial}
|
||||
/>
|
||||
</div>
|
||||
<div className="itemContour bp3-label">
|
||||
{
|
||||
this._IsMaterial ?
|
||||
<div className="material_detail" >
|
||||
<div className="detail_name">
|
||||
<span>材质名:</span>
|
||||
<div className="materialName">{item.example.name || "无"}</div>
|
||||
</div>
|
||||
<div className="detail_type">
|
||||
<span>类型:</span>
|
||||
<div className="materialType">{item.example.type || "无"}</div>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="contour_detail" >
|
||||
<div className="detail_logo">
|
||||
{
|
||||
item.example.logo ? <svg
|
||||
width="100"
|
||||
height="100"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d={item.example.logo} fill="transparent" stroke="black" strokeWidth="1" />
|
||||
</svg>
|
||||
:
|
||||
<Icon iconSize={40} icon="add-to-artifact" />
|
||||
}
|
||||
</div>
|
||||
<div className="detail_name">
|
||||
<span>轮廓名称:</span>
|
||||
<div className="materialName">{item.example.name || "无"}</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<Button
|
||||
text="选择"
|
||||
onClick={() =>
|
||||
{
|
||||
this.props.selectStore.itemIndex = this.props.itemIndex;
|
||||
this.props.display(Display.Block);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { AnyObject } from '../../Store/OptionInterface/IOptionInterface';
|
||||
import { DataList } from '../Common/Datalist';
|
||||
|
||||
interface IDataListProps
|
||||
{
|
||||
dataList?: any[];
|
||||
select?: (e, data) => void;
|
||||
selectIds?: Set<string>;
|
||||
showInfos?: boolean;
|
||||
idKey?: string;
|
||||
handleDbClick?: (data: AnyObject) => void;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class OnlySelectDataList extends React.Component<IDataListProps, {}>
|
||||
{
|
||||
render()
|
||||
{
|
||||
return (
|
||||
<DataList
|
||||
dataList={this.props.dataList}
|
||||
idKey={this.props.idKey}
|
||||
select={this.props.select}
|
||||
selectData={this.props.selectIds}
|
||||
dbclickImg={this.props.handleDbClick}
|
||||
hintClassName="hint editor-lint"
|
||||
isSvg={this.props.idKey === "topline_id"} //需改动
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,397 @@
|
||||
import { Classes, HTMLSelect, ITreeNode, Tree } from "@blueprintjs/core";
|
||||
import hotkeys from "hotkeys-js-ext";
|
||||
import { action, observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import { app } from "../../../ApplicationServices/Application";
|
||||
import { DirUrl } from "../../../Common/HostUrl";
|
||||
import { MouseKey } from "../../../Common/KeyEnum";
|
||||
import { DirectoryId, PostJson, RequestStatus } from "../../../Common/Request";
|
||||
import { EOrderType } from "../../../Editor/OrderType";
|
||||
import { AnyObject } from "../../Store/OptionInterface/IOptionInterface";
|
||||
import { OrderType } from "../SourceManage/CommonPanel";
|
||||
import { CommonPanelStore, commonPanelStore } from "../SourceManage/CommonPanelStore";
|
||||
import { Pagination } from "../SourceManage/Pagination";
|
||||
import { OnlySelectPanelStore } from "./OnlySelectPanelStore";
|
||||
import './SelectManagePanel.less';
|
||||
|
||||
export interface IDirectoryProps
|
||||
{
|
||||
id: DirectoryId | string;
|
||||
path: string;
|
||||
pathNum: number[];
|
||||
}
|
||||
interface ICommonPanelState
|
||||
{
|
||||
nodes: ITreeNode[]; //目录节点
|
||||
defaultDirName: string; //新目录名字
|
||||
updateNode: ITreeNode; //需要更新的目录节点
|
||||
}
|
||||
interface ICommonPanelProps
|
||||
{
|
||||
defaultDirId: string; //根目录ID
|
||||
getUrl: string; //获取数据URL
|
||||
dirNameFilter?: string[];
|
||||
handleDbClick?: (data: AnyObject) => void; //双击dataImg事件
|
||||
}
|
||||
@observer
|
||||
export class OnlySelectDataManage extends React.Component<ICommonPanelProps, ICommonPanelState>
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
nodes: [],
|
||||
defaultDirName: "",
|
||||
updateNode: undefined,
|
||||
};
|
||||
this._CurrentDir.id = this.props.defaultDirId;
|
||||
switch (this.props.defaultDirId)
|
||||
{
|
||||
case DirectoryId.ImgDir:
|
||||
this._IdKey = "image_id";
|
||||
break;
|
||||
case DirectoryId.HistoryDit:
|
||||
case DirectoryId.FileDir:
|
||||
this._IdKey = "file_id";
|
||||
break;
|
||||
case DirectoryId.MaterialDir:
|
||||
this._IdKey = "material_id";
|
||||
break;
|
||||
case DirectoryId.ToplineDir:
|
||||
case DirectoryId.Frame:
|
||||
case DirectoryId.KnifePathDir:
|
||||
case DirectoryId.CeilingContour:
|
||||
this._IdKey = "topline_id";
|
||||
break;
|
||||
case DirectoryId.DrillingDir:
|
||||
case DirectoryId.TemplateDir:
|
||||
this._IdKey = "module_id";
|
||||
break;
|
||||
default:
|
||||
console.warn("未知目录id");
|
||||
this._IdKey = "";
|
||||
}
|
||||
}
|
||||
_SelectStore: OnlySelectPanelStore = OnlySelectPanelStore.GetSingleInstance();
|
||||
static CurrentDirCache: Map<string, IDirectoryProps> = new Map();
|
||||
@observable _DataList = [];
|
||||
@observable _CurrentDir: IDirectoryProps = {
|
||||
id: DirectoryId.None,
|
||||
path: "",
|
||||
pathNum: []
|
||||
};
|
||||
@observable _PageData = { //分页数据
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
pageCount: 15
|
||||
};
|
||||
@observable _SearchStr = "";//搜索材质名
|
||||
_IdKey: string;
|
||||
_Tree: HTMLElement; //目录数元素
|
||||
_TimeId = null; //搜索时的定时器
|
||||
|
||||
get IsCtrlDown()
|
||||
{
|
||||
return app.Editor.ModalManage.IsCtrlDown || hotkeys.ctrl;
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
//监听右键其他位置
|
||||
if (this._Tree)
|
||||
{
|
||||
this._Tree.addEventListener('mousedown', this._HandleTreeMouseDown);
|
||||
}
|
||||
this._LoadingData();
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
if (this._Tree)
|
||||
{
|
||||
this._Tree.removeEventListener('mousedown', this._HandleTreeMouseDown);
|
||||
}
|
||||
}
|
||||
render()
|
||||
{
|
||||
return (
|
||||
<>
|
||||
<div className="searchMaterial">
|
||||
<HTMLSelect
|
||||
disabled={this.props.defaultDirId === DirectoryId.HistoryDit}
|
||||
defaultValue={commonPanelStore.m_Option.orderType}
|
||||
options={OrderType}
|
||||
onChange={(e) =>
|
||||
{
|
||||
commonPanelStore.m_Option.orderType = e.target.value as EOrderType;
|
||||
this._HandleGetData();
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
disabled={this.props.defaultDirId === DirectoryId.HistoryDit}
|
||||
className="bp3-input"
|
||||
placeholder="搜索..."
|
||||
type="search"
|
||||
defaultValue={this._SearchStr}
|
||||
onKeyDown={(e) => { e.stopPropagation(); }}
|
||||
onChange={(e) => this._HandleSearch(e)}
|
||||
/>
|
||||
</div>
|
||||
<div className="materialParams">
|
||||
<div
|
||||
className="bp3-card img-tree"
|
||||
ref={c => this._Tree = c}
|
||||
>
|
||||
<Tree
|
||||
contents={this.state.nodes}
|
||||
onNodeClick={this._HandleNodeClick}
|
||||
onNodeCollapse={(node) => this._HandleNodeCollapse(node, true)}
|
||||
onNodeExpand={(node) => this._HandleNodeCollapse(node, false)}
|
||||
className={Classes.ELEVATION_0}
|
||||
/>
|
||||
</div>
|
||||
<div className="bp3-card img-lib" >
|
||||
{
|
||||
React.Children.map(this.props.children, child =>
|
||||
child && React.cloneElement(child as React.DetailedReactHTMLElement<any, any>,
|
||||
{
|
||||
dataList: this._DataList,
|
||||
currentDir: this._CurrentDir,
|
||||
getData: this._HandleGetData,
|
||||
select: this._HandleSelectData,
|
||||
handleDbClick: this._HandleDbClick,
|
||||
selectIds: this._SelectStore.currentSelectId,
|
||||
idKey: this._IdKey,
|
||||
})
|
||||
)
|
||||
}
|
||||
{
|
||||
this._PageData.count > this._PageData.pageCount &&
|
||||
<Pagination
|
||||
getImgListFun={this._HandleGetData}
|
||||
pageData={this._PageData}
|
||||
maxCount={3}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
_HandleSelectData = (e: React.MouseEvent<HTMLInputElement>, data) =>
|
||||
{
|
||||
const id = data[this._IdKey];
|
||||
this._SelectStore.Clear();
|
||||
this._SelectStore.currentSelectId.add(id);
|
||||
this._SelectStore.dataName = data.name;
|
||||
};
|
||||
|
||||
//双击dataImg事件
|
||||
_HandleDbClick = (data) =>
|
||||
{
|
||||
this.props.handleDbClick(data);
|
||||
};
|
||||
|
||||
//选中目录亮显
|
||||
_SelectNode = (nodeData: ITreeNode, isSelected?: boolean) =>
|
||||
{
|
||||
this._ForEachNode(this.state.nodes, n => (n.isSelected = false));
|
||||
nodeData.isSelected = true;
|
||||
this.setState(this.state);
|
||||
};
|
||||
|
||||
//点击目录
|
||||
_HandleNodeClick = async (nodeData: ITreeNode, _nodePath: number[]) =>
|
||||
{
|
||||
const isReLoad = nodeData.id !== this._CurrentDir.id;
|
||||
this._GetCurrentDir(nodeData.id, _nodePath);
|
||||
this._SelectStore.Clear();
|
||||
if (isReLoad)
|
||||
await this._HandleGetData();
|
||||
this._SelectNode(nodeData);
|
||||
};
|
||||
|
||||
//去掉其他节点被选择状态
|
||||
_ForEachNode(nodes: ITreeNode[], callback: (node: ITreeNode) => void)
|
||||
{
|
||||
if (nodes == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const node of nodes)
|
||||
{
|
||||
callback(node);
|
||||
this._ForEachNode(node.childNodes, callback);
|
||||
}
|
||||
}
|
||||
|
||||
//获取当前目录路径
|
||||
_GetCurrentDir = (dirId: React.ReactText, nodePath: number[]) =>
|
||||
{
|
||||
let path = "";
|
||||
let childNodes: ITreeNode[];
|
||||
for (let i of nodePath)
|
||||
{
|
||||
let node: ITreeNode;
|
||||
if (!childNodes)
|
||||
{
|
||||
node = this.state.nodes[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
node = childNodes[i];
|
||||
}
|
||||
path += node.label + "/";
|
||||
childNodes = node.childNodes;
|
||||
}
|
||||
Object.assign(this._CurrentDir, { id: dirId, path, pathNum: nodePath });
|
||||
OnlySelectDataManage.CurrentDirCache.set(this.props.defaultDirId, { id: dirId as DirectoryId, path, pathNum: nodePath });
|
||||
};
|
||||
|
||||
//分析目录转换为ui节点数
|
||||
_ParseNodes = (dirs: any) =>
|
||||
{
|
||||
let newNodes: ITreeNode[] = [];
|
||||
for (let dir of dirs)
|
||||
{
|
||||
let node: ITreeNode = {
|
||||
id: dir.dir_id,
|
||||
label: dir.dir_name,
|
||||
icon: "folder-close",
|
||||
hasCaret: dir.childs.length > 0,
|
||||
className: dir.dir_id, //为了识别这个元素的目录id
|
||||
childNodes: this._ParseNodes(dir.childs),
|
||||
};
|
||||
newNodes.push(node);
|
||||
}
|
||||
return newNodes;
|
||||
};
|
||||
|
||||
//展开折叠目录
|
||||
_HandleNodeCollapse = (nodeData: ITreeNode, isCollapse: boolean) =>
|
||||
{
|
||||
nodeData.isExpanded = !isCollapse;
|
||||
this.setState(this.state);
|
||||
};
|
||||
|
||||
/**
|
||||
* 服务段获取数据
|
||||
* name-查询字符串,curr_page-当前页,dir_id:目录id
|
||||
* desc 倒序
|
||||
*/
|
||||
@action
|
||||
_HandleGetData = async (queryData?: { dir_id?: string, name?: string, curr_page?: number; }) =>
|
||||
{
|
||||
let query: any;
|
||||
|
||||
query = {
|
||||
dir_id: this._CurrentDir.id,
|
||||
curr_page: 1,
|
||||
page_count: this._PageData.pageCount,
|
||||
name: this._SearchStr,
|
||||
};
|
||||
query.order = CommonPanelStore.GetInstance().m_Option.orderType;
|
||||
|
||||
//若不传入数据,用默认查询数据.
|
||||
if (queryData)
|
||||
{
|
||||
Object.assign(query, queryData);
|
||||
}
|
||||
|
||||
this._PageData.currentPage = query.curr_page;
|
||||
|
||||
let data = await PostJson(this.props.getUrl, query);
|
||||
|
||||
if (data.err_code === RequestStatus.Ok && Number(data.count))
|
||||
{
|
||||
let dataList: any[];
|
||||
dataList = data.images || data.materials || data.toplines || data.files || data.modules || [];
|
||||
dataList.forEach(d => d.isChecked = false);
|
||||
this._DataList = dataList;
|
||||
}
|
||||
else
|
||||
this._DataList.length = 0;
|
||||
|
||||
this._PageData.count = parseInt(data.count);
|
||||
this._SelectStore.Clear();
|
||||
};
|
||||
|
||||
//点击节点容器的动作
|
||||
_HandleTreeMouseDown = (e: MouseEvent) =>
|
||||
{
|
||||
this._SelectStore.Clear();
|
||||
let el = e.target as HTMLElement;
|
||||
if (e.button === MouseKey.Left)
|
||||
{
|
||||
if (el.classList.contains('bp3-tree'))
|
||||
{
|
||||
this._ForEachNode(this.state.nodes, n => (n.isSelected = false));
|
||||
if (this._CurrentDir.id !== this.props.defaultDirId)
|
||||
{
|
||||
Object.assign(this._CurrentDir, { id: this.props.defaultDirId, path: "", pathNum: [] });
|
||||
OnlySelectDataManage.CurrentDirCache.set(this.props.defaultDirId, { id: this.props.defaultDirId as DirectoryId, path: "", pathNum: [] });
|
||||
this._HandleGetData();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_LoadingData = async () =>
|
||||
{
|
||||
let data = await PostJson(DirUrl.query, { dir_type: this.props.defaultDirId });
|
||||
if (data.err_code === RequestStatus.Ok)
|
||||
{
|
||||
let dirs = data.dirs as { dir_name: string; }[];
|
||||
if (this.props.dirNameFilter)
|
||||
{
|
||||
dirs = dirs.filter(dir =>
|
||||
{
|
||||
return this.props.dirNameFilter.some(s => dir.dir_name.includes(s));
|
||||
});
|
||||
}
|
||||
this.setState({ nodes: this._ParseNodes(dirs) });
|
||||
}
|
||||
let currentDirProps = OnlySelectDataManage.CurrentDirCache.get(this.props.defaultDirId);
|
||||
if (currentDirProps)
|
||||
{
|
||||
this._LoadCurrentNode(currentDirProps);
|
||||
}
|
||||
await this._HandleGetData();
|
||||
};
|
||||
|
||||
_LoadCurrentNode = (currentDirProps: IDirectoryProps) =>
|
||||
{
|
||||
let node: ITreeNode;
|
||||
for (let n of currentDirProps.pathNum)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
node = this.state.nodes[n];
|
||||
}
|
||||
else
|
||||
node = node.childNodes[n];
|
||||
if (!node) return;
|
||||
if (node.childNodes.length)
|
||||
node.isExpanded = true;
|
||||
}
|
||||
if (node)
|
||||
{
|
||||
this._SelectNode(node, true);
|
||||
Object.assign(this._CurrentDir, currentDirProps);
|
||||
}
|
||||
};
|
||||
|
||||
_HandleSearch = async (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
{
|
||||
this._SearchStr = e.currentTarget.value;
|
||||
if (this._TimeId)
|
||||
clearTimeout(this._TimeId);
|
||||
this._TimeId = setTimeout(async () =>
|
||||
{
|
||||
await this._HandleGetData();
|
||||
}, 500);
|
||||
};
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { observable } from "mobx";
|
||||
|
||||
//只用于 选择的面板Store
|
||||
export class OnlySelectPanelStore
|
||||
{
|
||||
itemIndex: number = 0;
|
||||
dataName: string = "";
|
||||
@observable currentSelectId: Set<string> = new Set<string>(); //当前选择的信息
|
||||
|
||||
Clear()
|
||||
{
|
||||
this.dataName = "";
|
||||
this.currentSelectId.clear();
|
||||
}
|
||||
|
||||
private static _SingleInstance: OnlySelectPanelStore;
|
||||
static GetSingleInstance(): OnlySelectPanelStore
|
||||
{
|
||||
if (this._SingleInstance) return this._SingleInstance;
|
||||
this._SingleInstance = new OnlySelectPanelStore;
|
||||
return this._SingleInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
#SelectManagePanel {
|
||||
position: absolute;
|
||||
width: 1000px;
|
||||
|
||||
.bp3-dialog-body {
|
||||
width: 100%;
|
||||
height: 700px;
|
||||
|
||||
.searchMaterial {
|
||||
margin: 2px 0 0 0;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
input {
|
||||
width: 31%;
|
||||
}
|
||||
|
||||
.bp3-html-select{
|
||||
margin-right: 10px;
|
||||
|
||||
select{
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.bp3-icon {
|
||||
right: 2px;
|
||||
top: 7.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.materialParams {
|
||||
display: flex;
|
||||
height: 665px;
|
||||
|
||||
.img-tree {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.img-lib {
|
||||
width: 75%;
|
||||
|
||||
.editor-lint {
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
img {
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
.apply-img-hint:hover:before {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
.hint:hover::before {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
&>:nth-child(1) {
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.fileList {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fileList:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
height : 40px;
|
||||
display : flex;
|
||||
padding : 10px 0;
|
||||
align-items : center;
|
||||
flex-direction : row;
|
||||
justify-content: center;
|
||||
|
||||
.bp3-label {
|
||||
line-height : 1.5rem;
|
||||
margin-bottom: 0.5px;
|
||||
|
||||
span{
|
||||
width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
import { Button, Classes, Icon } from '@blueprintjs/core';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { MaterialUrls, ToplineUrls } from '../../../Common/HostUrl';
|
||||
import { DirectoryId } from '../../../Common/Request';
|
||||
import { HeadCeilingInfoStore } from '../../Store/HeadCeilingStore/HeadCeilingInfoStore';
|
||||
import { HeadCeilingProfileMaterialStore } from '../../Store/HeadCeilingStore/HeadCeilingMaterialStore';
|
||||
import { Display } from '../HeadCeiling/HeadCeilingInfoConfigPanel';
|
||||
import { ModalState } from '../Modal/ModalInterface';
|
||||
import { OnlySelectDataList } from './OnlySelectDataList';
|
||||
import { OnlySelectDataManage } from './OnlySelectManage';
|
||||
import { OnlySelectPanelStore } from './OnlySelectPanelStore';
|
||||
|
||||
interface IDataListProps
|
||||
{
|
||||
directoryId: DirectoryId;
|
||||
setDisplay: (display: Display) => void;
|
||||
dataStore: HeadCeilingInfoStore | HeadCeilingProfileMaterialStore;
|
||||
selectStore: OnlySelectPanelStore;
|
||||
dispaly: Display;
|
||||
return: (status: ModalState) => void;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class OnlySelectManagePanel extends React.Component<IDataListProps, {}>
|
||||
{
|
||||
_Title: string = "";
|
||||
_GetUrl: string = "";
|
||||
|
||||
constructor(prop)
|
||||
{
|
||||
//这边修改标题和数据地址
|
||||
super(prop);
|
||||
switch (this.props.directoryId)
|
||||
{
|
||||
case DirectoryId.ImgDir:
|
||||
break;
|
||||
case DirectoryId.HistoryDit:
|
||||
case DirectoryId.FileDir:
|
||||
break;
|
||||
case DirectoryId.MaterialDir:
|
||||
this._Title = "选择材质";
|
||||
this._GetUrl = MaterialUrls.get;
|
||||
break;
|
||||
case DirectoryId.ToplineDir:
|
||||
case DirectoryId.Frame:
|
||||
case DirectoryId.KnifePathDir:
|
||||
break;
|
||||
case DirectoryId.CeilingContour:
|
||||
this._Title = "选择吊顶轮廓";
|
||||
this._GetUrl = ToplineUrls.get;
|
||||
break;
|
||||
case DirectoryId.DrillingDir:
|
||||
case DirectoryId.TemplateDir:
|
||||
break;
|
||||
default:
|
||||
console.warn("未知目录id");
|
||||
}
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
return (
|
||||
<div id='SelectManagePanel' className={Classes.DIALOG_CONTAINER}>
|
||||
<div className={Classes.DIALOG} tabIndex={1}>
|
||||
<div className={Classes.DIALOG_HEADER} data-id="dragArea">
|
||||
<Icon icon="plus" iconSize={18} />
|
||||
<h4 className={Classes.HEADING}>{this._Title}</h4>
|
||||
<Button
|
||||
icon="cross"
|
||||
aria-label="Close"
|
||||
minimal={true}
|
||||
onClick={() => { this._Return(ModalState.Cancel); }}
|
||||
/>
|
||||
</div>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<OnlySelectDataManage
|
||||
defaultDirId={this.props.directoryId}
|
||||
getUrl={this._GetUrl}
|
||||
handleDbClick={() => { this._Return(ModalState.Ok); }}
|
||||
>
|
||||
<OnlySelectDataList />
|
||||
</OnlySelectDataManage>
|
||||
</div>
|
||||
<div className={Classes.DIALOG_FOOTER} >
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button
|
||||
className={Classes.INTENT_PRIMARY}
|
||||
text="确定"
|
||||
onClick={() => { this._Return(ModalState.Ok); }}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.INTENT_DANGER}
|
||||
text="取消"
|
||||
onClick={() => { this._Return(ModalState.Cancel); }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
//选择完成或者取消
|
||||
_Return = async (status: ModalState) =>
|
||||
{
|
||||
this.props.return(status);
|
||||
this.props.setDisplay(Display.None);
|
||||
};
|
||||
}
|
@ -0,0 +1,563 @@
|
||||
import { Button, Classes, Icon, Intent } from "@blueprintjs/core";
|
||||
import { observer } from "mobx-react";
|
||||
import React, { Component } from "react";
|
||||
import { Matrix4, Vector3 } from "three";
|
||||
import { SelectExtrudeContour, selectOutlinePosition } from "../../../../Add-on/DrawBoard/DrawSpecialShapeBoardTool";
|
||||
import { ViewChange } from "../../../../Add-on/ViewChange";
|
||||
import { app } from "../../../../ApplicationServices/Application";
|
||||
import { MaterialUrls } from "../../../../Common/HostUrl";
|
||||
import { NormalMatrix } from "../../../../Common/Matrix4Utils";
|
||||
import { DirectoryId, PostJson, RequestStatus } from "../../../../Common/Request";
|
||||
import { MaterialIn } from "../../../../Common/SerializeMaterial";
|
||||
import { DuplicateRecordCloning } from "../../../../Common/Status";
|
||||
import { inflateBase64 } from "../../../../Common/inflate";
|
||||
import { CADFiler } from "../../../../DatabaseServices/CADFiler";
|
||||
import { Contour } from "../../../../DatabaseServices/Contour";
|
||||
import { Database } from "../../../../DatabaseServices/Database";
|
||||
import { Curve } from "../../../../DatabaseServices/Entity/Curve";
|
||||
import { Polyline } from "../../../../DatabaseServices/Entity/Polyline";
|
||||
import { ObjectId } from "../../../../DatabaseServices/ObjectId";
|
||||
import { PhysicalMaterialRecord } from "../../../../DatabaseServices/PhysicalMaterialRecord";
|
||||
import { BulkheadCeiling, BulkheadCeiling_ContourType } from "../../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeiling";
|
||||
import { BulkheadCeilingShapeTemplateExtendData } from "../../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeilingShapeExtendData";
|
||||
import { RoomFlatTop } from "../../../../DatabaseServices/Room/Entity/Flat/RoomFlatTop";
|
||||
import { CommandWrap } from "../../../../Editor/CommandMachine";
|
||||
import { JigUtils } from "../../../../Editor/JigUtils";
|
||||
import { SelectBox, SelectType } from "../../../../Editor/SelectBox";
|
||||
import { AsVector2, ZAxisN } from "../../../../Geometry/GeUtils";
|
||||
import { BulkheadCeilingContourData, GetCeilingContourDate, HeadCeilingInfoStore, NONE_CONTOUR_ID } from "../../../Store/HeadCeilingStore/HeadCeilingInfoStore";
|
||||
import { NONE_MATERIAL_ID } from "../../../Store/HeadCeilingStore/HeadCeilingMaterialStore";
|
||||
import { BoardModalType } from "../../Board/BoardModalType";
|
||||
import { LastExtractBoardContour } from "../../Board/LastExtractBoardContour";
|
||||
import { DialogUserConfig } from "../../Board/UserConfigComponent";
|
||||
import { HeadCeilingInfoConfigPanel } from "../../HeadCeiling/HeadCeilingInfoConfigPanel";
|
||||
import { ModalPosition } from "../../Modal/ModalInterface";
|
||||
import { AppToaster } from "../../Toaster";
|
||||
import './ModifyModel.less';
|
||||
|
||||
interface RoomBaseParamsProps
|
||||
{
|
||||
roomFlatTopEnt?: RoomFlatTop;
|
||||
headCeilingEnt?: BulkheadCeiling;
|
||||
}
|
||||
|
||||
interface ContourData
|
||||
{
|
||||
polyline: Polyline;
|
||||
database: Database;
|
||||
extData: BulkheadCeilingShapeTemplateExtendData;
|
||||
}
|
||||
|
||||
@observer
|
||||
export default class RoomFlatTopParams extends Component<RoomBaseParamsProps, {}>
|
||||
{
|
||||
//提取天花板轮廓
|
||||
_PickUpModelingOnFlatTop = async () =>
|
||||
{
|
||||
let roomFlatTop = this.props.roomFlatTopEnt;
|
||||
|
||||
//载入UI配置
|
||||
let store = HeadCeilingInfoStore.GetInstance();
|
||||
let config = new DialogUserConfig(store, BoardModalType.BulkheadCeilingContour);
|
||||
await config.LoadAndInitConfig();
|
||||
|
||||
await CommandWrap(async () =>
|
||||
{
|
||||
app.Editor.SelectCtrl.Cancel();
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.Clear();
|
||||
|
||||
//视角转为俯视图
|
||||
await new ViewChange(ZAxisN, true).exec();
|
||||
app.Viewer.CameraCtrl.ZoomExtentsBox3(roomFlatTop.BoundingBox.expandByScalar(8000));
|
||||
|
||||
//获取天花板轮廓并放置
|
||||
let cu = JigUtils.Draw(roomFlatTop.Contour.Clone().ApplyMatrix(roomFlatTop.OCSNoClone));
|
||||
NormalMatrix(cu.OCSNoClone);
|
||||
LastExtractBoardContour.Contour = cu;
|
||||
cu.Erase(false);
|
||||
let moveCus = [cu];
|
||||
let isOk = await selectOutlinePosition(moveCus);
|
||||
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
if (isOk)
|
||||
{
|
||||
//配置吊顶轮廓编辑时呼出的UI的Items
|
||||
let date: BulkheadCeilingContourData[] = [];
|
||||
date.push({
|
||||
contourType: BulkheadCeiling_ContourType.Land,
|
||||
contourId: NONE_CONTOUR_ID,
|
||||
color: 1
|
||||
});
|
||||
|
||||
await store.InitEditorContourItems(date);
|
||||
cu.ColorIndex = date[0].color;
|
||||
|
||||
app.Editor.ModalManage.RenderModeless(
|
||||
HeadCeilingInfoConfigPanel,
|
||||
{
|
||||
store,
|
||||
isNotUpdateStore: true,
|
||||
directoryId: DirectoryId.CeilingContour,
|
||||
configType: BoardModalType.BulkheadCeilingContour,
|
||||
noClose: true
|
||||
},
|
||||
{ canMinimize: false, position: ModalPosition.RightMid }
|
||||
);
|
||||
app.Editor.MaskManage.Clear();
|
||||
app.Editor.ModalManage.MinAll();
|
||||
}
|
||||
}, "提取天花板轮廓");
|
||||
};
|
||||
|
||||
//应用轮廓生成吊顶
|
||||
_ApplayContour = async () =>
|
||||
{
|
||||
app.Editor.SelectCtrl.Cancel();
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.Clear();
|
||||
|
||||
//视角转为俯视图
|
||||
if (!app.Viewer.CameraCtrl.Direction.equals(new Vector3(0, 0, -1)))
|
||||
await new ViewChange(ZAxisN, false).exec();
|
||||
|
||||
AppToaster.show({
|
||||
message: "请选择该天花板提取出来的外围轮廓!",
|
||||
timeout: 5000,
|
||||
intent: Intent.PRIMARY,
|
||||
}, "ApplayContour");
|
||||
|
||||
await CommandWrap(async () =>
|
||||
{
|
||||
//获取选择的轮廓范围内曲线
|
||||
let { contour, group, useCurves } = await SelectExtrudeContour(true, true, true);
|
||||
AppToaster.dismiss("ApplayContour");
|
||||
|
||||
if (!contour) return;
|
||||
if (!(useCurves[0] as Curve)?.IsClose)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "选择的外围轮廓错误或没有闭合!",
|
||||
timeout: 5000,
|
||||
intent: Intent.DANGER,
|
||||
}, "ApplayContour");
|
||||
return;
|
||||
}
|
||||
let box = contour.BoundingBox.applyMatrix4(app.Viewer.DCS);
|
||||
box.expandByVector(new Vector3(1, 1, 1));
|
||||
let selectBox = new SelectBox(app.Viewer, AsVector2(box.min), AsVector2(box.max), SelectType.C);
|
||||
|
||||
for (let g of group)
|
||||
{
|
||||
for (let curve of g)
|
||||
{
|
||||
if (selectBox.CheckSelectTraverse(curve.GetDrawObjectFromRenderType()))
|
||||
{
|
||||
if (!curve.IsClose)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "内部曲线必须全是闭合多段线!",
|
||||
timeout: 5000,
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let objChace: Map<number, ContourData> = new Map();
|
||||
//载入UI配置
|
||||
let contourStore = HeadCeilingInfoStore.GetInstance();
|
||||
let config = new DialogUserConfig(contourStore, BoardModalType.BulkheadCeilingContour);
|
||||
await config.LoadAndInitConfig();
|
||||
|
||||
let bulkheadCeiling = new BulkheadCeiling();
|
||||
|
||||
let matrix = new Matrix4().setPosition(this.props.roomFlatTopEnt.BoundingBox.min.sub(useCurves[0].BoundingBox.min));
|
||||
matrix.multiply(new Matrix4().setPosition(0, 0, -bulkheadCeiling.Height));
|
||||
useCurves[0].ApplyMatrix(matrix);
|
||||
|
||||
//先根据最外圈曲线绘制吊顶
|
||||
await this._BuildBulkheadCeiling(contourStore, useCurves[0] as Curve, objChace, bulkheadCeiling);
|
||||
|
||||
for (let c of useCurves)
|
||||
c.Erase();
|
||||
|
||||
//再根据内部曲线绘制吊顶
|
||||
for (let g of group)
|
||||
{
|
||||
for (let curve of g)
|
||||
{
|
||||
if (selectBox.CheckSelectTraverse(curve.GetDrawObjectFromRenderType()))
|
||||
{
|
||||
curve.ApplyMatrix(matrix);
|
||||
await this._BuildBulkheadCeiling(contourStore, curve, objChace, bulkheadCeiling);
|
||||
|
||||
curve.Erase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//吊顶绑定天花板
|
||||
bulkheadCeiling.RelativeRoomFlatTop = this.props.roomFlatTopEnt.objectId;
|
||||
app.Database.ModelSpace.Append(bulkheadCeiling);
|
||||
}, "绘制吊顶");
|
||||
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.ModalManage.DestoryAll();
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据曲线颜色、形状 添加吊顶形状、材质
|
||||
*
|
||||
* @param {HeadCeilingInfoStore} contourStore
|
||||
* @param {Curve} curve
|
||||
* @param {Map<number, ContourData>} objChace 吊顶轮廓数据缓存 轮廓ID-ContourData
|
||||
* @param {BulkheadCeiling} bulkheadCeiling
|
||||
* @memberof RoomFlatTopParams
|
||||
*/
|
||||
async _BuildBulkheadCeiling(contourStore: HeadCeilingInfoStore, curve: Curve, objChace: Map<number, ContourData>, bulkheadCeiling: BulkheadCeiling)
|
||||
{
|
||||
let dbData: ContourData = {
|
||||
polyline: undefined,
|
||||
database: undefined,
|
||||
extData: undefined
|
||||
};
|
||||
|
||||
let materials: number[] = [];//服务端的mtl_id
|
||||
let shapeMaterialSlotData: number[] = []; //轮廓顺序对应的材质序列
|
||||
|
||||
let contourShapeId = contourStore.m_Option.Item.find(item => item.color === curve.ColorIndex && item.example.id !== NONE_CONTOUR_ID)?.example.id;
|
||||
//该曲线有使用吊顶截面轮廓
|
||||
if (contourShapeId)
|
||||
{
|
||||
if (!objChace.has(contourShapeId))
|
||||
{
|
||||
//获取截面轮廓信息
|
||||
let db = new Database(false, false, true);
|
||||
let contourData = await GetCeilingContourDate(contourShapeId.toString());
|
||||
if (!contourData) contourShapeId = undefined;
|
||||
else
|
||||
{
|
||||
let json = inflateBase64(contourData.toplines.file);
|
||||
let f = new CADFiler(JSON.parse(json));
|
||||
db.FileRead(f);
|
||||
dbData.polyline = Contour.Combine(db.ModelSpace.Entitys as Curve[], true) as Polyline;
|
||||
if (dbData.polyline.Area2 > 0)
|
||||
dbData.polyline.Reverse();
|
||||
|
||||
let tempF = new CADFiler(db.ExtendedData);
|
||||
let extData = new BulkheadCeilingShapeTemplateExtendData;
|
||||
extData.ReadFile(tempF);
|
||||
|
||||
dbData.database = db;
|
||||
dbData.extData = extData;
|
||||
|
||||
objChace.set(contourShapeId, dbData);
|
||||
}
|
||||
}
|
||||
else
|
||||
dbData = objChace.get(contourShapeId);
|
||||
|
||||
//收集材质id
|
||||
if (dbData.extData)
|
||||
for (let [color, mtlId] of dbData.extData.Color_MaterialId)
|
||||
materials.push(mtlId);
|
||||
|
||||
//材质槽分析
|
||||
if (contourShapeId) // 该轮廓已从 轮廓管理中 被删除 continue
|
||||
{
|
||||
// for (let e of dbData.database.ModelSpace.Entitys)
|
||||
// TestDraw(e.Clone());
|
||||
|
||||
for (let i = 0; i < dbData.polyline.EndParam; i++)
|
||||
{
|
||||
let param = i + 0.5;
|
||||
let p = dbData.polyline.GetPointAtParam(param);
|
||||
|
||||
// let c = new Circle(p, 5);
|
||||
// TestDraw(c, i + 1);
|
||||
|
||||
for (let ent of dbData.database.ModelSpace.Entitys)
|
||||
{
|
||||
if (ent instanceof Curve && ent.PtOnCurve(p))
|
||||
{
|
||||
let color = ent.ColorIndex;
|
||||
let materialId = dbData.extData.Color_MaterialId.get(color);
|
||||
if (materialId)
|
||||
shapeMaterialSlotData.push(materials.findIndex((mtlId) => mtlId === materialId));
|
||||
else
|
||||
shapeMaterialSlotData.push(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//将材质载入到当前图纸
|
||||
let clonedMtls: ObjectId<PhysicalMaterialRecord>[] = [];
|
||||
for (let mtlid of materials)
|
||||
{
|
||||
if (mtlid === NONE_MATERIAL_ID)
|
||||
{
|
||||
clonedMtls.push(undefined);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mtlData = await PostJson(MaterialUrls.detail, { material_id: mtlid }, false);
|
||||
|
||||
if (mtlData.err_code !== RequestStatus.Ok)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "截面轮廓内设置的材质已被删除或丢失,请检查!",
|
||||
timeout: 3000,
|
||||
intent: Intent.DANGER,
|
||||
}, "mtl_err");
|
||||
clonedMtls.push(undefined);
|
||||
continue;
|
||||
}
|
||||
|
||||
let material = MaterialIn(JSON.parse(inflateBase64(mtlData.materials.file)) as Object[]) as PhysicalMaterialRecord;
|
||||
material.Name = mtlData.materials.name;
|
||||
app.Database.WblockCloneObejcts(
|
||||
[material],
|
||||
app.Database.MaterialTable,
|
||||
new Map(),
|
||||
DuplicateRecordCloning.Ignore
|
||||
);
|
||||
clonedMtls.push(app.Database.MaterialTable.GetAt(material.Name).Id);
|
||||
}
|
||||
|
||||
let example = contourStore.m_Option.Item.find((item) => curve.ColorIndex === item.color).example;
|
||||
bulkheadCeiling.ContourData.push({
|
||||
ContourType: example.contourType,
|
||||
Path: curve.Clone(),
|
||||
SweepShapeTempalteId: undefined,
|
||||
Contour: dbData.polyline,
|
||||
ContourId: example.id,
|
||||
Materials: clonedMtls,
|
||||
ShapeMaterialSlotData: shapeMaterialSlotData
|
||||
});
|
||||
}
|
||||
|
||||
//提取吊顶轮廓
|
||||
_PickUpModelingOnHeadCeiling = async () =>
|
||||
{
|
||||
let bulkheadCeiling = this.props.headCeilingEnt;
|
||||
|
||||
//载入UI配置
|
||||
let store = HeadCeilingInfoStore.GetInstance();
|
||||
let config = new DialogUserConfig(store, BoardModalType.BulkheadCeilingContour);
|
||||
await config.LoadAndInitConfig();
|
||||
|
||||
await CommandWrap(async () =>
|
||||
{
|
||||
app.Editor.SelectCtrl.Cancel();
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.Clear();
|
||||
|
||||
//视角使用俯视图
|
||||
await new ViewChange(ZAxisN, true).exec();
|
||||
app.Viewer.CameraCtrl.ZoomExtentsBox3(bulkheadCeiling.BoundingBox.expandByScalar(8000));
|
||||
|
||||
let cu: Polyline;
|
||||
let paths: Curve[] = [];
|
||||
let firstPath = bulkheadCeiling.ContourData[0].Path;
|
||||
|
||||
//获取吊顶轮廓信息
|
||||
for (let data of bulkheadCeiling.ContourData)
|
||||
{
|
||||
let path = JigUtils.Draw(data.Path.Clone().ApplyMatrix(bulkheadCeiling.OCSNoClone));
|
||||
paths.push(path);
|
||||
}
|
||||
|
||||
let roomFlatTop = bulkheadCeiling.RelativeRoomFlatTop.Object as RoomFlatTop;
|
||||
//天花板被拉伸,且面积大于吊顶最大轮廓 补填一个最外围的天花板轮廓
|
||||
if (roomFlatTop.Area > firstPath.Area)
|
||||
{
|
||||
let contuor = roomFlatTop.Contour.Clone();
|
||||
let mtl = new Matrix4().setPosition(roomFlatTop.BoundingBox.min.sub(contuor.BoundingBox.min));
|
||||
mtl.multiply(new Matrix4().setPosition(0, 0, -bulkheadCeiling.Height));
|
||||
cu = JigUtils.Draw(contuor.ApplyMatrix(mtl));
|
||||
paths.push(cu);
|
||||
}
|
||||
|
||||
let isOk = await selectOutlinePosition(paths);
|
||||
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
//根据吊顶轮廓信息配置Store
|
||||
let data: BulkheadCeilingContourData[] = [];
|
||||
for (let contourData of bulkheadCeiling.ContourData)
|
||||
{
|
||||
data.push({
|
||||
contourType: contourData.ContourType,
|
||||
contourId: contourData.ContourId,
|
||||
color: 0
|
||||
});
|
||||
}
|
||||
|
||||
if (cu)
|
||||
{
|
||||
data.push({
|
||||
contourType: BulkheadCeiling_ContourType.Hole,
|
||||
contourId: NONE_CONTOUR_ID,
|
||||
color: 0
|
||||
});
|
||||
}
|
||||
|
||||
await store.InitEditorContourItems(data);
|
||||
|
||||
for (let i = 0; i < paths.length; i++)
|
||||
paths[i].ColorIndex = data[i].color;
|
||||
app.Editor.ModalManage.RenderModeless(
|
||||
HeadCeilingInfoConfigPanel,
|
||||
{
|
||||
store,
|
||||
isNotUpdateStore: true,
|
||||
directoryId: DirectoryId.CeilingContour,
|
||||
configType: BoardModalType.BulkheadCeilingContour,
|
||||
noClose: true
|
||||
},
|
||||
{ canMinimize: false, position: ModalPosition.RightMid }
|
||||
);
|
||||
app.Editor.MaskManage.Clear();
|
||||
app.Editor.ModalManage.MinAll();
|
||||
}
|
||||
}, "提取吊顶轮廓");
|
||||
};
|
||||
|
||||
//已有的吊顶使用新轮廓,重新生成新吊顶
|
||||
_RedoContour = async () =>
|
||||
{
|
||||
app.Editor.SelectCtrl.Cancel();
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.MaskManage.Clear();
|
||||
|
||||
if (!app.Viewer.CameraCtrl.Direction.equals(new Vector3(0, 0, -1)))
|
||||
await new ViewChange(ZAxisN, false).exec();
|
||||
|
||||
AppToaster.show({
|
||||
message: "请选择该吊顶提取出来的外围轮廓!",
|
||||
timeout: 5000,
|
||||
intent: Intent.PRIMARY,
|
||||
}, "RedoContour");
|
||||
|
||||
await CommandWrap(async () =>
|
||||
{
|
||||
//获取应用的轮廓
|
||||
let { contour, group, useCurves } = await SelectExtrudeContour(true, true, true);
|
||||
AppToaster.dismiss("RedoContour");
|
||||
|
||||
if (!contour) return;
|
||||
if (!(useCurves[0] as Curve)?.IsClose)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "选择的外围轮廓错误或没有闭合!",
|
||||
timeout: 5000,
|
||||
intent: Intent.DANGER,
|
||||
}, "ApplayContour");
|
||||
return;
|
||||
}
|
||||
|
||||
let box = contour.BoundingBox.applyMatrix4(app.Viewer.DCS);
|
||||
box.expandByVector(new Vector3(1, 1, 1));
|
||||
let selectBox = new SelectBox(app.Viewer, AsVector2(box.min), AsVector2(box.max), SelectType.C);
|
||||
|
||||
for (let g of group)
|
||||
{
|
||||
for (let curve of g)
|
||||
{
|
||||
if (selectBox.CheckSelectTraverse(curve.GetDrawObjectFromRenderType()))
|
||||
{
|
||||
if (!curve.IsClose)
|
||||
{
|
||||
AppToaster.show({
|
||||
message: "内部曲线必须全是闭合多段线!",
|
||||
timeout: 5000,
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//载入UI配置
|
||||
let contourStore = HeadCeilingInfoStore.GetInstance();
|
||||
let objChace: Map<number, ContourData> = new Map();
|
||||
|
||||
let config = new DialogUserConfig(contourStore, BoardModalType.BulkheadCeilingContour);
|
||||
await config.LoadAndInitConfig();
|
||||
|
||||
let bulkheadCeiling = this.props.headCeilingEnt;
|
||||
let roomFlatTop = bulkheadCeiling.RelativeRoomFlatTop.Object as RoomFlatTop;
|
||||
bulkheadCeiling.ContourData = [];
|
||||
|
||||
let matrix = bulkheadCeiling.OCSInv;
|
||||
matrix.multiply(new Matrix4().setPosition(roomFlatTop.BoundingBox.min.sub(useCurves[0].BoundingBox.min)));
|
||||
matrix.multiply(new Matrix4().setPosition(0, 0, -bulkheadCeiling.Height));
|
||||
useCurves[0].ApplyMatrix(matrix);
|
||||
|
||||
//先根据最外圈曲线绘制吊顶
|
||||
await this._BuildBulkheadCeiling(contourStore, useCurves[0] as Curve, objChace, bulkheadCeiling);
|
||||
|
||||
for (let c of useCurves)
|
||||
c.Erase();
|
||||
//再根据内部曲线绘制吊顶
|
||||
for (let g of group)
|
||||
{
|
||||
for (let curve of g)
|
||||
{
|
||||
if (selectBox.CheckSelectTraverse(curve.GetDrawObjectFromRenderType()))
|
||||
{
|
||||
curve.ApplyMatrix(matrix);
|
||||
await this._BuildBulkheadCeiling(contourStore, curve, objChace, bulkheadCeiling);
|
||||
|
||||
curve.Erase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bulkheadCeiling.Update();
|
||||
}, "重做吊顶");
|
||||
|
||||
app.Editor.ModalManage.ToggleShow();
|
||||
app.Editor.ModalManage.DestoryAll();
|
||||
};
|
||||
|
||||
render()
|
||||
{
|
||||
return (
|
||||
<div id="OperRoomFlatTop" className={Classes.DIALOG_CONTAINER}>
|
||||
<div className={Classes.DIALOG}>
|
||||
<div className={Classes.DIALOG_HEADER} data-id="dragArea">
|
||||
<Icon icon="exchange" iconSize={18} />
|
||||
<h4 className={Classes.HEADING}>吊顶工具</h4>
|
||||
<Button
|
||||
icon="cross"
|
||||
aria-label="Close"
|
||||
minimal={true}
|
||||
onClick={() => { app.Editor.ModalManage.Destory(); }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<Button
|
||||
text="轮廓提取"
|
||||
onClick={this.props.headCeilingEnt ? this._PickUpModelingOnHeadCeiling : this._PickUpModelingOnFlatTop}
|
||||
/>
|
||||
<Button
|
||||
text="轮廓应用"
|
||||
onClick={this.props.headCeilingEnt ? this._RedoContour : this._ApplayContour}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
import { Intent } from "@blueprintjs/core";
|
||||
import { observable } from "mobx";
|
||||
import { ToplineUrls } from "../../../Common/HostUrl";
|
||||
import { IResponseData, PostJson, RequestStatus } from "../../../Common/Request";
|
||||
import { CADFiler } from "../../../DatabaseServices/CADFiler";
|
||||
import { BulkheadCeiling_ContourType } from "../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeiling";
|
||||
import { AppToaster } from "../../Components/Toaster";
|
||||
import { IConfigStore } from "../BoardStore";
|
||||
import { BulkheadCeilingOption } from "../OptionInterface/BulkheadCeilingOption";
|
||||
|
||||
export const NONE_CONTOUR_ID = -1;
|
||||
|
||||
export interface BulkheadCeilingContourData
|
||||
{
|
||||
contourType: BulkheadCeiling_ContourType;
|
||||
contourId: number;
|
||||
color: number;
|
||||
}
|
||||
|
||||
export class HeadCeilingInfoStore implements IConfigStore
|
||||
{
|
||||
@observable configName = "默认";
|
||||
@observable configsNames: string[] = [];
|
||||
@observable m_Option: BulkheadCeilingOption = { Item: [] };
|
||||
|
||||
InitOption()
|
||||
{
|
||||
this.InitModelingItems();
|
||||
}
|
||||
|
||||
InitModelingItems()
|
||||
{
|
||||
this.m_Option.Item = [];
|
||||
for (let i = 0; i < 15; i++)
|
||||
{
|
||||
{
|
||||
this.m_Option.Item.push(
|
||||
{
|
||||
color: i + 1,
|
||||
example: {
|
||||
contourType: BulkheadCeiling_ContourType.Land, //默认是岛
|
||||
id: NONE_CONTOUR_ID,
|
||||
name: "",
|
||||
logo: ""
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置 吊顶轮廓编辑时呼出的UI的Items
|
||||
* 保留原有配置后增加
|
||||
* 初始空材质为NONE_CONTOUR_ID 过程标记0便于归类
|
||||
*/
|
||||
async InitEditorContourItems(extendData: BulkheadCeilingContourData[])
|
||||
{
|
||||
let index = 0;
|
||||
if (extendData.length > 0)
|
||||
for (let data of extendData)
|
||||
{
|
||||
//标记下没有材质的轮廓
|
||||
if (data.contourId === NONE_CONTOUR_ID) data.contourId = 0; //因为 等于NONE_CONTOUR_ID 的话 会被存在轮廓覆盖
|
||||
|
||||
//item中是否包含这个材质
|
||||
let item = this.m_Option.Item.find(e => (
|
||||
e.example.id === data.contourId &&
|
||||
e.example.contourType === data.contourType
|
||||
));
|
||||
|
||||
//有就不添加
|
||||
if (item)
|
||||
{
|
||||
//设置对应表 data[0]是curve的颜色 {视图中curve改成item.color的颜色 调用extendData.Color_MaterialId.get(data[0])}
|
||||
data.color = item.color;
|
||||
continue;
|
||||
}
|
||||
//没有包含这个材质 添加
|
||||
let contourData: IResponseData;
|
||||
|
||||
//不是空材质就获取材质信息
|
||||
if (data.contourId !== 0)
|
||||
contourData = await GetCeilingContourDate(data.contourId.toString());
|
||||
|
||||
//store的15个item 都有材质值了 往后添加第16 17....
|
||||
if (index > this.m_Option.Item.length)
|
||||
{
|
||||
this.m_Option.Item.push(
|
||||
{
|
||||
color: index + 1,
|
||||
example: {
|
||||
contourType: data.contourType,
|
||||
id: data.contourId,
|
||||
name: contourData?.toplines?.name ?? "无",
|
||||
logo: contourData?.toplines?.logo ?? "",
|
||||
}
|
||||
},
|
||||
);
|
||||
data.color = this.m_Option.Item[index].color;
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; index < this.m_Option.Item.length; index++)
|
||||
{
|
||||
let example = this.m_Option.Item[index].example;
|
||||
//没有材质的Item用上
|
||||
if (example.id === NONE_CONTOUR_ID)
|
||||
{
|
||||
example.id = data.contourId;
|
||||
example.contourType = data.contourType;
|
||||
example.name = contourData?.toplines?.name ?? "无";
|
||||
example.logo = contourData?.toplines?.logo ?? "";
|
||||
data.color = this.m_Option.Item[index].color;
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SaveConfig()
|
||||
{
|
||||
return this.WriteFile() as any;
|
||||
};
|
||||
|
||||
UpdateOption(confData: any[] | any)
|
||||
{
|
||||
if (!Array.isArray(confData))
|
||||
confData = confData.CADFilerData as any[];
|
||||
|
||||
let file = new CADFiler(confData);
|
||||
this.ReadFile(file);
|
||||
}
|
||||
|
||||
ReadFile = (file: CADFiler) =>
|
||||
{
|
||||
let ver = file.Read();
|
||||
let count = file.Read();
|
||||
this.m_Option.Item = [];
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
this.m_Option.Item.push(
|
||||
{
|
||||
color: file.Read(),
|
||||
example: {
|
||||
contourType: file.Read(),
|
||||
id: file.Read(),
|
||||
name: file.Read(),
|
||||
logo: file.Read(),
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
WriteFile(file: CADFiler = new CADFiler)
|
||||
{
|
||||
file.Write(1);
|
||||
file.Write(this.m_Option.Item.length);
|
||||
for (let item of this.m_Option.Item)
|
||||
{
|
||||
file.Write(item.color);
|
||||
file.Write(item.example.contourType);
|
||||
file.Write(item.example.id);
|
||||
file.Write(item.example.name);
|
||||
file.Write(item.example.logo);
|
||||
}
|
||||
return file.Data;
|
||||
}
|
||||
|
||||
private static _SingleInstance: HeadCeilingInfoStore;
|
||||
static GetInstance(): HeadCeilingInfoStore
|
||||
{
|
||||
if (this._SingleInstance) return this._SingleInstance;
|
||||
this._SingleInstance = new HeadCeilingInfoStore;
|
||||
return this._SingleInstance;
|
||||
}
|
||||
}
|
||||
|
||||
export async function GetCeilingContourDate(contour_id: string): Promise<IResponseData | undefined>
|
||||
{
|
||||
let data = await PostJson(ToplineUrls.detail, { topline_id: contour_id });
|
||||
|
||||
if (data.err_code === RequestStatus.Ok)
|
||||
return data;
|
||||
|
||||
AppToaster.show({
|
||||
message: "未找到该吊顶截面轮廓,可能已被删除!",
|
||||
timeout: 5000,
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
return undefined;
|
||||
};
|
@ -0,0 +1,189 @@
|
||||
import { observable } from "mobx";
|
||||
import { MaterialUrls } from "../../../Common/HostUrl";
|
||||
import { PostJson, RequestStatus } from "../../../Common/Request";
|
||||
import { MaterialIn } from "../../../Common/SerializeMaterial";
|
||||
import { inflateBase64 } from "../../../Common/inflate";
|
||||
import { CADFiler } from "../../../DatabaseServices/CADFiler";
|
||||
import { PhysicalMaterialRecord } from "../../../DatabaseServices/PhysicalMaterialRecord";
|
||||
import { BulkheadCeilingShapeTemplateExtendData } from "../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeilingShapeExtendData";
|
||||
import { IConfigStore } from "../BoardStore";
|
||||
import { BulkheadCeilingProfileMaterialOption } from "../OptionInterface/BulkheadCeilingOption";
|
||||
|
||||
//空材质ID使用-1
|
||||
export const NONE_MATERIAL_ID = -1;
|
||||
|
||||
export interface ICeilingProfileMaterialItem
|
||||
{
|
||||
readonly color: number;
|
||||
example: {
|
||||
id: number;
|
||||
name: string,
|
||||
type: string,
|
||||
};
|
||||
}
|
||||
|
||||
export class HeadCeilingProfileMaterialStore implements IConfigStore
|
||||
{
|
||||
@observable configName = "默认";
|
||||
@observable configsNames: string[] = [];
|
||||
@observable m_Option: BulkheadCeilingProfileMaterialOption = { Item: [] };
|
||||
|
||||
InitOption()
|
||||
{
|
||||
this.InitModelingItems();
|
||||
}
|
||||
|
||||
InitModelingItems()
|
||||
{
|
||||
this.m_Option.Item = [];
|
||||
for (let i = 0; i < 15; i++)
|
||||
{
|
||||
{
|
||||
this.m_Option.Item.push(
|
||||
{
|
||||
color: i + 1,
|
||||
example: {
|
||||
id: NONE_MATERIAL_ID,
|
||||
name: "",
|
||||
type: "",
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置 吊顶轮廓编辑时呼出的UI的Items
|
||||
* 保留原有配置后增加
|
||||
* 初始空材质为NONE_MATERIAL_ID 过程标记0便于归类
|
||||
*/
|
||||
async InitEditorMaterialItems(extendData: BulkheadCeilingShapeTemplateExtendData)
|
||||
{
|
||||
let index = 0;
|
||||
if (extendData.Color_MaterialId.size)
|
||||
for (let data of extendData.Color_MaterialId)
|
||||
{
|
||||
//标记下空材质的data id
|
||||
if (data[1] === NONE_MATERIAL_ID) data[1] = 0;
|
||||
|
||||
//item中是否包含这个材质
|
||||
let item = this.m_Option.Item.find(e => e.example.id === data[1]);
|
||||
//有就不添加
|
||||
if (item)
|
||||
{
|
||||
//设置对应表 data[0]是curve的颜色 {视图中curve改成item.color的颜色 调用extendData.Color_MaterialId.get(data[0])}
|
||||
extendData.Color_MaterialId.set(data[0], item.color);
|
||||
continue;
|
||||
}
|
||||
//没有包含这个材质 添加
|
||||
let material: PhysicalMaterialRecord;
|
||||
|
||||
//不是空材质就获取材质信息
|
||||
if (data[1] !== 0)
|
||||
{
|
||||
let mtlData = await PostJson(MaterialUrls.detail, { material_id: data[1].toString() });
|
||||
if (mtlData.err_code !== RequestStatus.Ok)
|
||||
{
|
||||
//材质不可用 设置为空材质
|
||||
data[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
material = MaterialIn(JSON.parse(inflateBase64(mtlData.materials.file)) as Object[]) as PhysicalMaterialRecord;
|
||||
material.Name = mtlData.materials.name;
|
||||
}
|
||||
}
|
||||
|
||||
//store的15个item 都有材质值了 往后添加第16 17....
|
||||
if (index > this.m_Option.Item.length)
|
||||
{
|
||||
this.m_Option.Item.push(
|
||||
{
|
||||
color: index + 1,
|
||||
example: {
|
||||
id: data[1],
|
||||
name: material?.Name ?? "无",
|
||||
type: material?.type ?? "无"
|
||||
}
|
||||
},
|
||||
);
|
||||
extendData.Color_MaterialId.set(data[0], this.m_Option.Item[index].color);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; index < this.m_Option.Item.length; index++)
|
||||
{
|
||||
let contour = this.m_Option.Item[index].example;
|
||||
//没有材质的Item用上
|
||||
if (this.m_Option.Item[index].example.id === NONE_MATERIAL_ID)
|
||||
{
|
||||
contour.id = data[1];
|
||||
contour.name = material?.Name ?? "无";
|
||||
contour.type = material?.type ?? "无";
|
||||
|
||||
extendData.Color_MaterialId.set(data[0], this.m_Option.Item[index].color);
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SaveConfig()
|
||||
{
|
||||
return this.WriteFile() as any;
|
||||
};
|
||||
|
||||
UpdateOption(confData: any[] | any)
|
||||
{
|
||||
if (!Array.isArray(confData))
|
||||
confData = confData.CADFilerData as any[];
|
||||
|
||||
let file = new CADFiler(confData);
|
||||
this.ReadFile(file);
|
||||
}
|
||||
|
||||
ReadFile = (file: CADFiler) =>
|
||||
{
|
||||
let ver = file.Read();
|
||||
let count = file.Read();
|
||||
this.m_Option.Item = [];
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
this.m_Option.Item.push(
|
||||
{
|
||||
color: file.Read(),
|
||||
example: {
|
||||
id: file.Read(),
|
||||
name: file.Read(),
|
||||
type: file.Read(),
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
WriteFile(file: CADFiler = new CADFiler)
|
||||
{
|
||||
file.Write(1);
|
||||
file.Write(this.m_Option.Item.length);
|
||||
for (let item of this.m_Option.Item)
|
||||
{
|
||||
file.Write(item.color);
|
||||
file.Write(item.example.id);
|
||||
file.Write(item.example.name);
|
||||
file.Write(item.example.type);
|
||||
}
|
||||
return file.Data;
|
||||
}
|
||||
|
||||
private static _SingleInstance: HeadCeilingProfileMaterialStore;
|
||||
static GetInstance(): HeadCeilingProfileMaterialStore
|
||||
{
|
||||
if (this._SingleInstance) return this._SingleInstance;
|
||||
this._SingleInstance = new HeadCeilingProfileMaterialStore;
|
||||
return this._SingleInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
import { BulkheadCeiling_ContourType } from "../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeiling";
|
||||
import { IBaseOption } from "./IOptionInterface";
|
||||
|
||||
export interface ICeilingProfileMaterialItem
|
||||
{
|
||||
readonly color: number;
|
||||
example: {
|
||||
id: number;
|
||||
name: string,
|
||||
type: string,
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICeilingItem
|
||||
{
|
||||
readonly color: number;
|
||||
example: {
|
||||
contourType: BulkheadCeiling_ContourType;//洞 还是岛
|
||||
id: number; //吊顶轮廓id
|
||||
name: string;
|
||||
logo: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface BulkheadCeilingOption extends IBaseOption
|
||||
{
|
||||
Item: ICeilingItem[];
|
||||
}
|
||||
|
||||
export interface BulkheadCeilingProfileMaterialOption extends IBaseOption
|
||||
{
|
||||
Item: ICeilingProfileMaterialItem[];
|
||||
}
|
Loading…
Reference in new issue