node-red-contrib-knx-ultimate
Version:
Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control, ETS group address importer, KNX AI for diagnosticsand KNX routing between interfaces. Easy to use and highly configurable.
114 lines (101 loc) • 3.85 kB
JavaScript
module.exports = {
/**
* Calculate XY color points for a given RGB value.
* @param {number} red RGB red value (0-255)
* @param {number} green RGB green value (0-255)
* @param {number} blue RGB blue value (0-255)
* @param {object} lampGamut Hue bulb gamut range (the lamp provides a gamut object red:{x:1,y:1}, etc)
* @returns {number[]}
*/
calculateXYFromRGB (red, green, blue, lampGamut) {
red /= 255
green /= 255
blue /= 255
const r = red > 0.04045 ? ((red + 0.055) / 1.055) ** 2.4000000953674316 : red / 12.92
const g = green > 0.04045 ? ((green + 0.055) / 1.055) ** 2.4000000953674316 : green / 12.92
const b = blue > 0.04045 ? ((blue + 0.055) / 1.055) ** 2.4000000953674316 : blue / 12.92
const x = r * 0.664511 + g * 0.154324 + b * 0.162028
const y = r * 0.283881 + g * 0.668433 + b * 0.047685
const z = r * 8.8E-5 + g * 0.07231 + b * 0.986039
const xy = [x / (x + y + z), y / (x + y + z)]
if (isNaN(xy[0])) {
xy[0] = 0.0
}
if (isNaN(xy[1])) {
xy[1] = 0.0
}
if (lampGamut !== null && lampGamut !== undefined) {
const colorPoints = [[lampGamut.red.x, lampGamut.red.y], [lampGamut.green.x, lampGamut.green.y], [lampGamut.blue.x, lampGamut.blue.y]]
const inReachOfLamps = checkPointInLampsReach(xy, lampGamut)
if (!inReachOfLamps) {
const pAB = getClosestPointToPoints(colorPoints[0], colorPoints[1], xy)
const pAC = getClosestPointToPoints(colorPoints[2], colorPoints[0], xy)
const pBC = getClosestPointToPoints(colorPoints[1], colorPoints[2], xy)
const dAB = getDistanceBetweenTwoPoints(xy, pAB)
const dAC = getDistanceBetweenTwoPoints(xy, pAC)
const dBC = getDistanceBetweenTwoPoints(xy, pBC)
let lowest = dAB
let closestPoint = pAB
if (dAC < dAB) {
lowest = dAC
closestPoint = pAC
}
if (dBC < lowest) {
closestPoint = pBC
}
xy[0] = closestPoint[0]
xy[1] = closestPoint[1]
}
}
xy[0] = precision(xy[0])
xy[1] = precision(xy[1])
// Check boundary (min 0, max 1)
xy[0] = xy[0] < 0 ? 0 : xy[0]
xy[0] = xy[0] > 1 ? 1 : xy[0]
xy[1] = xy[1] < 0 ? 0 : xy[1]
xy[1] = xy[1] > 1 ? 1 : xy[1]
return { x: xy[0], y: xy[1] }
}
}
function crossProduct (point1, point2) {
return point1[0] * point2[1] - point1[1] * point2[0]
}
function checkPointInLampsReach (point, lampGamutObject) {
if (point != null && lampGamutObject != null) {
const { red } = lampGamutObject
const { green } = lampGamutObject
const { blue } = lampGamutObject
const v1 = [green.x - red.x, green.y - red.y]
const v2 = [blue.x - red.x, blue.y - red.y]
const q = [point[0] - red.x, point[1] - red.y]
const s = crossProduct(q, v2) / crossProduct(v1, v2)
const t = crossProduct(v1, q) / crossProduct(v1, v2)
return s >= 0.0 && t >= 0.0 && s + t <= 1.0
}
return false
}
function getClosestPointToPoints (pointA, pointB, pointP) {
if (pointA != null && pointB != null && pointP != null) {
const pointAP = [pointP[0] - pointA[0], pointP[1] - pointA[1]]
const pointAB = [pointB[0] - pointA[0], pointB[1] - pointA[1]]
const ab2 = pointAB[0] * pointAB[0] + pointAB[1] * pointAB[1]
const apAb = pointAP[0] * pointAB[0] + pointAP[1] * pointAB[1]
let t = apAb / ab2
if (t < 0.0) {
t = 0.0
} else if (t > 1.0) {
t = 1.0
}
return [pointA[0] + pointAB[0] * t, pointA[1] + pointAB[1] * t]
}
return null
}
function getDistanceBetweenTwoPoints (pointA, pointB) {
const dx = pointA[0] - pointB[0]
const dy = pointA[1] - pointB[1]
const dist = Math.sqrt(dx * dx + dy * dy)
return dist
}
function precision (d) {
return Math.round(10000.0 * d) / 10000.0
}