Pookkalam by Bichu Ben

Code

#Code_a_Pookalam - Bichu Ben Kuruvilla

#defining all properties as dictionaries which are later passed to the member functions of pookalam object
#properties of the base square    
base_square = {
    "height":300,
    "width":300,
    "fill":"rgba(0,0,0,0.85)",
    "stroke":"none"
}

#properties of the concentric sectors at the outer edge of the pookalam 
outer_concentric_sectors = {
    "concentric_count":5,
    "sectors_count":12,
    "max_radius":130,
    "radius_gap":7,
    "min_start_angle":8,
    "min_end_angle":22,
    "angle_gap":2,
    "fill":["red","orange","gold","lemonchiffon","crimson"],
    "stroke":"none"
}

#properties of the middle circle of the pookalam
middle_circle = {
    "radius":95,
    "fill":"crimson",
    "stroke":"none"
}

#middle concentric sectors
middle_concentric_sectors = {
    "concentric_count":6,
    "stroke":["red","orange","lemonchiffon","orange","red","lemonchiffon"],
    "initial_upper":95,
    "initial_lower":90,
    "rotate_angle":90,
    "outer_sector_start":-37.5,
    "outer_sector_end":52.5,
}

#properties to create a round of diamonds around the inner circle
circle_of_diamonds = {
    "fill":["gold","orange","lemonchiffon"],
    "stroke":["none","none","none"],
    "width":[35,25,15],
    "height":[70,60,50],
    "repeat_per_round":[12,12,12],
    "no_of_rounds":3,
}

#properties of the inner circle
inner_circle = {
    "radius":22,
    "fill":"crimson",
    "stroke":"crimson"
}

#properties of the merged squares inside inner circle
merged_squares = {
    "first_height":22,
    "first_width":22,
    "first_fill":"gold",
    "first_stroke":"none",
    "first_rotate_angle":45,
    "second_points":[[0,0],[0,12],[-12,12],[-12,4],[-6,9]],
    "second_fill":"orange",
    "second_stroke":"none",
    "second_no_of_repeat":4,
    "second_rotate_angle":90
}


class pookalam:
    
    #constructor
    def __init__(self):
        #all the shapes are appended to shape[] and are combined at the end
        self.shape = []
    
    #create the a square by passing properties as a dictionary 
    def square(self, dict):
        square = rectangle(h = dict["height"], w= dict["width"], fill= dict["fill"], stroke= dict["stroke"])
        self.shape.append(square)
    
    #create a circle by passing properties as a dictionary    
    def circle(self, dict):
        sole_circle = circle(r=dict["radius"], fill=dict["fill"], stroke=dict["stroke"])
        self.shape.append(sole_circle)
    
    
    #create the concentric sectors by passing properties as a dictionary
    def outer_concentric_sectors(self, dict):
        radius = dict["max_radius"]
        sector_angular_width = 360/dict["sectors_count"]
        
        #create circles starting from the outermost concentric one
        for circle_number in range(dict["concentric_count"]):
            sole_circle = circle(r=radius, fill=dict["fill"][circle_number], stroke=dict["stroke"])
            self.shape.append(sole_circle)
            
            #angles to determine limits to which lines must be drawn
            start_angle = sector_angular_width + dict["min_start_angle"]
            end_angle = sector_angular_width + dict["min_end_angle"]
            
            #multiple lines are draw to the left and right of each sector to create a thick boundary
            sole_line = line(x1=0, y1=0, x2=dict["max_radius"], y2=0, stroke=dict["fill"][circle_number], stroke_width=2)
            lines = sole_line | rotate(start_angle) | repeat(dict["angle_gap"]*4, rotate(angle=0.25)) 
            sole_sector = lines
            sole_line = line(x1=0, y1=0, x2=dict["max_radius"], y2=0, stroke=dict["fill"][circle_number])
            lines = sole_line | rotate(end_angle) | repeat(dict["angle_gap"]*4, rotate(angle=-0.25))
            sole_sector = sole_sector + lines
            
            #generate multiple sectors from one sector
            sectors = sole_sector | repeat(dict["sectors_count"], rotate(angle=sector_angular_width))
            self.shape.append(sectors)
            
            #with each interior circle the width of the sector increases
            dict["min_start_angle"] = dict["min_start_angle"] - dict["angle_gap"]
            dict["min_end_angle"] = dict["min_end_angle"] + dict["angle_gap"]
            radius = radius-dict["radius_gap"]
    
    
    #function to create the equidistant concentric sectors in the middle section that together forms a concentric circle
    def middle_concentric_sectors(self, dict):
        #find angular width occupied by a group of adjacent sectors such that all colours in dict["stroke"] are used
        sector_angular_width = dict["outer_sector_end"]-dict["outer_sector_start"]
        y=90
        #repeat for each layer of sector
        for i in range(dict["concentric_count"]):
            sole_sector = line(x1=0, y1=0, x2=0, y2=0)
            
            #each group of sectors having all the required colors are created
            for j in range(len(dict["stroke"])):
                sole_line = line(x1=0, y1=dict["initial_lower"], x2=0, y2=dict["initial_upper"], stroke=dict["stroke"][j], stroke_width=3)
                sole_line = sole_line | rotate(dict["outer_sector_start"]+ (j*sector_angular_width/6) )
                sole_sector = sole_sector + (sole_line | repeat((sector_angular_width/6), rotate(angle=1)))
            
            #each group is repeated to complete a circle
            sectors = sole_sector | repeat(360/dict["rotate_angle"], rotate(angle=dict["rotate_angle"]))
            self.shape.append(sectors)
            
            #reducing y values for next layer of sectors
            dict["initial_upper"] = dict["initial_upper"]-9
            dict["initial_lower"] = dict["initial_lower"]-9
        
          
    #function to create the diamond pattern
    def circle_of_diamonds(self, dict):
        #an iteration for each circlular round of diamonds
        for i in range(dict["no_of_rounds"]):
            #each diamond shape has 4 points
            p1 = point(x=0, y=0)
            p2 = point(x=-dict["width"][i]/2, y=2*dict["height"][i]/3)
            p3 = point(x=0, y=dict["height"][i])
            p4 = point(x=dict["width"][i]/2, y=2*dict["height"][i]/3)
            diamond = polygon([p1,p2,p3,p4], fill=dict["fill"][i], stroke=dict["stroke"][i])
            
            #a round of diamonds are created using a single diamond
            diamonds = diamond | repeat(dict["repeat_per_round"][i], rotate(angle=360/dict["repeat_per_round"][i]))
            self.shape.append(diamonds)
    
    
    #function to create pattern that looks like merged squares inside inner circle
    def merged_squares(self, dict):
        p = []
        #the first(bottom) square is created and rotated
        first_square = rectangle(h= dict["first_height"], w= dict["first_width"], fill= dict["first_fill"], stroke= dict["first_stroke"])
        first_square = first_square | rotate(dict["first_rotate_angle"])
        self.shape.append(first_square)
        
        #create a single part of the second square using some points
        for i in dict["second_points"]:
            p.append(point(x=i[0], y=i[1]))
        partial_square = polygon(p, fill=dict["second_fill"], stroke=dict["second_stroke"])
        
        #generate the second square from it's partial parts 
        second_square = partial_square | repeat(dict["second_no_of_repeat"], rotate(angle=dict["second_rotate_angle"]))
        self.shape.append(second_square)
        
    
    #display all the shapes present in shape[]
    def display(self):
        show(combine(self.shape))
        
        
#create pookalam object and call member functions
obj = pookalam()
obj.square(base_square)
obj.outer_concentric_sectors(outer_concentric_sectors)
obj.circle(middle_circle)
obj.middle_concentric_sectors(middle_concentric_sectors)
obj.circle_of_diamonds(circle_of_diamonds)
obj.circle(inner_circle)
obj.merged_squares(merged_squares)
obj.display()