// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_PARAM_H_
#define FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_PARAM_H_

#include "flutter/impeller/geometry/path_source.h"
#include "flutter/impeller/geometry/point.h"
#include "flutter/impeller/geometry/rect.h"
#include "flutter/impeller/geometry/rounding_radii.h"
#include "flutter/impeller/geometry/size.h"

namespace impeller {

// A utility struct that expands input parameters for a rounded superellipse to
// drawing variables.
struct RoundSuperellipseParam {
  // Parameters for drawing a square-like rounded superellipse.
  //
  // This structure is used to define an octant of an arbitrary rounded
  // superellipse.
  //
  // A `se_n` of 0 means that the radius is 0, and this octant is a square
  // of size `se_a` at `offset` and all other fields are ignored.
  struct Octant {
    // The offset of the square-like rounded superellipse's center from the
    // origin.
    //
    // All other coordinates in this structure are relative to this point.
    Point offset;

    // The semi-axis length of the superellipse.
    Scalar se_a;
    // The degree of the superellipse.
    //
    // If this value is 0, then this octant is a square of size `se_a`.
    Scalar se_n;
    // The range of the parameter "theta" used to define the superellipse curve.
    //
    // The "theta" is not the angle of the curve but the implicit parameter
    // used in the curve's parametric equation.
    Scalar se_max_theta;

    // The coordinate of the top left end of the circular arc, relative to the
    // `offset` point.
    Point circle_start;
    // The center of the circular arc, relative to the `offset` point.
    Point circle_center;
    // The angular span of the circular arc, measured in radians.
    Radians circle_max_angle;
  };

  // Parameters for drawing a rounded superellipse with equal radius size for
  // all corners.
  //
  // This structure is used to define a quadrant of an arbitrary rounded
  // superellipse.
  struct Quadrant {
    // The offset of the rounded superellipse's center from the origin.
    //
    // All other coordinates in this structure are relative to this point.
    Point offset;

    // The scaling factor used to transform a normalized rounded superellipse
    // back to its original, unnormalized shape.
    //
    // Normalization refers to adjusting the original curve, which may have
    // asymmetrical corner sizes, into a symmetrical one by reducing the longer
    // radius to match the shorter one. For instance, to draw a rounded
    // superellipse with size (200, 300) and radii (20, 10), the function first
    // draws a normalized RSE with size (100, 300) and radii (10, 10), then
    // scales it by (2x, 1x) to restore the original proportions.
    //
    // Normalization also flips the curve to the first quadrant (positive x and
    // y) if it originally resides in another quadrant. This affects the signs
    // of `signed_scale`.
    Point signed_scale;

    // The parameters for the two octants that make up this quadrant after
    // normalization.
    Octant top;
    Octant right;
  };

  // The parameters for the four quadrants that make up the full contour.
  //
  // If `all_corners_same` is true, then only `top_right` is popularized.
  Quadrant top_right;
  Quadrant bottom_right;
  Quadrant bottom_left;
  Quadrant top_left;

  // If true, all corners are the same and only `top_right` is popularized.
  bool all_corners_same;

  // Create a param for a rounded superellipse with the specific bounds and
  // radii.
  [[nodiscard]] static RoundSuperellipseParam MakeBoundsRadii(
      const Rect& bounds,
      const RoundingRadii& radii);

  [[nodiscard]] static RoundSuperellipseParam MakeBoundsRadius(
      const Rect& bounds,
      Scalar radius);

  // Returns whether this rounded superellipse contains the point.
  //
  // This method does not perform any prescreening such as comparing the point
  // with the bounds, which is recommended for callers.
  bool Contains(const Point& point) const;

  // Dispatch the path operations of this rounded superellipse to the receiver.
  void Dispatch(PathReceiver& receiver) const;

  // A factor used to calculate the "gap", defined as the distance from the
  // midpoint of the curved corners to the nearest sides of the bounding box.
  //
  // When the corner radius is symmetrical on both dimensions, the midpoint of
  // the corner is where the circular arc intersects its quadrant bisector. When
  // the corner radius is asymmetrical, since the corner can be considered
  // "elongated" from a symmetrical corner, the midpoint is transformed in the
  // same way.
  //
  // Experiments indicate that the gap is linear with respect to the corner
  // radius on that dimension.
  static constexpr Scalar kGapFactor = 0.29289321881f;  // 1-cos(pi/4)
};

}  // namespace impeller

#endif  // FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_PARAM_H_
