def xyz_to_rgb(cs, xc, yc, zc):
    """
    Given an additive tricolour system CS, defined by the CIE x
    and y chromaticities of its three primaries (z is derived
    trivially as 1-(x+y)), and a desired chromaticity (XC, YC,
    ZC) in CIE space, determine the contribution of each
    primary in a linear combination which sums to the desired
    chromaticity.  If the  requested chromaticity falls outside
    the Maxwell  triangle (colour gamut) formed by the three
    primaries, one of the r, g, or b weights will be negative.

    Caller can use constrain_rgb() to desaturate an
    outside-gamut colour to the closest representation within
    the available gamut and/or norm_rgb to normalise the RGB
    components so the largest nonzero component has value 1.
    """
    xr = cs['xRed']
    yr = cs['yRed']
    zr = 1 - (xr + yr)
    xg = cs['xGreen']
    yg = cs['yGreen']
    zg = 1 - (xg + yg)
    xb = cs['xBlue']
    yb = cs['yBlue']
    zb = 1 - (xb + yb)
    xw = cs['xWhite']
    yw = cs['yWhite']
    zw = 1 - (xw + yw)
    rx = yg * zb - yb * zg
    ry = xb * zg - xg * zb
    rz = xg * yb - xb * yg
    gx = yb * zr - yr * zb
    gy = xr * zb - xb * zr
    gz = xb * yr - xr * yb
    bx = yr * zg - yg * zr
    by = xg * zr - xr * zg
    bz = xr * yg - xg * yr
    rw = (rx * xw + ry * yw + rz * zw) / yw
    gw = (gx * xw + gy * yw + gz * zw) / yw
    bw = (bx * xw + by * yw + bz * zw) / yw
    rx = rx / rw
    ry = ry / rw
    rz = rz / rw
    gx = gx / gw
    gy = gy / gw
    gz = gz / gw
    bx = bx / bw
    by = by / bw
    bz = bz / bw
    r = rx * xc + ry * yc + rz * zc
    g = gx * xc + gy * yc + gz * zc
    b = bx * xc + by * yc + bz * zc
    return r, g, b
