cut a polygon with a polyline (not the contrary)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Sylvain22

Hi,

I looked for some existing code in Geomery to cut my polygon with the player’s tail in a Qix / Gals panic like game I’m working on:

But as far I understand there’s no such method exposed.

So I coded my own:

start_edge and end_edge are index of the point in the polygon representing the playground (white square on the screenshot above). In this case start_edge = 2, end_edge = 1

PolygonIterator is a class with a little magic for looping on the edge in the polygon array of point, which on a given size known when to go through the end of the Array and restart at the beginning.

func cut(tail, start_edge, end_edge):
	var pol1 : Array = tail.points

	# process of linking the 2 polygons:
	# pol1
	# 1. all the tail points
	# 2. the area points from where the tail ends in clockwise order throught
	#    where the tail starts

	if is_on_corner(pol1[0], start_edge):
		start_edge = prev_corner(start_edge)
	
	if is_on_corner(pol1[-1], end_edge):
		end_edge = next_corner(end_edge)

	var iter = PolygonIterator.new(pol.polygon.size(), end_edge, start_edge)
	print(iter)
	
	for i in iter:
		print("cut: add point %d" % i)
		pol1.append(pol.polygon[i])
	
	var polys = Geometry.clip_polygons_2d(pol.polygon, pol1)
	print("cliped: %d" % len(polys))
	return [ pol1, polys[0] ]

ThePolygonIterator class code:

class_name PolygonIterator
# this iterator loop over start to the end to cover all points
# excluding  start, including  end

var start
var current
var end
var count = 0
var size
var counter = 0

func _init(size, start, stop):
	self.size = size
	self.start = start
	self.current = start
	if stop < size:
		self.end = stop
	else:
		self.end = size - 1
		
	if start < end:
		count = end - start
	elif start == end:
		count = 0
	else:
		count = end + (size - start)	
	
func should_continue():
	return counter > 0

func init_count():
	counter = count

func _iter_init(arg):
	init_count()
	current = next_val(start)
	return should_continue()

func next_val(val):
	return (val + 1 + size) % size
	
func _iter_next(arg):
	counter -= 1
	current = next_val(current)
	return should_continue()
	
func _iter_get(arg):
	return current
	
func _to_string():
	return "iter: (%d) start %d end %d count %d" % [ size, start, end, count ]

So I first complete my Polyline (tail) with some polygon’s point in order to have a polygon, and then I subtract it to the playground’s polygon with clip_polygons_2d().

Is there better way to perform it?

Regards,
Sylvain.

:bust_in_silhouette: Reply From: Xrayez

There’s no such method exposed because the underlying library for polygon clipping in Godot (Clipper) doesn’t support such operation.

You can in theory simulate this by using Geometry.offset_polyline_2d with a very small delta, which will grow your polyline into a thin polygon, and then do the clipping between polygons. Or, you can generate two rectangles along with a polyline (if it’s a straight line), and do Geometry.intersect_polygons_2d two times against your subject polygon on the both side of the polyline.