Fix for gap close lines

A fix to stop coloring gap close lines beyond the fill area.
This commit is contained in:
Tom 2023-10-28 21:01:57 -04:00
parent e8dfc81d79
commit 81934292d8
2 changed files with 202 additions and 143 deletions

View file

@ -1052,12 +1052,12 @@ void fillAreaWithUndo(const TImageP &img, const TRectD &area, TStroke *stroke,
for (int tempY = 0; tempY < tempRaster->getLy(); tempY++) {
for (int tempX = 0; tempX < tempRaster->getLx();
tempX++, tempPix++, keepPix++) {
if (tempPix->getInk() < IGNORECOLORSTYLE) {
keepPix->setInk(tempPix->getInk());
}
if (tempPix->getPaint() < IGNORECOLORSTYLE) {
keepPix->setPaint(tempPix->getPaint());
if (tempPix->getInk() >= IGNORECOLORSTYLE || tempPix->getPaint() >= IGNORECOLORSTYLE) {
continue;
}
keepPix->setInk(tempPix->getInk());
keepPix->setPaint(tempPix->getPaint());
keepPix->setTone(tempPix->getTone());
}
}

View file

@ -142,124 +142,6 @@ bool areRectPixelsTransparent(TPixel32 *pixels, TRect rect, int wrap) {
} // namespace
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void finishGapLine(const TRasterCM32P &r, const TRasterCM32P &combined,
const TPoint &pin, int clickedColorStyle, int fillColorStyle,
int closeColorStyle, int searchRay, TRect *insideRect,
bool closeGaps) {
r->lock();
TRasterCM32P myCombined;
if (!combined.getPointer() || combined->isEmpty()) {
myCombined = r;
} else {
myCombined = combined;
}
TPixelCM32 *pixels = (TPixelCM32 *)r->getRawData();
TPixelCM32 *combinedPixels = (TPixelCM32 *)myCombined->getRawData();
;
TPoint p = pin;
int filledNeighbor = 0;
int unfilledNeighbor = 0;
int inkStyle = 0;
int paintStyle = 0;
int toneValue = 0;
TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x);
TPixelCM32 *pixc = combinedPixels + (p.y * myCombined->getWrap() + p.x);
std::stack<TPoint> gapLinePixels;
std::stack<TPoint> seeds;
seeds.push(p);
while (!seeds.empty()) {
p = seeds.top();
seeds.pop();
if (!r->getBounds().contains(p)) {
continue;
}
if (insideRect && !insideRect->contains(p)) {
continue;
}
TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x);
TPixelCM32 *pixc = combinedPixels + (p.y * myCombined->getWrap() + p.x);
// handle gap close pixel
if (pix->getInk() == GAP_CLOSE_USED) continue;
if (pix->getInk() == GAP_CLOSE_TEMP) {
pix->setInk(GAP_CLOSE_USED);
// push to the gapLinePixels collection for later processing as a line
gapLinePixels.push(p);
// push neighboring pixels into the seeds queue
seeds.push(TPoint(p.x - 1, p.y - 1)); // sw
seeds.push(TPoint(p.x - 1, p.y)); // west
seeds.push(TPoint(p.x - 1, p.y + 1)); // nw
seeds.push(TPoint(p.x, p.y - 1)); // south
seeds.push(TPoint(p.x, p.y + 1)); // north
seeds.push(TPoint(p.x + 1, p.y - 1)); // se
seeds.push(TPoint(p.x + 1, p.y)); // east
seeds.push(TPoint(p.x + 1, p.y + 1)); // ne
continue;
}
// a neighboring filled pixel
if (pix->getTone() > 0 && pix->getPaint() == fillColorStyle) {
filledNeighbor++;
continue;
}
// a neighboring fillable but unfilled pixel
if ((pix->getTone() == 255 &&
((pix->getPaint() == clickedColorStyle) || (pix->getPaint() == 0) ||
(pix->getPaint() == IGNORECOLORSTYLE))) &&
(pixc->getTone() == 255 && ((pixc->getPaint() == clickedColorStyle) ||
(pixc->getPaint() == 0)))) {
unfilledNeighbor++;
continue;
}
}
// determine the final disposition of the gap line
if (filledNeighbor > 0) {
if (unfilledNeighbor > 0) {
if (closeGaps) {
inkStyle = closeColorStyle;
paintStyle = fillColorStyle;
toneValue = 0;
} else {
inkStyle = 0;
paintStyle = fillColorStyle;
toneValue = 255;
}
} else {
inkStyle = 0;
paintStyle = fillColorStyle;
toneValue = 255;
}
} else {
inkStyle = IGNORECOLORSTYLE;
paintStyle = 0;
toneValue = 0;
}
// process the stored gap close line pixels
while (!gapLinePixels.empty()) {
p = gapLinePixels.top();
gapLinePixels.pop();
TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x);
pix->setInk(inkStyle);
pix->setPaint(paintStyle);
pix->setTone(toneValue);
}
r->unlock();
}
//-----------------------------------------------------------------------------
// This function finishes candidate gap lines that were created
// during a fill process.
@ -269,42 +151,219 @@ void finishGapLines(TRasterCM32P &rin, TRect &rect, const TRasterCM32P &rbefore,
int clickedColorStyle, int fillIndex, int closeColorStyle,
bool closeGaps) {
assert(plt);
rin->lock();
TRasterCM32P r = rin->extract(rect);
assert(r->getSize() == rbefore->getSize());
assert(r->getSize() == combined->getSize());
TRasterCM32P myCombined;
if (!combined.getPointer() || combined->isEmpty()) {
myCombined = r;
} else {
myCombined = combined;
}
int i, j;
int filledNeighbor = 0;
int unfilledNeighbor = 0;
std::stack<TPoint> gapLinePixels;
TPoint p;
// process all the pixels looking for gap close pixels
for (i = 0; i < r->getLy(); i++) {
TPixelCM32 *pix = r->pixels(i);
TPixelCM32 *pixb = rbefore->pixels(i);
TPixelCM32 *pixc = myCombined->pixels(i);
for (j = 0; j < r->getLx(); j++, pix++, pixb++) {
int paint = pix->getPaint();
int tone = pix->getTone();
int ink = pix->getInk();
if (ink == GAP_CLOSE_TEMP &&
(
// north
(i < rin->getLy() - 1 &&
(pix + rin->getWrap())->getPaint() == fillIndex &&
(pix + rin->getWrap())->getPaint() !=
(pixb + rbefore->getWrap())->getPaint())
// south
|| (i > 0 && (pix - rin->getWrap())->getPaint() == fillIndex &&
(pix - rin->getWrap())->getPaint() !=
(pixb - rbefore->getWrap())->getPaint())
// east
|| (j < rin->getLx() - 1 && (pix + 1)->getPaint() == fillIndex &&
(pix + 1)->getPaint() != (pixb + 1)->getPaint())
// west
|| (j > 0 && (pix - 1)->getPaint() == fillIndex &&
(pix - 1)->getPaint() != (pixb - 1)->getPaint()))) {
finishGapLine(rin, combined, TPoint(j, i) + rect.getP00(),
clickedColorStyle, fillIndex, closeColorStyle, 0, &rect,
closeGaps);
if (ink != GAP_CLOSE_TEMP) continue;
// current pixel is a gap close pixel, does it qualify to be kept?
filledNeighbor = 0;
unfilledNeighbor = 0;
// check for new filled neighbor
// north
if (i < rin->getLy() - 1 && (pix + rin->getWrap())->getTone() == 255 &&
(pix + rin->getWrap())->getInk() < IGNORECOLORSTYLE &&
(pix + rin->getWrap())->getPaint() == fillIndex &&
(pix + rin->getWrap())->getPaint() !=
(pixb + rbefore->getWrap())->getPaint()) {
filledNeighbor++;
}
// south
if (i > 0 && (pix - rin->getWrap())->getTone() == 255 &&
(pix - rin->getWrap())->getInk() < IGNORECOLORSTYLE &&
(pix - rin->getWrap())->getPaint() == fillIndex &&
(pix - rin->getWrap())->getPaint() !=
(pixb - rbefore->getWrap())->getPaint()) {
filledNeighbor++;
}
// east
if (j < rin->getLx() - 1 && (pix + 1)->getTone() == 255 &&
(pix + 1)->getInk() < IGNORECOLORSTYLE &&
(pix + 1)->getPaint() == fillIndex &&
(pix + 1)->getPaint() != (pixb + 1)->getPaint()) {
filledNeighbor++;
}
// west
if (j > 0 && (pix - 1)->getTone() == 255 &&
(pix - 1)->getInk() < IGNORECOLORSTYLE &&
(pix - 1)->getPaint() == fillIndex &&
(pix - 1)->getPaint() != (pixb - 1)->getPaint()) {
filledNeighbor++;
}
// Check for fillable but unfilled pixel neighbor
// north
if ((i < rin->getLy() - 1 && (pix + rin->getWrap())->getTone() == 255 &&
(((pix + rin->getWrap())->getPaint() == clickedColorStyle) ||
((pix + rin->getWrap())->getPaint() == 0) ||
((pix + rin->getWrap())->getPaint() == IGNORECOLORSTYLE))) &&
((pixc + myCombined->getWrap())->getTone() == 255 &&
(((pixc + myCombined->getWrap())->getPaint() == clickedColorStyle) ||
((pixc + myCombined->getWrap())->getPaint() == 0)))) {
unfilledNeighbor++;
}
// south
if ((i > 0 && (pix - rin->getWrap())->getTone() == 255 &&
(((pix - rin->getWrap())->getPaint() == clickedColorStyle) ||
((pix - rin->getWrap())->getPaint() == 0) ||
((pix - rin->getWrap())->getPaint() == IGNORECOLORSTYLE))) &&
((pixc - myCombined->getWrap())->getTone() == 255 &&
(((pixc - myCombined->getWrap())->getPaint() == clickedColorStyle) ||
((pixc - myCombined->getWrap())->getPaint() == 0)))) {
unfilledNeighbor++;
}
// east
if ((j < rin->getLx() - 1 && (pix + 1)->getTone() == 255 &&
(((pix + 1)->getPaint() == clickedColorStyle) ||
((pix + 1)->getPaint() == 0) ||
((pix + 1)->getPaint() == IGNORECOLORSTYLE))) &&
((pixc + 1)->getTone() == 255 &&
(((pixc + 1)->getPaint() == clickedColorStyle) ||
((pixc + 1)->getPaint() == 0)))) {
unfilledNeighbor++;
}
// west
if ((j > 0 && (pix - 1)->getTone() == 255 &&
(((pix - 1)->getPaint() == clickedColorStyle) ||
((pix - 1)->getPaint() == 0) ||
((pix - 1)->getPaint() == IGNORECOLORSTYLE))) &&
((pixc - 1)->getTone() == 255 &&
(((pixc - 1)->getPaint() == clickedColorStyle) ||
((pixc - 1)->getPaint() == 0)))) {
unfilledNeighbor++;
}
// determine the final disposition of the gap line pixel
if (filledNeighbor > 0) {
if (unfilledNeighbor > 0) {
// keep
if (closeGaps) {
// ink
pix->setInk(closeColorStyle);
pix->setPaint(fillIndex);
pix->setTone(0);
} else {
// paint
pix->setInk(GAP_CLOSE_USED);
pix->setPaint(fillIndex);
pix->setTone(255);
gapLinePixels.push(TPoint(j, i));
}
// Print out the neighbors of kept gap close pixels, for testing
// purposes
// TSystem::outputDebug("i:"+ std::to_string(i)+", j:"+
// std::to_string(j)+", filledNeighbor:" +
// std::to_string(filledNeighbor) + ", unfilledNeighbor:" +
// std::to_string(unfilledNeighbor));
//// north
// if (i < rin->getLy() - 1){
// TSystem::outputDebug("North, r:" + std::to_string((pix +
// rin->getWrap())->getInk()) + "." + std::to_string((pix +
// rin->getWrap())->getPaint()) + "." + std::to_string((pix +
// rin->getWrap())->getTone())
// + ", combined:" + std::to_string((pixc +
// myCombined->getWrap())->getInk()) + "." + std::to_string((pixc +
// myCombined->getWrap())->getPaint()) + "." + std::to_string((pixc +
// myCombined->getWrap())->getTone())
// );
//}
//// south
// if (i > 0) {
// TSystem::outputDebug("South, r:" + std::to_string((pix -
// rin->getWrap())->getInk()) + "." + std::to_string((pix -
// rin->getWrap())->getPaint()) + "." + std::to_string((pix -
// rin->getWrap())->getTone())
// + ", combined:" + std::to_string((pixc -
// myCombined->getWrap())->getInk()) + "." + std::to_string((pixc -
// myCombined->getWrap())->getPaint()) + "." + std::to_string((pixc
// - myCombined->getWrap())->getTone())
// );
//}
//// east
// if (j < rin->getLx() - 1){
// TSystem::outputDebug("East, r:" + std::to_string((pix +
// 1)->getInk()) + "." + std::to_string((pix + 1)->getPaint()) + "."
// + std::to_string((pix + 1)->getTone())
// + ", combined:" + std::to_string((pixc + 1)->getInk()) + "." +
// std::to_string((pixc + 1)->getPaint()) + "." +
// std::to_string((pixc + 1)->getTone())
// );
//}
//// west
// if (j > 0) {
// TSystem::outputDebug("West, r:" + std::to_string((pix -
// 1)->getInk()) + "." + std::to_string((pix - 1)->getPaint()) + "."
// + std::to_string((pix - 1)->getTone())
// + ", combined:" + std::to_string((pixc - 1)->getInk()) + "." +
// std::to_string((pixc - 1)->getPaint()) + "." +
// std::to_string((pixc - 1)->getTone())
// );
//}
} else {
// paint
pix->setInk(GAP_CLOSE_USED);
pix->setPaint(fillIndex);
pix->setTone(255);
gapLinePixels.push(TPoint(j, i));
}
} else {
// ignore
pix->setInk(IGNORECOLORSTYLE);
pix->setPaint(0);
pix->setTone(0);
}
}
}
// process all the GAP_CLOSE_USED ink values.
TPixelCM32 *pixels = (TPixelCM32 *)r->getRawData();
while (!gapLinePixels.empty()) {
p = gapLinePixels.top();
gapLinePixels.pop();
TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x);
// TSystem::outputDebug("gapLinePixels, p.y:" + std::to_string(p.y) + ",
// p.x:" + std::to_string(p.x) + ", getInk():" +
// std::to_string(pix->getInk()));
pix->setInk(0);
}
rin->unlock();
}
//=============================================================================