kopia lustrzana https://github.com/villares/sketch-a-day
main
rodzic
cfc61ac416
commit
9986fdee26
|
@ -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()
|
|
@ -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,115 @@
|
|||
#*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import division, print_function
|
||||
from random import sample, choice
|
||||
|
||||
|
||||
class Grid():
|
||||
|
||||
def __init__(self, graph, width, height, margin=None, mode=0):
|
||||
"""
|
||||
mode 0: heavy center
|
||||
mode 1: heavy perifery
|
||||
"""
|
||||
margin = margin or width / 40
|
||||
cols, rows = dim_grid(len(graph))
|
||||
w, h = (width - margin * 2) / cols, (height - margin * 2) / rows
|
||||
points = []
|
||||
for i in range(cols * rows):
|
||||
c = i % cols
|
||||
r = i // rows
|
||||
x = margin + w * 0.5 + c * w # - 14 * (r % 2) + 7
|
||||
y = margin + h * 0.5 + r * h # - 14 * (c % 2) + 7
|
||||
z = 0
|
||||
points.append([x, y, z])
|
||||
points = sorted(
|
||||
points, key=lambda p: dist(p[0], p[1], width / 2, height / 2))
|
||||
if mode == 0:
|
||||
v_list = reversed(
|
||||
sorted(graph.vertices(), key=graph.vertex_degree))
|
||||
elif mode == 1:
|
||||
v_list = sorted(graph.vertices(), key=graph.vertex_degree)
|
||||
else:
|
||||
v_list = graph.vertices()
|
||||
print("random mode")
|
||||
|
||||
Grid.w, Grid.h = w, h
|
||||
self.graph = graph
|
||||
self.grid = {v: p for v, p in zip(v_list, points)}
|
||||
recalculate_sizes_from_v_deg(self.graph, self)
|
||||
|
||||
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 = edge_distances(graph, grid)
|
||||
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 = edge_distances(graph, new_grid)
|
||||
if m > n:
|
||||
t = "{:.2%} at: {} tries of {}v shuffle/swap" \
|
||||
.format((n - m) / m, fail + 1, num)
|
||||
print("\n" + t, end="")
|
||||
recalculate_sizes_from_v_deg(graph, new_grid)
|
||||
self.grid = new_grid
|
||||
else:
|
||||
fail += 1
|
||||
print(".", end='')
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
def edge_distances(graph, grid):
|
||||
total = 0
|
||||
for edge in graph.edges():
|
||||
if len(edge) == 2:
|
||||
a, b = edge
|
||||
d = PVector.dist(PVector(*grid[a]),
|
||||
PVector(*grid[b]))
|
||||
total += d
|
||||
return total
|
||||
|
||||
|
||||
def recalculate_sizes_from_v_deg(graph, grid):
|
||||
u = Grid.w / 10
|
||||
for k in grid.keys():
|
||||
grid[k][2] = u * graph.vertex_degree(k)
|
||||
return u
|
||||
|
||||
def v_dist(a, b):
|
||||
xa, ya, _ = a
|
||||
xb, yb, _ = b
|
||||
return dist(xa, ya, xb, yb)
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 90 KiB |
|
@ -0,0 +1,134 @@
|
|||
from __future__ import print_function, division
|
||||
from random import choice
|
||||
from graph import Graph
|
||||
from grid import * # setup_grid, grid_swap, edge_distances
|
||||
from arcs import var_bar
|
||||
|
||||
thread_running = False
|
||||
gx, gy = 0, 100
|
||||
viz_stat = False
|
||||
selected_v = None
|
||||
|
||||
def setup():
|
||||
size(500, 500)
|
||||
colorMode(HSB)
|
||||
textAlign(CENTER, CENTER)
|
||||
f = createFont("Source Code Pro Bold", 12)
|
||||
textFont(f)
|
||||
setup_graph()
|
||||
|
||||
def setup_graph(mode=0):
|
||||
# create a random graph and a dict of grid postions for its vertices
|
||||
global graph, grid, m, d
|
||||
graph = Graph.random_graph(range(64),
|
||||
connect_rate=.95,
|
||||
allow_loops=False,
|
||||
connected=True,
|
||||
allow_cyclic=False)
|
||||
grid = Grid(graph,
|
||||
width=width,
|
||||
height=width,
|
||||
margin=10,
|
||||
mode=mode)
|
||||
d = recalculate_sizes_from_v_deg(graph, grid)
|
||||
m = edge_distances(graph, grid) # "metric", sum of edge distances
|
||||
print("Cyclic: " + str(graph.is_cyclic()))
|
||||
|
||||
def draw():
|
||||
background(200)
|
||||
for e in graph.edges():
|
||||
va = e.pop()
|
||||
xa, ya, za = grid[va]
|
||||
if len(e) == 1:
|
||||
vb = e.pop()
|
||||
xb, yb, zb = grid[vb]
|
||||
fill(240)
|
||||
degree = ((za + zb) / 2) / d
|
||||
strokeWeight(map(degree, 1.5, 5, 5, 1))
|
||||
var_bar(xa, ya, xb, yb, za, zb)
|
||||
|
||||
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(x, y, 10)
|
||||
if viz_stat:
|
||||
fill(255)
|
||||
text("{}:{}".format(v, graph.vertex_degree(v)).upper(),
|
||||
x - 15, y - 5)
|
||||
fill(100)
|
||||
text(int(m / 200), 20, 20)
|
||||
|
||||
if selected_v:
|
||||
x, y, _ = grid[selected_v]
|
||||
stroke(0)
|
||||
strokeWeight(5)
|
||||
line(x, y, mouseX, mouseY)
|
||||
|
||||
|
||||
def keyTyped():
|
||||
global gx, gy, viz_stat
|
||||
if key == 'r':
|
||||
setup_graph(mode=0)
|
||||
gx, gy = 0, 100
|
||||
if key == 'e':
|
||||
setup_graph(mode=1)
|
||||
gx, gy = 0, 100
|
||||
if key == 'R':
|
||||
setup_graph(mode=2)
|
||||
gx, gy = 0, 100
|
||||
elif key == 'v':
|
||||
viz_stat = not viz_stat
|
||||
else:
|
||||
if not thread_running:
|
||||
thread("swapping")
|
||||
|
||||
def swapping():
|
||||
global grid, thread_running, gx, gy, m
|
||||
if str(key) not in 'sc23456789':
|
||||
return
|
||||
thread_running = True
|
||||
m = edge_distances(graph, grid)
|
||||
len_graph = len(graph)
|
||||
multiple = 1 if mousePressed else 100
|
||||
for _ in range(multiple):
|
||||
if key == 's':
|
||||
grid.swap(num=len_graph)
|
||||
if key in '234556789':
|
||||
grid.swap(num=int(key))
|
||||
n = edge_distances(graph, grid)
|
||||
gx += 1
|
||||
if n < m:
|
||||
gy -= gy * (m - n) / m
|
||||
m = n
|
||||
thread_running = False
|
||||
|
||||
def mouse_near(v):
|
||||
x, y, _ = grid[v]
|
||||
return dist(x, y, 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, u
|
||||
if selected_v:
|
||||
for v in grid.keys():
|
||||
if mouse_near(v):
|
||||
grid[selected_v], grid[v] = grid[v], grid[selected_v]
|
||||
u = recalculate_sizes_from_v_deg(graph, grid)
|
||||
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
|
|
@ -22,6 +22,12 @@
|
|||
|
||||
---
|
||||
|
||||

|
||||
|
||||
[sketch_2020_08_18a](https://github.com/villares/sketch-a-day/tree/master/2020/sketch_2020_08_18a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)]
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
[sketch_2020_08_17a](https://github.com/villares/sketch-a-day/tree/master/2020/sketch_2020_08_17a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)]
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
palavra = "Heineken"
|
||||
palavra_invertida = "" # começa vazia
|
||||
for letra in palavra:
|
||||
# soma letra da palavra uma por uma
|
||||
# formando string invertido
|
||||
palavra_invertida = letra + palavra_invertida
|
||||
|
||||
print(palavra_invertida)
|
||||
|
||||
print(reversed(palavra))
|
Ładowanie…
Reference in New Issue