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属性,代码看起来非常优雅:
其实如果您JavaScript用多了,就会觉得Java、Flex等太重太不灵活了。后端Node.js+前端AngularJS是新项目的最佳选择。
下面分5步实现了2D变3D的功能:
1. 弹出打开Dxf文件对话框:
1 | function 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); |
10 | reader.readAsText(file); |
2. 加载Dxf文件:
1 | var parser = new dxf.Dxf(); |
3 | function loadDxfFile (text) { |
3. 计算最大高度,将CAD坐标转换成MONO坐标:
3 | function 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; |
18 | function translatePoint (point) { |
19 | return { x: point.x + 20, y: -point.y + maxHeight + 20 }; |
4. 加载墙:
4 | parser.sections.entities.forEach( function (entity) { |
5 | if (entity.attrib.layer === 'wall' ) { |
6 | var wall = new ImageShapeNode(); |
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 })); |
18 | wall.setPoints(points); |
19 | wall.setClient( 'shapenode.closed' , entity.flags === 1); |
20 | network.getElementBox().add(wall); |
22 | var floor = new FloorShapeNode(); |
23 | floor.setClient( 'hostNodeId' , wall.getId()); |
24 | floor.setPoints(points); |
25 | network.getElementBox().add(floor); |
5. 加载窗户和门:
1 | function 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); |
10 | index = item.getPointIndex(p2); |
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' ) { |
29 | node.setClient( "picture" , "images/window03.png" ); |
30 | node.setClient( 'positionY' , 100); |
31 | } else if (entity.attrib.layer === 'door' ) { |
33 | node.setClient( "picture" , "images/door02_3d.png" ); |
34 | node.setClient( 'positionY' , 0); |
36 | node.setClient( 'edgeIndex' , index); |
38 | node.setClient( 'offset' , offset); |
39 | network.getElementBox().add(node); |
虽然本文只实现了房间里墙、窗户和门的导入,但稍微扩展一下就能实现其他对象的导入,比如机柜、空调等等。还在等什么,赶紧申请试用MONO DESIGN吧,而且马上就能使用MONO DESIGN的在线平台了。