From 417d980a80c7d266afca9e27a455b7d2b936625e Mon Sep 17 00:00:00 2001 From: Michael Fogleman Date: Fri, 13 Jan 2017 22:18:02 -0500 Subject: [PATCH] examples --- examples/circles.py | 42 ++++++++++++++++++++++++ examples/field.py | 70 ++++++++++++++++++++++++++++++++++++++++ examples/motor_test.py | 27 ++++++++++++++-- examples/poisson_disc.py | 57 ++++++++++++++++++++++++++++++++ examples/stars.py | 46 ++++++++++++++++++++++++++ 5 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 examples/circles.py create mode 100644 examples/field.py create mode 100644 examples/poisson_disc.py create mode 100644 examples/stars.py diff --git a/examples/circles.py b/examples/circles.py new file mode 100644 index 0000000..46b3f1d --- /dev/null +++ b/examples/circles.py @@ -0,0 +1,42 @@ +import axi +import math +import random + +def circle(cx, cy, r, n): + points = [] + for i in range(n + 1): + a = 2 * math.pi * i / n + x = cx + math.cos(a) * r + y = cy + math.sin(a) * r + points.append((x, y)) + return points + +def random_points_on_circle(cx, cy, r, n): + result = [] + a = random.random() * 2 * math.pi + da = 2 * math.pi / n + for i in range(n): + x = cx + math.cos(a) * r + y = cy + math.sin(a) * r + result.append((x, y)) + a += da + return result + +def add(x, y, r, paths): + if r < 1: + return + paths.append(circle(x, y, r, 90)) + points = random_points_on_circle(x, y, r, 2) + for x, y in points: + add(x, y, r / 2, paths) + +def main(): + paths = [] + add(0, 0, 64, paths) + drawing = axi.Drawing(paths).rotate_and_scale_to_fit(11, 8.5).sort_paths() + im = drawing.render() + im.write_to_png('out.png') + axi.draw(drawing) + +if __name__ == '__main__': + main() diff --git a/examples/field.py b/examples/field.py new file mode 100644 index 0000000..411284a --- /dev/null +++ b/examples/field.py @@ -0,0 +1,70 @@ +import axi +import random +import time + +from math import hypot, atan2, sin, cos, pi + +class Model(object): + def __init__(self): + self.particles = [] + + def add(self, x, y, m=1.0): + self.particles.append((x, y, m)) + + def test(self, x, y): + dx = 0 + dy = 0 + for px, py, pm in self.particles: + d = hypot(x - px, y - py) + if abs(d) < 1e-8: + return (0, 0) + angle = atan2(y - py, x - px) + dx += pm * cos(angle) / d + dy += pm * sin(angle) / d + angle = atan2(dy, dx) + pi / 2 + dx = cos(angle) + dy = sin(angle) + return (dx, dy) + +def polygon(sides, d): + x = 0.5 + y = 0.5 + rotation = 0 + angle = 2 * pi / sides + angles = [angle * i + rotation for i in range(sides)] + return [(x + cos(a) * d, y + sin(a) * d) for a in angles] + +def create_path(model, scale, ox, oy, x, y, m, length): + result = [] + n = int(length * 32) + f = float(length) / scale / n + for j in range(n): + result.append((ox + x * scale, oy + y * scale)) + dx, dy = model.test(x, y) + x += dx * f * m + y += dy * f * m + if x < 0 or y < 0 or x > 1 or y > 1: + break + return result + +def main(): + # axi.reset() + # return + + model = Model() + for x, y in polygon(5, 0.35): + model.add(x, y, 1) + model.add(0.5, 0.5, 0.1) + + paths = [] + for _ in range(500): + x = random.random() + y = random.random() + path = create_path(model, 8.5, 1.25, 0, x, y, -1, 3) + paths.append(path) + + drawing = axi.Drawing(paths).sort_paths().simplify_paths(0.001) + axi.draw(drawing) + +if __name__ == '__main__': + main() diff --git a/examples/motor_test.py b/examples/motor_test.py index b593a3c..3c18690 100644 --- a/examples/motor_test.py +++ b/examples/motor_test.py @@ -1,7 +1,17 @@ import axi +import math import random import time +def circle(cx, cy, radius, n, rotation): + points = [] + for i in range(n + 1): + a = 2 * math.pi * i / n + rotation + x = cx + math.cos(a) * radius + y = cy + math.sin(a) * radius + points.append((x, y)) + return points + def main(): d = axi.Device() d.pen_up() @@ -10,9 +20,20 @@ def main(): points = [] points.append((0, 0)) for i in range(10): - x = random.random() * 11 - y = random.random() * 8.5 - points.append((x, y)) + while True: + x = random.random() * 11 + y = random.random() * 8.5 + r = random.random() * 4 + if x - r < 0 or x + r > 11: + continue + if y - r < 0 or y + r > 8.5: + continue + break + rotation = random.random() * 2 * math.pi + c = circle(x, y, r, 90, rotation) + if random.random() < 0.5: + c = list(reversed(c)) + points.extend(c) points.append((0, 0)) d.run_path(points) d.wait() diff --git a/examples/poisson_disc.py b/examples/poisson_disc.py new file mode 100644 index 0000000..48e1933 --- /dev/null +++ b/examples/poisson_disc.py @@ -0,0 +1,57 @@ +import random + +from math import pi, sin, cos, hypot, floor + +class Grid(object): + def __init__(self, r): + self.r = r + self.size = r / 2 ** 0.5 + self.cells = {} + + def points(self): + return self.cells.values() + + def normalize(self, x, y): + i = int(floor(x / self.size)) + j = int(floor(y / self.size)) + return (i, j) + + def nearby(self, x, y): + result = [] + i, j = self.normalize(x, y) + for p in xrange(i - 2, i + 3): + for q in xrange(j - 2, j + 3): + if (p, q) in self.cells: + result.append(self.cells[(p, q)]) + return result + + def insert(self, x, y): + for bx, by in self.nearby(x, y): + if hypot(x - bx, y - by) < self.r: + return False + i, j = self.normalize(x, y) + self.cells[(i, j)] = (x, y) + return True + +def poisson_disc(x1, y1, x2, y2, r, n): + x = x1 + (x2 - x1) / 2.0 + y = y1 + (y2 - y1) / 2.0 + active = [(x, y)] + grid = Grid(r) + grid.insert(x, y) + while active: + ax, ay = random.choice(active) + for i in xrange(n): + a = random.random() * 2 * pi + d = random.random() * r + r + x = ax + cos(a) * d + y = ay + sin(a) * d + if x < x1 or y < y1 or x > x2 or y > y2: + continue + if not grid.insert(x, y): + continue + active.append((x, y)) + break + else: + active.remove((ax, ay)) + return grid.points() diff --git a/examples/stars.py b/examples/stars.py new file mode 100644 index 0000000..71873b7 --- /dev/null +++ b/examples/stars.py @@ -0,0 +1,46 @@ +import axi +import math +import random + +from axi.spatial import Index +from poisson_disc import poisson_disc + +def perturb_points(points, deviation): + result = [] + for x, y in points: + a = random.random() * 2 * math.pi + r = random.gauss(0, deviation) + x += math.cos(a) * r + y += math.sin(a) * r + result.append((x, y)) + return result + +def star(x, y, r): + sides = 5 + a = random.random() * 2 * math.pi + angle = 2 * math.pi / sides + angles = [angle * i + a for i in range(sides)] + points = [(x + math.cos(a) * r, y + math.sin(a) * r) for a in angles] + points = perturb_points(points, 0.04) + points.append(points[0]) + return points[0::2] + points[1::2] + +def main(): + points = poisson_disc(0, 0, 11, 8.5, 0.4, 64) + index = Index(points) + paths = [] + for x1, y1 in points: + index.remove((x1, y1)) + x2, y2 = index.nearest((x1, y1)) + index.insert((x1, y1)) + d = math.hypot(x2 - x1, y2 - y1) + paths.append(star(x1, y1, d / 2)) + drawing = axi.Drawing(paths) + drawing = drawing.remove_paths_outside(11, 8.5) + drawing = drawing.sort_paths() + # im = drawing.render() + # im.write_to_png('out.png') + axi.draw(drawing) + +if __name__ == '__main__': + main()