File: linetype.py

package info (click to toggle)
pythoncad 0.1.35-4
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 3,536 kB
  • ctags: 4,286
  • sloc: python: 62,752; sh: 743; makefile: 39
file content (253 lines) | stat: -rw-r--r-- 7,765 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#
# Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas
#
# This file is part of PythonCAD.
# 
# PythonCAD is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# PythonCAD is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with PythonCAD; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# linetype class
#

import types
from sys import maxint

from PythonCAD.Generic import globals

class Linetype(object):
    """A class representing linetypes.

This class provides the basis for solid and dashed lines.
Dashed lines are more 'interesting' in the various ways
the dashes can be drawn.

A Linetype object has two attributes:

name: A string describing this linetype
dlist: A list of integers used for drawing dashed lines

A solid line has a dlist attribute of None.

A Linetype object has the following methods:

getName(): Return the Linetype name
getList(): Return the Linetype dashlist
clone(): Make a copy of a Linetype object.
    """
    def __init__(self, name, dashlist=None):
        """Initstantiate a Linetype object.

Linetype(name, dashlist)

The name should be a string representing what this linetype
is called. The dashlist can be None (solid lines) or a list of
integers which will be used to determine the on/off bits
of a dashed line. The list must have at least two integers.
        """
        _n = name
        if not isinstance(_n, types.StringTypes):
            raise TypeError, "Invalid Linetype name: " + `_n`
        if not isinstance(_n, unicode):
            _n = unicode(name)
        _l = dashlist
        if _l is not None:
            if not isinstance(_l, list):
                raise TypeError, "Second argument must be a list or None."
            _length = len(_l)
            if _length < 2:
                raise ValueError, "Dash list must hold at least two integers."
            _temp = []
            for _i in range(_length):
                _item = _l[_i]
                if not isinstance(_item, int):
                    _item = int(_l[_i])
                if _item < 0:
                    raise ValueError, "Invalid list value: %d" % _item
                _temp.append(_item)
            _l = _temp
        self.__name = _n
        if _l is None:
            self.__list = None
        else:
            self.__list = _l[:]

    def __str__(self):
        if self.__list is None:
            return "Solid Line: '%s'" % self.__name
        else:
            _str = "Dashed Line: '%s': " % self.__name
            return _str + `self.__list`
        
    def __eq__(self, obj):
        """Compare one Linetype to another for equality.

The comparison examines the dash list - if both lists
are None, or the same length and with identical values,
the function returns True. Otherwise the function returns
False.
        """
        if not isinstance(obj, Linetype):
            return False
        if obj is self:
            return True
        _slist = self.__list
        _olist = obj.getList()
        return ((_slist is None and _olist is None) or
                ((type(_slist) == type(_olist)) and (_slist == _olist)))

    def __ne__(self, obj):
        """Compare one Linetype to another for non-equality.

The comparison examines the dash list - if both lists
are None, or the same length and with identical values,
the function returns False. Otherwise the function returns
True.
        """
        return not self == obj

    def __hash__(self):
        """Provide a hash function for Linetypes.

Defining this method allows Linetype objects to be stored
as dictionary keys.
        """
        _dashlist = self.__list
        _val = 0 # hash value for solid lines
        if _dashlist is not None:
            _val = hash_dashlist(_dashlist)
        return _val
    
    def getName(self):
        """Get the name of the Linetype.

getName()        
        """
        return self.__name

    name = property(getName, None, None, "Linetype name.")

    def getList(self):
        """Get the list used for determining the dashed line pattern.

getList()
This function returns None for solid Linetypes.
        """
        _list = None
        if self.__list is not None:
            _list = self.__list[:]
        return _list

    list = property(getList, None, None, "Linetype dash list.")

    def clone(self):
        """Make a copy of a Linetype

clone()        
        """
        _name = self.__name[:]
        _dashlist = None
        if self.__list is not None:
            _dashlist = self.__list[:]
        return Linetype(_name, _dashlist)

#
# LinetypeDict Class
#
# The LinetypeDict is built from the dict object. Using instances
# of this class will guarantee than only Linetype objects will be
# stored in the instance
#

class LinetypeDict(dict):
    def __init__(self):
        super(LinetypeDict, self).__init__()
        
    def __setitem__(self, key, value):
        if not isinstance(key, Linetype):
            raise TypeError, "LinetypeDict keys must be Linetype objects: " + `key`
        if not isinstance(value, Linetype):
            raise TypeError, "LinetypeDict values must be Linetype objects: " + `value`
        super(LinetypeDict, self).__setitem__(key, value)

#
# the hash function for linetype dashlists
#

def hash_dashlist(dashlist):
    """The hashing function for linetype dashlists

hash_dashlist(dashlist)

Argument 'dashlist' should be a list containing two or
more integer values.
    """
    if not isinstance(dashlist, list):
        raise TypeError, "Invalid list: " + `dashlist`
    if len(dashlist) < 2:
        raise ValueError, "Invalid list length: " + str(dashlist)
    _dlist = []
    for _obj in dashlist:
        if not isinstance(_obj, int):
            raise TypeError, "Invalid list item: " + `_obj`
        if _obj < 0:
            raise ValueError, "Invalid list value: %d" % _obj
        _dlist.append(_obj)
    _val = (0xffffff & _dlist[0]) << 6
    for _i in _dlist:
        _val =  c_mul(160073, _val) ^ ((_i << 5) | _i) # made this up
    _val = _val ^ len(_dlist)
    if _val == -1:
        _val = -2
    return _val

#
# mulitplication used for hashing
#
# an eval-based routine came from http://effbot.org/zone/python-hash.htm,
# but the move to Python 2.3 printed warnings when executing that code
# due to changes in large hex values, so the code was re-written to
# avoid the eval-loop and hackish long->str->int conversions ...
#

def c_mul(a, b):
    _lval = (long(a * b) & 0xffffffffL) - maxint
    return int(_lval)

#
# find an existing linetype in the global linetype dictionary
#

def get_linetype_by_dashes(dashlist):
    if dashlist is None:
        _key = 0
    elif isinstance(dashlist, list):
        _key = hash_dashlist(dashlist)
    else:
        raise TypeError, "Invalid dashlist: " + `dashlist`
    for _k in globals.linetypes.keys():
        if hash(_k) == _key:
            return _k
    raise ValueError, "No matching linetype found: " + str(dashlist)
        
def get_linetype_by_name(name):
    if not isinstance(name, types.StringTypes):
        raise TypeError, "Invalid linetype name: " + str(name)
    _name = name
    if not isinstance(_name, unicode):
        _name = unicode(name)
    for _lt in globals.linetypes:
        if _lt.getName() == _name:
            return _lt
    return None