Krita Source Code Documentation
Loading...
Searching...
No Matches
KisBorderSelectionFilter Class Reference

#include <kis_selection_filters.h>

+ Inheritance diagram for KisBorderSelectionFilter:

Public Member Functions

QRect changeRect (const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override
 
 KisBorderSelectionFilter (qint32 xRadius, qint32 yRadius, bool fade)
 
KUndo2MagicString name () override
 
void process (KisPixelSelectionSP pixelSelection, const QRect &rect) override
 
- Public Member Functions inherited from KisSelectionFilter
virtual ~KisSelectionFilter ()
 

Private Attributes

bool m_antialiasing
 
qint32 m_xRadius
 
qint32 m_yRadius
 

Additional Inherited Members

- Protected Member Functions inherited from KisSelectionFilter
void computeBorder (qint32 *circ, qint32 xradius, qint32 yradius)
 
void computeTransition (quint8 *transition, quint8 **buf, qint32 width)
 
void rotatePointers (quint8 **p, quint32 n)
 

Detailed Description

Definition at line 60 of file kis_selection_filters.h.

Constructor & Destructor Documentation

◆ KisBorderSelectionFilter()

KisBorderSelectionFilter::KisBorderSelectionFilter ( qint32 xRadius,
qint32 yRadius,
bool fade )

Definition at line 246 of file kis_selection_filters.cpp.

247 : m_xRadius(xRadius),
248 m_yRadius(yRadius),
249 m_antialiasing(antialiasing)
250{
251}

Member Function Documentation

◆ changeRect()

QRect KisBorderSelectionFilter::changeRect ( const QRect & rect,
KisDefaultBoundsBaseSP defaultBounds )
overridevirtual

Reimplemented from KisSelectionFilter.

Definition at line 258 of file kis_selection_filters.cpp.

259{
260 Q_UNUSED(defaultBounds);
261
262 return rect.adjusted(-m_xRadius, -m_yRadius, m_xRadius, m_yRadius);
263}

References m_xRadius, and m_yRadius.

◆ name()

KUndo2MagicString KisBorderSelectionFilter::name ( )
overridevirtual

Reimplemented from KisSelectionFilter.

Definition at line 253 of file kis_selection_filters.cpp.

254{
255 return kundo2_i18n("Border Selection");
256}
KUndo2MagicString kundo2_i18n(const char *text)

References kundo2_i18n().

◆ process()

void KisBorderSelectionFilter::process ( KisPixelSelectionSP pixelSelection,
const QRect & rect )
overridevirtual

Implements KisSelectionFilter.

Definition at line 265 of file kis_selection_filters.cpp.

266{
267 if (m_xRadius <= 0 || m_yRadius <= 0) return;
268
269 quint8 *buf[3];
270 quint8 **density;
271 quint8 **transition;
272
273 if (m_xRadius == 1 && m_yRadius == 1) {
274 // optimize this case specifically
275 quint8* source[3];
276
277 for (qint32 i = 0; i < 3; i++)
278 source[i] = new quint8[rect.width()];
279
280 quint8* transition = new quint8[rect.width()];
281
282 pixelSelection->readBytes(source[0], rect.x(), rect.y(), rect.width(), 1);
283 memcpy(source[1], source[0], rect.width());
284 if (rect.height() > 1)
285 pixelSelection->readBytes(source[2], rect.x(), rect.y() + 1, rect.width(), 1);
286 else
287 memcpy(source[2], source[1], rect.width());
288
289 computeTransition(transition, source, rect.width());
290 pixelSelection->writeBytes(transition, rect.x(), rect.y(), rect.width(), 1);
291
292 for (qint32 y = 1; y < rect.height(); y++) {
294 if (y + 1 < rect.height())
295 pixelSelection->readBytes(source[2], rect.x(), rect.y() + y + 1, rect.width(), 1);
296 else
297 memcpy(source[2], source[1], rect.width());
298 computeTransition(transition, source, rect.width());
299 pixelSelection->writeBytes(transition, rect.x(), rect.y() + y, rect.width(), 1);
300 }
301
302 for (qint32 i = 0; i < 3; i++)
303 delete[] source[i];
304 delete[] transition;
305 return;
306 }
307
308 qint32* max = new qint32[rect.width() + 2 * m_xRadius];
309 for (qint32 i = 0; i < (rect.width() + 2 * m_xRadius); i++)
310 max[i] = m_yRadius + 2;
311 max += m_xRadius;
312
313 for (qint32 i = 0; i < 3; i++)
314 buf[i] = new quint8[rect.width()];
315
316 transition = new quint8*[m_yRadius + 1];
317 for (qint32 i = 0; i < m_yRadius + 1; i++) {
318 transition[i] = new quint8[rect.width() + 2 * m_xRadius];
319 memset(transition[i], 0, rect.width() + 2 * m_xRadius);
320 transition[i] += m_xRadius;
321 }
322 quint8* out = new quint8[rect.width()];
323 density = new quint8*[2 * m_xRadius + 1];
324 density += m_xRadius;
325
326 for (qint32 x = 0; x < (m_xRadius + 1); x++) { // allocate density[][]
327 density[ x] = new quint8[2 * m_yRadius + 1];
328 density[ x] += m_yRadius;
329 density[-x] = density[x];
330 }
331
332 // compute density[][]
333 if (m_antialiasing) {
334 KIS_SAFE_ASSERT_RECOVER_NOOP(m_xRadius == m_yRadius && "anisotropic fading is not implemented");
335 const qreal maxRadius = 0.5 * (m_xRadius + m_yRadius);
336 const qreal minRadius = maxRadius - 1.0;
337
338 for (qint32 x = 0; x < (m_xRadius + 1); x++) {
339 double dist;
340 quint8 a;
341
342 for (qint32 y = 0; y < (m_yRadius + 1); y++) {
343
344 dist = sqrt(pow2(x) + pow2(y));
345
346 if (dist > maxRadius) {
347 a = 0;
348 } else if (dist > minRadius) {
349 a = qRound((1.0 - dist + minRadius) * 255.0);
350 } else {
351 a = 255;
352 }
353
354 density[ x][ y] = a;
355 density[ x][-y] = a;
356 density[-x][ y] = a;
357 density[-x][-y] = a;
358 }
359 }
360
361 } else {
362 for (qint32 x = 0; x < (m_xRadius + 1); x++) {
363 double tmpx, tmpy, dist;
364 quint8 a;
365
366 tmpx = x > 0.0 ? x - 0.5 : 0.0;
367
368 for (qint32 y = 0; y < (m_yRadius + 1); y++) {
369 tmpy = y > 0.0 ? y - 0.5 : 0.0;
370
371 dist = (pow2(tmpy) / pow2(m_yRadius) +
372 pow2(tmpx) / pow2(m_xRadius));
373
374 a = dist <= 1.0 ? 255 : 0;
375
376 density[ x][ y] = a;
377 density[ x][-y] = a;
378 density[-x][ y] = a;
379 density[-x][-y] = a;
380 }
381 }
382 }
383
384 pixelSelection->readBytes(buf[0], rect.x(), rect.y(), rect.width(), 1);
385 memcpy(buf[1], buf[0], rect.width());
386 if (rect.height() > 1)
387 pixelSelection->readBytes(buf[2], rect.x(), rect.y() + 1, rect.width(), 1);
388 else
389 memcpy(buf[2], buf[1], rect.width());
390 computeTransition(transition[1], buf, rect.width());
391
392 for (qint32 y = 1; y < m_yRadius && y + 1 < rect.height(); y++) { // set up top of image
393 rotatePointers(buf, 3);
394 pixelSelection->readBytes(buf[2], rect.x(), rect.y() + y + 1, rect.width(), 1);
395 computeTransition(transition[y + 1], buf, rect.width());
396 }
397 for (qint32 x = 0; x < rect.width(); x++) { // set up max[] for top of image
398 max[x] = -(m_yRadius + 7);
399 for (qint32 j = 1; j < m_yRadius + 1; j++)
400 if (transition[j][x]) {
401 max[x] = j;
402 break;
403 }
404 }
405 for (qint32 y = 0; y < rect.height(); y++) { // main calculation loop
406 rotatePointers(buf, 3);
407 rotatePointers(transition, m_yRadius + 1);
408 if (y < rect.height() - (m_yRadius + 1)) {
409 pixelSelection->readBytes(buf[2], rect.x(), rect.y() + y + m_yRadius + 1, rect.width(), 1);
410 computeTransition(transition[m_yRadius], buf, rect.width());
411 } else
412 memcpy(transition[m_yRadius], transition[m_yRadius - 1], rect.width());
413
414 for (qint32 x = 0; x < rect.width(); x++) { // update max array
415 if (max[x] < 1) {
416 if (max[x] <= -m_yRadius) {
417 if (transition[m_yRadius][x])
418 max[x] = m_yRadius;
419 else
420 max[x]--;
421 } else if (transition[-max[x]][x])
422 max[x] = -max[x];
423 else if (transition[-max[x] + 1][x])
424 max[x] = -max[x] + 1;
425 else
426 max[x]--;
427 } else
428 max[x]--;
429 if (max[x] < -m_yRadius - 1)
430 max[x] = -m_yRadius - 1;
431 }
432 quint8 last_max = max[0][density[-1]];
433 qint32 last_index = 1;
434 for (qint32 x = 0 ; x < rect.width(); x++) { // render scan line
435 last_index--;
436 if (last_index >= 0) {
437 last_max = 0;
438 for (qint32 i = m_xRadius; i >= 0; i--)
439 if (max[x + i] <= m_yRadius && max[x + i] >= -m_yRadius && density[i][max[x+i]] > last_max) {
440 last_max = density[i][max[x + i]];
441 last_index = i;
442 }
443 out[x] = last_max;
444 } else {
445 last_max = 0;
446 for (qint32 i = m_xRadius; i >= -m_xRadius; i--)
447 if (max[x + i] <= m_yRadius && max[x + i] >= -m_yRadius && density[i][max[x + i]] > last_max) {
448 last_max = density[i][max[x + i]];
449 last_index = i;
450 }
451 out[x] = last_max;
452 }
453 if (last_max == 0) {
454 qint32 i;
455 for (i = x + 1; i < rect.width(); i++) {
456 if (max[i] >= -m_yRadius)
457 break;
458 }
459 if (i - x > m_xRadius) {
460 for (; x < i - m_xRadius; x++)
461 out[x] = 0;
462 x--;
463 }
464 last_index = m_xRadius;
465 }
466 }
467 pixelSelection->writeBytes(out, rect.x(), rect.y() + y, rect.width(), 1);
468 }
469 delete [] out;
470
471 for (qint32 i = 0; i < 3; i++)
472 delete[] buf[i];
473
474 max -= m_xRadius;
475 delete[] max;
476
477 for (qint32 i = 0; i < m_yRadius + 1; i++) {
478 transition[i] -= m_xRadius;
479 delete transition[i];
480 }
481 delete[] transition;
482
483 for (qint32 i = 0; i < m_xRadius + 1 ; i++) {
484 density[i] -= m_yRadius;
485 delete density[i];
486 }
487 density -= m_xRadius;
488 delete[] density;
489}
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
void writeBytes(const quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h)
void rotatePointers(quint8 **p, quint32 n)
void computeTransition(quint8 *transition, quint8 **buf, qint32 width)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
T pow2(const T &x)
Definition kis_global.h:166
constexpr std::enable_if< sizeof...(values)==0, size_t >::type max()

References KisSelectionFilter::computeTransition(), KIS_SAFE_ASSERT_RECOVER_NOOP, m_antialiasing, m_xRadius, m_yRadius, pow2(), KisPaintDevice::readBytes(), KisSelectionFilter::rotatePointers(), source(), and KisPaintDevice::writeBytes().

Member Data Documentation

◆ m_antialiasing

bool KisBorderSelectionFilter::m_antialiasing
private

Definition at line 74 of file kis_selection_filters.h.

◆ m_xRadius

qint32 KisBorderSelectionFilter::m_xRadius
private

Definition at line 72 of file kis_selection_filters.h.

◆ m_yRadius

qint32 KisBorderSelectionFilter::m_yRadius
private

Definition at line 73 of file kis_selection_filters.h.


The documentation for this class was generated from the following files: