2 # Copyright (c) 2003 Art Haas
4 # This file is part of PythonCAD.
6 # PythonCAD is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # PythonCAD is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with PythonCAD; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 # a class for reading (and hopefully eventually writing) DWG files
23 from __future__
import generators
29 """The class for revision-neutral handling of DWG files.
31 The Dwg class is designed to provide a version-neutral interface
32 for reading DWG files. A Dwg instance has the following methods:
34 getHandle(): Get the opened file handle associated with the instance.
35 {get/set}Version(): Get/Set the version of the underlying DWG file.
36 {get/set}Offset(): Get/Set the offsets to sections with the DWG file.
37 getOffsetKeys(): Retrieve the section names for which offsets are stored.
38 setReader(): Set the function used for reading a particular DWG section.
39 {get/set}Header(): Get/Set a header variable used in the DWG file.
40 getHeaderKeys(): Get all the header variables in the DWG file.
41 {get/set}Class(): Get/Set a class used in the DWG file.
42 getClassKeys(): Get all the classes used in the DWG file.
43 {get/set}Object(): Get/Set an entity stored in the DWG file.
44 {get/set}ImageData(): Get/Set any bitmap image data in the DWG file.
46 Older versions of the DWG format lack image data and header variables,
47 and the presence of image data is optional. Also, the header data
48 variables keys can be different from one release to another.
50 def __init__(self
, filename
):
51 """Initialize a Dwg instance.
55 The one required argument is the path to a DWG file.
58 if sys
.platform
== 'win32':
60 self
.__fp
= file(filename
, _mode
)
62 self
.__offsets
= {} # file offsets
63 self
.__entities
= [] # entity offset data
64 self
.__dxfnames
= {} # class/dxfname map
69 self
.__wmfdata
= None # not before R13
70 self
.__bmpdata
= None # not before R13
79 """Return the opened file handle associated with the DWG file.
86 """Store the version of the DWG file.
95 elif _buf
== 'AC1010': # autocad 10?
97 elif _buf
== 'AC1012':
99 dwg1314
.initialize_dwg(self
)
101 elif _buf
== 'AC1014':
103 dwg1314
.initialize_dwg(self
)
105 elif _buf
== 'AC1015':
107 dwg15
.initialize_dwg(self
)
110 _ver
= None # unknown file - maybe raise an error?
112 self
.__version
= _ver
114 def getVersion(self
):
115 """Return the version of the DWG file in use.
119 if self
.__version
is None:
121 return self
.__version
123 def setOffset(self
, key
, value
):
124 """Store the offset to a section within the DWG file.
126 setOffset(key, value)
128 This method requires two arguments:
130 key: A text string giving the section name.
131 value: A tuple of two objects.
133 Valid keys are one of the following:
134 HEADERS, CLASSES, OBJECTS, IMAGES, UNKNOWN, R14DATA, R15REC5
136 The tuple is of the following format:
140 offset: Offset in the file
141 size: The size of the section; This argument can be 'None'
143 if not isinstance(key
, str):
144 raise TypeError, "Invalid offset key: " + str(key
)
145 if not isinstance(value
, tuple):
146 raise TypeError, "Invalid offset tuple: " + str(value
)
147 if not len(value
) == 2:
148 raise ValueError, "Invalid offset tuple: " + str(value
)
149 if key
in self
.__offsets
:
150 raise ValueError, "Key already set: " + key
151 if (key
== 'HEADERS' or
158 self
.__offsets
[key
] = value
160 raise ValueError, "Unexpected offset key: " + key
162 def getOffsetKeys(self
):
163 """Return the strings giving the sections for which offset data is stored.
167 This method returns the keys used in the setOffset() calls. The ordering
168 of the keys is random. The offset data can be retrieved by calling the
171 return self
.__offsets
.keys()
173 def getOffset(self
, key
):
174 """Return the section data associated with a particular section key.
178 Argument 'key' should be a string returned from getOffsetKeys().
180 return self
.__offsets
[key
]
182 def setReader(self
, key
, value
):
183 """Store a function which reads a section of the DWG file.
185 setReader(key, value)
187 This function has two required arguments:
189 key: A text string giving the reader type
190 value: The function used to read the section of the DWG file.
193 HEADERS, CLASSES, OBJECTS, IMAGES
195 if not isinstance(key
, str):
196 raise TypeError, "Invalid offset key: " + str(key
)
197 if not isinstance(value
, types
.FunctionType
):
198 raise TypeError, "Invalid reader for '%s': %s" % (key
, str(value
))
199 if (key
== 'HEADERS' or
205 self
.__readers
[key
] = value
207 raise ValueError, "Unexpected reader key: " + key
209 def getReader(self
, key
):
210 """Return the function for reading a DWG file section.
214 return self
.__readers
[key
]
216 def setHeader(self
, key
, value
):
217 """Store a header variable found in the DWG file.
219 setHeader(key, value)
221 This method has two arguments:
223 key: The header variable
226 The 'key' must be a string, and the value can be any type of Python
227 object (string, int, double, tuple, etc...)
229 if not isinstance(key
, str):
230 raise TypeError, "Invalid header key: " + str(key
)
231 self
.__headers
[key
] = value
233 def getHeaderKeys(self
):
234 """Return the various header variables found in the DWG file.
238 This method returns a list of strings, with each being one of the
239 header variables found in the DWG file. The data associated with
240 each header can be retrieved with the getHeader() method.
242 if not len(self
.__headers
):
243 if 'HEADERS' in self
.__readers
:
244 _reader
= self
.__readers
['HEADERS']
246 return self
.__headers
.keys()
248 def getHeader(self
, key
):
249 """Return the associated value for a particular header variable.
253 Argument 'key' should be one of the strings returned from getHeaderKeys()
255 return self
.__headers
[key
]
257 def setDxfName(self
, key
, dxfname
):
258 """Store the mapping between the type number and DXF name.
260 setDxfName(key, dxfname)
262 Argument 'key' is an integer, and argument 'dxfname' is a string.
263 This data is found in the class data section in R13, R14, and R15
266 if not isinstance(key
, int):
267 raise TypeError, "Invalid dxfname key: " + str(key
)
268 if not isinstance(dxfname
, str):
269 raise TypeError, "Invalid dxfname: " + str(key
)
270 self
.__dxfnames
[key
] = dxfname
272 def getDxfName(self
, key
):
273 """Return the dxfname for a given class key.
277 Argument 'key' should be an integer. This method returns a
278 string if there is a class for the key value. Otherwise this
282 if not isinstance(key
, int):
283 raise TypeError, "Invalid dxfname key: " + str(key
)
284 return self
.__dxfnames
.get(key
)
286 def setClass(self
, key
, value
):
287 """Store a class variable found in the DWG file.
291 This method has two required arguments:
293 key: An integer value
296 The contents of the tuple are as follows:
297 (appname, cplusplusname, dxfname, zombie, id)
299 The tuple data comes from the R13/R14/R15 spec.
301 if not isinstance(key
, int):
302 raise TypeError, "Non-integer class key: " + str(key
)
303 if not isinstance(value
, tuple):
304 raise TypeError, "Non-tuple class value: " + str(value
)
305 self
.__classes
[key
] = value
307 def getClassKeys(self
):
308 """Return the various classes found in the DWG file.
312 This method returns a list of class values. The data associated
313 for each class can be obtained with getClass().
315 if not len(self
.__classes
):
316 if 'CLASSES' in self
.__readers
:
317 _reader
= self
.__readers
['CLASSES']
319 return self
.__classes
.keys()
321 def getClass(self
, key
):
322 """Return the class data for a given class.
326 This method returns a tuple holding the class data.
328 return self
.__classes
.get(key
)
330 def addEntityOffset(self
, handle
, offset
):
331 """Store handle/offset data for an entity in the DWG file.
333 addEntityOffset(handle, offset)
335 self
.__entities
.append((handle
, offset
))
337 def getEntityOffset(self
):
338 """Return the list of handle/offset data for the DWG file entities.
342 for _entdata
in self
.__entities
:
343 _id
, _offset
= _entdata
346 def setObject(self
, obj
):
347 """Store an entity found within the DWG file.
351 Argument 'obj' must be an dwgEntity instance.
353 if not isinstance(obj
, dwgEntity
):
354 raise TypeError, "Invalid DWG object: " + str(obj
)
355 self
.__objects
.append(obj
)
358 """Return a single object from the DWG file.
362 This method can be called to extract the dwgEntity objects from
363 the DWG file one object at a time. The first call gets the
364 first entity, and each subsequent call retrieves the following
367 if not len(self
.__classes
):
368 if 'CLASSES' in self
.__readers
:
369 _reader
= self
.__readers
['CLASSES']
371 if not len(self
.__entities
):
372 if 'OFFSETS' in self
.__readers
:
373 _reader
= self
.__readers
['OFFSETS']
375 if 'OBJECT' not in self
.__readers
:
377 _reader
= self
.__readers
['OBJECT']
378 for entdata
in self
.__entities
:
379 _id
, _offset
= entdata
380 yield _reader(self
, _offset
)
383 if not len(self
.__classes
):
384 if 'CLASSES' in self
.__readers
:
385 _reader
= self
.__readers
['CLASSES']
387 if not len(self
.__entities
):
388 if 'OFFSETS' in self
.__readers
:
389 _reader
= self
.__readers
['OFFSETS']
392 self
.__len
= len(self
.__entities
)
394 def next_object(self
):
395 if self
.__index
== self
.__len
:
397 _id
, _offset
= self
.__entities
[self
.__index
]
398 _reader
= self
.__readers
['OBJECT']
399 self
.__index
= self
.__index
+ 1
400 return _reader(self
, _offset
)
402 def getEntities(self
):
403 if not len(self
.__classes
):
404 if 'CLASSES' in self
.__readers
:
405 _reader
= self
.__readers
['CLASSES']
407 if not len(self
.__entities
):
408 if 'OFFSETS' in self
.__readers
:
409 _reader
= self
.__readers
['OFFSETS']
411 return self
.__entities
413 def getObjects(self
):
414 """Return all the stored objects found in the DWG file.
418 This method returns a list of dwgEntity objects.
420 if not len(self
.__classes
):
421 if 'CLASSES' in self
.__readers
:
422 _reader
= self
.__readers
['CLASSES']
424 if not len(self
.__entities
):
425 if 'OFFSETS' in self
.__readers
:
426 _reader
= self
.__readers
['OFFSETS']
428 if not len(self
.__objects
):
429 if 'OBJECTS' in self
.__readers
:
430 _reader
= self
.__readers
['OBJECTS']
432 return self
.__objects
[:]
434 def setImageData(self
, imagetype
, data
):
435 """Store the bitmap image data found in the DWG file.
437 setImageData(imagetype, data)
439 This method has two required arguments:
441 imagetype: A string - either 'BMP' or 'WMF'
444 The format in which the data is stored is not checked. The R13/R14/R15
445 readers use array.array instances for this. The image data is not
446 found in R12 and earlier files.
448 if not isinstance(imagetype
, str):
449 raise TypeError, "Invalid image type: " + str(imagetype
)
450 if imagetype
== 'BMP':
451 self
.__bmpdata
= data
452 elif imagetype
== 'WMF':
453 self
.__wmfdata
= data
455 raise ValueError, "Unexpected image type: " + imagetype
457 def getImageData(self
, imagetype
):
458 """Return the image data found in the DWG file.
460 getImageData(imagetype)
462 This method requires a single argument:
464 imagetype: A string - either 'BMP' or 'WMF'.
466 There is no image data in R12 and earlier files, and image data
467 is optional in R13 and later files. If there is no image data
468 this method returns None.
470 if not isinstance(imagetype
, str):
471 raise TypeError, "Invalid image type: " + str(imagetype
)
472 if imagetype
== 'BMP':
473 return self
.__bmpdata
474 elif imagetype
== 'WMF':
475 return self
.__wmfdata
477 raise ValueError, "Unexpected image type: " + imagetype
480 """A generic class for storing information about DWG objects.
482 The dwgEntity class provides a revision neutral means of storing
483 data found within the DWG file for all the drawing entities. Some entities
484 are visible entities like lines, circles, and arcs, and others are
485 non-graphical entities like tables. The dwgEntity class has the
488 {get/set}Type(): Get/Set the entity type.
489 {get/set}Handle(): Get/Set the entity handle (identifier).
490 {get/set}EntityData(): Get/Set some information about a DWG entity.
491 getEntityKeys(): Return the keys used for storing entity data.
493 Each different type of DWG entity will have different keys stored,
494 and the number of keys varies based on the entity and the ability to
495 decode the information found in the DWG file itself.
497 DWG entities in R13, R14, and R15 files have a large number of
498 shared data attributes. The followin method are available for
499 examining this information. Many of the following methods will only
500 be useful when reading the entities from the DWG file itself.
502 {get/set}Version(): Get/Set a DWG version in the entity
503 {get/set}Mode(): Get/Set the entity mode.
504 {get/set}NumReactors(): Get/Set the number of reactors.
505 {get/set}NoLinks(): Get/Set the entity linkage flag.
506 {get/set}IsLayerByLinetype(): ????
507 {get/set}Color(): Get/Set the entity color.
508 {get/set}LinetypeScale(): Get/Set the linetype scale factor.
509 {get/set}LinetypeFlags(): Get/Set the linetype flags.
510 {get/set}PlotstyleFlags(): Get/Set the plotstyle flags.
511 {get/set}Invisibility(): Get/Set the entity invisiblity flags.
512 {get/set}Lineweight(): Get/Set the entity lineweight factor.
513 {get/set}Subentity(): Get/Set the subentity flgas.
514 addReactor(): Add a handle of a reactor object.
515 getReactors(): Get all the reactors associated with an object.
516 {get/set}Xdicobj(): ????
517 {get/set}Layer(): Get/Set the layer where the object is placed.
518 {get/set}Linetype(): Get/Set the entity linetype
519 getPrevious(): Get the previous entity in a entity chain.
520 getNext(): Get the subsequent entity in an entity chain.
521 {get/set}Plotstyle(): Get/Set the plotstyle flags.
523 Some of the methods are particular to R13 and R14 files, and some
524 are particular to R15 files.
527 """Initialize a dwgEntity instance.
531 This method requires no arguments.
533 self
.__cdata
= {} # "common" stuff for all entities
534 self
.__edata
= {} # entity specfic data
536 def getEntityKeys(self
):
537 """Return the keys used to store entity specific data.
541 THis method returns an unsorted list of strings. The value associated
542 with each key can be obtained by calling the getEntityData() method.
544 return self
.__edata
.keys()
546 def setEntityData(self
, key
, value
):
547 """Store entity specfic data in the dwgEntity.
549 setEntityData(key, value)
551 This method requires two arguments:
553 key: A string used to describe the stored data.
554 value: Any Python type.
557 if not isinstance(key
, str):
558 raise TypeError, "Invalid entity data key: " + str(key
)
559 self
.__edata
[key
] = value
561 def getEntityData(self
, key
):
562 """Retrieve the entity data value for a given key.
566 Argument 'key' should be one of the keys returned from getEntityKeys().
568 return self
.__edata
[key
]
570 def setType(self
, objtype
):
571 """Store the type of object in the dwgEntity instance.
575 Argument 'objtype' is an integer value corresponding to the entity
576 type. The OpenDWG specs give this information in more detail.
578 if not isinstance(objtype
, int):
579 raise TypeError, "Invalid object type: " + str(objtype
)
580 self
.__cdata
['TYPE'] = objtype
583 """Return the type of object the dwgEntity represents.
587 This method returns an integer. See the OpenDWG specs for information
588 to match this value to the entity type.
590 return self
.__cdata
.get('TYPE')
592 def setHandle(self
, handle
):
593 """Set the handle (id) that the dwgEntity holds.
597 Argument 'handle' is a tuple containing integer values.
599 if not isinstance(handle
, tuple):
600 raise TypeError, "Invalid handle: " + str(handle
)
601 self
.__cdata
['HANDLE'] = handle
604 """Return the handle (id) of the dwgEntity.
608 This method returns a tuple containing integers.
610 return self
.__cdata
['HANDLE']
612 def setVersion(self
, version
):
613 """Set a version string in the dwgEntity.
617 Argument 'version' must be a string.
619 if not isinstance(version
, str):
620 raise TypeError, "Invalid version string: " + str(version
)
621 self
.__cdata
['VERSION'] = version
623 def getVersion(self
):
624 """Retrieve the version string in the dwgEntity.
628 This method returns a string, or None if the setVersion() method
629 has not been invoked on the instance.
631 return self
.__cdata
.get('VERSION')
633 def setMode(self
, mode
):
634 """Set the mode of the entity.
638 Argument 'mode' must be an integer.
640 if not isinstance(mode
, int):
641 raise TypeError, "Invalid mode: " + str(mode
)
642 self
.__cdata
['MODE'] = mode
645 """Return the mode of the entity.
649 This method returns an integer value.
651 return self
.__cdata
.get('MODE')
653 def setNumReactors(self
, nr
):
654 """Set the number of reactors of an entity.
658 Argument 'nr' must be an integer.
660 if not isinstance(nr
, int):
661 raise TypeError, "Invalind reactor count:" + str(nr
)
662 self
.__cdata
['NUMREACTORS'] = nr
664 def getNumReactors(self
):
665 """Get the number of reactors of an entity.
669 This method returns an integer value.
671 return self
.__cdata
.get('NUMREACTORS', 0)
673 def setNoLinks(self
, flag
):
674 """Set the 'nolinks' flag of an entity.
676 setNoLinks(self, flag)
678 Argument 'flag' can be either True, False, or an integer. If
679 it is an integer, 0 is False, and all other values are True.
681 if isinstance(flag
, int):
691 raise TypeError, "Invalid type for flag: " + str(flag
)
692 self
.__cdata
['NOLINKS'] = _nlflag
694 def getNoLinks(self
):
695 """Return the 'nolinks' flag of an entity.
699 return self
.__cdata
.get('NOLINKS')
701 def setIsLayerByLinetype(self
, flag
):
704 setIsLayerByLinetype(flag)
706 Argument 'flag' can be either True, False, or an integer. If
707 it is an integer, 0 is False, and all other values are True.
709 if isinstance(flag
, int):
719 raise TypeError, "Invalid type for flag: " + str(flag
)
720 self
.__cdata
['ILBT'] = _iflag
722 def getIsLayerByLinetype(self
):
723 """Return the flag value.
725 getIsLayerByLinetype()
727 return self
.__cdata
.get('ILBT')
729 def setColor(self
, color
):
730 """Store the entity color in the dwgEntity object.
734 Argument 'color' is an integer.
736 if not isinstance(color
, int):
737 raise TypeError, "Invalid color: " + str(color
)
738 self
.__cdata
['COLOR'] = color
741 """Return the color of the entity.
745 This method returns an integer giving the entity color.
747 return self
.__cdata
.get('COLOR')
749 def setLinetypeScale(self
, scale
):
750 """Store the linetype scale factor of the DWG object.
752 setLinetypeScale(scale)
754 Argument 'scale' must be a float value.
756 if not isinstance(scale
, float):
757 raise TypeError, "Invalid linetype scale: " + str(scale
)
758 self
.__cdata
['LTSCALE'] = scale
760 def getLinetypeScale(self
):
761 """Return the linetype scale factor for the dwgEntity.
765 This method returns a float value.
767 return self
.__cdata
.get('LTSCALE')
769 def setLinetypeFlags(self
, flags
):
770 """Set the linetype flags.
772 setLinetypeFlags(flags)
774 Argument 'flags' must be an integer.
776 if not isinstance(flags
, int):
777 raise TypeError, "Invalid linetype flags: " + str(flags
)
778 self
.__cdata
['LTFLAGS'] = flags
780 def getLinetypeFlags(self
):
781 """Return the linetype flags.
785 return self
.__cdata
.get('LTFLAGS')
787 def setPlotstyleFlags(self
, flags
):
788 """Set the plotstyle flags.
790 setPlotstyleFlags(flags)
792 Argument 'flags' must be an integer.
794 if not isinstance(flags
, int):
795 raise TypeError, "Invalid plotstyle flags: " + str(flags
)
796 self
.__cdata
['PSFLAGS'] = flags
798 def getPlotstyleFlags(self
):
799 """Get the plotstyle flags.
803 return self
.__cdata
.get('PSFLAGS')
805 def setInvisiblity(self
, flag
):
806 """Set the invisiblity flag.
810 Argument 'flag' can be either True, False, or an integer. If
811 it is an integer, 0 is False, and all other values are True.
813 if isinstance(flag
, int):
823 raise TypeError, "Invalid type for flag: " + str(flag
)
824 self
.__cdata
['INVIS'] = _iflag
826 def getInvisibility(self
):
827 """Get the invisibility flag.
831 return self
.__cdata
.get('INVIS')
833 def setLineweight(self
, weight
):
834 """Set the line weight.
836 setLineweight(weight)
838 Argument 'weight' must be an integer.
840 if not isinstance(weight
, int):
841 raise TypeError, "Invalid lineweight: " + str(weight
)
842 self
.__cdata
['LINEWEIGHT'] = weight
844 def getLineweight(self
):
845 """Get the line weight.
849 return self
.__cdata
.get('LINEWEIGHT')
851 def setSubentity(self
, handle
): # code 3 handles
852 """Set the subentity handle (id).
856 Argument 'handle' must be a tuple
858 if not isinstance(handle
, tuple):
859 raise TypeError, "Invalid handle: " + str(handle
)
860 self
.__cdata
['SUBENTITY'] = handle
862 def getSubentity(self
):
863 """Get the subentity handle.
867 return self
.__cdata
.get('SUBENTITY')
869 def addReactor(self
, handle
): # code 4 handles
870 """Add a reactor to an dwgEntity.
874 Argument 'handle' must be a tuple.
876 if not isinstance(handle
, tuple):
877 raise TypeError, "Invalid handle: " + str(handle
)
878 if 'REACTORS' not in self
.__cdata
:
879 self
.__cdata
['REACTORS'] = []
880 self
.__cdata
['REACTORS'].append(handle
)
882 def getReactors(self
):
883 """Get all the reactors for a dwgEntity.
887 This method returns a list of tuples.
890 if 'REACTORS' in self
.__cdata
:
891 _rlist
.extend(self
.__cdata
['REACTORS'][:])
894 def setXdicobj(self
, handle
): # code 3 handle
895 if not isinstance(handle
, tuple):
896 raise TypeError, "Invalid handle: " + str(handle
)
897 self
.__cdata
['XDICOBJ'] = handle
899 def getXdicobj(self
):
900 return self
.__cdata
.get('XDICOBJ')
902 def setLayer(self
, handle
): # code 5 handle
903 """Store the layer where the entity is held.
907 Argument 'handle' is a tuple containing integers.
909 if not isinstance(handle
, tuple):
910 raise TypeError, "Invalid handle: " + str(handle
)
911 self
.__cdata
['LAYER'] = handle
914 """Return the layer handle to which this entity belongs.
918 This method returns a tuple.
920 return self
.__cdata
.get('LAYER')
922 def setLinetype(self
, handle
): # code 5 handle
923 """Set the linetype handle for a dwgEntity.
927 Argument 'handle' must be a tuple.
929 if not isinstance(handle
, tuple):
930 raise TypeError, "Invalid handle: " + str(handle
)
931 self
.__cdata
['LINETYPE'] = handle
933 def getLinetype(self
):
934 """Get the linetype for a dwgEntity.
938 return self
.__cdata
.get('LINETYPE')
940 def setPrevious(self
, handle
): # code 4 handle
941 """Set the previous entity handle for a dwgEntity.
945 Argument 'handle' must be a tuple.
947 if not isinstance(handle
, tuple):
948 raise TypeError, "Invalid handle: " + str(handle
)
949 self
.__cdata
['PREV'] = handle
951 def getPrevious(self
):
952 """Get the previous entity handle for a dwgEntity.
956 return self
.__cdata
.get('PREV')
958 def setNext(self
, handle
): # code 4 handle
959 """Set the next entity handle for a dwgEntity.
963 Argument 'handle' must be a tuple.
965 if not isinstance(handle
, tuple):
966 raise TypeError, "Invalid handle: " + str(handle
)
967 self
.__cdata
['NEXT'] = handle
970 """Get the next entity handle for a dwgEntity.
974 return self
.__cdata
.get('NEXT')
976 def setPlotstyle(self
, handle
): # code 5 handle
977 """Set the plotstyle handle for an dwgEntity.
981 Argument 'handle' must be a tuple.
983 if not isinstance(handle
, tuple):
984 raise TypeError, "Invalid handle: " + str(handle
)
985 self
.__cdata
['PLOTSTYLE'] = handle
987 def getPlotstyle(self
):
988 """Get the plotstyle handle for a dwgEntity.
992 return self
.__cdata
.get('PLOTSTYLE')