+#!/usr/bin/env python3
+#
+# Draw a circle surrounded by other circles
+#
+# Copyright (C) 2018 Antonio Ospite <ao2@ao2.it>
+# SPDX-License-Identifier: WTFPL
+#
+# Using a formula from:
+# https://math.stackexchange.com/questions/12166/numbers-of-circles-around-a-circle
+
+from math import pi, sin, cos, degrees
+import svgwrite
+
+
+def calc_inner_circle_radius(outer_circles_radius, number_of_circles):
+ if outer_circles_radius <= 0:
+ raise ValueError("Radius of outer circles cannot be zero")
+
+ if number_of_circles < 3:
+ raise ValueError("Number of outer circles cannot be smaller than 3")
+
+ # Ratio between the inner circle and the outer circles
+ ratio = sin(pi / number_of_circles) / (1 - sin(pi / number_of_circles))
+
+ inner_circle_radius = outer_circles_radius / ratio
+
+ return inner_circle_radius
+
+
+def write_svg(filename, inner_circle_radius, outer_circles_radius,
+ number_of_circles, unit=""):
+ border = 10
+
+ width = height = (inner_circle_radius + outer_circles_radius + border) * 2
+
+ svg = svgwrite.Drawing(filename, profile='full',
+ size=(str(width) + unit, str(height) + unit),
+ viewBox=('0 0 %g %g') % (width, height))
+
+ cx_inner = cy_inner = width / 2
+
+ inner_circle = svgwrite.shapes.Circle(center=(cx_inner, cy_inner),
+ r=inner_circle_radius,
+ fill='none',
+ stroke='black',
+ stroke_width=0.5)
+ svg.add(inner_circle)
+
+ # Add a group for the first outer circle for extra flexibility.
+ outer_circle_group = svgwrite.container.Group()
+ svg.add(outer_circle_group)
+
+ cx_outer = cx_inner + sin(0) * (inner_circle_radius +
+ outer_circles_radius)
+ cy_outer = cy_inner + cos(0) * (inner_circle_radius +
+ outer_circles_radius)
+ outer_circle = svgwrite.shapes.Circle(center=(cx_outer, cy_outer),
+ r=outer_circles_radius,
+ fill='none',
+ stroke='black',
+ stroke_width=0.5)
+ outer_circle_group.add(outer_circle)
+
+ # Clone the group for the other outer circles to make it easier to keep
+ # visual symmetry by editing just the first group added above.
+ for i in range(1, number_of_circles):
+ theta = i * 2 * pi / number_of_circles
+ outer_circle_clone = svgwrite.container.Use(outer_circle_group,
+ insert=(0, 0),
+ transform="rotate(%f, %f, %f)" %
+ (degrees(theta),
+ cx_inner,
+ cy_inner))
+ svg.add(outer_circle_clone)
+
+ svg.save()
+
+
+def main():
+ outer_circles_radius = 2.5
+ number_of_circles = 22
+
+ inner_circle_radius = calc_inner_circle_radius(outer_circles_radius, number_of_circles)
+
+ write_svg("circle-surrounded-by-circles.svg", inner_circle_radius,
+ outer_circles_radius, number_of_circles, unit="mm")
+
+
+if __name__ == "__main__":
+ main()