void HorizontalSymmetry::generateStrokes(const Stroke& mainStroke, Strokes& strokes, ToolLoop* loop) { int adjust = (loop->getBrush()->bounds().w % 2); strokes.push_back(mainStroke); Stroke stroke2; for (const auto& pt : mainStroke) stroke2.addPoint(gfx::Point(m_x - (pt.x - m_x + adjust), pt.y)); strokes.push_back(stroke2); }
void VerticalSymmetry::generateStrokes(const Stroke& mainStroke, Strokes& strokes, ToolLoop* loop) { int adjust = (loop->getBrush()->bounds().h % 2); strokes.push_back(mainStroke); Stroke stroke2; for (const auto& pt : mainStroke) stroke2.addPoint(gfx::Point(pt.x, m_y - (pt.y - m_y + adjust))); strokes.push_back(stroke2); }
void ToolLoopManager::doLoopStep(bool last_step) { // Original set of points to interwine (original user stroke, // relative to sprite origin). Stroke main_stroke; if (!last_step) m_toolLoop->getController()->getStrokeToInterwine(m_stroke, main_stroke); else main_stroke = m_stroke; // Calculate the area to be updated in all document observers. Symmetry* symmetry = m_toolLoop->getSymmetry(); Strokes strokes; if (symmetry) symmetry->generateStrokes(main_stroke, strokes, m_toolLoop); else strokes.push_back(main_stroke); calculateDirtyArea(strokes); // Validate source image area. if (m_toolLoop->getInk()->needsSpecialSourceArea()) { gfx::Region srcArea; m_toolLoop->getInk()->createSpecialSourceArea(m_dirtyArea, srcArea); m_toolLoop->validateSrcImage(srcArea); } else { m_toolLoop->validateSrcImage(m_dirtyArea); } m_toolLoop->getInk()->prepareForStrokes(m_toolLoop, strokes); // Invalidate destionation image areas. if (m_toolLoop->getTracePolicy() == TracePolicy::Last) { // Copy source to destination (reset the previous trace). Useful // for tools like Line and Ellipse (we kept the last trace only). m_toolLoop->invalidateDstImage(); } else if (m_toolLoop->getTracePolicy() == TracePolicy::AccumulateUpdateLast) { // Revalidate only this last dirty area (e.g. pixel-perfect // freehand algorithm needs this trace policy to redraw only the // last dirty area, which can vary in one pixel from the previous // tool loop cycle). m_toolLoop->invalidateDstImage(m_dirtyArea); } m_toolLoop->validateDstImage(m_dirtyArea); // Join or fill user points if (!m_toolLoop->getFilled() || (!last_step && !m_toolLoop->getPreviewFilled())) m_toolLoop->getIntertwine()->joinStroke(m_toolLoop, main_stroke); else m_toolLoop->getIntertwine()->fillStroke(m_toolLoop, main_stroke); if (m_toolLoop->getTracePolicy() == TracePolicy::Overlap) { // Copy destination to source (yes, destination to source). In // this way each new trace overlaps the previous one. m_toolLoop->copyValidDstToSrcImage(m_dirtyArea); } if (!m_dirtyArea.isEmpty()) m_toolLoop->updateDirtyArea(); }