Week 10 recap - Final algorithm

·

3 min read

Here's the relevant part of the new code that I have been working on in kis_tool_freehandhelper::paint :

if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::SIMPLE_SMOOTHING
            || m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::WEIGHTED_SMOOTHING){
         // initial case where there isn't any lastDrawnPixel yet
         if(!m_d->hasLastDrawnPixel){
            currentPixel = info.pos();
            m_d->waitingPixel = currentPixel;
            paintLine(m_d->previousPaintInformation, KisPaintInformation(m_d->waitingPixel));
            m_d->lastDrawnPixel = m_d->waitingPixel;
            m_d->hasLastDrawnPixel = true;
            m_d->pixelInLineCount = 1;

        } else {
        // once there is a last drawn pixel 
            if (abs(currentPixel.x() - m_d->lastDrawnPixel.x()) > 1.5 || abs(currentPixel.y() - m_d->lastDrawnPixel.y()) > 1.5) {
            // current pixel is too far, draw the waiting pixel
                paintLine(m_d->lastDrawnPixel, KisPaintInformation(m_d->waitingPixel));
                m_d->pixelInLineCount += 1;
                m_d->lastDrawnPixel = m_d->waitingPixel;
                m_d->waitingPixel = currentPixel;
            }
            // check axis, if the currentpixel is in the same axis as the lastdrawnpixel, we can draw waiting pixel otherwise
            if (m_d->pixelInLineCount > 2 && (currentPixel.x() == m_d->lastDrawnPixel.x() || currentPixel.y() == m_d->lastDrawnPixel.y())) 
                    m_d->olderPaintInformation = m_d->previousPaintInformation;
                    //draw 
                    paintLine(m_d->KisPaintInformation(m_d->waitingPixel),KisPaintInformation(m_d->waitingPixel))
                    m_d->lastDrawnPixel = m_d->waitingPixel;
                }
                //otherwise just change update waiting pixel without drawing it
                m_d->waitingPixel = currentPixel;
                m_d->pixelInLineCount = 0;
            }
            // Enable stroke timeout only when not airbrushing.
            if (!m_d->airbrushingTimer.isActive()) {
                m_d->strokeTimeoutTimer.start(100);
            }
        }

Before a super glaring problem was that the algorithm made drawing very non-continuous, you barely get to see what gets drawn. When currentPixel gets too far from lastDrawnPixel, we have an infinite gap that doesn't get filled. In response, I took a page from Tom Cantwell's implementation, and if the currentPixel gets too far from the lastDrawnPixel, we draw the waitingPixel, except we draw the entire line from lastDrawnPixel to waitingpixel instead because only drawing the waitingpixel caused a lot of undrawn gaps likely due to mouse speed or the refresh rate of stuff getting read. Also if you notice, I made it so that the distance between currentPixel and lastDrawnPixel > 1.5 instead of > 1.0 because with just 1.0 we were not giving enough room to actually wait for the waitingPixel to be assessed and drawn if it's not a corner pixel.

In the context of waiting, I also added a pixelInLineCount so that we compound at least 2 pixels read before actually going through with the axis check because at less than two pixels read we either haven't drawn anything or we have only drawn one pixel and there can't be a complete check for a corner until we reach a scenario where there are three coordinates to check i.e. when we get to simulate the waiting pixel *lagging* behind currentPixel in an attempt to compare them and then see if it needs to be drawn.

There seems to only be one scenario left where the corner gets drawn, which also has to do with the fix we implemented. My running theory is that it has to do with how the line gets filled because sometimes although most lines will just be pixel-perfect with this line fill, we reach the middle of the Venn diagram where the mouse speed is just fast enough that we run into the > 1.5 distance check and so the line drawn isn't going through the axis check but then its also just slow enough where it draws exactly a horizontal into a vertical line between two close pixels.