<> <> <> <> <> <> DIRECTORY Atom USING [GetPName, MakeAtom], CNSColor, Rope USING [ROPE]; CNSColorImpl: CEDAR PROGRAM IMPORTS Atom EXPORTS CNSColor = BEGIN OPEN CNSColor; hueRecord: TYPE = RECORD [ name: ATOM, value: REAL ]; hueMapping: ARRAY CSLChroma OF hueRecord ¬ [ [$Achromatic, 0.0], [$Red, 0.0], [$OrangishRed, 0.01], [$RedOrange, 0.02], [$ReddishOrange, 0.03], [$Orange, 0.04], [$YellowishOrange, 0.07], [$OrangeYellow, 0.10], [$OrangishYellow, 0.13], [$Yellow, 0.1673], [$GreenishYellow, 0.2073], [$YellowGreen, 0.2473], [$YellowishGreen, 0.2873], [$Green, 0.3333], [$BluishGreen, 0.4133], [$GreenBlue, 0.4933], [$GreenishBlue, 0.5733], [$Blue, 0.6666], [$PurplishBlue, 0.6816], [$BluePurple, 0.6966], [$BluishPurple, 0.7116], [$Purple, 0.73], [$ReddishPurple, 0.80], [$PurpleRed, 0.87], [$PurplishRed, 0.94], [$BrownishRed, 0.01], [$RedBrown, 0.02], [$ReddishBrown, 0.03], [$Brown, 0.04], [$YellowishBrown, 0.07], [$BrownYellow, 0.10], [$BrownishYellow, 0.13] ]; saturationRecord: TYPE = RECORD [ name: ATOM, value: REAL ]; saturationMapping: ARRAY CSLSaturation OF saturationRecord ¬ [ [$NoSaturation, 0.0], [$Grayish, 0.25], [$Moderate, 0.50], [$Strong, 0.75], [$Vivid, 1.0] ]; lightnessRecord: TYPE = RECORD [ name: ATOM, value: REAL ]; lightnessMapping: ARRAY CSLLightness OF lightnessRecord ¬ [ [$Black, 0.0], [$VeryDark, 0.1666], [$Dark, 0.3333], [$Medium, 0.5], [$Light, 0.6666], [$VeryLight, 0.8333], [$White, 1.0] ]; CSLFromCNS: PUBLIC PROCEDURE [cns: CNS] RETURNS [CSL] = { hueAtom, saturationAtom, lightnessAtom: ATOM; c: CSLChroma; s: CSLSaturation; l: CSLLightness; hueAtom ¬ Atom.MakeAtom[cns.hue]; FOR c IN [red..brownishYellow] DO IF hueAtom = hueMapping[c].name THEN EXIT; REPEAT FINISHED => c ¬ achromatic; ENDLOOP; IF c = achromatic THEN s ¬ noSaturation ELSE { saturationAtom ¬ Atom.MakeAtom[cns.saturation]; FOR s IN [grayish..vivid] DO IF saturationAtom = saturationMapping[s].name THEN EXIT; REPEAT FINISHED => s ¬ vivid; ENDLOOP; }; SELECT hueAtom FROM $Black => l ¬ black; $White => l ¬ white; ENDCASE => { lightnessAtom ¬ Atom.MakeAtom[cns.lightness]; FOR l IN [veryDark..veryLight] DO IF lightnessAtom = lightnessMapping[l].name THEN EXIT; REPEAT FINISHED => l ¬ medium; ENDLOOP; }; RETURN[[c, s, l]]; }; CNSFromCSL: PUBLIC PROCEDURE [csl: CSL] RETURNS [CNS] = { hue, saturation, lightness: Rope.ROPE ¬ ""; IF csl.c = achromatic THEN { SELECT csl.l FROM black => { hue ¬ "Black"; }; white => { hue ¬ "White"; }; ENDCASE => { hue ¬ "Gray"; lightness ¬ Atom.GetPName[lightnessMapping[csl.l].name]; }; } ELSE { hue ¬ Atom.GetPName[hueMapping[csl.c].name]; saturation ¬ Atom.GetPName[saturationMapping[csl.s].name]; lightness ¬ Atom.GetPName[lightnessMapping[csl.l].name]; }; RETURN[[hue, saturation, lightness]]; }; HSLFromCSL: PUBLIC PROCEDURE [csl: CSL] RETURNS [HSL] = { hue, saturation, lightness: REAL ¬ 0.0; IF csl.c = achromatic THEN { lightness ¬ lightnessMapping[csl.l].value; } ELSE { hue ¬ hueMapping[csl.c].value; saturation ¬ saturationMapping[csl.s].value; lightness ¬ lightnessMapping[csl.l].value; }; RETURN[[hue, saturation, lightness]]; }; CSLFromHSL: PUBLIC PROCEDURE [hsl: HSL] RETURNS [CSL] = { hue, saturation, lightness: REAL; c: CSLChroma; s: CSLSaturation; l: CSLLightness; [hue, saturation, lightness] _ hsl; FOR s IN CSLSaturation DO IF s = CSLSaturation.LAST THEN EXIT; IF saturation <= saturationMapping[s].value + (saturationMapping[s.SUCC].value - saturationMapping[s].value)/2 THEN EXIT; ENDLOOP; IF s = noSaturation THEN { c ¬ achromatic; FOR l IN CSLLightness DO IF l = CSLLightness.LAST THEN EXIT; IF lightness <= lightnessMapping[l].value + (lightnessMapping[l.SUCC].value - lightnessMapping[l].value)/2 THEN EXIT; ENDLOOP; } ELSE { FOR cc: CSLChroma IN [red..purplishRed] DO c ¬ cc; -- to satisfy fussier Mimosa compiler (if c is the loop variable, can't assign to it) IF c = purplishRed THEN { IF hue > hueMapping[c].value + (1.0 - hueMapping[c].value)/2 THEN c ¬ red; EXIT; }; IF hue <= hueMapping[c].value + (hueMapping[c.SUCC].value - hueMapping[c].value)/2 THEN EXIT; ENDLOOP; FOR l IN [veryDark..veryLight] DO IF l = veryLight THEN EXIT; IF lightness <= lightnessMapping[l].value + (lightnessMapping[l.SUCC].value - lightnessMapping[l].value)/2 THEN EXIT; ENDLOOP; }; RETURN[[c, s, l]]; }; END.