Skip to content

Commit

Permalink
Preview LED text selector (index, x, y, angle, radius) for troublesho…
Browse files Browse the repository at this point in the history
…oting problematic layouts.

Add layout LED index gap detection.
Add error for led and index count mismatch.
Show and log all errors, not just the first.
Better render error, add current LED info.
Log index passed to ColorFromPalette to console.
Found coordinate byte values.
  • Loading branch information
jasoncoon committed Sep 22, 2023
1 parent 886e770 commit 67561b6
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 26 deletions.
12 changes: 11 additions & 1 deletion index.htm
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ <h6 class="mb-2 text-muted">Choose one of the tabs below and paste in your input
<div class="text-muted">
Paste an LED layout copied from
<a href="https://sheets.google.com" target="_blank" rel="noopener noreferrer">Google Sheets</a>
or other spreadsheet in tab-delimited text format, with a unique LED index in each cell. LED indexes should start at zero. Cells without an LED should be empty.
or other spreadsheet in tab-delimited text format, with a unique LED index in each cell. LED indices should start at zero. Cells without an LED should be empty.
</div>
<textarea class="form-control" id="textAreaLayout" rows="7" style="white-space: pre; overflow-wrap: normal; overflow-x: auto;">
0 1 2 3 4 5 6 7 8 9 10 11 12 13
Expand Down Expand Up @@ -546,6 +546,16 @@ <h2 class="accordion-header" id="headingPreview">
<i id="iconShowPreviewNumbers" class="bi bi-square"></i>
Numbers</label
>
<div class="input-group" title="LED Number Text">
<div class="input-group-text">Text</div>
<select id="selectPreviewText" class="form-control" style="width: 5rem">
<option>Index</option>
<option>X</option>
<option>Y</option>
<option>Angle</option>
<option>Radius</option>
</select>
</div>
<div class="input-group" title="LED Numbers Font Size">
<div class="input-group-text">Size</div>
<input id="inputPreviewFontSize" class="form-control" type="number" step="0.25" min="0.25" value="10" style="width: 5rem" />
Expand Down
73 changes: 57 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const inputPreviewFontSize = document.getElementById("inputPreviewFontSize");
const inputPreviewSpeed = document.getElementById("inputPreviewSpeed");

const selectPalette = document.getElementById("selectPalette");
const selectPattern = document.getElementById("selectPattern");
const selectPreviewText = document.getElementById("selectPreviewText");

const textAreaCoordinates = document.getElementById("textAreaCoordinates");
const textAreaLayout = document.getElementById("textAreaLayout");
Expand All @@ -37,14 +37,15 @@ const textAreaPixelblaze = document.getElementById("textAreaPixelblaze");
const renderError = document.getElementById("renderError");

// define some global variables (working on eliminating these)
let width, height, rows, leds, maxX, maxY, minX, minY, coordsX, coordsY, angles, radii;
let width, height, rows, leds, maxIndex, maxX, maxY, minIndex, minX, minY, coordsX, coordsY, angles, radii, duplicateIndices, gaps;

let offset = 0;
let offsetIncrement = 1.0;

let running = true;
let showPreviewNumbers = false;
let showPreviewLEDs = true;
let previewNumberSource = 'index';

let renderFunction = undefined;

Expand Down Expand Up @@ -253,6 +254,26 @@ function onShowPreviewNumbersChange() {
if (!running) window.requestAnimationFrame(render);
}

function onPreviewTextChange() {
switch(selectPreviewText.value) {
case "Index":
previewNumberSource = 'index';
break;
case "X":
previewNumberSource = 'x256';
break;
case "Y":
previewNumberSource = 'y256';
break;
case "Angle":
previewNumberSource = 'angle256';
break;
case "Radius":
previewNumberSource = 'radius256';
break;
}
}

function onTextLayoutChange() {
parseLayout();
generateCode();
Expand Down Expand Up @@ -317,6 +338,7 @@ function addEventHandlers() {

document.getElementById("checkboxShowPreviewLEDs").onchange = onShowPreviewLEDsChange;
document.getElementById("checkboxShowPreviewNumbers").onchange = onShowPreviewNumbersChange;
document.getElementById("selectPreviewText").onchange = onPreviewTextChange;

document.getElementById("form").onsubmit = onFormSubmit;

Expand All @@ -339,9 +361,16 @@ function configureCanvas2dContext() {
}

function ColorFromPalette(palette, index, brightness = 255) {
while (index > 255) index -= 256;
while (index < 0) index += 256;
const imageData = contextSelectedPalette.getImageData(index, 0, canvasSelectedPalette.width, canvasSelectedPalette.height);
let fixedIndex = index;
while (fixedIndex > 255) fixedIndex -= 256;
while (fixedIndex < 0) fixedIndex += 256;
let imageData;
try {
imageData = contextSelectedPalette.getImageData(fixedIndex, 0, canvasSelectedPalette.width, canvasSelectedPalette.height);
} catch(error) {
console.error(`Error getting color from palette. index: ${index}, fixedIndex: ${fixedIndex}`, error);
throw error;
}
const data = imageData.data;

while (brightness > 255) brightness -= 256;
Expand Down Expand Up @@ -407,7 +436,7 @@ function generateCode() {
const centerX = inputCenterX.value;
const centerY = inputCenterY.value;

const results = generateFastLedMapCode({ centerX, centerY, leds, maxX, maxY, minX, minY });
const results = generateFastLedMapCode({ centerX, centerY, leds, maxX, maxY, minX, minY, minIndex, maxIndex });

// destructure the results into our global variables
({ coordsX, coordsY, angles, radii } = results);
Expand Down Expand Up @@ -450,14 +479,26 @@ function parseLayout(value) {
if (!value) value = textAreaLayout.value;
const results = parseLayoutText(value);

if (results.minIndex !== 0) {
document.getElementById('layoutError').innerText = `Layout should start at 0 instead of ${results.minIndex}`;
} else if (results.duplicateIndices.length > 0) {
document.getElementById('layoutError').innerText = `Duplicate indices found: ${results.duplicateIndices.join(', ')}`;
// destructure the results into our global variables
({ height, leds, maxX, maxY, minX, minY, rows, width, minIndex, maxIndex, duplicateIndices, gaps } = results);

let errors = [];

if (leds.length !== maxIndex + 1) {
errors.push(`Layout has ${leds.length} LEDs but only ${maxIndex + 1} unique LED indices.`);
}
if (minIndex !== 0) {
errors.push(`Layout should start at 0 instead of ${minIndex}.`);
}
if (duplicateIndices.length > 0) {
errors.push(`Duplicate indices found: ${duplicateIndices.join(', ')}.`);
}
if (gaps.length > 0) {
errors.push(`Gaps found at indices: ${gaps.join(', ')}.`);
}

// destructure the results into our global variables
({ height, leds, maxX, maxY, minX, minY, rows, width } = results);
errors.forEach(error => console.error(error));
document.getElementById('layoutError').innerHTML = errors.join('<br />');

document.getElementById("codeParsedLayout").innerText = JSON.stringify(rows);

Expand Down Expand Up @@ -538,10 +579,10 @@ function parseQueryString() {
}
}

function handleRenderFunctionError(error) {
function handleRenderFunctionError(error, led) {
renderFunction = undefined;
console.error({ error });
renderError.innerText = `Error: ${error.message}.`;
renderError.innerText = `Error: ${error.message}, LED: ${JSON.stringify(led)}.`;
}

function render() {
Expand Down Expand Up @@ -580,7 +621,7 @@ function render() {
try {
fillStyle = renderFunction(angles, beat8, beatsin8, CHSV, ColorFromPalette, coordsX, coordsY, cos8, CRGB, currentPalette, i, offset, radii, sin8, speed);
} catch (error) {
handleRenderFunctionError(error);
handleRenderFunctionError(error, led);
return;
}

Expand All @@ -602,7 +643,7 @@ function render() {

if (showPreviewNumbers) {
context.fillStyle = !showPreviewLEDs ? fillStyle : "white";
context.fillText(i, x + ledWidth / 2, y + ledHeight / 2);
context.fillText(led[previewNumberSource].toFixed(0), x + ledWidth / 2, y + ledHeight / 2);
}
}

Expand Down
20 changes: 14 additions & 6 deletions js/fastled.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function CRGB(r, g, b) {
}

export function generateFastLedMapCode(args) {
const { centerX, centerY, leds, maxX, maxY, minX, minY } = args;
const { centerX, centerY, leds, maxX, maxY, minX, minY, minIndex, maxIndex } = args;

let minX256, minY256, minAngle, minAngle256, minRadius, minRadius256;
let maxX256, maxY256, maxAngle, maxAngle256, maxRadius, maxRadius256;
Expand Down Expand Up @@ -105,17 +105,17 @@ export function generateFastLedMapCode(args) {
}

for (const led of leds) {
const { x, y, angle, radius } = led;
const { index, x, y, angle, radius } = led;

let x256 = mapNumber(x, minX, maxX, 0, 255);
let y256 = mapNumber(y, minY, maxY, 0, 255);
let angle256 = mapNumber(angle, 0, 360, 0, 255);
let radius256 = mapNumber(radius, 0, maxRadius, 0, 255);

led.x256 = x256;
led.y256 = y256;
led.angle256 = angle256;
led.radius256 = radius256;
led.x256 = Math.round(x256);
led.y256 = Math.round(y256);
led.angle256 = Math.round(angle256);
led.radius256 = Math.round(radius256);

if (x256 < minX256) minX256 = x256;
if (x256 > maxX256) maxX256 = x256;
Expand Down Expand Up @@ -158,6 +158,12 @@ export function generateFastLedMapCode(args) {
].join("\n");

const stats = `LEDs: ${leds.length}
coordsX length: ${coordsX.length}
coordsY length: ${coordsY.length}
angles length: ${angles.length}
radii length: ${radii.length}
minIndex: ${minIndex}
maxIndex: ${maxIndex}
minX: ${minX}
maxX: ${maxX}
minY: ${minY}
Expand All @@ -175,6 +181,8 @@ maxAngle256: ${maxAngle256.toFixed(0)}
minRadius256: ${minRadius256.toFixed(0)}
maxRadius256: ${maxRadius256.toFixed(0)}`;

// leds: ${JSON.stringify(leds, null, 2)}

return {
stats,
fastLedCode,
Expand Down
21 changes: 18 additions & 3 deletions js/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export function parseLayoutText(text) {

const leds = [];

let minX, minY, maxX, maxY, width, height, minIndex;
let minX, minY, maxX, maxY, width, height, minIndex, maxIndex;

const duplicateIndices = [];

minX = minY = minIndex = 1000000;
maxX = maxY = -1000000;
maxX = maxY = maxIndex = -1000000;

for (let y = 0; y < rows.length; y++) {
const row = rows[y];
Expand All @@ -34,7 +34,8 @@ export function parseLayoutText(text) {
if (y < minY) minY = y;
if (y > maxY) maxY = y;

if (index < minIndex) minIndex = index;
minIndex = Math.min(minIndex, index);
maxIndex = Math.max(maxIndex, index);

if (leds.some(l => l.index === index)) {
duplicateIndices.push(index);
Expand All @@ -51,6 +52,18 @@ export function parseLayoutText(text) {
width = maxX - minX + 1;
height = maxY - minY + 1;

let previousIndex = -1;
const gaps = [];
const sorted = [...leds].sort((a, b) => a.index - b.index);

for (const led of sorted) {
const index = led.index;
if (index - 1 !== previousIndex && !duplicateIndices.includes(index)) {
gaps.push(index);
}
previousIndex = index;
}

return {
height,
leds,
Expand All @@ -61,6 +74,8 @@ export function parseLayoutText(text) {
rows,
width,
minIndex,
maxIndex,
duplicateIndices,
gaps
};
}

0 comments on commit 67561b6

Please sign in to comment.