Reputation:
I am trying to connect any 2 points on sphere surface with quartic Bézier curve in such way that every point of a curve are very close to the surface. I saw this solution, but it works only for cubic curves and only in the case when given 2 points have the same latitude or longitude - example A. I have 2 questions:
1) In other cases - example B this solution doesn't work and I feel like control points vectors lack power and I want any curve be spherical like in example A. So what is a right way of calculating control points vectors for cubic Bézier curve to align sphere surface.
2) If question 1 is solvable - how do I randomize middle control point in quartic Bézier curve in order to achieve unique curve every time I generate it like in example C
Thank you!
EDIT: question 2 is solved by the @Kpym solution.
Upvotes: 1
Views: 1651
Reputation: 391
I interpreted this question as "How to calculate a Bézier curve confined to the surface of a sphere?"
The only solution I could find that is guaranteed to stay surface-bound is to use De Casteljau's algorithm with great circle way-points. Basically, the idea is to first plot a great-circle course on the surface of the sphere between all control-points and walk each course by a given percentage. Then use all those waypoints as control-points of a lower degree Bézier-curve. I've scripted this recursively in python:
def _spherical_bezier(*LatLongs, progress=0):
#DON'T USE IN PRODUCTION! UNTESTED!!!
"""accepts a list of latitude/longitude coordinate-pairs.
Calculates a point of the bezier-curve characterized by those points.
Progress is expected between 0 and 1, but DOES accept values outside that range!"""
#terminate if only one point left or still at start
if progress == 0 or len(LatLongs) == 1:
return LatLongs[0]
#prepare list of points
next_order = []
#don't include last point ...
for i, P1 in enumerate(LatLongs[:-1]):
#... it will be taken care of here:
P2 = LatLongs[i+1]
#12-notation as in wikipedia
lambda12 = P2[1] - P1[1]
cos1 = cos(P1[0])
cos2 = cos(P2[0])
cosL = cos(lambda12)
sin1 = sin(P1[0])
sin2 = sin(P2[0])
sinL = sin(lambda12)
sigma = atan2(sqrt((cos1*sin2 - sin1*cos2*cosL)**2 + (cos2*sinL)**2), (sin1*sin2 + cos1*cos2*cosL))
alpha = atan2(cos2*sinL, cos1*sin2 - sin1*cos2*cosL)
cosa = cos(alpha)
sina = sin(alpha)
#1x = from 1 to x
sigma1x = sigma*progress
coss = cos(sigma1x)
sins = sin(sigma1x)
phix = atan2(sin1*coss + cos1*sins*cosa, sqrt((cos1*coss-sin1*sins*cosa)**2+(sins*sina)**2))
lambda1x = atan2(sins*sina, cos1*coss - sin1*sins*cosa)
next_order.append((phix, P1[1]+lambda1x))
return _spherical_bezier(*next_order, progress=progress)
Upvotes: 0
Reputation: 1169
Upvotes: 0