@@ -793,14 +793,41 @@ void Segment::deletejMap() {
793793}
794794
795795
796- // WLEDMM constants for mapping mode "Pinwheel"
797- constexpr int Pinwheel_Steps_Medium = 208 ; // no holes up to 32x32; 60fps
798- constexpr int Pinwheel_Size_Medium = 32 ; // larger than this -> use "Big"
799- constexpr int Pinwheel_Steps_Big = 360 ; // no holes expected up to 58x58; 40fps
800- constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
801- constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
802- // WLEDMM end
803-
796+ // Constants for mapping mode "Pinwheel"
797+ #ifndef WLED_DISABLE_2D
798+ constexpr int Pinwheel_Steps_Small = 72 ; // no holes up to 16x16
799+ constexpr int Pinwheel_Size_Small = 16 ; // larger than this -> use "Medium"
800+ constexpr int Pinwheel_Steps_Medium = 192 ; // no holes up to 32x32
801+ constexpr int Pinwheel_Size_Medium = 32 ; // larger than this -> use "Big"
802+ constexpr int Pinwheel_Steps_Big = 304 ; // no holes up to 50x50
803+ constexpr int Pinwheel_Size_Big = 50 ; // larger than this -> use "XL"
804+ constexpr int Pinwheel_Steps_XL = 368 ;
805+ constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Small; // conversion: from 0...72 to Radians
806+ constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Medium; // conversion: from 0...192 to Radians
807+ constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_Big; // conversion: from 0...304 to Radians
808+ constexpr float Int_to_Rad_XL = (DEG_TO_RAD * 360 ) / Pinwheel_Steps_XL; // conversion: from 0...368 to Radians
809+
810+ constexpr int Fixed_Scale = 512 ; // fixpoint scaling factor (9bit for fraction)
811+
812+ // Pinwheel helper function: pixel index to radians
813+ static float getPinwheelAngle (int i, int vW, int vH) {
814+ int maxXY = max (vW, vH);
815+ if (maxXY <= Pinwheel_Size_Small) return float (i) * Int_to_Rad_Small;
816+ if (maxXY <= Pinwheel_Size_Medium) return float (i) * Int_to_Rad_Med;
817+ if (maxXY <= Pinwheel_Size_Big) return float (i) * Int_to_Rad_Big;
818+ // else
819+ return float (i) * Int_to_Rad_XL;
820+ }
821+ // Pinwheel helper function: matrix dimensions to number of rays
822+ static int getPinwheelLength (int vW, int vH) {
823+ int maxXY = max (vW, vH);
824+ if (maxXY <= Pinwheel_Size_Small) return Pinwheel_Steps_Small;
825+ if (maxXY <= Pinwheel_Size_Medium) return Pinwheel_Steps_Medium;
826+ if (maxXY <= Pinwheel_Size_Big) return Pinwheel_Steps_Big;
827+ // else
828+ return Pinwheel_Steps_XL;
829+ }
830+ #endif
804831
805832// 1D strip
806833uint16_t Segment::virtualLength () const {
@@ -831,12 +858,8 @@ uint16_t Segment::virtualLength() const {
831858 else
832859 vLen = max (vW,vH) * 0.5 ; // get the longest dimension
833860 break ;
834- case M12_sPinWheel: // WLEDMM
835- // vLen = full circle
836- if (max (vW,vH) <= Pinwheel_Size_Medium)
837- vLen = Pinwheel_Steps_Medium;
838- else
839- vLen = Pinwheel_Steps_Big;
861+ case M12_sPinwheel:
862+ vLen = getPinwheelLength (vW, vH);
840863 break ;
841864 }
842865 return vLen;
@@ -978,32 +1001,46 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
9781001 }
9791002 }
9801003 break ;
981- case M12_sPinWheel : { // WLEDMM
982- // i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
1004+ case M12_sPinwheel : {
1005+ // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small )
9831006 float centerX = roundf ((vW-1 ) / 2 .0f );
9841007 float centerY = roundf ((vH-1 ) / 2 .0f );
985- // int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
986- float angleRad = (max (vW,vH) > Pinwheel_Size_Medium) ? float (i) * Int_to_Rad_Big : float (i) * Int_to_Rad_Med; // angle in radians
1008+ float angleRad = getPinwheelAngle (i, vW, vH); // angle in radians
9871009 float cosVal = cosf (angleRad);
9881010 float sinVal = sinf (angleRad);
9891011
1012+ // avoid re-painting the same pixel
1013+ int lastX = INT_MIN ; // impossible position
1014+ int lastY = INT_MIN ; // impossible position
9901015 // draw line at angle, starting at center and ending at the segment edge
9911016 // we use fixed point math for better speed. Starting distance is 0.5 for better rounding
992- constexpr int_fast32_t Fixed_Scale = 512 ; // fixpoint scaling factor
993- int_fast32_t posx = (centerX + 0 .5f * cosVal) * Fixed_Scale; // X starting position in fixed point
994- int_fast32_t posy = (centerY + 0 .5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
995- int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
996- int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
1017+ // int_fast16_t and int_fast32_t types changed to int, minimum bits commented
1018+ int posx = (centerX + 0 .5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
1019+ int posy = (centerY + 0 .5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
1020+ int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
1021+ int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
9971022
9981023 int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
9991024 int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
1000- // draw until we hit any edge
1001- while ((posx > 0 ) && (posy > 0 ) && (posx < maxX) && (posy < maxY)) {
1025+
1026+ // Odd rays start further from center if prevRay started at center.
1027+ static int prevRay = INT_MIN ; // previous ray number
1028+ if ((i % 2 == 1 ) && (i - 1 == prevRay || i + 1 == prevRay)) {
1029+ int jump = min (vW/3 , vH/3 ); // can add 2 if using medium pinwheel
1030+ posx += inc_x * jump;
1031+ posy += inc_y * jump;
1032+ }
1033+ prevRay = i;
1034+
1035+ // draw ray until we hit any edge
1036+ while ((posx >= 0 ) && (posy >= 0 ) && (posx < maxX) && (posy < maxY)) {
10021037 // scale down to integer (compiler will replace division with appropriate bitshift)
10031038 int x = posx / Fixed_Scale;
10041039 int y = posy / Fixed_Scale;
10051040 // set pixel
1006- setPixelColorXY (x, y, col);
1041+ if (x != lastX || y != lastY) setPixelColorXY (x, y, col); // only paint if pixel position is different
1042+ lastX = x;
1043+ lastY = y;
10071044 // advance to next position
10081045 posx += inc_x;
10091046 posy += inc_y;
@@ -1154,16 +1191,36 @@ uint32_t Segment::getPixelColor(int i)
11541191 else
11551192 return getPixelColorXY (vW / 2 , vH / 2 - i - 1 );
11561193 break ;
1157- case M12_sPinWheel: // WLEDMM
1158- // not 100% accurate, returns outer edge of circle
1159- float distance = max (1 .0f , min (vH-1 , vW-1 ) / 2 .0f );
1160- float centerX = (vW - 1 ) / 2 .0f ;
1161- float centerY = (vH - 1 ) / 2 .0f ;
1162- float angleRad = (max (vW,vH) > Pinwheel_Size_Medium) ? float (i) * Int_to_Rad_Big : float (i) * Int_to_Rad_Med; // angle in radians
1163- int x = roundf (centerX + distance * cosf (angleRad));
1164- int y = roundf (centerY + distance * sinf (angleRad));
1194+ case M12_sPinwheel:
1195+ // not 100% accurate, returns pixel at outer edge
1196+ // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small)
1197+ float centerX = roundf ((vW-1 ) / 2 .0f );
1198+ float centerY = roundf ((vH-1 ) / 2 .0f );
1199+ float angleRad = getPinwheelAngle (i, vW, vH); // angle in radians
1200+ float cosVal = cosf (angleRad);
1201+ float sinVal = sinf (angleRad);
1202+
1203+ int posx = (centerX + 0 .5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
1204+ int posy = (centerY + 0 .5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
1205+ int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
1206+ int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
1207+ int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
1208+ int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
1209+
1210+ // trace ray from center until we hit any edge - to avoid rounding problems, we use the same method as in setPixelColor
1211+ int x = INT_MIN ;
1212+ int y = INT_MIN ;
1213+ while ((posx >= 0 ) && (posy >= 0 ) && (posx < maxX) && (posy < maxY)) {
1214+ // scale down to integer (compiler will replace division with appropriate bitshift)
1215+ x = posx / Fixed_Scale;
1216+ y = posy / Fixed_Scale;
1217+ // advance to next position
1218+ posx += inc_x;
1219+ posy += inc_y;
1220+ }
11651221 return getPixelColorXY (x, y);
1166- }
1222+ break ;
1223+ }
11671224 return 0 ;
11681225 }
11691226#endif
0 commit comments