#include "IsometricBackgroundPainter.h" #include #include "Util.h" IsometricBackgroundPainter::IsometricBackgroundPainter(bool drawLines): drawLines(drawLines) {} IsometricBackgroundPainter::~IsometricBackgroundPainter() = default; void IsometricBackgroundPainter::resetConfig() { this->defaultForegroundColor1 = 0xBDBDBDU; this->defaultAlternativeForegroundColor1 = 0x434343U; this->lineWidth = drawLines ? 1.0 : 1.5; this->drawRaster1 = 14.17; } namespace { template void paintBackgroundDotted(int cols, int rows, double xstep, double ystep, DrawFunc drawDot) { for (int col = 0; col <= cols; ++col) { const auto x = col * xstep; const auto evenCol = col % 2 == 0; const auto yoffset = evenCol ? ystep : 0.0; const auto rowsInCol = evenCol ? rows - 2 : rows; for (int row = 0; row <= rowsInCol; row += 2) { const auto y = yoffset + row * ystep; drawDot(x, y); } } } template void paintBackgroundGraph(int cols, int rows, double xstep, double ystep, DrawFunc drawLine) { const auto contentWidth = cols * xstep; const auto contentHeight = rows * ystep; // Draw Orthogonal Grid drawLine(0.0, 0.0, contentWidth, 0.0); // top drawLine(0.0, contentHeight, contentWidth, contentHeight); // bottom for (int col = 0; col <= cols; ++col) { const auto x = col * xstep; drawLine(x, 0.0, x, contentHeight); } // Determine the number of diagonals to draw auto hdiags = static_cast(std::floor(cols / 2)); auto vdiags = static_cast(std::floor(rows / 2)); auto diags = hdiags + vdiags; auto hcorr = cols - 2 * hdiags; auto vcorr = rows - 2 * vdiags; // Draw diagonals starting in the top left corner (left-down) for (int d = 0; d < diags + hcorr * vcorr; ++d) { // Point 1 travels horizontally from top left to top right, // then from top right to bottom right. double x1 = contentWidth, y1 = 0.0; if (d < hdiags) { x1 = xstep + d * 2 * xstep; } else { y1 = ystep + (d - hdiags) * 2 * ystep - hcorr * ystep; } // Point 2 travels verticlally from top left to bottom left, // then from bottom left to bottom right. double x2 = 0.0, y2 = contentHeight; if (d < vdiags) { y2 = ystep + d * 2 * ystep; } else { x2 = xstep + (d - vdiags) * 2 * xstep - vcorr * xstep; } drawLine(x1, y1, x2, y2); } // Draw diagonals starting in the top right corner (right-down) for (int d = 0; d < diags; ++d) { // Point 1 travels horizontally from top right to top left, // then from top left to bottom left. double x1 = 0.0, y1 = 0.0; if (d < hdiags) { x1 = contentWidth - (xstep + d * 2 * xstep) - hcorr * xstep; } else { y1 = ystep + (d - hdiags) * 2 * ystep; } // Point 2 travels vertically from top right to bottom right, // then from top bottom right to bottom left. double x2 = contentWidth, y2 = contentHeight; if (d < vdiags) { y2 = ystep + d * 2 * ystep + hcorr * ystep; } else { x2 = contentWidth - (xstep + (d - vdiags) * 2 * xstep) + (vcorr - hcorr) * xstep; } drawLine(x1, y1, x2, y2); } } } // namespace void IsometricBackgroundPainter::paint() { paintBackgroundColor(); Util::cairo_set_source_rgbi(cr, this->foregroundColor1); cairo_set_line_width(cr, lineWidth * lineWidthFactor); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); const auto xstep = std::sqrt(3.0) / 2.0 * drawRaster1; const auto ystep = drawRaster1 / 2.0; // Deduce the maximum grid size const auto margin = drawRaster1; const int cols = static_cast(std::floor((width - 2 * margin) / xstep)); const int rows = static_cast(std::floor((height - 2 * margin) / ystep)); // Center the grid on the page const auto contentWidth = cols * xstep; const auto contentHeight = rows * ystep; const auto contentXOffset = (width - contentWidth) / 2; const auto contentYOffset = (height - contentHeight) / 2; if (drawLines) { auto drawLine = [&](double x1, double y1, double x2, double y2) { cairo_move_to(cr, contentXOffset + x1, contentYOffset + y1); cairo_line_to(cr, contentXOffset + x2, contentYOffset + y2); }; paintBackgroundGraph(cols, rows, xstep, ystep, drawLine); } else { auto drawDot = [&](double x, double y) { cairo_move_to(cr, contentXOffset + x, contentYOffset + y); cairo_line_to(cr, contentXOffset + x, contentYOffset + y); }; paintBackgroundDotted(cols, rows, xstep, ystep, drawDot); } cairo_stroke(cr); }