import rhinoscriptsyntax as rs import random # Delete all objects allobjs = rs.AllObjects() rs.DeleteObjects(allobjs) def create_building(base_point, width, depth, height, facade_type): # Define base rectangle rect_pts = [ (base_point[0] - width / 2, base_point[1] - depth / 2, base_point[2]), (base_point[0] + width / 2, base_point[1] - depth / 2, base_point[2]), (base_point[0] + width / 2, base_point[1] + depth / 2, base_point[2]), (base_point[0] - width / 2, base_point[1] + depth / 2, base_point[2]), (base_point[0] - width / 2, base_point[1] - depth / 2, base_point[2]), ] # Create the base and top rectangles base_curve = rs.AddPolyline(rect_pts) top_pts = [(x, y, z + height) for x, y, z in rect_pts] top_curve = rs.AddPolyline(top_pts) # Loft between base and top curves building = rs.AddLoftSrf([base_curve, top_curve])[0] # Add a roof (cap the top of the building) rs.AddPlanarSrf(top_curve) # Apply facade apply_facade(base_point, width, depth, height, facade_type) # Clean up rs.DeleteObject(base_curve) rs.DeleteObject(top_curve) return building def apply_facade(base_point, width, depth, height, facade_type): if facade_type == "wavy": apply_wavy_facade(base_point, width, depth, height) elif facade_type == "angular": apply_angular_facade(base_point, width, depth, height) def apply_wavy_facade(base_point, width, depth, height): num_waves = 10 wave_height = width / 8 for i in range(num_waves): wave_x = base_point[0] - width / 2 + i * (width / num_waves) for j in range(int(height / (2 * wave_height))): z = base_point[2] + j * (2 * wave_height) points = [ (wave_x, base_point[1] - depth / 2, z), (wave_x + wave_height / 2, base_point[1] - depth / 2, z + wave_height), (wave_x, base_point[1] - depth / 2, z + 2 * wave_height) ] rs.AddPolyline(points) def apply_angular_facade(base_point, width, depth, height): num_sections = 5 for i in range(num_sections): section_height = height / num_sections z = base_point[2] + i * section_height angle_shift = random.uniform(-width / 4, width / 4) points = [ (base_point[0] - width / 2, base_point[1] - depth / 2 + angle_shift, z), (base_point[0] + width / 2, base_point[1] - depth / 2 - angle_shift, z), (base_point[0] + width / 2, base_point[1] + depth / 2 + angle_shift, z), (base_point[0] - width / 2, base_point[1] + depth / 2 - angle_shift, z), (base_point[0] - width / 2, base_point[1] - depth / 2 + angle_shift, z) ] rs.AddPolyline(points) def create_streets(): street_lines = [] main_street_width = 40 side_street_width = 10 # Create the main street (a wide straight line in the middle) main_street = rs.AddRectangle((-500, -main_street_width / 2, 0), 1000, main_street_width) street_lines.append(main_street) # Create side streets for x in range(-400, 500, 100): side_street = rs.AddRectangle((x, -500, 0), side_street_width, 1000) street_lines.append(side_street) return street_lines def place_buildings_along_streets(street_lines): building_positions = [] for street in street_lines: bbox = rs.BoundingBox(street) if not bbox: continue # Define the street edges x_min, y_min, _ = bbox[0] x_max, y_max, _ = bbox[2] # Place buildings on both sides of the street for side in [-1, 1]: # -1 for one side, 1 for the other for y in range(int(y_min), int(y_max), random.randint(50, 80)): # Randomize building dimensions width = random.uniform(10, 30) depth = random.uniform(10, 20) height = random.uniform(50, 150) # Offset buildings from the street offset = 15 * side jitter_x = random.uniform(-5, 5) jitter_y = random.uniform(-5, 5) base_point = (x_min + offset + jitter_x, y + jitter_y, 0) # Randomize facade type facade_type = random.choice(["wavy", "angular"]) # Create the building create_building(base_point, width, depth, height, facade_type) building_positions.append((base_point, width, depth)) return building_positions def place_random_buildings(building_positions): area_width = 1000 area_depth = 1000 num_random_buildings = 50 for _ in range(num_random_buildings): while True: # Randomize building base point base_x = random.uniform(-area_width / 2, area_width / 2) base_y = random.uniform(-area_depth / 2, area_depth / 2) base_point = (base_x, base_y, 0) # Randomize building dimensions width = random.uniform(10, 50) depth = random.uniform(10, 50) height = random.uniform(50, 300) # Check if the building overlaps with existing ones if not does_building_overlap(base_point, width, depth, building_positions): building_positions.append((base_point, width, depth)) break # Randomize facade type facade_type = random.choice(["wavy", "angular"]) # Create the building create_building(base_point, width, depth, height, facade_type) def does_building_overlap(base_point, width, depth, existing_positions): """ Check if a building overlaps with existing ones. """ for pos, w, d in existing_positions: if (abs(base_point[0] - pos[0]) < (width / 2 + w / 2) and abs(base_point[1] - pos[1]) < (depth / 2 + d / 2)): return True return False def add_landmarks(): landmarks = [ {"width": 70, "depth": 70, "height": 500, "location": (-200, 200, 0), "facade_type": "angular"}, {"width": 50, "depth": 50, "height": 400, "location": (300, -300, 0), "facade_type": "wavy"}, {"width": 60, "depth": 60, "height": 450, "location": (0, 0, 0), "facade_type": "angular"} ] for landmark in landmarks: create_building(landmark["location"], landmark["width"], landmark["depth"], landmark["height"], landmark["facade_type"]) if __name__ == "__main__": street_lines = create_streets() building_positions = place_buildings_along_streets(street_lines) place_random_buildings(building_positions) add_landmarks() rs.EnableRedraw(True)