Advertisement


Programmatically creating radiating rows of dots


Question

I want to create a speaker hole pattern like this: enter image description here

But I'm not sure where to start. Can this be achieved without laborious positioning in Illustrator or similar software?

2016/10/06
1
17
10/6/2016 12:43:00 PM

Accepted Answer

I'll add my method, since it seems to me like it's the simplest. Basically, you:

  1. Computationally generate the circles in Python
  2. Render them as a simple SVG file
  3. Open file in Illustrator

Here is the Python script (requires svgwrite and math):

"""
This script has two purposes:

- Simple demonstration of using Python (specifically the svgwrite library) to create an SVG file
- Answer the question http://graphicdesign.stackexchange.com/q/56200/21332
"""

# n[x] should give the number of circles at a distance of (x+1)*d from the center
d = 30
n = [8, 16, 20, 20, 20]

r = 7  # radius of each circle

# Calculate the center points of each circle
circles = [(0, 0)]  # There is always one circle in the middle

import math
for i in range(0, len(n)):
    m = n[i]  # m is the number of circle in this "row", i is the number of the row
    for j in range(0, m):  # for each circle...
        phi = 2*math.pi*j/m  # Calculate the angle at which the circle will be

        # Convert polar coordinates to cartesian
        x = d*(i+1)*math.cos(phi)
        y = d*(i+1)*math.sin(phi)

        circles.append((x, y))

# Write circles to SVG
import svgwrite

# Determine correct size of drawing
width = max([c[0] for c in circles])*2.2
height = max([c[1] for c in circles])*2.2

dwg = svgwrite.Drawing('demo.svg', size = (width, height))  # output will be in the same folder as this script

# offsets for shifting all circles so that the SVG can be easily viewed in browser
x_offset = min([c[0] for c in circles])*1.1
y_offset = min([c[1] for c in circles])*1.1

for c in circles:
    adjusted_x = c[0] - x_offset
    adjusted_y = c[1] - y_offset

    dwg.add(svgwrite.shapes.Circle((adjusted_x, adjusted_y), r))

# Save the file
dwg.save()

# Print SVG source to console
print(dwg.tostring())

It will create an SVG file in the directory it's in. You can open this in a browser:

enter image description here

Or in Illustrator:

enter image description here

You should use a bigger Illustrator window than me, though, mine was a bit too small to work with comfortably...

If you can't have Python scripts create files (maybe running this in an online Python interpreter) then simply comment out dwg.save(). The last line prints the contents of the SVG to console, you can paste this into Notepad, then save as my file.svg.

I got carried away and added a few "neat" features, like:

  • Make sure the circles are properly centered, so that circles with negative coordinates don't get clipped when viewing in your browser.
  • Resize the SVG canvas.

You could easily leave these out, since Illustrator doesn't hide objects outside canvas bounds and allows you to resize the canvas manually:

enter image description here

2015/07/10
9
7/10/2015 1:55:00 AM

You dont actually specify whether or not the image is something you have generated yourself in TK, have at hand or not. If you already have this code then you can export the TK applications canvas as EPS and open it in illustrator. All you need to do is call canvas.postscript().

If you want to use TK

Simple sample in python 2:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from Tkinter import *
import math

def circle(c, x, y, r=10):
    return c.create_oval(x-r, y-r, x+r, y+r, width=0, fill="black")

def draw_circles(c, num, r):
    step = (2.0*math.pi)/float(num)
    for i in range(num):
        x = 400 + r * math.sin(i*step)
        y = 400 + r * math.cos(i*step)
        circle(c, x, y)


main_window = Tk()
main_window.title('Pattern to EPS')
canvas = Canvas(main_window,
                    width=800, height=800, 
                    bg = 'white')

circle(canvas, 400, 400)
for i in range(1, 6):
    draw_circles(canvas, i*8, i*60)

canvas.pack()

# next line generates a eps file
canvas.postscript(file = "pattern.eps",  width=800, height=800 )

# uncomment next line if you want to see the tk window
# main_window.mainloop()

This results in a file named "patten.eps".

result of pattern.eps

Image 1: Opening the generated EPS in illustrator.

You can do this in extendScript, SVG or directly by writing the EPS program all of which are easy to do (see appendix below for some examples). See following posts for resources:

PS: I dont know if its worth scripting as it takes about 3 minutes to draw them in with help of rotate tool and Ctrl+D

Parametric blend in Illustrator

  1. Draw a circle.
  2. duplicate it.
  3. blend the circles
  4. draw another circle that represents the spine, cut it in one point
  5. Select both blend and circle and do Object → Blend → Replace spine
  6. adjust the number of spheres with Object → Blend → Blend Options... minus one object.
  7. Copy and adjust spne circles size and options. done

one ring

Image 2: One ring with method above


Appendix 1: With manually written EPS

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 800 800
%%Title: pattern
%%Creator: joojaa
%%CreationDate:  2015-07-08
%%EndComments

/c {newpath 10 0 360 arc closepath fill} def
/cr {
    dup 8 mul 2 dict begin /i exch def /r exch 60 mul def 
    1 1 i {360 i div mul dup sin exch cos r mul exch r mul c} for 
    end
} def

400 400 translate
0 0 c
1 1 6 {cr} for
%%EOF

Appendix 2: ExtendScript example

#target illustrator

var doc = app.activeDocument; 

function circle(x,y) {
    doc.pathItems.ellipse(x+5,y-5,10,10);
}

function draw_circles(num, r){
    var step = (2.0*Math.PI)/num;
    for (var i = 0; i < num; i++) {
        var x = -200 + r * Math.sin(i*step);
        var y = 200 + r * Math.cos(i*step);
        circle(x, y);
    }
}

circle(-200,200);
for (var i = 1; i <= 6; i++) {
    draw_circles(i*8, i*30);
}
2017/04/13