Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chromacorners #208

Open
wants to merge 53 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
796243e
random colors now being sampled from hsluv
mittimithai Apr 6, 2021
c4c8506
Random sampling from CIELUV now via colorspaces, fallback to RGB.
mittimithai Apr 6, 2021
abfba13
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 6, 2021
6a1ef8e
Initialized rand_color_hex to avoid typecheck errors
mittimithai Apr 6, 2021
dcc53d7
Trying to see if type declaration stop CI from complaining
mittimithai Apr 7, 2021
a6f2d2c
small change to not roll black so much
mittimithai Apr 11, 2021
89d79eb
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 11, 2021
a449b00
Added prettier to package.json/dev
mittimithai Apr 11, 2021
9181abe
Moved prettier back to where it was in package.json
mittimithai Apr 11, 2021
1f4a1e4
Small fix to rgb sampling
mittimithai Apr 11, 2021
d896144
Commented out console.logs
mittimithai Apr 11, 2021
ebca987
Fixed Luv bounds based on openCV page
mittimithai Apr 11, 2021
5e3b822
Fixed arguments to fill()
mittimithai Apr 11, 2021
220326c
Removed desc.d.ts, idiomized a line
mittimithai Apr 11, 2021
f3cbc6e
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 11, 2021
64f884c
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 12, 2021
81ddacd
small change in the way random Luvs are created
mittimithai Apr 12, 2021
6b80796
rgb should use inRange
mittimithai Apr 12, 2021
3d8cca9
import NumericInterval
mittimithai Apr 12, 2021
0ec6f20
Added JSDoc string to inInterval, max->supremum
mittimithai Apr 13, 2021
7515652
sup back to max, screws things up too much
mittimithai Apr 13, 2021
18ee0a9
more reverting sup -> max
mittimithai Apr 13, 2021
7da4669
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 17, 2021
7f1af36
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 20, 2021
de14c01
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai Apr 27, 2021
96e1a6a
Color rules working
mittimithai Apr 29, 2021
46aab95
Small type-related fixes
mittimithai Apr 29, 2021
4a58de6
prettied
mittimithai Apr 29, 2021
8a1f32e
Added hucontrast color rule
mittimithai Apr 30, 2021
4ee1264
added randgrey color rule
mittimithai Apr 30, 2021
46f0bfd
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai May 11, 2021
e1e19d1
Added Nina's color functions
mittimithai May 15, 2021
4b5bb9c
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai May 15, 2021
f5cd6b8
Fixed up nina's functions
mittimithai May 15, 2021
877fe7d
Forgot prettier
mittimithai May 15, 2021
cb68828
Small bug in color generation.
mittimithai May 16, 2021
a80f830
Merge branch 'main' of https://github.com/toolness/mystic-symbolic in…
mittimithai May 16, 2021
f733815
Small changes to colors, commented out old funcs.
mittimithai May 19, 2021
9b80370
fixes + commenting out function bodies
mittimithai May 19, 2021
58510df
gah, more commenting in/out
mittimithai May 19, 2021
f3d1f69
Better L value sampling, max L=80 to avoid lots of low chroma whites.
mittimithai May 19, 2021
e10e4e2
Just bumping up minium L to 10
mittimithai May 19, 2021
6d66ac0
Added random hue version of threevals
mittimithai Jun 28, 2021
f0bd3b7
Seemed to have to stage package-lock
mittimithai Jun 28, 2021
b0af2fb
Merge branch 'mysticsymbolic:main' into main
mittimithai Jun 28, 2021
4eb67cb
Merge branch 'main' of https://github.com/mittimithai/mystic-symbolic…
mittimithai Jun 28, 2021
fb4ac97
forgot prettier again, caught a few other files
mittimithai Jun 28, 2021
e07d4c8
more silly errors fixed
mittimithai Jun 28, 2021
2f044ca
added hichroma
mittimithai Jul 13, 2021
007f2f7
added chromatools
mittimithai Jul 13, 2021
0aa226e
Merge branch 'main' into chromacorners
mittimithai Jul 13, 2021
8de2f07
prettying
mittimithai Jul 13, 2021
4ac2050
chroma corners
mittimithai Aug 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 269 additions & 0 deletions lib/chromatools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
/*
Copyright (c) 2012-2021 Alexei Boronine
Copyright (c) 2016 Florian Dormont

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/

//Taken from hsluv haxe source transpiled to js: https://github.com/hsluv/hsluv/tree/master/haxe/src/hsluv

type Point = {
x: number;
y: number;
};

type Line = {
slope: number;
intercept: number;
};

type Angle = number;

type Intersection = {
lineIndex1: number;
lineIndex2: number;
intersectionPoint: Point;
intersectionPointAngle: Angle;
relativeAngle: Angle;
};

export type UVSliceGeometery = {
lines: Line[];
verticies: Point[];
angles: Angle[];
outerCircleRadius: number;
innerCircleRadius: number;
};

//XYZ2RGB
const m: number[][] = [
[3.240969941904521, -1.537383177570093, -0.498610760293],
[-0.96924363628087, 1.87596750150772, 0.041555057407175],
[0.055630079696993, -0.20397695888897, 1.056971514242878],
];

/*
//RGB2XYZ
const minv: number[][] = [
[0.41239079926595, 0.35758433938387, 0.18048078840183],
[0.21263900587151, 0.71516867876775, 0.072192315360733],
[0.019330818715591, 0.11919477979462, 0.95053215224966],
];


const refY = 1.0;
const refU = 0.19783000664283;
const refV = 0.46831999493879;
*/

const kappa = 903.2962962;
const epsilon = 0.0088564516;

function intersectLine(a: Line, b: Line): Point {
let x = (a.intercept - b.intercept) / (b.slope - a.slope);
let y = a.slope * x + a.intercept;
return { x: x, y: y };
}

function distanceFromOrigin(p: Point): number {
return Math.sqrt(Math.pow(p.x, 2) + Math.pow(p.y, 2));
}

function distanceLineFromOrigin(l: Line) {
return Math.abs(l.intercept) / Math.sqrt(Math.pow(l.slope, 2) + 1);
}

/*
function perpendicularThroughPoint(l: Line, p: Point) {
let slope = -1 / l.slope;
let intercept = p.y - slope * p.x;
return { slope: slope, intercept: intercept };
}
*/

function normalizeAngle(ang: Angle) {
let m = 2 * Math.PI;

//This seems like you don't need to add the m...but it is necessary
let nang = ((ang % m) + m) % m;
return nang;
}

function angleFromOrigin(p: Point) {
return Math.atan2(p.y, p.x);
}


function lengthOfRayUntilIntersect(theta: Angle, l: Line) {
return l.intercept / (Math.sin(theta) - l.slope * Math.cos(theta));
}


function getBounds(L: number): Line[] {
let result: Line[] = [];
let sub1 = Math.pow(L + 16, 3) / 1560896;
let sub2 = sub1 > epsilon ? sub1 : L / kappa;
for (let i = 0; i < 3; i++) {
let m1 = m[i][0];
let m2 = m[i][1];
let m3 = m[i][2];
let top1 = (284517 * m1 - 94839 * m3) * sub2;
let top2 = (838422 * m3 + 769860 * m2 + 731718 * m1) * L * sub2 - 0 * L;
let bottom = (632260 * m3 - 126452 * m2) * sub2;
result.push({ slope: top1 / bottom, intercept: top2 / bottom });
let top11 = (284517 * m1 - 94839 * m3) * sub2;
let top21 =
(838422 * m3 + 769860 * m2 + 731718 * m1) * L * sub2 - 769860 * L;
let bottom1 = (632260 * m3 - 126452 * m2) * sub2 + 126452;
result.push({ slope: top11 / bottom1, intercept: top21 / bottom1 });
}
return result;
}


export function maxSafeChromaForL(L): number {
let bounds = getBounds(L);
let min = Infinity;

for (let i = 0; i < bounds.length; i++) {
let bound = bounds[i];
let length = distanceLineFromOrigin(bound);
min = Math.min(min, length);
}
return min;
}


export function maxChromaForLH(L: number, H: number): number {
let hrad = (H / 360) * Math.PI * 2;
let bounds = getBounds(L);
let min = Infinity;

for (let i = 0; i < bounds.length; i++) {
let bound = bounds[i];
var length = lengthOfRayUntilIntersect(hrad, bound);
if (length >= 0) {
min = Math.min(min, length);
}
}
return min;
}

/*
function dotProduct(a, b) {
let sum = 0;
for (let i = 0; i < a.length; i++)
while (_g < _g1) {
sum += a[i] * b[i];
}
return sum;
}
*/

export function getUVSliceGeometery(L: number): UVSliceGeometery {
// Array of lines
let lines: Line[] = getBounds(L);
let numLines = lines.length;
let outerCircleRadius = 0.0;

// Find the line closest to origin
let closestLineIndex = -1;
let closestLineDistance = Infinity;

for (let i = 0; i < numLines; i++) {
let d = distanceLineFromOrigin(lines[i]);
if (closestLineDistance == null || d < closestLineDistance) {
closestLineDistance = d;
closestLineIndex = i;
}
}

// For finding starting angle
let closestLine: Line = lines[closestLineIndex];
let perpendicularLine: Line = {
slope: 0 - 1 / closestLine.slope,
intercept: 0.0,
};
let intersectionPoint: Point = intersectLine(closestLine, perpendicularLine);
let startingAngle: Angle = angleFromOrigin(intersectionPoint);

// Get all intersections
let intersections: Intersection[] = [];

for (let i1 = 0; i1 < numLines - 1; i1++) {
for (let i2 = i1 + 1; i2 < numLines; i2++) {
let intersectionPoint: Point = intersectLine(lines[i1], lines[i2]);
let intersectionPointAngle: Angle = angleFromOrigin(intersectionPoint);
let relativeAngle = intersectionPointAngle - startingAngle;
intersections.push({
lineIndex1: i1,
lineIndex2: i2,
intersectionPoint: intersectionPoint,
intersectionPointAngle: intersectionPointAngle,
relativeAngle: normalizeAngle(relativeAngle),
});
}
}

//sort wrt to relative angle
intersections.sort(function (a, b) {
if (a.relativeAngle > b.relativeAngle) {
return 1;
} else {
return -1;
}
});

let orderedLines = [];
let orderedVerticies = [];
let orderedAngles = [];

let nextLineIndex = null;
let currentIntersection = null;
let intersectionPointDistance = null;

let currentLineIndex = closestLineIndex;
let d = [];

//in angle order, find the first intersection that occurs on the closest line, then find the other line on that intersection
for (let i = 0; i < intersections.length; i++) {
currentIntersection = intersections[i];
nextLineIndex = null;
if (currentIntersection.lineIndex1 == currentLineIndex) {
nextLineIndex = currentIntersection.lineIndex2;
} else if (currentIntersection.lineIndex2 == currentLineIndex) {
nextLineIndex = currentIntersection.lineIndex1;
}
if (nextLineIndex != null) {
currentLineIndex = nextLineIndex;

d.push(currentLineIndex);
orderedLines.push(lines[nextLineIndex]);
orderedVerticies.push(currentIntersection.intersectionPoint);
orderedAngles.push(currentIntersection.intersectionPointAngle);

intersectionPointDistance = distanceFromOrigin(
currentIntersection.intersectionPoint
);
if (intersectionPointDistance > outerCircleRadius) {
outerCircleRadius = intersectionPointDistance;
}
}
}

return {
lines: orderedLines,
verticies: orderedVerticies,
angles: orderedAngles,
outerCircleRadius: outerCircleRadius,
innerCircleRadius: closestLineDistance,
};
}
Loading