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
|