Drawing a constant slope spiral on a sphere

Hi, I am trying to draw a spiral with a constant slope on top of a sphere, I am encountering an error with rs.vectorAngle which I can’t manage to solve (to keep my script going clockwise along the sphere). Can anyone help or letting me know what I am doing wrong?

this is the procedure:

  1. The script starts by getting user inputs: the step between contour lines, a sphere object, and a set of curves.
  2. It calculates the center of the sphere and sets the initial radius of the contour circles.
  3. The script starts processing curves from a specified index. It begins by getting the starting point of the first curve.
  4. It creates a circle at the starting point and calculates a vector from the center of the sphere to this point.
  5. Then, it iterates through the remaining curves. For each curve:
  • The script copies the curve downward by the specified step.
  • It finds intersection points between the circle and the new curve.
  • Calculates the angle between the original vector and the vector to the intersection point.
  • Decides whether to add the first or second intersection point as the new point based on the angle.
  • Creates a new circle at the new point’s location and moves it up by the step.
  1. The script accumulates all the generated points in a list.
  2. Finally, it creates a curve through all the points, generating the contour line.

this is the script

import rhinoscriptsyntax as rs

# Get the step between contour lines from the user
step = 1 #
rs.GetReal("Insert the step between contour lines")

# Get the sphere object and curves from the user
sphere = rs.GetObject("Select the sphere", 8)
curves = rs.GetObjects("Select curves", 4)

# Calculate the center of the sphere
center = rs.SurfaceAreaCentroid(sphere)[0]

# Define the initial radius of the circle
circleRadius = 4

# Set the starting index for processing curves
index = 23

# Get the starting point for the contour creation
point = rs.CurveStartPoint(curves[index])

# Create the first circle at the starting point
circle = rs.AddCircle(point, circleRadius)

# Calculate the vector from the center of the sphere to the starting point
vector1 = rs.VectorCreate([center[0], center[1], 0], [point[0], point[1], 0])

# Initialize the angle variable
angle = 0

# Store the points that will form the final contour
allpoints = [point]

# Loop through the remaining curves for contour creation
for i in range(index, len(curves) - 1):
    # Copy the current curve downward by the specified step
    newcurve = rs.CopyObject(curves[i + 1], [0, 0, -step])
    
    # Find the intersection points between the circle and the new curve
    intersect = rs.CurveCurveIntersection(circle, newcurve, 1)
    newpointcoord = intersect[0][1]
    
    # Calculate the vector from the center of the sphere to the new intersection point
    vector2 = rs.VectorCreate([center[0], center[1], 0], [newpointcoord[0], newpointcoord[1], 0])
    
    # Calculate the angle between the two vectors
    newangle = rs.VectorAngle(vector1, vector2)
    
    # Determine the direction of the new point based on the angle
    if newangle > angle:
        newpoint = rs.AddPoint(intersect[0][1])
    else:
        newpoint = rs.AddPoint(intersect[1][1])
        print("other dir")
        
    # Update the angle variable and create a new circle
    angle = newangle
    circle = rs.AddCircle(newpoint, circleRadius)
    
    # Move the circle upwards by the specified step
    rs.MoveObject(circle, [0, 0, step])
    
    # Add the new point to the list of all points
    allpoints.append(newpoint)

# Create a curve through all the generated points
rs.AddCurve(allpoints)```

[spiral input.3dm|attachment](upload://pSTWtxbmPxzZSrDTt6414aAwCKV.3dm) (267.3 KB)

I actually managed by finding the smallest clockwise angle between the center of the circle and the two intersections.


# Function to calculate the angle between two vectors
def angle_between(v1, v2):
    dot_product = v1[0] * v2[0] + v1[1] * v2[1]
    det = v1[0] * v2[1] - v1[1] * v2[0]
    angle = math.atan2(det, dot_product)
    return angle

# Function to determine if vector 'va' has a smaller rotation than vector 'vb' with respect to vector 'v0'
def is_vecA_smallest_rotation(v0, va, vb):
    angle_a = angle_between(v0, va)
    angle_b = angle_between(v0, vb)
    
    if angle_a < 0:
        angle_a += 2 * math.pi
    if angle_b < 0:
        angle_b += 2 * math.pi
    
    return angle_a < angle_b```

hope this helps someone else
1 Like