怎么做一幅画墙

2023年3月10日18:06:53怎么做一幅画墙已关闭评论

首页

画户型

tips:圆圈代表成员变量,方框代表成员函数

实体墙体的表达

实体墙体的表达主要有基础数据的表达和视图可视化元素的表达。

1.数据层:

entity文件夹中新建Wall类,继承自Entity。承载2d/3d视图的公共数据,即2d/3d视图墙体绘制的基础数据。

Wall类结构

完整的类实现:

/*
* @Description: file content
* @Version: 1.0
* @Author: Catknight
* @Date: 2020-10-20 16:57:12
* @LastEditors: Catknight
* @LastEditTime: 2020-10-21 14:16:38
* @FilePath: /newdrawhome/src/CORE/display/entity/wall.js
*/import{ Entity } from./entity;import{WallShapeType} from../../commdata/drawWallTypeimport{EntityTypes} from../../commdata/entitytypesclassWallextendsEntity{constructor() {super();this.type=EntityTypes.Wall;this._wallShapetype=WallShapeType.XXQ;this._startPoint=null;this._endPoint=null;this._thickness=180;this._height=3000;this._centerPoint=null;//弧形墙的圆心this._linkRooms=[];//关联的房间this._linkDoors=[];//墙上的门this._linkWindows=[];//墙上的窗户this._preWalls=[];//相连的墙(CCW)this._nextWalls=[];//相连的墙(CCW)}setheight(data){this._height=data;
}getheight(){returnthis._height;
}setthickness(data){this._thickness=data;
}getthickness(){returnthis._thickness;
}setstartPoint(data){this._startPoint=data;
}getstartPoint(){returnthis._startPoint;
}setendPoint(data){this._endPoint=data;
}getendPoint(){returnthis._endPoint;
}setcenterPoint(data){this._centerPoint=data;
}getcenterPoint(){returnthis._centerPoint;
}
addLinkRoom(roomid){if(roomid)this._linkRooms.push(roomid);
}
removeLinkRoom(roomid){if(roomid)this._linkRooms.splice(this._linkRooms.findIndex(roomid),1);
}
addLinkDoor(doorid){if(doorid)this._linkDoors.push(doorid);
}
removeLinkDoor(doorid){if(doorid)this._linkDoors.splice(this._linkDoors.findIndex(doorid),1);
}
addLinkWindow(winid){if(winid)this._linkWindows.push(winid);
}
removeLinkWindow(winid){if(winid)this._linkWindows.splice(this._linkDoors.findIndex(winid),1);
}

addPreWall(wallid){if(wallid)this._preWalls.push(wallid);
}
removePreWall(wallid){if(wallid)this._preWalls.splice(this._preWalls.findIndex(wallid),1);
}
addNextWall(wallid){if(wallid)this._nextWalls.push(wallid);
}
removeNextWall(wallid){if(wallid)this._nextWalls.splice(this._nextWalls.findIndex(wallid),1);
}

}
export { Wall }

2.视图层:

在2d/3d的文件夹下,新建object目录,用于保存可视化元素,如room,wall等等。以2d视图为例,在2d/object目录下新建wall2d.js文件,文件中新建Wall2D类,继承自ViewElement类。

Wall2D类的结构

完整的类实现:

/*
* @Description: Wall2D
* @Version: 1.0
* @Author: LiangHui
* @Date: 2020-10-20 16:56:26
* @LastEditors: LiangHui
* @LastEditTime: 2020-10-21 14:43:42
* @FilePath: /newdrawhome/src/CORE/display/2d/object/wall2d.js
*/import{ ViewElement }from../../viewElementimport{WallGeoCreator}from../geometry/creatorclassWall2DextendsViewElement{constructor(scene,context,entity) {super(scene,context,entity);this.startPoint=entity.startPoint;this.endPoint=entity.endPoint;this.centerPoint=entity.centerPoint;this.wallShapeType=entity.wallShapeType;

}
_onCreateSceneNode(){

}

}export{ Wall2D }

墙体部分的数据表达到这儿就结束了,但是我们的系统如何记录下这些墙体数据呢?这里我们要引入‘设计’这个概念。既然是家装设计平台,那么我们就要能加载保存我们所做的设计,一个设计通常要记录设计名称,作者(用户),设计中设计了哪些东西如房间、墙、家具等等实体。当我们打开设计平台,登陆账户后,第一眼通常是这个账户下所有的设计,然后点击其中任意一个设计进入到设计界面进行场景的加载。如果是新账户,一定有个类似‘新建设计’的按钮,点击后会进入空白场景。

实体墙体的存储

1.设计数据的存储:Design类

接下来我们创建设计类,我们给它命名为design。在display的根目录下创建design.js文件。创建Design类,Design里至少要有设计id、名称、用户信息或者其他一些你认为有必要加到设计中的信息。目前为止我们只创建了墙体,所以我们在设计里要有个容器来存储这个设计里有多少个墙,我们把这个容器命名为wallSet,是个Map类型的容器,key为墙体的id,value为墙体数据,这样我们在查找墙体时能够快速找到。为了能获取到系统里墙体的添加删除等事件,我们需要将Design类接入事件系统,很简单,引入EventManager和Events,在Events中添加WALLADDED和WALLREMOVED事件名称。在Design类中添加相应的事件响应函数如addWall、removeWall。为了能统一管理监听事件,我们在connectEventSystem函数里放置监听函数,并在Design类的构造函数里执行,这样就能在Design初始化的时候执行监听函数。具体类结构如下:

Design类的结构

完整的类实现:

/*
* @Description: 工程
* @Version: 1.0
* @Author: Catknight
* @Date: 2020-10-21 16:15:31
* @LastEditors: Catknight
* @LastEditTime: 2020-10-21 17:59:31
* @FilePath: /newdrawhome/src/CORE/display/design.js
*/import{ Wall } from./entity/wallimport{ EventManager } from../manager/eventsManagerimport{ Events } from../commdata/eventsimport*asUUID fromuuidclassDesign{constructor(name) {this.id = UUID.v4();this.userinfo = {};this.name = name ? name :"未命名";this.wallSet = new Map();this.roomSet = new Map();this.connectEventSystem();
}
connectEventSystem() {
EventManager.instance().listen(Events.WALLADDED,this.addWall.bind(this),this);
EventManager.instance().listen(Events.WALLREMOVED,this.removeWall.bind(this),this);
}
disConnenctEventSystem() {
EventManager.instance().unlisten(Events.WALLADDED,this.addWall,this);
EventManager.instance().unlisten(Events.WALLREMOVED,this.removeWall,this);
}
addWall(wall) {if(wall)this.wallSet.set(wall.id, wall);
}
removeWall(wall) {if(wall)this.wallSet.delete(wall.id);
}
}
export { Design };

2.设计管理器:DesignManager

Design类实现完毕后,需要将其加入到系统中,但Design仅仅是一个数据存储的表达,系统里会有多个设计,例如我关闭当前的设计,打开了另一个设计,这些就需要一个管理器了。我们将其命名为DesignManager,在CORE/manager文件夹下创建designManager.js 文件,建立design的容器和当前design两个成员变量,建立创建设计和打开、关闭设计函数。完整类实现如下:

/*
* @Description: file content
* @Version: 1.0
* @Author: Catknight
* @Date: 2020-10-21 16:23:56
* @LastEditors: Catknight
* @LastEditTime: 2020-10-21 16:43:33
* @FilePath: /newdrawhome/src/CORE/manager/designManager.js
*/import{ Design }from../display/design;classDesignManager{constructor() {this.designs =newMap();this.currentDesign =null;
}
creatDesign(name) {letdesign =newDesign(name);this.designs.set(design.id, design);this.currentDesign = design;
}
openDesign(id){letdesign=this.designs.get(id);this.currentDesign = design;//TODO}
saveDesign(){//TODO}

}export{ DesignManager }

3.接入Application

在Apllication中添加DesignManager模块并在Application构造函数中新建DesignManager对象,这样设计就接入了了我们的系统中并且可以运转了。

this._designManager=new DesignManager();

整个管理流程是:Application->DesignManager->Design。

至此,实体墙体的存储就可以了,接下来是重头-绘制!

实体墙体的绘制

第一步:修改上一节中的创建墙体action即CreatWallAction类。添加creatWallEntity函数,用于绘制实体墙体。导入实体墙Wall类,在函数里新建一个实体墙体,填充实体墙的数据如起始点等等。将实体墙加入到对应View的实体元素容器中,让其能在view中显示。另外要发送WALLADDED事件,通知Design存入当前绘制的墙体。为了能够连续绘制墙体,我们将最后一次点击的位置记录下来,作为下一次墙体绘制命令的墙体的起点,重新启动绘制墙体命令这样就能连续绘制墙体了,直到遇到墙体闭合的情况或者右键取消墙体绘制。

creatWallEntity(p) {
let wall = new Wall();
wall.startPoint =this._start;
wall.endPoint = p;
wall.thickness =this.thickness;this._viewer._addEntity(wall);//存入viewEventManager.instance().send(Events.WALLADDED, wall);//存入designactionManager.currentCommand.setLastData(p);//设置上一次绘制墙体的终点actionManager.cancelAndResumeCurrentCommand();
}

第二步:在CreatWallAction鼠标左键事件响应函数里,加入上面的creatWallEntity

lMouseDown(view, e) {
let p =this._getPoint(e);if(!this._start &&this._isFristTime) {this._start = p;this._isFristTime =false;return;
}this.creatWallEntity(p);
}

第三步:由于我们绘制墙体是一个全局的概念,一个房间可能有多个墙,不能在单个墙的数据上绘制,因为会影响其他墙体的状态,所以需要在更高一个层级进行全局墙体绘制,这样才能正确的绘制整个空间的墙体。我们需要在Design中添加一个全局的绘制的工具类。

懵懂先生