/* SPDX-FileCopyrightText: 2024-2025 Blender Authors
 *
 * SPDX-License-Identifier: Apache-2.0 */

/* The following files are always to be kept as exact copies of each other:
 * radial_tiling_shared.hh
 * node_radial_tiling_shared.h
 * radial_tiling_shared.h
 * gpu_shader_material_radial_tiling_shared.glsl */

/* The SVM implementation is used as the base shared version because multiple math function
 * identifiers are already used as macros in the SVM code, making a code adaption into an SVM
 * implementation using macros impossible. */

/* Define macros for code adaption. */
#ifdef ADAPT_TO_GEOMETRY_NODES
#  define atanf math::atan
#  define atan2f math::atan2
#  define ceilf math::ceil
#  define cosf math::cos
#  define fabsf math::abs
#  define floorf math::floor
#  define fmaxf math::max
#  define fminf math::min
#  define fractf math::fract
#  define mix math::interpolate
#  define sinf math::sin
#  define sqrtf math::sqrt
#  define sqr math::square
#  define tanf math::tan

#  define make_float2 float2
#  define make_float4 float4
#  define M_PI_F M_PI
#  define M_2PI_F M_TAU
#  define ccl_device
#else
#  ifdef ADAPT_TO_OSL
#    define atanf atan
#    define atan2f atan2
#    define ceilf ceil
#    define cosf cos
#    define fabsf abs
#    define floorf floor
#    define fmaxf max
#    define fminf min
#    define fractf fract
#    define mix mix
#    define sinf sin
#    define sqrtf sqrt
#    define sqr sqr
#    define tanf tan

#    define bool int
#    define float2 vector2
#    define float4 vector4
#    define make_float2 vector2
#    define make_float4 vector4
#    define M_PI_F M_PI
#    define M_2PI_F M_2PI
#    define ccl_device

#    define false 0
#    define true 1
#  else
#    ifdef ADAPT_TO_SVM
/* No code adaption necessary for the SVM implementation as it is the base shared version. */
#    else
/* Adapt code to GLSL by default. */
#      define atanf atan
#      define atan2f atan2
#      define ceilf ceil
#      define cosf cos
#      define fabsf abs
#      define floorf floor
#      define fmaxf max
#      define fminf min
#      define fractf fract
#      define mix mix
#      define sinf sin
#      define sqrtf sqrt
#      define sqr square
#      define tanf tan

#      define make_float2 float2
#      define make_float4 float4
#      define M_PI_F M_PI
#      define M_2PI_F M_TAU
#      define ccl_device
#    endif
#  endif
#endif

/* The geometry nodes has optional specialized functions for certain combinations of input values.
 * These specialized functions output the same values as the general functions, but are faster when
 * they can be used. To reduce the complexity on the GPU kernel while also keeping all rendering
 * implementations the same, they are only enabled in the geometry nodes implementation. */
#ifdef ADAPT_TO_GEOMETRY_NODES
#  define CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(X) (X)
#  define STATIC_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION static
#else
#  define CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(X) true
#  define STATIC_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION
#endif

/* Naming convention for the Radial Tiling node code:
 * Let x and y be 2D vectors.
 * The length of X is expressed as l_x, which is an abbreviation of length_x.
 * The counterclockwise unsinged angle in [0.0, M_TAU] from X to Y is expressed as x_A_y, which
 * is an abbreviation of x_Angle_y. The singed angle in [-M_PI, M_PI] from x to y is expressed
 * as x_SA_y, which is an abbreviation of x_SingedAngle_y. Counterclockwise angles are positive,
 * clockwise angles are negative. A signed angle from x to y of which the output is mirrored along
 * a certain vector is expressed as x_MSA_y, which is an abbreviation of x_MirroredSingedAngle_y.
 *
 * Let z and w be scalars.
 * The ratio z/w is expressed as z_R_w, which is an abbreviation of z_Ratio_y. */

#ifdef ADAPT_TO_GEOMETRY_NODES
static ccl_device float4
calculate_out_variables_full_roundness_irregular_circular(bool calculate_r_gon_parameter_field,
                                                          bool normalize_r_gon_parameter,
                                                          float r_gon_sides,
                                                          float2 coord,
                                                          float l_coord)
{
  float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F;
  float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides;
  float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector;
  float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider);
  float segment_divider_A_coord = x_axis_A_coord -
                                  segment_id * segment_divider_A_next_segment_divider;

  float last_angle_bisector_A_x_axis = M_PI_F -
                                       floorf(r_gon_sides) * segment_divider_A_angle_bisector;
  float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis;
  float l_last_circle_radius = tanf(last_angle_bisector_A_x_axis) /
                               tanf(float(0.5) * (segment_divider_A_angle_bisector +
                                                  last_angle_bisector_A_x_axis));
  float2 last_circle_center = make_float2(
      cosf(last_angle_bisector_A_x_axis) -
          l_last_circle_radius * cosf(last_angle_bisector_A_x_axis),
      l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) -
          sinf(last_angle_bisector_A_x_axis));
  float2 outer_last_bevel_start = last_circle_center +
                                  l_last_circle_radius *
                                      make_float2(cosf(segment_divider_A_angle_bisector),
                                                  sinf(segment_divider_A_angle_bisector));
  float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y /
                                                outer_last_bevel_start.x);
  float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector -
                                                  x_axis_A_outer_last_bevel_start;

  if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) &&
      (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start))
  {
    if ((x_axis_A_coord >=
         M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) ||
        (x_axis_A_coord < segment_divider_A_angle_bisector))
    {
      /* Regular straight part. */

      float l_angle_bisector = float(0.0);
      float r_gon_parameter = float(0.0);

      l_angle_bisector = l_coord *
                         cosf(segment_divider_A_angle_bisector - segment_divider_A_coord);

      float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector -
                                                    x_axis_A_outer_last_bevel_start) /
                                                   tanf(segment_divider_A_angle_bisector);
      float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) *
                                                  x_axis_A_outer_last_bevel_start;

      if (calculate_r_gon_parameter_field) {
        r_gon_parameter = l_angle_bisector *
                          tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord));
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          float normalize_based_on_l_angle_bisector =
              l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) +
              spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
              effective_roundness * x_axis_A_outer_last_bevel_start;

          r_gon_parameter /= normalize_based_on_l_angle_bisector;
        }
      }
      return make_float4(l_angle_bisector,
                         r_gon_parameter,
                         segment_divider_A_angle_bisector,
                         segment_id * segment_divider_A_next_segment_divider +
                             segment_divider_A_angle_bisector);
    }
    else {
      /* Regular rounded part. */

      float r_gon_parameter = float(0.0);
      if (calculate_r_gon_parameter_field) {
        r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord);
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          r_gon_parameter /= segment_divider_A_angle_bisector;
        }
      }
      return make_float4(l_coord,
                         r_gon_parameter,
                         segment_divider_A_angle_bisector,
                         segment_id * segment_divider_A_next_segment_divider +
                             segment_divider_A_angle_bisector);
    }
  }
  else {
    /* Irregular rounded part. */

    /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector
     * to avoid a case distinction. */
    float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x);
    if ((x_axis_A_coord >=
         M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) &&
        (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis))
    {
      nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis;
      nearest_segment_divider_MSA_coord *= -float(1.0);
    }
    float l_angle_bisector = float(0.0);
    float r_gon_parameter = float(0.0);
    float max_unit_parameter = float(0.0);
    float x_axis_A_angle_bisector = float(0.0);

    float l_coord_R_l_last_angle_bisector =
        sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y +
        cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x +
        sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y +
                  cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) +
              sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y));
    float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) /
                                                     cosf(last_angle_bisector_A_x_axis);

    l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_coord /
                       l_coord_R_l_last_angle_bisector;

    if (nearest_segment_divider_MSA_coord < float(0.0)) {
      /* Irregular rounded inner part. */

      if (calculate_r_gon_parameter_field) {
        r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector *
                          (last_angle_bisector_A_x_axis + nearest_segment_divider_MSA_coord);
        if (segment_divider_A_coord < last_angle_bisector_A_x_axis) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector *
                             last_angle_bisector_A_x_axis;
        }
      }
      max_unit_parameter = l_angle_bisector_R_l_last_angle_bisector * last_angle_bisector_A_x_axis;
      x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider +
                                last_angle_bisector_A_x_axis;
    }
    else {
      /* Irregular rounded outer part. */

      float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector -
                                                    x_axis_A_outer_last_bevel_start) /
                                                   tanf(segment_divider_A_angle_bisector);
      float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) *
                                                  x_axis_A_outer_last_bevel_start;

      if (calculate_r_gon_parameter_field) {
        float coord_A_bevel_start = x_axis_A_outer_last_bevel_start -
                                    fabsf(nearest_segment_divider_MSA_coord);
        r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector);

        if (coord_A_bevel_start < spline_start_outer_last_bevel_start) {
          r_gon_parameter +=
              l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * coord_A_bevel_start +
              float(0.5) * (float(1.0) - l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) *
                  sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start;
        }
        else {
          r_gon_parameter += spline_start_outer_last_bevel_start *
                                 (float(0.5) * l_coord *
                                      cosf(outer_last_bevel_start_A_angle_bisector) -
                                  float(0.5)) +
                             coord_A_bevel_start;
        }
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          float normalize_based_on_l_angle_bisector =
              l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) +
              spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
              effective_roundness * x_axis_A_outer_last_bevel_start;
          float normalize_based_on_l_coord =
              l_coord * sinf(outer_last_bevel_start_A_angle_bisector) +
              spline_start_outer_last_bevel_start *
                  (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) +
                   float(0.5)) +
              effective_roundness * x_axis_A_outer_last_bevel_start;

          /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and
           * normalize_based_on_l_coord field converge against the same scalar field. */
          r_gon_parameter /= mix(normalize_based_on_l_angle_bisector,
                                 normalize_based_on_l_coord,
                                 coord_A_bevel_start / x_axis_A_outer_last_bevel_start);
        }
      }
      max_unit_parameter = segment_divider_A_angle_bisector;
      x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider +
                                segment_divider_A_angle_bisector;
    }
    return make_float4(
        l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector);
  }
}
#endif

STATIC_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION ccl_device float4
calculate_out_variables_irregular_circular(bool calculate_r_gon_parameter_field,
                                           bool calculate_max_unit_parameter,
                                           bool normalize_r_gon_parameter,
                                           float r_gon_sides,
                                           float r_gon_roundness,
                                           float2 coord,
                                           float l_coord)
{
#ifdef ADAPT_TO_SVM
  /* Silence compiler warnings. */
  (void)calculate_r_gon_parameter_field;
  (void)calculate_max_unit_parameter;
#endif

  float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F;
  float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides;
  float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector;
  float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider);
  float segment_divider_A_coord = x_axis_A_coord -
                                  segment_id * segment_divider_A_next_segment_divider;
  float segment_divider_A_bevel_start = segment_divider_A_angle_bisector -
                                        atanf((float(1.0) - r_gon_roundness) *
                                              tanf(segment_divider_A_angle_bisector));

  float last_angle_bisector_A_x_axis = M_PI_F -
                                       floorf(r_gon_sides) * segment_divider_A_angle_bisector;
  float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis;
  float inner_last_bevel_start_A_x_axis = last_angle_bisector_A_x_axis -
                                          atanf((float(1.0) - r_gon_roundness) *
                                                tanf(last_angle_bisector_A_x_axis));
  float l_last_circle_radius = r_gon_roundness * tanf(last_angle_bisector_A_x_axis) /
                               tanf(float(0.5) * (segment_divider_A_angle_bisector +
                                                  last_angle_bisector_A_x_axis));
  float2 last_circle_center = make_float2(
      (cosf(inner_last_bevel_start_A_x_axis) /
       cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis)) -
          l_last_circle_radius * cosf(last_angle_bisector_A_x_axis),
      l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) -
          (sinf(inner_last_bevel_start_A_x_axis) /
           cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis)));
  float2 outer_last_bevel_start = last_circle_center +
                                  l_last_circle_radius *
                                      make_float2(cosf(segment_divider_A_angle_bisector),
                                                  sinf(segment_divider_A_angle_bisector));
  float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y /
                                                outer_last_bevel_start.x);
  float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector -
                                                  x_axis_A_outer_last_bevel_start;

  if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) &&
      (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start))
  {
    float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector -
                                         segment_divider_A_bevel_start;

    if (((segment_divider_A_coord >= segment_divider_A_bevel_start) &&
         (segment_divider_A_coord <
          segment_divider_A_next_segment_divider - segment_divider_A_bevel_start)) ||
        (x_axis_A_coord >=
         M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_bevel_start) ||
        (x_axis_A_coord < segment_divider_A_bevel_start))
    {
      /* Regular straight part. */

      float l_angle_bisector = float(0.0);
      float r_gon_parameter = float(0.0);
      float max_unit_parameter = float(0.0);

      l_angle_bisector = l_coord *
                         cosf(segment_divider_A_angle_bisector - segment_divider_A_coord);

      float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                         segment_divider_A_bevel_start;

      if ((x_axis_A_coord >=
           M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) ||
          (x_axis_A_coord < segment_divider_A_angle_bisector))
      {
        /* Irregular rounded outer part. */

        float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector -
                                                      x_axis_A_outer_last_bevel_start) /
                                                     tanf(segment_divider_A_angle_bisector);
        float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) *
                                                    x_axis_A_outer_last_bevel_start;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector -
                                                          segment_divider_A_coord));
          if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) +
                spline_start_outer_last_bevel_start *
                    (float(0.5) * l_angle_bisector + float(0.5)) +
                effective_roundness * x_axis_A_outer_last_bevel_start;

            r_gon_parameter /= normalize_based_on_l_angle_bisector;
          }
        }
      }
      else {
        /* Regular straight part. */

        float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                           segment_divider_A_bevel_start;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector -
                                                          segment_divider_A_coord));
          if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(bevel_start_A_angle_bisector) +
                spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
                r_gon_roundness * segment_divider_A_bevel_start;

            r_gon_parameter /= normalize_based_on_l_angle_bisector;
          }
        }
      }

      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
        r_gon_parameter = l_angle_bisector *
                          tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord));
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }

        if (normalize_r_gon_parameter) {
          if ((x_axis_A_coord >=
               M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) ||
              (x_axis_A_coord < segment_divider_A_angle_bisector))
          {
            /* Irregular rounded outer part. */

            float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector -
                                                          x_axis_A_outer_last_bevel_start) /
                                                         tanf(segment_divider_A_angle_bisector);
            float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) *
                                                        x_axis_A_outer_last_bevel_start;

            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) +
                spline_start_outer_last_bevel_start *
                    (float(0.5) * l_angle_bisector + float(0.5)) +
                effective_roundness * x_axis_A_outer_last_bevel_start;

            r_gon_parameter /= normalize_based_on_l_angle_bisector;
          }
          else {
            /* Regular straight part. */

            float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                               segment_divider_A_bevel_start;

            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(bevel_start_A_angle_bisector) +
                spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
                r_gon_roundness * segment_divider_A_bevel_start;

            r_gon_parameter /= normalize_based_on_l_angle_bisector;
          }
        }
      }
      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
        max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start +
                             r_gon_roundness * segment_divider_A_bevel_start;
      }
      return make_float4(l_angle_bisector,
                         r_gon_parameter,
                         max_unit_parameter,
                         segment_id * segment_divider_A_next_segment_divider +
                             segment_divider_A_angle_bisector);
    }
    else {
      /* Regular rounded part. */

      /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise
       * angles are negative.*/
      float nearest_segment_divider_SA_coord = segment_divider_A_coord -
                                               float(segment_divider_A_coord >
                                                     segment_divider_A_angle_bisector) *
                                                   segment_divider_A_next_segment_divider;
      float l_angle_bisector = float(0.0);
      float r_gon_parameter = float(0.0);
      float max_unit_parameter = float(0.0);

      float l_circle_center = (float(1.0) - r_gon_roundness) /
                              cosf(segment_divider_A_angle_bisector);
      float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center +
                                      sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) *
                                                l_circle_center) +
                                            sqr(r_gon_roundness) - sqr(l_circle_center));

      l_angle_bisector = l_coord / l_coord_R_l_bevel_start;

      float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                         segment_divider_A_bevel_start;

      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
        float coord_A_bevel_start = segment_divider_A_bevel_start -
                                    fabsf(nearest_segment_divider_SA_coord);
        r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector);

        if (coord_A_bevel_start < spline_start_A_bevel_start) {
          r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start +
                             float(0.5) *
                                 (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) *
                                 sqr(coord_A_bevel_start) / spline_start_A_bevel_start;
        }
        else {
          r_gon_parameter += spline_start_A_bevel_start *
                                 (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) -
                                  float(0.5)) +
                             coord_A_bevel_start;
        }
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          float normalize_based_on_l_angle_bisector =
              l_angle_bisector * tanf(bevel_start_A_angle_bisector) +
              spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
              r_gon_roundness * segment_divider_A_bevel_start;
          float normalize_based_on_l_coord =
              l_coord * sinf(bevel_start_A_angle_bisector) +
              spline_start_A_bevel_start *
                  (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) +
              r_gon_roundness * segment_divider_A_bevel_start;

          /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and
           * normalize_based_on_l_coord field converge against the same scalar field. */
          r_gon_parameter /= mix(normalize_based_on_l_angle_bisector,
                                 normalize_based_on_l_coord,
                                 coord_A_bevel_start / segment_divider_A_bevel_start);
        }
      }
      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
        max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start +
                             r_gon_roundness * segment_divider_A_bevel_start;
      }
      return make_float4(l_angle_bisector,
                         r_gon_parameter,
                         max_unit_parameter,
                         segment_id * segment_divider_A_next_segment_divider +
                             segment_divider_A_angle_bisector);
    }
  }
  else {
    float inner_last_bevel_start_A_last_angle_bisector = last_angle_bisector_A_x_axis -
                                                         inner_last_bevel_start_A_x_axis;

    if ((x_axis_A_coord >=
         M_2PI_F - last_segment_divider_A_x_axis + inner_last_bevel_start_A_x_axis) &&
        (x_axis_A_coord < M_2PI_F - inner_last_bevel_start_A_x_axis))
    {
      /* Irregular straight part. */

      float l_angle_bisector = float(0.0);
      float r_gon_parameter = float(0.0);
      float max_unit_parameter = float(0.0);

      float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) /
                                                       cosf(last_angle_bisector_A_x_axis);
      float l_last_angle_bisector = l_coord *
                                    cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord);

      l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector;

      float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                         inner_last_bevel_start_A_x_axis;

      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
        r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector *
                          tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord));
        if (segment_divider_A_coord < last_angle_bisector_A_x_axis) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          float normalize_based_on_l_l_angle_bisector =
              l_angle_bisector_R_l_last_angle_bisector *
              (l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) +
               spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) +
               r_gon_roundness * inner_last_bevel_start_A_x_axis);

          r_gon_parameter /= normalize_based_on_l_l_angle_bisector;
        }
      }
      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
        max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) +
                             l_angle_bisector_R_l_last_angle_bisector *
                                 (spline_start_A_bevel_start *
                                      ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) +
                                       float(0.5)) +
                                  r_gon_roundness * inner_last_bevel_start_A_x_axis);
      }
      return make_float4(l_angle_bisector,
                         r_gon_parameter,
                         max_unit_parameter,
                         segment_id * segment_divider_A_next_segment_divider +
                             last_angle_bisector_A_x_axis);
    }
    else {
      /* Irregular rounded part. */

      /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector
       * to avoid a case distinction. */
      float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x);
      if ((x_axis_A_coord >=
           M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) &&
          (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis))
      {
        nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis;
        nearest_segment_divider_MSA_coord *= -float(1.0);
      }
      float l_angle_bisector = float(0.0);
      float r_gon_parameter = float(0.0);
      float max_unit_parameter = float(0.0);
      float x_axis_A_angle_bisector = float(0.0);

      float l_coord_R_l_last_angle_bisector =
          sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y +
          cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x +
          sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y +
                    cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) +
                sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y));
      float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) /
                                                       cosf(last_angle_bisector_A_x_axis);
      float l_last_angle_bisector = l_coord / l_coord_R_l_last_angle_bisector;

      l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector;

      if (nearest_segment_divider_MSA_coord < float(0.0)) {
        /* Irregular rounded inner part. */

        float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                           inner_last_bevel_start_A_x_axis;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          float coord_A_bevel_start = inner_last_bevel_start_A_x_axis -
                                      fabsf(nearest_segment_divider_MSA_coord);
          r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_coord *
                            sinf(inner_last_bevel_start_A_last_angle_bisector);

          if (coord_A_bevel_start < spline_start_A_bevel_start) {
            r_gon_parameter +=
                l_angle_bisector_R_l_last_angle_bisector *
                (l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) *
                     coord_A_bevel_start +
                 float(0.5) *
                     (float(1.0) - l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector)) *
                     sqr(coord_A_bevel_start) / spline_start_A_bevel_start);
          }
          else {
            r_gon_parameter += l_angle_bisector_R_l_last_angle_bisector *
                               (spline_start_A_bevel_start *
                                    (float(0.5) * l_coord *
                                         cosf(inner_last_bevel_start_A_last_angle_bisector) -
                                     float(0.5)) +
                                coord_A_bevel_start);
          }
          if (segment_divider_A_coord < last_angle_bisector_A_x_axis) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            float normalize_based_on_l_l_angle_bisector =
                l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) +
                spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) +
                r_gon_roundness * inner_last_bevel_start_A_x_axis;
            float normalize_based_on_l_coord =
                l_coord * sinf(inner_last_bevel_start_A_last_angle_bisector) +
                spline_start_A_bevel_start *
                    (float(0.5) * l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) +
                     float(0.5)) +
                r_gon_roundness * inner_last_bevel_start_A_x_axis;

            /* For r_gon_roundness -> 1.0 the normalize_based_on_l_l_angle_bisector field and
             * normalize_based_on_l_coord field converge against the same scalar field. */
            r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector *
                               mix(normalize_based_on_l_l_angle_bisector,
                                   normalize_based_on_l_coord,
                                   coord_A_bevel_start / inner_last_bevel_start_A_x_axis);
          }
        }
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
          max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) +
                               l_angle_bisector_R_l_last_angle_bisector *
                                   (spline_start_A_bevel_start *
                                        ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) +
                                         float(0.5)) +
                                    r_gon_roundness * inner_last_bevel_start_A_x_axis);
        }
        x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider +
                                  last_angle_bisector_A_x_axis;
      }
      else {
        /* Irregular rounded outer part. */

        float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector -
                                                      x_axis_A_outer_last_bevel_start) /
                                                     tanf(segment_divider_A_angle_bisector);
        float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) *
                                                    x_axis_A_outer_last_bevel_start;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          float coord_A_bevel_start = x_axis_A_outer_last_bevel_start -
                                      fabsf(nearest_segment_divider_MSA_coord);
          r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector);

          if (coord_A_bevel_start < spline_start_outer_last_bevel_start) {
            r_gon_parameter += l_coord * cosf(outer_last_bevel_start_A_angle_bisector) *
                                   coord_A_bevel_start +
                               float(0.5) *
                                   (float(1.0) -
                                    l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) *
                                   sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start;
          }
          else {
            r_gon_parameter += spline_start_outer_last_bevel_start *
                                   (float(0.5) * l_coord *
                                        cosf(outer_last_bevel_start_A_angle_bisector) -
                                    float(0.5)) +
                               coord_A_bevel_start;
          }
          if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) +
                spline_start_outer_last_bevel_start *
                    (float(0.5) * l_angle_bisector + float(0.5)) +
                effective_roundness * x_axis_A_outer_last_bevel_start;
            float normalize_based_on_l_coord =
                l_coord * sinf(outer_last_bevel_start_A_angle_bisector) +
                spline_start_outer_last_bevel_start *
                    (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) +
                     float(0.5)) +
                effective_roundness * x_axis_A_outer_last_bevel_start;

            /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and
             * normalize_based_on_l_coord field converge against the same scalar field. */
            r_gon_parameter /= mix(normalize_based_on_l_angle_bisector,
                                   normalize_based_on_l_coord,
                                   coord_A_bevel_start / x_axis_A_outer_last_bevel_start);
          }
        }
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
          float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector -
                                               segment_divider_A_bevel_start;
          float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                             segment_divider_A_bevel_start;

          max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start +
                               r_gon_roundness * segment_divider_A_bevel_start;
        }
        x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider +
                                  segment_divider_A_angle_bisector;
      }
      return make_float4(
          l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector);
    }
  }
}

ccl_device float4 calculate_out_variables(bool calculate_r_gon_parameter_field,
                                          bool calculate_max_unit_parameter,
                                          bool normalize_r_gon_parameter,
                                          float r_gon_sides,
                                          float r_gon_roundness,
                                          float2 coord)
{
#ifdef ADAPT_TO_SVM
  /* Silence compiler warnings. */
  (void)calculate_r_gon_parameter_field;
  (void)calculate_max_unit_parameter;
#endif

  float l_coord = sqrtf(sqr(coord.x) + sqr(coord.y));
  float4 out_variables;

  if (fractf(r_gon_sides) == float(0.0)) {
    float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F;
    float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides;
    float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector;
    float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider);
    float segment_divider_A_coord = x_axis_A_coord -
                                    segment_id * segment_divider_A_next_segment_divider;

    if (r_gon_roundness == float(0.0)) {
      /* Regular straight part. */

      float l_angle_bisector = float(0.0);
      float r_gon_parameter = float(0.0);
      float max_unit_parameter = float(0.0);

      l_angle_bisector = l_coord *
                         cosf(segment_divider_A_angle_bisector - segment_divider_A_coord);

      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
        r_gon_parameter = l_angle_bisector *
                          tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord));
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter && (r_gon_sides != float(2.0))) {
          r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector);
        }
      }
      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
        max_unit_parameter = (r_gon_sides != float(2.0)) ? tanf(segment_divider_A_angle_bisector) :
                                                           float(0.0);
      }
      out_variables = make_float4(l_angle_bisector,
                                  r_gon_parameter,
                                  max_unit_parameter,
                                  segment_id * segment_divider_A_next_segment_divider +
                                      segment_divider_A_angle_bisector);
    }
    else if (r_gon_roundness == float(1.0)) {
      /* Regular rounded part. */

      float r_gon_parameter = float(0.0);
      if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
        r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord);
        if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
          r_gon_parameter *= -float(1.0);
        }
        if (normalize_r_gon_parameter) {
          r_gon_parameter /= segment_divider_A_angle_bisector;
        }
      }
      out_variables = make_float4(l_coord,
                                  r_gon_parameter,
                                  segment_divider_A_angle_bisector,
                                  segment_id * segment_divider_A_next_segment_divider +
                                      segment_divider_A_angle_bisector);
    }
    else {
      float segment_divider_A_bevel_start = segment_divider_A_angle_bisector -
                                            atanf((float(1.0) - r_gon_roundness) *
                                                  tanf(segment_divider_A_angle_bisector));
      float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector -
                                           segment_divider_A_bevel_start;

      if ((segment_divider_A_coord >=
           segment_divider_A_next_segment_divider - segment_divider_A_bevel_start) ||
          (segment_divider_A_coord < segment_divider_A_bevel_start))
      {
        /* Regular rounded part. */

        /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise
         * angles are negative.*/
        float nearest_segment_divider_SA_coord = segment_divider_A_coord -
                                                 float(segment_divider_A_coord >
                                                       segment_divider_A_angle_bisector) *
                                                     segment_divider_A_next_segment_divider;
        float l_angle_bisector = float(0.0);
        float r_gon_parameter = float(0.0);
        float max_unit_parameter = float(0.0);

        float l_circle_center = (float(1.0) - r_gon_roundness) /
                                cosf(segment_divider_A_angle_bisector);
        float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center +
                                        sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) *
                                                  l_circle_center) +
                                              sqr(r_gon_roundness) - sqr(l_circle_center));

        l_angle_bisector = l_coord / l_coord_R_l_bevel_start;

        float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                           segment_divider_A_bevel_start;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          float coord_A_bevel_start = segment_divider_A_bevel_start -
                                      fabsf(nearest_segment_divider_SA_coord);
          r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector);

          if (coord_A_bevel_start < spline_start_A_bevel_start) {
            r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start +
                               float(0.5) *
                                   (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) *
                                   sqr(coord_A_bevel_start) / spline_start_A_bevel_start;
          }
          else {
            r_gon_parameter += spline_start_A_bevel_start *
                                   (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) -
                                    float(0.5)) +
                               coord_A_bevel_start;
          }
          if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(bevel_start_A_angle_bisector) +
                spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
                r_gon_roundness * segment_divider_A_bevel_start;
            float normalize_based_on_l_coord =
                l_coord * sinf(bevel_start_A_angle_bisector) +
                spline_start_A_bevel_start *
                    (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) +
                r_gon_roundness * segment_divider_A_bevel_start;

            /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and
             * normalize_based_on_l_coord field converge against the same scalar field. */
            r_gon_parameter /= mix(normalize_based_on_l_angle_bisector,
                                   normalize_based_on_l_coord,
                                   coord_A_bevel_start / segment_divider_A_bevel_start);
          }
        }
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
          max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start +
                               r_gon_roundness * segment_divider_A_bevel_start;
        }
        out_variables = make_float4(l_angle_bisector,
                                    r_gon_parameter,
                                    max_unit_parameter,
                                    segment_id * segment_divider_A_next_segment_divider +
                                        segment_divider_A_angle_bisector);
      }
      else {
        /* Regular straight part. */

        float l_angle_bisector = float(0.0);
        float r_gon_parameter = float(0.0);
        float max_unit_parameter = float(0.0);

        l_angle_bisector = l_coord *
                           cosf(segment_divider_A_angle_bisector - segment_divider_A_coord);

        float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) *
                                           segment_divider_A_bevel_start;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector -
                                                          segment_divider_A_coord));
          if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            float normalize_based_on_l_angle_bisector =
                l_angle_bisector * tanf(bevel_start_A_angle_bisector) +
                spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) +
                r_gon_roundness * segment_divider_A_bevel_start;

            r_gon_parameter /= normalize_based_on_l_angle_bisector;
          }
        }
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
          max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start +
                               r_gon_roundness * segment_divider_A_bevel_start;
        }
        out_variables = make_float4(l_angle_bisector,
                                    r_gon_parameter,
                                    max_unit_parameter,
                                    segment_id * segment_divider_A_next_segment_divider +
                                        segment_divider_A_angle_bisector);
      }
    }
  }
  else {
    if (r_gon_roundness == float(0.0)) {
      float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F;
      float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides;
      float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector;
      float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider);
      float segment_divider_A_coord = x_axis_A_coord -
                                      segment_id * segment_divider_A_next_segment_divider;

      float last_angle_bisector_A_x_axis = M_PI_F -
                                           floorf(r_gon_sides) * segment_divider_A_angle_bisector;
      float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis;

      if (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis) {
        /* Regular straight part. */

        float l_angle_bisector = float(0.0);
        float r_gon_parameter = float(0.0);
        float max_unit_parameter = float(0.0);

        l_angle_bisector = l_coord *
                           cosf(segment_divider_A_angle_bisector - segment_divider_A_coord);
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector -
                                                          segment_divider_A_coord));
          if (segment_divider_A_coord < segment_divider_A_angle_bisector) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector);
          }
        }
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
          max_unit_parameter = tanf(segment_divider_A_angle_bisector);
        }
        out_variables = make_float4(l_angle_bisector,
                                    r_gon_parameter,
                                    max_unit_parameter,
                                    segment_id * segment_divider_A_next_segment_divider +
                                        segment_divider_A_angle_bisector);
      }
      else {
        /* Irregular straight part. */

        float l_angle_bisector = float(0.0);
        float r_gon_parameter = float(0.0);
        float max_unit_parameter = float(0.0);

        float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) /
                                                         cosf(last_angle_bisector_A_x_axis);
        float l_last_angle_bisector = l_coord *
                                      cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord);

        l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector;

        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) {
          r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector *
                            tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord));
          if (segment_divider_A_coord < last_angle_bisector_A_x_axis) {
            r_gon_parameter *= -float(1.0);
          }
          if (normalize_r_gon_parameter) {
            r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector *
                               tanf(last_angle_bisector_A_x_axis);
          }
        }
        if (CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) {
          max_unit_parameter = tanf(last_angle_bisector_A_x_axis);
        }
        out_variables = make_float4(l_angle_bisector,
                                    r_gon_parameter,
                                    max_unit_parameter,
                                    segment_id * segment_divider_A_next_segment_divider +
                                        last_angle_bisector_A_x_axis);
      }
    }
#ifdef ADAPT_TO_GEOMETRY_NODES
    else if (r_gon_roundness == float(1.0)) {
      out_variables = calculate_out_variables_full_roundness_irregular_circular(
          calculate_r_gon_parameter_field, normalize_r_gon_parameter, r_gon_sides, coord, l_coord);
    }
#endif
    else {
      out_variables = calculate_out_variables_irregular_circular(calculate_r_gon_parameter_field,
                                                                 calculate_max_unit_parameter,
                                                                 normalize_r_gon_parameter,
                                                                 r_gon_sides,
                                                                 r_gon_roundness,
                                                                 coord,
                                                                 l_coord);
    }
  }

  if ((coord.x == float(0.0)) && (coord.y == float(0.0))) {
    /* The r_gon_parameter is defined to 0 when it is not normalized and the input coordinate is
     * the zero vector. */
    out_variables.y = float(0.0);
  }

  if (normalize_r_gon_parameter) {
    /* Normalize r_gon_parameter from a [-1, 1] interval to a [0, 1] interval. */
    out_variables.y = float(0.5) * out_variables.y + float(0.5);
  }
  else {
    out_variables.x -= float(1.0);
  }

  return out_variables;
}

ccl_device float calculate_out_segment_id(float r_gon_sides, float2 coord)
{
  return floorf(r_gon_sides *
                ((atan2f(coord.y, coord.x) / M_2PI_F) + float(coord.y < float(0.0))));
}

/* Undefine macros used for code adaption. */
#ifdef ADAPT_TO_GEOMETRY_NODES
#  undef atanf
#  undef atan2f
#  undef ceilf
#  undef cosf
#  undef fabsf
#  undef floorf
#  undef fmaxf
#  undef fminf
#  undef fractf
#  undef mix
#  undef sinf
#  undef sqrtf
#  undef sqr
#  undef tanf

#  undef make_float2
#  undef make_float4
#  undef ccl_device
#else
#  ifdef ADAPT_TO_OSL
#    undef atanf
#    undef atan2f
#    undef ceilf
#    undef cosf
#    undef fabsf
#    undef floorf
#    undef fmaxf
#    undef fminf
#    undef fractf
#    undef mix
#    undef sinf
#    undef sqrtf
#    undef sqr
#    undef tanf

#    undef bool
#    undef float2
#    undef float4
#    undef make_float2
#    undef make_float4
#    undef M_PI_F
#    undef M_2PI_F
#    undef ccl_device

#    undef false
#    undef true
#  else
#    ifdef ADAPT_TO_SVM
/* No code adaption necessary for the SVM implementation as it is the base shared version. */
#    else
/* Adapt code to GLSL by default. */
#      undef atanf
#      undef atan2f
#      undef ceilf
#      undef cosf
#      undef fabsf
#      undef floorf
#      undef fmaxf
#      undef fminf
#      undef fractf
#      undef mix
#      undef sinf
#      undef sqrtf
#      undef sqr
#      undef tanf

#      undef make_float2
#      undef make_float4
#      undef M_PI_F
#      undef M_2PI_F
#      undef ccl_device
#    endif
#  endif
#endif

#undef CHECK_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION
#undef STATIC_ONLY_IN_GEOMETRY_NODES_IMPLEMENTATION
