home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 13 / 13.iso / p / p024 / 12.img / ADS1.LIB / COLEXT.C < prev    next >
Encoding:
Text File  |  1993-02-18  |  71.3 KB  |  2,325 lines

  1. /* Next available MSG number is  66 */
  2.  
  3. /*    COLEXT.C
  4.       ¬⌐┼v (C) 1990-1992  Autodesk ñ╜Ñq
  5.  
  6.       Ñ╗│n┼ΘºK╢O¿╤▒z╢iªµÑ⌠ª≤Ñ╬│~╗▌¿D¬║½■¿⌐íB¡╫º∩ñ╬╡oªµ, ª²¼O░╚╜╨┐φ┤`ñU¡z
  7.       ¡∞½h :
  8.  
  9.       1)  ñWªC¬║¬⌐┼v│qºi░╚╗▌ÑX▓{ªb¿Cñ@Ñ≈½■¿⌐∙╪íC
  10.       2)  ¼█├÷¬║╗í⌐·ñσÑ≤ñ]Ñ▓╢╖⌐·╕ⁿ¬⌐┼v│qºiñ╬Ñ╗╢╡│\Ñi│qºiíC
  11.  
  12.       Ñ╗│n┼Θ╢╚┤ú¿╤º@¼░└│Ñ╬ñW¬║░╤ª╥, ª╙Ñ╝┴n⌐·⌐╬┴⌠ºtÑ⌠ª≤½O├╥; ╣∩⌐≤Ñ⌠ª≤»S«φ
  13.       Ñ╬│~ñº╛A║┘⌐╩, ÑHñ╬░╙╖~╛P░Γ⌐╥┴⌠ºtÑX¿π¬║½O├╥, ªbª╣ñ@╖ºñ⌐ÑHº_╗{íC
  14.  
  15.  
  16.  
  17.       DESCRIPTION:
  18.  
  19.         AutoCAD colour manipulation functions
  20.  
  21.         Designed and implemented in October of 1989 by John Walker
  22.  
  23.         This ADS application permits AutoCAD colours to  be  specified
  24.         in  any  of  a  number  of  commonly-used colour systems.  The
  25.         application provides AutoLisp functions for each colour system
  26.         which  accept  the  parameters  which  define a colour in that
  27.         system and return the AutoCAD colour number from the  standard
  28.         palette  for  256  colour  devices which best approximates the
  29.         requested colour.
  30.  
  31.         In  addition, functions are provided to convert either AutoCAD
  32.         colour indices  or  Red-Green-Blue  colour  triples  to  their
  33.         representation in each of the colour systems.
  34.  
  35.         Finally, functions which convert  colours  in  non-RGB  colour
  36.         systems to RGB triples are provided.
  37.  
  38.  
  39.         COLOUR SYSTEMS
  40.         ==============
  41.  
  42.         The colour systems implemented are:
  43.  
  44.         RGB      Colours  are  specified  as the  intensities  of  the
  45.                  three  additive  primary colours Red, Green, and Blue
  46.                  which generate the colour.  The intensities are given
  47.                  in the range from 0 to 1, with 0 indicating no  light
  48.                  of  that colour and 1 representing maximum intensity.
  49.  
  50.         CMY      Colours  are  specified by  the  intensities  of  the
  51.                  subtractive   primary   colours  Cyan,  Magenta,  and
  52.                  Yellow.  The CMY system is used in composing ink  and
  53.                  toner  mixtures  for  subtractive printing processes.
  54.                  Intensities are specified in the range from 0  to  1,
  55.                  with  0  indicating  none  of  the  specified pigment
  56.                  present and 1 indicating the maximum amount.
  57.  
  58.         YIQ      The  YIQ  system  is  used   to  encode  colours  for
  59.                  television broadcasting.  The YIQ system  remaps  the
  60.                  RGB  space such that Y represents a primary scaled to
  61.                  the human luminosity  response  curve.   Two  colours
  62.                  with the same Y values will be indistinguishable when
  63.                  viewed on a monochrome monitor; to guarantee  colours
  64.                  are  distinct  when viewed in monochrome, they should
  65.                  be converted to YIQ and  checked  for  a  substantial
  66.                  difference  in  Y.   Y  ranges from 0 to 1, with zero
  67.                  indicating black and 1 maximum intensity.  Since  the
  68.                  YIQ system is a remapping of the RGB colour cube by a
  69.                  nontrivial affine transformation, the I and Q  values
  70.                  in  the  YIQ  system do not "come out even"; I ranges
  71.                  from -0.6 to 0.6, and Q ranges from  -0.52  to  0.52.
  72.  
  73.         HSV      The HSV system approximates the intuitive concepts of
  74.                  hue  (tint),  saturation  (shade), and value (tone or
  75.                  brightness), by mapping colours into a hexcone.   Hue
  76.                  is  specified  by  a number from 0 to 1, representing
  77.                  the  angle  around  the hue circle in fraction of the
  78.                  circumference of the hue wheel with red at 0,  yellow
  79.                  at  1/6,  and  so  on.   Saturation is expressed as a
  80.                  number from 0 to  1,  with  0  indicating  a  totally
  81.                  desaturated  shade  (grey  scale), and 1 a completely
  82.                  saturated  shade  (no  admixture  of  white).   Value
  83.                  expresses intensity from 0 to 1, with zero indicating
  84.                  black and 1 maximum intensity.
  85.  
  86.         HLS      The  HLS system encodes the intuitive concepts of hue
  87.                  (tint),   lightness   (intensity),   and   saturation
  88.                  (shade), by mapping colours into  a  double  hexcone.
  89.                  The  HLS system is closely related to the HSV system,
  90.                  and can be thought of as the result of stretching the
  91.                  flat   end   of   the  HSV  hexcone  upward  until  a
  92.                  symmetrical   double   hexcone  is  formed.   Hue  is
  93.                  specified by a number from 0 to 1,  representing  the
  94.                  angle  around  the  hue  circle  in  fraction  of the
  95.                  circumference of the hue wheel with red at 0,  yellow
  96.                  at  1/6, and so on.  Lightness expresses intensity as
  97.                  a number from 0 to 1, with zero indicating black  and
  98.                  1  maximum  intensity.   Saturation is expressed as a
  99.                  number from 0 to  1,  with  0  indicating  a  totally
  100.                  desaturated  shade  (grey  scale), and 1 a completely
  101.                  saturated shade (no admixture of white).
  102.  
  103.         CTEMP    The  CTEMP  system  specifies  colours  emitted  by a
  104.                  Planckian  (black  body)  radiator   with   a   given
  105.                  temperature   in   degrees  Kelvin.   Typical  colour
  106.                  temperatures are:
  107.  
  108.                     The star Spica                  28000 K
  109.                     The star Sirius                 10700 K
  110.                     North sky light                  7500 K
  111.                     Average daylight                 6500 K
  112.                     Xenon lamp                       6000 K
  113.                     Typical sunlight + skylight      5500 K
  114.                     The star Betelgeuse              3400 K
  115.                     Tungsten/halogen lamps           3300 K
  116.                     Incandescent bulbs (100-200 W)   2900 K
  117.                     Sunlight at sunset               2000 K
  118.                     Candle flame                     1900 K
  119.  
  120.         CNS      The CNS system expresses colours as English language
  121.                  names.
  122.  
  123.                  A colour is specified in the CNS system by a sequence
  124.                  of  English  words.   CNS  colours  may be achromatic
  125.                  (grey scale values) or chromatic.  Chromatic  colours
  126.                  consist  of  a  hue  (dominant  spectral  component),
  127.                  saturation (the extent of dilution with  white),  and
  128.                  lightness  (intensity).   A chromatic hue is composed
  129.                  by naming and mixing the following primary hues:
  130.  
  131.                     Red, Orange/Brown, Yellow, Green, Blue, Purple
  132.  
  133.                  and secondary hues:
  134.  
  135.                     Reddish, Orangish/Brownish, Yellowish,
  136.                     Greenish, Bluish, Purplish
  137.  
  138.                  To  obtain  one of the primary hues, just specify its
  139.                  name,  e.g.   "Yellow".   To  obtain  a  hue  halfway
  140.                  between  two  primary  hues, compose the two bounding
  141.                  hues: for example "Yellow-green" (or  "Green-yellow";
  142.                  it  doesn't  matter  which  is  specified first).  To
  143.                  obtain a hue one quarter the distance from one colour
  144.                  to  an adjacent colour, compose the "ish" form of the
  145.                  adjacent  colour  with  the  primary   colour.    For
  146.                  example, the hues between Yellow and Green are named:
  147.  
  148.                     Yellow
  149.                     Greenish yellow
  150.                     Yellow-green (or Green-yellow)
  151.                     Yellowish green
  152.                     Green
  153.  
  154.                  Brown  is  a  somewhat  confusing  special case.  The
  155.                  colour we perceive as  brown  has  the  same  hue  as
  156.                  orange  but  when  seen  with  reduced saturation and
  157.                  intensity it appears as brown, a colour distinct from
  158.                  orange  (that's  why there's no brown in the rainbow,
  159.                  in case you've ever lost sleep pondering that  fact).
  160.                  To  compensate for this perceptual quirk, "brown" and
  161.                  "brownish" may be used as synonyms for  "orange"  and
  162.                  "orangish"  when  specifying  hues.   If  "brown"  or
  163.                  "brownish"  are  used,  the  default  saturation  and
  164.                  lightness  (see  below)  are  set  so  the orange hue
  165.                  appears brown; if explicit saturation  and  lightness
  166.                  are given orange and brown are synonymous.
  167.  
  168.                  Lightness  (brightness or intensity) may be specified
  169.                  by adding one of  the  following  adjectives  to  the
  170.                  colour name:
  171.  
  172.                     very dark
  173.                     dark
  174.                     medium
  175.                     light
  176.                     very light
  177.  
  178.                  If  no  lightness  adjective  appears,  a  default is
  179.                  assumed (unless a brown hue was named, in which  case
  180.                  the default will be "light").  This diverges from the
  181.                  CNS specification in which omitted lightness defaults
  182.                  to medium intensity.
  183.  
  184.                  Saturation (the degree of admixture of  white  light)
  185.                  is specified by the following adjectives:
  186.  
  187.                     grayish (or greyish)
  188.                     moderate
  189.                     strong
  190.                     vivid
  191.  
  192.                  "Vivid" denotes a fully saturated colour, and is  the
  193.                  default  (unless  a brown is specified, in which case
  194.                  the default saturation is "strong").
  195.  
  196.                  Examples of chromatic colour specifications are:
  197.  
  198.                     red
  199.                     blue-green
  200.                     purplish red
  201.                     very dark green
  202.                     strong yellow-green
  203.                     very light grayish greenish yellow
  204.  
  205.                  the last  describing  the  colour  of  snow  I  don't
  206.                  recommend you eat.
  207.  
  208.                  Achromatic  specifications describe 7 shades of grey,
  209.                  to wit:
  210.  
  211.                     black
  212.                     very dark gray
  213.                     dark gray
  214.                     gray (or medium gray)
  215.                     light gray
  216.                     very light gray
  217.                     white
  218.  
  219.                  in all cases "grey" may be used instead of "gray".
  220.  
  221.                  Although the word order used herein is as  prescribed
  222.                  by the formal specification of CNS, my implementation
  223.                  is  totally  insensitive  to  word  order.   You  can
  224.                  specify  "yellow  greyish light greenish very" if you
  225.                  like, silly seems how notwithstanding it.
  226.  
  227.  
  228.         AUTOLISP-CALLABLE FUNCTIONS
  229.         ===========================
  230.  
  231.         Three groups of AutoLisp-callable functions  are  implemented.
  232.         The first convert specifications in external colour systems to
  233.         AutoCAD's internal colour indices.  These  functions  map  the
  234.         specifications  into either AutoCAD's standard 8 or 256 colour
  235.         palette.  The palette is selected with the (COLSET) function:
  236.  
  237.            (COLSET <gamut>)
  238.  
  239.         where  <gamut>  is  either  8  or 256 to choose the colour set
  240.         desired.  (COLSET) returns the current colour gamut; if called
  241.         with  no  arguments, (COLSET) returns the current colour gamut
  242.         without changing it.  The following functions  return  AutoCAD
  243.         colour indices between 1 and <gamut> - 1.
  244.  
  245.            (CMY   <cyan> <magenta> <yellow>)
  246.            (CMY '(<cyan> <magenta> <yellow>))
  247.  
  248.            (CNS "CNS colour name description")
  249.  
  250.            (CTEMP <temperature>)
  251.  
  252.            (HLS   <hue> <lightness> <saturation>)
  253.            (HLS '(<hue> <lightness> <saturation>))
  254.  
  255.            (HSV   <hue> <saturation> <value>)
  256.            (HSV '(<hue> <saturation> <value>))
  257.  
  258.            (RGB   <red> <green> <blue>)
  259.            (RGB '(<<red> <green> <blue>))
  260.  
  261.            (YIQ   <Y-value> <I-value> <Q-value>)
  262.            (YIQ '(<Y-value> <I-value> <Q-value>))
  263.  
  264.         Except for the (CNS) function, which takes a string  argument,
  265.         and  (CTEMP)  which  takes  a  single numeric temperature, all
  266.         these  conversion  functions  accept  either  three  numerical
  267.         arguments  (either  integer  or  real),  or  a  list  of three
  268.         numbers.  Representing colour triples as lists,  in  the  same
  269.         manner as three-dimensional point co-ordinates, allows them to
  270.         be manipulated  as  units  and  operated  upon  with  AutoLisp
  271.         functions.  For example the (distance) function can be used to
  272.         determine distance in colour space  as  well  as  in  physical
  273.         space.  If invalid arguments are passed to these functions, an
  274.         error message is displayed and nil  is  returned.   The  (CNS)
  275.         function,  which can generate a wide variety of error messages
  276.         resulting from syntax errors  in  the  string  passed  to  it,
  277.         indicates  an error by returning nil.  A string describing the
  278.         most recent error  detected  by  the  (CNS)  function  can  be
  279.         obtained  by  calling (CNSERR).  If no error has been detected
  280.         by (CNS), (CNSERR) returns nil.
  281.  
  282.         When passed valid arguments, all  of  these  functions  return
  283.         AutoCAD  colour  numbers  ranging  from  1  to  255.  They may
  284.         therefore be specified at any AutoCAD prompt which requests  a
  285.         colour number.
  286.  
  287.         A   second   group   of  functions  converts  external  colour
  288.         specifications to lists of RGB  intensities.   Each  of  these
  289.         functions  takes  the  same  arguments  as the functions which
  290.         return AutoCAD colour indices.
  291.  
  292.            (CMY-RGB   <cyan> <magenta> <yellow>)
  293.            (CMY-RGB '(<cyan> <magenta> <yellow>))
  294.  
  295.            (CNS-RGB "CNS colour name description")
  296.  
  297.            (CTEMP-RGB <temperature>)
  298.  
  299.            (HLS-RGB   <hue> <lightness> <saturation>)
  300.            (HLS-RGB '(<hue> <lightness> <saturation>))
  301.  
  302.            (HSV-RGB   <hue> <saturation> <value>)
  303.            (HSV-RGB '(<hue> <saturation> <value>))
  304.  
  305.            (YIQ-RGB   <Y-value> <I-value> <Q-value>)
  306.            (YIQ-RGB '(<Y-value> <I-value> <Q-value>))
  307.  
  308.         There  is  no RGB-RGB function; it would be simply an identity
  309.         function.
  310.  
  311.         The  third family of functions converts AutoCAD colour indices
  312.         from 0 to 255 or RGB triples to their representation  in  each
  313.         of  the  external  colour  systems.   AutoCAD  colour  index 0
  314.         (black), which cannot be specified as  an  entity  colour,  is
  315.         nonetheless a valid argument to these functions.
  316.  
  317.            (TO-CMY <colour>)
  318.            (TO-CNS <colour>)
  319.            (TO-HLS <colour>)
  320.            (TO-HSV <colour>)
  321.            (TO-RGB <colour>)
  322.            (TO-YIQ <colour>)
  323.  
  324.         With  the  exception  of  (TO-CNS), which returns a CNS colour
  325.         specification string, all of these functions return a list  of
  326.         three  real numbers specifying the values in its colour system
  327.         corresponding to the AutoCAD colour index or RGB  triple.   If
  328.         an  RGB  triple  is  specified for <colour> it may be given as
  329.         three arguments or as a list of three numbers.
  330.  
  331.  
  332.         INTERNAL FUNCTIONS
  333.         ==================
  334.  
  335.         Internal conversion functions implemented in this  module  are
  336.         as  described  below.  Definitions are given as prototypes for
  337.         readability;  for  compatibility  with  older  compilers,  the
  338.         actual  code  is  not  prototyped.  All conversions are to and
  339.         from RGB--to get between two non-RGB systems, you must convert
  340.         through RGB.
  341.  
  342.                                 CMY
  343.  
  344.         void rgb_cmy(ads_real r, ads_real g, ads_real b,
  345.                      ads_real *c, ads_real *m, ads_real *y)
  346.            Converts r, g, b (0 to 1) to c, m, y (0 to 1).
  347.  
  348.         void cmy_rgb(ads_real c, ads_real m, ads_real y,
  349.                      ads_real *r, ads_real *g, ads_real *b)
  350.            Converts c, m, y (0 to 1) to r, g, b (0 to 1).
  351.  
  352.                                CTEMP
  353.  
  354.         void ctemp_rgb(ads_real temperature,
  355.                        ads_real *r, ads_real *g, ads_real *b)
  356.            Converts a colour temperature specified in degrees Kelvin,
  357.            to r, g, b (0 to 1).
  358.  
  359.                                 YIQ
  360.  
  361.         void rgb_yiq(ads_real r, ads_real g, ads_real b,
  362.                      ads_real *y, ads_real *i, ads_real *q)
  363.            Converts r, g, b (0 to 1) to y (0 to 1), i (-0.6 to 0.6),
  364.            and q (-0.52 to 0.52).
  365.  
  366.         void yiq_rgb(ads_real y, ads_real i, ads_real q,
  367.                      ads_real *r, ads_real *g, ads_real *b)
  368.            Converts y (0 to 1), i (-0.6 to 0.6), and q (-0.52 to 0.52)
  369.            to r, g, b (0 to 1).
  370.  
  371.                                 HSV
  372.  
  373.         void rgb_hsv(ads_real r, ads_real g, ads_real b,
  374.                      ads_real *h, ads_real *s, ads_real *v)
  375.            Converts r, g, b (0 to 1) to h (0 to 360), s (0 to 1),  and
  376.            v  (0  to  1).  Note that rgb_hsv() returns hue in terms of
  377.            degrees, not as a  fraction  of  circumference  as  do  the
  378.            AutoLisp-callable functions.
  379.  
  380.         void hsv_rgb(ads_real h, ads_real s, ads_real v,
  381.                      ads_real *r, ads_real *g, ads_real *b)
  382.            Converts  h (0 to 360), s (0 to 1), and v (0 to 1) to r, g,
  383.            b (0 to 1).  Note that rgb_hsv() expects hue  in  terms  of
  384.            degrees,  not  as  a  fraction  of  circumference as do the
  385.            AutoLisp-callable functions.
  386.  
  387.                                 HLS
  388.  
  389.         void rgb_hls(ads_real r, ads_real g, ads_real b,
  390.                      ads_real *h, ads_real *l, ads_real *s)
  391.            Converts r, g, b (0 to 1) to h (0 to 360), l (0 to 1),  and
  392.            s  (0  to  1).  Note that rgb_hls() returns hue in terms of
  393.            degrees, not as a  fraction  of  circumference  as  do  the
  394.            AutoLisp-callable functions.
  395.  
  396.         void hls_rgb(ads_real h, ads_real l, ads_real s,
  397.                      ads_real *r, ads_real *g, ads_real *b)
  398.            Converts  h (0 to 360), l (0 to 1), and s (0 to 1) to r, g,
  399.            b (0 to 1).  Note that rgb_hls() expects hue  in  terms  of
  400.            degrees,  not  as  a  fraction  of  circumference as do the
  401.            AutoLisp-callable functions.
  402.  
  403.                                 CNS
  404.  
  405.         void rgb_cns(ads_real r, ads_real g, ads_real b, char *cnstr)
  406.            Edits  a  zero-terminated  CNS  description  of  the colour
  407.            represented by r, g, and b (0 to 1), into the string cnstr.
  408.            The  maximum  length of the edited string is 36 characters,
  409.            so a buffer of at least 37 characters  should  be  supplied
  410.            for  cnstr.   If  the lightness of the colour is closest to
  411.            the CNS nomenclature for the default  lightness  stored  in
  412.            the  scaled  integer  variable  defcnslit (initially 10000,
  413.            representing 1),  no  intensity  is  edited.   The  default
  414.            saturation of "vivid" is not edited.
  415.  
  416.         Boolean cns_rgb(char *cns, ads_real *r, ads_real *g, ads_real *b)
  417.            Scans  a CNS specification in the string cns and stores RGB
  418.            intensities in r, g, and b which range from 0 to 1.  If  no
  419.            lightness  is  specified, the lightness (as defined for the
  420.            HSV routines) in the  scaled  integer  defcnslit  is  used.
  421.            This  value  is  initially  set  to  10000  for  a  default
  422.            intensity of very light (maximum).  The function returns  1
  423.            if  the  specification  is  valid and 0 if an incorrect CNS
  424.            specification is supplied,  in  which  case  the  character
  425.            pointer  cnserr  will  point to an error message describing
  426.            the problem.
  427.  
  428.         BIBLIOGRAPHY
  429.         ============
  430.  
  431.            Fundamentals of Interactive Computer Graphics
  432.               by J. D. Foley and A. van Dam, Reading Massachusetts:
  433.               Addison-Wesley, 1984.
  434.  
  435.            Measuring Colour
  436.               by R. W. G. Hunt, West Sussex England: Ellis Horwood
  437.               Ltd., 1987.  (Distributed by John Wiley & Sons).
  438.  
  439.            A New Color-Naming System for Graphics Languages
  440.               by Toby Berk, Lee Brownston, and Arie  Kaufman,  Florida
  441.               International  University,  IEEE  Computer  Graphics and
  442.               Applications, May 1982, Page 37.
  443.  
  444. */
  445.  
  446. #include   <stdio.h>
  447. #include   <string.h>
  448. #include   <ctype.h>
  449. #include   <math.h>
  450.  
  451. #include   "adslib.h"
  452.  
  453. #ifdef lint
  454. extern char *sprintf();               /* Adjust for Sun's strange stdio.h */
  455. #endif
  456.  
  457. /* Special assertion handler for ADS applications. */
  458.  
  459. #ifndef NDEBUG
  460. #define assert(ex) {if (!(ex)){ads_printf( \
  461.                     /*MSG1*/"COLEXT: ┴n⌐· (%s) Ñó▒╤: └╔«╫íu%sív, \
  462.                     ▓─ %d ªC\n", /*MSG0*/" ex ",__FILE__,__LINE__); \
  463.                     ads_abort(/*MSG2*/"íu┴n⌐·ívÑó▒╤íC");}}
  464. #else
  465. #define assert(ex)
  466. #endif
  467.  
  468. /*  Data types  */
  469.  
  470. typedef enum {False = 0, True = 1} Boolean;
  471. #define V        (void)
  472.  
  473. /* Set point variable from three co-ordinates */
  474.  
  475. #define Spoint(pt, x, y, z)  pt[X] = (x);  pt[Y] = (y);  pt[Z] = (z)
  476.  
  477. /* Copy point  */
  478.  
  479. #define Cpoint(d, s)   d[X] = s[X];  d[Y] = s[Y];  d[Z] = s[Z]
  480.  
  481. /* Utility definition to get an  array's  element  count  (at  compile
  482.    time).   For  example:
  483.  
  484.        int  arr[] = {1,2,3,4,5};
  485.        ...
  486.        printf("%d", ELEMENTS(arr));
  487.  
  488.    would print a five.  ELEMENTS("abc") can also be used to  tell  how
  489.    many  bytes are in a string constant INCLUDING THE TRAILING NULL. */
  490.  
  491. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  492.  
  493. /* Utility definitions */
  494.  
  495. #ifdef abs
  496. #undef abs
  497. #endif
  498. #define abs(x)      ((x)<0 ? -(x) : (x))
  499. #ifdef min
  500. #undef  min
  501. #endif
  502. #define min(a,b)    ((a)<(b) ? (a) : (b))
  503. #ifdef max
  504. #undef  max
  505. #endif
  506. #define max(a,b)    ((a)>(b) ? (a) : (b))
  507.  
  508. #ifndef M_E
  509. #define M_E     2.7182818284590452354
  510. #endif
  511.  
  512. #define Tbit(x)  (tok & (1L << ((int) (x))))  /* Test token bit set */
  513. #define Tb(x)    (1L << ((int) (x)))  /* Obtain bit to test */
  514.  
  515. /* AutoCAD standard color palette */
  516.  
  517. #define         BLACK           0
  518. #define         RED             1
  519. #define         YELLOW          2
  520. #define         GREEN           3
  521. #define         CYAN            4
  522. #define         BLUE            5
  523. #define         MAGENTA         6
  524. #define         WHITE           7
  525.  
  526. #define         SAT             1.0
  527.  
  528. struct r_g_b {                        /* RGB colour description */
  529.         ads_real red, green, blue;
  530. };
  531.  
  532. /*  Colour naming system vocabulary definition.  The vocabulary
  533.     is defined in this somewhat unusal fashion to facilitate
  534.     translation to languages other than English. */
  535.  
  536. typedef enum {
  537.         /* Chromatic colours */
  538.         Red, Orange, Brown, Yellow, Green, Blue, Purple,
  539.  
  540.         /* "ish" forms of chromatic colours */
  541.         Reddish, Orangish, Brownish, Yellowish, Greenish, Bluish, Purplish,
  542.  
  543.         /* Achromatic names */
  544.         Gray, Black, White,
  545.  
  546.         /* Lightness specifications */
  547.         Very, Dark, Medium, Light,
  548.  
  549.         /* Saturation specifications */
  550.         Grayish, Moderate, Strong, Vivid,
  551.  
  552.         /* Punctuation */
  553.         Hyphen, Period, Huh
  554.        } colourvocab;
  555.  
  556. static struct {
  557.         char *cname;
  558.         colourvocab ccode;
  559. } cvocab[] = {
  560.         {/*MSG3*/"red", Red},
  561.         {/*MSG4*/"orange", Orange},
  562.         {/*MSG5*/"brown", Brown},
  563.         {/*MSG6*/"yellow", Yellow},
  564.         {/*MSG7*/"green", Green},
  565.         {/*MSG8*/"blue", Blue},
  566.         {/*MSG9*/"purple", Purple},
  567.  
  568.         {/*MSG10*/"reddish", Reddish},
  569.         {/*MSG11*/"orangish", Orangish},
  570.         {/*MSG12*/"brownish", Brownish},
  571.         {/*MSG13*/"yellowish", Yellowish},
  572.         {/*MSG14*/"greenish", Greenish},
  573.         {/*MSG15*/"bluish", Bluish},
  574.         {/*MSG16*/"purplish", Purplish},
  575.  
  576.         {/*MSG17*/"gray", Gray},
  577.         {/*MSG18*/"grey", Gray},
  578.         {/*MSG19*/"black", Black},
  579.         {/*MSG20*/"white", White},
  580.  
  581.         {/*MSG21*/"very", Very},
  582.         {/*MSG22*/"dark", Dark},
  583.         {/*MSG23*/"medium", Medium},
  584.         {/*MSG24*/"light", Light},
  585.  
  586.         {/*MSG25*/"grayish", Grayish},
  587.         {/*MSG26*/"greyish", Grayish},
  588.         {/*MSG27*/"moderate", Moderate},
  589.         {/*MSG28*/"strong", Strong},
  590.         {/*MSG29*/"vivid", Vivid}
  591.        };
  592.  
  593. /* Table mapping generic hues to HSV hue indices. */
  594.  
  595. static struct {
  596.         long cbit;
  597.         int chue;
  598. } colhue[] = {
  599.         {Tb(Red),      0},            /* red */
  600.         {Tb(Orange),  30},            /* orange */
  601.         {Tb(Brown),  -30},            /* brown */
  602.         {Tb(Yellow),  60},            /* yellow */
  603.         {Tb(Green),  120},            /* green */
  604.         {Tb(Blue),   240},            /* blue */
  605.         {Tb(Purple), 300},            /* purple */
  606.         {0L,         360}             /* red (other incarnation) */
  607.        };
  608.  
  609. /* Table mapping secondary hues to HSV hue indices. */
  610.  
  611. static struct {
  612.         long cbit;
  613.         int chue;
  614. } ishhue[] = {
  615.         {Tb(Reddish),      0},        /* reddish */
  616.         {Tb(Orangish),    30},        /* orangish */
  617.         {Tb(Brownish),   -30},        /* brownish */
  618.         {Tb(Yellowish),   60},        /* yellowish */
  619.         {Tb(Greenish),   120},        /* greenish */
  620.         {Tb(Bluish),     240},        /* bluish */
  621.         {Tb(Purplish),   300},        /* purplish */
  622.         {0L,             360}         /* reddish (other incarnation) */
  623.        };
  624.  
  625. #define MAXTK    10                   /* Maximum tokens in specification */
  626. #define MAXTKS   20                   /* Longest token in characters */
  627.  
  628. #define BROWNLIGHT  3                 /* Brown lightness:  Medium */
  629. #define BROWNSAT    3                 /* Brown saturation: Strong */
  630.  
  631. /* Modal variables  */
  632.  
  633. static int defcnslit = 10000;         /* Default lightness if none specified */
  634. static int gamut = 256;               /* Colour gamut available */
  635.  
  636. /*  Local variables  */
  637.  
  638. static char *cnserr = NULL;           /* Error message string */
  639. static char cnserb[80];               /* Error message edit buffer */
  640. static char tokenb[MAXTKS];           /* Token buffer */
  641.  
  642. /*  Forward functions  */
  643.  
  644. void   main _((int, char **));
  645. void   funcload _((void));
  646. void   hsv_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  647. void   rgb_hsv _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  648. void   rgb_hls _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  649. ads_real hlsval _((ads_real, ads_real, ads_real));
  650. void   hls_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  651. void   rgb_yiq _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  652. void   yiq_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  653. void   rgb_cmy _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  654. void   ctemp_rgb _((ads_real, ads_real *,ads_real *,ads_real *));
  655. #ifdef NEEDED
  656. void   cmy_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  657. #endif
  658. colourvocab token _((char **));
  659. Boolean cns_rgb _((char *, ads_real *, ads_real *, ads_real *));
  660. char    *cixname _((colourvocab));
  661. void    rgb_cns _((ads_real, ads_real, ads_real, char *));
  662. void    acadrgb _((int, struct r_g_b *));
  663. int     rgbacad _((ads_real, ads_real, ads_real));
  664. void    retrgb _((Boolean, ads_real, ads_real, ads_real));
  665. Boolean triple _((ads_real *, Boolean));
  666. void    cmy _((Boolean));
  667. void    cns _((Boolean));
  668. void    cnser _((void));
  669. void    ctemp _((Boolean));
  670. void    hls _((Boolean));
  671. void    hsv _((Boolean));
  672. void    rgb _((Boolean));
  673. void    yiq _((Boolean));
  674. void    cmyac _((void));
  675. void    ctempac _((void));
  676. void    yiqac _((void));
  677. void    hsvac _((void));
  678. void    rgbac _((void));
  679. void    hlsac _((void));
  680. void    cnsac _((void));
  681. void    cmyrgb _((void));
  682. void    ctemprgb _((void));
  683. void    yiqrgb _((void));
  684. void    hsvrgb _((void));
  685. void    hlsrgb _((void));
  686. void    cnsrgb _((void));
  687. Boolean acadcol _((struct r_g_b *));
  688. void    torgb _((void));
  689. void    tocmy _((void));
  690. void    toyiq _((void));
  691. void    tohsv _((void));
  692. void    tohls _((void));
  693. void    tocns _((void));
  694. void    colset _((void));
  695.  
  696.  
  697. /*  Command definition and dispatch table.  */
  698.  
  699. struct {
  700.         char *cmdname;
  701.         void (*cmdfunc)();
  702. } cmdtab[] = {
  703. /*        Name         Function  */
  704.  
  705. /* External colour system to AutoCAD colour functions */
  706.  
  707. {/*MSG0*/"CMY",       cmyac},
  708. {/*MSG0*/"CNS",       cnsac},
  709. {/*MSG0*/"CTEMP",     ctempac},
  710. {/*MSG0*/"HLS",       hlsac},
  711. {/*MSG0*/"HSV",       hsvac},
  712. {/*MSG0*/"RGB",       rgbac},
  713. {/*MSG0*/"YIQ",       yiqac},
  714.  
  715. /* External colour system to RGB functions */
  716.  
  717. {/*MSG0*/"CMY-RGB",   cmyrgb},
  718. {/*MSG0*/"CNS-RGB",   cnsrgb},
  719. {/*MSG0*/"CTEMP-RGB", ctemprgb},
  720. {/*MSG0*/"HLS-RGB",   hlsrgb},
  721. {/*MSG0*/"HSV-RGB",   hsvrgb},
  722. {/*MSG0*/"YIQ-RGB",   yiqrgb},
  723.  
  724. /* AutoCAD colour index to external colour system functions */
  725.  
  726. {/*MSG0*/"TO-RGB",    torgb},
  727. {/*MSG0*/"TO-CMY",    tocmy},
  728. {/*MSG0*/"TO-YIQ",    toyiq},
  729. {/*MSG0*/"TO-HSV",    tohsv},
  730. {/*MSG0*/"TO-HLS",    tohls},
  731. {/*MSG0*/"TO-CNS",    tocns},
  732.  
  733. /* Control and utility functions */
  734.  
  735. {/*MSG0*/"CNSERR",    cnser},
  736. {/*MSG0*/"COLSET",    colset}
  737. };
  738.  
  739. /*  MAIN  --  Main ADS dispatch loop.  */
  740.  
  741. void main(argc, argv)
  742.   int argc;
  743.   char *argv[];
  744. {
  745.     int stat, cindex, scode = RSRSLT;
  746.  
  747.     ads_init(argc, argv);             /* Initialise the application */
  748.  
  749.     /* Main dispatch loop. */
  750.  
  751.     while (True) {
  752.  
  753.         if ((stat = ads_link(scode)) < 0) {
  754.             V printf(/*MSG30*/"\
  755. COLEXT: Ñ╤ ads_link() ╢╟ª^¬║ñú¿╬¬¼║A = %d\n", stat);
  756.             exit(1);
  757.         }
  758.  
  759.         scode = RSRSLT;               /* Default return code */
  760.  
  761.         switch (stat) {
  762.  
  763.         case RQXLOAD:                 /* Load functions.  Called at the start
  764.                                                 of the drawing editor.  */
  765.             funcload();
  766.             break;
  767.  
  768.         case RQSUBR:                  /* Evaluate external lisp function */
  769.             cindex = ads_getfuncode();
  770.  
  771.             /* Execute the command from the command table with
  772.                the index associated with this function. */
  773.  
  774.             if (cindex > 0) {
  775.                 cindex--;
  776.                 assert(cindex < ELEMENTS(cmdtab));
  777.                 (*cmdtab[cindex].cmdfunc)();
  778.             }
  779.             break;
  780.  
  781.         default:
  782.             break;
  783.         }
  784.     }
  785. }
  786.  
  787. /* FUNCLOAD  --  Load external functions into AutoLisp.  */
  788.  
  789. static void funcload()
  790. {
  791.     int i;
  792.  
  793.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  794.         ads_defun(cmdtab[i].cmdname, i + 1);
  795.     }
  796. }
  797.  
  798. /*      ***************************************************
  799.         **                                               **
  800.         **       Colour Interconversion Functions        **
  801.         **                                               **
  802.         ***************************************************
  803. */
  804.  
  805. /*  HSV_RGB  --  Convert HSV colour specification to RGB  intensities.
  806.                  Hue is specified as a  real  value  from  0  to  360,
  807.                  Saturation  and  Intensity as reals from 0 to 1.  The
  808.                  RGB components are returned as reals from 0 to 1.      */
  809.  
  810. static void hsv_rgb(h, s, v, r, g, b)
  811.   ads_real h, s, v;
  812.   ads_real *r, *g, *b;
  813. {
  814.     int i;
  815.     ads_real f, p, q, t;
  816.  
  817.     if (s == 0) {
  818.         *r = *g = *b = v;
  819.     } else {
  820.         if (h == 360.0)
  821.             h = 0;
  822.         h /= 60.0;
  823.  
  824.         i = h;
  825.         f = h - i;
  826.         p = v * (1.0 - s);
  827.         q = v * (1.0 - (s * f));
  828.         t = v * (1.0 - (s * (1.0 - f)));
  829.         assert(i >= 0 && i <= 5);
  830.         switch (i) {
  831.  
  832.         case 0:
  833.             *r = v;
  834.             *g = t;
  835.             *b = p;
  836.             break;
  837.  
  838.         case 1:
  839.             *r = q;
  840.             *g = v;
  841.             *b = p;
  842.             break;
  843.  
  844.         case 2:
  845.             *r = p;
  846.             *g = v;
  847.             *b = t;
  848.             break;
  849.  
  850.         case 3:
  851.             *r = p;
  852.             *g = q;
  853.             *b = v;
  854.             break;
  855.  
  856.         case 4:
  857.             *r = t;
  858.             *g = p;
  859.             *b = v;
  860.             break;
  861.  
  862.         case 5:
  863.             *r = v;
  864.             *g = p;
  865.             *b = q;
  866.             break;
  867.         }
  868.     }
  869. }
  870.  
  871. /*  RGB_HSV  --  Map R, G, B intensities in the range from 0 to 1 into
  872.                  Hue, Saturation,  and  Value:  Hue  from  0  to  360,
  873.                  Saturation  from  0  to  1,  and  Value  from 0 to 1.
  874.                  Special case: if Saturation is 0 (it's a  grey  scale
  875.                  tone), Hue is undefined and is returned as -1.
  876.  
  877.                  This follows Foley & van Dam, section 17.4.4.  */
  878.  
  879. static void rgb_hsv(r, g, b, h, s, v)
  880.   ads_real r, g, b;
  881.   ads_real *h, *s, *v;
  882. {
  883.     ads_real imax = max(r, max(g, b)),
  884.              imin = min(r, min(g, b)),
  885.              rc, gc, bc;
  886.  
  887.     *v = imax;
  888.     if (imax != 0)
  889.         *s = (imax - imin) / imax;
  890.     else
  891.         *s = 0;
  892.  
  893.     if (*s == 0) {
  894.         *h = -1;
  895.     } else {
  896.         rc = (imax - r) / (imax - imin);
  897.         gc = (imax - g) / (imax - imin);
  898.         bc = (imax - b) / (imax - imin);
  899.         if (r == imax)
  900.             *h = bc - gc;
  901.         else if (g == imax)
  902.             *h = 2.0 + rc - bc;
  903.         else
  904.             *h = 4.0 + gc - rc;
  905.         *h *= 60.0;
  906.         if (*h < 0.0)
  907.             *h += 360.0;
  908.     }
  909. }
  910.  
  911. /*  RGB_HLS  --  Map R, G, B intensities in the range from 0 to 1 into
  912.                  Hue, Lightness, and Saturation: Hue from  0  to  360,
  913.                  Lightness  from  0  to 1, and Saturation from 0 to 1.
  914.                  Special case: if Saturation is 0 (it's a  grey  scale
  915.                  tone), Hue is undefined and is returned as -1.
  916.  
  917.                  This follows Foley & van Dam, section 17.4.5.  */
  918.  
  919. static void rgb_hls(r, g, b, h, l, s)
  920.   ads_real r, g, b;
  921.   ads_real *h, *l, *s;
  922. {
  923.     ads_real imax = max(r, max(g, b)),
  924.              imin = min(r, min(g, b)),
  925.              rc, gc, bc;
  926.  
  927.     *l = (imax + imin) / 2;
  928.  
  929.     if (imax == imin) {
  930.         *s = 0;
  931.         *h = -1;
  932.     } else {
  933.         if (*l <= 0.5)
  934.             *s = (imax - imin) / (imax + imin);
  935.         else
  936.             *s = (imax - imin) /
  937.                  (2.0 - imax - imin);
  938.  
  939.         rc = (imax - r) / (imax - imin);
  940.         gc = (imax - g) / (imax - imin);
  941.         bc = (imax - b) / (imax - imin);
  942.         if (r == imax)
  943.             *h = bc - gc;
  944.         else if (g == imax)
  945.             *h = 2.0 + rc - bc;
  946.         else
  947.             *h = 4.0 + gc - rc;
  948.         *h *= 60.0;
  949.         if (*h < 0)
  950.             *h += 360.0;
  951.     }
  952. }
  953.  
  954. /*  HLS_RGB  --  Convert HLS colour specification to RGB  intensities.
  955.                  Hue  is  specified  as  a  real  value from 0 to 360;
  956.                  Lightness and Saturation as reals from 0 to  1.   The
  957.                  RGB components are returned as reals from 0 to 1.      */
  958.  
  959. static ads_real hlsval(n1, n2, hue)
  960.   ads_real n1, n2, hue;
  961. {
  962.     if (hue > 360.0)
  963.         hue -= 360.0;
  964.     else if (hue < 0.0)
  965.         hue += 360.0;
  966.     if (hue < 60.0) {
  967.         return n1 + ((n2 - n1) * hue) / 60.0;
  968.     } else if (hue < 180.0) {
  969.         return n2;
  970.     } else if (hue < 240.0) {
  971.         return n1 + ((n2 - n1) * (240.0 - hue)) / 60.0;
  972.     } else {
  973.         return n1;
  974.     }
  975. }
  976.  
  977. static void hls_rgb(h, l, s, r, g, b)
  978.   ads_real h, l, s;
  979.   ads_real *r, *g, *b;
  980. {
  981.     ads_real m1, m2;
  982.  
  983.     if (l <= 0.5)
  984.         m2 = l * (1.0 + s);
  985.     else
  986.         m2 = l + s - (l * s);
  987.     m1 = 2 * l - m2;
  988.  
  989.     if (s == 0) {
  990.         *r = *g = *b = l;
  991.     } else {
  992.         *r = hlsval(m1, m2, h + 120.0);
  993.         *g = hlsval(m1, m2, h);
  994.         *b = hlsval(m1, m2, h - 120.0);
  995.     }
  996. }
  997.  
  998. /*  RGB_YIQ  --  Convert RGB colour specification, R, G, B ranging
  999.                  from 0 to 1, to Y, I, Q colour specification.
  1000.  
  1001.                  |Y|   |0.30  0.59  0.11|   |R|
  1002.                  |I| = |0.60 -0.28 -0.32| . |G|
  1003.                  |Q|   |0.21 -0.52  0.31|   |B|
  1004. */
  1005.  
  1006. static void rgb_yiq(r, g, b, y, i, q)
  1007.   ads_real r, g, b;
  1008.   ads_real *y, *i, *q;
  1009. {
  1010.     ads_real ay = (r * 0.30 + g *  0.59 + b *  0.11),
  1011.              ai = (r * 0.60 + g * -0.28 + b * -0.32),
  1012.              aq = (r * 0.21 + g * -0.52 + b *  0.31);
  1013.  
  1014.     *y = ay;
  1015.     if (ay == 1.0) {                  /* Prevent round-off on grey scale */
  1016.         ai = aq = 0.0;
  1017.     }
  1018.     *i = ai;
  1019.     *q = aq;
  1020. }
  1021.  
  1022. /*  YIQ_RGB  --  Convert YIQ colour specification, Y, I,  Q  given  as
  1023.                  reals,  Y  from  0  to  1, I from -0.6 to 0.6, Q from
  1024.                  -0.52 to 0.52, to R, G, B intensities  in  the  range
  1025.                  from  0 to 1.  The matrix below is the inverse of the
  1026.                  RGB_YIQ matrix above.
  1027.  
  1028.                  |R|   |1.00  0.948  0.624|   |Y|
  1029.                  |G| = |1.00 -0.276 -0.640| . |I|
  1030.                  |B|   |1.00 -1.105  1.730|   |Q|
  1031. */
  1032.  
  1033. static void yiq_rgb(y, i, q, r, g, b)
  1034.   ads_real y, i, q;
  1035.   ads_real *r, *g, *b;
  1036. {
  1037.     ads_real ar = (y + i *   0.948 + q *  0.624),
  1038.              ag = (y + i *  -0.276 + q * -0.640),
  1039.              ab = (y + i *  -1.105 + q *  1.730);
  1040.  
  1041.     *r = max(0, min(1.0, ar));
  1042.     *g = max(0, min(1.0, ag));
  1043.     *b = max(0, min(1.0, ab));
  1044. }
  1045.  
  1046. /*  RGB_CMY  --  Convert RGB colour specification,  R,  G,  B  ranging
  1047.                  from  0  to  1, to C, M, Y colour specification, also
  1048.                  ranging from 0 to 1.
  1049.  
  1050.                  |C|   |1|   |R|
  1051.                  |M| = |1| - |G|
  1052.                  |Y|   |1|   |B|
  1053. */
  1054.  
  1055. static void rgb_cmy(r, g, b, c, m, y)
  1056.   ads_real r, g, b;
  1057.   ads_real *c, *m, *y;
  1058. {
  1059.     *c = 1.0 - r;
  1060.     *m = 1.0 - g;
  1061.     *y = 1.0 - b;
  1062. }
  1063.  
  1064. #ifdef NEEDED
  1065.  
  1066. /*  CMY_RGB  --  Convert CMY colour specification,  C,  M,  Y  ranging
  1067.                  from  0  to  1, to R, G, B colour specification, also
  1068.                  ranging from 0 to 1.
  1069.  
  1070.                  |R|   |1|   |C|
  1071.                  |G| = |1| - |M|
  1072.                  |B|   |1|   |Y|
  1073. */
  1074.  
  1075. static void cmy_rgb(c, m, y, r, g, b)
  1076.   ads_real c, m, y;
  1077.   ads_real *r, *g, *b;
  1078. {
  1079.     *r = 1.0 - c;
  1080.     *g = 1.0 - m;
  1081.     *b = 1.0 - y;
  1082. }
  1083. #endif
  1084.  
  1085. /*  CTEMP_RGB  --  Calculate the relative R, G, and B components for a
  1086.                    black body emitting light at a  given  temperature.
  1087.                    The  Planck  radiation  equation is solved directly
  1088.                    for the R, G, and B wavelengths defined for the CIE
  1089.                    1931  Standard  Colorimetric  Observer.  The colour
  1090.                    temperature is specified in degrees Kelvin. */
  1091.  
  1092. static void ctemp_rgb(temp, r, g, b)
  1093.   double temp;
  1094.   double *r, *g, *b;
  1095. {
  1096.     double c1 = 3.74183e10,
  1097.            c2 = 14388.0,
  1098.            er, eg, eb, es;
  1099.  
  1100. /* Lambda is the wavelength in microns: 5500 angstroms is 0.55 microns. */
  1101.  
  1102. #define Planck(lambda)  ((c1 * pow((double) lambda, -5.0)) /  \
  1103.                          (pow(M_E, c2 / (lambda * temp)) - 1))
  1104.  
  1105.     er = Planck(0.7000);
  1106.     eg = Planck(0.5461);
  1107.     eb = Planck(0.4358);
  1108. #undef Planck
  1109.  
  1110.     es = 1.0 / max(er, max(eg, eb));
  1111.  
  1112.     *r = er * es;
  1113.     *g = eg * es;
  1114.     *b = eb * es;
  1115. }
  1116.  
  1117. /*  TOKEN  --  Scan next token from the CNS string and update the
  1118.                scan pointer.  */
  1119.  
  1120. static colourvocab token(icp)
  1121.   char **icp;
  1122. {
  1123.     char ch;
  1124.     char *cp = *icp, *tch;
  1125.     int i, t = 0;
  1126.  
  1127.     /* Ignore leading space */
  1128.  
  1129.     while (True) {
  1130.         ch = *cp++;
  1131.         if (!isspace(ch))
  1132.             break;
  1133.     }
  1134.  
  1135.     if (ch == EOS)
  1136.         return Period;
  1137.  
  1138.     if (ch == '-') {
  1139.         *icp = cp;
  1140.         return Hyphen;
  1141.     }
  1142.  
  1143.     tch = cp - 1;                     /* Start of token pointer */
  1144.     if (!isalpha(ch)) {
  1145.         *cp = EOS;
  1146.         *icp = tch;
  1147.         return Huh;
  1148.     }
  1149.  
  1150.     while (isalpha(ch)) {
  1151.         if (isupper(ch))
  1152.             ch = tolower(ch);
  1153.         if (t < ((sizeof tokenb) - 2))
  1154.             tokenb[t++] = ch;
  1155.         ch = *cp++;
  1156.     }
  1157.     tokenb[t] = EOS;
  1158.     *icp = cp - 1;
  1159.  
  1160.     for (i = 0; i < ELEMENTS(cvocab); i++) {
  1161.         if (strcmp(tokenb, cvocab[i].cname) == 0) {
  1162.             return cvocab[i].ccode;
  1163.         }
  1164.     }
  1165.     **icp = EOS;
  1166.     *icp = tch;
  1167.     return Huh;
  1168. }
  1169.  
  1170. /*  CNS_RGB  --  Convert a CNS string to RGB intensities scaled from 0
  1171.                  to 1.  If an invalid specification is made,  0
  1172.                  is returned and an error message is pointed to by the
  1173.                  global character pointer  cnserr.   Otherwise,  1  is
  1174.                  returned.  */
  1175.  
  1176. static Boolean cns_rgb(cns, r, g, b)
  1177.   char *cns;
  1178.   ads_real *r, *g, *b;
  1179. {
  1180.     int i, j, k = 0, lightness, saturation;
  1181.     long tok = 0L, hue;
  1182.     colourvocab t;
  1183.     static char conflite[] = /*MSG31*/"íu⌐·½G½╫│W«µív╜─¼≡íC";
  1184.     /* Grey scale table */
  1185.     static int greyscale[] = {50, 17, 33, 50, 67, 83};
  1186.     /* Saturation percentage table */
  1187.     static int satab[] = {10000, 2500, 5000, 7500, 10000};
  1188.     /* Chromatic lightness table */
  1189.     static int litetab[] = {5000, 1300, 2500, 5000, 7500, 10000};
  1190.  
  1191.     cnserr = NULL;                    /* Initially no error in CNS string */
  1192.     j = strlen(cns);
  1193.     if (j == 0) {
  1194.         cnserr = /*MSG32*/"íu│W«µív╡L«─íC";
  1195.         return False;
  1196.     }
  1197.  
  1198.     /* Scan string and parse tokens */
  1199.  
  1200.     while (True) {
  1201.         t = token(&cns);
  1202.         if (t == Huh) {
  1203.             V sprintf(cnserb, /*MSG33*/"╡L¬k┐δ╗{¬║▓┼╕╣:íu%sívíC", cns);
  1204.             cnserr = cnserb;
  1205.             return False;
  1206.         }
  1207.         if (Tbit(t)) {
  1208.             V sprintf(cnserb, /*MSG34*/"¡½╜╞¬║▓┼╕╣:íu%sívíC", tokenb);
  1209.             cnserr = cnserb;
  1210.             return False;
  1211.         }
  1212.         if (t == Period)
  1213.             break;
  1214.         tok |= 1L << ((int) t);
  1215.     }
  1216.  
  1217.     /* Try to obtain lightness from specification */
  1218.  
  1219.     if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
  1220.         if (Tbit(Medium)) {
  1221.             if (Tbit(Very)) {
  1222.                 cnserr = /*MSG35*/"½D▒`▓▀║Díuññ╢í½G½╫ívíC";
  1223.                 return False;
  1224.             }
  1225.             if (Tbit(Light) || Tbit(Dark)) {
  1226.                 cnserr = conflite;
  1227.                 return False;
  1228.             }
  1229.             lightness = 3;
  1230.         } else if (Tbit(Dark)) {
  1231.             lightness = Tbit(Very) ? 1 : 2;
  1232.             if (Tbit(Light)) {
  1233.                 cnserr = conflite;
  1234.                 return False;
  1235.             }
  1236.         } else if (Tbit(Light)) {
  1237.             lightness = Tbit(Very) ? 5 : 4;
  1238.         } else {
  1239.             cnserr = /*MSG36*/"½D▒`▓▀║DñúÑ╬íu⌐·½Gív⌐╬íu╖t▓HívíC";
  1240.             return False;
  1241.         }
  1242.     } else {
  1243.         lightness = 0;
  1244.     }
  1245.  
  1246.     /* Test for achromatic colour specification. */
  1247.  
  1248.     i = !!(Tbit(Black)) + !!(Tbit(Gray)) + !!(Tbit(White));
  1249.     if (i > 0) {
  1250.  
  1251.         /* Test for conflicting specification of more than
  1252.            one achromatic colour. */
  1253.  
  1254.         if (i != 1) {
  1255.             cnserr = /*MSG37*/"íu╢┬/ª╟/Ñ╒ív¬║│W«µ╜─¼≡íC";
  1256.             return False;
  1257.         }
  1258.  
  1259.         /* Test for specification of chromatic colour with
  1260.            achromatic colour. */
  1261.  
  1262.         if (tok & (Tb(Red) | Tb(Orange) | Tb(Brown) | Tb(Yellow) |
  1263.                    Tb(Green) | Tb(Blue) | Tb(Purple))) {
  1264.             cnserr = /*MSG38*/"íu▒mªΓív╗Píu«°ªΓív┤y╝v▓VÑ╬íC";
  1265.             return False;
  1266.         }
  1267.  
  1268.         /* Test for specification of chromatic colour ish form with
  1269.            achromatic colour. */
  1270.  
  1271.         if (tok & (Tb(Reddish) | Tb(Orangish) |
  1272.                    Tb(Brownish) | Tb(Yellowish) |
  1273.                    Tb(Greenish) | Tb(Bluish) | Tb(Purplish) |
  1274.                    Tb(Hyphen))) {
  1275.             cnserr = /*MSG39*/"íuªΓ▒m¡╫Ñ┐ív╗Píu«°ªΓív┤y╝v▓VÑ╬íC";
  1276.             return False;
  1277.         }
  1278.  
  1279.         /* Test for saturation specification with achromatic shade. */
  1280.  
  1281.         if (tok & (Tb(Grayish) | Tb(Moderate) | Tb(Strong) | Tb(Vivid))) {
  1282.             cnserr = /*MSG40*/"ÑHíu«°ªΓív┤y╝v│]⌐wíu╣íªX½╫ívíC";
  1283.             return False;
  1284.         }
  1285.  
  1286.         /* Test for lightness specified with White or Black. */
  1287.  
  1288.         if (Tbit(White) || Tbit(Black)) {
  1289.             if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
  1290.                 cnserr = /*MSG41*/"ÑHíu╢┬/Ñ╒ív¿╙│]⌐wíu½G½╫ívíC";
  1291.                 return False;
  1292.             }
  1293.             if (Tbit(White)) {
  1294.                 *r = *g = *b = 1.0;   /* White */
  1295.             } else {
  1296.                 *r = *g = *b = 0;     /* Black */
  1297.             }
  1298.             return True;
  1299.         }
  1300.  
  1301.         /* Calculate grey scale value from lightness specification. */
  1302.  
  1303.         *r = *g = *b = greyscale[lightness] / 100.0;
  1304.         return True;
  1305.     }
  1306.  
  1307.     /* It isn't a grey scale, so it must be a chromatic colour
  1308.        specification.  Before we tear into the hue, let's try and
  1309.        determine the saturation. */
  1310.  
  1311.     i = (!!Tbit(Grayish)) + (!!Tbit(Moderate)) +
  1312.         (!!Tbit(Strong)) + (!!Tbit(Vivid));
  1313.     if (i > 0) {
  1314.         if (i > 1) {
  1315.             cnserr = /*MSG42*/"íu╣íªX½╫ív¬║│W«µ╜─¼≡íC";
  1316.             return False;
  1317.         }
  1318.         saturation = Tbit(Grayish) ? 1 :
  1319.                      (Tbit(Moderate) ? 2 :
  1320.                       (Tbit(Strong) ? 3 : 4));
  1321.     } else {
  1322.         saturation = 0;
  1323.     }
  1324.  
  1325.     /* Count primary hue specifications. */
  1326.  
  1327.     i = (!!Tbit(Red)) + (!!Tbit(Orange)) + (!!Tbit(Brown)) +
  1328.         (!!Tbit(Yellow)) +
  1329.         (!!Tbit(Green)) + (!!Tbit(Blue)) + (!!Tbit(Purple));
  1330.  
  1331.     if (i == 0) {
  1332.         cnserr = /*MSG43*/"Ñ╝½ⁿ⌐wíuªΓ╜╒ívíC";
  1333.         return False;
  1334.     }
  1335.     if (i > 2) {
  1336.         cnserr = /*MSG44*/"½ⁿ⌐w¬║íuªΓ╜╒ív╢W╣L 2 ║╪íC";
  1337.         return False;
  1338.     }
  1339.  
  1340.     /* Count secondary hue specifications. */
  1341.  
  1342.     j = (!!Tbit(Reddish)) + (!!Tbit(Orangish)) + (!!Tbit(Brownish)) +
  1343.         (!!Tbit(Yellowish)) +
  1344.         (!!Tbit(Greenish)) + (!!Tbit(Bluish)) + (!!Tbit(Purplish));
  1345.  
  1346.     if (j > 1) {
  1347.         cnserr = /*MSG45*/"½ⁿ⌐w¬║íuª╕ªΓ╜╒ív╢W╣L 1 ║╪íC";
  1348.         return False;
  1349.     }
  1350.     if (i == 2 && j > 0) {
  1351.         cnserr = /*MSG46*/"ÑH 2 ║╪íuÑDªΓ╜╒ív½ⁿ⌐wíuª╕ªΓ╜╒ívíC";
  1352.         return False;
  1353.     }
  1354.  
  1355.     /* Obtain hue based on form of specification we've determined
  1356.        is being made.
  1357.  
  1358.        Case 1.  Pure hue specified by a single primary hue. */
  1359.  
  1360.     hue = -1;
  1361.     if (i == 1 && j == 0) {
  1362.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1363.             if (tok & colhue[i].cbit) {
  1364.                 hue = abs(colhue[i].chue) * 100L;
  1365.                 /* If it's brown, impute saturation and lightness
  1366.                    if none was explicitly specified. */
  1367.                 if (colhue[i].chue < 0) {
  1368.                     if (lightness == 0)
  1369.                         lightness = BROWNLIGHT;
  1370.                     if (saturation == 0)
  1371.                         saturation = BROWNSAT;
  1372.                 }
  1373.                 break;
  1374.             }
  1375.         }
  1376.     } else if (i == 2) {
  1377.  
  1378.         /* Case 2.  Halfway hue specified by composing two adjacent
  1379.                     primary hues. */
  1380.  
  1381.         j = k = -1;
  1382.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1383.             if (tok & colhue[i].cbit) {
  1384.                 if (j < 0)
  1385.                     j = i;
  1386.                 else {
  1387.                     k = i;
  1388.                     break;
  1389.                 }
  1390.             }
  1391.         }
  1392.         if ((colhue[j].chue == -colhue[k].chue) ||
  1393.             (((j + 1) != k) &&
  1394.              !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
  1395.              (!(j == 0 && k == (ELEMENTS(colhue) - 2))))) {
  1396.             cnserr = /*MSG47*/"2 ║╪íuÑDªΓ╜╒ívñú▒╡╛FíC";
  1397.             return False;
  1398.         }
  1399.  
  1400.         if (Tbit(Red) && Tbit(Purple))
  1401.             j = ELEMENTS(colhue) - 1;
  1402.  
  1403.         hue = (abs(colhue[j].chue) + abs(colhue[k].chue)) * 50L;
  1404.         /* If either is brown, impute saturation and lightness
  1405.            if none was explicitly specified. */
  1406.         if (colhue[j].chue < 0 || colhue[k].chue < 0) {
  1407.             if (lightness == 0)
  1408.                 lightness = BROWNLIGHT;
  1409.             if (saturation == 0)
  1410.                 saturation = BROWNSAT;
  1411.         }
  1412.     } else {
  1413.  
  1414.         /* Case 3.  Quarterway hue specified by one primary hue
  1415.                     and one secondary hue. */
  1416.  
  1417.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1418.             if (tok & colhue[i].cbit) {
  1419.                 j = i;
  1420.                 break;
  1421.             }
  1422.         }
  1423.         for (i = 0; i < ELEMENTS(ishhue); i++) {
  1424.             if (tok & ishhue[i].cbit) {
  1425.                 k = i;
  1426.                 break;
  1427.             }
  1428.         }
  1429.         if ((colhue[j].chue == -colhue[k].chue) || (
  1430.                ((j + 1) != k) && ((j - 1) != k) &&
  1431.                !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
  1432.                !(k == 0 && j == 2) && !(k == 1 && j == 3) &&
  1433.                (!(j == 0 && k == (ELEMENTS(ishhue) - 2))) &&
  1434.                (!(k == 0 && j == (ELEMENTS(ishhue) - 2)))
  1435.               )
  1436.            ) {
  1437.             cnserr = /*MSG48*/"íuÑDªΓ╜╒ív╗Píuª╕ªΓ╜╒ívñú▒╡╛FíC";
  1438.             return False;
  1439.         }
  1440.  
  1441.         if (Tbit(Red) && Tbit(Purplish))
  1442.             j = ELEMENTS(colhue) - 1;
  1443.         else if (Tbit(Purple) && Tbit(Reddish))
  1444.             k = ELEMENTS(ishhue) - 1;
  1445.  
  1446.         hue = (abs(colhue[j].chue) * 3 + abs(ishhue[k].chue)) * 25L;
  1447.  
  1448.         /* If either is brown, impute saturation and lightness
  1449.            if none was explicitly specified. */
  1450.  
  1451.         if (colhue[j].chue < 0 || ishhue[k].chue < 0) {
  1452.             if (lightness == 0)
  1453.                 lightness = BROWNLIGHT;
  1454.             if (saturation == 0)
  1455.                 saturation = BROWNSAT;
  1456.         }
  1457.     }
  1458.  
  1459.     if (hue < 0) {
  1460.         cnserr = /*MSG49*/"ñ║│í┐∙╗~ í╨ ╡L¬k¿M⌐wíuªΓ╜╒ívíC";
  1461.         return False;
  1462.     }
  1463.  
  1464.     if (lightness == 0)
  1465.         k = defcnslit;
  1466.     else
  1467.         k = litetab[lightness];
  1468.  
  1469.     hsv_rgb(hue / 100.0, satab[saturation] / 10000.0, k / 10000.0,
  1470.             r, g, b);
  1471.     return True;
  1472. }
  1473.  
  1474. /*  CIXNAME  --  Find name of colour vocabulary word from its index.  */
  1475.  
  1476. static char *cixname(cx)
  1477.   colourvocab cx;
  1478. {
  1479.     int i;
  1480.  
  1481.     for (i = 0; i < ELEMENTS(cvocab); i++)
  1482.         if (cvocab[i].ccode == cx)
  1483.             break;
  1484.     return cvocab[i].cname;
  1485. }
  1486.  
  1487. /*  RGB_CNS  --  Find best CNS description for RGB colour expressed
  1488.                  in R, G, and B, from 0 to 1.  */
  1489.  
  1490. static void rgb_cns(r, g, b, cnstr)
  1491.   ads_real r, g, b;
  1492.   char *cnstr;
  1493. {
  1494.     int i, j = 0, k, d, s, v;
  1495.     long lh, ld, hd;
  1496.     ads_real rh, rs, rv;
  1497.  
  1498. #define C(x)  ((char) (x))
  1499. #define CV(x) ((colourvocab) (x))
  1500.  
  1501.     /* Grey scale name table */
  1502.  
  1503.     static struct {
  1504.        int intens;
  1505.        char gname[3];
  1506.     } gtab[] = {
  1507.        {0,     {C(Black),                  0}},
  1508.        {1700,  {C(Very),  C(Dark), C(Gray)  }},
  1509.        {3300,  {C(Dark),  C(Gray),         0}},
  1510.        {5000,  {C(Gray),                   0}},
  1511.        {6700,  {C(Light), C(Gray),         0}},
  1512.        {8300,  {C(Very),  C(Light), C(Gray) }},
  1513.        {10000, {C(White),                  0}}
  1514.       };
  1515.  
  1516.     /* Hue name table */
  1517.  
  1518.     static struct {
  1519.        long huecode;
  1520.        char purename,
  1521.             ishname;
  1522.     } huetab[] = {
  1523.        {0L,     C(Red),    C(Reddish)},
  1524.        {3000L,  C(Orange), C(Orangish)},
  1525.        {6000L,  C(Yellow), C(Yellowish)},
  1526.        {12000L, C(Green),  C(Greenish)},
  1527.        {24000L, C(Blue),   C(Bluish)},
  1528.        {30000L, C(Purple), C(Purplish)},
  1529.        {36000L, C(Red),    C(Reddish)}
  1530.       };
  1531.  
  1532.     /* Chromatic lightness table */
  1533.  
  1534.     static struct {
  1535.        int intens;
  1536.        char lname[2];
  1537.     } ltab[] = {
  1538.        {1250,  {C(Very), C(Dark)  }},
  1539.        {2500,  {C(Dark),         0}},
  1540.        {5000,  {C(Medium),       0}},
  1541.        {7500,  {C(Light),        0}},
  1542.        {10000, {C(Very), C(Light) }}
  1543.       };
  1544.  
  1545.     /* Chromatic saturation table */
  1546.  
  1547.     static struct {
  1548.        int satper;
  1549.        char sname;
  1550.     } stab[] = {
  1551.        {2500,  C(Grayish)  },
  1552.        {5000,  C(Moderate) },
  1553.        {7500,  C(Strong)   },
  1554.        {10000, C(Vivid)    }
  1555.       };
  1556.  
  1557.     cnstr[0] = EOS;
  1558.  
  1559.     rgb_hsv(r, g, b, &rh, &rs, &rv);
  1560.     lh = rh * 100L;
  1561.     s = rs * 10000;
  1562.     v = rv * 10000;
  1563.  
  1564.     if (s == 0) {
  1565.  
  1566.         /* Achromatic */
  1567.  
  1568.         d = 20000;
  1569.         for (i = 0; i < ELEMENTS(gtab); i++) {
  1570.             if (abs(gtab[i].intens - v) < d) {
  1571.                 d = abs(gtab[i].intens - v);
  1572.                 j = i;
  1573.             }
  1574.         }
  1575.         for (i = 0; i < 3; i++) {
  1576.             if (gtab[j].gname[i] == 0)
  1577.                 break;
  1578.             if (strlen(cnstr) > 0)
  1579.                 V strcat(cnstr, " ");
  1580.             V strcat(cnstr, cixname(CV(gtab[j].gname[i])));
  1581.         }
  1582.     } else {
  1583.  
  1584.         /* Chromatic.  */
  1585.  
  1586.         /* Locate intensity.   If  the  closest  intensity  is  the
  1587.            default  intensity  in  DEFCNSLIT,  we  don't  edit  any
  1588.            intensity.  You can disable this by setting DEFCNSLIT to
  1589.            -1.  */
  1590.  
  1591.         d = 20000;
  1592.         for (i = 0; i < ELEMENTS(ltab); i++) {
  1593.             if (abs(ltab[i].intens - v) < d) {
  1594.                 d = abs(ltab[i].intens - v);
  1595.                 j = i;
  1596.             }
  1597.         }
  1598.         if (ltab[j].intens != defcnslit) {
  1599.             for (i = 0; i < 2; i++) {
  1600.                 if (ltab[j].lname[i] == 0)
  1601.                     break;
  1602.                 if (strlen(cnstr) > 0)
  1603.                     V strcat(cnstr, " ");
  1604.                 V strcat(cnstr, cixname(CV(ltab[j].lname[i])));
  1605.             }
  1606.         }
  1607.  
  1608.         /* Locate saturation.  If the saturation is vivid, nothing
  1609.            is edited. */
  1610.  
  1611.         d = 20000;
  1612.         for (i = 0; i < ELEMENTS(stab); i++) {
  1613.             if (abs(stab[i].satper - s) <= d) {
  1614.                 d = abs(stab[i].satper - s);
  1615.                 j = i;
  1616.             }
  1617.         }
  1618.         if (stab[j].satper != 10000) {
  1619.             if (strlen(cnstr) > 0)
  1620.                 V strcat(cnstr, " ");
  1621.             V strcat(cnstr, cixname(CV(stab[j].sname)));
  1622.         }
  1623.  
  1624.         if (strlen(cnstr) > 0)
  1625.             V strcat(cnstr, " ");
  1626.  
  1627.         /* Find closest hue name. */
  1628.  
  1629.         ld = 100000L;
  1630.         if (lh == 36000L)
  1631.             lh = 0;
  1632.         for (i = 0; i < ELEMENTS(huetab); i++) {
  1633.             if (abs(huetab[i].huecode - lh) < ld) {
  1634.                 ld = abs(huetab[i].huecode - lh);
  1635.                 j = i;
  1636.             }
  1637.         }
  1638.  
  1639.         /* Now we'll find the next hue in the direction of the
  1640.            actual hue from the specified hue. */
  1641.  
  1642.         if (lh > huetab[j].huecode) {
  1643.             if (j == (ELEMENTS(huetab) - 1))
  1644.                 k = 1;
  1645.             else
  1646.                 k = j + 1;
  1647.         } else {
  1648.             if (j == 0)
  1649.                 k = ELEMENTS(huetab) - 2;
  1650.             else
  1651.                 k = j - 1;
  1652.         }
  1653.  
  1654.         /* Next, compute the distance between the hue and the next
  1655.            neighbour in the hue's direction.  */
  1656.  
  1657.         hd = abs(huetab[j].huecode - huetab[k].huecode);
  1658.  
  1659.         /* The  form of the hue then  depends upon the relationship
  1660.            between the actual distance, D, and the total  distance,
  1661.            HD,  from the closest pure hue, J, and the next pure hue
  1662.            in the direction of the hue supplied,  K.   We  generate
  1663.            the following based upon the relationship:
  1664.  
  1665.                  D / HD          Name
  1666.               ------------     --------
  1667.               0     - 0.125       J
  1668.               0.125 - 0.375     Kish J
  1669.               0.375 - 0.5        J-K
  1670.         */
  1671.  
  1672.         hd = (ld * 10000L) / hd;
  1673.         if (hd < 1250L) {
  1674.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1675.         } else if (hd < 3750L) {
  1676.             V strcat(cnstr, cixname(CV(huetab[k].ishname)));
  1677.             V strcat(cnstr, " ");
  1678.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1679.         } else {
  1680.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1681.             V strcat(cnstr, "-");
  1682.             V strcat(cnstr, cixname(CV(huetab[k].purename)));
  1683.         }
  1684.     }
  1685. }
  1686.  
  1687. /*  ACADRGB  --  Takes  an  AutoCAD  colour  number in hsv and returns
  1688.                  red, green, and blue intensities in rgp in the  range
  1689.                  0.0 to 1.0 */
  1690.  
  1691. static void acadrgb(hsv, rgp)
  1692.   int  hsv;
  1693.   struct r_g_b *rgp;
  1694. {
  1695.     static ads_real brightfac[5] = {  /* Brightness levels */
  1696.        1.0, 0.65, 0.5, 0.3, 0.15
  1697.       }, halfsat = .5;                /* Halfway saturation */
  1698.     int ih, vs;
  1699.     ads_real h, s, f, value;
  1700.  
  1701.     assert(hsv > 0 || hsv < 256);
  1702.  
  1703.     switch (hsv) {
  1704.     case BLACK:
  1705.         rgp->red   = 0.0;
  1706.         rgp->blue  = 0.0;
  1707.         rgp->green = 0.0;
  1708.         value = 0.0;
  1709.         break;
  1710.  
  1711.     case RED:
  1712.         rgp->red   = SAT;
  1713.         rgp->green = 0.0;
  1714.         rgp->blue  = 0.0;
  1715.         value = 1.0;
  1716.         break;
  1717.  
  1718.     case YELLOW:
  1719.         rgp->red   = SAT;
  1720.         rgp->green = SAT;
  1721.         rgp->blue  = 0.0;
  1722.         value = 1.0;
  1723.         break;
  1724.  
  1725.     case GREEN:
  1726.         rgp->red   = 0.0;
  1727.         rgp->green = SAT;
  1728.         rgp->blue  = 0.0;
  1729.         value = 1.0;
  1730.         break;
  1731.  
  1732.     case CYAN:
  1733.         rgp->red   = 0.0;
  1734.         rgp->green = SAT;
  1735.         rgp->blue  = SAT;
  1736.         value = 1.0;
  1737.         break;
  1738.  
  1739.     case BLUE:
  1740.         rgp->red   = 0.0;
  1741.         rgp->green = 0.0;
  1742.         rgp->blue  = SAT;
  1743.         value = 1.0;
  1744.         break;
  1745.  
  1746.     case MAGENTA:
  1747.         rgp->red   = SAT;
  1748.         rgp->green = 0.0;
  1749.         rgp->blue  = SAT;
  1750.         value = 1.0;
  1751.         break;
  1752.  
  1753.     case WHITE:
  1754.     case 8:
  1755.     case 9:
  1756.         rgp->red   = SAT;
  1757.         rgp->green = SAT;
  1758.         rgp->blue  = SAT;
  1759.         value = 1.0;
  1760.         break;
  1761.  
  1762.     default:
  1763.  
  1764.         /*  The chromatic colors.  The  hue  resulting  from  an
  1765.             AutoCAD color 10-249 will be determined by its first
  1766.             two digits, and the saturation and  value  from  the
  1767.             last digit, as follows:
  1768.  
  1769.             Hues:
  1770.  
  1771.              10 -- Red
  1772.              50 -- Yellow
  1773.              90 -- Green
  1774.             130 -- Cyan
  1775.             170 -- Blue
  1776.             210 -- Magenta
  1777.  
  1778.             Between  each  of these are three intermediate hues,
  1779.             e.g., between red and yellow, we have:
  1780.  
  1781.              20 -- reddish orange
  1782.              30 -- orange
  1783.              40 -- yellowish orange
  1784.  
  1785.             To each hue number, 0, 2, 4, 6, or 8 can be added to
  1786.             give a different "value", or brightness, with 0  the
  1787.             brightest  and  8  the  weakest.   Finally, 1 can be
  1788.             added to  produce  a  "half-saturated",  or  pastel,
  1789.             color.  For example, color 18 is the dimmest red and
  1790.             10 the brightest red.  19 is the dimmest pink and 11
  1791.             the brightest pink.
  1792.         */
  1793.  
  1794.         if (hsv > 9 && hsv < 250) {
  1795.  
  1796.             /* Apply the algorithm from Foley & van Dam to turn
  1797.                HSV into RGB values */
  1798.  
  1799.             ih = (hsv - 10) / 10;     /* Integer hue value. */
  1800.             if (ih >= 24)             /* Range is 0-23. */
  1801.                 ih -= 24;
  1802.             vs = hsv % 10;            /* Encoded value and saturation */
  1803.             h = ih / 4.;              /* Map into range [0.0,6.0) */
  1804.             ih = h;                   /* The integer part. */
  1805.             f = h - ih;               /* Fractional part. */
  1806.             value = brightfac[vs >> 1]; /* Value in [0,1] */
  1807.             s = vs & 1 ? halfsat : 1.0; /* Saturation */
  1808.  
  1809.             switch (ih) {
  1810.             case 0:
  1811.                 rgp->red   = 1.0;
  1812.                 rgp->green = (ads_real) (1.0 - s * (1.0 - f));
  1813.                 rgp->blue  = (ads_real) (1.0 - s);
  1814.                 break;
  1815.  
  1816.             case 1:
  1817.                 rgp->red   = (ads_real) (1.0 - s * f);
  1818.                 rgp->green = 1.0;
  1819.                 rgp->blue  = (ads_real) (1 - s);
  1820.                 break;
  1821.  
  1822.             case 2:
  1823.                 rgp->red   = (ads_real) (1.0 - s);
  1824.                 rgp->green = 1.0;
  1825.                 rgp->blue  = (ads_real) (1.0 - s *(1.0 - f));
  1826.                 break;
  1827.  
  1828.             case 3:
  1829.                 rgp->red   = (ads_real) (1.0 - s);
  1830.                 rgp->green = (ads_real) (1.0 - s * f);
  1831.                 rgp->blue  = 1.0;
  1832.                 break;
  1833.  
  1834.             case 4:
  1835.                 rgp->red   = (ads_real) (1.0 - s * (1.0 - f));
  1836.                 rgp->green = (ads_real) (1.0 - s);
  1837.                 rgp->blue  = 1.0;
  1838.                 break;
  1839.  
  1840.             case 5:
  1841.                 rgp->red   = 1.0;
  1842.                 rgp->green = (ads_real) (1.0 - s);
  1843.                 rgp->blue  = (ads_real) (1.0 - s * f);
  1844.                 break;
  1845.             }
  1846.         } else {
  1847.             /* Define some extra colours from dark grey to white
  1848.                in the 250 to 255 slots */
  1849.             value = 0.33 + (hsv - 250) * 0.134;
  1850.             rgp->red   = 1.0;
  1851.             rgp->green = 1.0;
  1852.             rgp->blue  = 1.0;
  1853.         }
  1854.         break;                        /* Default */
  1855.     }
  1856.     rgp->red   *= value;              /* Apply lightness scale factor */
  1857.     rgp->green *= value;              /* to components resulting from */
  1858.     rgp->blue  *= value;              /* hue and saturation. */
  1859. }
  1860.  
  1861. /*  RGBACAD  --  Find the AutoCAD colour closest to in RGB space to a
  1862.                  specified RGB triple.  */
  1863.  
  1864. static int rgbacad(r, g, b)
  1865.   ads_real r, g, b;
  1866. {
  1867.     int i, low, ccol;
  1868.     ads_real closest = 1000.0;
  1869.     struct r_g_b rc;
  1870.  
  1871.     assert(r >= 0.0 && r <= 1.0);
  1872.     assert(g >= 0.0 && g <= 1.0);
  1873.     assert(b >= 0.0 && b <= 1.0);
  1874.  
  1875.     /* If we're mapping to the 8 colour gamut, turn all grey scale
  1876.        colours into white and map the rest based on hue alone. */
  1877.  
  1878.     if (gamut == 8) {
  1879.         ads_real h, s, v;
  1880.  
  1881.         rgb_hsv(r, g, b, &h, &s, &v);
  1882.         return s == 0.0 ? WHITE :
  1883.                (RED + ((((int) (h + 30.0)) % 360) / 60));
  1884.     }
  1885.  
  1886.     /* Note  that we start with  colour 1 since 0 (black) is not a
  1887.        valid user-specified colour.  If this is a grey scale tone,
  1888.        map only to AutoCAD's grey scale indices.  */
  1889.  
  1890.     ccol = low = (r == g && r == b) ? 250 : 1;
  1891.  
  1892.     for (i = low; i < 256; i++) {
  1893.         ads_real cdist;
  1894.  
  1895.         acadrgb(i, &rc);
  1896.         rc.red -= r;
  1897.         rc.green -= g;
  1898.         rc.blue -= b;
  1899.         cdist = rc.red * rc.red + rc.green * rc.green +
  1900.                 rc.blue * rc.blue;
  1901.         if (cdist < closest) {
  1902.             ccol = i;
  1903.             if ((closest = cdist) == 0.0)
  1904.                 break;
  1905.         }
  1906.     }
  1907.     if (ccol == 255)                  /* If synonym for white... */
  1908.         ccol = 7;                     /* ...make simple white. */
  1909.     return ccol;
  1910. }
  1911.  
  1912. /*  RETRGB  --  Return an RGB triple as either an RGB point or
  1913.                 the closest AutoCAD standard colour.  */
  1914.  
  1915. static void retrgb(acad, r, g, b)
  1916.   Boolean acad;
  1917.   ads_real r, g, b;
  1918. {
  1919.     if (acad) {
  1920.         ads_retint(rgbacad(r, g, b));
  1921.     } else {
  1922.         ads_point p;
  1923.  
  1924.         Spoint(p, r, g, b);
  1925.         ads_retpoint(p);
  1926.     }
  1927. }
  1928.  
  1929. /*  TRIPLE  --  Scan  a  triple  of  real  arguments  into an array of
  1930.                 reals.  Integers are accepted and converted to  reals.
  1931.                 True  is  returned  if  valid  arguments are obtained;
  1932.                 False otherwise.  */
  1933.  
  1934. static Boolean triple(cdesc, rangecheck)
  1935.   ads_real cdesc[3];
  1936.   Boolean rangecheck;
  1937. {
  1938.     int nargs;
  1939.     struct resbuf *rb1 = ads_getargs();
  1940.  
  1941.     ads_retnil();
  1942.     for (nargs = 0; nargs < 3; nargs++) {
  1943.         if (rb1 == NULL)
  1944.             break;
  1945.         if (rb1->restype == RTSHORT) {
  1946.             cdesc[nargs] = rb1->resval.rint;
  1947.         } else if (rb1->restype == RTREAL) {
  1948.             cdesc[nargs] = rb1->resval.rreal;
  1949.         } else if (nargs == 0 && rb1->restype == RT3DPOINT) {
  1950.             Cpoint(cdesc, rb1->resval.rpoint);
  1951.             nargs = 2;
  1952.         } else {
  1953.             ads_fail(/*MSG50*/"íuñ▐╝╞½¼║Aívª│╗~");
  1954.             return False;
  1955.         }
  1956.         rb1 = rb1->rbnext;
  1957.     }
  1958.  
  1959.     /* Make sure there were enough arguments. */
  1960.  
  1961.     if (nargs < 3) {
  1962.         ads_fail(/*MSG51*/"íuñ▐╝╞ív╣Lñ╓");
  1963.         return False;
  1964.     }
  1965.  
  1966.     /* Make sure there are no more arguments. */
  1967.  
  1968.     if (rb1 != NULL) {
  1969.         ads_fail(/*MSG52*/"íuñ▐╝╞ív╣Lªh");
  1970.         return False;
  1971.     }
  1972.  
  1973.     /* Range check arguments if requested. */
  1974.  
  1975.     if (rangecheck) {
  1976.         for (nargs = 0; nargs < 3; nargs++) {
  1977.             if (rangecheck && (cdesc[nargs] < 0.0 || cdesc[nargs] > 1.0)) {
  1978.                 ads_fail(/*MSG53*/"íuñ▐╝╞ív╢WÑX╜d│≥");
  1979.                 return False;
  1980.             }
  1981.         }
  1982.     }
  1983.  
  1984.     return True;
  1985. }
  1986.  
  1987. /*  CMY  --  Specify colour as CMY triple.  */
  1988.  
  1989. static void cmy(acad)
  1990.   Boolean acad;
  1991. {
  1992.     ads_real cdesc[3];
  1993.  
  1994.     if (triple(cdesc, True)) {
  1995.         retrgb(acad, 1.0 - cdesc[0], 1.0 - cdesc[1],
  1996.                1.0 - cdesc[2]);
  1997.     }
  1998. }
  1999.  
  2000. /*  CTEMP  --  Specify colour as a colour temperature.  */
  2001.  
  2002. static void ctemp(acad)
  2003.   Boolean acad;
  2004. {
  2005.     struct resbuf *rb;
  2006.  
  2007.     ads_retnil();
  2008.  
  2009.     if ((rb = ads_getargs()) == NULL) {
  2010.         ads_fail(/*MSG63*/"íuñ▐╝╞ív╣Lñ╓");
  2011.     } else {
  2012.         ads_real degrees, ir, ig, ib;
  2013.  
  2014.         if (rb->restype == RTSHORT) {
  2015.             degrees = rb->resval.rint;
  2016.         } else if (rb->restype == RTREAL) {
  2017.             degrees = rb->resval.rreal;
  2018.         } else {
  2019.             ads_fail(/*MSG64*/"íuñ▐╝╞½¼║Aívª│╗~");
  2020.             return;
  2021.         }
  2022.  
  2023.         /* Make sure there are no more arguments. */
  2024.  
  2025.         if (rb->rbnext != NULL) {
  2026.             ads_fail(/*MSG65*/"íuñ▐╝╞ív╣Lªh");
  2027.             return;
  2028.         }
  2029.  
  2030.         ctemp_rgb(degrees, &ir, &ig, &ib);
  2031.         retrgb(acad, ir, ig, ib);
  2032.     }
  2033. }
  2034.  
  2035. /*  CNS  --  Specify colour as a CNS string.  */
  2036.  
  2037. static void cns(acad)
  2038.   Boolean acad;
  2039. {
  2040.     struct resbuf *rb;
  2041.  
  2042.     ads_retnil();
  2043.  
  2044.     if ((rb = ads_getargs()) == NULL) {
  2045.         ads_fail(/*MSG54*/"íuñ▐╝╞ív╣Lñ╓");
  2046.         return;
  2047.     } else {
  2048.         struct resbuf *rb1 = rb;
  2049.         ads_real ir, ig, ib;
  2050.  
  2051.         if (rb1->restype != RTSTR) {
  2052.             ads_fail(/*MSG55*/"íuñ▐╝╞½¼║Aívª│╗~");
  2053.             return;
  2054.         }
  2055.  
  2056.         /* Make sure there are no more arguments. */
  2057.  
  2058.         if (rb1->rbnext != NULL) {
  2059.             ads_fail(/*MSG56*/"íuñ▐╝╞ív╣Lªh");
  2060.             return;
  2061.         }
  2062.  
  2063.         if (cns_rgb(rb1->resval.rstring, &ir, &ig, &ib)) {
  2064.             retrgb(acad, ir, ig, ib);
  2065.         }
  2066.     }
  2067. }
  2068.  
  2069. /*  CNSER  --  Return string describing last CNS error, if any.  */
  2070.  
  2071. static void cnser()
  2072. {
  2073.     if (cnserr == NULL)
  2074.         ads_retnil();
  2075.     else
  2076.         ads_retstr(cnserr);
  2077. }
  2078.  
  2079. /*  HLS  --  Specify colour as HLS triple.  */
  2080.  
  2081. static void hls(acad)
  2082.   Boolean acad;
  2083. {
  2084.     ads_real cdesc[3];
  2085.  
  2086.     if (triple(cdesc, True)) {
  2087.         ads_real ir, ig, ib;
  2088.  
  2089.         hls_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
  2090.         retrgb(acad, ir, ig, ib);
  2091.     }
  2092. }
  2093.  
  2094. /*  HSV  --  Specify colour as HSV triple.  */
  2095.  
  2096. static void hsv(acad)
  2097.   Boolean acad;
  2098. {
  2099.     ads_real cdesc[3];
  2100.  
  2101.     if (triple(cdesc, True)) {
  2102.         ads_real ir, ig, ib;
  2103.  
  2104.         hsv_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
  2105.         retrgb(acad, ir, ig, ib);
  2106.     }
  2107. }
  2108.  
  2109. /*  RGB  --  Specify colour as RGB triple.  */
  2110.  
  2111. static void rgb(acad)
  2112.   Boolean acad;
  2113. {
  2114.     ads_real cdesc[3];
  2115.  
  2116.     if (triple(cdesc, True)) {
  2117.         retrgb(acad, cdesc[0], cdesc[1], cdesc[2]);
  2118.     }
  2119. }
  2120.  
  2121. /*  YIQ  --  Specify colour as YIQ triple.  */
  2122.  
  2123. static void yiq(acad)
  2124.   Boolean acad;
  2125. {
  2126.     ads_real cdesc[3];
  2127.  
  2128.     if (triple(cdesc, False)) {
  2129.         ads_real ir, ig, ib;
  2130.  
  2131.         if ((cdesc[0] < 0.0 || cdesc[0] > 1.0) &&
  2132.             (cdesc[1] < -0.6 || cdesc[0] > 0.6) &&
  2133.             (cdesc[2] < -0.52 || cdesc[2] > 0.52)) {
  2134.             ads_fail(/*MSG57*/"íuñ▐╝╞ív╢WÑX╜d│≥");
  2135.         }
  2136.  
  2137.         yiq_rgb(cdesc[0], cdesc[1], cdesc[2], &ir, &ig, &ib);
  2138.  
  2139.         retrgb(acad, ir, ig, ib);
  2140.     }
  2141. }
  2142.  
  2143. /*  Colour system to AutoCAD colour functions. */
  2144.  
  2145. static void cmyac()   { cmy(True);   }
  2146. static void ctempac() { ctemp(True); }
  2147. static void yiqac()   { yiq(True);   }
  2148. static void hsvac()   { hsv(True);   }
  2149. static void rgbac()   { rgb(True);   }
  2150. static void hlsac()   { hls(True);   }
  2151. static void cnsac()   { cns(True);   }
  2152.  
  2153. /*  Colour system to RGB functions.  */
  2154.  
  2155. static void cmyrgb()   { cmy(False);   }
  2156. static void ctemprgb() { ctemp(False); }
  2157. static void yiqrgb()   { yiq(False);   }
  2158. static void hsvrgb()   { hsv(False);   }
  2159. static void hlsrgb()   { hls(False);   }
  2160. static void cnsrgb()   { cns(False);   }
  2161.  
  2162. /*  ACADCOL  --  Obtain AutoCAD colour.  We accept any of the following:
  2163.  
  2164.     1.  A single integer, representing an AutoCAD standard colour index.
  2165.     2.  A triple of reals and/or integers, representing RGB intensities.
  2166.     3.  A list of three reals and/or integers, representing RGB intensities.
  2167. */
  2168.  
  2169. static Boolean acadcol(rp)
  2170.   struct r_g_b *rp;
  2171. {
  2172.     ads_real crgb[3];
  2173.     struct resbuf *rb = ads_getargs();
  2174.  
  2175.     ads_retnil();
  2176.  
  2177.     if (rb == NULL) {
  2178.         ads_fail(/*MSG58*/"íuñ▐╝╞ív╣Lñ╓");
  2179.         return False;
  2180.     }
  2181.  
  2182.     if ((rb->restype == RTSHORT) && (rb->rbnext == NULL)) {
  2183.         int cindex = rb->resval.rint;
  2184.  
  2185.         if (cindex < 0 || cindex > 255) {
  2186.             ads_fail(/*MSG59*/"íuñ▐╝╞ív╢WÑX╜d│≥");
  2187.             return False;
  2188.         }
  2189.         acadrgb(cindex, rp);
  2190.         return True;
  2191.     }
  2192.  
  2193.     if (triple(crgb, True)) {
  2194.         rp->red   = crgb[0];
  2195.         rp->green = crgb[1];
  2196.         rp->blue  = crgb[2];
  2197.     } else {
  2198.         return False;
  2199.     }
  2200.  
  2201.     return True;
  2202. }
  2203.  
  2204. /*  TORGB  --  Convert internal colour to RGB triple.  */
  2205.  
  2206. static void torgb()
  2207. {
  2208.     struct r_g_b rc;
  2209.  
  2210.     if (acadcol(&rc)) {
  2211.         ads_point p;
  2212.  
  2213.         Spoint(p, rc.red, rc.green, rc.blue);
  2214.         ads_retpoint(p);
  2215.     }
  2216. }
  2217.  
  2218. /*  TOCMY  --  Convert internal colour to CMY triple.  */
  2219.  
  2220. static void tocmy()
  2221. {
  2222.     struct r_g_b rc;
  2223.  
  2224.     if (acadcol(&rc)) {
  2225.         ads_point p;
  2226.  
  2227.         rgb_cmy(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2228.         ads_retpoint(p);
  2229.     }
  2230. }
  2231.  
  2232. /*  TOYIQ  --  Convert internal colour to YIQ triple.  */
  2233.  
  2234. static void toyiq()
  2235. {
  2236.     struct r_g_b rc;
  2237.  
  2238.     if (acadcol(&rc)) {
  2239.         ads_point p;
  2240.  
  2241.         rgb_yiq(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2242.         ads_retpoint(p);
  2243.     }
  2244. }
  2245.  
  2246. /*  TOHSV  --  Convert internal colour to HSV triple.  */
  2247.  
  2248. static void tohsv()
  2249. {
  2250.     struct r_g_b rc;
  2251.  
  2252.     if (acadcol(&rc)) {
  2253.         ads_point p;
  2254.  
  2255.         rgb_hsv(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2256.         p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
  2257.         ads_retpoint(p);
  2258.     }
  2259. }
  2260.  
  2261. /*  TOHLS  --  Convert internal colour to HLS triple.  */
  2262.  
  2263. static void tohls()
  2264. {
  2265.     struct r_g_b rc;
  2266.  
  2267.     if (acadcol(&rc)) {
  2268.         ads_point p;
  2269.  
  2270.         rgb_hls(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2271.         p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
  2272.         ads_retpoint(p);
  2273.     }
  2274. }
  2275.  
  2276. /*  TOCNS  --  Convert internal colour to CNS string.  */
  2277.  
  2278. static void tocns()
  2279. {
  2280.     struct r_g_b rc;
  2281.  
  2282.     if (acadcol(&rc)) {
  2283.         char cnstr[40];
  2284.  
  2285.         rgb_cns(rc.red, rc.green, rc.blue, cnstr);
  2286.         ads_retstr(cnstr);
  2287.     }
  2288. }
  2289.  
  2290. /*  COLSET  --  Set colour gamut available.  */
  2291.  
  2292. static void colset()
  2293. {
  2294.     struct resbuf *rb = ads_getargs();
  2295.  
  2296.     ads_retnil();
  2297.  
  2298.     if (rb == NULL) {
  2299.         ads_retint(gamut);
  2300.         return;
  2301.     }
  2302.  
  2303.     if (rb->rbnext != NULL) {
  2304.         ads_fail(/*MSG60*/"íuñ▐╝╞ív╣Lªh");
  2305.         return;
  2306.     }
  2307.  
  2308.     if (rb->restype == RTSHORT) {
  2309.         int colsys = rb->resval.rint;
  2310.  
  2311.         switch (colsys) {
  2312.         case 8:
  2313.         case 256:
  2314.             gamut = colsys;
  2315.             ads_retint(gamut);
  2316.             break;
  2317.  
  2318.         default:
  2319.             ads_fail(/*MSG61*/"íuñ▐╝╞ív╢WÑX╜d│≥");
  2320.         }
  2321.         return;
  2322.     }
  2323.     ads_fail(/*MSG62*/"íuñ▐╝╞½¼║Aívª│╗~");
  2324. }
  2325.