TWaver - 專(zhuān)注UI技術(shù)

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          幾年前就有用戶提出TWaver讀取并轉(zhuǎn)換AutoCAD圖紙的需求了,最近又需要修改并保存AutoCAD圖紙。用戶的需求就是我們的動(dòng)力,目前TWaver終于有了導(dǎo)入導(dǎo)出AutoCAD圖紙的解決方案。



          首先我們先看看AutoCAD的幾種文件格式:
          1. DWG:是原始圖紙格式,包含了圖紙所有的信息,Autodesk公司出于安全考慮沒(méi)有給出詳細(xì)的格式說(shuō)明
          2. DWF:比DWG文件小很多,用于其他用戶瀏覽,添加備注等,不能編輯
          3. DXF:是用于和其他CAD系統(tǒng)交換數(shù)據(jù)的文件格式,分二進(jìn)制和ASCII格式,AutoCAD的幫助里包含了DXF文件的詳細(xì)描述

          雖然Open Design Specification(http://www.opendesign.com)對(duì)DWG文件格式有很詳細(xì)的介紹(http://www.opendesign.com/files/guestdownloads/OpenDesign_Specification_for_.dwg_files.pdf),但是研究其二進(jìn)制格式的復(fù)雜程度可想而知,因此公開(kāi)的ASCII格式的DXF文件格式成為了TWaver與AutoCAD數(shù)據(jù)交換的首選。

          進(jìn)入正題之前,我們先來(lái)了解一下DXF文件的格式,具體規(guī)范在Autodesk的網(wǎng)站有詳細(xì)說(shuō)明(http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=12272454&linkID=10809853, 另外, 這里還有個(gè)中文的http://docs.autodesk.com/ACD/2011/CHS/filesDXF/WSfacf1429558a55de185c428100849a0ab7-5f35.htm):
          1. DXF文件由組碼(Group Code)和值(Value)組成,Group Code和Value都分別占一行,Group Code是整數(shù)(從-5到1071),Value可以是整數(shù)、十六進(jìn)制整數(shù)、布爾值(0或者1)、浮點(diǎn)數(shù)(精度可以達(dá)到16位小數(shù))或者字符串。
          2. Group Code確定了下一行Value的意義,有些Group Code有明確的意義(比如0代表entity類(lèi)型,8代表Layer Name,9代表變量名并只用在HEADER段,62代表顏色),有些Group Code的代表一類(lèi)值(比如10代表一個(gè)點(diǎn)的x值,11代表y值,12代表z值,這個(gè)點(diǎn)可能是一個(gè)Circle的中心點(diǎn),也可能是一個(gè)Line的起始點(diǎn)/結(jié)束點(diǎn)等)。
          3. DXF文件共分為7個(gè)段(Section):
          3.1 HEADER,包含了一系列和圖紙相關(guān)的變量信息,每個(gè)變量由給出變量名稱(chēng)的組碼 9 指定,其后是提供變量值的組。比如AutoCAD版本,坐標(biāo)系的最小、最大值等。
          3.2 CLASSES,包含了在BLOCKS,ENTITIES和OBJECTS段用到的類(lèi)的定義,比如LWPOLYLINE
          3.3 TABLES,包含各種表,比如圖層(Layer)、線條類(lèi)型(LTYPE)等;每個(gè)表可以包含多個(gè)條目
          3.4 BLOCKS,包含構(gòu)成圖形中每個(gè)塊參照的塊定義和圖形圖元,由一系列Entity組成
          3.5 ENTITIES,包含各種圖形對(duì)象,也叫圖元(Entity),比如點(diǎn)(POINT)、線(LINE),圓(CIRCLE),?。ˋRC),多邊形(LWPOLYLINE)等,是我們解析的重點(diǎn)
          3.6 OBJECTS,包括非圖形對(duì)象的數(shù)據(jù),供 AutoLISP 以及 ObjectARX 應(yīng)用程序所使用
          3.7 THUMBNAILIMAGE,包含DXF文件的縮略圖
          4. 每個(gè)Section以Group Code(0)和Value(SECTION)開(kāi)始,以Group Code(0)和Value(ENDSEC)結(jié)束

          下面對(duì)TWaver DXF包做詳細(xì)的解釋?zhuān)?br /> 1 twaver.dxf.common包下的類(lèi)對(duì)所有DXF的數(shù)據(jù)進(jìn)行了封裝(基類(lèi)DXFData)


          1.1 section包下的類(lèi)分別封裝了DXF文件的7個(gè)段,實(shí)現(xiàn)接口DxfSection

          1.2 entities包下的所有類(lèi)對(duì)應(yīng)Entity段的所有圖元,基類(lèi)為DxfEntity

          1.3 objects包對(duì)應(yīng)Objects段下的元素,基類(lèi)為DxfObject
          1.4 tables包對(duì)應(yīng)Tables段下的元素,基類(lèi)為DxfTable

          1.5 DxfBlock類(lèi)對(duì)應(yīng)Blocks段下的元素
          1.6 DxfClass類(lèi)對(duì)應(yīng)Classes段下的元素
          1.7 DxfVariable類(lèi)對(duì)應(yīng)Header段下的一個(gè)變量
          1.8 DxfValue類(lèi)封裝了DXF文件的Value值
          1.9 DxfValuePair類(lèi)封裝了DXF文件的一個(gè)組碼和值對(duì)
          1.10 DxfValuePairCollection類(lèi)包含構(gòu)成一個(gè)Block或Entity等的組碼和值集合
          2 twaver.dxf.element包對(duì)DXF文件的Entity段的每種圖元和TWaver的Element網(wǎng)元進(jìn)行了一一對(duì)應(yīng)

          3 twaver.dxf.parser包是解析DXF文件的核心
          3.1 handle包對(duì)DXF文件的7個(gè)段分別進(jìn)行解析,接口為DxfSectionHandler
          3.2 entities包對(duì)Entity段的每種圖元進(jìn)行細(xì)化解析
          3.3 objects包對(duì)Objects段進(jìn)行細(xì)化解析
          3.4 tables包對(duì)Table段進(jìn)行細(xì)化解析
          4 DxfDocument封裝了DXF文件的7個(gè)段
          5 DxfReader讀取DXF文件,生成DxfDocument
          6 DxfViewer繼承TNetwork類(lèi),將 DxfDocument顯示成TWaver的拓?fù)鋱D,并可以添加、修改和刪除DxfDocument中的元素
          7 DxfWriter將DxfDocument的修改保存為DXF文件

          現(xiàn)在可以正式進(jìn)入DXF文件的解析了,這里只拿一個(gè)簡(jiǎn)單的情況(Circle圖元)舉個(gè)例子,其他圖元的解析大同小異,具體需要研究DXF的參考文檔。下面的圖片是從DXF參考文檔中截取出來(lái)的,其中最主要的是Group Code 10、20、30以及40。Group Code 10、20、30分別代表Circle的中心點(diǎn)的X、Y以及Z坐標(biāo),40代表Circle的半徑。

          這里是從DXF文件中截取的關(guān)于Cricle圖元的片段:

           

           1  0            //組碼0代表一個(gè)Entity的開(kāi)始
           2CIRCLE        //值CIRCLE代表這個(gè)Entity是一個(gè)Cricle
           3  5            //組碼5代表唯一標(biāo)識(shí)這個(gè)Entity的編號(hào),或者叫句柄
           4BC4E        //十六進(jìn)制的Entity的編號(hào)值
           5330            //組碼330代表指向所有者字典的句柄(可省略)
           61F            //十六進(jìn)制的所有者句柄值
           7100            //組碼100代表子類(lèi)標(biāo)記
           8AcDbEntity    //所有Entity的父類(lèi)都是AcDbEntity
           9  8            //組碼8代表圖層
          10圖層1        //圖層的名字
          11370            //組碼370代表線寬,是一個(gè)枚舉值
          12    35
          13100            //組碼100代表子類(lèi)標(biāo)記
          14AcDbCircle    //Circle的類(lèi)名為AcDbCircle
          15 10            //組碼10代表中心點(diǎn)X坐標(biāo)
          16-708.4449011916222
          17 20            //組碼20代表中心點(diǎn)Y坐標(biāo)
          183306.535626846471
          19 30            //組碼30代表中心點(diǎn)Z坐標(biāo)
          200.0
          21 40            //組碼40代表半徑
          2212.4186311615631

           

          TWaver DXF包對(duì)DXF文件的解析進(jìn)行了封裝,只需要?jiǎng)?chuàng)建DxfReader對(duì)象,調(diào)用parse方法,就可以返回DxfDocument對(duì)象,然后調(diào)用DXFViewer的setDxfDocument方法即可顯示DXF文件,setDxfDocument內(nèi)部會(huì)將所有DXF圖元映射成TWaver的網(wǎng)元(接口為DxfElement):

           

           1private void initDatabox(File file, double scale){
           2    DxfReader dxfReader = new DxfReader();
           3    FileInputStream in = null;
           4    try {
           5        in = new FileInputStream(file);
           6        doc = dxfReader.parse(in, new HashMap());
           7    }
           catch (Exception e) {
           8        handleException(e);
           9    }
          finally{
          10        if(in != null){
          11            try {
          12                in.close();
          13            }
           catch (IOException e) {
          14            }

          15        }

          16    }

          17    if(doc == null){
          18        return;
          19    }

          20    this.network.setScale(scale);
          21    this.network.setDxfDocument(doc);
          22}

           

          DXFViewer. setDxfDocument創(chuàng)建TWaver網(wǎng)元的代碼片段如下:

           

           1private void initDataBox(DxfDocument dxfDocument) throws Exception {
           2    if(dxfDocument == null){
           3        return;
           4    }

           5    this.getDataBox().clear();
           6    this.dxfDocument = dxfDocument;
           7    this.context.setOriginX(this.dxfDocument.getHeader().getOriginX());
           8    this.context.setOriginY(-this.dxfDocument.getHeader().getOriginY());
           9
          10    for(DxfEntity entity : this.dxfDocument.getAllEntities()){
          11        entity.transform(context);
          12        if(!entity.getLayer().isVisible()){
          13            continue;
          14        }

          15        if(!entity.isVisibile()){
          16            continue;
          17        }

          18        addDxfElement(entity);
          19    }

          20}

          21
          22private void addDxfElement(DxfEntity entity) throws Exception {
          23    Class< ? extends DxfElement> elementClass = entity.getElementClass();
          24    if (elementClass == null{
          25        System.err.println("Can not handle entity: " + entity.getType());
          26        return;
          27    }

          28
          29    DxfElement element = elementClass.newInstance();
          30    if (entity instanceof DxfEntityInsert) {
          31        DxfEntityInsert insert = (DxfEntityInsert) entity;
          32        this.addDxfInsertItems(insert, (DxfInsert)element);
          33
          34        Point2D point = element.getLocation();
          35        point = context.restore(point, entity.isBlockEntity());
          36        insert.setOffsetX(insert.getValue(10).getDoubleValue() - point.getX());
          37        insert.setOffsetY(insert.getValue(20).getDoubleValue() - point.getY());
          38    }

          39    element.setDxfEntity(entity);
          40    this.getDataBox().addElement(element);
          41}

          42
          43private void addDxfInsertItems(DxfEntityInsert insert, DxfInsert parent) throws Exception {
          44    DxfBlock block = insert.getBlock();
          45    if (block != null{
          46        for (DxfEntity itemEntity : block.getEntities()) {
          47            if (!itemEntity.getLayer().isVisible()) {
          48                continue;
          49            }

          50            if (!itemEntity.isVisibile()) {
          51                continue;
          52            }

          53
          54            Class< ? extends DxfElement> itemElementClass = itemEntity.getElementClass();
          55            if (itemElementClass == null{
          56                System.err.println("Can not handle entity in block: " + itemEntity.getType());
          57                return;
          58            }

          59
          60            DxfElement itemElement = itemElementClass.newInstance();
          61            itemElement.setDxfEntity(itemEntity);
          62            itemElement.putRenderColor(DxfUtils.getColor(insert.getLayer().getColor()));
          63            parent.addChild(itemElement);
          64            this.getDataBox().addElement(itemElement);
          65        }

          66    }

          67}

          在DxfViewer中修改網(wǎng)元后,需要將修改結(jié)果從DxfElement中保存到DxfEntity中,代碼片段如下:

           1private void handleDxfElementPropertyChange(PropertyChangeEvent evt) {
           2    if(this.zooming || this.initializing){
           3        return;
           4    }

           5
           6    DxfElement element = (DxfElement)evt.getSource();
           7    if(element.getDxfEntity().isBlockEntity()){
           8        return;
           9    }

          10    String propertyName = TWaverUtil.getPropertyName(evt);
          11    if(TWaverConst.PROPERTYNAME_LOCATION.equals(propertyName)
          12            || TWaverConst.PROPERTYNAME_WIDTH.equals(propertyName)
          13            || TWaverConst.PROPERTYNAME_HEIGHT.equals(propertyName)
          14            || TWaverConst.PROPERTYNAME_SHAPELINKPOINTS.equals(propertyName)
          15            || TWaverConst.PROPERTYNAME_NAME.equals(propertyName)){
          16        element.saveDxfEntity(this.context);
          17    }

          18}

           

          最后解釋一下如何創(chuàng)建DXF圖元,下面是從Demo中DxfButton.java類(lèi)中截取的代碼片段,也拿圖元Cricle做例子:


           1protected void preProcess(ResizableNode node){
           2 DxfCircle circle = (DxfCircle)node;
           3
           4 DxfEntityCircle circleEntity = new DxfEntityCircle();
           5 circleEntity.setDocument(dxfViewer.getDxfDocument());
           6 circleEntity.setBlockEntity(false);
           7
           8 circleEntity.setID(dxfViewer.getDxfDocument().getHeader().getNextID());
           9 Point2D point = dxfViewer.getTransformContext().restore(circle.getCenterLocation(), circleEntity.isBlockEntity());
          10 circleEntity.getCenterPoint().setX(point.getX());
          11 circleEntity.getCenterPoint().setY(point.getY());
          12 circleEntity.setLayer(dxfViewer.getDxfDocument().getRootLayer());
          13 circleEntity.setRadius(dxfViewer.getTransformContext().restoreWidth(circle.getWidth()/2));
          14
          15 circleEntity.put(DxfConsts.GROUPCODE_HANDLE, DxfUtils.toHexString(circleEntity.getID()));
          16 circleEntity.put(DxfConsts.GROUPCODE_SUBCLASS_MARKER, "AcDbEntity");
          17 circleEntity.put(DxfConsts.GROUPCODE_LAYER_NAME, circleEntity.getLayer().getName());
          18 circleEntity.put(DxfConsts.GROUPCODE_SUBCLASS_MARKER, "AcDbCircle");
          19 circleEntity.put(DxfConsts.GROUPCODE_START_X, DxfUtils.toString(circleEntity.getCenterPoint().getX()));
          20 circleEntity.put(DxfConsts.GROUPCODE_START_Y, DxfUtils.toString(circleEntity.getCenterPoint().getY()));
          21 circleEntity.put(DxfConsts.GROUPCODE_START_Z, "0");
          22 circleEntity.put(DxfConsts.GROUPCODE_CIRCLE_RADIUS, DxfUtils.toString(circleEntity.getRadius()));
          23
          24 dxfViewer.getDxfDocument().addEntity(circleEntity);
          25 circleEntity.transform(dxfViewer.getTransformContext());
          26
          27 circle.setDxfEntity(circleEntity);
          28}

           

          這里再解釋一下TransformContext類(lèi):主要目的是將AutoCAD的坐標(biāo)系映射成Java的坐標(biāo)系,里面的transform和restore方法在縮放和保存時(shí)使用

          注意點(diǎn):
          1 絕對(duì)值小于1E-3或者大于1E7的非零double數(shù)據(jù)轉(zhuǎn)化成String時(shí),JDK默認(rèn)會(huì)用科學(xué)計(jì)數(shù)法表示,具體可以參考JDK文檔,所以需要用DecimalFormat特殊處理一把,參考DxfUtils.toString(double value)
          2 MText的text字段包含了一些格式信息,可以通過(guò)DxfUtils.stripMText(String text)過(guò)濾
          3 HEADER段的$HANDSEED變量代表下一個(gè)可用的句柄,可以用這個(gè)變量的值作為新加的Entity的句柄值,然后這個(gè)變量的值要加1
          4 AutoCAD的坐標(biāo)原點(diǎn)在左下,Java的坐標(biāo)原點(diǎn)在左上,通過(guò)TransformContext進(jìn)行轉(zhuǎn)換
          5 AutoCAD的縮放模式只縮放位置和寬高,線條粗細(xì)不會(huì)縮放,但TWaver的縮放模式跟放大鏡是一樣的效果,所以DxfViewer做了特殊處理,通過(guò)鼠標(biāo)滾輪實(shí)現(xiàn)和AutoCAD一樣的縮放

          目前已有功能:
          1 導(dǎo)入AutoCAD DXF文件并在Network中展示,目前能處理包含在ENTITY和BLOCK段的ARC、CIRCLE、HATCH、INSERT、LINE、LWPOLYLINE、MTEXT、POLYLINE以及TEXT等entity。
          2 能修改TEXT的文字,LINE的起始和結(jié)束點(diǎn)的位置,LWPOLYLINE和POLYLINE的頂點(diǎn)位置,CIRCLE的半徑和位置等并保存。
          3 能添加刪除已支持的Entity,并保存。
          4 鼠標(biāo)滾輪能實(shí)現(xiàn)和AutoCAD一樣的縮放效果
          5 對(duì)于不能顯示的Entity不會(huì)做任何修改,保存時(shí)也不會(huì)遺漏。

          后續(xù)待開(kāi)發(fā)的功能:
          1 支持更多Entity,比如標(biāo)注(DIMENSION)等
          2 支持創(chuàng)建全新的DXF文件,實(shí)現(xiàn)將TWaver的拓?fù)鋱D保存為AutoCAD的DXF圖紙



          評(píng)論

          # 我們需要TWaver導(dǎo)入導(dǎo)出AutoCAD DXF圖紙功能請(qǐng)問(wèn)哪里有下載開(kāi)發(fā)包?  回復(fù)  更多評(píng)論   

          2016-04-13 13:06 by 曾曉南
          我們的項(xiàng)目需要TWaver導(dǎo)入導(dǎo)出AutoCAD DXF圖紙功能請(qǐng)問(wèn)哪里有下載開(kāi)發(fā)包?
          我的郵箱是:1391211019@qq.com

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 阿克陶县| 禹城市| 托里县| 景德镇市| 贡觉县| 开封县| 华蓥市| 应用必备| 江陵县| 陵水| 迁西县| 呼玛县| 濉溪县| 锡林浩特市| 昆明市| 钟山县| 陕西省| 陆川县| 寿宁县| 福清市| 河津市| 保山市| 万安县| 罗城| 京山县| 额尔古纳市| 铜山县| 白玉县| 集贤县| 阳东县| 龙江县| 桂东县| 泽普县| 射阳县| 龙门县| 易门县| 勐海县| 房产| 尚义县| 怀仁县| 山西省|