diff --git a/guided_mrmp/conflict_resolvers/curve_path.py b/guided_mrmp/conflict_resolvers/curve_path.py
index a20aaa34638f41adaf0c05e47dba146f1ed99591..12373761b66875dd855937198f6f6848320853dc 100644
--- a/guided_mrmp/conflict_resolvers/curve_path.py
+++ b/guided_mrmp/conflict_resolvers/curve_path.py
@@ -1,176 +1,188 @@
 import numpy as np
 import matplotlib.pyplot as plt
-from guided_mrmp.utils import Library
-import sys
-
-# from guided_mrmp.conflict_resolvers import TrajOptMultiRobot
-# 
-# Function to calculate the Bézier curve points
-def bezier_curve(t, control_points):
-    P0, P1, P2 = control_points
-    return (1 - t)**2 * P0 + 2 * (1 - t) * t * P1 + t**2 * P2
-
-def smooth_path(points, control_point_distance, N=40):
-    # List to store the points along the smoothed curve
-    smoothed_curve = []
-
-    # Connect the first point to the first control point
-    # control_point_start = points[0] + (points[1] - points[0]) * control_point_distance
-    smoothed_curve.append(points[0])
-    # smoothed_curve.append(control_point_start)
-
-    # Iterate through each set of three consecutive points
-    for i in range(len(points) - 2):
-        # Extract the three consecutive points
-        P0 = points[i]
-        P1 = points[i + 1]
-        P2 = points[i + 2]
-        
-        # Calculate the tangent directions at the start and end points
-        if np.linalg.norm(P1 - P0) == 0:
-            tangent_start = np.array([0, 0])
-        else: tangent_start = (P1 - P0) / np.linalg.norm(P1 - P0)
-        if np.linalg.norm(P2 - P1) == 0:
-            tangent_end = np.array([0, 0])
-        else: tangent_end = (P2 - P1) / np.linalg.norm(P2 - P1)
-        
-        # Calculate the control points
-        control_point_start = P1 - tangent_start * control_point_distance
-        control_point_end = P1 + tangent_end * control_point_distance
-        
-        # Construct the Bézier curve for the current set of points
-        control_points = [control_point_start, P1, control_point_end]
-        t_values = np.linspace(0, 1, 10)
-        # print(t_values)
-        curve_points = np.array([bezier_curve(t, control_points) for t in t_values])
+import math
+from scipy.ndimage import gaussian_filter1d
+
+def bezier(t, points):
+    """Calculate Bezier curve point for parameter t and given control points."""
+    n = len(points) - 1
+    return sum(
+        (math.comb(n, i) * (1 - t) ** (n - i) * t ** i * points[i] for i in range(n + 1)),
+        np.zeros(2)
+    )
+
+def smooth_path(points, N=100, alpha=0.25, sigma=1.0):
+    smooth_points = []
+    control_points = []
+    i = 0
+    while i < len(points) - 1:
+        if i < len(points) - 3 and is_bend(points[i:i+4]):
+            # Double bend (cubic bezier with two softened control points)
+            p0, p1, p2, p3 = np.array(points[i]), np.array(points[i+1]), np.array(points[i+2]), np.array(points[i+3])
+            cp1 = soften_control_point(p1, alpha, p0, p2)  # Soften the first control point
+            cp2 = soften_control_point(p2, alpha, p1, p3)  # Soften the second control point
+            control_points.extend([cp1, cp2])  # Collect control points for visualization
+            for t in np.linspace(0, 1, 20):
+                smooth_points.append(bezier(t, [p0, cp1, cp2, p3]))
+            i += 3
+        elif i < len(points) - 2 and is_bend(points[i:i+3]):
+            # Single bend (quadratic bezier with one softened control point)
+            p0, p1, p2 = np.array(points[i]), np.array(points[i+1]), np.array(points[i+2])
+            cp = soften_control_point(p1, alpha, p0, p2)  # Use refined softening
+            control_points.append(cp)  # Collect control point for visualization
+            for t in np.linspace(0, 1, 20):
+                smooth_points.append(bezier(t, [p0, cp, p2]))
+            i += 2
+        else:
+            # No bend, interpolate straight line
+            smooth_points.append(points[i])
+            i += 1
+
+    # Ensure start and end points are included
+    smooth_points = [points[0]] + smooth_points + [points[-1]]
+
+    # Apply Gaussian smoothing to soften remaining sharp transitions
+    smooth_points = np.array(smooth_points)
+    smooth_points[:, 0] = gaussian_filter1d(smooth_points[:, 0], sigma=sigma)
+    smooth_points[:, 1] = gaussian_filter1d(smooth_points[:, 1], sigma=sigma)
+
+    # Downsample to N points, preserving start and end points
+    indices = np.linspace(0, len(smooth_points) - 1, N).astype(int)
+    downsampled_points = smooth_points[indices]
+    downsampled_points[0], downsampled_points[-1] = points[0], points[-1]
+
+    return downsampled_points, np.array(control_points)
+
+def soften_control_point(middle_point, alpha, prev_point, next_point):
+    """Move middle point along the bisector away from the 90-degree angle."""
+
+    middle_point = np.array(middle_point, dtype=np.float64)
+    prev_point = np.array(prev_point, dtype=np.float64)
+    next_point = np.array(next_point, dtype=np.float64)
+
+    # Vectors from middle point to adjacent points
+    vec1 = prev_point - middle_point
+    vec2 = next_point - middle_point
+
+    # Normalize the vectors
+    vec1 /= np.linalg.norm(vec1)
+    vec2 /= np.linalg.norm(vec2)
+
+    # Calculate the bisector direction
+    bisector = vec1 + vec2
+    bisector /= np.linalg.norm(bisector)  # Normalize bisector
+
+    # Move middle point along the bisector direction
+    adjusted_point = middle_point + alpha * bisector
+    return adjusted_point
+
+def is_bend(segment):
+    """Check if three or four points form a 90-degree bend."""
+    if len(segment) == 3:
+        return np.cross(segment[1] - segment[0], segment[2] - segment[1]) != 0
+    elif len(segment) == 4:
+        return (np.cross(segment[1] - segment[0], segment[2] - segment[1]) != 0 and
+                np.cross(segment[2] - segment[1], segment[3] - segment[2]) != 0)
+    return False
+
+def calculate_headings(path_points):
+    """
+    Calculate headings for each segment in the path, allowing for reverse movement.
+
+    Parameters:
+        path_points (np.ndarray): Array of (x, y) points representing the smoothed path.
+
+    Returns:
+        headings (list): List of headings (in radians) for each segment in the path.
+    """
+    headings = []
+    prev_heading = None
+
+    for i in range(len(path_points) - 1):
+        # Calculate forward and reverse headings for each segment
+        p1, p2 = path_points[i], path_points[i + 1]
+        forward_heading = np.arctan2(p2[1] - p1[1], p2[0] - p1[0])
+
         
-        # Append the points along the curve to the smoothed curve list
-        smoothed_curve.extend(curve_points[1:])
 
-        smoothed_curve = np.array(smoothed_curve)
-        t_original = np.linspace(0, 1, len(smoothed_curve))
-        t_resampled = np.linspace(0, 1, N)
-        smoothed_curve = np.array([np.interp(t_resampled, t_original, smoothed_curve[:, i]) for i in range(smoothed_curve.shape[1])]).T
-        smoothed_curve = smoothed_curve.tolist()
+        reverse_heading = (forward_heading + np.pi) % (2 * np.pi)
+
+        # Choose direction based on previous heading to minimize angle change
+        if prev_heading is not None:
+            forward_diff = np.abs((forward_heading - prev_heading + np.pi) % (2 * np.pi) - np.pi)
+            reverse_diff = np.abs((reverse_heading - prev_heading + np.pi) % (2 * np.pi) - np.pi)
+
+
 
-    # Connect the last control point to the last point
-    # control_point_end = points[-1] - (points[-1] - points[-2]) * control_point_distance
-    # smoothed_curve.append(control_point_end)
-    smoothed_curve.append(points[-1])
+            chosen_heading = forward_heading if forward_diff <= reverse_diff else reverse_heading
+        else:
+            # If it's the first segment, choose forward heading by default
+            chosen_heading = forward_heading
 
-    # Convert smoothed curve points to a numpy array
-    return np.array(smoothed_curve)
 
+        # plot the two points and the heading
+        # import matplotlib.pyplot as plt
+        # plt.plot([p1[0], p2[0]], [p1[1], p2[1]], 'ro-')  # Plot the two points
+        # dx = 0.1 * np.cos(forward_heading)
+        # dy = 0.1 * np.sin(forward_heading)
+        # plt.arrow(p1[0], p1[1], dx, dy, head_width=0.01, head_length=0.1, fc='blue', ec='blue')
+        # dx = 0.1 * np.cos(reverse_heading)
+        # dy = 0.1 * np.sin(reverse_heading)
+        # plt.arrow(p1[0], p1[1], dx, dy, head_width=0.01, head_length=0.1, fc='green', ec='green')
+        # plt.show()
+
+        headings.append(chosen_heading)
+        prev_heading = chosen_heading
+
+    return headings
 
 if __name__ == "__main__":
+    # Example points and visualization
+    points = np.array([
+        [0, 0], [0, 1], [1, 1], [2, 1], [2, 2], [2, 3], [2, 2], [2, 1], [2,0]
+    ])
+
+    # points = np.array([
+    #     [0, 0], [0, 1], [1, 1], [1,0], [0,0]
+    # ])
 
-    # define obstacles
-    circle_obs = np.array([])
+    # Generate smooth curve and get control points
+    N = 20
+    smooth_points, control_points = smooth_path(points, N, alpha=-.5, sigma=0.8)
 
-    rectangle_obs = np.array([])
+    print(f"smooth_points = {smooth_points}")
 
-    # points1 = np.array([[1,6],
-    #           [1,1],
-    #           [9,1]])
-    
-    # points2 = np.array([[9,1],
-    #           [9,6],
-    #           [1,6]])
+    # Example usage with a smooth path
+    # path_points, control_points = smooth_path(points, N=100, alpha=0.2, sigma=1.5)
+    headings = calculate_headings(smooth_points)
 
-    # smoothed_curve1 = smooth_path(points1, 3)
-    # smoothed_curve2 = smooth_path(points2, 3)
+    # Displaying the headings
+    for i, heading in enumerate(headings):
+        print(f"Segment {i}: Heading = {np.degrees(heading):.2f} degrees")
 
-    # # Plot the original points and the smoothed curve
-    # plt.plot(points1[:, 0], points1[:, 1], 'bo-', label='original path')
-    # plt.plot(smoothed_curve1[:, 0], smoothed_curve1[:, 1], 'r-', label='curved path')
-    # plt.xlabel('X')
-    # plt.ylabel('Y')
-    # # plt.title('Smoothed Curve using Bézier Curves')
-    # plt.legend()
-    # plt.grid(True)
-    # plt.axis('equal')
-    # plt.show()
+    # Plotting
+    plt.figure(figsize=(8, 8))
+    plt.plot(smooth_points[:, 0], smooth_points[:, 1], 'b-', label="Bezier Smooth Path")
 
-    # Example points
-    lib = Library("guided_mrmp/database/2x3_library")
-    lib.read_library_from_file()
+    plt.scatter(points[:, 0], points[:, 1], color="purple", marker="x", s=100, label="Control Points")
 
-    robot_starts = [[0, 0], [0, 2], [1, 2]]
-    robot_goals = [[0, 1],[1, 2], [0, 2]]
-    sol = lib.get_matching_solution(robot_starts, robot_goals)
+    # Add circles and headings
+    for i, (x, y) in enumerate(smooth_points):
+        plt.plot(x, y, 'ro')  # Circle at each point
+        if i < len(headings):
+            heading = headings[i]
+            dx = 0.1 * np.cos(heading)
+            dy = 0.1 * np.sin(heading)
+            plt.arrow(x, y, dx, dy, head_width=0.05, head_length=0.1, fc='green', ec='green')
 
-    print(sol)
+    plt.xlabel("X")
+    plt.ylabel("Y")
+    plt.title("Smoothed Path with Control Points and Headings")
+    plt.legend()
+    plt.grid(True)
+    plt.show()
 
-    for points in sol:
 
 
-        # Condition to filter out rows equal to [-1, -1]
-        points = np.array(points)
-        
-        condition = (points != [-1, -1]).any(axis=1)
-        points = points[condition]
-        print(f"points = {points}")
-
-        # Parameters
-        control_point_distance = 0.3  # Distance of control points from the middle point
-
-        smoothed_curve = smooth_path(points, control_point_distance)
-        print(f"smoothed_curve = {smoothed_curve}")
-
-        # Plot the original points and the smoothed curve
-        plt.plot(points[:, 0], points[:, 1], 'bo-', label='original path')
-        plt.plot(smoothed_curve[:, 0], smoothed_curve[:, 1], 'r-', label='curved path')
-        plt.xlabel('X')
-        plt.ylabel('Y')
-        # plt.title('Smoothed Curve using Bézier Curves')
-        plt.legend()
-        plt.grid(True)
-        plt.axis('equal')
-        plt.show()
-
-
-    # weights for the cost function
-    dist_robots_weight = 10
-    dist_obstacles_weight = 10
-    control_costs_weight = 1.0
-    time_weight = 5.0
-
-    # other params
-    num_robots = 3
-    rob_radius = 0.25
-    N = 20
 
 
-    # # initial guess 
-    # print(f"N = {N}")
-    # initial_guess = np.zeros((num_robots*3,N+1))
-    # print(initial_guess)
-    # # for i,(start,goal) in enumerate(zip(robot_starts, robot_goals)):
-    # for i in range(0,num_robots*2,3):
-    #     start=robot_starts[int(i/2)]
-    #     goal=robot_goals[int(i/2)]
-    #     initial_guess[i,:] = np.linspace(start[0], goal[0], N+1)
-    #     initial_guess[i+1,:] = np.linspace(start[1], goal[1], N+1)
-    #     # initial_guess[i+2,:] = np.linspace(.5, .5, N+1)
-    #     # initial_guess[i+3,:] = np.linspace(.5, .5, N+1)
-
-    # print(initial_guess)
-
-    
-
-    # solver = TrajOptMultiRobot(num_robots=num_robots, 
-    #                            robot_radius=rob_radius,
-    #                            starts=robot_starts, 
-    #                            goals=robot_goals, 
-    #                            circle_obstacles=circle_obs, 
-    #                            rectangle_obstacles=rectangle_obs,
-    #                            rob_dist_weight=dist_robots_weight,
-    #                            obs_dist_weight=dist_obstacles_weight,
-    #                            control_weight=control_costs_weight,
-    #                            time_weight=time_weight
-    #                            )
-    # sol,pos = solver.solve(N, initial_guess)
-    # pos_vals = np.array(sol.value(pos))
-
-    
-    # solver.plot_paths(pos_vals, initial_guess)