// Copyright (c) 2024 The YAC Authors
//
// SPDX-License-Identifier: BSD-3-Clause

#ifndef CLIPPING_H
#define CLIPPING_H

#include "grid_cell.h"

struct yac_circle;

/**
  * \brief cell clipping to get the cells describing the intersections
  *
  * The routine takes (a list of) source cells and a target cell. It sets the
  * target cell data and does some further initialisation. Thus it needs to be
  * called for each new target cell intersection calculation
  *
  * The vertices of source and target cells can be either provided in a clockwise
  * or anticlockwise sense.
  *
  * @param[in] N              number of source cells
  * @param[in] source_cell    list of source cells
  * @param[in] target_cell    target cell
  * @param[in] overlap_buffer buffer for the overlaps between the target and
  *                           the source cells
  *
  * \remark source cells can be either convex or concave
  * \remark target cell has to be convex
  * \remark cells in overlap_buffer can be concave (even if source cell was convex)
  * \remark overlap_buffer must contain valid grid_cells (have to be initialised
  *         using \ref yac_init_grid_cell; initialisation have to be done only once,
  *         in consecutive calls, the cells can be reused with have to be
  *         reinitialised)
  *
 **/
void yac_cell_clipping (size_t N,
                        struct yac_grid_cell * source_cell,
                        struct yac_grid_cell target_cell,
                        struct yac_grid_cell * overlap_buffer);

/**
  * \brief cell clipping to get the cells describing the intersections
  *
  * The routine takes (a list of) cells and two latitude bounds.
  *
  * @param[in] N              number of cells
  * @param[in] cells          list of cells
  * @param[in] lat_bounds     latitude bounds in radiant
  * @param[in] overlap_buffer buffer for the overlaps between the cells and
  *                           latitude band
  *
  * \remark cells in overlap_buffer can be concave
  * \remark overlap_buffer must contain valid grid_cells (have to be initialised
  *         using \ref yac_init_grid_cell; initialisation have to be done only once,
  *         in consecutive calls, the cells can be reused with have to be
  *         reinitialised)
  * \remark this routine is currently not being used within YAC but potentially
  *         used within the CDOs
  *
 **/
void yac_cell_lat_clipping (size_t N,
                            struct yac_grid_cell * cells,
                            double lat_bounds[2],
                            struct yac_grid_cell * overlap_buffer);

/**
  * \brief calculates partial areas for all overlapping parts of the source
  *        cells with arbitrary target cells, this is required for conservative
  *        remapping.
  *
  * Some of the underlying concepts can be found in
  *
  * See e.g. Joseph O'Rourke, Computational Geometry in C, 2nd Ed., 1998
  *          Sec. 7.6 Intersections of Convex Polygons, page 253.
  *
  * The routine takes (a list of) source cells and a target cell. It determines the
  * clipping points of the intersection between a source and the target cells using
  * cell_clipping internally. In a second step areas are calculated for each
  * intersection described in the overlap cells. If a target cell is fully
  * covered by N source cells the N partial areas should add up to the area of
  * the target cell.
  *
  * @param[in]  N               number of source cells
  * @param[in]  source_cell     list of source cells
  * @param[in]  target_cell     target cell
  * @param[out] partial_areas   list of N partial weights, one weight for each
  *                             source-target intersection
  *
 **/
void yac_compute_overlap_areas (size_t N,
                                struct yac_grid_cell * source_cell,
                                struct yac_grid_cell target_cell,
                                double * partial_areas);

/**
  * \brief calculates partial areas for all overlapping parts of the source
  *        cells with arbitrary target cells, this is required for conservative
  *        remapping. In addition, the barycenter of each overlap is calculated.
  *
  * Some of the underlying concepts can be found in
  *
  * See e.g. Joseph O'Rourke, Computational Geometry in C, 2nd Ed., 1998
  *          Sec. 7.6 Intersections of Convex Polygons, page 253.
  *
  * The routine takes (a list of) source cells and a target cell. It determines the
  * clipping points of the intersection between a source and the target cells using
  * cell_clipping internally. In a second step areas are calculated for each
  * intersection described in the overlap cells. If a target cell is fully
  * covered by N source cells the N partial areas should add up to the area of
  * the target cell.
  *
  * @param[in]  N                   number of source cells
  * @param[in]  source_cell         list of source cells
  * @param[in]  target_cell         target cell
  * @param[out] overlap_areas       list of N partial weights, one weight for
  *                                 each source-target intersection
  * @param[out] overlap_barycenters coordinates of the barycenters of the
  *                                 overlap cell
  * @remark for efficiency the overlap computation keeps an internal buffer,
  *         which can be freed by a call to \ref yac_compute_overlap_buf_free
  *
 **/
void yac_compute_overlap_info (size_t N,
                               struct yac_grid_cell * source_cell,
                               struct yac_grid_cell target_cell,
                               double * overlap_areas,
                               double (*overlap_barycenters)[3]);

/**
  * Frees buffer allocated by \ref yac_compute_overlap_info
 **/
void yac_compute_overlap_buf_free();

/**
  * \brief correct interpolation weights
  *
  * Returns weights with a sum close to 1.0
  *
  * @param[in]  N                 number of source cells
  * @param[out] weight            list of N partial weights
  *
 **/
void yac_correct_weights (size_t N, double * weight);

/**
 * Generate a YAC circle
 *
 * @param[in]  a             point a
 * @param[in]  b             point b
 * @param[in]  type          typ of edge connecting points a and b
 * @param[in]  edge_ordering ordering of the points a and b
 * @param[out] circle        YAC circle
 */
void yac_circle_generate(
  double const * a, double const * b, enum yac_edge_type type,
  int edge_ordering, struct yac_circle * circle);

/**
 * Compare routine for YAC circles (first by type and second parameters
 *                                  of the circle, if types are identical)
 *
 * @param[in] a YAC circle a
 * @param[in] b YAC circle b
 * @returns -1, 0, or 1 depending on the circles (lat circles always come last)
 */
int yac_circle_compare(void const * a, void const * b);

/**
 * Determines whether the provided YAC circle contains the north pole
 * @param[in] circle YAC circle
 * @return 1 if the circle contains the north pole, 0 otherwise
 */
int yac_circle_contains_north_pole(struct yac_circle * circle);

/**
 * Determines whether a given point is on the "inside"-side of a plane
 * defined by the given YAC circle
 *
 * @param[in] point  point to be checked
 * @param[in] circle YAC circle
 * @returns  0 if the point is not inside\n
 *           1 if the point is inside\n
 *           2 if the point is on the plane
 */
int yac_circle_point_is_inside(
  double const point[3], struct yac_circle * circle);

/** Compares the distances of two points to a given YAC circle
 *
 * @param[in] a      point a
 * @param[in] b      point b
 * @param[in] circle YAC circle
 * @returns -1 if point a is closer to the circle than point b\n
 *           0 if point a and b have the same distance to the circle\n
 *           1 if point b is closer to the circle than point a
 */
int yac_circle_compare_distances(
  double const a[3], double const b[3], struct yac_circle * circle);

#endif // CLIPPING_H
