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
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 is more complicated because there may be compound hues
[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𡤀 l𡤀};
white => {h ← undefined; s𡤀 l𡤁};
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.