+ @classmethod
+ def _polygon_inner_point(cls, points):
+ symbols = points[0].symbols
+ coordinates = {symbol: 0 for symbol in symbols}
+ for point in points:
+ for symbol, coordinate in point.coordinates():
+ coordinates[symbol] += coordinate
+ for symbol in symbols:
+ coordinates[symbol] /= len(points)
+ return Point(coordinates)
+
+ @classmethod
+ def _sort_polygon_2d(cls, points):
+ if len(points) <= 3:
+ return points
+ o = cls._polygon_inner_point(points)
+ angles = {}
+ for m in points:
+ om = Vector(o, m)
+ dx, dy = (coordinate for symbol, coordinate in om.coordinates())
+ angle = math.atan2(dy, dx)
+ angles[m] = angle
+ return sorted(points, key=angles.get)
+
+ @classmethod
+ def _sort_polygon_3d(cls, points):
+ if len(points) <= 3:
+ return points
+ o = cls._polygon_inner_point(points)
+ a = points[0]
+ oa = Vector(o, a)
+ norm_oa = oa.norm()
+ for b in points[1:]:
+ ob = Vector(o, b)
+ u = oa.cross(ob)
+ if not u.isnull():
+ u = u.asunit()
+ break
+ else:
+ raise ValueError('degenerate polygon')
+ angles = {a: 0.}
+ for m in points[1:]:
+ om = Vector(o, m)
+ normprod = norm_oa * om.norm()
+ cosinus = max(oa.dot(om) / normprod, -1.)
+ sinus = u.dot(oa.cross(om)) / normprod
+ angle = math.acos(cosinus)
+ angle = math.copysign(angle, sinus)
+ angles[m] = angle
+ return sorted(points, key=angles.get)
+
+ def faces(self):
+ vertices = self.vertices()
+ faces = []
+ for constraint in self.constraints:
+ face = []
+ for vertex in vertices:
+ if constraint.subs(vertex.coordinates()) == 0:
+ face.append(vertex)
+ faces.append(face)
+ return faces
+
+ def plot(self):
+ """
+ Display 3D plot of set.
+ """
+ import matplotlib.pyplot as plt
+ import matplotlib.patches as patches
+
+ if len(self.symbols)> 3:
+ raise TypeError
+
+ elif len(self.symbols) == 2:
+ import pylab
+ points = []
+ for verts in self.vertices():
+ pairs=()
+ for coordinate, point in verts.coordinates():
+ pairs = pairs + (float(point),)
+ points.append(pairs)
+ cent=(sum([p[0] for p in points])/len(points),sum([p[1] for p in points])/len(points))
+ points.sort(key=lambda p: math.atan2(p[1]-cent[1],p[0]-cent[0]))
+ pylab.scatter([p[0] for p in points],[p[1] for p in points])
+ pylab.gca().add_patch(patches.Polygon(points,closed=True,fill=True))
+ pylab.grid()
+ pylab.show()
+
+ elif len(self.symbols)==3:
+ from mpl_toolkits.mplot3d import Axes3D
+ from mpl_toolkits.mplot3d.art3d import Poly3DCollection
+ faces = self.faces()
+ fig = plt.figure()
+ ax = Axes3D(fig)
+ for face in faces:
+ points = []
+ vertices = Polyhedron._sort_polygon_3d(face)
+ for verts in vertices:
+ pairs=()
+ for coordinate, point in verts.coordinates():
+ pairs = pairs + (float(point),)
+ points.append(pairs)
+ collection = Poly3DCollection([points], alpha=0.7)
+ face_color = [0.5, 0.5, 1] # alternative: matplotlib.colors.rgb2hex([0.5, 0.5, 1])
+ collection.set_facecolor(face_color)
+ ax.add_collection3d(collection)
+ ax.set_xlabel('X')
+ ax.set_xlim(0, 5)
+ ax.set_ylabel('Y')
+ ax.set_ylim(0, 5)
+ ax.set_zlabel('Z')
+ ax.set_zlim(0, 5)
+ plt.grid()
+ plt.show()
+ return points
+
+ @classmethod
+ def limit(cls, faces, variable, lim):
+ sym = []
+ if variable is 'x':
+ n = 0
+ elif variable is 'y':
+ n = 1
+ elif variable is 'z':
+ n = 2
+ for face in faces:
+ for vert in face:
+ coordinates = vert.coordinates()
+ for point in enumerate(coordinates):
+ coordinates.get(n)
+ sym.append(points)
+ if lim == 0:
+ value = min(sym)
+ else:
+ value = max(sym)
+ return value