TWaver - 专注UI技术

http://twaver.servasoft.com/
posts - 171, comments - 191, trackbacks - 0, articles - 2
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

将2D的CAD图纸变成3D的MONO场景

Posted on 2014-07-04 10:36 TWaver 阅读(5974) 评论(2)  编辑  收藏

随着使用MONO的用户越来越多,大家对快速搭建3D场景的需求也越来越强烈了。虽然MONO DESIGN一分钟创建房间,但最快速的还是直接将现有的2D图纸转换成MONO的3D场景。甚至有客户说如果有这个功能,马上就签合同。现场打单的同事不禁偷偷乐了一把,MONO正好有了这个功能,看来这家客户是跑不掉了。

几年前TWaver Java就可以导入CAD图纸了,随着TWaver HTML5的流行,如今终于有了HTML5版本的导入CAD图纸功能。有了这个基础,再将2D的CAD图纸变成3D的MONO场景就变得非常轻松了。

先上张效果图:

是不是觉得有点像变魔术,下面我们就来揭秘一下这个魔术。

如果您对CAD图纸的格式不太熟悉,可以参考这篇blog:TWaver导入导出AutoCAD DXF图纸。虽然是Java版本的,但HTML5上机制也是类似的,只是语言换成了JavaScript,而且JavaScript实现起来更加灵活。

比如以前Java要一堆switch判断Entity类型、处理Group Code,而JavaScript上直接将Entity类型对应到相应的处理函数上、Group Code对应成Entity属性,代码看起来非常优雅:

1var handler = {
2  CIRCLE: handleCircle,
3  //...
4};
5var groupCodes = {
6  CIRCLE: {
7    40: 'radius',
8    //...
9  },
10  //...
11};

其实如果您JavaScript用多了,就会觉得Java、Flex等太重太不灵活了。后端Node.js+前端AngularJS是新项目的最佳选择。

下面分5步实现了2D变3D的功能:
1. 弹出打开Dxf文件对话框:

1function openDxfFile () {
2  var fileSelector = document.createElement('input');
3  fileSelector.setAttribute('type''file');
4  fileSelector.onchange = function (e) {
5    var file = fileSelector.files[0];
6    var reader = new FileReader();
7    reader.onload = function (e) {
8      loadDxfFile(e.target.result);
9    };
10    reader.readAsText(file);
11  };
12  fileSelector.click();
13}

2. 加载Dxf文件:

1var parser = new dxf.Dxf();
2 
3function loadDxfFile (text) {
4  parser.parse(text);
5  getMaxHeight();
6  loadWall();
7  loadWindowAndDoor();
8}

3. 计算最大高度,将CAD坐标转换成MONO坐标:

1var maxHeight = 0;
2 
3function getMaxHeight() {
4  parser.sections.entities.forEach(function (entity) {
5    if (entity.attrib.layer === 'wall') {
6      if (entity instanceof dxf.LineData) {
7        maxHeight = entity.y1 > maxHeight ? entity.y1 : maxHeight;
8        maxHeight = entity.y2 > maxHeight ? entity.y2 : maxHeight;
9      else if (entity instanceof dxf.PolylineData) {
10        entity.points.forEach(function (vertex) {
11          maxHeight = vertex.y > maxHeight ? vertex.y : maxHeight;
12        });
13      }
14    }
15  });
16}
17 
18function translatePoint (point) {
19  return { x: point.x + 20, y: -point.y + maxHeight + 20 };
20}

4. 加载墙:

1var walls = [];
2 
3function loadWall() {
4  parser.sections.entities.forEach(function (entity) {
5    if (entity.attrib.layer === 'wall') {
6      var wall = new ImageShapeNode();
7      walls.push(wall);
8      wall.setClient('oid', wall.getId());
9      var points = new twaver.List();
10      if (entity instanceof dxf.LineData) {
11        points.add(translatePoint({ x: entity.x1, y: entity.y1 }));
12        points.add(translatePoint({ x: entity.x2, y: entity.y2 }));
13      else if (entity instanceof dxf.PolylineData) {
14        entity.points.forEach(function (vertex) {
15        points.add(translatePoint({ x: vertex.x, y: vertex.y }));
16        });
17      }
18      wall.setPoints(points);
19      wall.setClient('shapenode.closed', entity.flags === 1);
20      network.getElementBox().add(wall);
21       
22      var floor = new FloorShapeNode();
23      floor.setClient('hostNodeId', wall.getId());
24      floor.setPoints(points);
25      network.getElementBox().add(floor);
26    }
27  });
28}

5. 加载窗户和门:

1function loadWindowAndDoor() {
2  parser.sections.entities.forEach(function (entity) {
3    if (entity instanceof dxf.LineData && (entity.attrib.layer === 'window'|| entity.attrib.layer === 'door')) {
4      var node, index, offset, wall;
5      var p1 = translatePoint({ x: entity.x1, y: entity.y1 });
6      var p2 = translatePoint({ x: entity.x2, y: entity.y2 });
7      walls.some(function (item) {
8        index = item.getPointIndex(p1);
9        if (index < 0) {
10          index = item.getPointIndex(p2);
11        }
12        if (index >= 0) {
13          wall = item;
14        }
15        return wall == null;
16      });
17      if (wall == null) {
18        return;
19      }
20      var point = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };
21      var points = wall.getPoints();
22      var from = points.get(index);
23      var to = points.get(index == points.size() - 1 ? 0 : index + 1);
24      var dx = to.x - from.x;
25      var dy = to.y - from.y;
26      offset = Math.abs(dx) > Math.abs(dy) ? (point.x - from.x) / dx : (point.y - from.y) / dy;
27      if (entity.attrib.layer === 'window') {
28        node = new Window();
29        node.setClient("picture","images/window03.png");
30        node.setClient('positionY', 100);
31      else if (entity.attrib.layer === 'door') {
32        node = new Door();
33        node.setClient("picture","images/door02_3d.png");
34        node.setClient('positionY', 0);
35      }
36      node.setClient('edgeIndex', index);
37      node.setParent(wall);
38      node.setClient('offset', offset);
39      network.getElementBox().add(node);
40    }
41  });
42}

虽然本文只实现了房间里墙、窗户和门的导入,但稍微扩展一下就能实现其他对象的导入,比如机柜、空调等等。还在等什么,赶紧申请试用MONO DESIGN吧,而且马上就能使用MONO DESIGN的在线平台了。


评论

# re: 将2D的CAD图纸变成3D的MONO场景  回复  更多评论   

2014-07-05 09:30 by 微观互联网
学习了

# re: 将2D的CAD图纸变成3D的MONO场景  回复  更多评论   

2014-07-09 14:56 by wangyue
学习了!

只有注册用户登录后才能发表评论。


网站导航: