Created
February 22, 2018 17:24
-
-
Save Glavak/69400a15afff6dc646a7ca7cb99a9926 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "hexpoint.h" | |
#include "myimage.h" | |
#include <QDebug> | |
#include <QStack> | |
MyImage::MyImage(int width, int height) : QImage(width, height, QImage::Format_ARGB32) | |
{ | |
clear(Color(240, 240, 240)); | |
} | |
bool MyImage::isBlackPixel(QPoint coords) | |
{ | |
return *((QRgb *) getPixel(coords)) == qRgb(0, 0, 0); | |
} | |
void MyImage::clear(Color color) | |
{ | |
QRgb rgb = qRgb(color.r, color.g, color.b); | |
std::fill(this->bits(), this->bits() + this->bytesPerLine()*this->height(), rgb); | |
} | |
void MyImage::drawHex(QPointF center, QPoint offset, float size, int borderThickness, Color border, Color fill) | |
{ | |
float hexWidthHalf = sqrt(3) * size / 2; | |
if (center.x() < -hexWidthHalf || center.y() < -size) return; | |
if (center.x() > width() + hexWidthHalf || center.y() > height() + size) return; | |
// Left | |
QPointF start = center + QPointF(-hexWidthHalf, -size/2); | |
QPointF end = center + QPointF(-hexWidthHalf, size/2); | |
drawLine(start.toPoint(), end.toPoint(), borderThickness, border); | |
// Bottom-left: | |
start = center + QPointF(0, size); | |
drawLine(start.toPoint(), end.toPoint(), borderThickness, border); | |
// Bottom-right: | |
end = center + QPointF(hexWidthHalf, size/2); | |
drawLine(start.toPoint(), end.toPoint(), borderThickness, border); | |
// Right | |
start = center + QPointF(hexWidthHalf, -size/2); | |
drawLine(start.toPoint(), end.toPoint(), borderThickness, border); | |
// Top-right | |
end = center + QPointF(0, -size); | |
drawLine(start.toPoint(), end.toPoint(), borderThickness, border); | |
// Top-left | |
start = center + QPointF(-hexWidthHalf, -size/2); | |
drawLine(start.toPoint(), end.toPoint(), borderThickness, border); | |
QPoint fillPoint = center.toPoint(); | |
if (fillPoint.x() < 0) fillPoint.rx() = 0; | |
if (fillPoint.y() < 0) fillPoint.ry() = 0; | |
if (fillPoint.x() >= width()) fillPoint.rx() = width() - 1; | |
if (fillPoint.y() >= height()) fillPoint.ry() = height() - 1; | |
if (HexPoint::fromPixel(fillPoint-offset, size, borderThickness) == HexPoint::fromPixel(center-offset, size, borderThickness)) | |
{ | |
fillArea(fillPoint, fill); | |
} | |
} | |
void MyImage::drawLine(QPoint start, QPoint end, int thickness, Color color) | |
{ | |
bool steep = abs(end.y() - start.y()) > abs(end.x() - start.x()); | |
if (steep) | |
{ | |
// Swap x and y | |
std::swap(start.rx(), start.ry()); | |
std::swap(end.rx(), end.ry()); | |
} | |
if (start.x() > end.x()) | |
{ | |
// Swap start and end | |
std::swap(start.rx(), end.rx()); | |
std::swap(start.ry(), end.ry()); | |
} | |
int dx = end.x() - start.x(); | |
int dy = abs(end.y() - start.y()); | |
int error = dx / 2; | |
int ystep = (start.y() < end.y()) ? 1 : -1; | |
int y = start.y(); | |
for (int x = start.x(); x <= end.x(); x++) | |
{ | |
QPoint point(steep ? y : x, steep ? x : y); | |
if (x >= 0 && x < (steep ? height() : width())) | |
{ | |
if (y >= 0 && y < (steep ? width() : height())) | |
drawPixelUnsafe(point, color); | |
int currentThickness = 1; | |
while (currentThickness < thickness) | |
{ | |
int & orthCoord = (steep ? point.rx() : point.ry()); | |
orthCoord += currentThickness; | |
if (orthCoord >= 0 && orthCoord < (steep ? width() : height())) | |
drawPixelUnsafe(point, color); | |
if (++currentThickness >= thickness) break; | |
orthCoord -= currentThickness; | |
if (orthCoord >= 0 && orthCoord < (steep ? width() : height())) | |
drawPixelUnsafe(point, color); | |
} | |
} | |
error -= dy; | |
if (error < 0) | |
{ | |
y += ystep; | |
error += dx; | |
} | |
} | |
} | |
void MyImage::drawPixel(QPoint coords, Color color) | |
{ | |
if (!this->isPointInside(coords)) | |
{ | |
//qDebug() << "Pixel: out of range: (" << coords.x() << ", " << coords.y() << ");"; | |
return; | |
} | |
this->drawPixelUnsafe(coords, color); | |
} | |
void MyImage::fillArea(QPoint seed, Color color) | |
{ | |
if (!this->isPointInside(seed)) | |
{ | |
//qDebug() << "Fill: out of range: (" << coords.x() << ", " << coords.y() << ");"; | |
return; | |
} | |
QRgb seedColor = this->getPixelColor(seed); | |
QRgb targetColor = qRgb(color.r, color.g, color.b); | |
if (seedColor == targetColor) | |
{ | |
// Same color as already | |
return; | |
} | |
Span span(seed.x(), seed.x(), seed.y()); | |
while (span.xStart > 0 && | |
seedColor == getPixelColor(QPoint(span.xStart - 1, seed.y()))) | |
{ | |
span.xStart--; | |
} | |
while (span.xEnd < this->width() - 1 && | |
seedColor == getPixelColor(QPoint(span.xEnd + 1, seed.y()))) | |
{ | |
span.xEnd++; | |
} | |
QStack<Span> spans; | |
spans.push(span); | |
while (!spans.isEmpty()) | |
{ | |
span = spans.pop(); | |
Span newSpanTop(-1, -1, span.y - 1); | |
Span newSpanBottom(-1, -1, span.y + 1); | |
for (int x = span.xStart; x <= span.xEnd; x++) | |
{ | |
// Check for new top span: | |
if (newSpanTop.xStart == -1 && | |
newSpanTop.y >= 0 && | |
seedColor == getPixelColor(QPoint(x, span.y-1))) | |
{ | |
newSpanTop.xStart = x; | |
} | |
if (newSpanTop.xStart != -1 && | |
newSpanTop.y >= 0 && | |
(x == this->width() - 1 || | |
seedColor != getPixelColor(QPoint(x+1, span.y-1)))) | |
{ | |
newSpanTop.xEnd = x; | |
spans.push(newSpanTop); | |
newSpanTop.xStart = newSpanTop.xEnd = -1; | |
} | |
// Check for new bottom span: | |
if (newSpanBottom.xStart == -1 && | |
newSpanBottom.y < this->height() && | |
seedColor == getPixelColor(QPoint(x, span.y+1))) | |
{ | |
newSpanBottom.xStart = x; | |
} | |
if (newSpanBottom.xStart != -1 && | |
newSpanBottom.y < this->height() && | |
(x == this->width() - 1 || | |
seedColor != getPixelColor(QPoint(x+1, span.y+1)))) | |
{ | |
newSpanBottom.xEnd = x; | |
spans.push(newSpanBottom); | |
newSpanBottom.xStart = newSpanBottom.xEnd = -1; | |
} | |
// Fill pixel: | |
quint8 * pix = this->getPixel(QPoint(x, span.y)); | |
((QRgb *) pix)[0] = targetColor; | |
} | |
} | |
} | |
bool MyImage::isPointInside(QPoint point) const | |
{ | |
if (point.x() < 0 || point.y() < 0 || | |
point.x() >= this->width() || point.y() >= this->height()) | |
{ | |
return false; | |
} | |
return true; | |
} | |
quint8 * MyImage::getPixel(QPoint coords) | |
{ | |
quint8 * pix = this->bits(); | |
pix += this->bytesPerLine() * coords.y(); | |
pix += coords.x() * 4; | |
return pix; | |
} | |
QRgb MyImage::getPixelColor(QPoint coords) | |
{ | |
return *((QRgb *) this->getPixel(coords)); | |
} | |
void MyImage::drawPixelUnsafe(QPoint coords, Color color) | |
{ | |
quint8 * pix = this->getPixel(coords); | |
((QRgb *) pix)[0] = qRgb(color.r, color.g, color.b); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment