forked from sympy/sympy
/
entity.py
152 lines (129 loc) · 4.55 KB
/
entity.py
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
# How entities are ordered; used by __cmp__ in GeometryEntity
ordering_of_classes = [
"Point",
"Segment",
"Ray",
"Line",
"Triangle",
"RegularPolygon",
"Polygon",
"Circle",
"Ellipse"
]
class GeometryEntity(tuple):
"""The base class for any geometrical entity."""
def __new__(cls, *args, **kwargs):
return tuple.__new__(cls, args)
@staticmethod
def do_intersection(e1, e2):
"""
Determines the intersection between two geometrical entities. Returns
a list of all of the intersections.
"""
try:
return e1.intersection(e2)
except Exception:
pass
try:
return e2.intersection(e1)
except NotImplementedError:
n1,n2 = type(e1).__name__, type(e2).__name__
raise NotImplementedError("Unable to determine intersection between '%s' and '%s'" % (n1, n2))
def is_similar(self, other):
"""
Return True if self and other are similar. Two entities are similar
if a uniform scaling (enlarging or shrinking) of one of the entities
will allow one to obtain the other.
Notes:
======
- This method is not intended to be used directly but rather
through the are_similar() method found in util.py.
- An entity is not required to implement this method.
- If two different types of entities can be similar, it is only
required that one of them be able to determine this.
"""
raise NotImplementedError()
def intersection(self, o):
"""
Returns a list of all of the intersections of this entity and another
entity.
Notes:
======
- This method is not intended to be used directly but rather
through the intersection() method found in util.py.
- An entity is not required to implement this method.
- If two different types of entities can intersect, it is only
required that one of them be able to determine this.
"""
raise NotImplementedError()
@staticmethod
def extract_entities(args, remove_duplicates=True):
"""
Takes a set of arguments and extracts all of the GeometryEntity
instances (recursively). Returns a tuple of all of the instances
found.
Notes:
======
- Duplicates of entities are removed if the remove_duplicates
argument is set to True, otherwise duplicates remain.
The default is True.
- Anything that is not a GeometryEntity instance is simply
ignored.
- Ordering of arguments is always maintained. If duplicates
are removed then the entry with the lowest index is kept.
"""
ret = list()
for arg in args:
if isinstance(arg, GeometryEntity):
ret.append(arg)
elif isinstance(arg, (list, tuple, set)):
ret.extend(GeometryEntity.extract_entities(arg))
if remove_duplicates:
temp = set(ret)
ind, n = 0, len(ret)
for counter in xrange(0, n):
x = ret[ind]
if x in temp:
temp.remove(x)
ind += 1
else:
del ret[ind]
return tuple(ret)
def __ne__(self, o):
return not self.__eq__(o)
def __radd__(self, a):
return a.__add__(self)
def __rsub__(self, a):
return a.__sub__(self)
def __rmul__(self, a):
return a.__mul__(self)
def __rdiv__(self, a):
return a.__div__(self)
def __str__(self):
from sympy.printing import sstr
return type(self).__name__ + sstr (tuple(self))
def __repr__(self):
from sympy.printing import srepr
return type(self).__name__ + srepr(tuple(self))
def __cmp__(self, other):
n1 = self.__class__.__name__
n2 = other.__class__.__name__
c = cmp(n1, n2)
if not c: return 0
i1 = -1
for cls in self.__class__.__mro__:
try:
i1 = ordering_of_classes.index(cls.__name__)
break
except ValueError:
i1 = -1
if i1 == -1: return c
i2 = -1
for cls in other.__class__.__mro__:
try:
i2 = ordering_of_classes.index(cls.__name__)
break
except ValueError:
i2 = -1
if i2 == -1: return c
return cmp(i1, i2)