Po Szerokość: | Wysokość: | Rozmiar: 56 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 56 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 62 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 56 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 48 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 60 KiB |
|
@ -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
|
|
@ -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
|
Po Szerokość: | Wysokość: | Rozmiar: 53 KiB |
|
@ -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]
|