几年前就有用户提出TWaver读取并转换AutoCAD图纸的需求了,最近又需要修改并保存AutoCAD图纸。用户的需求就是我们的动力,目前TWaver终于有了导入导出AutoCAD图纸的解决方案。
首先我们先看看AutoCAD的几种文件格式:
1. DWG:是原始图纸格式,包含了图纸所有的信息,Autodesk公司出于安全考虑没有给出详细的格式说明
2. DWF:比DWG文件小很多,用于其他用户浏览,添加备注等,不能编辑
3. DXF:是用于和其他CAD系统交换数据的文件格式,分二进制和ASCII格式,AutoCAD的帮助里包含了DXF文件的详细描述
虽然Open Design Specification(http://www.opendesign.com)对DWG文件格式有很详细的介绍(http://www.opendesign.com/files/guestdownloads/OpenDesign_Specification_for_.dwg_files.pdf),但是研究其二进制格式的复杂程度可想而知,因此公开的ASCII格式的DXF文件格式成为了TWaver与AutoCAD数据交换的首选。
进入正题之前,我们先来了解一下DXF文件的格式,具体规范在Autodesk的网站有详细说明(http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=12272454&linkID=10809853, 另外, 这里还有个中文的http://docs.autodesk.com/ACD/2011/CHS/filesDXF/WSfacf1429558a55de185c428100849a0ab7-5f35.htm):
1. DXF文件由组码(Group Code)和值(Value)组成,Group Code和Value都分别占一行,Group Code是整数(从-5到1071),Value可以是整数、十六进制整数、布尔值(0或者1)、浮点数(精度可以达到16位小数)或者字符串。
2. Group Code确定了下一行Value的意义,有些Group Code有明确的意义(比如0代表entity类型,8代表Layer Name,9代表变量名并只用在HEADER段,62代表颜色),有些Group Code的代表一类值(比如10代表一个点的x值,11代表y值,12代表z值,这个点可能是一个Circle的中心点,也可能是一个Line的起始点/结束点等)。
3. DXF文件共分为7个段(Section):
3.1 HEADER,包含了一系列和图纸相关的变量信息,每个变量由给出变量名称的组码 9 指定,其后是提供变量值的组。比如AutoCAD版本,坐标系的最小、最大值等。
3.2 CLASSES,包含了在BLOCKS,ENTITIES和OBJECTS段用到的类的定义,比如LWPOLYLINE
3.3 TABLES,包含各种表,比如图层(Layer)、线条类型(LTYPE)等;每个表可以包含多个条目
3.4 BLOCKS,包含构成图形中每个块参照的块定义和图形图元,由一系列Entity组成
3.5 ENTITIES,包含各种图形对象,也叫图元(Entity),比如点(POINT)、线(LINE),圆(CIRCLE),弧(ARC),多边形(LWPOLYLINE)等,是我们解析的重点
3.6 OBJECTS,包括非图形对象的数据,供 AutoLISP 以及 ObjectARX 应用程序所使用
3.7 THUMBNAILIMAGE,包含DXF文件的缩略图
4. 每个Section以Group Code(0)和Value(SECTION)开始,以Group Code(0)和Value(ENDSEC)结束
下面对TWaver DXF包做详细的解释:
1 twaver.dxf.common包下的类对所有DXF的数据进行了封装(基类DXFData)
1.1 section包下的类分别封装了DXF文件的7个段,实现接口DxfSection
1.2 entities包下的所有类对应Entity段的所有图元,基类为DxfEntity
1.3 objects包对应Objects段下的元素,基类为DxfObject
1.4 tables包对应Tables段下的元素,基类为DxfTable
1.5 DxfBlock类对应Blocks段下的元素
1.6 DxfClass类对应Classes段下的元素
1.7 DxfVariable类对应Header段下的一个变量
1.8 DxfValue类封装了DXF文件的Value值
1.9 DxfValuePair类封装了DXF文件的一个组码和值对
1.10 DxfValuePairCollection类包含构成一个Block或Entity等的组码和值集合
2 twaver.dxf.element包对DXF文件的Entity段的每种图元和TWaver的Element网元进行了一一对应
3 twaver.dxf.parser包是解析DXF文件的核心
3.1 handle包对DXF文件的7个段分别进行解析,接口为DxfSectionHandler
3.2 entities包对Entity段的每种图元进行细化解析
3.3 objects包对Objects段进行细化解析
3.4 tables包对Table段进行细化解析
4 DxfDocument封装了DXF文件的7个段
5 DxfReader读取DXF文件,生成DxfDocument
6 DxfViewer继承TNetwork类,将 DxfDocument显示成TWaver的拓扑图,并可以添加、修改和删除DxfDocument中的元素
7 DxfWriter将DxfDocument的修改保存为DXF文件
现在可以正式进入DXF文件的解析了,这里只拿一个简单的情况(Circle图元)举个例子,其他图元的解析大同小异,具体需要研究DXF的参考文档。下面的图片是从DXF参考文档中截取出来的,其中最主要的是Group Code 10、20、30以及40。Group Code 10、20、30分别代表Circle的中心点的X、Y以及Z坐标,40代表Circle的半径。
这里是从DXF文件中截取的关于Cricle图元的片段:
0 //组码0代表一个Entity的开始
CIRCLE //值CIRCLE代表这个Entity是一个Cricle
5 //组码5代表唯一标识这个Entity的编号,或者叫句柄
BC4E //十六进制的Entity的编号值
330 //组码330代表指向所有者字典的句柄(可省略)
1F //十六进制的所有者句柄值
100 //组码100代表子类标记
AcDbEntity //所有Entity的父类都是AcDbEntity
8 //组码8代表图层
图层1 //图层的名字
370 //组码370代表线宽,是一个枚举值
35
100 //组码100代表子类标记
AcDbCircle //Circle的类名为AcDbCircle
10 //组码10代表中心点X坐标
-708.4449011916222
20 //组码20代表中心点Y坐标
3306.535626846471
30 //组码30代表中心点Z坐标
0.0
40 //组码40代表半径
12.4186311615631
TWaver DXF包对DXF文件的解析进行了封装,只需要创建DxfReader对象,调用parse方法,就可以返回DxfDocument对象,然后调用DXFViewer的setDxfDocument方法即可显示DXF文件,setDxfDocument内部会将所有DXF图元映射成TWaver的网元(接口为DxfElement):
private void initDatabox(File file, double scale){
DxfReader dxfReader = new DxfReader();
FileInputStream in = null;
try {
in = new FileInputStream(file);
doc = dxfReader.parse(in, new HashMap());
} catch (Exception e) {
handleException(e);
}finally{
if(in != null){
try {
in.close();
} catch (IOException e) {
}
}
}
if(doc == null){
return;
}
this.network.setScale(scale);
this.network.setDxfDocument(doc);
}
DXFViewer. setDxfDocument创建TWaver网元的代码片段如下:
private void initDataBox(DxfDocument dxfDocument) throws Exception {
if(dxfDocument == null){
return;
}
this.getDataBox().clear();
this.dxfDocument = dxfDocument;
this.context.setOriginX(this.dxfDocument.getHeader().getOriginX());
this.context.setOriginY(-this.dxfDocument.getHeader().getOriginY());
for(DxfEntity entity : this.dxfDocument.getAllEntities()){
entity.transform(context);
if(!entity.getLayer().isVisible()){
continue;
}
if(!entity.isVisibile()){
continue;
}
addDxfElement(entity);
}
}
private void addDxfElement(DxfEntity entity) throws Exception {
Class< ? extends DxfElement> elementClass = entity.getElementClass();
if (elementClass == null) {
System.err.println("Can not handle entity: " + entity.getType());
return;
}
DxfElement element = elementClass.newInstance();
if (entity instanceof DxfEntityInsert) {
DxfEntityInsert insert = (DxfEntityInsert) entity;
this.addDxfInsertItems(insert, (DxfInsert)element);
Point2D point = element.getLocation();
point = context.restore(point, entity.isBlockEntity());
insert.setOffsetX(insert.getValue(10).getDoubleValue() - point.getX());
insert.setOffsetY(insert.getValue(20).getDoubleValue() - point.getY());
}
element.setDxfEntity(entity);
this.getDataBox().addElement(element);
}
private void addDxfInsertItems(DxfEntityInsert insert, DxfInsert parent) throws Exception {
DxfBlock block = insert.getBlock();
if (block != null) {
for (DxfEntity itemEntity : block.getEntities()) {
if (!itemEntity.getLayer().isVisible()) {
continue;
}
if (!itemEntity.isVisibile()) {
continue;
}
Class< ? extends DxfElement> itemElementClass = itemEntity.getElementClass();
if (itemElementClass == null) {
System.err.println("Can not handle entity in block: " + itemEntity.getType());
return;
}
DxfElement itemElement = itemElementClass.newInstance();
itemElement.setDxfEntity(itemEntity);
itemElement.putRenderColor(DxfUtils.getColor(insert.getLayer().getColor()));
parent.addChild(itemElement);
this.getDataBox().addElement(itemElement);
}
}
}
在DxfViewer中修改网元后,需要将修改结果从DxfElement中保存到DxfEntity中,代码片段如下:
private void handleDxfElementPropertyChange(PropertyChangeEvent evt) {
if(this.zooming || this.initializing){
return;
}
DxfElement element = (DxfElement)evt.getSource();
if(element.getDxfEntity().isBlockEntity()){
return;
}
String propertyName = TWaverUtil.getPropertyName(evt);
if(TWaverConst.PROPERTYNAME_LOCATION.equals(propertyName)
|| TWaverConst.PROPERTYNAME_WIDTH.equals(propertyName)
|| TWaverConst.PROPERTYNAME_HEIGHT.equals(propertyName)
|| TWaverConst.PROPERTYNAME_SHAPELINKPOINTS.equals(propertyName)
|| TWaverConst.PROPERTYNAME_NAME.equals(propertyName)){
element.saveDxfEntity(this.context);
}
}
最后解释一下如何创建DXF图元,下面是从Demo中DxfButton.java类中截取的代码片段,也拿图元Cricle做例子:
protected void preProcess(ResizableNode node){
DxfCircle circle = (DxfCircle)node;
DxfEntityCircle circleEntity = new DxfEntityCircle();
circleEntity.setDocument(dxfViewer.getDxfDocument());
circleEntity.setBlockEntity(false);
circleEntity.setID(dxfViewer.getDxfDocument().getHeader().getNextID());
Point2D point = dxfViewer.getTransformContext().restore(circle.getCenterLocation(), circleEntity.isBlockEntity());
circleEntity.getCenterPoint().setX(point.getX());
circleEntity.getCenterPoint().setY(point.getY());
circleEntity.setLayer(dxfViewer.getDxfDocument().getRootLayer());
circleEntity.setRadius(dxfViewer.getTransformContext().restoreWidth(circle.getWidth()/2));
circleEntity.put(DxfConsts.GROUPCODE_HANDLE, DxfUtils.toHexString(circleEntity.getID()));
circleEntity.put(DxfConsts.GROUPCODE_SUBCLASS_MARKER, "AcDbEntity");
circleEntity.put(DxfConsts.GROUPCODE_LAYER_NAME, circleEntity.getLayer().getName());
circleEntity.put(DxfConsts.GROUPCODE_SUBCLASS_MARKER, "AcDbCircle");
circleEntity.put(DxfConsts.GROUPCODE_START_X, DxfUtils.toString(circleEntity.getCenterPoint().getX()));
circleEntity.put(DxfConsts.GROUPCODE_START_Y, DxfUtils.toString(circleEntity.getCenterPoint().getY()));
circleEntity.put(DxfConsts.GROUPCODE_START_Z, "0");
circleEntity.put(DxfConsts.GROUPCODE_CIRCLE_RADIUS, DxfUtils.toString(circleEntity.getRadius()));
dxfViewer.getDxfDocument().addEntity(circleEntity);
circleEntity.transform(dxfViewer.getTransformContext());
circle.setDxfEntity(circleEntity);
}
这里再解释一下TransformContext类:主要目的是将AutoCAD的坐标系映射成Java的坐标系,里面的transform和restore方法在缩放和保存时使用
注意点:
1 绝对值小于1E-3或者大于1E7的非零double数据转化成String时,JDK默认会用科学计数法表示,具体可以参考JDK文档,所以需要用DecimalFormat特殊处理一把,参考DxfUtils.toString(double value)
2 MText的text字段包含了一些格式信息,可以通过DxfUtils.stripMText(String text)过滤
3 HEADER段的$HANDSEED变量代表下一个可用的句柄,可以用这个变量的值作为新加的Entity的句柄值,然后这个变量的值要加1
4 AutoCAD的坐标原点在左下,Java的坐标原点在左上,通过TransformContext进行转换
5 AutoCAD的缩放模式只缩放位置和宽高,线条粗细不会缩放,但TWaver的缩放模式跟放大镜是一样的效果,所以DxfViewer做了特殊处理,通过鼠标滚轮实现和AutoCAD一样的缩放
目前已有功能:
1 导入AutoCAD DXF文件并在Network中展示,目前能处理包含在ENTITY和BLOCK段的ARC、CIRCLE、HATCH、INSERT、LINE、LWPOLYLINE、MTEXT、POLYLINE以及TEXT等entity。
2 能修改TEXT的文字,LINE的起始和结束点的位置,LWPOLYLINE和POLYLINE的顶点位置,CIRCLE的半径和位置等并保存。
3 能添加删除已支持的Entity,并保存。
4 鼠标滚轮能实现和AutoCAD一样的缩放效果
5 对于不能显示的Entity不会做任何修改,保存时也不会遗漏。
后续待开发的功能:
1 支持更多Entity,比如标注(DIMENSION)等
2 支持创建全新的DXF文件,实现将TWaver的拓扑图保存为AutoCAD的DXF图纸
分享到:
相关推荐
java操作cad画图,想通过dxf文件生成通风网络拓扑图, 第一个问题是dxf文件的读取, 基于java的平台中寻入dxf文件的关键技巧 TWaver导入导出AutoCAD DXF图纸中提到了方法,但是效果不好,
“twaver.js使用示例”这一标题表明了我们即将探讨的是一个关于twaver.js的实践应用案例。Twaver.js是一款强大的图形化建模和可视化库,主要用于创建复杂的网络拓扑图、流程图、组织结构图等。这个标题暗示我们将...
"TWaver的3d图形组件库,小demo" 提示我们这是一个基于TWaver库的3D图形展示实例。TWaver是一个专业级的图表和数据可视化工具,它提供了HTML5版本的3D图形组件,允许开发者在Web应用中创建交互式的三维图形。 ...
Twaver是一个强大的数据可视化和网络建模工具,广泛应用于网络拓扑、流程图、组织结构等场景。5.9.0是该库的一个特定版本,可能包含了新功能、性能优化或错误修复。 描述简单明了,"twaver-html5-5.9.0-api"直接...
此外,TWaver Flex还预定义了丰富的业务对象,如告警(`twaver.IAlarm`)和告警容器(`twaver.AlarmBox`),图层(`twaver.ILayer`)和图层管理容器(`twaver.LayerBox`),以及拓扑网元(`twaver.IElement`)和拓扑...
【标题】"TWaver-java-4.1最新 官网试用版jar包及Demo" 涉及的核心知识点是TWaver,一个基于Java的图形可视化库,主要用于数据的图表展示和交互。这个版本是4.1,是官方提供的试用版,包含jar包和演示示例。 【描述...
Twaver学习案例的例子
TWaver是一个强大的可视化框架,其核心特性是支持复杂的图形和网络图表的绘制,尤其适合在Web上创建交互式的机房、网络设备、服务器架构等展示。 一、TWaver概述 TWaver是一个高效且灵活的JavaScript库,专门用于...
【标题】"TWaver-java-4.1" 是一个针对Java平台的TWaver最新开发包,旨在帮助开发者创建更加生动且具有吸引力的用户界面。TWaver是一个强大的数据可视化工具,它提供了丰富的图表类型和交互功能,让数据展示更加直观...
这个框架支持多种数据源,包括JSON、XML、CSV等,使得数据导入和渲染变得简单。此外,它提供了丰富的图形元素库,如设备、线缆、标签等,能够快速构建出逼真的3D机房环境。在“3D机房Demo”中,我们可以看到TWaver...
2. **库文件**:包含Twaver库的SWC文件,这是Flex项目的编译依赖,通过导入这些库,开发者可以在自己的项目中使用Twaver的功能。 3. **资源文件**:可能包括图片、字体、样式表等,用于演示如何定制图形的外观和感觉...
### Twaver 3.7性能测试报告分析 #### 概述 Twaver是一款由Serva Software开发的强大软件工具,主要用于支持复杂网络环境中的数据管理和处理。本次报告主要针对Twaver Java版本(Twaver Java)在不同节点配置及连接...
【标题】"Twaver Web实例源码"是一个关于使用Twaver与ExtJS结合的Web应用程序开发的学习资源。Twaver是一款强大的图形化建模和可视化工具,常用于数据可视化、网络拓扑图、流程图等场景。ExtJS则是一个流行的...
根据给定的文件信息,我们可以总结出以下有关TWaver的关键知识点: ### TWaver概述 - **TWaver**是由赛瓦软件开发的一款图形界面组件解决方案,主要用于数据的图形化展示,尤其是在电信行业拥有广泛的应用。 - **...
**标题:“twaver-java-3.7”** **描述:“twaver-java-3.7 文档”** **标签:“twaver java 3.7”** 本文将深入探讨Twaver Java 3.7版本的相关知识,这是一个强大的数据可视化库,特别适用于Java开发人员。...
【描述】提到"支持各种常见类型的图形",意味着twaver具备绘制不同形状和符号的能力,包括但不限于节点、链路、多边形、圆形、矩形、线段等。这些图形可以代表服务器、路由器、交换机、传感器等硬件设备,也可以代表...
TWaver-flex的库TWaver.swc
TWaver HTML5 Developer Guide是关于TWaver HTML5组件套件的官方开发文档,由Serva Software发布。TWaver HTML5是一套基于HTML5的图形组件库,它提供了一整套用于构建网络拓扑图、树形结构、表格和图表等功能丰富的...
### TWaver for Flex 开发手册知识点总结 #### 一、TWaver for Flex 概述 TWaver for Flex 是一款由 Serva Software 开发的高级图形组件库,它为 Flex 应用程序提供了一系列丰富的图形控件和服务。这些控件允许...