import rhinoscriptsyntax as rs import random as ran rs.DeleteObjects(rs.AllObjects()) #box dimensions xsize = 50 ysize = 50 zsize = 200 uxsize = 10 uysize = 10 uzsize = 30 qxsize_min = 3 qxsize_max = 7 qysize_min = 3 qysize_max = 7 qzsize = 30 def make_box(insertion=[0, 0, 0], xsize=10, ysize=10, zsize=10): corners = [[0, 0, 0], [xsize, 0, 0], [xsize, ysize, 0], [0, ysize, 0], [0, 0, zsize], [xsize, 0, zsize], [xsize, ysize, zsize], [0, ysize, zsize]] box = rs.AddBox(corners) rs.MoveObjects(box, (-xsize / 2, -ysize / 2, 0)) rs.MoveObject(box, insertion) return box def make_sphere(center=[0, 0, 0], radius=1): return rs.AddSphere(center, radius) #spheres at each corner of the mainbody corners = [ [-xsize / 2, -ysize / 2, 30], [xsize / 2, -ysize / 2, 30], [xsize / 2, ysize / 2, 30], [-xsize / 2, ysize / 2, 30], [-xsize / 2, -ysize / 2, 30 + zsize], [xsize / 2, -ysize / 2, 30 + zsize], [xsize / 2, ysize / 2, 30 + zsize], [-xsize / 2, ysize / 2, 30 + zsize] ] for corner in corners: make_sphere(corner, 1) def make_cylinder(center=[0, 0, 0], radius=5, height=10): base_circle = rs.AddCircle(center, radius) cylinder = rs.ExtrudeCurveStraight(base_circle, center, [center[0], center[1], center[2] + height]) rs.CapPlanarHoles(cylinder) rs.DeleteObject(base_circle) return cylinder #mainbody mainbox = make_box([0, 0, 30], xsize, ysize, zsize) #secondary body (lower box) lower_box = make_box([0, 0, 0], uxsize, uysize, uzsize) #support pillars def create_support_pillars(): pillar_height = 30 num_pillars = 11 pillar_positions = [] #position for 4 corner pillars corners = [ [-xsize / 2 + qxsize_max / 2, -ysize / 2 + qysize_max / 2, pillar_height / 2], [xsize / 2 - qxsize_max / 2, -ysize / 2 + qysize_max / 2, pillar_height / 2], [xsize / 2 - qxsize_max / 2, ysize / 2 - qysize_max / 2, pillar_height / 2], [-xsize / 2 + qxsize_max / 2, ysize / 2 - qysize_max / 2, pillar_height / 2] ] #4 corner pillars for corner in corners: pillar_positions.append(corner) #random for other pillars while len(pillar_positions) < num_pillars: candidate_position = [ ran.uniform(-xsize / 2 + qxsize_max / 2, xsize / 2 - qxsize_max / 2), ran.uniform(-ysize / 2 + qysize_max / 2, ysize / 2 - qysize_max / 2), pillar_height / 2 ] #check for overlaps under lower box in_lower_box_footprint = ( abs(candidate_position[0]) < uxsize / 2 and abs(candidate_position[1]) < uysize / 2 ) if in_lower_box_footprint: continue #check overlaps with other pillars overlap = False for existing in pillar_positions: distance = ((candidate_position[0] - existing[0]) ** 2 + (candidate_position[1] - existing[1]) ** 2) ** 0.5 if distance < max(qxsize_max, qysize_max): overlap = True break if not overlap: pillar_positions.append(candidate_position) #make the pillars for pos in pillar_positions: random_qxsize = ran.uniform(qxsize_min, qxsize_max) random_qysize = ran.uniform(qysize_min, qysize_max) make_box([pos[0], pos[1], 0], random_qxsize, random_qysize, pillar_height) def make_hollow_frame(insertion, width, height, rotation_angle=0, offset_x=0, offset_y=0, offset_z=0): frame_thickness = 1.0 depth = 1 outer_width = width outer_height = height inner_width = width - 2 * frame_thickness inner_height = height - 2 * frame_thickness #outer frame corner points outer_frame_corners = [ [insertion[0] - outer_width / 2, insertion[1] - depth / 2, insertion[2] - outer_height / 2], [insertion[0] + outer_width / 2, insertion[1] - depth / 2, insertion[2] - outer_height / 2], [insertion[0] + outer_width / 2, insertion[1] - depth / 2, insertion[2] + outer_height / 2], [insertion[0] - outer_width / 2, insertion[1] - depth / 2, insertion[2] + outer_height / 2], [insertion[0] - outer_width / 2, insertion[1] + depth / 2, insertion[2] - outer_height / 2], [insertion[0] + outer_width / 2, insertion[1] + depth / 2, insertion[2] - outer_height / 2], [insertion[0] + outer_width / 2, insertion[1] + depth / 2, insertion[2] + outer_height / 2], [insertion[0] - outer_width / 2, insertion[1] + depth / 2, insertion[2] + outer_height / 2] ] #inner frame corner points inner_frame_corners = [ [insertion[0] - inner_width / 2, insertion[1] - depth / 2, insertion[2] - inner_height / 2], [insertion[0] + inner_width / 2, insertion[1] - depth / 2, insertion[2] - inner_height / 2], [insertion[0] + inner_width / 2, insertion[1] - depth / 2, insertion[2] + inner_height / 2], [insertion[0] - inner_width / 2, insertion[1] - depth / 2, insertion[2] + inner_height / 2], [insertion[0] - inner_width / 2, insertion[1] + depth / 2, insertion[2] - inner_height / 2], [insertion[0] + inner_width / 2, insertion[1] + depth / 2, insertion[2] - inner_height / 2], [insertion[0] + inner_width / 2, insertion[1] + depth / 2, insertion[2] + inner_height / 2], [insertion[0] - inner_width / 2, insertion[1] + depth / 2, insertion[2] + inner_height / 2] ] outer_frame = rs.AddBox(outer_frame_corners) inner_frame = rs.AddBox(inner_frame_corners) hollow_frame = rs.BooleanDifference(outer_frame, inner_frame) if rotation_angle != 0: rs.RotateObject(hollow_frame, insertion, rotation_angle, [0, 0, 1]) rs.MoveObject(hollow_frame, (offset_x, offset_y, offset_z)) return hollow_frame def create_grid_and_place_cubes(): grid_size = 10 num_cubes = 45 #sides of the mainbody sides = [ {"start": [-xsize / 2, -ysize / 2, 30], "axis1": "x", "axis2": "z", "length1": xsize, "length2": zsize, "offset_y": -5, "offset_z": 5, "rotation_angle": 0}, {"start": [xsize / 2, -ysize / 2, 30], "axis1": "y", "axis2": "z", "length1": ysize, "length2": zsize, "offset_x": 5, "offset_z": 5, "rotation_angle": 90}, {"start": [-xsize / 2, ysize / 2, 30], "axis1": "x", "axis2": "z", "length1": xsize, "length2": zsize, "offset_y": 5, "offset_z": 5, "rotation_angle": 0}, {"start": [-xsize / 2, -ysize / 2, 30], "axis1": "y", "axis2": "z", "length1": ysize, "length2": zsize, "offset_x": -5, "offset_z": 5, "rotation_angle": 90} ] for side in sides: start = side["start"] axis1 = side["axis1"] axis2 = side["axis2"] length1 = side["length1"] length2 = side["length2"] offset_x = side.get("offset_x", 0) offset_y = side.get("offset_y", 0) offset_z = side.get("offset_z", 0) rotation_angle = side.get("rotation_angle", 0) #make grid cells grid_cells = [] for i in range(int(length1 / grid_size)): for j in range(int(length2 / grid_size)): if axis1 == "x" and axis2 == "z": cell_center = [ start[0] + i * grid_size + grid_size / 2, start[1], start[2] + j * grid_size + grid_size / 2 ] elif axis1 == "y" and axis2 == "z": cell_center = [ start[0], start[1] + i * grid_size + grid_size / 2, start[2] + j * grid_size + grid_size / 2 ] grid_cells.append(cell_center) #cubes on grid cells for _ in range(num_cubes): if grid_cells: random_cell = ran.choice(grid_cells) grid_cells.remove(random_cell) #cube size within grid cells cube_xsize = min(grid_size, 10) cube_ysize = min(grid_size, 10) cube_zsize = 10 #cube stays below z=230 cube_position = random_cell[:] cube_position[2] += cube_zsize / 2 if cube_position[2] + cube_zsize / 2 > 225: cube_position[2] = 225 - cube_zsize / 2 main_cube = make_box(cube_position, cube_xsize, cube_ysize, cube_zsize) #rand for additional cube if ran.random() < 0.4: additional_position = cube_position[:] #random direction direction = ran.choice(["x", "y"]) if direction == "x": additional_position[0] += cube_xsize if cube_position[0] >= 0 else -cube_xsize elif direction == "y": additional_position[1] += cube_ysize if cube_position[1] >= 0 else -cube_ysize make_box(additional_position, cube_xsize, cube_ysize, cube_zsize) make_hollow_frame(additional_position, cube_xsize, cube_zsize, rotation_angle, offset_x, offset_y, offset_z) def place_cylinders_on_top(): num_cylinders = 10 cylinder_positions = [] cylinder_radii = [] while len(cylinder_positions) < num_cylinders: random_radius = ran.uniform(1, 7) #position cylinders candidate_position = [ ran.uniform(-xsize / 2 + random_radius, xsize / 2 - random_radius), ran.uniform(-ysize / 2 + random_radius, ysize / 2 - random_radius), 30 + zsize ] #overlap with other cylinders overlap = False for i, existing in enumerate(cylinder_positions): existing_radius = cylinder_radii[i] distance = ((candidate_position[0] - existing[0]) ** 2 + (candidate_position[1] - existing[1]) ** 2) ** 0.5 if distance < (random_radius + existing_radius): overlap = True break if not overlap: cylinder_positions.append(candidate_position) cylinder_radii.append(random_radius) #cylinders for pos, radius in zip(cylinder_positions, cylinder_radii): random_height = ran.uniform(6, 35) make_cylinder(pos, radius, random_height) def create_edges(): edges = [ #bottom [[-xsize / 2, -ysize / 2, 30], [xsize / 2, -ysize / 2, 30]], [[xsize / 2, -ysize / 2, 30], [xsize / 2, ysize / 2, 30]], [[xsize / 2, ysize / 2, 30], [-xsize / 2, ysize / 2, 30]], [[-xsize / 2, ysize / 2, 30], [-xsize / 2, -ysize / 2, 30]], #top [[-xsize / 2, -ysize / 2, 230], [xsize / 2, -ysize / 2, 230]], [[xsize / 2, -ysize / 2, 230], [xsize / 2, ysize / 2, 230]], [[xsize / 2, ysize / 2, 230], [-xsize / 2, ysize / 2, 230]], [[-xsize / 2, ysize / 2, 230], [-xsize / 2, -ysize / 2, 230]], #vertical [[-xsize / 2, -ysize / 2, 30], [-xsize / 2, -ysize / 2, 230]], [[xsize / 2, -ysize / 2, 30], [xsize / 2, -ysize / 2, 230]], [[xsize / 2, ysize / 2, 30], [xsize / 2, ysize / 2, 230]], [[-xsize / 2, ysize / 2, 30], [-xsize / 2, ysize / 2, 230]] ] #horizontal edge for i in range(20): z_position = 30 + (i + 1) * 10 if z_position > 230: break #front edge_start_front = [-xsize / 2, -ysize / 2, z_position] edge_end_front = [xsize / 2, -ysize / 2, z_position] edges.append([edge_start_front, edge_end_front]) #right edge_start_right = [xsize / 2, -ysize / 2, z_position] edge_end_right = [xsize / 2, ysize / 2, z_position] edges.append([edge_start_right, edge_end_right]) #back edge_start_back = [xsize / 2, ysize / 2, z_position] edge_end_back = [-xsize / 2, ysize / 2, z_position] edges.append([edge_start_back, edge_end_back]) #left edge_start_left = [-xsize / 2, ysize / 2, z_position] edge_end_left = [-xsize / 2, -ysize / 2, z_position] edges.append([edge_start_left, edge_end_left]) #vertical edges for i in range(4): x_offset = -xsize / 2 + (i + 1) * (xsize / 5) y_offset = -ysize / 2 + (i + 1) * (ysize / 5) #front edges.append([[x_offset, -ysize / 2, 30], [x_offset, -ysize / 2, 230]]) #back edges.append([[x_offset, ysize / 2, 30], [x_offset, ysize / 2, 230]]) #right edges.append([[xsize / 2, y_offset, 30], [xsize / 2, y_offset, 230]]) #left edges.append([[-xsize / 2, y_offset, 30], [-xsize / 2, y_offset, 230]]) for edge in edges: line = rs.AddLine(edge[0], edge[1]) rs.AddPipe(line, 0, 1) create_support_pillars() create_grid_and_place_cubes() place_cylinders_on_top() create_edges() make_sphere()