convert RGB color to XY - javascript

I have using RUCKUS API for changing color of lamp and I need to convert color from RGB to XY to call an API.
I have tried this code:
1) Get the RGB values from your color object and convert them to be between 0 and 1
function rgb_to_cie(red, green, blue)
{
//Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device
var red = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92);
var green = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92);
var blue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92);
//RGB values to XYZ using the Wide RGB D65 conversion formula
var X = red * 0.664511 + green * 0.154324 + blue * 0.162028;
var Y = red * 0.283881 + green * 0.668433 + blue * 0.047685;
var Z = red * 0.000088 + green * 0.072310 + blue * 0.986039;
//Calculate the xy values from the XYZ values
var x = (X / (X + Y + Z)).toFixed(4);
var y = (Y / (X + Y + Z)).toFixed(4);
if (isNaN(x))
x = 0;
if (isNaN(y))
y = 0;
return [x, y];
}
but it didn't provide a proper solution.
SO if i pass r:182 g: 255 B: 65 as this then I got x as 22932 and y as 35249 (AS PER DOC OF API.)
How can I do that?

I got the solution and here I attached the answer if you're looing for,
let red = 100
let green = 100
let blue = 100
let redC = (red / 255)
let greenC = (green / 255)
let blueC = (blue / 255)
console.log(redC, greenC , blueC)
let redN = (redC > 0.04045) ? Math.pow((redC + 0.055) / (1.0 + 0.055), 2.4): (redC / 12.92)
let greenN = (greenC > 0.04045) ? Math.pow((greenC + 0.055) / (1.0 + 0.055), 2.4) : (greenC / 12.92)
let blueN = (blueC > 0.04045) ? Math.pow((blueC + 0.055) / (1.0 + 0.055), 2.4) : (blueC / 12.92)
console.log(redN, greenN, blueN)
let X = redN * 0.664511 + greenN * 0.154324 + blueN * 0.162028;
let Y = redN * 0.283881 + greenN * 0.668433 + blueN * 0.047685;
let Z = redN * 0.000088 + greenN * 0.072310 + blueN * 0.986039;
console.log(X, Y, Z)
let x = X / (X + Y + Z);
let y = Y / (X + Y + Z);
X = x * 65536
Y = y * 65536

There are few errors:
First: You are using the normal transformation formula, where red, green, and blue should be in the range 0.0 to 1.0. So you may need to divide the values by 255.
Second: you are applying gamma. To transform to X,Y,Z you need linear values. Normally we have gamma corrected RGB (e.g. pixel values). So you are overcorrecting. Instead, you should apply the inverse of gamma, so that you will get the linear R,G,B, so that you can apply linear transformation to get X,Y,Z.
Third: you are returning x,y and not X,Y, as your question (and comment). On the other hand, are you sure you need X,Y? Often x,y are used for "colour". I would expect a x,y + Y (or some brightness parameter).
Possibly you should scale back the values. As you see, often the range is 0 to 1, or 0 to 100 (in past), or 0 to 255, 0 to 65535. There is no standard: these are just numbers without a unit. [Contrary to computer screens, a Phillips Hue should know what it is the maximum brightness, but .. this is an exception].

Related

Convert equations of lines solution into reusable javascript function with unknown x and y

So I have a solution to solving for location (point of intersection) of someone based on landmark angles (312.27) and (19.65) degrees and grid coordinates (1,5) and (9,7) of those landmarks. So the issue I'm having is how can I convert these formulas into something that I can dynamically plugin angles and grid coordinates and return the x and y intersection point for location?
Equations of the Lines based on land marks:
P1: y = cot(312.27)*x + 5 - cot(312.27)*1 ⇒ y = -0.91x + 5.91
P2: y = cot(19.65)*x + 7 - cot(19.65) * 9 ⇒ y = 2.80x - 18.21
solve point of intersection:
P1 = P2
-0.91x + 5.91 = 2.80x - 18.21
5.91 + 18.21 = 2.80x + 0.91x
24.12 = 3.71x
6.5 = x
y = -0.91(6.5) + 5.91
y = 0
Your position is (6.5,0).
So I'm looking at creating a function like:
function getLocation(angle1, angle2, coord1, coord2){}
but I just am having trouble trying to figure out how I can convert this solution into something that would output x and y. As I would have to pass around x or y which is unknown.
Any ideas would be appreciated.
note: angles are converted to radians.
You need to solve the system of equations in terms of the angles and the x,y coordinates:
// let phi1 be the first angle and phi2 be the second angle thus
// let P1 be the first point and P2 be the second point
y = x * cot(phi1) + P1.y - P1.x * cot(phi1)
Similarly
y = x * cot(phi2) + P2.y - P2.x * cot(phi2)
Equating both sides:
x * cot(phi1) + P1.y - P1.x * cot(phi1) = x * cot(phi2) + P2.y - P2.x * cot(phi2)
Solving for x
x * (cot(phi1) - cot(phi2)) = P2.y - P2.x * cot(phi2) - P1.y + P1.x * cot(phi1)
Thus:
x = (P2.y - P2.x * cot(phi2) - P1.y + P1.x * cot(phi1)) / (cot(phi1) - cot(phi2))
Once you get x you can plug x in any of the equations for y:
y = x * cot(phi1) + P1.y - P1.x * cot(phi1)
So to get x and y:
function getLocation(angle1, angle2, coord1, coord2) {
let num = coord2.y - coord2.x * cot(angle2) - coord1.y + coord1.x * cot(angle1)
let den = cot(angle1) - cot(angle2)
let x = num / den
let y = x * cot(angle1) + P1.y - P1.x * cot(angle1)
// do something awesome with x and y
}

With HTML5 canvas, how to calculate the final point coordinates with an offset?

On a HTML5 canvas object, I have to subtract a distance from a destination point, to give the final destination on the same line.
So, first I have calculated the distance between the source and target points, with the Pythagorean theorem, but my memories of Thales's theorem are too faulty to find the final point (on same line), with the right x and y attributes.
function getDistance (from, to){
return Math.hypot(to.x - from.x, to.y - from.y);
}
function getFinalTo (from, to, distanceToSubstract){
//with Pythagore we obtain the distance between the 2 points
var originalDistance = getDistance(from, to);
var finalDistance = originalDistance - distanceToSubstract;
//Now, I was thinking about Thales but all my tries are wrong
//Here some of ones, I need to get finalTo properties to draw an arrow to a node without
var finalTo = new Object;
finalTo.x = ((1 - finalDistance) * from.x) + (finalDistance * to.x);
finalTo.y = ((1 - finalDistance) * from.y) + (finalDistance * to.y);
return finalTo;
}
Indeed, the arrowhead be hidden by the round node that can be about 100 pixels of radius, so I try to get the final point.
Thanks a lot.
Regards,
Will depend on the line cap. For "butt" there is no change, for "round" and "square" you the line extends by half the width at each end
The following function shortens the line to fit depending on the line cap.
drawLine(x1,y1,x2,y2){
// get vector from start to end
var x = x2-x1;
var y = y2-y1;
// get length
const len = Math.hypot(x,y) * 2; // *2 because we want half the width
// normalise vector
x /= len;
y /= len;
if(ctx.lineCap !== "butt"){
// shorten both ends to fit the length
const lw = ctx.lineWidth;
x1 += x * lw;
y1 += y * lw;
x2 -= x * lw;
y2 -= y * lw;
}
ctx.beginPath()
ctx.lineTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
For miter joins the following answer will help https://stackoverflow.com/a/41184052/3877726
You can use simple proportion by distance ratio:
(I did not account for round cap)
ratio = finalDistance / originalDistance
finalTo.x = from.x + (to.x - from.x) * ratio;
finalTo.y = from.y + (to.y - from.y) * ratio;
Your approach was attempt to use linear interpolation, but you erroneously mixed distances (in pixels, meters etc) with ratios (dimensionless - is this term right?)
ratio = finalDistance / originalDistance
finalTo.x = ((1 - ratio) * from.x) + (ratio * to.x);
finalTo.y = ((1 - ratio) * from.y) + (ratio * to.y);
Note that both approaches is really the same formula.

How can we convert CMYK to RGB in illustrator script?

I fetch cmyk value for color and convert it into RGB and this RGB color is displayed in an html extension. But Color picker shows different values for RGB color due to which we get difference in color shades.i use normal java script method to convert CMYK to RGB.
Following formula that i used to convert CMYK to RGB--
CMYK to CMY
C = 1 - ( R / 255 )
M = 1 - ( G / 255 )
Y = 1 - ( B / 255 )
and then CMY TO RGB
R = ( 1 - C ) * 255
G = ( 1 - M ) * 255
B = ( 1 - Y ) * 255
Color picker shows different color as calculated from normal functions.
For eg : Color is Red.
In general
RGB : 255,0,0
CMYK : 0%,100%,100%,0%
HEXCODE : #FF0000
but in illustrator on double click of color picker it shows as
RGB : 237,28,36
CMYK : 0%,100%,100%,0%
HEXCODE : #ED1C24
So, is there any method or formula which can get the same values as calculated from the color picker .
Please Help ,thanks in advance.
please find attached image link for reference.
http://screencast.com/t/sYa1Y301Qa2
In Illustrator scripting you will find use in the app.convertSampleColor() function.
This function takes in the source and destination space names as well as an array of color values and returns an illustrator-accurate converted color array in the destination space.
CMYK to RGB conversion:
The R,G,B values are given in the range of 0-255.
The red (R) color is calculated from the cyan (C) and black (K) colors:
R = 255 × (1-C) × (1-K)
The green color (G) is calculated from the magenta (M) and black (K) colors:
G = 255 × (1-M) × (1-K)
The blue color (B) is calculated from the yellow (Y) and black (K) colors:
B = 255 × (1-Y) × (1-K)
There is no simple or a general conversion formula for RGB to CMYK. Basically, RGB is about present of optical color, while CMYK is about present of ink color. When you increase R, G and B you get brighter color, while in general CMYK acts opposite. I think these two articles can help you understand them in depth: Adobe RGB and Color space
The problem is that if you want to have exact values as softwares like illustrator or photoshop, you need to use ICC profile which is not accessible inside javascript (see this question: Is there any client-side technology able to convert sRGB to CMYK through an ICC color profile?).
However there are some mathematical conversions like just you did, or this python version, which converts the CMYK to CMY then to RGB (they are not standard ICC colors):
C = C * (1.0 - K) + K
M = M * (1.0 - K) + K
Y = Y * (1.0 - K) + K
R = 255 * (1.0 - C)
G = 255 * (1.0 - M)
B = 255 * (1.0 - Y)
PLEASE EXCUSE ME IN MY BAD ENGLISH !!
I THINK THAT I FIGURED IT OUT
THE PROBLEM IS THAT CMYK CYAN RETURNS TO LIGHT-CYAN IN RGB
AND ALSO CMYK PINK RETURNS TO REAL-BLUE IN RGB
SO I ADDED SOME VALUES :
IF CYAN > MAGENTA .. WE ADD 25% OF CYAN VALUE TO MAGENTA VALUE
ELSE IF CYAN < MAGENTA .. WE CUT 50% OF CYAN VALUE TO SHOW REAL-PINK
IT WORKED FOR ME AND HERE IS THE EXTENDSCRIPT CODE :
function CMYKTORGB1(_c, _m, _y, _k) {
var C = _c / 100; // THE PROBLEM THAT IT RETURNS LIGHT-CYAN IN RGB
var M = _m / 100;
var Y = _y / 100;
var K = _k / 100;
var _mc = 0;
if (_c > 0) {
if (_m >= _c) {
_mc = _c / 2;
C = (_c - _mc) / 100; // THIS WILL FIX BLUE-PINK VALUE
}
else {
_mc = _c / 4;
M = (_m + _mc) / 100; // THIS WILL FIX LIGHT-CYAN VALUE
}
}
var R = 255 * (1 - C) * (1 - K);
var G = 255 * (1 - M) * (1 - K);
var B = 255 * (1 - Y) * (1 - K);
if (R < 0) { R = 0; }
if (G < 0) { G = 0; }
if (B < 0) { B = 0; }
return [R, G, B];
}
OR THIS FUNTION IT WORKING TOO :
function CMYKTORGB2(_c, _m, _y, _k) {
var C = _c / 100; // THE PROBLEM THAT IT RETURNS LIGHT-CYAN IN RGB
var M = _m / 100;
var Y = _y / 100;
var K = _k / 100;
var _mc = 0;
if (_c > 0) {
if (_m >= _c) {
_mc = _c / 2;
C = (_c - _mc) / 100; // THIS WILL FIX BLUE-PINK VALUE
}
else {
_mc = _c / 4;
M = (_m + _mc) / 100; // THIS WILL FIX LIGHT-CYAN VALUE
}
}
var _C = C * (1.0 - K) + K
var _M = M * (1.0 - K) + K
var _Y = Y * (1.0 - K) + K
var R = 255 * (1.0 - C)
var G = 255 * (1.0 - M)
var B = 255 * (1.0 - Y)
if (R < 0) { R = 0; }
if (G < 0) { G = 0; }
if (B < 0) { B = 0; }
return [R, G, B];
}

Rotate around a changing origin - Javascript

So I have an object rotating around an origin point. Once I rotate and then change the origin point. My object seems to jump positions. After the jump it rotates fine... Need help finding the pattern/why it's jumping and what I need to do to stop it.
Here's the rotation code:
adjustMapTransform = function (_x, _y) {
var x = _x + (map.width/2);
var y = _y + (map.height/2);
//apply scale here
var originPoint = {
x:originXInt,
y:originYInt
};
var mapOrigin = {
x:map.x + (map.width/2),
y:map.y + (map.height/2)
};
//at scale 1
var difference = {
x:mapOrigin.x - originPoint.x,
y:mapOrigin.y - originPoint.y
};
x += (difference.x * scale) - difference.x;
y += (difference.y * scale) - difference.y;
var viewportMapCentre = {
x: originXInt,
y: originYInt
}
var rotatedPoint = {};
var angle = (rotation) * Math.PI / 180.0;
var s = Math.sin(angle);
var c = Math.cos(angle);
// translate point back to origin:
x -= viewportMapCentre.x;
y -= viewportMapCentre.y;
// rotate point
var xnew = x * c - y * s;
var ynew = x * s + y * c;
// translate point back:
x = xnew + viewportMapCentre.x - (map.width/2);
y = ynew + viewportMapCentre.y - (map.height/2);
var coords = {
x:x,
y:y
};
return coords;
}
Also here is a JS Fiddle project that you can play around in to give you a better idea of what's happening.
EDITED LINK - Got rid of the originY bug and scaling bug
https://jsfiddle.net/fionoble/6k8sfkdL/13/
Thanks!
The direction of rotation is a consequence of the sign you pick for the elements in your rotation matrix. [This is Rodrigues formula for rotation in two dimensions]. So to rotate in the opposite direction simply subtract your y cosine term rather than your y sine term.
Also you might try looking at different potential representations of your data.
If you use the symmetric representation of the line between your points you can avoid shifting and instead simply transform your coordinates.
Take your origin [with respect to your rotation], c_0, to be the constant offset in the symmetric form.
You have for a point p relative to c_0:
var A = (p.x - c_0.x);
var B = (p.y - c_0.y);
//This is the symmetric form.
(p.x - c_0.x)/A = (p.y - c_0.y)/B
which will be true under a change of coordinates and for any point on the line (which also takes care of scaling/dilation).
Then after the change of coordinates for rotation you have [noting that this rotation has the opposite sense, not the same as yours].
//This is the symmetric form of the line incident on your rotated point
//and on the center of its rotation
((p.x - c_0.x) * c + (p.y - c_0.y) * s)/A = ((p.x - c_0.x) * s - (p.y - c_0.y) * c)/B
so, multiplying out we get
(pn.x - c_0.x) * B * c + (pn.y - c_0.y) * B * s = (pn.x - c_0.x) * A * s - (pn.y - c_0.y) * A * c
rearrangement gives
(pn.x - c_0.x) * (B * c - A * s) = - (pn.y - c_0.y) * (B * s + A * c)
pn.y = -(pn.x - c_0.x) * (B * c - A * s) / (B * s + A * c) + c_0.y;
for any scaling.

How do I draw a closed curve over a set of points?

Basically I want to draw a polygon, but I want the edges to appear soft rather than hard. Since the shape of the polygon is important, the edges have to go over the points.
I've found monotone cubic splines to be accurate for open curves (i.e., curves that don't wrap around on themselves), but the algorithms I've found precalculate points 0 and N. Can I somehow change them to work with a closed curve?
I am implementing this in JavaScript, but pseudo-code would just as well.
There is an easy method (developed by Maxim Shemanarev) to construct (usually) good-looking closed Bezier curves set over a set of points. Example:
Key moments of algo:
and sample code:
// Assume we need to calculate the control
// points between (x1,y1) and (x2,y2).
// Then x0,y0 - the previous vertex,
// x3,y3 - the next one.
double xc1 = (x0 + x1) / 2.0;
double yc1 = (y0 + y1) / 2.0;
double xc2 = (x1 + x2) / 2.0;
double yc2 = (y1 + y2) / 2.0;
double xc3 = (x2 + x3) / 2.0;
double yc3 = (y2 + y3) / 2.0;
double len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
double len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
double len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
double k1 = len1 / (len1 + len2);
double k2 = len2 / (len2 + len3);
double xm1 = xc1 + (xc2 - xc1) * k1;
double ym1 = yc1 + (yc2 - yc1) * k1;
double xm2 = xc2 + (xc3 - xc2) * k2;
double ym2 = yc2 + (yc3 - yc2) * k2;
// Resulting control points. Here smooth_value is mentioned
// above coefficient K whose value should be in range [0...1].
ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;

Categories