|
@@ -27,7 +27,10 @@ const showCustomControls = () => getHideableControlNodes()
|
|
|
|
|
|
// Vector Math
|
|
|
const vectorDot = (u, v) => u.map((x, i) => x * v[i]).reduce((x, y) => x + y);
|
|
|
-const vectorMag = v => Math.sqrt(vectorDot(v, v));
|
|
|
+const vectorSqMag = v => vectorDot(v, v);
|
|
|
+const vectorMag = v => Math.sqrt(vectorSqMag(v));
|
|
|
+const vectorSqDist = (u, v) => vectorSqMag(u.map((x, i) => x - v[i]));
|
|
|
+const vectorDist = (u, v) => Math.sqrt(vectorSqDist(u, v));
|
|
|
const vectorNorm = v => { const n = vectorMag(v); return [ n, v.map(c => c / n) ]; };
|
|
|
|
|
|
// Angle Math
|
|
@@ -105,6 +108,10 @@ const scoringMetrics = [
|
|
|
-vectorDot(yJABHat, state.targetColor.qJABHat),
|
|
|
-vectorDot(yRGBHat, state.targetColor.qRGBHat),
|
|
|
],
|
|
|
+ ({ yJAB, yRGB }) => [
|
|
|
+ vectorSqDist(state.targetColor.qJAB, yJAB),
|
|
|
+ vectorSqDist(state.targetColor.qRGB, yRGB),
|
|
|
+ ],
|
|
|
({ yHueAngleJAB, yHueAngleRGB }) => [
|
|
|
angleDiff(state.targetColor.qHueAngleJAB, yHueAngleJAB),
|
|
|
angleDiff(state.targetColor.qHueAngleRGB, yHueAngleRGB),
|
|
@@ -122,7 +129,7 @@ const scoringMetrics = [
|
|
|
];
|
|
|
|
|
|
const calcDisplayMetrics = ({
|
|
|
- xJAB, xRGB, yJABHat, yJABNorm, yRGBHat, yRGBNorm, yHueAngleJAB, yHueAngleRGB,
|
|
|
+ xJAB, xRGB, yJAB, yRGB, yJABHat, yJABNorm, yRGBHat, yRGBNorm, yHueAngleJAB, yHueAngleRGB,
|
|
|
}) => {
|
|
|
// TODO - case on state.metric to avoid recalculation of subterms?
|
|
|
|
|
@@ -137,6 +144,8 @@ const calcDisplayMetrics = ({
|
|
|
stdDevJAB: Math.sqrt(xJAB - 2 * yTermJAB + state.targetColor.qJABNormSq),
|
|
|
angleJAB: rad2deg * Math.acos(cosAngleJAB),
|
|
|
angleRGB: rad2deg * Math.acos(cosAngleRGB),
|
|
|
+ meanDistJAB: vectorDist(state.targetColor.qJAB, yJAB),
|
|
|
+ meanDistRGB: vectorDist(state.targetColor.qRGB, yRGB),
|
|
|
hueAngleJAB: angleDiff(state.targetColor.qHueAngleJAB, yHueAngleJAB),
|
|
|
hueAngleRGB: angleDiff(state.targetColor.qHueAngleRGB, yHueAngleRGB),
|
|
|
};
|
|
@@ -157,12 +166,14 @@ const resultDefinition = TeXZilla.toMathML(String.raw`
|
|
|
\left(
|
|
|
\text{RMS}_P\left(q\right),
|
|
|
\angle \left(\vec{q}, \vec{Y}\left(P\right)\right),
|
|
|
+ \left|\left| \vec{q} - \vec{Y}\left(P\right) \right|\right|,
|
|
|
\Delta{H}
|
|
|
\right)
|
|
|
`);
|
|
|
const metricText = [
|
|
|
String.raw`\text{RMS}_{P}\left(q\right) ~ \arg\min_{P}\left[X\left(P\right) - 2\vec{q}\cdot \vec{Y}\left(P\right)\right]`,
|
|
|
String.raw`\angle \left(\vec{q}, \vec{Y}\left(P\right)\right) ~ \arg\max_{P}\left[\cos\left(\angle \left(\vec{q}, \vec{Y}\left(P\right)\right)\right)\right]`,
|
|
|
+ String.raw`\left|\left| \vec{q} - \vec{Y}\left(P\right) \right|\right| ~ \arg\min_{P}\left[\left|\left| \vec{q} - \vec{Y}\left(P\right) \right|\right|^2\right]`,
|
|
|
String.raw`\Delta{H} = \angle \left(\vec{q}_{\perp}, \vec{Y}_{\perp}\left(P\right) \right), \vec{v}_{\perp} = \text{oproj}_{\left\{\vec{J}, \vec{L}\right\}}{\vec{v}}`,
|
|
|
].map(s => TeXZilla.toMathML(s));
|
|
|
|
|
@@ -225,6 +236,7 @@ const renderPokemon = (data, classes = {}) => {
|
|
|
const {
|
|
|
stdDevJAB = 0, stdDevRGB = 0,
|
|
|
angleJAB = 0, angleRGB = 0,
|
|
|
+ meanDistJAB = 0, meanDistRGB,
|
|
|
hueAngleJAB = 0, hueAngleRGB = 0,
|
|
|
} = displayMetrics;
|
|
|
|
|
@@ -248,10 +260,10 @@ const renderPokemon = (data, classes = {}) => {
|
|
|
</div>
|
|
|
<div class="pokemon_tile-score_column ${resultsClass}">
|
|
|
<span class="pokemon_tile-no_flex ${jabClass}">
|
|
|
- (${stdDevJAB.toFixed(2)}, ${angleJAB.toFixed(2)}°, ${hueAngleJAB.toFixed(2)}°)
|
|
|
+ (${stdDevJAB.toFixed(2)}, ${angleJAB.toFixed(2)}°, ${meanDistJAB.toFixed(2)}, ${hueAngleJAB.toFixed(2)}°)
|
|
|
</span>
|
|
|
<span class="pokemon_tile-no_flex ${rgbClass}">
|
|
|
- (${stdDevRGB.toFixed(2)}, ${angleRGB.toFixed(2)}°, ${hueAngleRGB.toFixed(2)}°)
|
|
|
+ (${stdDevRGB.toFixed(2)}, ${angleRGB.toFixed(2)}°, ${meanDistRGB.toFixed(2)}, ${hueAngleRGB.toFixed(2)}°)
|
|
|
</span>
|
|
|
</div>
|
|
|
<div class="pokemon_tile-hex_column">
|
|
@@ -358,7 +370,7 @@ const onMetricChanged = skipScore => {
|
|
|
return;
|
|
|
}
|
|
|
state.metric = metric;
|
|
|
- if (state.metric === 3) { // Custom
|
|
|
+ if (state.metric === 4) { // Custom
|
|
|
showCustomControls();
|
|
|
onCustomControlsChanged(skipScore); // triggers rescore
|
|
|
} else {
|