import math # me - this DAT # scriptOp - the OP which is cooking # # press 'Setup Parameters' in the OP to call this function to re-create the parameters. def onSetupParameters(scriptOp): page = scriptOp.appendCustomPage('Custom') page.appendFloat('Valuea', label='Value A') page.appendFloat('Valueb', label='Value B') return def onCook(scriptOp): scriptOp.clear() # Define Table Header with position and rotation columns scriptOp.appendRow(['text', 'P(X)', 'P(Y)', 'P(Z)', 'R(X)', 'R(Y)', 'R(Z)']) # --- Fetch External Parameters --- const_op = op('constant1') if not const_op: return radius_scale = const_op['ring_scale'] rotate_speed = const_op['rotate_speed'] # text_space: used to define the angular gap between characters text_space = const_op['text_space'] arc_table = op('arc_table') if arc_table: arc_table.clear() arc_table.appendRow(['tx', 'ty', 'tz','rx', 'ry', 'rz','scale']) for source in scriptOp.inputs: # Safety check: Input must exist and have at least a header and one data row if not source or source.numRows < 2: continue # Iterate through the rows of the source DAT for i, row in enumerate(source.rows()[1:]): full_string = row[0].val if not full_string: continue str_len = len(full_string) # Fetch speed variation from the speed_variation CHOP speed_op = op('speed_variation') speed_variation = speed_op[0][i] if speed_op and i < speed_op.numSamples else 0 # Calculate time-based rotation offset (in radians) time_offset = absTime.seconds * rotate_speed *(1.0+ abs(speed_variation))/10.0 try: center = [op('scaled_positions')[0][i], op('scaled_positions')[1][i], op('scaled_positions')[2][i]] axis = [float(row[5]), float(row[6]), float(row[7])] radius = float(row[8]) * radius_scale except (ValueError, TypeError, IndexError): continue # --- Calculate Orthogonal Basis for the Ring Plane --- ax, ay, az = axis mag = math.sqrt(ax*ax + ay*ay + az*az) if mag == 0: ax, ay, az = 0, 1, 0 else: ax, ay, az = ax/mag, ay/mag, az/mag if abs(ax) < 0.9: tx, ty, tz = 1, 0, 0 else: tx, ty, tz = 0, 1, 0 ux = ay*tz - az*ty uy = az*tx - ax*tz uz = ax*ty - ay*tx umag = math.sqrt(ux*ux + uy*uy + uz*uz) ux, uy, uz = ux/umag, uy/umag, uz/umag vx = ay*uz - az*uy vy = az*ux - ax*uz vz = ax*uy - ay*ux # --- Calculate Arc Logic --- # Instead of forcing (i/str_len)*2*pi, we use text_space to determine the gap. # If the total arc (gap * characters) < 2*pi, it remains an arc. angular_step = text_space / (radius if radius > 0 else 1) # angular_step = radius*math.pi*2.0/text_space if radius>0 else math.pi*2.0/str_len total= math.floor(math.pi*2.0/(angular_step)) count=0 print(f"Processing string with length {str_len}, total positions: {total}") # Build the table character by character while count 0: nx, ny, nz = off_x/dist, off_y/dist, off_z/dist else: nx, ny, nz = 0, 0, 1 char_ry = math.degrees(math.atan2(nx, nz)) char_rx = math.degrees(math.asin(-ny)) + 90 char_rz = 0 tan_x = (ux * -math.sin(angle)) + (vx * math.cos(angle)) tan_y = (uy * -math.sin(angle)) + (vy * math.cos(angle)) tan_z = (uz * -math.sin(angle)) + (vz * math.cos(angle)) line_ry = math.degrees(math.atan2(tan_x, tan_z)) - 90 line_rx = math.degrees(math.asin(-tan_y)) # ry = math.degrees(math.atan2(nx, nz)) # rx = math.degrees(math.asin(-ny))-90 # rz = 0 if count>=str_len: scale= radius*angular_step if radius>0 else 1 arc_table.appendRow([px, py, pz, line_rx, line_ry, 0, scale/2]) # scriptOp.appendRow(['-', px, py, pz, char_rx, char_ry, 0]) else: char = full_string[count] scriptOp.appendRow([char, px, py, pz, char_rx, char_ry, 0]) # arc_table.appendRow([px, py, pz, rx, ry, rz, 1.0]) count+=1 return def onGetCookLevel(scriptOp): return CookLevel.ALWAYS