#!/usr/bin/env python3 # # Draw a circle surrounded by other circles # # Copyright (C) 2018 Antonio Ospite # 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()