import math # me - this DAT # scriptOp - the OP which is cooking 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() 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 # Fix for L22: CHOPs are not directly iterable. # We check for channel existence using the [] accessor and a fallback. def get_chan(chan_name, default=1.0): c = const_op[chan_name] return c.eval() if c is not None else default radius_scale = get_chan('ring_scale', 1.0) rotate_speed = get_chan('rotate_speed', 1.0) text_space = get_chan('text_space', 0.5) arc_table = op('arc_table') info_table = op('info_table') scaled_pos_op = op('scaled_positions') ring_const = op('/project1/RingConstant') draw_arc=parent().par.Drawarc.eval() if hasattr(parent().par, 'Drawarc') else False # Safety check for required info if not ring_const: return # Assuming ring_const is a Constant CHOP as well def get_remote_chan(op_ref, chan_name, default=1.0): if not op_ref: return default c = op_ref[chan_name] return c.eval() if c is not None else default f_size = get_remote_chan(ring_const, 'FontSize', 1.0) i_size = get_remote_chan(ring_const, 'InfoFontSize', 1.0) info_scale = i_size / f_size if f_size != 0 else 1.0 if arc_table: arc_table.clear() arc_table.appendRow(['tx', 'ty', 'tz','rx', 'ry', 'rz','scale', 'start1', 'end1', 'start2', 'end2']) if info_table: info_table.clear() info_table.appendRow(['text', 'tx', 'ty', 'tz', 'rx', 'ry', 'rz']) for source in scriptOp.inputs: if not source or source.numRows < 2: continue for i, row in enumerate(source.rows()[1:]): full_string = row[0].val # Ensure index exists for substring column sub_string = row[9].val if len(row) > 9 else "" if not full_string: continue str_len = len(full_string) sub_str_len = len(sub_string) # Fetch speed variation from CHOP speed_op = op('speed_variation') speed_variation = 0 if speed_op: # Use first channel, i-th sample if i < speed_op.numSamples: speed_variation = speed_op[0][i] # Time calculation time_offset = absTime.seconds * rotate_speed * (1.0 + abs(speed_variation)) / 10.0 try: # Use scaled_positions if it exists, otherwise default to origin if scaled_pos_op and i < scaled_pos_op.numSamples: center = [scaled_pos_op[0][i], scaled_pos_op[1][i], scaled_pos_op[2][i]] else: center = [0, 0, 0] axis = [float(row[5]), float(row[6]), float(row[7])] radius = float(row[8]) * radius_scale except (ValueError, TypeError, IndexError): continue # --- Calculate Orthogonal Basis --- 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) if umag == 0: umag = 1 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 --- angular_step = text_space / (radius if radius > 0.1 else 0.1) # SAFETY: Limit total iterations total = int(min(math.floor((math.pi * 2.0) / (angular_step if angular_step > 0.01 else 0.01)), 500)) total = max(total, str_len + sub_str_len*.5) arc_len = round((total - (str_len + sub_str_len*.5)) / 2) total= str_len + arc_len*2 + sub_str_len angle = time_offset # arc1_start_angle=str_len*angular_step # arc1_end_angle=arc1_start_angle + arc_len*angular_step # arc2_start_angle=arc1_end_angle+(sub_str_len*angular_step*info_scale*.5) # arc2_end_angle=arc2_start_angle + arc_len*angular_step arc1_start_angle=angular_step * str_len #+time_offset%(2*math.pi) arc1_end_angle=arc1_start_angle + arc_len*angular_step arc2_start_angle=arc1_end_angle+((sub_str_len)*angular_step*info_scale*.5) arc2_end_angle=math.pi*2.0 #arc2_start_angle + arc_len*angular_step for count in range(total): is_sub_str_zone = (count >= str_len + arc_len) and (count < str_len + arc_len + sub_str_len) step_mult = info_scale*.5 if is_sub_str_zone else 1.0 angle += (angular_step * step_mult) cos_a = math.cos(angle) * radius sin_a = math.sin(angle) * radius off_x = (ux * cos_a) + (vx * sin_a) off_y = (uy * cos_a) + (vy * sin_a) off_z = (uz * cos_a) + (vz * sin_a) kpx = getattr(parent().par, 'Keywordpositionx', 0) kpy = getattr(parent().par, 'Keywordpositiony', 0) kpz = getattr(parent().par, 'Keywordpositionz', 0) px = center[0] + off_x + kpx py = center[1] + off_y + kpy pz = center[2] + off_z + kpz # px=off_x + kpx # py=off_y + kpy # pz=off_z + kpz dist = math.sqrt(off_x**2 + off_y**2 + off_z**2) nx, ny, nz = (off_x/dist, off_y/dist, off_z/dist) if dist > 0 else (0,0,1) char_ry = math.degrees(math.atan2(nx, nz)) char_rx = math.degrees(math.asin(max(-1, min(1, -ny)))) + 90 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(max(-1, min(1, -tan_y)))) if count==0: pi=math.pi/2.0 two_pi=math.pi*2.0 half_pi=math.pi*0.5 arc_table.appendRow([center[0]+ kpx, center[1]+ kpy, center[2]+ kpz, 90, time_offset/math.pi*180.0, 0, radius, (arc1_start_angle)/two_pi, (arc1_end_angle)/two_pi, (arc2_start_angle)/two_pi, (arc2_end_angle)/two_pi, ]) # Header for arc table if count < str_len: char = full_string[count] scriptOp.appendRow([char, px, py, pz, char_rx, char_ry, 0]) elif count < str_len + arc_len: continue # if arc_table and draw_arc: # scale = (radius * angular_step * 0.5) if radius > 0 else 0.1 # arc_table.appendRow([px, py, pz, line_rx, line_ry, 0, scale]) elif count < str_len + arc_len + sub_str_len: char_idx = count - (str_len + arc_len) if char_idx < len(sub_string): char = sub_string[char_idx] if info_table: # continue info_table.appendRow([char, px, py, pz, char_rx, char_ry, 0]) else: continue # if arc_table and draw_arc: # scale = (radius * angular_step * 0.5) if radius > 0 else 0.1 # arc_table.appendRow([px, py, pz, line_rx, line_ry, 0, scale]) return def onGetCookLevel(scriptOp): return CookLevel.ALWAYS