Alexandre B A Villares 2020-02-11 22:58:11 -02:00
rodzic bfe4992fd3
commit 2d1f721c18
10 zmienionych plików z 420 dodań i 0 usunięć

Plik binarny nie jest wyświetlany.

Po

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

Plik binarny nie jest wyświetlany.

Po

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

Plik binarny nie jest wyświetlany.

Po

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

Plik binarny nie jest wyświetlany.

Po

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

Plik binarny nie jest wyświetlany.

Po

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

Plik binarny nie jest wyświetlany.

Po

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

Wyświetl plik

@ -0,0 +1,165 @@
def b_poly_arc_augmented(op_list, or_list=None, check_intersection=False):
if not op_list: return
if or_list == None:
r2_list = [0] * len(op_list)
else:
r2_list = or_list[:]
assert len(op_list) == len(r2_list), \
"Number of points and radii not the same"
# remove overlapping adjacent points
p_list, r_list = [], []
for i1, p1 in enumerate(op_list):
i2 = (i1 - 1)
p2, r2, r1 = op_list[i2], r2_list[i2], r2_list[i1]
if dist(p1[0], p1[1], p2[0], p2[1]) > 1: # or p1 != p2:
p_list.append(p1)
r_list.append(r1)
else:
r2_list[i2] = min(r1, r2)
# invert radius
for i1, p1 in enumerate(p_list):
i0 = (i1 - 1)
p0 = p_list[i0]
i2 = (i1 + 1) % len(p_list)
p2 = p_list[i2]
a = area(p0, p1, p2) / 1000.
if or_list == None:
r_list[i1] = a
else:
# if abs(a) < 1:
# r_list[i1] = r_list[i1] * abs(a)
if a <= 0:
r_list[i1] = -r_list[i1]
# reduce radius that won't fit
for i1, p1 in enumerate(p_list):
i2 = (i1 + 1) % len(p_list)
p2, r2, r1 = p_list[i2], r_list[i2], r_list[i1]
r_list[i1], r_list[i2] = reduce_radius(p1, p2, r1, r2)
# calculate the tangents
a_list = []
for i1, p1 in enumerate(p_list):
i2 = (i1 + 1) % len(p_list)
p2, r2, r1 = p_list[i2], r_list[i2], r_list[i1]
a = circ_circ_tangent(p1, p2, r1, r2)
a_list.append(a)
# draw
beginShape()
for i1, ia in enumerate(a_list):
i2 = (i1 + 1) % len(a_list)
p1, p2, r1, r2 = p_list[i1], p_list[i2], r_list[i1], r_list[i2]
a1, p11, p12 = ia
a2, p21, p22 = a_list[i2]
circle(p1[0], p1[1], 10, 10)
if a1 != None and a2 != None:
start = a1 if a1 < a2 else a1 - TWO_PI
if r2 < 0:
a2 = a2 - TWO_PI
b_arc(p2[0], p2[1], r2 * 2, r2 * 2, start, a2, mode=2)
else:
# when the the segment is smaller than the diference between
# radius, circ_circ_tangent won't renturn the angle
# ellipse(p2[0], p2[1], r2 * 2, r2 * 2) # debug
if a1:
vertex(p12[0], p12[1])
if a2:
vertex(p21[0], p21[1])
endShape(CLOSE)
def reduce_radius(p1, p2, r1, r2):
d = dist(p1[0], p1[1], p2[0], p2[1])
ri = abs(r1 - r2)
if d - ri <= 0:
if abs(r1) > abs(r2):
r1 = map(d, ri + 1, 0, r1, r2)
else:
r2 = map(d, ri + 1, 0, r2, r1)
return(r1, r2)
def circ_circ_tangent(p1, p2, r1, r2):
d = dist(p1[0], p1[1], p2[0], p2[1])
ri = r1 - r2
line_angle = atan2(p1[0] - p2[0], p2[1] - p1[1])
if d - abs(ri) >= 0:
theta = asin(ri / float(d))
x1 = -cos(line_angle + theta) * r1
y1 = -sin(line_angle + theta) * r1
x2 = -cos(line_angle + theta) * r2
y2 = -sin(line_angle + theta) * r2
return (line_angle + theta,
(p1[0] - x1, p1[1] - y1),
(p2[0] - x2, p2[1] - y2))
else:
return (None,
(p1[0], p1[1]),
(p2[0], p2[1]))
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()
def area(p0, p1, p2):
a = (p1[0] * (p2[1] - p0[1]) +
p2[0] * (p0[1] - p1[1]) +
p0[0] * (p1[1] - p2[1]))
return a

Wyświetl plik

@ -0,0 +1,164 @@
def intersecting(poly_points):
ed = edges(poly_points)
intersect = False
for p1, p2 in ed[::-1]:
for p3, p4 in ed[2::]:
# test only non consecutive edges
if (p1 != p3) and (p2 != p3) and (p1 != p4):
if line_instersect(Line(p1, p2), Line(p3, p4)):
intersect = True
break
return intersect
def is_inside(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_instersect(v, h):
return True
return False
def inter_lines(L, poly_points):
inter_points = []
for p1, p2 in edges(poly_points):
inter = line_instersect(Line(p1, p2), 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 p1, p2 in pairs:
if p2:
inter_lines.append(Line(PVector(p1.x, p1.y),
PVector(p2.x, p2.y)))
return inter_lines
class Line():
""" I should change this to a named tuple... """
def __init__(self, p1, p2):
self.p1 = PVector(*p1)
self.p2 = PVector(*p2)
def __getitem__(self, i):
return (self.p1, self.p2)[i]
def plot(self):
line(self.p1.x, self.p1.y, self.p2.x, self.p2.y)
def lerp(self, other, t):
p1 = PVector.lerp(self.p1, other.p1, t)
p2 = PVector.lerp(self.p2, other.p2, t)
return Line(p1, p2)
def line_instersect(line_a, line_b):
"""
code adapted from Bernardo Fontes
https://github.com/berinhard/sketches/
"""
x1, y1 = line_a.p1.x, line_a.p1.y
x2, y2 = line_a.p2.x, line_a.p2.y
x3, y3 = line_b.p1.x, line_b.p1.y
x4, y4 = line_b.p2.x, line_b.p2.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.p1.x + uA * (line_a.p2.x - line_a.p1.x)
y = line_a.p1.y + uA * (line_a.p2.y - line_a.p1.y)
return PVector(x, y)
# """
# code adapted from
# https://stackoverflow.com/questions/27745972/test-if-polylines-intersects-using-python
# """
# xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
# ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])
# def det(a, b):
# return a[0] * b[1] - a[1] * b[0]
# div = det(xdiff, ydiff)
# if div == 0:
# return None
# d = (det(*line1), det(*line2))
# x = det(d, xdiff) / div
# y = det(d, ydiff) / div
# return x, y
# return PVector(x, y)
def edges(poly_points):
return pairwise(poly_points) + [(poly_points[-1], poly_points[0])]
def pairwise(iterable):
import itertools
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)
def edges_as_sets(poly_points):
edge_set_pairs = set()
for edge in edges(poly_points):
s = frozenset(edge)
edge_set_pairs.add(s)
return frozenset(edge_set_pairs)
def min_max(points):
points = iter(points)
try:
p = points.next()
min_x, min_y = max_x, max_y = p.x, p.y
except StopIteration:
raise ValueError, "min_max requires at least one point"
for p in points:
if p.x < min_x:
min_x = p.x
elif p.x > max_x:
max_x = p.x
if p.y < min_y:
min_y = p.y
elif p.y > max_y:
max_y = p.y
return (PVector(min_x, min_y),
PVector(max_x, max_y))
def par_hatch(points, divisions, *sides):
vectors = [PVector(p.x, p.y) 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

Plik binarny nie jest wyświetlany.

Po

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

Wyświetl plik

@ -0,0 +1,91 @@
# Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day
from random import choice, sample, shuffle
from itertools import product, permutations, combinations
from forms import b_poly_arc_augmented
from line_geometry import *
NUM_POINTS = 6
BORDER = 100
SIZE = 100
RDS = 50
def setup():
size(500, 500)
global ensambles
ensambles = create_ensambles(create_points(), 30)
def create_ensambles(polys, r=1):
ens = []
for poly in polys:
for i in range(64):
rads = []
rad_opts = num_to_base(i, 2, 6)
for c in rad_opts:
if c == "0":
rads.append(-1 * r)
else:
rads.append(1 * r)
shuffle(rads)
print(rads)
ens.append((poly, rads))
return ens
def create_points():
""" non intersecting poly """
grid = list(product(range(BORDER, width - BORDER + 1, SIZE),
range(BORDER, height - BORDER + 1, SIZE)))
points = sample(grid, 6)
total = list(combinations(grid, 6))
polys = list(permutations(points, NUM_POINTS))
tested = set()
for poly in polys[:]:
edges = edges_as_sets(poly)
if edges not in tested and edges:
tested.add(edges)
else:
polys.remove(poly)
print("inicial: {}".format(len(polys)))
ni_polys = []
for poly in polys:
if not intersecting(poly):
ni_polys.append(poly)
print("sem auto-cruzar: {}".format(len(ni_polys)))
return list(ni_polys)
def draw():
background(200)
# b_poly_arc_augmented(ens, [30] * 6)
background(200)
scale(1/16.)
e = 0
total = len(ensambles)
for j in range(16):
for i in range(16):
pushMatrix()
translate(width * i, height * j)
if e < total:
noFill()
strokeWeight(16)
b_poly_arc_augmented(ensambles[e][0], ensambles[e][1])
popMatrix()
e += 1
def keyPressed():
if key == "p" or key == 'P':
saveFrame("####.png")
if key == ' ':
ensambles[:] = create_ensambles(create_points(), 30)
def num_to_base(num, base, pad=0):
BS = ""
for i in range(base):
BS += str(i)
result = ""
while num:
result += BS[num % base]
num //= base
while len(result) < pad:
result = result + "0"
return result[::-1]