user6505421
user6505421

Reputation:

How to make Bézier curve align sphere surface?

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

Answers (2)

GammaSQ
GammaSQ

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

Dominik Mokriš
Dominik Mokriš

Reputation: 1169

  1. Transform your problem into a coordinate system where the two points have the same latitude or longitude. This should be a moderately easy exercise on linear algebra. These lecture notes might be a good beginning if this is a completely new topic for you. Note that you look for a coordinate system and not the coordinate system, as there will be more than one solution.
  2. Use the solution that already worked for you in the"standard" case (i.e., when the two points are on the same latitude or longitude).
  3. Take the the Bézier curve from step 2 but express its control points in the original coordinate system. This works thanks to affine invariance of Bézier curves (and thus B-splines in general): affine transformation of the curve (and the change of the coordinates is one) is done by transforming the control points and constructing the curve again. Here you can read more.

Upvotes: 0

Related Questions