Connect two segments at intersection (make corner)

Hello, I have got quite far with the methods from the method reporter, but I am hitting a wall.

I have a path segment that has an intersection point with another path segment. Essentially, I would like to insert this intersection point on my first segment and thus create a new, shorter segment.

This technically works, but it doesn’t change the position of the other offcurve nodes of the segment.

So, I would need: the path time of the point closest to my given intersection point, or a method that directly inserts the point into the segment, but also shortens the offcurve nodes accordingly (so that the segment doesn’t visually change), or a method that lets me imitate “make corner” using two segments.

This is the segment I need:

How do I achieve this? Thanks!

Okay, Claude answered my question pretty well (some manual edits to make it work with the Python API had to be done). To find the path time of the highlighted extra node:

import math
from typing import Tuple

def path_time_for_point(segment, position: Tuple[float, float]) -> float:
	"""
	Find the path time parameter t where the given position lies on the cubic Bézier segment.
	Assumes the point is definitely on the segment.

	Args:
		segment: GSPathSegment with four control points
		position: Target coordinate (x, y) that lies on the segment

	Returns:
		float: Parameter t in [0, 1] where the curve passes through the position
	"""
	if segment.count() != 4:
		raise ValueError("Segment must have exactly four control points")
	points = []
	# Extract control points
	for index in range(4):
		points.append(segment.objectAtIndexedSubscript_(index))
	p0, p1, p2, p3 = points
	target_x, target_y = position

	# Quick check for endpoints
	if (target_x, target_y) == (p0.x, p0.y):
		return 0.0
	if (target_x, target_y) == (p3.x, p3.y):
		return 1.0

	def bezier_point(t: float) -> Tuple[float, float]:
		"""Calculate point on Bézier curve at parameter t"""
		u = 1 - t
		x = u ** 3 * p0.x + 3 * u ** 2 * t * p1.x + 3 * u * t ** 2 * p2.x + t ** 3 * p3.x
		y = u ** 3 * p0.y + 3 * u ** 2 * t * p1.y + 3 * u * t ** 2 * p2.y + t ** 3 * p3.y
		return x, y

	# Use Newton-Raphson to find t
	# Start with a good initial guess (midpoint)
	t = 0.5
	h = 1e-8  # Step for numerical derivatives

	for _ in range(20):  # Usually converges in just a few iterations
		# Current point
		x, y = bezier_point(t)

		# Check if we're close enough
		if abs(x - target_x) < 1e-10 and abs(y - target_y) < 1e-10:
			return t

		# Calculate numerical derivatives
		if t + h <= 1:
			x_plus, y_plus = bezier_point(t + h)
			dx_dt = (x_plus - x) / h
			dy_dt = (y_plus - y) / h
		else:
			x_minus, y_minus = bezier_point(t - h)
			dx_dt = (x - x_minus) / h
			dy_dt = (y - y_minus) / h

		# Newton-Raphson step for the x-coordinate equation
		# We solve x(t) - target_x = 0
		if abs(dx_dt) > 1e-12:
			t_new = t - (x - target_x) / dx_dt
			# Clamp to valid range
			t_new = max(0, min(1, t_new))
			t = t_new
		else:
			# If dx_dt is too small, try using y-coordinate
			if abs(dy_dt) > 1e-12:
				t_new = t - (y - target_y) / dy_dt
				t_new = max(0, min(1, t_new))
				t = t_new
			else:
				break

	return t

n = Layer.selection[0]

p = n.parent
s = p.segmentAtIndex_(n.index)
s2 = p.segmentAtIndex_(n.index + 2)

intersection = s.intersectionPoints_(s2)[0]

print(path_time_for_point(s, intersection))

closestPoint, pathTime = path.nearestPointOnPath_pathTime_(point, None)

Thanks, but I’d really prefer working only with segments, instead of GSPath objects.

The segments have various API to do exactly that. Have a look at the GSPathSegment.h header (in GlyphsCore).