FastLED 3.9.15
Loading...
Searching...
No Matches
corkscrew.cpp
Go to the documentation of this file.
1#include "fl/corkscrew.h"
2#include "fl/algorithm.h"
3#include "fl/math.h"
4#include "fl/splat.h"
5
6#define TWO_PI (PI * 2.0)
7
8namespace fl {
9
10void generateMap(const Corkscrew::Input &input, CorkscrewOutput &output);
11
12void generateMap(const Corkscrew::Input &input, CorkscrewOutput &output) {
13 // Calculate circumference per turn from height and total angle
14 float circumferencePerTurn = input.totalHeight * TWO_PI / input.totalAngle;
15
16 // Calculate vertical segments based on number of turns
17 // For a single turn (2π), we want exactly 1 vertical segment
18 // For two turns (4π), we want exactly 2 vertical segments
19 uint16_t verticalSegments = round(input.totalAngle / TWO_PI);
20
21 // Calculate width based on LED density per turn
22 float ledsPerTurn = static_cast<float>(input.numLeds) / verticalSegments;
23
24 // Determine cylindrical dimensions
25 output.height = verticalSegments;
26 output.width = ceil(ledsPerTurn);
27
28 output.mapping.clear();
29
30 // If numLeds is specified, use that for mapping size instead of grid
31 if (input.numLeds > 0) {
32 output.mapping.reserve(input.numLeds);
33
34 // Generate LED mapping based on numLeds
35 for (uint16_t i = 0; i < input.numLeds; ++i) {
36 // Calculate position along the corkscrew (0.0 to 1.0)
37 float position = static_cast<float>(i) / (input.numLeds - 1);
38
39 // Calculate angle and height
40 float angle = position * input.totalAngle;
41 float height = position * verticalSegments;
42
43 // Calculate circumference position
44 float circumference = fmodf(angle * circumferencePerTurn / TWO_PI,
45 circumferencePerTurn);
46
47 // Store the mapping
48 output.mapping.push_back({circumference, height});
49 }
50 } else {
51 // Original grid-based mapping
52 output.mapping.reserve(output.width * output.height);
53
54 // Corrected super sampling step size
55 float thetaStep = 0.5f / output.width;
56 float hStep = 0.5f / output.height;
57
58 // Precompute angle per segment
59 float anglePerSegment = input.totalAngle / verticalSegments;
60
61 // Loop over cylindrical pixels
62 for (uint16_t h = 0; h < output.height; ++h) {
63 float segmentOffset = input.offsetCircumference * h;
64 for (uint16_t w = 0; w < output.width; ++w) {
65 vec2f sample = {0, 0};
66 // 2x2 supersampling
67 for (uint8_t ssH = 0; ssH < 2; ++ssH) {
68 for (uint8_t ssW = 0; ssW < 2; ++ssW) {
69 float theta =
70 (w + 0.5f + ssW * thetaStep) / output.width;
71 float height = (h + 0.5f + ssH * hStep) / output.height;
72
73 // Corkscrew projection (θ,h)
74 float corkscrewTheta =
75 theta * TWO_PI + anglePerSegment * h;
76 float corkscrewH = height * verticalSegments;
77
78 // Apply circumference offset
79 float corkscrewCircumference = fmodf(
80 corkscrewTheta * circumferencePerTurn / TWO_PI +
81 segmentOffset,
82 circumferencePerTurn);
83
84 // Accumulate samples
85 sample.x += corkscrewCircumference;
86 sample.y += corkscrewH;
87 }
88 }
89
90 // Average the supersampled points
91 sample.x *= 0.25f;
92 sample.y *= 0.25f;
93
94 output.mapping.push_back(sample);
95 }
96 }
97 }
98
99 // Apply inversion if requested
100 if (input.invert) {
101 fl::reverse(output.mapping.begin(), output.mapping.end());
102 }
103}
104
105
109
110vec2f Corkscrew::at(uint16_t i) const {
111 if (i >= mOutput.mapping.size()) {
112 // Handle out-of-bounds access, possibly by returning a default value
113 return vec2f(0, 0);
114 }
115 // Convert the float position to integer
116 const vec2f &position = mOutput.mapping[i];
117 return position;
118}
119
121 if (i >= mOutput.mapping.size()) {
122 // Handle out-of-bounds access, possibly by returning a default
123 // Tile2x2_u8
124 return Tile2x2_u8();
125 }
126 // Use the splat function to convert the vec2f to a Tile2x2_u8
127 return splat(mOutput.mapping[i]);
128}
129
130size_t Corkscrew::size() const { return mOutput.mapping.size(); }
131
133 CorkscrewOutput output;
134 fl::generateMap(input, output);
135 return output;
136}
137
138} // namespace fl
size_t size() const
CorkscrewOutput mOutput
Definition corkscrew.h:154
vec2f at(uint16_t i) const
Tile2x2_u8 at_splat(uint16_t i) const
CorkscrewInput Input
Definition corkscrew.h:119
static CorkscrewOutput generateMap(const Input &input)
For testing.
Corkscrew(const Input &input)
#define TWO_PI
Definition corkscrew.cpp:6
Corkscrew projection utilities.
Tile2x2_u8 splat(vec2f xy)
"Splat" as in "splat pixel rendering" takes a pixel value in float x,y coordinates and "splats" it in...
Definition splat.cpp:14
T ceil(T value)
Definition math.h:18
vec2< float > vec2f
Definition geometry.h:318
void generateMap(const Corkscrew::Input &input, CorkscrewOutput &output)
Definition corkscrew.cpp:12
void reverse(Iterator first, Iterator last)
Definition algorithm.h:8
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
float offsetCircumference
Definition corkscrew.h:52
fl::vector< fl::vec2f, fl::allocator_psram< fl::vec2f > > mapping
Definition corkscrew.h:66
#define round(x)
Definition util.h:10