import math from helix.functions import fequal class Polygon(object): def __init__(self, line=None, points=()): if line: self.points = [line.start, line.end] elif points: self.points = points else: self.points = [] def continues_with_line(self, line): if not self.closed and line.start == self.points[-1]: return True return False @property def closed(self): return len(self.points) != 1 and self.points[0] == self.points[-1] def sorted_points(self): return sorted(self.points, key=lambda x: x[0]) def determine_orientation(self): points = self.sorted_points() p1 = points[0] other_points = sorted(points[1:], key=lambda x: (x[0] - p1[0]) ** 2 + (x[1] - p1[1]) ** 2) p2 = other_points[1] # other_points[0] is the point that (along with p1) defines the short edge of this rectangle # other_points[1] defines the long edge of this rectangle # other_points[2] is diagonally across from p1. Not useful for defining edges. x = p2[0] - p1[0] y = p2[1] - p1[1] return math.degrees(math.atan2(y, x)) def __do_something_with_long_edges__(self, module, fn, pair_spacing): def cmp_point(p1, p2, pair_spacing): dx = p1[0] - p2[0] dy = p1[1] - p2[1] d = math.sqrt(dx * dx + dy * dy) allowedVariance = 0.1 if pair_spacing is None: return d < allowedVariance else: d = math.fabs(d - pair_spacing) return d <= allowedVariance p1 = self.points[0] other_points = sorted(self.points[1:], key=lambda x: (x[0] - p1[0]) ** 2 + (x[1] - p1[1]) ** 2) self_long_edges = [sorted([p1, other_points[1]],), sorted([other_points[0], other_points[2]],)] p2 = module.points[0] other_points = sorted(module.points[1:], key=lambda x: (x[0] - p2[0]) ** 2 + (x[1] - p2[1]) ** 2) other_long_edges = [sorted([p2, other_points[1]],), sorted([other_points[0], other_points[2]],)] for edge in self_long_edges: for other_edge in other_long_edges: if cmp_point(edge[0], other_edge[0], pair_spacing) and\ cmp_point(edge[1], other_edge[1], pair_spacing): fn(self, module, edge, other_edge) return True return False def shares_module_on_long_edge(self, module, pair_spacing): def on_match_edges(this, other, this_edges, other_edges): pass return self.__do_something_with_long_edges__(module, on_match_edges, pair_spacing) def consolidate_with(self, pair, pair_spacing): def on_match_edges(this, other, this_edges, other_edges): this.points.remove(this_edges[0]) this.points.remove(this_edges[1]) other.points.remove(other_edges[0]) other.points.remove(other_edges[1]) this.points += pair.points self.__do_something_with_long_edges__(pair, on_match_edges, pair_spacing) def scale(self, scale_x=1, scale_y=1): polygon = Polygon() polygon.points = [(x * scale_x, y * scale_y) for x, y in self.points] return polygon def svg_points(self, array_size): value_string = "" if len(self.points) == 4: p0 = self.points[0] points = sorted(self.points, key=lambda x: (x[0] - p0[0]) ** 2 + (x[1] - p0[1]) ** 2) sorted_points = [p0, points[1], points[3], points[2]] else: sorted_points = self.points for point in sorted_points: value_string += "%f,%f " % (point[0], array_size[1] - point[1]) return value_string def __repr__(self): return str([(round(p[0], 3), round(p[1], 3)) for p in self.points]) def __eq__(self, other): if self is other: return True if not isinstance(other, self.__class__): return False if len(self.points) != len(other.points): return False for idx, point in enumerate(self.points): other_point = other.points[idx] for variable_index in range(len(point)): if not fequal(point[variable_index], other_point[variable_index]): return False return True