# -*- coding: utf-8 -*- import rhinoscriptsyntax as rs def clear_scene(): """Loescht alle Objekte in der Szene.""" all_objects = rs.AllObjects() if all_objects: rs.DeleteObjects(all_objects) def create_complex_cube(params): """Erstellt einen komplexen Würfel mit Verzierungen gemäß den angegebenen Parametern.""" # Parameter auslesen main_cube_length = params["main_cube_length"] small_cube_factor = params["small_cube_factor"] corner_offset = params["corner_offset"] pipe_radius = params["pipe_radius"] circle_factor = params["circle_factor"] additional_circle_factor = params["additional_circle_factor"] circle_pipe_radius = params["circle_pipe_radius"] # Schritt 1: Hauptwürfel erstellen main_cube_center = [0, 0, 0] half_length = main_cube_length / 2 main_cube = rs.AddBox([ [main_cube_center[0] - half_length, main_cube_center[1] - half_length, main_cube_center[2] - half_length], [main_cube_center[0] + half_length, main_cube_center[1] - half_length, main_cube_center[2] - half_length], [main_cube_center[0] + half_length, main_cube_center[1] + half_length, main_cube_center[2] - half_length], [main_cube_center[0] - half_length, main_cube_center[1] + half_length, main_cube_center[2] - half_length], [main_cube_center[0] - half_length, main_cube_center[1] - half_length, main_cube_center[2] + half_length], [main_cube_center[0] + half_length, main_cube_center[1] - half_length, main_cube_center[2] + half_length], [main_cube_center[0] + half_length, main_cube_center[1] + half_length, main_cube_center[2] + half_length], [main_cube_center[0] - half_length, main_cube_center[1] + half_length, main_cube_center[2] + half_length] ]) if not main_cube: raise ValueError("Hauptwürfel konnte nicht erstellt werden.") # Schritt 2: Kleinere Würfel an den Ecken des Hauptwürfels corner_cubes = [] small_cube_length = main_cube_length * small_cube_factor small_half_length = small_cube_length / 2 # Ecken des Hauptwürfels corners = rs.BoundingBox(main_cube) for corner in corners: small_cube = rs.AddBox([ [corner[0] - small_half_length, corner[1] - small_half_length, corner[2] - small_half_length], [corner[0] + small_half_length, corner[1] - small_half_length, corner[2] - small_half_length], [corner[0] + small_half_length, corner[1] + small_half_length, corner[2] - small_half_length], [corner[0] - small_half_length, corner[1] + small_half_length, corner[2] - small_half_length], [corner[0] - small_half_length, corner[1] - small_half_length, corner[2] + small_half_length], [corner[0] + small_half_length, corner[1] - small_half_length, corner[2] + small_half_length], [corner[0] + small_half_length, corner[1] + small_half_length, corner[2] + small_half_length], [corner[0] - small_half_length, corner[1] + small_half_length, corner[2] + small_half_length] ]) corner_cubes.append(small_cube) # Schritt 3: Würfel verschieben for i, small_cube in enumerate(corner_cubes): if i < 4: # Untere Würfel rs.MoveObject(small_cube, [0, 0, corner_offset]) # Nach unten verschieben if i == 0: rs.MoveObject(small_cube, [corner_offset, corner_offset, 0]) elif i == 1: rs.MoveObject(small_cube, [-corner_offset, corner_offset, 0]) elif i == 2: rs.MoveObject(small_cube, [-corner_offset, -corner_offset, 0]) elif i == 3: rs.MoveObject(small_cube, [corner_offset, -corner_offset, 0]) else: # Obere Würfel rs.MoveObject(small_cube, [0, 0, -corner_offset]) # Nach oben verschieben if i == 4: rs.MoveObject(small_cube, [corner_offset, corner_offset, 0]) elif i == 5: rs.MoveObject(small_cube, [-corner_offset, corner_offset, 0]) elif i == 6: rs.MoveObject(small_cube, [-corner_offset, -corner_offset, 0]) elif i == 7: rs.MoveObject(small_cube, [corner_offset, -corner_offset, 0]) # Schritt 4: Kreise und Pipes an den Mittelpunkten der Außenflächen des Hauptwürfels pipes = [] face_centers = [ [0, 0, half_length], # obere Fläche [0, 0, -half_length], # untere Fläche [half_length, 0, 0], # rechte Fläche [-half_length, 0, 0], # linke Fläche [0, half_length, 0], # vordere Fläche [0, -half_length, 0] # hintere Fläche ] for i, center in enumerate(face_centers): circle = rs.AddCircle(rs.WorldXYPlane(), main_cube_length * circle_factor) rs.MoveObject(circle, center) if i == 2 or i == 3: # Kreise auf den Seitenflächen um die Y-Achse drehen rs.RotateObject(circle, center, 90, [0, 1, 0]) elif i == 4 or i == 5: # Kreise auf den Vorder-/Hinterflächen um die X-Achse drehen rs.RotateObject(circle, center, 90, [1, 0, 0]) pipe = rs.AddPipe(circle, 0, pipe_radius) if pipe: pipes.append(pipe) rs.DeleteObject(circle) # Zusätzliche Kreise in der XY-Ebene an den Mittelpunkten additional_pipes = [] for center in face_centers: additional_circle = rs.AddCircle(rs.WorldXYPlane(), main_cube_length * additional_circle_factor) rs.MoveObject(additional_circle, center) additional_pipe = rs.AddPipe(additional_circle, 0, circle_pipe_radius) if additional_pipe: additional_pipes.append(additional_pipe) rs.DeleteObject(additional_circle) # Schritt 5: Boolesche Operation, um alles zu einem Objekt zu verbinden all_objects = [main_cube] + corner_cubes + pipes + additional_pipes final_result = rs.BooleanUnion(all_objects) if not final_result: raise ValueError("Boolesche Vereinigung fehlgeschlagen.") return final_result # Würfel verschieben def move_cube(cube, translation_vector): """Verschiebt den Hauptwürfel und seine zugehörigen Objekte.""" rs.MoveObject(cube, translation_vector) # Mittelpunkte der Kreise berechnen def get_circle_centers(cube, half_length): """Berechnet die Mittelpunkte der vier Kreise auf den Außenflächen des Hauptwürfels.""" radius_offset = cube_params["main_cube_length"] * cube_params["additional_circle_factor"] centers = [ [0, half_length + radius_offset , 0], # obere Fläche [0, -half_length - radius_offset, 0], # untere Fläche [half_length + radius_offset, 0, 0], # rechte Fläche [-half_length - radius_offset, 0, 0], # linke Fläche ] # Übersetzen, falls der Würfel verschoben wurde cube_center = rs.SurfaceVolumeCentroid(cube)[0] # Aktuellen Mittelpunkt des Würfels berechnen translated_centers = [rs.PointAdd(cube_center, center) for center in centers] return translated_centers def get_horizontal_circle_centers(cube, half_length): """ Berechnet die horizontalen Kreismittelpunkte basierend auf der Position und Größe des Würfels. """ all_circle_centers = get_circle_centers(cube, half_length) horizontal_centers = [c for c in all_circle_centers if abs(c[2] - cube[2]) < half_length] if len(horizontal_centers) < 4: raise ValueError("Nicht genügend Mittelpunkte für die horizontalen Kreise gefunden!") return horizontal_centers def create_torso(center, link_length, link_width, link_thickness, tangent): """Erstellt ein einzelnes elliptisches Kettenglied.""" plane = rs.PlaneFromNormal(center, tangent) # Ebene entlang der Tangentenrichtung if not plane: raise ValueError("Ebene konnte nicht erstellt werden.") ellipse = rs.AddEllipse(plane, link_length / 2, link_width / 2) if not ellipse: raise ValueError("Ellipse konnte nicht erstellt werden.") # Pipe um die Ellipse erstellen torso = rs.AddPipe(ellipse, [0, 1], [link_thickness, link_thickness]) if not torso: raise ValueError("Torso (Pipe) konnte nicht erstellt werden.") # Ellipse loeschen, da nur der Torso gebraucht wird rs.DeleteObject(ellipse) return torso def create_chain_along_curve(curve, link_length, link_width, link_thickness): """Erstellt eine Kette entlang einer Kurve.""" if not rs.IsCurve(curve): raise ValueError("Das angegebene Objekt ist keine Kurve.") # Punkte auf der Kurve generieren points = rs.DivideCurve(curve, rs.CurveLength(curve) / (link_width * 1.2), create_points=True) if not points: raise ValueError("Punkte konnten nicht entlang der Kurve generiert werden.") links = [] # Liste zum Speichern der erzeugten Kettenglieder for i, p in enumerate(points): # Berechne die Tangente entlang der Kurve param = rs.CurveClosestPoint(curve, p) tangent = rs.CurveTangent(curve, param) if not tangent: raise ValueError("Tangente konnte nicht berechnet werden an Position {}.".format(i)) # Normiere die Tangente tangent = rs.VectorUnitize(tangent) # Lokale X-, Y- und Z-Achsen berechnen local_x = rs.VectorCrossProduct(tangent, [0, 0, 1]) if rs.VectorLength(local_x) == 0: local_x = [1, 0, 0] # Fallback, falls Tangente parallel zu Z ist local_x = rs.VectorUnitize(local_x) local_y = rs.VectorCrossProduct(local_x, tangent) if rs.VectorLength(local_y) == 0: local_y = [0, 1, 0] # Fallback local_y = rs.VectorUnitize(local_y) local_z = tangent # Die Tangente selbst wird als lokale Z-Achse verwendet # Erstelle das Kettenglied an der aktuellen Position mit angepasster Tangentenrichtung link = create_torso(p, link_length, link_width, link_thickness, tangent) links.append(link) # Drehungen anwenden basierend auf dem Index (gerade/ungerade) if i % 2 == 0: # Erstes Kettenglied (gerade) rs.RotateObject(link, p, 90, local_x) # Drehung um X-Achse rs.RotateObject(link, p, 0, local_y) # Drehung um Y-Achse else: # Zweites Kettenglied (ungerade) rs.RotateObject(link, p, 90, local_y) # Drehung um Y-Achse rs.RotateObject(link, p, 90, local_x) # Drehung um X-Achse rs.RotateObject(link, p, 0, local_z) # Drehung um Z-Achse return links def create_pillar(base_point, width, length, height): """Erstellt eine rechteckige Säule an einem gegebenen Punkt.""" x, y, z = base_point half_w = width / 2 half_l = length / 2 pillar = rs.AddBox([ [x - half_w, y - half_l, z], [x + half_w, y - half_l, z], [x + half_w, y + half_l, z], [x - half_w, y + half_l, z], [x - half_w, y - half_l, z + height], [x + half_w, y - half_l, z + height], [x + half_w, y + half_l, z + height], [x - half_w, y + half_l, z + height] ]) return pillar, (x, y, z + height) # Rückgabe des Säulenobjekts und des neuen Startpunkts # Parameter für Würfel und Kettensteuerung cube_params = { "position": [0, 0, 120], # Position des Würfels im Raum "main_cube_length": 60, "small_cube_factor": 1/6, "corner_offset": 3, "pipe_radius": 2, "circle_factor": 1/3, "additional_circle_factor": 1/6, "circle_pipe_radius": 2 } # Parameter für die Säulen tower_params = { "pillar_width": 20, # Breite der Säule "pillar_length": 20, # Länge der Säule "pillar_height": 70 # Höhe der Säule } # Parameter für die Ketten chain_parameters = [ { "start_point": [0, 180, 0], # Startpunkt der Kette "end_circle_index": 0, # Ziel: Mittelpunkt 0 (von 4 möglichen) "knick_count": 2 # Anzahl der Knicke/Kontrollpunkte }, { "start_point": [0 ,-150, 0], "end_circle_index": 1, "knick_count":1 }, { "start_point": [180, 0, 0], "end_circle_index": 2, "knick_count": 2 }, { "start_point": [-220, 0, 0], "end_circle_index": 3, "knick_count": 2 } ] # Funktion zum Erstellen der Ketten def create_chain_with_custom_knicks(params, circle_centers): chains = [] for chain_param in params: # Erzeuge eine Säule am Startpunkt und setze den Startpunkt nach oben pillar, start_point = create_pillar( chain_param["start_point"], tower_params["pillar_width"], tower_params["pillar_length"], tower_params["pillar_height"] ) # Ziel: Mittelpunkt der Kreise (ausgewählt durch Index) end_circle_index = chain_param["end_circle_index"] end_point = circle_centers[end_circle_index] # Anzahl der Knicke/Kontrollpunkte knick_count = chain_param["knick_count"] # Kontrollpunkte generieren control_points = [start_point] for j in range(1, knick_count + 1): factor = j / (knick_count + 1) control_point = [ start_point[0] + factor * (end_point[0] - start_point[0]), start_point[1] + factor * (end_point[1] - start_point[1]), start_point[2] + factor * (end_point[2] - start_point[2]) + (5 if j % 2 == 0 else -5) ] control_points.append(control_point) control_points.append(end_point) # Interpolationskurve erstellen curve = rs.AddInterpCurve(control_points) # Kette entlang der Kurve erstellen link_length = 12.0 link_width = 8.0 link_thickness = 1.5 links = create_chain_along_curve(curve, link_length, link_width, link_thickness) chains.append(links) # Lösche Kurve, falls nicht benötigt rs.DeleteObject(curve) return chains # Hauptprogramm try: rs.EnableRedraw(False) # Szene löschen clear_scene() # Würfel erstellen und positionieren cube_center = cube_params["position"] main_cube = create_complex_cube(cube_params) rs.MoveObject(main_cube, cube_center) # Würfel verschieben # Mittelpunkte der horizontalen Kreise berechnen half_length = cube_params["main_cube_length"] / 2 horizontal_circle_centers = get_circle_centers(main_cube, half_length) # Ketten erstellen chains = create_chain_with_custom_knicks(chain_parameters, horizontal_circle_centers) # Säulen erstellen new_start_points = [] for param in chain_parameters: pillar, new_start = create_pillar( param["start_point"], tower_params["pillar_width"], tower_params["pillar_length"], tower_params["pillar_height"] ) new_start_points.append(new_start) # Startpunkte der Ketten aktualisieren for i, param in enumerate(chain_parameters): param["start_point"] = new_start_points[i] rs.EnableRedraw(True) # Lösche alle Linien und Punkte rs.DeleteObjects(rs.ObjectsByType(1 | 4)) rs.EnableRedraw(True) except Exception as e: print("Fehler:", e)