| |
| |
| |
| |
| |
| |
| |
| class HalfCord { |
| std::unique_ptr<int[]> m_array; |
| int m_radius; |
| |
| public: |
| HalfCord(int radius) : m_radius(radius), m_array(new int[radius + 1]) { |
| assert(radius >= 0); |
| memset(m_array.get(), 0, (m_radius + 1) * sizeof(int)); |
| |
| float dCircle = 1.25f - m_radius; |
| int y = m_radius; |
| int x = 0; |
| do { |
| m_array[y] = std::max(x, m_array[y]); |
| m_array[x] = y; |
| if (dCircle <= 0) { |
| dCircle = dCircle + 2 * x + 3; |
| } else { |
| y--; |
| dCircle = dCircle + 2 * (x - y) + 5; |
| } |
| x++; |
| |
| } while (y >= x); |
| } |
| |
| inline int getCord(int x) { |
| assert(0 <= x && x <= m_radius); |
| return m_array[x]; |
| }; |
| |
| private: |
| |
| HalfCord(const HalfCord &); |
| HalfCord &operator=(const HalfCord &); |
| }; |
| |
| |
| |
| void TRop::brush(TRaster32P ras, const TPoint &aa, const TPoint &bb, int radius, |
| const TPixel32 &col) { |
| TPoint a = aa; |
| TPoint b = bb; |
| if (a.y > b.y) tswap(a, b); |
| |
| int lx = ras->getLx(); |
| int ly = ras->getLy(); |
| ras->lock(); |
| |
| |
| if (radius == 0) { |
| |
| |
| |
| |
| int k = 1; |
| int dy = b.y - a.y; |
| int dx = b.x - a.x; |
| if (dx < 0) { |
| dx = -dx; |
| k = -1; |
| } |
| |
| assert(dx >= 0); |
| assert(dy >= 0); |
| |
| double m; |
| if (dx > 0) { |
| m = dy / (double)dx; |
| } |
| |
| const int alpha = dy, beta = -dx; |
| const int incE = alpha; |
| const int incNE = alpha + beta; |
| const int incN = beta; |
| |
| |
| |
| |
| int yMin = std::max(a.y, 0) - a.y; |
| int yMax = std::min(b.y, ly - 1) - a.y; |
| if (dx > 0 && m <= 1) { |
| |
| TPoint segm; |
| if (dy == 0) |
| { |
| segm.x = 0; |
| segm.y = yMin; |
| } else |
| { |
| segm.x = tceil((yMin - 0.5) / m); |
| segm.y = yMin; |
| } |
| |
| int dSegm = tfloor(alpha * (segm.x + 1) + beta * (segm.y + 0.5)); |
| while (segm.y <= yMax) { |
| int count = |
| 0; |
| while (dSegm < 0 && segm.x <= dx) |
| { |
| dSegm = dSegm + incE; |
| segm.x++; |
| count++; |
| } |
| |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max( |
| {a.x + segm.x - count, a.x, 0}); |
| xMax = std::min( |
| {a.x + segm.x, b.x, lx - 1}); |
| |
| } else { |
| xMin = std::max({a.x - segm.x, a.x - dx, |
| 0}); |
| xMax = std::min({a.x - segm.x + count, a.x, |
| lx - 1}); |
| } |
| |
| TPixel32 *p = ras->pixels(segm.y + a.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| |
| while (p <= q) *p++ = col; |
| |
| dSegm = dSegm + incNE; |
| segm.x++; |
| segm.y++; |
| } |
| } else |
| { |
| |
| TPoint segm; |
| if (dx == 0) |
| { |
| segm.x = 0; |
| segm.y = yMin; |
| } else |
| { |
| segm.x = tround(yMin / m); |
| segm.y = yMin; |
| } |
| |
| int dSegm = tfloor(alpha * (segm.x + 0.5) + beta * (segm.y + 1)); |
| while (segm.y <= yMax) { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(a.x + segm.x, 0); |
| xMax = std::min(a.x + segm.x, lx - 1); |
| |
| } else { |
| xMin = |
| std::max(a.x - segm.x, 0); |
| xMax = |
| std::min(a.x - segm.x, lx - 1); |
| } |
| |
| TPixel32 *p = ras->pixels(segm.y + a.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| |
| while (p <= q) *p++ = col; |
| |
| if (dSegm <= 0) |
| { |
| dSegm = dSegm + incNE; |
| segm.x++; |
| } else |
| { |
| dSegm = dSegm + incN; |
| } |
| segm.y++; |
| } |
| } |
| ras->unlock(); |
| return; |
| } |
| |
| HalfCord halfCord(radius); |
| |
| int x, y; |
| |
| |
| if (a == b) { |
| int yMin = std::max(a.y - radius, 0); |
| int yMax = std::min(a.y + radius, ly - 1); |
| for (y = yMin; y <= yMax; y++) { |
| int deltay = abs(y - a.y); |
| int xMin = std::max(a.x - halfCord.getCord(deltay), 0); |
| int xMax = |
| std::min(a.x + halfCord.getCord(deltay), lx - 1); |
| TPixel32 *p = ras->pixels(y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| } |
| ras->unlock(); |
| return; |
| } |
| |
| |
| if (a.y == b.y) { |
| int yMin = std::max((a.y - radius), 0); |
| int yMax = std::min((a.y + radius), ly - 1); |
| int xLeft = std::min(a.x, b.x); |
| int xRight = std::max(a.x, b.x); |
| for (y = yMin; y <= yMax; y++) { |
| int deltay = abs(y - a.y); |
| int xMin = std::max(xLeft - halfCord.getCord(deltay), 0); |
| int xMax = |
| std::min(xRight + halfCord.getCord(deltay), lx - 1); |
| TPixel32 *p = ras->pixels(y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| } |
| ras->unlock(); |
| return; |
| } |
| |
| |
| if (a.x == b.x) { |
| int xMin = std::max(a.x - radius, 0); |
| int xMax = std::min(a.x + radius, lx - 1); |
| for (x = xMin; x <= xMax; x++) { |
| int deltax = abs(x - a.x); |
| int yMin = std::max(a.y - halfCord.getCord(deltax), 0); |
| int yMax = |
| std::min(b.y + halfCord.getCord(deltax), ly - 1); |
| if (yMin <= yMax) { |
| TPixel32 *p = ras->pixels(yMin) + x; |
| TPixel32 *q = ras->pixels(yMax) + x; |
| int wrap = ras->getWrap(); |
| while (p <= q) { |
| *p = col; |
| p += wrap; |
| } |
| } |
| } |
| ras->unlock(); |
| return; |
| } |
| |
| |
| |
| int k = 1; |
| int dx = b.x - a.x; |
| if (dx < 0) { |
| dx = -dx; |
| k = -1; |
| } |
| int dy = b.y - a.y; |
| |
| assert(dx > 0); |
| assert(dy > 0); |
| |
| double length = sqrt((double)(dx * dx + dy * dy)); |
| const double m = dy / (double)dx; |
| |
| |
| TPointD up(-radius * dy / length, radius * dx / length); |
| |
| |
| int halfAmplCap = tfloor(-up.x); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int cutExt, cutIn; |
| |
| |
| TPointD rightUp; |
| TPointD rightDown; |
| TPointD leftUp; |
| TPointD leftDown; |
| double mParall; |
| |
| |
| if (radius > 1) { |
| for (cutExt = radius; |
| cutExt >= 0 && halfCord.getCord(cutExt) <= halfAmplCap; cutExt--) |
| ; |
| cutIn = cutExt; |
| rightUp.x = dx + halfCord.getCord(cutIn); |
| rightUp.y = dy - cutIn; |
| rightDown.x = halfCord.getCord(cutIn); |
| rightDown.y = -cutIn; |
| leftUp.x = dx - halfCord.getCord(cutIn); |
| leftUp.y = dy + cutIn; |
| leftDown.x = -halfCord.getCord(cutIn); |
| leftDown.y = cutIn; |
| mParall = dy / (double)dx; |
| } else |
| { |
| cutExt = radius; |
| |
| cutIn = 0; |
| |
| rightUp.x = dx - up.x; |
| rightUp.y = dy - up.y; |
| rightDown.x = -up.x; |
| rightDown.y = -up.y; |
| leftUp.x = dx + up.x; |
| leftUp.y = dy + up.y; |
| leftDown.x = up.x; |
| leftDown.y = up.y; |
| mParall = m; |
| } |
| |
| |
| |
| int yMin = std::max(a.y - radius, 0); |
| int yMax = std::min(a.y - cutExt - 1, ly - 1); |
| for (y = yMin; y <= yMax; y++) { |
| int r = halfCord.getCord(a.y - y); |
| int xMin = std::max(a.x - r, 0); |
| int xMax = std::min(a.x + r, lx - 1); |
| TPixel32 *p = ras->pixels(y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| } |
| |
| yMin = std::max(b.y + cutExt + 1, 0); |
| yMax = std::min(b.y + radius, ly - 1); |
| for (y = yMin; y <= yMax; y++) { |
| int r = halfCord.getCord(y - b.y); |
| int xMin = std::max(b.x - r, 0); |
| int xMax = std::min(b.x + r, lx - 1); |
| TPixel32 *p = ras->pixels(y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| } |
| |
| |
| |
| |
| |
| |
| int xSegmMax = tround(dx - up.x); |
| |
| |
| |
| int xSegmMin = tround(up.x); |
| |
| |
| |
| |
| |
| |
| |
| |
| yMin = std::max(a.y - cutExt, 0) - a.y; |
| yMax = std::min({a.y + cutIn, b.y - cutIn - 1, ly - 1}) - a.y; |
| |
| |
| const int alpha = dy, beta = -dx; |
| const double gammaRight = rightDown.y * dx - rightDown.x * dy; |
| const int incE = alpha; |
| const int incNE = alpha + beta; |
| const int incN = beta; |
| |
| if (m <= 1) { |
| |
| |
| TPoint segmRight( |
| tceil((yMin + 0.5 - rightDown.y) / mParall + rightDown.x) - 1, yMin); |
| int dSegmRight = tfloor(alpha * (segmRight.x + 1) + |
| beta * (segmRight.y + 0.5) + gammaRight); |
| while (segmRight.y <= yMax) { |
| if (dSegmRight < 0) |
| { |
| dSegmRight = dSegmRight + incE; |
| segmRight.x++; |
| } else |
| { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(a.x - halfCord.getCord(abs(segmRight.y)), |
| 0); |
| xMax = std::min(a.x + std::min(segmRight.x, xSegmMax), |
| lx - 1); |
| } else { |
| xMin = std::max(a.x - std::min(segmRight.x, xSegmMax), |
| 0); |
| xMax = std::min(a.x + halfCord.getCord(abs(segmRight.y)), |
| lx - 1); |
| } |
| TPixel32 *p = ras->pixels(segmRight.y + a.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| |
| dSegmRight = dSegmRight + incNE; |
| segmRight.x++; |
| segmRight.y++; |
| } |
| } |
| } else |
| { |
| |
| TPoint segmRight(tround((yMin - rightDown.y) / mParall + rightDown.x), |
| yMin); |
| int dSegmRight = tfloor(alpha * (segmRight.x + 0.5) + |
| beta * (segmRight.y + 1) + gammaRight); |
| while (segmRight.y <= yMax) { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(a.x - halfCord.getCord(abs(segmRight.y)), |
| 0); |
| xMax = std::min(a.x + segmRight.x, lx - 1); |
| } else { |
| xMin = std::max(a.x - segmRight.x, |
| 0); |
| xMax = std::min(a.x + halfCord.getCord(abs(segmRight.y)), |
| lx - 1); |
| } |
| TPixel32 *p = ras->pixels(segmRight.y + a.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| |
| if (dSegmRight <= 0) |
| { |
| dSegmRight = dSegmRight + incNE; |
| segmRight.x++; |
| } else |
| { |
| dSegmRight = dSegmRight + incN; |
| } |
| segmRight.y++; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| yMin = std::max({b.y - cutIn, a.y + cutIn + 1, 0}) - b.y; |
| yMax = std::min(b.y + cutExt, ly - 1) - b.y; |
| |
| |
| const double gammaLeft = leftDown.y * dx - leftDown.x * dy; |
| |
| if (m <= 1) { |
| |
| |
| TPoint segmLeft(tceil((yMin - 0.5 - leftDown.y) / mParall + leftDown.x), |
| yMin); |
| int dSegmLeft = tfloor(alpha * (segmLeft.x + 1) + |
| beta * (segmLeft.y + 0.5) + gammaLeft); |
| while (segmLeft.y <= yMax) { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(b.x + std::max(segmLeft.x, xSegmMin - dx), |
| 0); |
| xMax = std::min(b.x + halfCord.getCord(abs(segmLeft.y)), |
| lx - 1); |
| } else { |
| xMin = std::max(b.x - halfCord.getCord(abs(segmLeft.y)), |
| 0); |
| xMax = std::min(b.x - std::max(segmLeft.x, xSegmMin - dx), |
| lx - 1); |
| } |
| TPixel32 *p = ras->pixels(segmLeft.y + b.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| |
| while (p <= q) *p++ = col; |
| while (dSegmLeft < 0) { |
| dSegmLeft = dSegmLeft + incE; |
| segmLeft.x++; |
| } |
| dSegmLeft = dSegmLeft + incNE; |
| segmLeft.x++; |
| segmLeft.y++; |
| } |
| } else |
| { |
| |
| TPoint segmLeft(tround((yMin - leftDown.y) / mParall + leftDown.x), yMin); |
| int dSegmLeft = tfloor(alpha * (segmLeft.x + 0.5) + |
| beta * (segmLeft.y + 1) + gammaLeft); |
| while (segmLeft.y <= yMax) { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(b.x + segmLeft.x, 0); |
| xMax = std::min(b.x + halfCord.getCord(abs(segmLeft.y)), |
| lx - 1); |
| } else { |
| xMin = std::max(b.x - halfCord.getCord(abs(segmLeft.y)), |
| 0); |
| xMax = std::min(b.x - segmLeft.x, lx - 1); |
| } |
| TPixel32 *p = ras->pixels(segmLeft.y + b.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| |
| while (p <= q) *p++ = col; |
| |
| if (dSegmLeft <= 0) |
| { |
| dSegmLeft = dSegmLeft + incNE; |
| segmLeft.x++; |
| } else |
| { |
| dSegmLeft = dSegmLeft + incN; |
| } |
| segmLeft.y++; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| yMin = std::max(a.y + cutIn + 1, 0) - a.y; |
| yMax = std::min(b.y - cutIn - 1, ly - 1) - a.y; |
| if (m <= 1) { |
| |
| |
| TPoint segmRight( |
| tceil((yMin + 0.5 - rightDown.y) / mParall + rightDown.x) - 1, yMin); |
| TPoint segmLeft = |
| TPoint(tceil((yMin - 0.5 - leftDown.y) / mParall + leftDown.x), yMin); |
| int dSegmRight = tfloor(alpha * (segmRight.x + 1) + |
| beta * (segmRight.y + 0.5) + gammaRight); |
| int dSegmLeft = tfloor(alpha * (segmLeft.x + 1) + |
| beta * (segmLeft.y + 0.5) + gammaLeft); |
| while (segmRight.y <= yMax) { |
| if (dSegmRight < 0) |
| { |
| dSegmRight = dSegmRight + incE; |
| segmRight.x++; |
| } else |
| { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = |
| std::max(a.x + std::max(segmLeft.x, xSegmMin), 0); |
| xMax = std::min(a.x + std::min(segmRight.x, xSegmMax), |
| lx - 1); |
| } else { |
| xMin = std::max(a.x - std::min(segmRight.x, xSegmMax), |
| 0); |
| xMax = std::min(a.x - std::max(segmLeft.x, xSegmMin), |
| lx - 1); |
| } |
| |
| TPixel32 *p = ras->pixels(segmRight.y + a.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| |
| while (p <= q) *p++ = col; |
| |
| dSegmRight = dSegmRight + incNE; |
| segmRight.x++; |
| segmRight.y++; |
| |
| while (dSegmLeft < 0) |
| { |
| dSegmLeft = dSegmLeft + incE; |
| segmLeft.x++; |
| } |
| |
| dSegmLeft = dSegmLeft + incNE; |
| segmLeft.x++; |
| segmLeft.y++; |
| } |
| } |
| } else |
| { |
| |
| TPoint segmRight(tround((yMin - rightDown.y) / mParall + rightDown.x), |
| yMin); |
| TPoint segmLeft(tround((yMin - leftDown.y) / mParall + leftDown.x), yMin); |
| int dSegmRight = tfloor(alpha * (segmRight.x + 0.5) + |
| beta * (segmRight.y + 1) + gammaRight); |
| int dSegmLeft = tfloor(alpha * (segmLeft.x + 0.5) + |
| beta * (segmLeft.y + 1) + gammaLeft); |
| while (segmRight.y <= yMax) { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(a.x + segmLeft.x, 0); |
| xMax = std::min(a.x + segmRight.x, lx - 1); |
| } else { |
| xMin = std::max(a.x - segmRight.x, 0); |
| xMax = std::min(a.x - segmLeft.x, lx - 1); |
| } |
| |
| TPixel32 *p = ras->pixels(segmRight.y + a.y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| |
| while (p <= q) *p++ = col; |
| |
| if (dSegmRight <= 0) |
| { |
| dSegmRight = dSegmRight + incNE; |
| segmRight.x++; |
| } else |
| { |
| dSegmRight = dSegmRight + incN; |
| } |
| segmRight.y++; |
| |
| if (dSegmLeft <= 0) |
| { |
| dSegmLeft = dSegmLeft + incNE; |
| segmLeft.x++; |
| } else |
| { |
| dSegmLeft = dSegmLeft + incN; |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| yMin = std::max(b.y - cutIn, 0); |
| yMax = std::min(a.y + cutIn, ly - 1); |
| for (y = yMin; y <= yMax; y++) { |
| int xMin, xMax; |
| if (k > 0) { |
| xMin = std::max(a.x - halfCord.getCord(abs(y - a.y)), 0); |
| xMax = std::min(b.x + halfCord.getCord(abs(b.y - y)), |
| lx - 1); |
| } else { |
| xMin = std::max(b.x - halfCord.getCord(abs(b.y - y)), |
| 0); |
| xMax = std::min(a.x + halfCord.getCord(abs(y - a.y)), |
| lx - 1); |
| } |
| TPixel32 *p = ras->pixels(y) + xMin; |
| TPixel32 *q = p + (xMax - xMin); |
| while (p <= q) *p++ = col; |
| } |
| ras->unlock(); |
| } |