Formulae / Method to calculate smooth curved line between two points satisfying headings of both points

75 Views Asked by At

enter image description here
As shown in the image, formulae or method how to calculate smooth curved line is needed.The red line is the line which will look at the end after solving.

I'll appreciate your help / discussion.

I need mathematical formulae and may be how to solve it using scipy python package.

1

There are 1 best solutions below

0
lastchance On

Actually, you will gain more flexibility if you use cubic Bezier curves.

This for the first problem:

import math
import numpy as np
import matplotlib.pyplot as plt

#-----------------------------

def length( vector ): return np.linalg.norm( vector )      # length of a vector
def normalise( vector ): return vector / length(vector)    # normalise a vector (numpy array)

#-----------------------------

class Bezier:
    '''class for Cubic Bezier curve'''
    def __init__( self, q0, q1, q2, q3 ):
        self.p0 = np.array( q0 )
        self.p1 = np.array( q1 )
        self.p2 = np.array( q2 )
        self.p3 = np.array( q3 )

    def pt( self, t ):
        return ( 1.0 - t ) ** 3 * self.p0 + 3.0 * t * ( 1.0 - t ) ** 2 * self.p1 + 3.0 * t ** 2 * ( 1.0 - t ) * self.p2 + t ** 3 * self.p3

    def curve( self, n ):
        crv = []
        for t in np.linspace( 0.0, 1.0, n ):
            crv.append( self.pt( t ) )
        return crv

#-----------------------------

def drawBezier( x1, y1, heading1, x2, y2, heading2, n ):
    '''Turns two points plus headings into cubic Bezier control points [ P0, P1, P2, P3 ] by adding intermediate control points'''
    result = []

    rad1, rad2 = heading1 * math.pi / 180, heading2 * math.pi / 180
    d1 = np.array( [ np.sin( rad1 ), np.cos( rad1 ) ] )    # direction vector at point 1
    d2 = np.array( [ np.sin( rad2 ), np.cos( rad2 ) ] )

    p0 = np.array( ( x1, y1 ) )                            # start point of Bezier curve
    p3 = np.array( ( x2, y2 ) )                            # end point of Bezier curve
    p1 = p0 + d1 * length( p3 - p0 ) / 2.0                 # use direction at P0 to get P1
    p2 = p3 - d2 * length( p3 - p0 ) / 2.0                 # use direction at p3 to get P2

    arc = Bezier( p0, p1, p2, p3 )                         # define a cubic Bezier object

    x = [];   y = []
    for pt in arc.curve( n ):
        x.append( pt[0] )
        y.append( pt[1] )
    plt.plot( x, y )
    
#-----------------------------

x1, y1, heading1 = 0.0, 0.0, 0.0
x2, y2, heading2 = 1.0, 1.0, 90.0
drawBezier( x1, y1, heading1, x2, y2, heading2, 100 )
plt.plot( [ x1, x2 ], [ y1, y2 ], 'o' )                   # plot original support points
plt.show()

enter image description here

The advantage of the cubic Bezier is that you can also seamlessly deal with the cases such as where the two direction lines don't cross. For example

x2, y2, heading2 = 1.0, 1.0, 0.0

with output

enter image description here