import rhinoscriptsyntax as rs import math #clear everything and start fresh rs.DeleteObjects(rs.AllObjects()) rs.EnableRedraw(False) #tower parameters tower_params = [ {"height": 600, "num_segments": 200, "base_radius": 7, "cosine_amplitude": 5, "cosine_frequency": 5, "reduction_height": 30, "reduction_factor": 0.7, "x_offset": 0, "y_offset": 0}, {"height": 650, "num_segments": 200, "base_radius": 7, "cosine_amplitude": 6, "cosine_frequency": 6, "reduction_height": 40, "reduction_factor": 0.75, "x_offset": 30, "y_offset": 0}, {"height": 550, "num_segments": 200, "base_radius": 7, "cosine_amplitude": 4, "cosine_frequency": 8, "reduction_height": 20, "reduction_factor": 0.8, "x_offset": 60, "y_offset": 0} ] #box parameters xsize = 25 ysize = 3 zsize = 4 num_boxes = 17 num_extra_rows = 5 # number of extra rows vertical_spacing = 5 #distance between rows shrink_factor = 0.65 #for other rows def modulated_radius(z, amplitude, frequency, base_radius, tower_height, reduction_height, reduction_factor): radius = base_radius + amplitude * math.cos(2 * math.pi * frequency * z / tower_height) #reduction at top if z > (tower_height - reduction_height): reduction = (z - (tower_height - reduction_height)) / reduction_height radius *= (1 - reduction * reduction_factor) #reduction at base elif z < reduction_height: reduction = (reduction_height - z) / reduction_height radius *= (1 - reduction * reduction_factor) return radius #find maximum radii def max_radius_heights(tower_height, cosine_frequency): heights = [] for k in range(cosine_frequency): #full cosine cycles z = (k * tower_height) / cosine_frequency #step every full cycle if z <= tower_height: heights.append(z) return heights #function to create tower based on parameters def create_tower(params): tower_height = params['height'] num_segments = params['num_segments'] base_radius = params['base_radius'] cosine_amplitude = params['cosine_amplitude'] cosine_frequency = params['cosine_frequency'] reduction_height = params['reduction_height'] reduction_factor = params['reduction_factor'] x_offset = params['x_offset'] y_offset = params['y_offset'] #create curves curves = [] for i in range(num_segments + 1): z = i * (tower_height / num_segments) radius = modulated_radius(z, cosine_amplitude, cosine_frequency, base_radius, tower_height, reduction_height, reduction_factor) circle = rs.AddCircle((x_offset, y_offset, z), radius) curves.append(circle) #loft loft = rs.AddLoftSrf(curves, loft_type=0) if loft: loft = loft[0] rs.CapPlanarHoles(loft) rs.DeleteObjects(curves) #scaled loft for hollow structure scaled_loft = rs.ScaleObject(loft, (x_offset, y_offset, 0), (0.9, 0.9, 1), copy=True) #first tower tower = None if scaled_loft: tower = rs.BooleanDifference(loft, scaled_loft) if tower: rs.DeleteObjects(scaled_loft) #max radius height insertion_z_values = max_radius_heights(tower_height, cosine_frequency) #create box corners = [[-xsize/2, -ysize/2, 0], [xsize/2, -ysize/2, 0], [xsize/2, ysize/2, 0], [-xsize/2, ysize/2, 0], [-xsize/2, -ysize/2, zsize], [xsize/2, -ysize/2, zsize], [xsize/2, ysize/2, zsize], [-xsize/2, ysize/2, zsize]] boxes_list = [] #place boxes at the max radius points + extra rows for insertion_z in insertion_z_values: for row_offset in range(-num_extra_rows, num_extra_rows + 1): new_z = insertion_z + (row_offset * vertical_spacing) #skip if new row is out of tower bounds if new_z < 0 or new_z > tower_height: continue #scale boxes in extra rows scale_factor = shrink_factor ** abs(row_offset) radius = modulated_radius(new_z, cosine_amplitude, cosine_frequency, base_radius, tower_height, reduction_height, reduction_factor) #compute arc length for equal spacing circumference = 2 * math.pi * radius arc_length = circumference / num_boxes angle_step = math.degrees(arc_length / radius) #convert to degrees for i in range(num_boxes): angle = angle_step * i #compute box position x = radius * math.cos(math.radians(angle)) y = radius * math.sin(math.radians(angle)) insertion = [x + x_offset, y + y_offset, new_z] #create, move, rotate box box = rs.AddBox(corners) rs.MoveObject(box, insertion) rotated_box = rs.RotateObject(box, insertion, angle, copy=False) if rotated_box: scaled_box = rs.ScaleObject(rotated_box, insertion, [scale_factor, scale_factor * 0.75, scale_factor * 0.75]) if scaled_box: boxes_list.append(scaled_box) if boxes_list: final_result = rs.BooleanDifference(tower, boxes_list) if final_result: rs.DeleteObjects(boxes_list) #create towers for params in tower_params: create_tower(params) rs.EnableRedraw(True)