/* PIKA - Photo and Image Kooker Application
 * a rebranding of The GNU Image Manipulation Program (created with heckimp)
 * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
 *
 * Original copyright, applying to most contents (license remains unchanged): 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * pikavectors.h
 * Copyright (C) 2002 Simon Budig  <simon@gimp.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef __PIKA_VECTORS_H__
#define __PIKA_VECTORS_H__

#include "core/pikaitem.h"

#define PIKA_TYPE_VECTORS            (pika_vectors_get_type ())
#define PIKA_VECTORS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_VECTORS, PikaVectors))
#define PIKA_VECTORS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_VECTORS, PikaVectorsClass))
#define PIKA_IS_VECTORS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_VECTORS))
#define PIKA_IS_VECTORS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_VECTORS))
#define PIKA_VECTORS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_VECTORS, PikaVectorsClass))


typedef struct _PikaVectorsClass  PikaVectorsClass;

struct _PikaVectors
{
  PikaItem        parent_instance;

  GQueue         *strokes;        /* Queue of PikaStrokes         */
  GHashTable     *stroke_to_list; /* Map from PikaStroke to strokes listnode */
  gint            last_stroke_id;

  gint            freeze_count;
  gdouble         precision;

  PikaBezierDesc *bezier_desc;    /* Cached bezier representation */

  gboolean        bounds_valid;   /* Cached bounding box          */
  gboolean        bounds_empty;
  gdouble         bounds_x1;
  gdouble         bounds_y1;
  gdouble         bounds_x2;
  gdouble         bounds_y2;
};

struct _PikaVectorsClass
{
  PikaItemClass  parent_class;

  /*  signals  */
  void          (* freeze)            (PikaVectors       *vectors);
  void          (* thaw)              (PikaVectors       *vectors);

  /*  virtual functions  */
  void          (* stroke_add)        (PikaVectors       *vectors,
                                       PikaStroke        *stroke);
  void          (* stroke_remove)     (PikaVectors       *vectors,
                                       PikaStroke        *stroke);
  PikaStroke  * (* stroke_get)        (PikaVectors       *vectors,
                                       const PikaCoords  *coord);
  PikaStroke  * (* stroke_get_next)   (PikaVectors       *vectors,
                                       PikaStroke        *prev);
  gdouble       (* stroke_get_length) (PikaVectors       *vectors,
                                       PikaStroke        *stroke);
  PikaAnchor  * (* anchor_get)        (PikaVectors       *vectors,
                                       const PikaCoords  *coord,
                                       PikaStroke       **ret_stroke);
  void          (* anchor_delete)     (PikaVectors       *vectors,
                                       PikaAnchor        *anchor);
  gdouble       (* get_length)        (PikaVectors       *vectors,
                                       const PikaAnchor  *start);
  gdouble       (* get_distance)      (PikaVectors       *vectors,
                                       const PikaCoords  *coord);
  gint          (* interpolate)       (PikaVectors       *vectors,
                                       PikaStroke        *stroke,
                                       gdouble            precision,
                                       gint               max_points,
                                       PikaCoords        *ret_coords);
  PikaBezierDesc * (* make_bezier)    (PikaVectors       *vectors);
};


/*  vectors utility functions  */

GType           pika_vectors_get_type           (void) G_GNUC_CONST;

PikaVectors   * pika_vectors_new                (PikaImage         *image,
                                                 const gchar       *name);

PikaVectors   * pika_vectors_get_parent         (PikaVectors       *vectors);

void            pika_vectors_freeze             (PikaVectors       *vectors);
void            pika_vectors_thaw               (PikaVectors       *vectors);

void            pika_vectors_copy_strokes       (PikaVectors       *src_vectors,
                                                 PikaVectors       *dest_vectors);
void            pika_vectors_add_strokes        (PikaVectors       *src_vectors,
                                                 PikaVectors       *dest_vectors);


/* accessing / modifying the anchors */

PikaAnchor    * pika_vectors_anchor_get         (PikaVectors       *vectors,
                                                 const PikaCoords  *coord,
                                                 PikaStroke       **ret_stroke);

/* prev == NULL: "first" anchor */
PikaAnchor    * pika_vectors_anchor_get_next    (PikaVectors        *vectors,
                                                 const PikaAnchor   *prev);

/* type will be an xorable enum:
 * VECTORS_NONE, VECTORS_FIX_ANGLE, VECTORS_FIX_RATIO, VECTORS_RESTRICT_ANGLE
 *  or so.
 */
void          pika_vectors_anchor_move_relative (PikaVectors        *vectors,
                                                 PikaAnchor         *anchor,
                                                 const PikaCoords   *deltacoord,
                                                 gint                type);
void          pika_vectors_anchor_move_absolute (PikaVectors        *vectors,
                                                 PikaAnchor         *anchor,
                                                 const PikaCoords   *coord,
                                                 gint                type);

void          pika_vectors_anchor_delete        (PikaVectors        *vectors,
                                                 PikaAnchor         *anchor);

void          pika_vectors_anchor_select        (PikaVectors        *vectors,
                                                 PikaStroke         *target_stroke,
                                                 PikaAnchor         *anchor,
                                                 gboolean            selected,
                                                 gboolean            exclusive);


/* PikaStroke is a connected component of a PikaVectors object */

void            pika_vectors_stroke_add         (PikaVectors        *vectors,
                                                 PikaStroke         *stroke);
void            pika_vectors_stroke_remove      (PikaVectors        *vectors,
                                                 PikaStroke         *stroke);
gint            pika_vectors_get_n_strokes      (PikaVectors        *vectors);
PikaStroke    * pika_vectors_stroke_get         (PikaVectors        *vectors,
                                                 const PikaCoords   *coord);
PikaStroke    * pika_vectors_stroke_get_by_id   (PikaVectors        *vectors,
                                                 gint                id);

/* prev == NULL: "first" stroke */
PikaStroke    * pika_vectors_stroke_get_next    (PikaVectors        *vectors,
                                                 PikaStroke         *prev);
gdouble         pika_vectors_stroke_get_length  (PikaVectors        *vectors,
                                                 PikaStroke         *stroke);

/* accessing the shape of the curve */

gdouble         pika_vectors_get_length         (PikaVectors        *vectors,
                                                 const PikaAnchor   *start);
gdouble         pika_vectors_get_distance       (PikaVectors        *vectors,
                                                 const PikaCoords   *coord);

/* returns the number of valid coordinates */

gint            pika_vectors_interpolate        (PikaVectors        *vectors,
                                                 PikaStroke         *stroke,
                                                 gdouble             precision,
                                                 gint                max_points,
                                                 PikaCoords         *ret_coords);

/* usually overloaded */

/* returns a bezier representation */
const PikaBezierDesc * pika_vectors_get_bezier  (PikaVectors        *vectors);


#endif /* __PIKA_VECTORS_H__ */
