forked from viewit/KX-Bridge-Release
fix(web): match AMS slots by color globally, not position-first
This commit is contained in:
@@ -2926,29 +2926,85 @@ function openFilamentDialog(slots){
|
||||
var dr=ar[0]-br[0], dg=ar[1]-br[1], db=ar[2]-br[2];
|
||||
return (dr*dr + dg*dg + db*db);
|
||||
}
|
||||
var defaultSlotByPaint={};
|
||||
var usedDefaultSlot={};
|
||||
channels.forEach(function(gc,i){
|
||||
|
||||
// Globale, farboptimale Zuordnung Kanal -> Slot.
|
||||
// Anforderungen: 1) Material muss passen (harter Filter, wie bisher)
|
||||
// 2) Farbe so nah wie möglich
|
||||
// 3) Position spielt praktisch keine Rolle mehr
|
||||
// Ein rein gieriger Ansatz (Kanal für Kanal den "nächsten" Slot wählen)
|
||||
// kann bei knappen/mehrdeutigen Slots suboptimale Gesamtlösungen liefern
|
||||
// (z.B. Kanal A "verbraucht" den Slot, der eigentlich viel besser zu
|
||||
// Kanal B gepasst hätte). Da ein AMS in der Praxis nur wenige Slots hat
|
||||
// (üblich: bis zu 4), lohnt sich Brute-Force über alle möglichen
|
||||
// Zuordnungen mit Pruning - liefert garantiert das global beste Ergebnis,
|
||||
// ganz ohne einen vollen Hungarian-Algorithmus implementieren zu müssen.
|
||||
function _bestAssignment(slotsPerChannel){
|
||||
var n=slotsPerChannel.length;
|
||||
var assign=new Array(n).fill(-1);
|
||||
|
||||
// Sicherheitsnetz für unrealistisch viele Kanäle: gieriger Fallback
|
||||
// (kleinster Farbabstand zuerst bedient), um exponentielle Laufzeit zu
|
||||
// vermeiden. Greift in der Praxis nie, ein AMS hat max. wenige Slots.
|
||||
if(n>8){
|
||||
var used={};
|
||||
var order=slotsPerChannel.map(function(_,idx){return idx;}).sort(function(a,b){
|
||||
var da=slotsPerChannel[a].length?slotsPerChannel[a][0].dist:Infinity;
|
||||
var db=slotsPerChannel[b].length?slotsPerChannel[b][0].dist:Infinity;
|
||||
return da-db;
|
||||
});
|
||||
order.forEach(function(i){
|
||||
var cands=slotsPerChannel[i];
|
||||
if(!cands.length)return;
|
||||
var pick=cands.find(function(c){return !used[c.slot_index];})||cands[0];
|
||||
assign[i]=pick.slot_index;
|
||||
used[pick.slot_index]=true;
|
||||
});
|
||||
return assign;
|
||||
}
|
||||
|
||||
var bestCost=Infinity, bestAssign=assign.slice(), used={};
|
||||
(function backtrack(idx,cost){
|
||||
if(cost>=bestCost)return; // Pruning: kann eh nicht mehr besser werden
|
||||
if(idx===n){ bestCost=cost; bestAssign=assign.slice(); return; }
|
||||
var candidates=slotsPerChannel[idx];
|
||||
if(!candidates.length){
|
||||
assign[idx]=-1;
|
||||
backtrack(idx+1,cost);
|
||||
return;
|
||||
}
|
||||
var placedFree=false;
|
||||
for(var k=0;k<candidates.length;k++){
|
||||
var c=candidates[k];
|
||||
if(used[c.slot_index])continue;
|
||||
placedFree=true;
|
||||
used[c.slot_index]=true;
|
||||
assign[idx]=c.slot_index;
|
||||
backtrack(idx+1,cost+c.dist);
|
||||
used[c.slot_index]=false;
|
||||
}
|
||||
if(!placedFree){
|
||||
// keine freien kompatiblen Slots mehr -> Mehrfachbelegung des
|
||||
// farblich besten kompatiblen Slots zulassen (besser als leer)
|
||||
var best=candidates[0];
|
||||
assign[idx]=best.slot_index;
|
||||
backtrack(idx+1,cost+best.dist);
|
||||
}
|
||||
assign[idx]=-1;
|
||||
})(0,0);
|
||||
return bestAssign;
|
||||
}
|
||||
|
||||
var slotsPerChannel=channels.map(function(gc){
|
||||
var compatible=_amsSlots.filter(function(s){
|
||||
return _materialsCompatible(gc.material, s.material);
|
||||
});
|
||||
if(!compatible.length){
|
||||
defaultSlotByPaint[i]=-1;
|
||||
return;
|
||||
}
|
||||
|
||||
var ranked=compatible.slice().sort(function(a,b){
|
||||
var da=Math.abs((a.slot_index||0)-i), db=Math.abs((b.slot_index||0)-i);
|
||||
if(da!==db)return da-db;
|
||||
var ca=_colorDist(gc.color_hex, a.color_hex), cb=_colorDist(gc.color_hex, b.color_hex);
|
||||
if(ca!==cb)return ca-cb;
|
||||
return (a.slot_index||0)-(b.slot_index||0);
|
||||
});
|
||||
|
||||
var chosen=ranked.find(function(s){return !usedDefaultSlot[s.slot_index];}) || ranked[0];
|
||||
defaultSlotByPaint[i]=chosen?chosen.slot_index:-1;
|
||||
if(chosen) usedDefaultSlot[chosen.slot_index]=1;
|
||||
return compatible.map(function(s){
|
||||
return {slot_index:s.slot_index, dist:_colorDist(gc.color_hex, s.color_hex)};
|
||||
}).sort(function(a,b){ return a.dist-b.dist; });
|
||||
});
|
||||
var _assignResult=_bestAssignment(slotsPerChannel);
|
||||
var defaultSlotByPaint={};
|
||||
channels.forEach(function(gc,i){ defaultSlotByPaint[i]=_assignResult[i]; });
|
||||
|
||||
if(!_amsSlots.length){
|
||||
body.innerHTML='<p style="color:var(--txt2);font-size:13px;text-align:center;padding:16px 0">'+T.fd_no_slots_msg.replace('{br}','<br>')+'</p>';
|
||||
@@ -3402,4 +3458,4 @@ function loadPrinterTab(){
|
||||
}).catch(function(e){
|
||||
if(grid)grid.innerHTML='<div style="color:var(--err);font-size:13px;padding:20px">Fehler: '+e+'</div>';
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user