import __main__ BaseNode = __main__.BaseNode QtGui = __main__.QtGui import numpy as np import cv2 import time class SpringNode(BaseNode): """ Simulates a 1D damped spring. F = -k*x - c*v """ NODE_CATEGORY = "AI / Physics" NODE_COLOR = QtGui.QColor(100, 180, 100) def __init__(self, mass=1.0, stiffness=0.1, damping=0.05): super().__init__() self.node_title = "Spring (1D)" self.inputs = {'target_pos': 'signal'} self.outputs = {'position': 'signal'} self.mass = float(mass) self.stiffness = float(stiffness) self.damping = float(damping) self.position = 0.0 self.velocity = 0.0 self.last_time = time.time() def step(self): # Calculate delta time current_time = time.time() dt = current_time - self.last_time if dt > 0.1: # Clamp large timesteps (e.g., on load) dt = 0.1 self.last_time = current_time # Get target target = self.get_blended_input('target_pos', 'sum') or 0.0 # Calculate forces displacement = self.position - target spring_force = -self.stiffness * displacement damping_force = -self.damping * self.velocity total_force = spring_force + damping_force # Update physics (Euler integration) acceleration = total_force / self.mass self.velocity += acceleration * dt self.position += self.velocity * dt def get_output(self, port_name): if port_name == 'position': return self.position return None def get_display_image(self): w, h = 256, 128 img = np.zeros((h, w, 3), dtype=np.uint8) # Draw position pos_x = int(np.clip((self.position + 2) / 4.0, 0, 1) * w) cv2.circle(img, (pos_x, h//2), 10, (0, 255, 0), -1) # Draw target target = self.get_blended_input('target_pos', 'sum') or 0.0 target_x = int(np.clip((target + 2) / 4.0, 0, 1) * w) cv2.circle(img, (target_x, h//2), 5, (0, 0, 255), -1) cv2.putText(img, f"Pos: {self.position:.2f}", (5, 15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255,255,255), 1) cv2.putText(img, f"Vel: {self.velocity:.2f}", (5, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255,255,255), 1) return QtGui.QImage(img.data, w, h, w*3, QtGui.QImage.Format.Format_RGB888) def get_config_options(self): return [ ("Mass", "mass", self.mass, None), ("Stiffness", "stiffness", self.stiffness, None), ("Damping", "damping", self.damping, None) ]