// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * TODO: insert short description here
 *//*
 * Authors: see git history
 *
 * Copyright (C) 2010 Authors
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */
#ifndef INKSCAPE_LIVAROT_FLOAT_LINE_H
#define INKSCAPE_LIVAROT_FLOAT_LINE_H

/** \file
 * Coverage with floating-point boundaries.
 */

#include <vector>
#include "livarot/LivarotDefs.h"

class IntLigne;
class BitLigne;

/// A coverage portion ("run") with floating point boundaries.
struct float_ligne_run {
    float st;
    float en;
    float vst;
    float ven;
    float pente;   ///< (ven-vst)/(en-st)
};

/**
 * A floating-point boundary.
 * 
 * Each float_ligne_bord is a boundary of some coverage.
 * The Flatten() function will extract non-overlapping runs and produce an 
 * array of float_ligne_run. The float_ligne_bord are stored in an array, but 
 * linked like a doubly-linked list.
 * 
 * The idea behind that is that a given edge produces one float_ligne_bord at 
 * the beginning of Scan() and possibly another in AvanceEdge() and 
 * DestroyEdge(); but that second float_ligne_bord will not be far away in 
 * the list from the first, so it's faster to salvage the index of the first 
 * float_ligne_bord and try to insert the second from that salvaged position.
 */
struct float_ligne_bord {
    float pos;    ///< position of the boundary
    bool start;   ///< is the beginning of the coverage portion?
    float val;    ///< amount of coverage (ie vst if start==true, and ven if start==false)
    float pente;  ///< (ven-vst)/(en-st)
    int other;    ///< index, in the array of float_ligne_bord, of the other boundary associated to this one
    int s_prev;   ///< index of the previous bord in the doubly-linked list
    int s_next;   ///< index of the next bord in the doubly-linked list
    int pend_ind; ///< bords[i].pend_ind is the index of the float_ligne_bord that is the start of the
                  ///< coverage portion being scanned (in the Flatten() )  
    int pend_inv; ///< inverse of pend_ind, for faster handling of insertion/removal in the "pending" array
};

/**
 * Coverage with floating-point boundaries.
 *
 * The goal is to salvage exact coverage info in the sweepline performed by 
 * Scan() or QuickScan(), then clean up a bit, convert floating point bounds
 * to integer bounds, because pixel have integer bounds, and then raster runs 
 * of the type:
 * \verbatim
   position on the (pixel) line:                st         en
                                                |          |
   coverage value (0=empty, 1=full)            vst   ->   ven   \endverbatim
 */
class FloatLigne {
public:
    std::vector<float_ligne_bord> bords; ///< vector of coverage boundaries
    std::vector<float_ligne_run> runs;   ///< vector of runs

    /// first boundary in the doubly-linked list
    int s_first;
    /// last boundary in the doubly-linked list
    int s_last;

    FloatLigne();
    virtual ~FloatLigne();

    void Reset();
    
    int AddBord(float spos, float sval, float epos, float eval, int guess = -1);
    int AddBord(float spos, float sval, float epos, float eval, float pente, int guess = -1);
    int AddBordR(float spos, float sval, float epos, float eval, float pente, int guess = -1);
    int AppendBord(float spos, float sval, float epos, float eval, float pente);
    
    void Flatten();

    void Affiche();

    void Max(FloatLigne *a, float tresh, bool addIt);
    
    void Min(FloatLigne *a, float tresh, bool addIt);
    
    void Split(FloatLigne *a, float tresh, FloatLigne *over);
    
    void Over(FloatLigne *a, float tresh);
	
    void Copy(IntLigne *a);
    void Copy(FloatLigne *a);

    float RemainingValAt(float at, int pending);
  
    static int CmpBord(float_ligne_bord const &d1, float_ligne_bord const &d2) {
        if ( d1.pos == d2.pos ) {
            if ( d1.start && !(d2.start) ) {
                return 1;
            }
            if ( !(d1.start) && d2.start ) {
                return -1;
            }
            return 0;
        }
        
        return (( d1.pos < d2.pos ) ? -1 : 1);
    };

    int AddRun(float st, float en, float vst, float ven, float pente);

private:
    void InsertBord(int no, float p, int guess);
    int AddRun(float st, float en, float vst, float ven);

    inline float ValAt(float at, float ps, float pe, float vs, float ve) {
        return ((at - ps) * ve + (pe - at) * vs) / (pe - ps);
    };
};

#endif


/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
