summaryrefslogtreecommitdiffstats
path: root/src/livarot/float-line.h
blob: ebbd9aa1ba987d805fd57b76cf3f2e3df8e1f64f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 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;

/// 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 :