)abbrev domain COLOR Color
++ Author: Jim Wen
++ Date Created: 10 May 1989
++ Basic Operations: red, yellow, green, blue, hue, numberOfHues, color, +, *, =
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description: Color() specifies a domain of 27 colors provided in the
++ \Language{} system (the colors mix additively).


Color() : Exports == Implementation where
  I      ==> Integer
  PI     ==> PositiveInteger
  SF     ==> DoubleFloat

  Exports ==> AbelianSemiGroup with
    "*"    : (PI, %) -> %
      ++ s * c, returns the color c, whose weighted shade has been scaled by s.
    "*"    : (SF, %) -> %
      ++ s * c, returns the color c, whose weighted shade has been scaled by s.
    "+"    : (%, %) -> %
      ++ c1 + c2 additively mixes the two colors c1 and c2.
    red    : ()      -> %
      ++ red() returns the position of the red hue from total hues.
    yellow : ()      -> %
      ++ yellow() returns the position of the yellow hue from total hues.
    green  : ()      -> %
      ++ green() returns the position of the green hue from total hues.
    blue   : ()      -> %
      ++ blue() returns the position of the blue hue from total hues.
    hue    : %       -> I
      ++ hue(c) returns the hue index of the indicated color c.
    numberOfHues : ()    -> PI
      ++ numberOfHues() returns the number of total hues, set in totalHues.
    color  : Integer -> %
      ++ color(i) returns a color of the indicated hue i.

  Implementation ==> add
    totalHues   ==> 27  --see  (header.h file) for the current number

    Rep := Record(hue : I, weight : SF)

    import from I
    import from SF

    f : SF * c : % ==
      -- s * c returns the color c, whose weighted shade has been scaled by s
      zero? f => c
      -- 0 is the identity function...or maybe an error is better?
      [c.hue, f * c.weight]

    x + y ==
      x.hue = y.hue => [x.hue, x.weight + y.weight]
      if y.weight > x.weight then  -- let x be color with bigger weight
        c := x
        x := y
        y := c
      diff := x.hue - y.hue
      if (xHueSmaller := (diff < 0)) then diff := -diff
      if (moreThanHalf := (diff > totalHues quo 2)) then diff := totalHues-diff
      offset : I := wholePart(round (diff::SF/(2::SF)^(x.weight/y.weight)) )
      if (xHueSmaller and not moreThanHalf)
           or (not xHueSmaller and moreThanHalf)
      then
        ans := x.hue + offset
      else
        ans := x.hue - offset
      if (ans < 0) then ans := totalHues + ans
      else if (ans > totalHues) then ans := ans - totalHues
      [ans, 1]

    x = y     == (x.hue = y.hue) and (x.weight = y.weight)
    red()     == [1, 1]
    yellow()  == [11::I, 1]
    green()   == [14::I, 1]
    blue()    == [22::I, 1]
    -- sample()  == red()
    hue c     == c.hue
    i : PositiveInteger * c : % == i::SF * c
    numberOfHues() == totalHues

    color i ==
      if (i<0) or (i>totalHues) then
       error concat("Color should be in the range 1..",
                    convert(totalHues)@String)
      [i::I, 1]

    coerce(c : %) : OutputForm ==
      hconcat [message("Hue: "), (c.hue)::OutputForm,
               message("  Weight: "), (c.weight)::OutputForm]

)abbrev domain PALETTE Palette
++ Author: Jim Wen
++ Date Created: May 10th 1989
++ Basic Operations: dark, dim, bright, pastel, light, hue, shade, coerce
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords: dim, bright, pastel, coerce
++ References:
++ Description: This domain describes four groups of color shades (palettes).

Palette() : Exports == Implementation where
  I      ==> Integer
  C      ==> Color
  SHADE  ==> ["Dark","Dim","Bright","Pastel","Light"]@List(String)

  Exports ==> SetCategory with
    dark   : C  -> %
      ++ dark(c) sets the shade of the indicated hue of c to it's lowest value.
    dim    : C  -> %
      ++ dim(c) sets the shade of a hue, c,  above dark, but below bright.
    bright : C  -> %
      ++ bright(c) sets the shade of a hue, c, above dim, but below pastel.
    pastel : C  -> %
      ++ pastel(c) sets the shade of a hue, c,  above bright, but below light.
    light  : C  -> %
      ++ light(c) sets the shade of a hue, c,  to it's highest value.
    hue    : %  -> C
      ++ hue(p) returns the hue field of the indicated palette p.
    shade  : %  -> I
      ++ shade(p) returns the shade index of the indicated palette p.
    coerce : C  -> %
      ++ coerce(c) sets the average shade for the palette to that of the
      ++ indicated color c.

  Implementation ==> add
    Rep := Record(shadeField : I, hueField : C)

    dark   c == [1, c]
    dim    c == [2, c]
    bright c == [3, c]
    pastel c == [4, c]
    light  c == [5, c]
    hue    p == p.hueField
    shade  p == p.shadeField
    -- sample() == bright(sample())
    coerce(c : Color) : % == bright c
    coerce(p : %) : OutputForm ==
        hconcat([message("["), coerce(p.hueField), message("] from the "),
                 message(SHADE.(p.shadeField)), message(" palette")])

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
