Krita Source Code Documentation
Loading...
Searching...
No Matches
HatchingBrush Class Reference

#include <hatching_brush.h>

Public Member Functions

void hatch (KisPaintDeviceSP dev, qreal x, qreal y, double width, double height, double givenAngle, const KoColor &color, qreal additionalScale)
 
 HatchingBrush (KisHatchingPaintOpSettingsSP settings)
 
 HatchingBrush (KoColor inkColor)
 
 ~HatchingBrush ()
 

Private Member Functions

void init ()
 
void iterateLines (bool forward, int lineindex, bool oneline)
 
void iterateVerticalLines (bool forward, int lineindex, bool oneline)
 
double separationAsFunctionOfParameter (double parameter, double separation, int numintervals)
 

Private Attributes

double angle {0.0}
 
double baseLineIntercept {0}
 
double cursorLineIntercept {0}
 
double dx {0}
 
double dy {0}
 
double height_ {0.0}
 
double hotIntercept {0}
 
int m_counter {0}
 
KoColor m_inkColor
 
KisPainter m_painter
 
int m_radius {0}
 
KisHatchingPaintOpSettingsSP m_settings
 
double origin_x {0.0}
 
double origin_y {0.0}
 
double scanIntercept {0}
 
double separation {0.0}
 
double slope {0}
 
int thickness {0}
 
double verticalHotX {0.0}
 
double verticalScanX {0.0}
 
double width_ {0.0}
 

Detailed Description

Definition at line 20 of file hatching_brush.h.

Constructor & Destructor Documentation

◆ HatchingBrush() [1/2]

◆ ~HatchingBrush()

HatchingBrush::~HatchingBrush ( )

Definition at line 34 of file hatching_brush.cpp.

35{
36}

◆ HatchingBrush() [2/2]

HatchingBrush::HatchingBrush ( KoColor inkColor)

Member Function Documentation

◆ hatch()

void HatchingBrush::hatch ( KisPaintDeviceSP dev,
qreal x,
qreal y,
double width,
double height,
double givenAngle,
const KoColor & color,
qreal additionalScale )

Performs a single hatching pass according to specifications

Definition at line 42 of file hatching_brush.cpp.

43{
44 m_painter.begin(dev);
48
49 angle = givenAngle;
50 double tempthickness = m_settings->thickness * m_settings->thicknesssensorvalue;
51 thickness = qMax(1, qRound(additionalScale * tempthickness));
52 separation = additionalScale *
56
57 height_ = height;
58 width_ = width;
59
61
62 /* dx and dy are the separation between lines in the x and y axis
63 dx = separation / sin(angle*M_PI/180); csc = 1/sin(angle) */
64 dy = fabs(separation / cos(angle * M_PI / 180)); // sec = 1/cos(angle)
65 // I took the absolute value to avoid confusions with negative numbers
66
68 modf(dy, &dy);
69
70 // Exception for vertical lines, for which a tangent does not exist
71 if ((angle == 90) || (angle == -90)) {
72 verticalHotX = fmod((origin_x - x), separation);
73
74 iterateVerticalLines(true, 1, false); // Forward
75 iterateVerticalLines(true, 0, true); // In Between both
76 iterateVerticalLines(false, 1, false); // Backward
77 }
78 else {
79 // Turn Angle + Point into Slope + Intercept
80 slope = tan(angle * M_PI / 180); // Angle into slope
81 baseLineIntercept = origin_y - slope * origin_x; // Slope and Point of the Base Line into Intercept
83 hotIntercept = fmod((baseLineIntercept - cursorLineIntercept), dy); // This hotIntercept belongs to a line that intersects with the hatching area
84
85 iterateLines(true, 1, false); // Forward
86 iterateLines(true, 0, true); // In Between both
87 iterateLines(false, 1, false); // Backward
88 // I tried to make this cleaner but there's too many possibilities to be
89 // worth the micromanagement to optimize
90 }
91}
double baseLineIntercept
void iterateLines(bool forward, int lineindex, bool oneline)
void iterateVerticalLines(bool forward, int lineindex, bool oneline)
double cursorLineIntercept
KisPainter m_painter
double separationAsFunctionOfParameter(double parameter, double separation, int numintervals)
@ FillStyleForegroundColor
void setMaskImageSize(qint32 width, qint32 height)
void setBackgroundColor(const KoColor &color)
void setFillStyle(FillStyle fillStyle)
Set the current style with which to fill.
void begin(KisPaintDeviceSP device)
void setPaintColor(const KoColor &color)
#define M_PI
Definition kis_global.h:111

References angle, baseLineIntercept, KisPainter::begin(), cursorLineIntercept, dy, KisHatchingPaintOpSettings::enabledcurveseparation, KisPainter::FillStyleForegroundColor, height_, hotIntercept, iterateLines(), iterateVerticalLines(), m_painter, M_PI, m_settings, origin_x, origin_y, separation, KisHatchingPaintOpSettings::separation, separationAsFunctionOfParameter(), KisHatchingPaintOpSettings::separationintervals, KisHatchingPaintOpSettings::separationsensorvalue, KisPainter::setBackgroundColor(), KisPainter::setFillStyle(), KisPainter::setMaskImageSize(), KisPainter::setPaintColor(), slope, KisHatchingPaintOpSettings::subpixelprecision, thickness, KisHatchingPaintOpSettings::thickness, KisHatchingPaintOpSettings::thicknesssensorvalue, verticalHotX, and width_.

◆ init()

void HatchingBrush::init ( )
private

Definition at line 38 of file hatching_brush.cpp.

39{
40}

◆ iterateLines()

void HatchingBrush::iterateLines ( bool forward,
int lineindex,
bool oneline )
private

Function that begins exploring the field from hotIntercept and moves in the direction of dy (forward==true) or -dy (forward==false) to draw all the lines it finds to KisPaintDeviceSP 'dev'

Definition at line 93 of file hatching_brush.cpp.

94{
95 //---Preparations before the loop---
96
97 double xdraw[2] = {0, 0};
98 double ydraw[2] = {0, 0};
99 //points A and B of the segments to trace
100 QPointF A, B;
101 int append_index = 0;
102 bool remaininginnerlines = true;
103
104 while (remaininginnerlines) {
105
106 //---------START INTERSECTION POINT VERIFICATION--------
107
108 append_index = 0;
109 remaininginnerlines = false; // We assume there's no more lines unless proven contrary
110 if (forward)
111 scanIntercept = hotIntercept + dy * lineindex; // scanIntercept will represent the Intercept of the current line
112 else
113 scanIntercept = hotIntercept - dy * lineindex; // scanIntercept will represent the Intercept of the current line
114
115 lineindex++; // We are descending vertically out of convenience, see blog entry at pentalis.org/kritablog
116
117 /*
118 Explanation: only 2 out of the 4 segments can include limit values
119 to verify intersections, otherwise we could encounter a situation where
120 our new lines intersect with all 4 segments and is still considered an
121 inner line (for example, a line that goes from corner to corner), thus
122 triggering an error. The idea is of the algorithm is that only 2 intersections
123 at most are considered at a time. Graphically this is indistinguishable, it's
124 just there to avoid making unnecessary control structures (like additional "ifs").
125 */
126
127 if ((scanIntercept >= 0) && (scanIntercept <= height_)) {
128 xdraw[append_index] = 0;
129 ydraw[append_index] = scanIntercept; //intersection at left
130 remaininginnerlines = true;
131 append_index++;
132 }
133
134 if ((slope * width_ + scanIntercept <= height_) && (slope * width_ + scanIntercept >= 0)) {
135 xdraw[append_index] = width_;
136 ydraw[append_index] = scanIntercept + slope * width_; //intersection at right
137 remaininginnerlines = true;
138 append_index++;
139 }
140
141 if ((-scanIntercept / slope > 0) && (-scanIntercept / slope < width_)) {
142 xdraw[append_index] = -scanIntercept / slope;
143 ydraw[append_index] = 0; //intersection at top
144 remaininginnerlines = true;
145 append_index++;
146 }
147
148 if (((height_ - scanIntercept) / slope > 0) && ((height_ - scanIntercept) / slope < width_)) {
149 xdraw[append_index] = (height_ - scanIntercept) / slope;
150 ydraw[append_index] = height_; //intersection at bottom
151 remaininginnerlines = true;
152 append_index++;
153 }
154 //--------END INTERSECTION POINT VERIFICATION---------
155
156 if (!remaininginnerlines)
157 break;
158
160 myround(&xdraw[0]);
161 myround(&xdraw[1]);
162 myround(&ydraw[0]);
163 myround(&ydraw[1]);
164 }
165
166 A.setX(xdraw[0]);
167 A.setY(ydraw[0]);
168
169 // If 2 lines intersect with the dab square
170 if (append_index == 2) {
171 B.setX(xdraw[1]);
172 B.setY(ydraw[1]);
173
176 else
177 m_painter.drawLine(A, B, thickness, false); //testing no subpixel;
178
179 if (oneline)
180 break;
181 }
182 else {
183 continue;
184 /*Drawing points at the vertices causes inconsistent results due to
185 floating point calculations not being quite in sync with algebra,
186 therefore if I have only 1 intersection (= corner = this case),
187 don't draw*/
188 }
189 }
190}
void drawThickLine(const QPointF &start, const QPointF &end, int startWidth, int endWidth)
void drawLine(const QPointF &start, const QPointF &end)
void myround(double *x)

References A, KisHatchingPaintOpSettings::antialias, B, KisPainter::drawLine(), KisPainter::drawThickLine(), dy, height_, hotIntercept, m_painter, m_settings, myround(), scanIntercept, slope, KisHatchingPaintOpSettings::subpixelprecision, thickness, and width_.

◆ iterateVerticalLines()

void HatchingBrush::iterateVerticalLines ( bool forward,
int lineindex,
bool oneline )
private

Function that begins exploring the field from verticalHotX and moves in the direction of separation (forward==true) or -separation (forward==false) to draw all the lines it finds to KisPaintDeviceSP 'dev'. This function should only be called when (angle == 90) or (angle == -90)

Definition at line 192 of file hatching_brush.cpp.

193{
194 //---Preparations before the loop---
195
196 double xdraw = 0;
197 double ydraw[2] = {0, height_};
198 //points A and B of the segments to trace
199 QPointF A, B;
200 bool remaininginnerlines = true;
201
202 while (remaininginnerlines) {
203
204 //---------START INTERSECTION POINT VERIFICATION--------
205 remaininginnerlines = false; // We assume there's no more lines unless proven contrary
206 if (forward)
207 verticalScanX = verticalHotX + separation * lineindex;
208 else
209 verticalScanX = verticalHotX - separation * lineindex;
210
211 lineindex++;
212
213 /*Read the explanation in HatchingBrush::iterateLines for more information*/
214
215 if ((verticalScanX >= 0) && (verticalScanX <= width_)) {
216 xdraw = verticalScanX;
217 remaininginnerlines = true;
218 }
219 //--------END INTERSECTION POINT VERIFICATION---------
220
221 if (!remaininginnerlines)
222 break;
223
225 myround(&xdraw);
226 myround(&ydraw[1]);
227 }
228
229 A.setX(xdraw);
230 A.setY(ydraw[0]);
231 B.setX(xdraw);
232 B.setY(ydraw[1]);
233
236 else
237 m_painter.drawLine(A, B, thickness, false); //testing no subpixel;
238
239 if (oneline)
240 break;
241 else
242 continue;
243 }
244}

References A, KisHatchingPaintOpSettings::antialias, B, KisPainter::drawLine(), KisPainter::drawThickLine(), height_, m_painter, m_settings, myround(), separation, KisHatchingPaintOpSettings::subpixelprecision, thickness, verticalHotX, verticalScanX, and width_.

◆ separationAsFunctionOfParameter()

double HatchingBrush::separationAsFunctionOfParameter ( double parameter,
double separation,
int numintervals )
private

Simple function that returns a new distance equal to a multiple or divisor of separation depending on the magnitude of 'parameter' and the number of intervals of its magnitude. The multiples and divisors used are all powers of 2 to prevent desynchronization of the lines during drawing.

Definition at line 246 of file hatching_brush.cpp.

247{
248 if ((numintervals < 2) || (numintervals > 7)) {
249 dbgKrita << "Fix your function" << numintervals << "<> 2-7" ;
250 return separation;
251 }
252
253 double sizeinterval = 1 / double(numintervals);
254 double lowerlimit = 0;
255 double upperlimit = 0;
256 double factor = 0;
257
258 int basefactor = numintervals / 2;
259 // Make the base separation factor tend to greater instead of lesser numbers when numintervals is even
260 if ((numintervals % 2) == 0)
261 basefactor--;
262
263 for (quint8 currentinterval = 0; currentinterval < numintervals; currentinterval++) {
264 lowerlimit = upperlimit;
265 upperlimit += sizeinterval;
266 if (currentinterval == (numintervals - 1))
267 upperlimit = 1;
268 if ((parameter >= lowerlimit) && (parameter <= upperlimit)) {
269 factor = pow(2.0, (basefactor - currentinterval));
270 //dbgKrita << factor;
271 return (separation * factor);
272 }
273 }
274
275 dbgKrita << "Fix your function" << parameter << ">" << upperlimit ;
276 return separation;
277}
#define dbgKrita
Definition kis_debug.h:45

References dbgKrita, and separation.

Member Data Documentation

◆ angle

double HatchingBrush::angle {0.0}
private

Angle in degrees of all the lines in a single hatching pass

Definition at line 46 of file hatching_brush.h.

46{0.0};

◆ baseLineIntercept

double HatchingBrush::baseLineIntercept {0}
private

Intercept of the base line

Definition at line 64 of file hatching_brush.h.

64{0};

◆ cursorLineIntercept

double HatchingBrush::cursorLineIntercept {0}
private

Intercept of the line that extends from the mouse cursor position, calculated from the point (x, y) of the cursor and 'slope'

Definition at line 96 of file hatching_brush.h.

96{0};

◆ dx

double HatchingBrush::dx {0}
private

Unused variable, distance separating non-vertical lines in the X axis

Definition at line 88 of file hatching_brush.h.

88{0};

◆ dy

double HatchingBrush::dy {0}
private

Distance separating non-vertical lines in the Y axis

Definition at line 91 of file hatching_brush.h.

91{0};

◆ height_

double HatchingBrush::height_ {0.0}
private

Height of the imaginary square to be hatched, the "hatching area"

Definition at line 52 of file hatching_brush.h.

52{0.0};

◆ hotIntercept

double HatchingBrush::hotIntercept {0}
private

Intercept of the first line found to pass or be neighbour of a line that passes through the hatching area, this line is used as a base to start iterating with HatchingBrush::iterateLines()

Definition at line 70 of file hatching_brush.h.

70{0};

◆ m_counter

int HatchingBrush::m_counter {0}
private

Definition at line 37 of file hatching_brush.h.

37{0};

◆ m_inkColor

KoColor HatchingBrush::m_inkColor
private

Definition at line 36 of file hatching_brush.h.

◆ m_painter

KisPainter HatchingBrush::m_painter
private

Definition at line 40 of file hatching_brush.h.

◆ m_radius

int HatchingBrush::m_radius {0}
private

Definition at line 38 of file hatching_brush.h.

38{0};

◆ m_settings

KisHatchingPaintOpSettingsSP HatchingBrush::m_settings
private

Definition at line 39 of file hatching_brush.h.

◆ origin_x

double HatchingBrush::origin_x {0.0}
private

X coordinate of the point that determines the base line

Definition at line 58 of file hatching_brush.h.

58{0.0};

◆ origin_y

double HatchingBrush::origin_y {0.0}
private

Y coordinate of the point that determines the base line

Definition at line 61 of file hatching_brush.h.

61{0.0};

◆ scanIntercept

double HatchingBrush::scanIntercept {0}
private

Intercept of each line as it is scanned, this value changes constantly

Definition at line 73 of file hatching_brush.h.

73{0};

◆ separation

double HatchingBrush::separation {0.0}
private

Distance separating one line from the other, in pixels

Definition at line 49 of file hatching_brush.h.

49{0.0};

◆ slope

double HatchingBrush::slope {0}
private

Angle of the lines expressed algebraically, as in slope*x + intercept = y

Definition at line 85 of file hatching_brush.h.

85{0};

◆ thickness

int HatchingBrush::thickness {0}
private

Thickness in pixels of each hatch line

Definition at line 43 of file hatching_brush.h.

43{0};

◆ verticalHotX

double HatchingBrush::verticalHotX {0.0}
private

X position of the first vertical line found to pass or be neighbour of a line that passes through the hatching area, this line is used as a base to start iterating with HatchingBrush::iterateVerticalLines()

Definition at line 79 of file hatching_brush.h.

79{0.0};

◆ verticalScanX

double HatchingBrush::verticalScanX {0.0}
private

X position of the vertical lines as they are scanned, this value changes constantly

Definition at line 82 of file hatching_brush.h.

82{0.0};

◆ width_

double HatchingBrush::width_ {0.0}
private

Width of the imaginary square to be hatched, the "hatching area"

Definition at line 55 of file hatching_brush.h.

55{0.0};

The documentation for this class was generated from the following files: