Dividing distance between vector2 with leftover

Godot Version

4.7.2

Question

Hello, I’m experiencing a left over on distance dividing between two Vector2 coordinates.

The purpose is have same length added 10 between steps, and the last step would have leftover if is less then divider.

I made this minimalistic code to show what I mean:

func divide_junctions_to_equal_parts() -> void:
	var divider : int = 10
	var start : Vector2 = Vector2(450.0, 525.0)
	var stop : Vector2 = Vector2(450.0, 300.0)
	var direction = start.direction_to(stop)
	var distance = start.distance_to(stop)
	var steps = distance/divider
	print(steps, direction, distance)
	for step in steps:
		print(start +(direction*(step*divider)))

the last iteration from loop returns

(450.0, 305.0).

You are casting to an integer either by divider or iterating steps. This will be off the mark because your steps is truncated. Try printing a float version of steps, notice any decimals that would be removed

hmm, I have print both float(steps), steps and it’s same value of 22.5.

print(float(steps),steps, direction, distance)
22.522.5(0.0, -1.0)225.0
(450.0, 525.0)
(450.0, 515.0)
(450.0, 505.0)
(450.0, 495.0)
(450.0, 485.0)
(450.0, 475.0)
(450.0, 465.0)
(450.0, 455.0)
(450.0, 445.0)
(450.0, 435.0)
(450.0, 425.0)
(450.0, 415.0)
(450.0, 405.0)
(450.0, 395.0)
(450.0, 385.0)
(450.0, 375.0)
(450.0, 365.0)
(450.0, 355.0)
(450.0, 345.0)
(450.0, 335.0)
(450.0, 325.0)
(450.0, 315.0)
(450.0, 305.0)

issue is the last position I would need (450.0, 300.0) after (450.0, 305.0).

Would I need to introduce new variable to keep track of some subtractions?

So the for loop will perform 22 iterations, it can’t perform 22.5 iterations.

edit: Fun tip/function I just found prints will add a space between each argument, makes these big variable cluster print easier to read

print(float(steps),steps) # 22.522.5
prints(float(steps),steps) # 22.5 22.5

yeah, could add one more step

	for step in steps+1:
		print(start +(direction*(step*divider)))

but this will results in

(450.0, 305.0)
(450.0, 295.0)

Would need somehow keep leftover (0.0 , 5.0) for 23rd iteration to be added

Why are you doing steps as distance/divider?

Steps is 10.

Edit: Oh I see. My bad. Sorry.

the divider be fixed measure, and distance can vary if vector2 change, so amount of steps might be different.

You can use fmod(steps, 1.0) to get the remaining decimals, then use that for your last step

for step in steps:
	print(start +(direction*(step*divider)))
var remain := fmod(steps, 1.0)
print(start + (direction * (remain * divider)))

It may help to paint us the bigger picture, why the for loop iterations? It smells like a tween would do you better.

I’m using it for traffic to divide road into segments, then those segments be class but first I need to assign them individual positions start, stop from overall road start, stop.

I also thought about move_toward() but it would still do the leftover.

move_toward may work for this since you have fixed segment size, I think computationally it may be (a little) worse since it computes the direction/distance on each invocation.

var current_step := start
while current_step != end:
    print(current_step)
    current_step = current_step.move_toward(end, 10)

And it doesn’t calculate the segment count ahead of time, which is probably helpful for resizeing your arrays if you are using any.

Sounds good though! I think your path is good and does not smell tween-able anymore

This seem to works fine, some improvements suggested?

extends  Node2D
func _ready() -> void:
	var start : Vector2 = Vector2(300.0, -100.0)
	var stop : Vector2 = Vector2(450.0, 300.0)
	prints(divide_junctions_to_equal_parts(start,stop))
	
func divide_junctions_to_equal_parts(start: Vector2, stop: Vector2) -> Array:
	var divider: float = 10.0
	var direction = start.direction_to(stop)
	var distance = start.distance_to(stop)
	var steps: int = int(distance / divider)
	var points: Array
	for step in steps:
		var divided_position = start + direction * (step * divider)
		points.append(divided_position)
	var leftover_point = start + direction * distance
	points.append(leftover_point)
	return points


[(300.0, -100.0), (303.5112, -90.63671), (307.0225, -81.27341), (310.5337, -71.91013), (314.0449, -62.54683), (317.5562, -53.18354), (321.0674, -43.82025), (324.5786, -34.45695), (328.0899, -25.09367), (331.6011, -15.73037), (335.1123, -6.367081), (338.6236, 2.996208), (342.1348, 12.3595), (345.6461, 21.72279), (349.1573, 31.08609), (352.6685, 40.44937), (356.1797, 49.81267), (359.691, 59.17596), (363.2022, 68.53926), (366.7134, 77.90254), (370.2247, 87.26584), (373.7359, 96.62914), (377.2472, 105.9924), (380.7584, 115.3557), (384.2696, 124.719), (387.7809, 134.0823), (391.2921, 143.4456), (394.8033, 152.8089), (398.3146, 162.1722), (401.8258, 171.5355), (405.337, 180.8987), (408.8483, 190.2621), (412.3595, 199.6253), (415.8707, 208.9886), (419.382, 218.3519), (422.8932, 227.7152), (426.4044, 237.0785), (429.9156, 246.4418), (433.4269, 255.8051), (436.9381, 265.1684), (440.4494, 274.5317), (443.9606, 283.895), (450.0, 300.0)]

Use move_toward() as @gertkeno suggested. Much more elegant that way as you don’t need to manually do the boundary check, although what you have is fine too.

I think move_toward with my loop would still miss the last (or first) iteration. Inclusive loops are annoying :\

Path2D is also .sample()-able so this may be repeated work.

I couldn’t figure out how to stop while loop using move_toward() and add leftover iteration

I didn’t found this sample() func is it PathFollow2D node you are referring to ?

func divide_segment(start: Vector2, end: Vector2, divisions: int = 10) -> Array:
	var current := start
	var positions := []
	var step: float = floor(current.distance_to(end) / divisions)
	while not current.is_equal_approx(end):
		positions.append(current)
		current = current.move_toward(end, step)
	positions.append(current)
	return positions

trick was in the floor never used it before :slight_smile:

extends  Node2D
@onready var one: Vector2 = Vector2(100.0, 200.0)
@onready var two : Vector2 = Vector2(450.0, 300.0)
@onready var points_original = divide_junctions_to_equal_parts(one,two)
@onready var points_normalized = divide_segment(one,two)

func _ready() -> void:
	prints(points_original.size(),points_normalized.size())
	
func divide_junctions_to_equal_parts(start: Vector2, stop: Vector2) -> Array:
	var divider: float = 10.0
	var direction = start.direction_to(stop)
	var distance = start.distance_to(stop)
	var steps: int = int(distance / divider)
	var points: Array
	for step in steps:
		var divided_position = start + direction * (step * divider)
		points.append(divided_position)
	var leftover_point = start + direction * distance
	points.append(leftover_point)
	return points
	
func divide_segment(start: Vector2, end: Vector2, divisions: int = 10) -> Array:
	var current := start
	var positions := []
	var step: float = floor(current.distance_to(end) / divisions)
	while not current.is_equal_approx(end):
		positions.append(current)
		current = current.move_toward(end, step)
	positions.append(current)
	return positions

The return is

37 12

Why is it ?

My function takes the number of divisions as the third argument. You can easily rework it to take the step length instead. It gets even simpler then:

func divide_segment(start: Vector2, end: Vector2, step: float = 10.0) -> Array:
	var current := start
	var positions := []
	while not current.is_equal_approx(end):
		positions.append(current)
		current = current.move_toward(end, step)
	positions.append(current)
	return positions
extends  Node2D
@onready var one: Vector2 = Vector2(100.0, 200.0)
@onready var two : Vector2 = Vector2(450.0, 300.0)
@onready var points_original = divide_junctions_to_equal_parts(one,two)
@onready var points_normalized = divide_segment(one,two, one.distance_to(two)/10.0)

func _ready() -> void:
	prints(points_original.size(),points_normalized.size())
	
func divide_junctions_to_equal_parts(start: Vector2, stop: Vector2) -> Array:
	var divider: float = 10.0
	var direction = start.direction_to(stop)
	var distance = start.distance_to(stop)
	var steps: int = int(distance / divider)
	var points: Array
	for step in steps:
		var divided_position = start + direction * (step * divider)
		points.append(divided_position)
	var leftover_point = start + direction * distance
	points.append(leftover_point)
	return points
	
func divide_segment(start: Vector2, end: Vector2, divisions: int = 10) -> Array:
	var current := start
	var positions := []
	var step: float = floor(current.distance_to(end) / divisions)
	while not current.is_equal_approx(end):
		positions.append(current)
		current = current.move_toward(end, step)
	positions.append(current)
	return positions

now return is

37 38

:slight_smile: one off