Skip to contents

Draws multiple evenly-spaced and non-overlapping curves in a flow field, using the Jobard and Lefer (1997) algorithm.

Usage

even_spaced_curves(
  x_start,
  y_start,
  n_curves,
  n_steps,
  min_steps_allowed,
  step_length,
  d_sep,
  flow_field
)

Arguments

x_start

the x coordinate of the starting point from which the function will start to draw your curve.

y_start

the y coordinate of the starting point from which the function will start to draw your curve.

n_curves

the number of curves you want to draw.

n_steps

the number of steps used to draw each curve.

min_steps_allowed

the minimum number of steps allowed in each curve (see Details for more info).

step_length

the length/distance taken in each step.

d_sep

the "separation distance", i.e., the amount of distance that each curve must be from neighbouring curves.

flow_field

a 2D matrix with double values, each double value represents an angle value.

Value

This function returns a tibble object with 6 columns:

  • curve_id: the ID of the curve.

  • x: the x coordinates of each point that represents the curve.

  • y: the y coordinates of each point that represents the curve.

  • direction_id: which direction that the algorithm was following when drawing the current point (0 means from left to right, 1 means from right to left).

  • step_id: the ID (or the number) of the current step.

  • steps_taken: the number of steps taken to draw the current curve.

Details

You can use this function to draw multiple curves in a flow field. Each curve will be non-overlapping and evenly-space between it's neighbors.

In essence, this function takes a single starting point (x_start and y_start) in the flow field, and it starts to draw a initial curve in the flow field. After that, the function starts a loop process, to draw n_curves - 1 curves from this initial curve. In other words, all the curves that are drawn into the flow field are derived from this initial curve.

Is worth noting that each starting point represents the "middle point" of the curve, because the function draws a curve in both directions. That is why we have the direction_id column in the output of this function. It indicates what direction the function was following when drawing the current section (or "step") of the current curve.

In each step of the way, the function will check if the current curve that is being drawn is too close to it's neighbors, by calculating it's distance to the existing curves around it. If the current curve is getting too close to a neighbor curve, then, the function will stop drawing the current curve, and will start to draw the next curve in the queue.

If the function starts to draw a new curve, but the starting point of this new curve is already too close to other existing curves, then, the function completely drops this curve (i.e. it "gives up" on drawing this curve), and jumps to the next curve in the queue.

Also, if the function draws a new curve, but this curve have less than min_allowed_steps steps, then, this curve is also completely dropped. This avoids getting a high number of curves that are too short.

In other words, it is not guaranteed that this function will draw exactly n_curves curves into the field, because, it might not have enough space for n_curves curves, considering your current settings. So, the function will attempt to draw as many curves as possible. As long as they are not overlapping each other, and they are not too close to other neighbouring curves, the function will continue to draw curves into the field.

For more details about how the algorithm works, check: https://pedro-faria.netlify.app/posts/2024/2024-02-19-flow-even/en/

References

Jobard, Bruno, and Wilfrid Lefer. 1997. “Creating Evenly-Spaced Streamlines of Arbitrary Density.” In Visualization in Scientific Computing ’97, edited by Wilfrid Lefer and Michel Grave, 43–55. Vienna: Springer Vienna.

Examples

library(ambient)
set.seed(50)
flow_field <- noise_perlin(c(240, 240))
# The coordinates x = 45 and y = 24 are used as the starting point:
curves <- even_spaced_curves(
  45, 24,
  100,
  30,
  5,
  0.01*240,
  0.5,
  flow_field
)