@@ -426,7 +426,7 @@ void Segment::move(unsigned dir, unsigned delta, bool wrap) const {
426426 }
427427}
428428
429- void Segment::drawCircle (uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bool soft) const {
429+ void Segment::drawCircle (uint16_t cx, uint16_t cy, uint16_t radius, CRGBA col, bool soft) const {
430430 if (!isActive () || radius == 0 ) return ; // not active
431431 if (soft) {
432432 // Xiaolin Wu’s algorithm
@@ -446,11 +446,11 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bo
446446 int dx = (i & 1 ) ? -1 : 1 ; // 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1
447447 int dy = (i & 2 ) ? -1 : 1 ; // 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1
448448 if (swaps) {
449- px = cx + (y - adj) * dx;
450- py = cy + x * dy;
449+ px = cx + (y - adj) * dx;
450+ py = cy + x * dy;
451451 } else {
452- px = cx + x * dx;
453- py = cy + (y - adj) * dy;
452+ px = cx + x * dx;
453+ py = cy + (y - adj) * dy;
454454 }
455455 if (px < 0 || py < 0 || px >= (int )vWidth () || py >= (int )vHeight ()) continue ;
456456 blendPixelColorXYRaw (px, py, col, (uint8_t )(adj ? fade : 255 - fade));
@@ -483,22 +483,95 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bo
483483}
484484
485485// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
486- void Segment::fillCircle (uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bool soft) const {
486+ void Segment::fillCircle (uint16_t cx, uint16_t cy, uint16_t radius, CRGBA col, bool soft) const {
487487 if (!isActive () || radius == 0 ) return ; // not active
488488 const int vW = vWidth (); // segment width in logical pixels (can be 0 if segment is inactive)
489489 const int vH = vHeight (); // segment height in logical pixels (is always >= 1)
490490 // draw soft bounding circle
491491 if (soft) drawCircle (cx, cy, radius, col, soft);
492492 // fill it
493+ uint32_t rSq = radius * radius;
493494 for (int y = -radius; y <= radius; y++) {
494495 for (int x = -radius; x <= radius; x++) {
495- if (x * x + y * y <= radius * radius &&
496+ if (x * x + y * y <= rSq &&
496497 int (cx)+x >= 0 && int (cy)+y >= 0 &&
497- int (cx)+x < vW && int (cy)+y < vH)
498+ int (cx)+x < vW && int (cy)+y < vH) {
499+ col += getPixelColorXYRaw (cx + x, cy + y);
498500 setPixelColorXYRaw (cx + x, cy + y, col);
501+ }
502+ }
503+ }
504+ }
505+
506+ /*
507+ // see https://www.geeksforgeeks.org/dsa/midpoint-ellipse-drawing-algorithm/
508+ void Segment::drawEllipse(uint32_t cx, uint32_t cy, uint32_t rx, uint32_t ry, CRGBA color, bool fill, bool soft) {
509+ // all coodinates and radii are in 16.8 fixed point notation (use >> 8 to convert to pixel coordinates)
510+ if (!isActive()) return; // not active
511+ const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
512+ const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
513+ if (cx >= vW<<8 || cy >= vH<<8) return; // center outside segment
514+ int32_t rxSq = (rx * rx);
515+ int32_t rySq = (ry * ry);
516+ int32_t x = 0, y = ry;
517+ //auto fEllipse = [&](int32_t x, int32_t y) {
518+ // return (rySq * x * x) + (rxSq * y * y) - (rxSq * rySq);
519+ //};
520+
521+ // Region 1
522+ int32_t d1 = roundf((float)(rySq - (rxSq * ry)) + (0.25f * rxSq)); // initial decision parameter
523+ int32_t dx = 2 * rySq * x;
524+ int32_t dy = 2 * rxSq * y;
525+
526+ while (dx < dy) {
527+ if (fill) {
528+ drawLine((cx - x)>>8, (cy + y)>>8, (cx + x)>>8, (cy + y)>>8, color, false);
529+ drawLine((cx - x)>>8, (cy - y)>>8, (cx + x)>>8, (cy - y)>>8, color, false);
530+ } else {
531+ setWuPixelColor(cx - x, cy + y, color);
532+ setWuPixelColor(cx + x, cy + y, color);
533+ setWuPixelColor(cx - x, cy - y, color);
534+ setWuPixelColor(cx + x, cy - y, color);
535+ }
536+ if (d1 < 0) {
537+ x += 256; // increment x by 1 in 16.8 pixel notation
538+ dx += (2 * rySq);
539+ d1 += dx + rySq;
540+ } else {
541+ x += 256;
542+ y -= 256;
543+ dx += (2 * rySq);
544+ dy -= (2 * rxSq);
545+ d1 += dx - dy + rySq;
546+ }
547+ }
548+
549+ // Region 2
550+ int32_t d2 = (rxSq * ((x + 0.5f) * (x + 0.5f))) + (rxSq * ((y - 1) * (y - 1))) - (rxSq * rySq);
551+ while (y >= 0) {
552+ if (fill) {
553+ drawLine((cx - x)>>8, (cy + y)>>8, (cx + x)>>8, (cy + y)>>8, color, false);
554+ drawLine((cx - x)>>8, (cy - y)>>8, (cx + x)>>8, (cy - y)>>8, color, false);
555+ } else {
556+ setWuPixelColor(cx - x, cy + y, color);
557+ setWuPixelColor(cx + x, cy + y, color);
558+ setWuPixelColor(cx - x, cy - y, color);
559+ setWuPixelColor(cx + x, cy - y, color);
560+ }
561+ if (d2 > 0) {
562+ y -= 256;
563+ dy -= (2 * rxSq);
564+ d2 += rxSq - dy;
565+ } else {
566+ y -= 256;
567+ x += 256;
568+ dx += (2 * rySq);
569+ dy -= (2 * rxSq);
570+ d2 += dx - dy + rxSq;
499571 }
500572 }
501573}
574+ */
502575
503576// line function
504577void Segment::drawLine (uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGBA c, bool soft) const {
@@ -605,7 +678,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
605678// https://gist.github.com/sutaburosu/32a203c2efa2bb584f4b846a91066583#file-cakeday_hack-ino-L154
606679// @param x 16.8 fixed point
607680// @param y 16.8 fixed point
608- void Segment::wu_pixel (uint32_t x, uint32_t y, CRGBA c) const {
681+ void Segment::setWuPixelColor (uint32_t x, uint32_t y, CRGBA c) const {
609682 if (!isActive ()) return ; // not active
610683 // extract the fractional parts and derive their inverses
611684 unsigned xx = x & 0xff , yy = y & 0xff , ix = 255 - xx, iy = 255 - yy;
@@ -616,10 +689,10 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGBA c) const {
616689 for (int i = 0 ; i < 4 ; i++) {
617690 int wu_x = (x >> 8 ) + (i & 1 ); // precalculate x
618691 int wu_y = (y >> 8 ) + ((i >> 1 ) & 1 ); // precalculate y
619- CRGBA led = getPixelColorXY ( wu_x, wu_y);
620- c.a = wu[i]; // set alpha to weight
621- led += c;
622- setPixelColorXY (wu_x, wu_y, led);
692+ if ( /* wu_x >= 0 && wu_y >= 0 && */ wu_x < ( int ) vWidth () && wu_y < ( int ) vHeight ()) {
693+ c.a = wu[i]; // set alpha to weight
694+ setPixelColorXYRaw (wu_x, wu_y, getPixelColorXYRaw (wu_x, wu_y). add (c, true )); // also modifies resulting opacity; should use addPixelColorXYRaw but that crashes ESP
695+ }
623696 }
624697}
625698
0 commit comments