API proposal : GSNode.segments

Could it be useful to add an attribute to GSNode to access the segments linked to it?

GSNode.segment could run :

def get_node_segment(node):
    segments_with_node = []

    # Helper function to extract point coordinates
    def get_point_coords(point):
        return (point.x, point.y)

    # Determine the segment to which the node belongs based on its type
    if node.type != "offcurve":
        pos = get_point_coords(node)
        for path in node.layer.paths:
            for segment in path.segments:
                start_point = get_point_coords(segment.pointAtIndex_(0))
                end_point = get_point_coords(segment.lastPoint())

                if pos == start_point or pos == end_point:
                    segments_with_node.append(segment)
    else:
        nextCurve_node = node.nextNode if node.nextNode.type != "offcurve" else None
        prevCurve_node = node.prevNode if node.prevNode.type != "offcurve" else None

        for path in node.layer.paths:
            for segment in path.segments:
                start_point = get_point_coords(segment.pointAtIndex_(0))
                end_point = get_point_coords(segment.lastPoint())

                if nextCurve_node and get_point_coords(nextCurve_node) == end_point:
                    segments_with_node.append(segment)
                if prevCurve_node and get_point_coords(prevCurve_node) == start_point:
                    segments_with_node.append(segment)

    return segments_with_node

EDIT : This one also return single segment for offcurve node

What would be the use case for this?

The code would be pretty slow. e.g. path.segments is iterating all nodes and makes a list of new GSPathSegment objects every time you call it. If you really need the segment, the method could look like this:

def get_node_segment(node):
	segment = None
	oncurve_node = node
	index = node.index
	path = node.parent
	while oncurve_node.type == OFFCURVE:
		index += 1
		oncurve_node = path.nodes[index]
	if oncurve_node.type == LINE:
		segment = GSPathSegment(path.nodes[index - 1].position, oncurve_node.position)
	if oncurve_node.type == CURVE:
		segment = GSPathSegment(path.nodes[index - 3].position, path.nodes[index - 2].position, path.nodes[index - 1].position, oncurve_node.position)
	return segment

node = Layer.shapes[0].nodes[1]
print(get_node_segment(node))

this method is working differently as it is only returned one segment that ends at that node. But is should be easy to fine the next segment, too.

And why do you need get_point_coords()? Why not use the NSPoints directly?

1 Like

I’ve been using this direct approach without issues

def get_node_segments(node):
	segment1, segment2 = (), ()

	# the node is an offcurve
	if node.type == OFFCURVE:
		segment1 = (node.prevNode, node, node.nextNode, node.nextNode.nextNode) if node.nextNode.type == OFFCURVE else (node.prevNode.prevNode, node.prevNode, node, node.nextNode)

	# the node is an oncurve
	else:
		if node.prevNode:
			segment1 = (node, node.prevNode, node.prevNode.prevNode, node.prevNode.prevNode.prevNode) if node.prevNode.type == OFFCURVE else (node, node.prevNode)
		if node.nextNode:
			segment2 = (node, node.nextNode, node.nextNode.nextNode, node.nextNode.nextNode.nextNode) if node.nextNode.type == OFFCURVE else (node, node.nextNode)

	return segment1, segment2
1 Like

If it is performance critical, don’t use .prevNode and .nextNode. Better use the method I showed above (by keeping track of the index). At least store the result from those properties.

2 Likes