@@ -776,6 +776,16 @@ void Segment::deletejMap() {
776776 }
777777}
778778
779+
780+ // WLEDMM constants for mapping mode "Pinwheel"
781+ constexpr int Pinwheel_Steps_Medium = 208 ; // no holes up to 32x32; 60fps
782+ constexpr int Pinwheel_Size_Medium = 32 ; // larger than this -> use "Big"
783+ constexpr int Pinwheel_Steps_Big = 360 ; // no holes expected up to 58x58; 40fps
784+ constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
785+ constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
786+ // WLEDMM end
787+
788+
779789// 1D strip
780790uint16_t Segment::virtualLength () const {
781791#ifndef WLED_DISABLE_2D
@@ -806,7 +816,11 @@ uint16_t Segment::virtualLength() const {
806816 vLen = max (vW,vH) * 0.5 ; // get the longest dimension
807817 break ;
808818 case M12_sPinWheel: // WLEDMM
809- vLen = 360 ; // full circle
819+ // vLen = full circle
820+ if (max (vW,vH) <= Pinwheel_Size_Medium)
821+ vLen = Pinwheel_Steps_Medium;
822+ else
823+ vLen = Pinwheel_Steps_Big;
810824 break ;
811825 }
812826 return vLen;
@@ -875,13 +889,26 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
875889 else {
876890 // WLEDMM: drawArc(0, 0, i, col); could work as alternative
877891
878- float step = HALF_PI / (2 .85f *i);
879- for (float rad = 0 .0f ; rad <= HALF_PI+step/2 ; rad += step) {
892+ // WLEDMM: some optimizations for the drawing loop
893+ // pre-calculate loop limits, exploit symmetry at 45deg
894+ float radius = float (i);
895+ // float step = HALF_PI / (2.85f * radius); // upstream uses this
896+ float step = HALF_PI / (M_PI * radius); // WLEDMM we use the correct circumference
897+ bool useSymmetry = (max (vH, vW) > 20 ); // for segments wider than 20 pixels, we exploit symmetry
898+ unsigned numSteps;
899+ if (useSymmetry) numSteps = 1 + ((HALF_PI/2 .0f + step/2 .0f ) / step); // with symmetry
900+ else numSteps = 1 + ((HALF_PI + step/2 .0f ) / step); // without symmetry
901+
902+ float rad = 0 .0f ;
903+ for (unsigned count = 0 ; count < numSteps; count++) {
880904 // may want to try float version as well (with or without antialiasing)
881- int x = roundf (sin_t (rad) * i );
882- int y = roundf (cos_t (rad) * i );
905+ int x = roundf (sinf (rad) * radius );
906+ int y = roundf (cosf (rad) * radius );
883907 setPixelColorXY (x, y, col);
908+ if (useSymmetry) setPixelColorXY (y, x, col);// WLEDMM
909+ rad += step;
884910 }
911+
885912 // Bresenham’s Algorithm (may not fill every pixel)
886913 // int d = 3 - (2*i);
887914 // int y = i, x = 0;
@@ -909,8 +936,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
909936 case M12_sCircle: // WLEDMM
910937 if (vStrip > 0 )
911938 {
912- int x = roundf (sin_t (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
913- int y = roundf (cos_t (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
939+ int x = roundf (sinf (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
940+ int y = roundf (cosf (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
914941 setPixelColorXY (x + vW/2 , y + vH/2 , col);
915942 }
916943 else // pArc -> circle
@@ -935,24 +962,35 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
935962 }
936963 }
937964 break ;
938- case M12_sPinWheel: {
939- // i = 0 through 359
940- float centerX = ( vW-1 ) / 2 ;
941- float centerY = ( vH-1 ) / 2 ;
965+ case M12_sPinWheel: { // WLEDMM
966+ // i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
967+ float centerX = roundf (( vW-1 ) / 2 . 0f ) ;
968+ float centerY = roundf (( vH-1 ) / 2 . 0f ) ;
942969 // int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
943-
944- int distance = 0 ;
945- float cosVal = cosf ((float )i * (float )DEG_TO_RAD); // i = current angle
946- float sinVal = sinf ((float )i * (float )DEG_TO_RAD);
947- while (true ) {
948- int x = roundf (centerX + distance * cosVal);
949- int y = roundf (centerY + distance * sinVal);
950- // Check bounds
951- if (x < 0 || x >= vW || y < 0 || y >= vH) {
952- break ;
953- }
970+ float angleRad = (max (vW,vH) > Pinwheel_Size_Medium) ? float (i) * Int_to_Rad_Big : float (i) * Int_to_Rad_Med; // angle in radians
971+ float cosVal = cosf (angleRad);
972+ float sinVal = sinf (angleRad);
973+
974+ // draw line at angle, starting at center and ending at the segment edge
975+ // we use fixed point math for better speed. Starting distance is 0.5 for better rounding
976+ constexpr int_fast32_t Fixed_Scale = 512 ; // fixpoint scaling factor
977+ int_fast32_t posx = (centerX + 0 .5f * cosVal) * Fixed_Scale; // X starting position in fixed point
978+ int_fast32_t posy = (centerY + 0 .5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
979+ int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
980+ int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
981+
982+ int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
983+ int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
984+ // draw until we hit any edge
985+ while ((posx > 0 ) && (posy > 0 ) && (posx < maxX) && (posy < maxY)) {
986+ // scale down to integer (compiler will replace division with appropriate bitshift)
987+ int x = posx / Fixed_Scale;
988+ int y = posy / Fixed_Scale;
989+ // set pixel
954990 setPixelColorXY (x, y, col);
955- distance++;
991+ // advance to next position
992+ posx += inc_x;
993+ posy += inc_y;
956994 }
957995 break ;
958996 }
@@ -1076,8 +1114,8 @@ uint32_t Segment::getPixelColor(int i)
10761114 case M12_sCircle: // WLEDMM
10771115 if (vStrip > 0 )
10781116 {
1079- int x = roundf (sin_t (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
1080- int y = roundf (cos_t (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
1117+ int x = roundf (sinf (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
1118+ int y = roundf (cosf (360 *i/SEGLEN*DEG_TO_RAD) * vW * (vStrip+1 )/nrOfVStrips ());
10811119 return getPixelColorXY (x + vW/2 , y + vH/2 );
10821120 }
10831121 else
@@ -1094,12 +1132,13 @@ uint32_t Segment::getPixelColor(int i)
10941132 return getPixelColorXY (vW / 2 , vH / 2 - i - 1 );
10951133 break ;
10961134 case M12_sPinWheel: // WLEDMM
1097- // not 100% accurate, returns outer edge of circle
1098- int distance = min (vH, vW) / 2 ;
1099- float centerX = (vW - 1 ) / 2 ;
1100- float centerY = (vH - 1 ) / 2 ;
1101- int x = round (centerX + distance * cos (i * DEG_TO_RAD));
1102- int y = round (centerY + distance * sin (i * DEG_TO_RAD));
1135+ // not 100% accurate, returns outer edge of circle
1136+ float distance = max (1 .0f , min (vH-1 , vW-1 ) / 2 .0f );
1137+ float centerX = (vW - 1 ) / 2 .0f ;
1138+ float centerY = (vH - 1 ) / 2 .0f ;
1139+ float angleRad = (max (vW,vH) > Pinwheel_Size_Medium) ? float (i) * Int_to_Rad_Big : float (i) * Int_to_Rad_Med; // angle in radians
1140+ int x = roundf (centerX + distance * cosf (angleRad));
1141+ int y = roundf (centerY + distance * sinf (angleRad));
11031142 return getPixelColorXY (x, y);
11041143 }
11051144 return 0 ;
0 commit comments