2020_11_02polys

Polygons from 6 points on a 4x4 grid
main
Alexandre B A Villares 2020-11-02 19:24:41 -03:00
rodzic 0aaba32163
commit 5ced1e8e99
5 zmienionych plików z 200133 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,273 @@
# -*- coding: UTF-8 -*-
"""
From github.com/villares/villares/line_geometry.py
2020-09-25
2020-10-15 Fixed "line_instersection" typo, added dist() & removed TOLERANCE
2020-10-17 Added point_in_screen(), renamed poly() -> draw_poly()
2020-10-19 Fixed line_intersection typo, again :/, cleaned up stuff
"""
from __future__ import division
class Line():
def __init__(self, a, b):
self.a = PVector(*a)
self.b = PVector(*b)
def __getitem__(self, i):
return (self.a, self.b)[i]
def dist(self):
return PVector.dist(self.a, self.b)
def plot(self):
line(self.a.x, self.a.y, self.b.x, self.b.y)
draw = plot
def lerp(self, other, t):
a = PVector.lerp(self.a, other.a, t)
b = PVector.lerp(self.b, other.b, t)
return Line(a, b)
def intersect(self, other):
return line_intersect(self, other)
def contains_point(self, x, y, tolerance=0.1):
return point_over_line(x, y,
self[0][0], self[0][1],
self[1][0], self[1][1],
tolerance)
point_over = contains_point
def point_colinear(self, x, y, tolerance=EPSILON):
return points_are_colinear(x, y,
self[0][0], self[0][1],
self[1][0], self[1][1],
tolerance)
def line_intersect(line_a, line_b):
"""
code adapted from Bernardo Fontes
https://github.com/berinhard/sketches/
"""
x1, y1 = line_a.a.x, line_a.a.y
x2, y2 = line_a.b.x, line_a.b.y
x3, y3 = line_b.a.x, line_b.a.y
x4, y4 = line_b.b.x, line_b.b.y
try:
uA = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / \
((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
uB = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / \
((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
except ZeroDivisionError:
return
if not(0 <= uA <= 1 and 0 <= uB <= 1):
return
x = line_a.a.x + uA * (line_a.b.x - line_a.a.x)
y = line_a.a.y + uA * (line_a.b.y - line_a.a.y)
return PVector(x, y)
def point_over_line(px, py, lax, lay, lbx, lby,
tolerance=0.1):
"""
Check if point is over line using the sum of
the distances from the point to the line ends
(the result has to be near equal for True).
"""
ab = dist(lax, lay, lbx, lby)
pa = dist(lax, lay, px, py)
pb = dist(px, py, lbx, lby)
return (pa + pb) <= ab + tolerance
def points_are_colinear(ax, ay, bx, by, cx, cy,
tolerance=EPSILON):
"""
Test for colinearity by calculating the area
of a triangle formed by the 3 points.
"""
area = triangle_area((ax, ay), (bx, by), (cx, cy))
return abs(area) < tolerance
def triangle_area(a, b, c):
area = (a[0] * (b[1] - c[1]) +
b[0] * (c[1] - a[1]) +
c[0] * (a[1] - b[1]))
return area
# class Poly():
# def __init__(iterable):
# self.__points = [p for p in iterable]
# def __iter__(self):
# return iter(self.__points)
# def plot(self):
# poly(self)
# draw = poly
def draw_poly(points, holes=None, closed=True):
"""
Aceita como pontos sequencias de tuplas, lista ou vetores com (x, y) ou (x, y, z).
Note que `holes` espera uma sequencias de sequencias ou uma única sequencia de
pontos. Por default faz um polígono fechado.
"""
def depth(seq):
"""
usada para checar se temos um furo ou vários
devolve 2 para um furo, 3 para vários furos
"""
if (isinstance(seq, list) or
isinstance(seq, tuple) or
isinstance(seq, PVector)):
return 1 + max(depth(item) for item in seq)
else:
return 0
beginShape() # inicia o PShape
for p in points:
if len(p) == 2 or p[2] == 0:
vertex(p[0], p[1])
else:
vertex(*p) # desempacota pontos em 3d
# tratamento dos furos, se houver
holes = holes or [] # equivale a: holes if holes else []
if holes and depth(holes) == 2: # sequência única de pontos
holes = (holes,) # envolve em um tupla
for hole in holes: # para cada furo
beginContour() # inicia o furo
for p in hole:
if len(p) == 2 or p[2] == 0:
vertex(p[0], p[1])
else:
vertex(*p)
endContour() # final e um furo
# encerra o PShape
if closed:
endShape(CLOSE)
else:
endShape()
poly = draw_poly
def edges_as_sets(poly_points):
"""
Return a frozenset of poly edges as frozensets of 2 points.
"""
return frozenset(frozenset(edge) for edge in edges(poly_points))
def edges(poly_points):
"""
Return a list of edges (tuples containing pairs of points)
for a list of points that represent a closed polygon
"""
return pairwise(poly_points) + [(poly_points[-1], poly_points[0])]
def pairwise(iterable):
from itertools import tee
"s -> (s0, s1), (s1, s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def min_max(points):
"""
Return two PVectors with the most extreme coordinates,
resulting in "bounding box" corners.
"""
points = iter(points)
try:
p = points.next()
min_x, min_y = max_x, max_y = p[0], p[1]
except StopIteration:
raise ValueError, "min_max requires at least one point"
for p in points:
if p[0] < min_x:
min_x = p[0]
elif p[0] > max_x:
max_x = p[0]
if p[1] < min_y:
min_y = p[1]
elif p[1] > max_y:
max_y = p[1]
return (PVector(min_x, min_y),
PVector(max_x, max_y))
def par_hatch(points, divisions, *sides):
vectors = [PVector(p[0], p[1]) for p in points]
lines = []
if not sides:
sides = [0]
for s in sides:
a, b = vectors[-1 + s], vectors[+0 + s]
d, c = vectors[-2 + s], vectors[-3 + s]
for i in range(1, divisions):
s0 = PVector.lerp(a, b, i / float(divisions))
s1 = PVector.lerp(d, c, i / float(divisions))
lines.append(Line(s0, s1))
return lines
def is_poly_self_intersecting(poly_points):
ed = edges(poly_points)
intersect = False
for a, b in ed[::-1]:
for c, d in ed[2::]:
# test only non consecutive edges
if (a != c) and (b != c) and (a != d):
if line_intersect(Line(a, b), Line(c, d)):
intersect = True
break
return intersect
def point_inside_poly(x, y, poly_points):
min_, max_ = min_max(poly_points)
if x < min_.x or y < min_.y or x > max_.x or y > max_.y:
return False
a = PVector(x, min_.y)
b = PVector(x, max_.y)
v_lines = inter_lines(Line(a, b), poly_points)
if not v_lines:
return False
a = PVector(min_.x, y)
b = PVector(max_.x, y)
h_lines = inter_lines(Line(a, b), poly_points)
if not h_lines:
return False
for v in v_lines:
for h in h_lines:
if line_intersect(v, h):
return True
return False
def inter_lines(L, poly_points):
inter_points = []
for a, b in edges(poly_points):
inter = line_intersect(Line(a, b), L)
if inter:
inter_points.append(inter)
if not inter_points:
return []
inter_lines = []
if len(inter_points) > 1:
inter_points.sort()
pairs = zip(inter_points[::2], inter_points[1::2])
for a, b in pairs:
if b:
inter_lines.append(Line(PVector(a.x, a.y),
PVector(b.x, b.y)))
return inter_lines
def point_in_screen(p):
return 0 <= p[0] <= width and 0 <= p[1] <= height

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 188 KiB

Wyświetl plik

@ -0,0 +1,148 @@
"""
Explorando um experimento de geração de formas proposto por Leopoldo Leal
USE 'R' pre-calc poly paths for shape-maker pins
(non self-intersecting polys from 6 points in a grid)
OK - salvar em disco
OK - implementar no outro sketch pickle para ler os polígonos
OK - regra da exclusão de lines_shown ou colunas cheias
OK - exclusão de duplicaçoes com menos de 4 linhas ou 4 colunas
"""
import pickle
from random import choice, sample, shuffle
from itertools import product, permutations, combinations
from line_geometry import is_poly_self_intersecting, draw_poly, edges_as_sets
add_library('pdf')
DEBUG = False
SIZE, BORDER, HEIGHT = 100, 100, 500
NUM_POINTS = 6
poly_groups = []
reduction = 10
lines_shown = 15
save_pdf = False # press 'p' to save a PDF
pin_size = 50 # for drawing the points repr.
def setup():
size(1280, 640)
create_point_groups()
# recalc_polys() # press "SHIFT+R"
def draw():
global save_pdf # necessário para desligar o 'flag'
if save_pdf: # inicia a gravação
beginRecord(PDF, "####.pdf")
background(200)
scale(1. / reduction)
for line_n in range(len(poly_groups[:lines_shown])):
pushMatrix()
translate(0, HEIGHT * line_n)
for i in range(16):
# use the first poly from poly_groups to draw pins
draw_pins(i, poly_groups[line_n][0])
translate(500, 0)
for i in range(len(poly_groups[line_n])):
pushMatrix()
translate(HEIGHT * i, 0)
draw_polys(i, poly_groups[line_n])
popMatrix()
i += 1
popMatrix()
if save_pdf: # termina a gravação
endRecord()
save_pdf = False
def create_point_groups():
global grid, point_groups
grid = list(product(range(BORDER, HEIGHT - BORDER + 1, SIZE),
range(BORDER, HEIGHT - BORDER + 1, SIZE)))
naive_point_groups = list(combinations(grid, 6)) # [120::80]]
control_set = set()
point_groups = []
for points in naive_point_groups:
tp = translated_points(points)
if tp not in control_set:
control_set.add(tp)
point_groups.append(points)
print("number of 6 point groups:{}".format(len(point_groups)))
def translated_points(points):
"""Return points translated to 0,0"""
minX = min(x for x, y in points)
minY = min(y for x, y in points)
return tuple(sorted((x - minX, y - minY)
for x, y in points))
def recalc_polys():
global grid, point_groups, poly_groups
poly_groups = [create_polys(points) for points in point_groups]
poly_groups = [polys for polys in poly_groups if polys]
print("6 point groups that generated good poly paths:{}".format(len(poly_groups)))
def create_polys(points, no_four_rule=True):
"""
Generate non-intersecting polygons' from points.
- check_lines avoids polys with 4 points in a row or col.
"""
all_polys = list(permutations(points, NUM_POINTS))
tested, polys = set(), []
for poly in all_polys:
edges = edges_as_sets(poly)
if edges not in tested and edges:
tested.add(edges)
polys.append(poly)
new_polys = [poly for poly in polys
if (not no_four_rule or check_lines(poly))
and not is_poly_self_intersecting(poly)]
print("non-crossing paths: {}".format(len(new_polys)))
return list(new_polys)
def check_lines(poly):
"""return False for polys with 4 colinear points."""
from collections import Counter
xs = Counter()
ys = Counter()
for x, y in poly:
xs[x] += 1
ys[y] += 1
if xs.most_common(1)[0][1] > 3 or ys.most_common(1)[0][1] > 3:
return False # polígono ruim, tem line_n ou coluna cheia
else:
return True # polígono bom
def draw_polys(i, polys):
if i < len(polys):
fill(0)
draw_poly(polys[i])
def draw_pins(i, points):
# resetMatrix()
noStroke()
fill(255, 100)
if grid[i] in points:
fill(0, 100)
circle(grid[i][0],
grid[i][1], pin_size * 2)
def keyPressed():
global save_pdf
if key == "p" or key == 'P':
save_pdf = True
if key == 'R':
recalc_polys()
if key == "s":
with open("data/poly.data", "wb") as file_out:
pickle.dump(poly_groups, file_out)
println("poly groups saved")
if key == "l":
with open("data/poly.data", "rb") as file_in:
saved_project = pickle.load(file_in)
poly_groups[:] = saved_project
println("poly groups loaded: {}".format(len(poly_groups)))
if key == "L":
shuffle(poly_groups)

Wyświetl plik

@ -26,6 +26,12 @@ Here are listed some of the tools I have been using:
---
![sketch_2020_11_02polys](2020/sketch_2020_11_02polys/sketch_2020_11_02polys.jpeg)
[sketch_2020_11_02polys](https://github.com/villares/sketch-a-day/tree/master/2020/sketch_2020_11_02polys) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)]
---
![sketch_2020_11_01a](2020/sketch_2020_11_01a/sketch_2020_11_01a.gif)
[sketch_2020_11_01a](https://github.com/villares/sketch-a-day/tree/master/2020/sketch_2020_11_01a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)]