Hi @nickbeaulieu -
Looks this is a zig-zag wired matrix where you’re using it rotated 90-degrees, wrapped into a cylinder, and you need three of them stacked.
Start by configuring the number of pixels in the Settings tab to (3 x 8 x 32) = 768 pixels.
Now, in the Mapper tab, load the Multiple Panel Matrix example:
First, we change the parameters to show us a single 8x32 panel rotated on its side:
Noting these sections:
zigzag = false
// ...
//create a set of coordinates for a matrix panel
//sized (w, h), rotated by an angle, and offset by (sx, sy)
function panel(w, h, sx, sy, angle) {
// ....
map = map.concat(panel(8, 8, 0, 0, 0))
map = map.concat(panel(8, 8, 8, 0, 0))
// etc...
I changed these key parts first:
zigzag = true
//...
map = map.concat(panel(8, 32, 0, 0, 90))
return map
Ok, this looks good because now we see a single panel in the preview window, rotated like in your diagram.
Now let’s stack three of them vertically:
map = map.concat(panel(8, 32, 0, 0, 90))
map = map.concat(panel(8, 32, 0, 8, 90))
map = map.concat(panel(8, 32, 0, 16, 90))
Good deal. Now for the hard part, which is that we want to make it three-dimensional. Right now, the Z coordinate is 0 across all pixels, because it’s flat. To make it into a cylinder, we need to compress the X-axis by cosine, and the Z-axis by sine. We should do this every 8 pixels, completing a full circle after every 8 * 32 = 256 pixels. I’ll do this with a simple for
loop to make it easier to follow along.
First, I want to get an iterator going that adds a Z-axis value of zero, keeping it flat:
// ...
map = map.concat(panel(8, 32, 0, 16, 90))
var map3D = [];
for (i = 0; i < map.length; i++) {
var x = map[i][0], y = map[i][1]
map3D.push([x, y, 0])
}
return map3D
So far so good, looks right:
Now we need a bit of math that will give us that angle around the cylinder for each pixel. I know it’s 8 * 32 = 256 pixels each time around, so I could start with something basic that converts each of the 256 pixels into a fraction of a complete rotation, 0…1. Math.sin/cos take radians, which is 0…2 Pi instead of 0…1.
for (i = 0; i < map.length; i++) {
var x = map[i][0], y = map[i][1]
var angle = i / 256 * 2 * Math.PI
map3D.push([Math.cos(angle), y, Math.sin(angle)])
}
Ah - I see, because Sin and Cos return values from -1…1, but the Y-axis height is still in units of pixels (it’s 24 pixels tall), I’ll cheat and just use the “fill” map mode instead of the “contain” mode for now. This will stretch it out in all dimensions to fill a 1x1x1 cube.
Great. Getting closer. The next thing to fix is to make the angle only advance every 8 pixels. There’s 32 columns of 8 pixels, so what math do I need to get each column’s angle in 0…2 Pi, in 8 pixel chunks?
var columnNumber = Math.floor(i / 8)
var angle = columnNumber / 32 * 2 * Math.PI
Let’s check it by grabbing it and rotating it in 3D.
Looks pretty good!
Here’s the final, complete map code:
Click to expand final cylinder map generator
function (pixelCount) {
//set zigzag to true if every other LED row travels in reverse
//if they are all straight across, set it to false
zigzag = true
//rotate a point (x, y), along a center (cx, cy), by an angle in degrees
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return [nx, ny];
}
//create a set of coordinates for a matrix panel
//sized (w, h), rotated by an angle, and offset by (sx, sy)
function panel(w, h, sx, sy, angle) {
var x, x2, y, p, map = []
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
//for zigzag, flip direction every other row
if (zigzag && y % 2 == 1)
x2 = w - 1 - x
else
x2 = x
p = rotate((w-1)/2, (h-1)/2, x2, y, angle);
p[0] += sx
p[1] += sy
map.push(p)
}
}
return map;
}
//assemble one or more panels
var map = [];
// Three 8x32 panels, rotated on their side, then stacked up in Y axis
map = map.concat(panel(8, 32, 0, 0, 90))
map = map.concat(panel(8, 32, 0, 8, 90))
map = map.concat(panel(8, 32, 0, 16, 90))
// Cobvert to a 3D map, and wrap into a cylinder
var map3D = [];
for (i = 0; i < map.length; i++) {
var x = map[i][0], y = map[i][1]
// Each column of 8 pixels should have the same angle in the cylinder
var columnNumber = Math.floor(i / 8)
// There're 32 columns in a full rotation. Radians = turns * 2Pi
var angle = columnNumber / 32 * 2 * Math.PI
map3D.push([Math.cos(angle), y, Math.sin(angle)])
}
return map3D
}
From here, you might need to make a few tweaks when you get it wired up. I’m going to leave those to you as an exercise, and I think you’ll be able to figure them out. If you struggle for more than an hour, post your issue here and let’s see if the community can help out. Some things you might encounter:
- The panels need to be stacked top-down instead of bottom-up.
- The zig-zag from left-to-right actually starts down-up instead of up-down as in your diagram.
- You don’t want to use map fill mode, you want to get the diameter of the cylinder accurate with respect to its height. Hint: a 32-LED circumference is a 5.1 LED radius, so multiply the Math.cos and Math.sin each by 5.1.