Counting slots fixed one half of the problem; this fixes the other. A slot is now filled by a spool of the same material whose colour is close to what the slot asks for, one spool per slot, best matches assigned first. So four PLA slots in black, blue-grey, grey and white are not satisfied by four spools of white — only the white slot is. Closeness is redmean distance with a tolerance of 50, which treats genuinely near shades as the same colour while keeping #000000 and #161616 (about 66 apart) distinct. Slot colours arrive as #RRGGBB and #RRGGBBAA — the alpha channel is parsed off rather than making the colour unreadable. The model page now lists every slot: its colour, which spool fills it, and the nearest thing on the shelf when nothing does. Two things this fixes in code I wrote an hour ago: renderDetailPrintable still called a function the rewrite removed, so opening any model would have thrown; and the README claimed colours weren't matched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
4.2 KiB
JavaScript
86 lines
4.2 KiB
JavaScript
const test = require('node:test');
|
||
const assert = require('node:assert/strict');
|
||
const filaments = require('../lib/filaments');
|
||
|
||
const spool = (material, hex, name) => ({ id: hex, material, colour_hex: hex, colour: name || hex, remaining_g: 500 });
|
||
|
||
// The model that started this: four PLA slots, one spool of Jade White.
|
||
const pooh = [
|
||
{ type: 'PLA', colour: '#000000' },
|
||
{ type: 'PLA', colour: '#586579' },
|
||
{ type: 'PLA', colour: '#8E9089' },
|
||
{ type: 'PLA', colour: '#FFFFFF' },
|
||
];
|
||
|
||
test('a four-colour print needs those colours, not four spools of anything', () => {
|
||
const shelf = [spool('PLA', '#ffffff', 'Jade White')];
|
||
const slots = filaments.assignSpools(pooh, shelf);
|
||
assert.deepEqual(slots.map((s) => s.filled), [false, false, false, true]);
|
||
assert.equal(slots[3].by, 'Jade White');
|
||
assert.equal(filaments.isPrintable(pooh, shelf), false);
|
||
assert.equal(filaments.shortfall(pooh, shelf).length, 3);
|
||
|
||
// Four white spools still can't print it: the other three colours are missing.
|
||
const fourWhite = ['a', 'b', 'c', 'd'].map((k) => ({ ...spool('PLA', '#ffffff', 'Jade White'), id: k }));
|
||
assert.equal(filaments.isPrintable(pooh, fourWhite), false);
|
||
});
|
||
|
||
test('with every colour on the shelf it prints', () => {
|
||
const shelf = [spool('PLA', '#000000', 'Black'), spool('PLA', '#586579', 'Blue Grey'),
|
||
spool('PLA', '#8E9089', 'Grey'), spool('PLA', '#ffffff', 'Jade White')];
|
||
assert.equal(filaments.isPrintable(pooh, shelf), true);
|
||
assert.deepEqual(filaments.assignSpools(pooh, shelf).map((s) => s.by),
|
||
['Black', 'Blue Grey', 'Grey', 'Jade White']);
|
||
});
|
||
|
||
test('one spool cannot fill two slots of the same colour', () => {
|
||
const twoBlack = [{ type: 'PLA', colour: '#000000' }, { type: 'PLA', colour: '#000000' }];
|
||
assert.equal(filaments.isPrintable(twoBlack, [spool('PLA', '#000000', 'Black')]), false);
|
||
assert.equal(filaments.isPrintable(twoBlack,
|
||
[spool('PLA', '#000000', 'Black'), { ...spool('PLA', '#000000', 'Black 2'), id: 'b2' }]), true);
|
||
});
|
||
|
||
test('8-digit hex with alpha parses as its colour', () => {
|
||
assert.deepEqual(filaments.rgb('#FFFFFFFF'), { r: 255, g: 255, b: 255 });
|
||
assert.deepEqual(filaments.rgb('#586579'), { r: 88, g: 101, b: 121 });
|
||
assert.equal(filaments.rgb('not a colour'), null);
|
||
// A slot written with alpha still matches a plain spool of that colour.
|
||
assert.equal(filaments.isPrintable([{ type: 'PLA', colour: '#FFFFFFFF' }],
|
||
[spool('PLA', '#ffffff', 'Jade White')]), true);
|
||
});
|
||
|
||
test('near shades count, but near-black is not black', () => {
|
||
const nearWhite = [{ type: 'PLA', colour: '#FDFDFD' }];
|
||
assert.equal(filaments.isPrintable(nearWhite, [spool('PLA', '#ffffff', 'Jade White')]), true);
|
||
// #161616 sits about 66 away from black, beyond the tolerance of 50.
|
||
assert.ok(filaments.colourDistance('#000000', '#161616') > filaments.COLOUR_TOLERANCE);
|
||
assert.equal(filaments.isPrintable([{ type: 'PLA', colour: '#161616' }],
|
||
[spool('PLA', '#000000', 'Black')]), false);
|
||
});
|
||
|
||
test('the nearest spool is named when a slot can’t be filled', () => {
|
||
const [slot] = filaments.assignSpools([{ type: 'PLA', colour: '#000000' }],
|
||
[spool('PLA', '#ffffff', 'Jade White')]);
|
||
assert.equal(slot.filled, false);
|
||
assert.equal(slot.nearest.name, 'Jade White');
|
||
assert.ok(slot.nearest.distance > 0);
|
||
});
|
||
|
||
test('material still matters, and a slot with no colour takes any spool of it', () => {
|
||
assert.equal(filaments.isPrintable([{ type: 'PETG', colour: '#ffffff' }],
|
||
[spool('PLA', '#ffffff', 'Jade White')]), false);
|
||
assert.equal(filaments.isPrintable([{ type: 'PLA', colour: null }],
|
||
[spool('PLA', '#123456', 'Anything')]), true);
|
||
});
|
||
|
||
test('an empty spool doesn’t count, but an unweighed one does', () => {
|
||
const one = [{ type: 'PLA', colour: '#ffffff' }];
|
||
assert.equal(filaments.isPrintable(one, [{ ...spool('PLA', '#ffffff', 'Jade White'), remaining_g: 0 }]), false);
|
||
assert.equal(filaments.isPrintable(one, [{ ...spool('PLA', '#ffffff', 'Jade White'), remaining_g: null }]), true);
|
||
});
|
||
|
||
test('a model we know nothing about is not claimed to be printable', () => {
|
||
assert.equal(filaments.isPrintable(null, [spool('PLA', '#ffffff')]), false);
|
||
assert.equal(filaments.isPrintable([], [spool('PLA', '#ffffff')]), false);
|
||
assert.deepEqual(filaments.assignSpools(null, []), []);
|
||
});
|