kopia lustrzana https://github.com/villares/sketch-a-day
				
				
				
			wip 21
							rodzic
							
								
									538d5ee4bf
								
							
						
					
					
						commit
						14e138ef80
					
				|  | @ -0,0 +1,171 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| 
 | ||||
| ROTATION = {0: 0, | ||||
|             BOTTOM: 0, | ||||
|             DOWN: 0, | ||||
|             1: HALF_PI, | ||||
|             LEFT: HALF_PI, | ||||
|             2: PI, | ||||
|             TOP: PI, | ||||
|             UP: PI, | ||||
|             3: PI + HALF_PI, | ||||
|             RIGHT: PI + HALF_PI, | ||||
|             BOTTOM + RIGHT: 0, | ||||
|             DOWN + RIGHT: 0, | ||||
|             DOWN + LEFT: HALF_PI, | ||||
|             BOTTOM + LEFT: HALF_PI, | ||||
|             TOP + LEFT: PI, | ||||
|             UP + LEFT: PI, | ||||
|             TOP + RIGHT: PI + HALF_PI, | ||||
|             UP + RIGHT: PI + HALF_PI, | ||||
|             } | ||||
| 
 | ||||
| def quarter_circle(x, y, radius, quadrant): | ||||
|     circle_arc(x, y, radius, ROTATION[quadrant], HALF_PI) | ||||
| 
 | ||||
| def half_circle(x, y, radius, quadrant): | ||||
|     circle_arc(x, y, radius, ROTATION[quadrant], PI) | ||||
| 
 | ||||
| def circle_arc(x, y, radius, start_ang, sweep_ang): | ||||
|     arc(x, y, radius * 2, radius * 2, start_ang, start_ang + sweep_ang) | ||||
| 
 | ||||
| def poly_arc(x, y, radius, start_ang, sweep_ang, num_points=2): | ||||
|     angle = sweep_ang / int(num_points) | ||||
|     a = start_ang | ||||
|     with beginShape(): | ||||
|         while a <= start_ang + sweep_ang: | ||||
|             sx = x + cos(a) * radius | ||||
|             sy = y + sin(a) * radius | ||||
|             vertex(sx, sy) | ||||
|             a += angle | ||||
| 
 | ||||
| def arc_poly(x, y, d, _, start_ang, end_ang, num_points=5): | ||||
|     sweep_ang = end_ang - start_ang | ||||
|     angle = sweep_ang / int(num_points) | ||||
|     a = start_ang | ||||
|     with beginShape(): | ||||
|         while a <= end_ang: | ||||
|             sx = x + cos(a) * d / 2 | ||||
|             sy = y + sin(a) * d / 2 | ||||
|             vertex(sx, sy) | ||||
|             a += angle | ||||
| 
 | ||||
| def bar(x1, y1, x2, y2, thickness=None, shorter=0, ends=(1, 1)): | ||||
|     """ | ||||
|     O código para fazer as barras, dois pares (x, y), | ||||
|     um parâmetro de encurtamento: shorter | ||||
|     """ | ||||
|     L = dist(x1, y1, x2, y2) | ||||
|     if not thickness: | ||||
|         thickness = 10 | ||||
|     with pushMatrix(): | ||||
|         translate(x1, y1) | ||||
|         angle = atan2(x1 - x2, y2 - y1) | ||||
|         rotate(angle) | ||||
|         offset = shorter / 2 | ||||
|         line(thickness / 2, offset, thickness / 2, L - offset) | ||||
|         line(-thickness / 2, offset, -thickness / 2, L - offset) | ||||
|         if ends[0]: | ||||
|             half_circle(0, offset, thickness / 2, UP) | ||||
|         if ends[1]: | ||||
|             half_circle(0, L - offset, thickness / 2, DOWN) | ||||
| 
 | ||||
| def var_bar(p1x, p1y, p2x, p2y, r1, r2=None): | ||||
|     """ | ||||
|     Tangent/tangent shape on 2 circles of arbitrary radius | ||||
|     """ | ||||
|     if r2 is None: | ||||
|         r2 = r1 | ||||
|     #line(p1x, p1y, p2x, p2y) | ||||
|     d = dist(p1x, p1y, p2x, p2y) | ||||
|     ri = r1 - r2 | ||||
|     if d > abs(ri): | ||||
|         rid = (r1 - r2) / d | ||||
|         if rid > 1: | ||||
|             rid = 1 | ||||
|         if rid < -1: | ||||
|             rid = -1 | ||||
|         beta = asin(rid) + HALF_PI | ||||
|         with pushMatrix(): | ||||
|             translate(p1x, p1y) | ||||
|             angle = atan2(p1x - p2x, p2y - p1y) | ||||
|             rotate(angle + HALF_PI) | ||||
|             x1 = cos(beta) * r1 | ||||
|             y1 = sin(beta) * r1 | ||||
|             x2 = cos(beta) * r2 | ||||
|             y2 = sin(beta) * r2 | ||||
|             #print((d, beta, ri, x1, y1, x2, y2)) | ||||
|             beginShape()   | ||||
|             b_arc(0, 0, r1 * 2, r1 * 2, | ||||
|                 -beta - PI, beta - PI, mode=2) | ||||
|             b_arc(d, 0, r2 * 2, r2 * 2, | ||||
|                 beta - PI, PI - beta, mode=2) | ||||
|             endShape(CLOSE) | ||||
|     else: | ||||
|         ellipse(p1x, p1y, r1 * 2, r1 * 2) | ||||
|         ellipse(p2x, p2y, r2 * 2, r2 * 2) | ||||
|          | ||||
| def b_arc(cx, cy, w, h, start_angle, end_angle, mode=0): | ||||
|     """ | ||||
|     A bezier approximation of an arc | ||||
|     using the same signature as the original Processing arc() | ||||
|     mode: 0 "normal" arc, using beginShape() and endShape() | ||||
|               1 "middle" used in recursive call of smaller arcs | ||||
|               2 "naked" like normal, but without beginShape() and endShape() | ||||
|                  for use inside a larger PShape | ||||
|     """ | ||||
|     theta = end_angle - start_angle | ||||
|     # Compute raw Bezier coordinates. | ||||
|     if mode != 1 or abs(theta) < HALF_PI: | ||||
|         x0 = cos(theta / 2.0) | ||||
|         y0 = sin(theta / 2.0) | ||||
|         x3 = x0 | ||||
|         y3 = 0 - y0 | ||||
|         x1 = (4.0 - x0) / 3.0 | ||||
|         if y0 != 0: | ||||
|             y1 = ((1.0 - x0) * (3.0 - x0)) / (3.0 * y0)  # y0 != 0... | ||||
|         else: | ||||
|             y1 = 0 | ||||
|         x2 = x1 | ||||
|         y2 = 0 - y1 | ||||
|         # Compute rotationally-offset Bezier coordinates, using: | ||||
|         # x' = cos(angle) * x - sin(angle) * y | ||||
|         # y' = sin(angle) * x + cos(angle) * y | ||||
|         bezAng = start_angle + theta / 2.0 | ||||
|         cBezAng = cos(bezAng) | ||||
|         sBezAng = sin(bezAng) | ||||
|         rx0 = cBezAng * x0 - sBezAng * y0 | ||||
|         ry0 = sBezAng * x0 + cBezAng * y0 | ||||
|         rx1 = cBezAng * x1 - sBezAng * y1 | ||||
|         ry1 = sBezAng * x1 + cBezAng * y1 | ||||
|         rx2 = cBezAng * x2 - sBezAng * y2 | ||||
|         ry2 = sBezAng * x2 + cBezAng * y2 | ||||
|         rx3 = cBezAng * x3 - sBezAng * y3 | ||||
|         ry3 = sBezAng * x3 + cBezAng * y3 | ||||
|         # Compute scaled and translated Bezier coordinates. | ||||
|         rx, ry = w / 2.0, h / 2.0 | ||||
|         px0 = cx + rx * rx0 | ||||
|         py0 = cy + ry * ry0 | ||||
|         px1 = cx + rx * rx1 | ||||
|         py1 = cy + ry * ry1 | ||||
|         px2 = cx + rx * rx2 | ||||
|         py2 = cy + ry * ry2 | ||||
|         px3 = cx + rx * rx3 | ||||
|         py3 = cy + ry * ry3 | ||||
|         # Debug points... comment this out! | ||||
|         # stroke(0) | ||||
|         # ellipse(px3, py3, 15, 15) | ||||
|         # ellipse(px0, py0, 5, 5) | ||||
|     # Drawing | ||||
|     if mode == 0:  # 'normal' arc (not 'middle' nor 'naked') | ||||
|         beginShape() | ||||
|     if mode != 1:  # if not 'middle' | ||||
|         vertex(px3, py3) | ||||
|     if abs(theta) < HALF_PI: | ||||
|         bezierVertex(px2, py2, px1, py1, px0, py0) | ||||
|     else: | ||||
|         # to avoid distortion, break into 2 smaller arcs | ||||
|         b_arc(cx, cy, w, h, start_angle, end_angle - theta / 2.0, mode=1) | ||||
|         b_arc(cx, cy, w, h, start_angle + theta / 2.0, end_angle, mode=1) | ||||
|     if mode == 0:  # end of a 'normal' arc | ||||
|         endShape() | ||||
										
											
												Plik diff jest za duży
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,338 @@ | |||
| #*- coding: utf-8 -*- | ||||
| 
 | ||||
| """ | ||||
| A simple Python graph class, demonstrating the essential facts and functionalities of graphs | ||||
| based on https://www.python-course.eu/graphs_python.php and https://www.python.org/doc/essays/graphs/ | ||||
| """ | ||||
| 
 | ||||
| from random import choice | ||||
| 
 | ||||
| class Graph(object): | ||||
| 
 | ||||
|     def __init__(self, graph_dict=None): | ||||
|         """ | ||||
|         Initialize a graph object with dictionary provided, | ||||
|         if none provided, create an empty one. | ||||
|         """ | ||||
|         if graph_dict is None: | ||||
|             graph_dict = {} | ||||
|         self.__graph_dict = graph_dict | ||||
| 
 | ||||
|     def __len__(self): | ||||
|         return len(self.__graph_dict) | ||||
| 
 | ||||
|     def vertices(self): | ||||
|         """Return the vertices of graph.""" | ||||
|         return list(self.__graph_dict.keys()) | ||||
| 
 | ||||
|     def edges(self): | ||||
|         """Return the edges of graph """ | ||||
|         return self.__generate_edges() | ||||
| 
 | ||||
|     def add_vertex(self, vertex): | ||||
|         """ | ||||
|         If the vertex "vertex" is not in self.__graph_dict, | ||||
|         add key "vertex" with an empty list as a value, | ||||
|         otherwise, do nothing. | ||||
|         """ | ||||
|         if vertex not in self.__graph_dict: | ||||
|             self.__graph_dict[vertex] = [] | ||||
| 
 | ||||
|     def add_edge(self, edge): | ||||
|         """ | ||||
|         Assuming that edge is of type set, tuple or list; | ||||
|         add edge between vertices. Can add multiple edges! | ||||
|         """ | ||||
|         edge = set(edge) | ||||
|         vertex1 = edge.pop() | ||||
|         if edge: | ||||
|             # not a loop | ||||
|             vertex2 = edge.pop() | ||||
|             if vertex1 in self.__graph_dict: | ||||
|                 self.__graph_dict[vertex1].append(vertex2) | ||||
|             else: | ||||
|                 self.__graph_dict[vertex1] = [vertex2] | ||||
|             if vertex2 in self.__graph_dict: | ||||
|                 self.__graph_dict[vertex2].append(vertex1) | ||||
|             else: | ||||
|                 self.__graph_dict[vertex2] = [vertex1] | ||||
|         else: | ||||
|             # a loop | ||||
|             if vertex1 in self.__graph_dict: | ||||
|                 self.__graph_dict[vertex1].append(vertex1) | ||||
|             else: | ||||
|                 self.__graph_dict[vertex1] = [vertex1] | ||||
| 
 | ||||
|     def remove_vertex(self, vert): | ||||
|         del self.__graph_dict[vert] | ||||
|         for k in self.__graph_dict.keys(): | ||||
|             if vert in self.__graph_dict[k]: | ||||
|                 self.__graph_dict[k].remove(vert) | ||||
| 
 | ||||
|     def remove_edge(self, edge): | ||||
|         edge = set(edge) | ||||
|         vertex1 = edge.pop() | ||||
|         if edge: | ||||
|             vertex2 = edge.pop() | ||||
|             self.__graph_dict[vertex1].remove(vertex2) | ||||
|             self.__graph_dict[vertex2].remove(vertex1) | ||||
|         else: | ||||
|             self.__graph_dict[vertex1].remove(vertex1) | ||||
| 
 | ||||
|     def __generate_edges(self): | ||||
|         """ | ||||
|         Generate the edges, represented as sets with one | ||||
|         (a loop back to the vertex) or two vertices. | ||||
|         """ | ||||
|         edges = [] | ||||
|         for vertex in self.__graph_dict: | ||||
|             for neighbour in self.__graph_dict[vertex]: | ||||
|                 if {neighbour, vertex} not in edges: | ||||
|                     edges.append({vertex, neighbour}) | ||||
|         return edges | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         res = "vertices: " | ||||
|         for k in self.__graph_dict: | ||||
|             res += str(k) + " " | ||||
|         res += "\nedges: " | ||||
|         for edge in self.__generate_edges(): | ||||
|             res += str(edge) + " " | ||||
|         return res | ||||
| 
 | ||||
|     def find_isolated_vertices(self): | ||||
|         """ | ||||
|         Return a list of isolated vertices. | ||||
|         """ | ||||
|         graph = self.__graph_dict | ||||
|         isolated = [] | ||||
|         for vertex in graph: | ||||
|             print(isolated, vertex) | ||||
|             if not graph[vertex]: | ||||
|                 isolated += [vertex] | ||||
|         return isolated | ||||
| 
 | ||||
|     def find_path(self, start_vertex, end_vertex, path=[]): | ||||
|         """ | ||||
|         Find a path from start_vertex to end_vertex in graph. | ||||
|         """ | ||||
|         graph = self.__graph_dict | ||||
|         path = path + [start_vertex] | ||||
|         if start_vertex == end_vertex: | ||||
|             return path | ||||
|         if start_vertex not in graph: | ||||
|             return None | ||||
|         for vertex in graph[start_vertex]: | ||||
|             if vertex not in path: | ||||
|                 extended_path = self.find_path(vertex, | ||||
|                                                end_vertex, | ||||
|                                                path) | ||||
|                 if extended_path: | ||||
|                     return extended_path | ||||
|         return None | ||||
| 
 | ||||
|     def find_all_paths(self, start_vertex, end_vertex, path=[]): | ||||
|         """ | ||||
|         Find all paths from start_vertex to end_vertex. | ||||
|         """ | ||||
|         graph = self.__graph_dict | ||||
|         path = path + [start_vertex] | ||||
|         if start_vertex == end_vertex: | ||||
|             return [path] | ||||
|         if start_vertex not in graph: | ||||
|             return [] | ||||
|         paths = [] | ||||
|         for vertex in graph[start_vertex]: | ||||
|             if vertex not in path: | ||||
|                 extended_paths = self.find_all_paths(vertex, | ||||
|                                                      end_vertex, | ||||
|                                                      path) | ||||
|                 for p in extended_paths: | ||||
|                     paths.append(p) | ||||
|         return paths | ||||
| 
 | ||||
|     def is_connected(self, | ||||
|                      vertices_encountered=None, | ||||
|                      start_vertex=None): | ||||
|         """Find if the graph is connected.""" | ||||
|         if vertices_encountered is None: | ||||
|             vertices_encountered = set() | ||||
|         gdict = self.__graph_dict | ||||
|         vertices = list(gdict.keys())  # "list" necessary in Python 3 | ||||
|         if not start_vertex: | ||||
|             # chosse a vertex from graph as a starting point | ||||
|             start_vertex = vertices[0] | ||||
|         vertices_encountered.add(start_vertex) | ||||
|         if len(vertices_encountered) != len(vertices): | ||||
|             for vertex in gdict[start_vertex]: | ||||
|                 if vertex not in vertices_encountered: | ||||
|                     if self.is_connected(vertices_encountered, vertex): | ||||
|                         return True | ||||
|         else: | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def vertex_degree(self, vertex): | ||||
|         """ | ||||
|         Return the number of edges connecting to a vertex (the number of adjacent vertices). | ||||
|         Loops are counted double, i.e. every occurence of vertex in the list of adjacent vertices. | ||||
|         """ | ||||
|         adj_vertices = self.__graph_dict[vertex] | ||||
|         degree = len(adj_vertices) + adj_vertices.count(vertex) | ||||
|         return degree | ||||
| 
 | ||||
|     def degree_sequence(self): | ||||
|         """Calculates the degree sequence.""" | ||||
|         seq = [] | ||||
|         for vertex in self.__graph_dict: | ||||
|             seq.append(self.vertex_degree(vertex)) | ||||
|         seq.sort(reverse=True) | ||||
|         return tuple(seq) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def is_degree_sequence(sequence): | ||||
|         """ | ||||
|         Return True, if the sequence is a degree sequence (non-increasing), | ||||
|         otherwise return False. | ||||
|         """ | ||||
|         return all(x >= y for x, y in zip(sequence, sequence[1:])) | ||||
| 
 | ||||
|     def delta(self): | ||||
|         """Find minimum degree of vertices.""" | ||||
|         min = 100000000 | ||||
|         for vertex in self.__graph_dict: | ||||
|             vertex_degree = self.vertex_degree(vertex) | ||||
|             if vertex_degree < min: | ||||
|                 min = vertex_degree | ||||
|         return min | ||||
| 
 | ||||
|     def Delta(self): | ||||
|         """Finde maximum degree of vertices.""" | ||||
|         max = 0 | ||||
|         for vertex in self.__graph_dict: | ||||
|             vertex_degree = self.vertex_degree(vertex) | ||||
|             if vertex_degree > max: | ||||
|                 max = vertex_degree | ||||
|         return max | ||||
| 
 | ||||
|     def density(self): | ||||
|         """Calculate the graph density.""" | ||||
|         g = self.__graph_dict | ||||
|         V = len(g.keys()) | ||||
|         E = len(self.edges()) | ||||
|         return 2.0 * E / (V * (V - 1)) | ||||
| 
 | ||||
|     def diameter(self): | ||||
|         """Calculates the graph diameter.""" | ||||
| 
 | ||||
|         v = self.vertices() | ||||
|         pairs = [ | ||||
|             (v[i], | ||||
|              v[j]) for i in range( | ||||
|                 len(v)) for j in range( | ||||
|                 i + 1, | ||||
|                 len(v) - 1)] | ||||
|         smallest_paths = [] | ||||
|         for (s, e) in pairs: | ||||
|             paths = self.find_all_paths(s, e) | ||||
|             smallest = sorted(paths, key=len)[0] | ||||
|             smallest_paths.append(smallest) | ||||
| 
 | ||||
|         smallest_paths.sort(key=len) | ||||
| 
 | ||||
|         # longest path is at the end of list, | ||||
|         # i.e. diameter corresponds to the length of this path | ||||
|         diameter = len(smallest_paths[-1]) - 1 | ||||
|         return diameter | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def erdoes_gallai(dsequence): | ||||
|         """ | ||||
|         Check if Erdoes-Gallai inequality condition is fullfilled. | ||||
|         """ | ||||
|         if sum(dsequence) % 2: | ||||
|             # sum of sequence is odd | ||||
|             return False | ||||
|         if Graph.is_degree_sequence(dsequence): | ||||
|             for k in range(1, len(dsequence) + 1): | ||||
|                 left = sum(dsequence[:k]) | ||||
|                 right = k * (k - 1) + sum([min(x, k) for x in dsequence[k:]]) | ||||
|                 if left > right: | ||||
|                     return False | ||||
|         else: | ||||
|             # sequence is increasing | ||||
|             return False | ||||
|         return True | ||||
| 
 | ||||
|     # Code by Eryk Kopczyński | ||||
|     def find_shortest_path(self, start, end): | ||||
|         from collections import deque | ||||
|         graph = self.__graph_dict | ||||
|         dist = {start: [start]} | ||||
|         q = deque((start,)) | ||||
|         while len(q): | ||||
|             at = q.popleft() | ||||
|             for next in graph[at]: | ||||
|                 if next not in dist: | ||||
|                     # dist[next] = [dist[at], next] | ||||
|                     # less efficient but nicer output | ||||
|                     dist[next] = dist[at] + [next] | ||||
|                     q.append(next) | ||||
|         return dist.get(end) | ||||
| 
 | ||||
|     ############## | ||||
|     def is_cyclic(self): | ||||
|         """ | ||||
|         Returns true if the graph contains a cycle, else false. | ||||
|         """ | ||||
|         # Mark all the vertices as not visited | ||||
|         visited = [False] * len(self) | ||||
|         # Call helper function to detect cycle in different DFS trees | ||||
|         for i, v in enumerate(visited): | ||||
|             # Don't recur for u if it is already visited | ||||
|             if v == False: | ||||
|                 if self.dfs(i, visited, -1): | ||||
|                     return True | ||||
|         return False | ||||
| 
 | ||||
|     def dfs(self, v, visited, parent): | ||||
|         # Mark the current node as visited | ||||
|         visited[v] = True | ||||
|         # Recur for all the vertices adjacent to this vertex | ||||
|         for i in self.__graph_dict[v]: | ||||
|             # If the node is not visited then recurse on it | ||||
|             if visited[i] == False: | ||||
|                 if(self.dfs(i, visited, v)): | ||||
|                     return True | ||||
|             # If an adjacent vertex is visited and not parent of current | ||||
|             # vertex, then there is a cycle | ||||
|             elif parent != i: | ||||
|                 return True | ||||
|         return False | ||||
| 
 | ||||
|     ############## | ||||
| 
 | ||||
|     def get_random_vertex(self): | ||||
|         return choice(self.vertices()) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def random_graph(names, | ||||
|                      connect_rate=.9, | ||||
|                      allow_loops=True, | ||||
|                      allow_cyclic=False, | ||||
|                      connected=False): | ||||
|         vertices = set(names) | ||||
|         while True: | ||||
|             graph = Graph() | ||||
|             for v in vertices: | ||||
|                 graph.add_vertex(v) | ||||
|                 if random(1) < connect_rate: | ||||
|                     if allow_loops: | ||||
|                         names = list(vertices) | ||||
|                     else: | ||||
|                         names = list(vertices - set((v,))) | ||||
|                     graph.add_edge({v, choice(names)}) | ||||
|             if not connected or graph.is_connected(): | ||||
|                 if allow_cyclic or not graph.is_cyclic(): | ||||
|                     break | ||||
|         return graph | ||||
|  | @ -0,0 +1,132 @@ | |||
| #*- coding: utf-8 -*- | ||||
| 
 | ||||
| from __future__ import division, print_function | ||||
| from random import sample, choice | ||||
| 
 | ||||
| 
 | ||||
| class Grid(): | ||||
| 
 | ||||
|     def __init__(self, graph, cols, rows, mode=0): | ||||
|         """ | ||||
|         mode 0: heavy center | ||||
|         mode 1: heavy perifery | ||||
|         """ | ||||
|         self.cols = cols | ||||
|         self.rows = rows | ||||
|         self.graph = graph | ||||
|         self.grid = self.generate_points(mode) | ||||
|         self.other_grid = self.generate_points(mode) | ||||
|         self.recalculate_d() | ||||
| 
 | ||||
|     def generate_points(self, mode): | ||||
|         points = [] | ||||
|         for i in range(self.cols * self.rows): | ||||
|             x = i % self.cols | ||||
|             y = i // self.rows | ||||
|             z = 0 | ||||
|             points.append([x, y, z]) | ||||
|         p_dist = lambda p: dist(p[0], p[1], self.cols / 2, self.rows / 2) | ||||
|         points = sorted(points, key=p_dist) | ||||
|         if mode == 0: | ||||
|             v_list = reversed(sorted(self.graph.vertices(), | ||||
|                                      key=self.graph.vertex_degree)) | ||||
|         elif mode == 1: | ||||
|             v_list = sorted(self.graph.vertices(), | ||||
|                             key=self.graph.vertex_degree) | ||||
|         else: | ||||
|             v_list = self.graph.vertices() | ||||
|             print("random mode") | ||||
| 
 | ||||
|         return {v: p for v, p in zip(v_list, points)} | ||||
| 
 | ||||
|     def __getitem__(self, k): | ||||
|         return self.grid[k] | ||||
| 
 | ||||
|     def __setitem__(self, k, v): | ||||
|         self.grid[k] = v | ||||
| 
 | ||||
|     def __len__(self): | ||||
|         return len(self.grid) | ||||
| 
 | ||||
|     def keys(self): | ||||
|         return self.grid.keys() | ||||
| 
 | ||||
|     def values(self): | ||||
|         return self.grid.values() | ||||
| 
 | ||||
|     def __iter__(self): | ||||
|         return iter(self.grid) | ||||
| 
 | ||||
|     def swap(self, num=2): | ||||
|         grid = self.grid | ||||
|         graph = self.graph | ||||
|         fail = 0 | ||||
|         n = m = self.edge_distances() | ||||
|         while m <= n and fail < len(graph) ** 2: | ||||
|             new_grid = dict(grid) | ||||
|             if num == 2: | ||||
|                 a, b = sample(graph.vertices(), 2) | ||||
|                 new_grid[a], new_grid[b] = new_grid[b], new_grid[a] | ||||
|             else: | ||||
|                 ks = sample(graph.vertices(), num) | ||||
|                 vs = [grid[k] for k in sample(ks, num)] | ||||
|                 for k, v in zip(ks, vs): | ||||
|                     new_grid[k] = v | ||||
|             n = self.edge_distances(new_grid) | ||||
|             if m > n: | ||||
|                 t = "{:.2%} at: {} tries of {}v shuffle/swap" \ | ||||
|                     .format((n - m) / m, fail + 1, num) | ||||
|                 print("\n" + t, end="") | ||||
|                 self.grid = new_grid | ||||
|                 self.recalculate_d() | ||||
|             else: | ||||
|                 fail += 1 | ||||
|         print(".", end='') | ||||
| 
 | ||||
|     def recalculate_d(self): | ||||
|         for k in self.graph.vertices(): | ||||
|             d = self.graph.vertex_degree(k) | ||||
|             self.other_grid[k][2] = d | ||||
|             self.grid[k][2] = d | ||||
| 
 | ||||
|     def edge_distances(self, ng=None): | ||||
|         grid = ng or self.grid | ||||
|         total = 0 | ||||
|         for edge in self.graph.edges(): | ||||
|             if len(edge) == 2: | ||||
|                 a, b = edge | ||||
|                 xa, ya, _ = grid[a] | ||||
|                 xb, yb, _ = grid[b] | ||||
|                 d = dist(xa, ya, xb, yb) | ||||
|                 total += d | ||||
|         return total | ||||
| 
 | ||||
|     def edges(self, t): | ||||
|         z = zip(self.sorted_edges(self.grid), | ||||
|                 self.sorted_edges(self.other_grid)) | ||||
|         lerped_edges = [] | ||||
|         for za, zb in z: | ||||
|             lerped_edges.append([lerp(ea, eb, t) | ||||
|                                  for ea, eb in zip(za, zb)]) | ||||
|         return lerped_edges | ||||
| 
 | ||||
|     def sorted_edges(self, grid): | ||||
|         edgs = [] | ||||
|         for e in self.graph.edges(): | ||||
|             if len(e) == 2: | ||||
|                 a, b = tuple(e) | ||||
|                 (xa, ya, za) = grid[a] | ||||
|                 (xb, yb, zb) = grid[b] | ||||
|                 da = self.graph.vertex_degree(a) | ||||
|                 db = self.graph.vertex_degree(b) | ||||
|                 deg = ((da + db) / 2)  # r / (Grid.w / 10) | ||||
|                 edgs.append((xa, ya, xb, yb, za, zb, deg)) | ||||
|         return sorted(edgs, key=lambda e: e[6]) | ||||
| 
 | ||||
| def dim_grid(n): | ||||
|     a = int(sqrt(n)) | ||||
|     b = n // a | ||||
|     if a * b < n: | ||||
|         b += 1 | ||||
|     print(u'{}: {} × {} ({})'.format(n, a, b, a * b)) | ||||
|     return a, b | ||||
|  | @ -0,0 +1,170 @@ | |||
| from __future__ import print_function, division | ||||
| import pickle | ||||
| 
 | ||||
| from graph import Graph | ||||
| from grid import Grid, dim_grid | ||||
| from arcs import var_bar | ||||
| 
 | ||||
| thread_running = False | ||||
| viz_stat = False | ||||
| selected_v = None | ||||
| t, v = 0, 0.01 | ||||
| animate = False | ||||
| 
 | ||||
| def setup(): | ||||
|     size(600, 600) | ||||
|     # colorMode(HSB) | ||||
|     textAlign(CENTER, CENTER) | ||||
|     f = createFont("Source Code Pro Bold", 12) | ||||
|     textFont(f) | ||||
|     global graph, margin, w, h, cols, rows | ||||
|     graph = Graph.random_graph(range(100), | ||||
|                                connect_rate=.95, | ||||
|                                allow_loops=False, | ||||
|                                connected=True, | ||||
|                                allow_cyclic=True) | ||||
|     margin = width / 40 | ||||
|     cols, rows = dim_grid(len(graph)) | ||||
|     w, h = (width - margin * 2) / cols, (height - margin * 2) / rows | ||||
|     setup_grid(cols, rows) | ||||
| 
 | ||||
| def setup_grid(cols, rows, mode=0): | ||||
|     # create a random graph and a dict of grid postions for its vertices | ||||
|     global grid, m | ||||
|     grid = Grid(graph, cols, rows, mode=mode) | ||||
|     m = grid.edge_distances()  # "metric", sum of edge distances | ||||
|     print("Cyclic: " + str(graph.is_cyclic())) | ||||
|     global gx, gy | ||||
|     gx, gy = 0, 100 | ||||
| 
 | ||||
| 
 | ||||
| def draw(): | ||||
|     global t | ||||
|     # scale(.5) | ||||
|     background(32, 0, 64) | ||||
|     for e in reversed(grid.edges(t)): | ||||
|         xa, ya, xb, yb, za, zb, deg = e | ||||
|         strokeWeight(map(deg, 1.5, 5, 4, 1)) | ||||
|         fill(255, 200) | ||||
|         var_bar(margin + w / 2 + xa * w, | ||||
|                 margin + h / 2 + ya * w, | ||||
|                 margin + w / 2 + xb * w, | ||||
|                 margin + h / 2 + yb * w, | ||||
|                 za * w / 10, zb * w / 10) | ||||
|         strokeWeight(1) | ||||
|         circle(margin + w / 2 + xa * w, | ||||
|                margin + h / 2 + ya * h, 10) | ||||
|         circle(margin + w / 2 + xb * w, | ||||
|                margin + h / 2 + yb * h, 10) | ||||
|          | ||||
|     for v in grid.keys(): | ||||
|         x, y, z = grid[v] | ||||
|         # if v == selected_v: | ||||
|         #     fill(0) | ||||
|         # elif mouse_near(v): | ||||
|         #     fill(128) | ||||
|         # else: | ||||
|         #     noFill() | ||||
|         # strokeWeight(1) | ||||
|         # circle(margin + w / 2 + x * w, | ||||
|         #        margin + h / 2 + y * h, 10) | ||||
|         if viz_stat: | ||||
|             fill(255, 0, 0) | ||||
|             text("{}:{}".format(v, graph.vertex_degree(v)).upper(), | ||||
|                  margin + w / 2 + x * w - 15,  | ||||
|                  margin + h / 2 + y * h - 5) | ||||
|              | ||||
|                               | ||||
|     fill(100) | ||||
|     text(int(m), 30, 20) | ||||
| 
 | ||||
|     if selected_v: | ||||
|         x, y, _ = grid[selected_v] | ||||
|         stroke(0) | ||||
|         strokeWeight(5) | ||||
|         line(margin + w / 2 + x * w, | ||||
|              margin + h / 2 + y * h, mouseX, mouseY) | ||||
| 
 | ||||
|     if animate and 0 < t < 1: | ||||
|         t += v | ||||
| 
 | ||||
| def keyTyped(): | ||||
|     global gx, gy, viz_stat, grid, graph, animate, t, v | ||||
|     if key == 'x': | ||||
|         grid.grid, grid.other_grid = grid.other_grid, grid.grid | ||||
|     elif key  == 'a': | ||||
|         animate != animate | ||||
|     elif key == ' ': | ||||
|         v = -v | ||||
|     elif key == 'r': | ||||
|         setup_grid(cols, rows, mode=0) | ||||
|     elif key == 'e': | ||||
|         setup_grid(cols, rows, mode=1) | ||||
|     elif key == 'R': | ||||
|         setup_grid(cols, rows, mode=2) | ||||
|     elif key == 'v': | ||||
|         viz_stat = not viz_stat | ||||
|     elif key == 'p': | ||||
|         saveFrame("####.png") | ||||
|     elif key == 'd': | ||||
|         with open("data/grid.data", "w") as f: | ||||
|             pickle.dump((graph, grid), f) | ||||
|             print("dump grid.data") | ||||
|     elif key == 'l': | ||||
|         with open("data/grid.data", "rb") as f2: | ||||
|             graph, grid = pickle.load(f2) | ||||
|             print("load grid.data") | ||||
|     else: | ||||
|         if not thread_running: | ||||
|             thread("swapping") | ||||
|         else: | ||||
|             print("\nalready swapping") | ||||
| 
 | ||||
| def swapping(): | ||||
|     global grid, thread_running, gx, gy, m | ||||
|     if str(key) not in 's23456789': | ||||
|         print("wrong key!") | ||||
|         return | ||||
|     thread_running = True | ||||
|     print("starting thread.", end="") | ||||
|     m = grid.edge_distances() | ||||
|     len_graph = len(graph) | ||||
|     multiple = 1 if mousePressed else 100 | ||||
|     for _ in range(multiple): | ||||
|         if key == 's': | ||||
|             grid.swap(num=len_graph) | ||||
|         if str(key) in '234556789': | ||||
|             grid.swap(num=int(key)) | ||||
|         n = grid.edge_distances() | ||||
|         gx += 1 | ||||
|         if n < m: | ||||
|             gy -= gy * (m - n) / m | ||||
|             m = n | ||||
|     thread_running = False | ||||
|     print("\nending thread.") | ||||
| 
 | ||||
| def mouse_near(v): | ||||
|     x, y, _ = grid[v] | ||||
|     return dist(margin + w / 2 + x * w, | ||||
|                 margin + h / 2 + y * h, mouseX, mouseY) < 12 | ||||
| 
 | ||||
| def mousePressed(): | ||||
|     global selected_v | ||||
|     for v in grid.keys(): | ||||
|         if mouse_near(v): | ||||
|             selected_v = v | ||||
|             return | ||||
| 
 | ||||
| def mouseReleased(): | ||||
|     global selected_v | ||||
|     if selected_v: | ||||
|         for v in grid.keys(): | ||||
|             if mouse_near(v): | ||||
|                 grid[selected_v], grid[v] = grid[v], grid[selected_v] | ||||
|                 grid.recalculate_d() | ||||
|     selected_v = None | ||||
| 
 | ||||
| 
 | ||||
| # TODO IDEAS: | ||||
| # Find distance outliers and try to shuffle them closer | ||||
| # Run many times without visualisation on Python 3 to get some huge samples | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Alexandre B A Villares
						Alexandre B A Villares