DIRECTORY ColorNames, ColorModels USING [undefined], RuntimeError USING [BoundsFault], IO USING [STREAM, RIS, GetTokenRope, PutFR, rope], Rope USING [ROPE, Length, Match,Cat ]; ColorNamesImpl: CEDAR PROGRAM IMPORTS IO, Rope, RuntimeError EXPORTS ColorNames = BEGIN OPEN ColorNames; ROPE: TYPE=Rope.ROPE; UndefinedName: PUBLIC SIGNAL = CODE; undefined: REAL = ColorModels.undefined; --for undefined color values hueRecord: TYPE = RECORD [ name: ROPE, value: REAL ]; hueMapping: ARRAY HueType OF hueRecord _ [ undefined: ["Undefined", undefined], black: ["Black", undefined], --achromatic white: ["White", undefined], --achromatic gray: ["Gray", undefined], --achromatic grey: ["Grey", undefined], --achromatic red: ["Red", 0.0], orangishRed: ["OrangishRed", 0.01], redOrange: ["RedOrange", 0.02], reddishOrange: ["ReddishOrange", 0.03], brownishRed: ["BrownishRed", 0.01], redBrown: ["RedBrown", 0.02], reddishBrown: ["ReddishBrown", 0.03], orange: ["Orange", 0.04], yellowishOrange: ["YellowishOrange", 0.07], orangeYellow: ["OrangeYellow", 0.10], orangishYellow: ["OrangishYellow", 0.13], brown: ["Brown", 0.04], yellowishBrown: ["YellowishBrown", 0.07], brownYellow: ["BrownYellow", 0.10], brownishYellow: ["BrownishYellow", 0.13], yellow: ["Yellow", 0.1673], greenishYellow: ["GreenishYellow", 0.2073], yellowGreen: ["YellowGreen", 0.2473], yellowishGreen: ["YellowishGreen", 0.2873], green: ["Green", 0.3333], bluishGreen: ["BluishGreen", 0.4133], greenBlue: ["GreenBlue", 0.4933], greenishBlue: ["GreenishBlue", 0.5733], blue: ["Blue", 0.6666], purplishBlue: ["PurplishBlue", 0.6816], bluePurple: ["BluePurple", 0.6966], bluishPurple: ["BluishPurple", 0.7116], purple: ["Purple", 0.73], reddishPurple: ["ReddishPurple", 0.80], purpleRed: ["PurpleRed", 0.87], purplishRed: ["PurplishRed", 0.94] ]; saturationRecord: TYPE = RECORD [ name: ROPE, value: REAL ]; saturationMapping: ARRAY SaturationType OF saturationRecord _ [ default: ["Default", 1.0], achromatic: ["Achromatic", 0.0], weak: ["Weak", 0.25], moderate: ["Moderate", 0.50], strong: ["Strong", 0.75], vivid: ["Vivid", 1.0] ]; lightnessRecord: TYPE = RECORD [ name: ROPE, value: REAL ]; lightnessMapping: ARRAY LightnessType OF lightnessRecord _ [ default: ["Default", 0.5], veryDark: ["VeryDark", 0.1666], dark: ["Dark", 0.3333], medium: ["Medium", 0.5], light: ["Light", 0.6666], veryLight: ["VeryLight", 0.8333] ]; ishTable: ARRAY [0..7) OF ROPE _ [ "Reddish", "Orangish", "Brownish", "Yellowish", "Greenish", "Bluish", "Purplish" ]; ParseColorName: PUBLIC PROCEDURE[rope: ROPE] RETURNS[names: Names] = { hue: HueType _ undefined; saturation: SaturationType _ default; lightness: LightnessType _ default; hueList: ARRAY [0..2) OF ROPE; index: CARDINAL _ 0; --for hueList very, found: BOOLEAN _ FALSE; token: ROPE; Done: SIGNAL=CODE; stream: IO.STREAM _ IO.RIS[rope]; FindLightness: PROC[r: ROPE] RETURNS [lt: LightnessType, fnd: BOOLEAN] = { FOR lt IN LightnessType DO IF Rope.Match[r,lightnessMapping[lt].name,FALSE] THEN RETURN[lt, TRUE]; ENDLOOP; RETURN[default,FALSE]; }; FindSaturation: PROC[r: ROPE] RETURNS [sat: SaturationType, fnd: BOOLEAN] = { FOR sat IN SaturationType DO IF Rope.Match[r,saturationMapping[sat].name,FALSE] THEN RETURN[sat, TRUE]; ENDLOOP; RETURN[default,FALSE]; }; FindHue: PROC[r: ROPE] RETURNS [h: HueType, fnd: BOOLEAN] = { FOR h IN HueType DO IF Rope.Match[r,hueMapping[h].name,FALSE] THEN RETURN[h, TRUE]; ENDLOOP; RETURN[undefined,FALSE]; }; FindHuish: PROC[r: ROPE] RETURNS [name: ROPE, fnd: BOOLEAN] = { FOR i: CARDINAL IN [0..LENGTH[ishTable]) DO IF Rope.Match[r,ishTable[i],FALSE] THEN RETURN[ishTable[i], TRUE]; ENDLOOP; RETURN[NIL,FALSE]; }; NextToken: PROC = { DO [token: token, charsSkipped: ] _ IO.GetTokenRope[stream]; IF token=NIL THEN SIGNAL Done; IF Rope.Length[token] > 2 THEN EXIT; ENDLOOP; }; DO NextToken[! Done => EXIT]; IF lightness=default THEN { IF Rope.Match[token, "Very", FALSE] THEN {very _ TRUE; LOOP}; [lightness, found] _ FindLightness[token]; IF found THEN { IF very AND (lightness=dark OR lightness=light) THEN [lightness, found] _ FindLightness[Rope.Cat["Very",token]]; LOOP; } ELSE very _ FALSE; --very has to immediately precede a lightness term }; IF saturation=default THEN { [saturation, found] _ FindSaturation[token]; IF found THEN LOOP; }; [hue, found] _ FindHue[token]; IF found THEN { ENABLE RuntimeError.BoundsFault => SIGNAL UndefinedName; hueList[index] _ token; index _ index+1; } ELSE IF index=0 THEN { --*ish only occures for the first half of a compound color huish: ROPE; [huish, found] _ FindHuish[token]; IF found THEN {hueList[index] _ huish; index _ index+1} }; ENDLOOP; SELECT index FROM 1 => { --check for valid single hue [hue, found] _ FindHue[hueList[0]]; IF ~found THEN SIGNAL UndefinedName; }; 2 => { --compound hue [hue, found] _ FindHue[Rope.Cat[hueList[0], hueList[1]]]; IF ~found THEN SIGNAL UndefinedName; }; ENDCASE => UndefinedName; --we must have a hue RETURN[[hue: hue, saturation: saturation, lightness: lightness]]; }; NamesToHSL: PUBLIC PROCEDURE [names: Names] RETURNS [h,s,l: REAL] = { SELECT names.hue FROM black => {h _ undefined; s_0; l_0}; white => {h _ undefined; s_0; l_1}; ENDCASE => { h _ hueMapping[names.hue].value; IF h = undefined THEN s _ 0 ELSE s _ saturationMapping[names.saturation].value; l _ lightnessMapping[names.lightness].value; }; RETURN[h,s,l]; }; NamesToRope: PUBLIC PROCEDURE [names: Names] RETURNS [rope: ROPE] = { rope _ IO.PutFR["%g %g %g", IO.rope[lightnessMapping[names.lightness].name], IO.rope[saturationMapping[names.saturation].name], IO.rope[hueMapping[names.hue].name]]; RETURN[rope]; }; HSLToNames: PUBLIC PROCEDURE [h,s,l: REAL] RETURNS [Names] = { hue: HueType; saturation: SaturationType; lightness: LightnessType; minD, d: REAL _ 10; --infinity IF l=0.0 THEN RETURN[[hue: black, saturation: achromatic, lightness: default]]; IF l=1.0 THEN RETURN[[hue: white, saturation: achromatic, lightness: default]]; FOR index: LightnessType IN [veryDark..veryLight] DO d _ ABS[l-lightnessMapping[index].value]; IF d < minD THEN {minD _ d; lightness _ index}; ENDLOOP; minD _ 10; --infinity FOR index: SaturationType IN [achromatic..vivid] DO d _ ABS[s-saturationMapping[index].value]; IF d < minD THEN {minD _ d; saturation _ index}; ENDLOOP; IF saturation=achromatic THEN RETURN[[hue: gray, saturation: achromatic, lightness: lightness]]; IF h=undefined THEN SIGNAL UndefinedName; minD _ 10; --infinity FOR index: HueType IN [red..purplishRed] DO d _ ABS[h-hueMapping[index].value]; IF d < minD THEN {minD _ d; hue _ index}; ENDLOOP; RETURN[[hue: hue, saturation: saturation, lightness: lightness]]; }; END. ColorNamesImpl.mesa Written by Maureen Stone on June 23, 1983 11:48 am Last Edited by: Beach, June 22, 1983 2:52 pm Last Edited by: Stone, October 19, 1983 5:20 pm Last Edited by: Pier, January 18, 1984 1:09 pm hue is more complicated because there may be compound hues Κ %˜Iproc– "Cedar" stylešœ™K– "Cedar" stylešœ2™2J™,J™/J™.unitšΟk ˜ Jšœ ˜ Jšœ œ ˜Jšœ œ˜!Jšœœœ"˜2Jš œœœœœœ˜&—šœœ˜Jšœœ œ ˜4—Lšœœ ˜Lšœœœ˜L˜Jšœœœœ˜$Jšœ œΟc˜Ešœ œœ˜Jšœœ˜ Jšœ˜ J˜J˜—šœ œ œ˜*Jšœ'˜'Jšœ#ž ˜/Jšœ"ž ˜.Jšœ!ž ˜-Jšœ!ž ˜-Jšœ˜Jšœ&˜&Jšœ#˜#Jšœ)˜)Jšœ%˜%Jšœ!˜!Jšœ'˜'Jšœ˜Jšœ,˜,Jšœ(˜(Jšœ,˜,Jšœ˜Jšœ*˜*Jšœ%˜%Jšœ*˜*Jšœ!˜!Jšœ-˜-Jšœ(˜(Jšœ-˜-Jšœ ˜ Jšœ)˜)Jšœ%˜%Jšœ)˜)Jšœ˜Jšœ)˜)Jšœ'˜'Jšœ)˜)Jšœ˜Jšœ)˜)Jšœ#˜#Jšœ&˜&J˜J˜—šœœœ˜!Jšœœ˜ Jšœ˜ J˜—J˜šœœœ˜?Jšœ˜Jšœ!˜!Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜J˜—šœœœ˜ Jšœœ˜ Jšœ˜ J˜—J˜šœœœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ œž ˜Jšœœœ;˜OJšœœœ;˜Ošœœ˜4Jšœœ"˜)Jšœ œ˜/Jšœ˜—Jšœ ž ˜šœœ˜3Jšœœ#˜*Jšœ œ ˜0Jšœ˜—Jšœœœ<˜`Jšœ œœ˜)Jšœ ž ˜šœœ˜+Jšœœ˜#Jšœ œ˜)Jšœ˜—Jšœ;˜AJ˜—J˜Jšœ˜—…—”$Ν