UNPKG

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, and KNX routing between interfaces. Easy to use and highly configurable.

114 lines (101 loc) 3.85 kB
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 }