1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released      *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission.     *
5  ******************************************************************************************************/
6 
7 #ifndef SEGMENT_FACTORY_H
8 #define SEGMENT_FACTORY_H
9 
10 #include <QList>
11 #include <QPointF>
12 #include <vector>
13 
14 class ColorFilter;
15 class DocumentModelSegments;
16 class QGraphicsScene;
17 class QImage;
18 class Segment;
19 
20 typedef std::vector<Segment*> SegmentVector;
21 
22 /// Factory class for Segment objects. The input is the filtered image.
23 ///
24 /// The strategy is to fill out the segments output array as each segment finishes. This makes it easy to
25 /// keep too-short Segments out of the output array, versus adding every new Segment to the output array
26 /// as soon as it is created
27 class SegmentFactory
28 {
29 public:
30   /// Single constructor.
31   SegmentFactory(QGraphicsScene &scene,
32                  bool isGnuplot);
33 
34   /// Remove the segments created by makeSegments
35   void clearSegments(QList<Segment*> &segments);
36 
37   /// Return segment fill points for all segments, for previewing
38   QList<QPoint> fillPoints(const DocumentModelSegments &modelSegments,
39                            QList<Segment*> segments);
40 
41   /// Main entry point for creating all Segments for the filtered image.
42   void makeSegments (const QImage &imageFiltered,
43                      const DocumentModelSegments &modelSegments,
44                      QList<Segment*> &segments,
45                      bool useDlg = true);
46 
47 private:
48   SegmentFactory();
49 
50   // Return the number of runs adjacent to the pixels from yStart to yStop (inclusive)
51   int adjacentRuns(bool *columnBool,
52                    int yStart,
53                    int yStop,
54                    int height);
55 
56   // Find the single segment pointer among the adjacent pixels from yStart-1 to yStop+1
57   Segment *adjacentSegment(SegmentVector &lastSegment,
58                            int yStart,
59                            int yStop,
60                            int height);
61 
62   // Return the number of segments adjacent to the pixels from yStart to yStop (inclusive)
63   int adjacentSegments(SegmentVector &lastSegment,
64                        int yStart,
65                        int yStop,
66                        int height);
67 
68   // Process a run of pixels. If there are fewer than two adjacent pixel runs on
69   // either side, this run will be added to an existing segment, or the start of
70   // a new segment
71   void finishRun(bool *lastBool,
72                  bool *nextBool,
73                  SegmentVector &lastSegment,
74                  SegmentVector &currSegment,
75                  int x,
76                  int yStart,
77                  int yStop,
78                  int height,
79                  const DocumentModelSegments &modelSegments,
80                  int* madeLines);
81 
82   // Initialize one column of boolean flags using the pixels of the specified column
83   void loadBool (const ColorFilter &filter,
84                  bool *columnBool,
85                  const QImage &image,
86                  int x);
87 
88   // Initialize one column of segment pointers
89   void loadSegment (SegmentVector &columnSegment,
90                     int height);
91 
92   // Identify the runs in a column, and connect them to segments
93   void matchRunsToSegments (int x,
94                             int height,
95                             bool *lastBool,
96                             SegmentVector &lastSegment,
97                             bool *currBool,
98                             SegmentVector &currSegment,
99                             bool *nextBool,
100                             const DocumentModelSegments &modelSegments,
101                             int *madeLines,
102                             int *foldedLines,
103                             int *shortLine,
104                             QList<Segment*> &segments);
105 
106   /// Remove any Segment with no lines. This prevents crashes in Segment::firstPoint which requires at least one line in each Segment
107   void removeEmptySegments (QList<Segment*> &segments) const;
108 
109   // Remove unneeded lines belonging to segments that just finished in the previous column.
110   // The results of this function are displayed in the debug spew of makeSegments
111   void removeUnneededLines(SegmentVector &lastSegment,
112                            SegmentVector &currSegment,
113                            int height,
114                            int *foldedLines,
115                            int *shortLines,
116                            const DocumentModelSegments &modelSegments,
117                            QList<Segment*> &segments);
118 
119   // Scroll the boolean flags of the right column into the left column
120   void scrollBool(bool *left,
121                   bool *right,
122                   int height);
123 
124   // Scroll the segment pointers of the right column into the left column
125   void scrollSegment(SegmentVector &left,
126                      SegmentVector &right,
127                      int height);
128 
129   QGraphicsScene &m_scene;
130 
131   bool m_isGnuplot;
132 };
133 
134 #endif // SEGMENT_FACTORY_H
135