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 and ETS group address importer. 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 }