Python
import c4d
def reverse_spline_points(op):
if not isinstance(op, c4d.SplineObject):
return
points = op.GetAllPoints()
points.reverse() # reverse point order
op.SetAllPoints(points)
# Reverse segment directions (important for multiple segments)
if op.GetSegmentCount() > 1:
segs = [op.GetSegment(i) for i in range(op.GetSegmentCount())]
segs.reverse()
for i, seg in enumerate(segs):
op.SetSegment(i, seg)
op.Message(c4d.MSG_UPDATE)
c4d.EventAdd()
def main():
obj = doc.GetActiveObject()
if obj is not None:
reverse_spline_points(obj)
main()
Compare multiple splines and align their sequence direction:
Python
import c4d
def get_spline_direction(spline):
"""Calculate the spline direction, prioritizing start-to-end vector, with segment sum as fallback."""
if not isinstance(spline, c4d.SplineObject) or spline.GetPointCount() < 2:
print(f"Error: '{spline.GetName()}' is not a valid spline or has insufficient points.")
return None, None, None
points = spline.GetAllPoints()
start = points[0]
end = points[-1]
# Try start-to-end direction first
direction = end - start
length = direction.GetLength()
if length > 0.0001: # Check if start-to-end vector is valid
return direction.GetNormalized(), start, end
# Fallback: Sum weighted segment vectors
print(f"Warning: '{spline.GetName()}' has near-zero start-to-end length, using segment sum.")
total_direction = c4d.Vector(0)
total_length = 0.0
for i in range(len(points) - 1):
segment = points[i + 1] - points[i]
segment_length = segment.GetLength()
if segment_length > 0.0001:
total_direction += segment * segment_length
total_length += segment_length
if total_length < 0.0001:
print(f"Error: '{spline.GetName()}' has near-zero total length.")
return None, start, end
return total_direction.GetNormalized(), start, end
def flip_spline(spline):
"""Reverse the point order of a spline."""
try:
points = spline.GetAllPoints()
points.reverse()
spline.SetAllPoints(points)
# Reverse tangents if they exist
if spline.GetTangentCount() > 0:
tangents = spline.GetAllTangents()
tangents.reverse()
spline.SetAllTangents(tangents)
spline.Message(c4d.MSG_UPDATE)
return True
except Exception as e:
print(f"Error flipping spline '{spline.GetName()}': {str(e)}")
return False
def main():
doc = c4d.documents.GetActiveDocument()
splines = [
op for op in doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if isinstance(op, c4d.SplineObject)
]
if len(splines) < 2:
print("Error: Select at least 2 spline objects.")
return
print(f"\nSelected {len(splines)} splines.")
valid_entries = []
for i, s in enumerate(splines):
direction, start, end = get_spline_direction(s)
if direction:
valid_entries.append((s, direction, start, end))
print(f"Spline #{i} '{s.GetName()}': Points = {s.GetPointCount()}, Start = {start}, End = {end}, Dir = {direction}")
else:
print(f"Spline #{i} '{s.GetName()}': SKIPPED (invalid or zero-length)")
if len(valid_entries) < 2:
print("Error: Not enough valid splines to compute a reference direction.")
return
# Use the first valid spline as the reference direction
majority_spline, majority_dir, _, _ = valid_entries[0]
majority_spline_name = majority_spline.GetName()
print(f"Using spline #0 '{majority_spline_name}' as reference direction: {majority_dir}")
# Start an undo stack
doc.StartUndo()
# Check and flip splines that are opposite to the reference direction
flipped_count = 0
perpendicular_count = 0
for i, (spline, dir_vec, start, end) in enumerate(valid_entries):
dot = dir_vec.Dot(majority_dir)
print(f"Spline #{i} '{spline.GetName()}': Points = {spline.GetPointCount()}, Dot = {dot:.3f}")
# Handle perpendicular or ambiguous cases
if abs(dot) < 0.3: # Relaxed threshold for perpendicularity
print(f"Spline #{i} '{spline.GetName()}': SKIPPED (perpendicular to reference, dot = {dot:.3f})")
perpendicular_count += 1
continue
# Flip if opposite direction
if dot < 0: # Flip any spline in the opposite direction
print(f"Flipping spline #{i} '{spline.GetName()}' (opposite direction, dot = {dot:.3f})")
doc.AddUndo(c4d.UNDOTYPE_CHANGE, spline)
if flip_spline(spline):
flipped_count += 1
else:
print(f"Failed to flip spline #{i} '{spline.GetName()}'")
else:
print(f"Spline #{i} '{spline.GetName()}': Aligned (dot = {dot:.3f})")
# End the undo stack
doc.EndUndo()
print(f"\nCompleted: Flipped {flipped_count} out of {len(valid_entries)} valid splines.")
if perpendicular_count > 0:
print(f"Warning: {perpendicular_count} splines were perpendicular to the reference direction and were not flipped.")
# Update the Cinema 4D interface
c4d.EventAdd()
if __name__ == "__main__":
main()