What color space is Revit using?

What color space is Revit using?

jagostinho74
Collaborator Collaborator
4,647 Views
8 Replies
Message 1 of 9

What color space is Revit using?

jagostinho74
Collaborator
Collaborator

Hello,

 

I would like to get the colour name from the integers used to set the fill patterns colours.

What colour space is being used? It is not Hex or RBG?

Or can I find a list online for all the colours using that system so to create a dictionary?

 

Thank you

Assistant BIM/CAD Manager

Manchester, UK


0 Likes
Accepted solutions (1)
4,648 Views
8 Replies
Replies (8)
Message 2 of 9

jeremy_tammik
Alumni
Alumni

There are many lists of colour names around, e.g., on Wikipedia:

 

https://en.wikipedia.org/wiki/List_of_colors:_A%E2%80%93F

 

Are you interested in a programming solution using the API, or an end user approach?

 

If you are not doing anything programmatically, then unfortunately this is not the best place to ask such a question. Please note that this discussion forum is dedicated to programming Revit using the Revit API.

 

For a programmatic solution, it will help to determine where the fill pattern colour is accessible. You can use RevitLookup for that task. 

 

Once that is known, you can use a filtered element collector to retrieve all fill patterns, query them for their colour, create a sorted list of the unique colours in use and convert them to the corresponding colour names.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 9

jagostinho74
Collaborator
Collaborator

hI @jeremy_tammik ,

 

Thank you for your reply.

I am working on a renamer for Filled Regions that picks up on its properties for more consistent naming, using the following syntax

[Description][ForegroundPatternName][ForegroundColourName][BackgroundPatternName][BackgroundColourName]

 

I would like, thus, to write the script so that it looks at the integer and pushes the color name to the new Filled Region Type name.

 

I managed to get it to work by manually creating a dictionary with the integers and color names, see below, but I was looking at whether if there is a list for these integer values > color names.

 

Does this make sense to you?

 

colourDic = {
			0:'Black',
			16711680:'Blue',
			16776960:'Cyan',
			65280:'Green',
			16711935:'Magenta',
			255:'Red',
			65535:'Yellow',
			16777215:'White',
			8388608:'DarkBlue',
			8421376:'DarkCyan',
			32768:'DarkGreen',
			8388736:'DarkMagenta',
			128:'DarkRed',
			32896:'DarkBrown',
			9211020:'DarkGray',
			12632256:'LightGray'
			}

 

Assistant BIM/CAD Manager

Manchester, UK


0 Likes
Message 4 of 9

jagostinho74
Collaborator
Collaborator

oh...and YES! 🙂

I have used Revit Lookup for looking at the integer color values.

Fantastic tool.

Assistant BIM/CAD Manager

Manchester, UK


0 Likes
Message 5 of 9

RPTHOMAS108
Mentor
Mentor
Accepted solution

The integers are actually an alternate way of storing the RGB byte values. The post below notes how to convert between integer and RGB bytes.

 

The Building Coder: Changing Text Colour (typepad.com)

 

So there are more colours than names, you can have any colour that a 32bit integer will store.

 

Apart from the RGBA form (no A in Revit) there is also HSL (Hue, Saturation, Luminance). In my view HSL is better at categorizing the colours. Since the Hue part is mainly categorising the colour. Then the saturation and luminance parts are creating variations of that form of colour. It is easier to group all reds, greens and blues etc. since they are in one scale not a combination of three scales.

 

210424.png

As for naming things I would be using the numbers.

Message 6 of 9

jeremy_tammik
Alumni
Alumni

Glad that you find RevitLookup useful.

 

If you want to approach the task seriously, you will probably find the attached C module useful, originally implemented by John Walker, the main founder of Autodesk. I massaged it a bit to use in a C++ environment about 23 years ago. Time flies.

 

Cheers,

 

Jeremy

 

 

//
// colext.cpp - colour conversion
//
// Adapted for C++ by Jeremy Tammik, 1998-02-12.
//
/*
Autodesk ADS sample file.

DESCRIPTION:

AutoCAD colour manipulation functions

Designed and implemented in October of 1989 by John Walker

This ADS application permits AutoCAD colours to  be  specified
in  any  of  a  number  of  commonly-used colour systems.  The
application provides AutoLisp functions for each colour system
which  accept  the  parameters  which  define a colour in that
system and return the AutoCAD colour number from the  standard
palette  for  256  colour  devices which best approximates the
requested colour.

In  addition, functions are provided to convert either AutoCAD
colour indices  or  Red-Green-Blue  colour  triples  to  their
representation in each of the colour systems.

Finally, functions which convert  colours  in  non-RGB  colour
systems to RGB triples are provided.


COLOUR SYSTEMS
==============

The colour systems implemented are:

RGB      Colours  are  specified  as the  intensities  of  the
         three  additive  primary colours Red, Green, and Blue
         which generate the colour.  The intensities are given
         in the range from 0 to 1, with 0 indicating no  light
         of  that colour and 1 representing maximum intensity.

CMY      Colours  are  specified by  the  intensities  of  the
         subtractive   primary   colours  Cyan,  Magenta,  and
         Yellow.  The CMY system is used in composing ink  and
         toner  mixtures  for  subtractive printing processes.
         Intensities are specified in the range from 0  to  1,
         with  0  indicating  none  of  the  specified pigment
         present and 1 indicating the maximum amount.

YIQ      The  YIQ  system  is  used   to  encode  colours  for
         television broadcasting.  The YIQ system  remaps  the
         RGB  space such that Y represents a primary scaled to
         the human luminosity  response  curve.   Two  colours
         with the same Y values will be indistinguishable when
         viewed on a monochrome monitor; to guarantee  colours
         are  distinct  when viewed in monochrome, they should
         be converted to YIQ and  checked  for  a  substantial
         difference  in  Y.   Y  ranges from 0 to 1, with zero
         indicating black and 1 maximum intensity.  Since  the
         YIQ system is a remapping of the RGB colour cube by a
         nontrivial affine transformation, the I and Q  values
         in  the  YIQ  system do not "come out even"; I ranges
         from -0.6 to 0.6, and Q ranges from  -0.52  to  0.52.

HSV      The HSV system approximates the intuitive concepts of
         hue  (tint),  saturation  (shade), and value (tone or
         brightness), by mapping colours into a hexcone.   Hue
         is  specified  by  a number from 0 to 1, representing
         the  angle  around  the hue circle in fraction of the
         circumference of the hue wheel with red at 0,  yellow
         at  1/6,  and  so  on.   Saturation is expressed as a
         number from 0 to  1,  with  0  indicating  a  totally
         desaturated  shade  (grey  scale), and 1 a completely
         saturated  shade  (no  admixture  of  white).   Value
         expresses intensity from 0 to 1, with zero indicating
         black and 1 maximum intensity.

HLS      The  HLS system encodes the intuitive concepts of hue
         (tint),   lightness   (intensity),   and   saturation
         (shade), by mapping colours into  a  double  hexcone.
         The  HLS system is closely related to the HSV system,
         and can be thought of as the result of stretching the
         flat   end   of   the  HSV  hexcone  upward  until  a
         symmetrical   double   hexcone  is  formed.   Hue  is
         specified by a number from 0 to 1,  representing  the
         angle  around  the  hue  circle  in  fraction  of the
         circumference of the hue wheel with red at 0,  yellow
         at  1/6, and so on.  Lightness expresses intensity as
         a number from 0 to 1, with zero indicating black  and
         1  maximum  intensity.   Saturation is expressed as a
         number from 0 to  1,  with  0  indicating  a  totally
         desaturated  shade  (grey  scale), and 1 a completely
         saturated shade (no admixture of white).

CTEMP    The  CTEMP  system  specifies  colours  emitted  by a
         Planckian  (black  body)  radiator   with   a   given
         temperature   in   degrees  Kelvin.   Typical  colour
         temperatures are:

            The star Spica                  28000 K
            The star Sirius                 10700 K
            North sky light                  7500 K
            Average daylight                 6500 K
            Xenon lamp                       6000 K
            Typical sunlight + skylight      5500 K
            The star Betelgeuse              3400 K
            Tungsten/halogen lamps           3300 K
            Incandescent bulbs (100-200 W)   2900 K
            Sunlight at sunset               2000 K
            Candle flame                     1900 K

CNS      The CNS system expresses colours as English language
         names.

         A colour is specified in the CNS system by a sequence
         of  English  words.   CNS  colours  may be achromatic
         (grey scale values) or chromatic.  Chromatic  colours
         consist  of  a  hue  (dominant  spectral  component),
         saturation (the extent of dilution with  white),  and
         lightness  (intensity).   A chromatic hue is composed
         by naming and mixing the following primary hues:

            Red, Orange/Brown, Yellow, Green, Blue, Purple

         and secondary hues:

            Reddish, Orangish/Brownish, Yellowish,
            Greenish, Bluish, Purplish

         To  obtain  one of the primary hues, just specify its
         name,  e.g.   "Yellow".   To  obtain  a  hue  halfway
         between  two  primary  hues, compose the two bounding
         hues: for example "Yellow-green" (or  "Green-yellow";
         it  doesn't  matter  which  is  specified first).  To
         obtain a hue one quarter the distance from one colour
         to  an adjacent colour, compose the "ish" form of the
         adjacent  colour  with  the  primary   colour.    For
         example, the hues between Yellow and Green are named:

            Yellow
            Greenish yellow
            Yellow-green (or Green-yellow)
            Green

         Brown  is  a  somewhat  confusing  special case.  The
         colour we perceive as  brown  has  the  same  hue  as
         orange  but  when  seen  with  reduced saturation and
         intensity it appears as brown, a colour distinct from
         orange  (that's  why there's no brown in the rainbow,
         in case you've ever lost sleep pondering that  fact).
         To  compensate for this perceptual quirk, "brown" and
         "brownish" may be used as synonyms for  "orange"  and
         "orangish"  when  specifying  hues.   If  "brown"  or
         "brownish"  are  used,  the  default  saturation  and
         lightness  (see  below)  are  set  so  the orange hue
         appears brown; if explicit saturation  and  lightness
         are given orange and brown are synonymous.

         Lightness  (brightness or intensity) may be specified
         by adding one of  the  following  adjectives  to  the
         colour name:

            very dark
            dark
            medium
            light
            very light

         If  no  lightness  adjective  appears,  a  default is
         assumed (unless a brown hue was named, in which  case
         the default will be "light").  This diverges from the
         CNS specification in which omitted lightness defaults
         to medium intensity.

         Saturation (the degree of admixture of  white  light)
         is specified by the following adjectives:

            grayish (or greyish)
            moderate
            strong
            vivid

         "Vivid" denotes a fully saturated colour, and is  the
         default  (unless  a brown is specified, in which case
         the default saturation is "strong").

         Examples of chromatic colour specifications are:

            red
            blue-green
            purplish red
            very dark green
            strong yellow-green
            very light grayish greenish yellow

         the last  describing  the  colour  of  snow  I  don't
         recommend you eat.

         Achromatic  specifications describe 7 shades of grey,
         to wit:

            black
            very dark gray
            dark gray
            gray (or medium gray)
            light gray
            very light gray
            white

         in all cases "grey" may be used instead of "gray".

         Although the word order used herein is as  prescribed
         by the formal specification of CNS, my implementation
         is  totally  insensitive  to  word  order.   You  can
         specify  "yellow  greyish light greenish very" if you
         like, silly seems how notwithstanding it.


AUTOLISP-CALLABLE FUNCTIONS
===========================

Three groups of AutoLisp-callable functions  are  implemented.
The first convert specifications in external colour systems to
AutoCAD's internal colour indices.  These  functions  map  the
specifications  into either AutoCAD's standard 8 or 256 colour
palette.  The palette is selected with the (COLSET) function:

   (COLSET <gamut>)

where  <gamut>  is  either  8  or 256 to choose the colour set
desired.  (COLSET) returns the current colour gamut; if called
with  no  arguments, (COLSET) returns the current colour gamut
without changing it.  The following functions  return  AutoCAD
colour indices between 1 and <gamut> - 1.

   (CMY   <cyan> <magenta> <yellow>)
   (CMY '(<cyan> <magenta> <yellow>))

   (CNS "CNS colour name description")

   (CTEMP <temperature>)

   (HLS   <hue> <lightness> <saturation>)
   (HLS '(<hue> <lightness> <saturation>))

   (HSV   <hue> <saturation> <value>)
   (HSV '(<hue> <saturation> <value>))

   (RGB   <red> <green> <blue>)
   (RGB '(<<red> <green> <blue>))

   (YIQ   <Y-value> <I-value> <Q-value>)
   (YIQ '(<Y-value> <I-value> <Q-value>))

Except for the (CNS) function, which takes a string  argument,
and  (CTEMP)  which  takes  a  single numeric temperature, all
these  conversion  functions  accept  either  three  numerical
arguments  (either  integer  or  real),  or  a  list  of three
numbers.  Representing colour triples as lists,  in  the  same
manner as three-dimensional point co-ordinates, allows them to
be manipulated  as  units  and  operated  upon  with  AutoLisp
functions.  For example the (distance) function can be used to
determine distance in colour space  as  well  as  in  physical
space.  If invalid arguments are passed to these functions, an
error message is displayed and nil  is  returned.   The  (CNS)
function,  which can generate a wide variety of error messages
resulting from syntax errors  in  the  string  passed  to  it,
indicates  an error by returning nil.  A string describing the
most recent error  detected  by  the  (CNS)  function  can  be
obtained  by  calling (CNSERR).  If no error has been detected
by (CNS), (CNSERR) returns nil.

When passed valid arguments, all  of  these  functions  return
AutoCAD  colour  numbers  ranging  from  1  to  255.  They may
therefore be specified at any AutoCAD prompt which requests  a
colour number.

A   second   group   of  functions  converts  external  colour
specifications to lists of RGB  intensities.   Each  of  these
functions  takes  the  same  arguments  as the functions which
return AutoCAD colour indices.

   (CMY-RGB   <cyan> <magenta> <yellow>)
   (CMY-RGB '(<cyan> <magenta> <yellow>))

   (CNS-RGB "CNS colour name description")

   (CTEMP-RGB <temperature>)

   (HLS-RGB   <hue> <lightness> <saturation>)
   (HLS-RGB '(<hue> <lightness> <saturation>))

   (HSV-RGB   <hue> <saturation> <value>)
   (HSV-RGB '(<hue> <saturation> <value>))

   (YIQ-RGB   <Y-value> <I-value> <Q-value>)
   (YIQ-RGB '(<Y-value> <I-value> <Q-value>))

There  is  no RGB-RGB function; it would be simply an identity
function.

The  third family of functions converts AutoCAD colour indices
from 0 to 255 or RGB triples to their representation  in  each
of  the  external  colour  systems.   AutoCAD  colour  index 0
(black), which cannot be specified as  an  entity  colour,  is
nonetheless a valid argument to these functions.

   (TO-CMY <colour>)
   (TO-CNS <colour>)
   (TO-HLS <colour>)
   (TO-HSV <colour>)
   (TO-RGB <colour>)
   (TO-YIQ <colour>)

With  the  exception  of  (TO-CNS), which returns a CNS colour
specification string, all of these functions return a list  of
three  real numbers specifying the values in its colour system
corresponding to the AutoCAD colour index or RGB  triple.   If
an  RGB  triple  is  specified for <colour> it may be given as
three arguments or as a list of three numbers.


INTERNAL FUNCTIONS
==================

Internal conversion functions implemented in this  module  are
as  described  below.  Definitions are given as prototypes for
readability;  for  compatibility  with  older  compilers,  the
actual  code  is  not  prototyped.  All conversions are to and
from RGB--to get between two non-RGB systems, you must convert
through RGB.

                        CMY

void rgb_cmy(double r, double g, double b,
             double *c, double *m, double *y)
   Converts r, g, b (0 to 1) to c, m, y (0 to 1).

void cmy_rgb(double c, double m, double y,
             double *r, double *g, double *b)
   Converts c, m, y (0 to 1) to r, g, b (0 to 1).

                       CTEMP

void ctemp_rgb(double temperature,
               double *r, double *g, double *b)
   Converts a colour temperature specified in degrees Kelvin,
   to r, g, b (0 to 1).

                        YIQ

void rgb_yiq(double r, double g, double b,
             double *y, double *i, double *q)
   Converts r, g, b (0 to 1) to y (0 to 1), i (-0.6 to 0.6),
   and q (-0.52 to 0.52).

void yiq_rgb(double y, double i, double q,
             double *r, double *g, double *b)
   Converts y (0 to 1), i (-0.6 to 0.6), and q (-0.52 to 0.52)
   to r, g, b (0 to 1).

                        HSV

void rgb_hsv(double r, double g, double b,
             double *h, double *s, double *v)
   Converts r, g, b (0 to 1) to h (0 to 360), s (0 to 1),  and
   v  (0  to  1).  Note that rgb_hsv() returns hue in terms of
   degrees, not as a  fraction  of  circumference  as  do  the
   AutoLisp-callable functions.

void hsv_rgb(double h, double s, double v,
             double *r, double *g, double *b)
   Converts  h (0 to 360), s (0 to 1), and v (0 to 1) to r, g,
   b (0 to 1).  Note that rgb_hsv() expects hue  in  terms  of
   degrees,  not  as  a  fraction  of  circumference as do the
   AutoLisp-callable functions.

                        HLS

void rgb_hls(double r, double g, double b,
             double *h, double *l, double *s)
   Converts r, g, b (0 to 1) to h (0 to 360), l (0 to 1),  and
   s  (0  to  1).  Note that rgb_hls() returns hue in terms of
   degrees, not as a  fraction  of  circumference  as  do  the
   AutoLisp-callable functions.

void hls_rgb(double h, double l, double s,
             double *r, double *g, double *b)
   Converts  h (0 to 360), l (0 to 1), and s (0 to 1) to r, g,
   b (0 to 1).  Note that rgb_hls() expects hue  in  terms  of
   degrees,  not  as  a  fraction  of  circumference as do the
   AutoLisp-callable functions.

                        CNS

void rgb_cns(double r, double g, double b, char *cnstr)
   Edits  a  zero-terminated  CNS  description  of  the colour
   represented by r, g, and b (0 to 1), into the string cnstr.
   The  maximum  length of the edited string is 36 characters,
   so a buffer of at least 37 characters  should  be  supplied
   for  cnstr.   If  the lightness of the colour is closest to
   the CNS nomenclature for the default  lightness  stored  in
   the  scaled  integer  variable  defcnslit (initially 10000,
   representing 1),  no  intensity  is  edited.   The  default
   saturation of "vivid" is not edited.

bool cns_rgb(char *cns, double *r, double *g, double *b)
   Scans  a CNS specification in the string cns and stores RGB
   intensities in r, g, and b which range from 0 to 1.  If  no
   lightness  is  specified, the lightness (as defined for the
   HSV routines) in the  scaled  integer  defcnslit  is  used.
   This  value  is  initially  set  to  10000  for  a  default
   intensity of very light (maximum).  The function returns  1
   if  the  specification  is  valid and 0 if an incorrect CNS
   specification is supplied,  in  which  case  the  character
   pointer  cnserr  will  point to an error message describing
   the problem.


BIBLIOGRAPHY
============

Fundamentals of Interactive Computer Graphics
  by J. D. Foley and A. van Dam, Reading Massachusetts:
  Addison-Wesley, 1984.

Measuring Colour
  by R. W. G. Hunt, West Sussex England: Ellis Horwood
  Ltd., 1987.  (Distributed by John Wiley & Sons).

A New Color-Naming System for Graphics Languages
  by Toby Berk, Lee Brownston, and Arie  Kaufman,  Florida
  International  University,  IEEE  Computer  Graphics and
  Applications, May 1982, Page 37.

*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "rocad.h"
#include "roconst.h"
#include "strutil.h"
#include "colext.h"

#ifdef COLEXT_STANDALONE

/* ADS Function Table structure */
typedef struct {
  char  *name;
  void  (*fptr)();
} ftblent;

int funcLoad   (void);
int funcUnload (void);
int doFun      (void);


extern "C" {
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg,void * pkt);
}

/*  Data types
*/
typedef enum {false = 0, true = 1} bool;
#endif // COLEXT_STANDALONE

#define V (void)
#define EOS '\0'

/* Set point variable from three co-ordinates
*/
#define Spoint(pt, x, y, z)  pt[X] = (x);  pt[Y] = (y);  pt[Z] = (z)

/* Copy point
*/
#define Cpoint(d, s)   d[X] = s[X];  d[Y] = s[Y];  d[Z] = s[Z]

/* Utility definition to get an  array's  element  count  (at  compile
   time).   For  example:

       int  arr[] = {1,2,3,4,5};
       ...
       printf("%d", ELEMENTS(arr));

   would print a five.  ELEMENTS("abc") can also be used to  tell  how
   many  bytes are in a string constant INCLUDING THE TRAILING NULL.
*/
#define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))

/* Utility definitions
*/
#ifdef abs
#undef abs
#endif
#define abs(x)      ((x)<0 ? -(x) : (x))
#ifdef min
#undef min
#endif
#define min(a,b)    ((a)<(b) ? (a) : (b))
#ifdef max
#undef max
#endif
#define max(a,b)    ((a)>(b) ? (a) : (b))

#ifndef M_E
#define M_E     2.7182818284590452354
#endif

#define Tbit(x)  (tok & (1L << ((int) (x))))  /* Test token bit set */
#define Tb(x)    (1L << ((int) (x)))  /* Obtain bit to test */

/* AutoCAD standard color palette */

#define         BLACK           0
#define         RED             1
#define         YELLOW          2
#define         GREEN           3
#define         CYAN            4
#define         BLUE            5
#define         MAGENTA         6
#define         WHITE           7

#define         SAT             1.0

struct r_g_b {                        /* RGB colour description */
  double red, green, blue;
};

/*  Colour naming system vocabulary definition.  The vocabulary
  is defined in this somewhat unusal fashion to facilitate
  translation to languages other than English. */

typedef enum {
  /* Chromatic colours */
  Red, Orange, Brown, Yellow, Green, Blue, Purple,

  /* "ish" forms of chromatic colours */
  Reddish, Orangish, Brownish, Yellowish, Greenish, Bluish, Purplish,

  /* Achromatic names */
  Gray, Black, White,

  /* Lightness specifications */
  Very, Dark, Medium, Light,

  /* Saturation specifications */
  Grayish, Moderate, Strong, Vivid,

  /* Punctuation */
  Hyphen, Period, Huh
} colourvocab;

static struct {
  char *cname;
  colourvocab ccode;
} cvocab[] = {
  {/*MSG3*/"red", Red},
  {/*MSG4*/"orange", Orange},
  {/*MSG5*/"brown", Brown},
  {/*MSG6*/"yellow", Yellow},
  {/*MSG7*/"green", Green},
  {/*MSG8*/"blue", Blue},
  {/*MSG9*/"purple", Purple},

  {/*MSG10*/"reddish", Reddish},
  {/*MSG11*/"orangish", Orangish},
  {/*MSG12*/"brownish", Brownish},
  {/*MSG13*/"yellowish", Yellowish},
  {/*MSG14*/"greenish", Greenish},
  {/*MSG15*/"bluish", Bluish},
  {/*MSG16*/"purplish", Purplish},

  {/*MSG17*/"gray", Gray},
  {/*MSG18*/"grey", Gray},
  {/*MSG19*/"black", Black},
  {/*MSG20*/"white", White},

  {/*MSG21*/"very", Very},
  {/*MSG22*/"dark", Dark},
  {/*MSG23*/"medium", Medium},
  {/*MSG24*/"light", Light},

  {/*MSG25*/"grayish", Grayish},
  {/*MSG26*/"greyish", Grayish},
  {/*MSG27*/"moderate", Moderate},
  {/*MSG28*/"strong", Strong},
  {/*MSG29*/"vivid", Vivid}
};

/* Table mapping generic hues to HSV hue indices. */

static struct {
  long cbit;
  int chue;
} colhue[] = {
  {Tb(Red),      0},            /* red */
  {Tb(Orange),  30},            /* orange */
  {Tb(Brown),  -30},            /* brown */
  {Tb(Yellow),  60},            /* yellow */
  {Tb(Green),  120},            /* green */
  {Tb(Blue),   240},            /* blue */
  {Tb(Purple), 300},            /* purple */
  {0L,         360}             /* red (other incarnation) */
};

/* Table mapping secondary hues to HSV hue indices. */

static struct {
  long cbit;
  int chue;
} ishhue[] = {
  {Tb(Reddish),      0},        /* reddish */
  {Tb(Orangish),    30},        /* orangish */
  {Tb(Brownish),   -30},        /* brownish */
  {Tb(Yellowish),   60},        /* yellowish */
  {Tb(Greenish),   120},        /* greenish */
  {Tb(Bluish),     240},        /* bluish */
  {Tb(Purplish),   300},        /* purplish */
  {0L,             360}         /* reddish (other incarnation) */
};

#define MAXTK    10                   /* Maximum tokens in specification */
#define MAXTKS   20                   /* Longest token in characters */

#define BROWNLIGHT  3                 /* Brown lightness:  Medium */
#define BROWNSAT    3                 /* Brown saturation: Strong */

/* Modal variables  */

static int defcnslit = 10000;         /* Default lightness if none specified */
static int gamut = 256;               /* Colour gamut available */

/*  Local variables  */

static char *cnserr = NULL;           /* Error message string */
static char cnserb[80];               /* Error message edit buffer */
static char tokenb[MAXTKS];           /* Token buffer */

/*  Forward functions  */

#define _(x) x

static void   hsv_rgb _((double,double,double,double *,double *,double *));
static void   rgb_hsv _((double,double,double,double *,double *,double *));
static void   rgb_hls _((double,double,double,double *,double *,double *));
static double hlsval _((double, double, double));
static void   hls_rgb _((double,double,double,double *,double *,double *));
static void   rgb_yiq _((double,double,double,double *,double *,double *));
static void   yiq_rgb _((double,double,double,double *,double *,double *));
static void   rgb_cmy _((double,double,double,double *,double *,double *));
static void   ctemp_rgb _((double, double *,double *,double *));
#ifdef NEEDED
static void   cmy_rgb _((double,double,double,double *,double *,double *));
#endif
static colourvocab token _((char **));
static bool    cns_rgb _((char *, double *, double *, double *));
static char    *cixname _((colourvocab));
static void    rgb_cns _((double, double, double, char *));
static void    acadrgb _((int, struct r_g_b *));
static int     rgbacad _((double, double, double));
static void    retrgb _((bool, double, double, double));
static bool    triple _((double *, bool));
static void    cmy _((bool));
static void    cns _((bool));
static void    cnser _((void));
static void    ctemp _((bool));
static void    hls _((bool));
static void    hsv _((bool));
static void    rgb _((bool));
static void    yiq _((bool));
static void    cmyac _((void));
static void    ctempac _((void));
static void    yiqac _((void));
static void    hsvac _((void));
static void    rgbac _((void));
static void    hlsac _((void));
static void    cnsac _((void));
static void    cmyrgb _((void));
static void    ctemprgb _((void));
static void    yiqrgb _((void));
static void    hsvrgb _((void));
static void    hlsrgb _((void));
static void    cnsrgb _((void));
static bool acadcol _((struct r_g_b *));
static void    torgb _((void));
static void    tocmy _((void));
static void    toyiq _((void));
static void    tohsv _((void));
static void    tohls _((void));
static void    tocns _((void));
static void    colset _((void));

#ifdef COLEXT_STANDALONE

/*  Colour system to AutoCAD colour functions. */

static void cmyac()   { cmy(true);   }
static void ctempac() { ctemp(true); }
static void yiqac()   { yiq(true);   }
static void hsvac()   { hsv(true);   }
static void rgbac()   { rgb(true);   }
static void hlsac()   { hls(true);   }
static void cnsac()   { cns(true);   }

/*  Colour system to RGB functions.  */

static void cmyrgb()   { cmy(false);   }
static void ctemprgb() { ctemp(false); }
static void yiqrgb()   { yiq(false);   }
static void hsvrgb()   { hsv(false);   }
static void hlsrgb()   { hls(false);   }
static void cnsrgb()   { cns(false);   }

/*  Command definition and dispatch table.  */

ftblent exfun[] = {

/*        Name         Function  */

/* External colour system to AutoCAD colour functions */

{/*MSG0*/"CMY",       cmyac},
{/*MSG0*/"CNS",       cnsac},
{/*MSG0*/"CTEMP",     ctempac},
{/*MSG0*/"HLS",       hlsac},
{/*MSG0*/"HSV",       hsvac},
{/*MSG0*/"RGB",       rgbac},
{/*MSG0*/"YIQ",       yiqac},

/* External colour system to RGB functions */

{/*MSG0*/"CMY-RGB",   cmyrgb},
{/*MSG0*/"CNS-RGB",   cnsrgb},
{/*MSG0*/"CTEMP-RGB", ctemprgb},
{/*MSG0*/"HLS-RGB",   hlsrgb},
{/*MSG0*/"HSV-RGB",   hsvrgb},
{/*MSG0*/"YIQ-RGB",   yiqrgb},

/* AutoCAD colour index to external colour system functions */

{/*MSG0*/"TO-RGB",    torgb},
{/*MSG0*/"TO-CMY",    tocmy},
{/*MSG0*/"TO-YIQ",    toyiq},
{/*MSG0*/"TO-HSV",    tohsv},
{/*MSG0*/"TO-HLS",    tohls},
{/*MSG0*/"TO-CNS",    tocns},

/* Control and utility functions */

{/*MSG0*/"CNSERR",    cnser},
{/*MSG0*/"COLSET",    colset}
};


/******************************************************************************/
/*.doc funcLoad(internal) */
/*+
    This function is called to define all function names in the ADS
    function table.  Each named function will be callable from lisp or
    invokable from another ADS application.
-*/
/******************************************************************************/
int
/*FCN*/funcLoad()
{
  int i;

  for (i = 0; i < ELEMENTS(exfun); i++) {
    if (!ads_defun(exfun[i].name, i))
      return RTERROR;
  }

  return RTNORM;
}


/******************************************************************************/
/*.doc funclUnload(internal) */
/*+
    This function is called to undefine all function names in the ADS
    function table.  Each named function will be removed from the
    AutoLISP hash table.
-*/
/******************************************************************************/
int
/*FCN*/funcUnload()
{
  int i;

  /* Undefine each function we defined */

  for (i = 0; i < ELEMENTS(exfun); i++) {
    ads_undef(exfun[i].name,i);
  }

  return RTNORM;
}


/******************************************************************************/
/*.doc doFun(internal) */
/*+
    This function is called to invoke the function which has the
    registerd function code that is obtained from  ads_getfuncode.  The
    function will return RTERROR if the function code is invalid, or
    RSERR if the invoked function fails to return RTNORM.  The value
    RSRSLT will be returned if the function code is valid and the
    invoked subroutine returns RTNORM.
-*/
/******************************************************************************/
int
/*FCN*/doFun()
{
  int  val;

  ads_retvoid();

  if ((val = ads_getfuncode()) < 0 || val > ELEMENTS(exfun))
    return RTERROR;

  (*exfun[val].fptr)();

  return RTNORM;
}


AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* ptr)
{

  if (ptr != NULL) {
    // We have been handed some kind of object
    // but we aren't going to do anything with it.
  }

  switch(msg) {
	  case AcRx::kInitAppMsg:
      acrxUnlockApplication(ptr);
      RO_SAY_WE_ARE_MDI_AWARE( ptr );
      break;
    case AcRx::kInvkSubrMsg:
      doFun();
      break;
    case AcRx::kLoadDwgMsg:
      funcLoad();
      break;
    case AcRx::kUnloadDwgMsg:
      funcUnload();
      ads_printf(/*MSG2*/"Unloading.\n");
      break;
	  case AcRx::kUnloadAppMsg:
      default:
      break;
  }
  return AcRx::kRetOK;
}
#endif // COLEXT_STANDALONE

/*      ***************************************************
        **                                               **
        **       Colour Interconversion Functions        **
        **                                               **
        ***************************************************
*/

/*  HSV_RGB  --  Convert HSV colour specification to RGB  intensities.
                 Hue is specified as a  real  value  from  0  to  360,
                 Saturation  and  Intensity as reals from 0 to 1.  The
                 RGB components are returned as reals from 0 to 1.      */

static void hsv_rgb(double h, double s, double v,
        double *r, double *g, double *b)
{
  int i;
  double f, p, q, t;

  if (s == 0) {
    *r = *g = *b = v;
  } else {
    if (h == 360.0)
      h = 0;
    h /= 60.0;

    i = (int)h;
    f = h - i;
    p = v * (1.0 - s);
    q = v * (1.0 - (s * f));
    t = v * (1.0 - (s * (1.0 - f)));
    // roassert(i >= 0 && i <= 5);
    switch (i) {

    case 0:
      *r = v;
      *g = t;
      *b = p;
      break;

    case 1:
      *r = q;
      *g = v;
      *b = p;
      break;

    case 2:
      *r = p;
      *g = v;
      *b = t;
      break;

    case 3:
      *r = p;
      *g = q;
      *b = v;
      break;

    case 4:
      *r = t;
      *g = p;
      *b = v;
      break;

    case 5:
      *r = v;
      *g = p;
      *b = q;
      break;
    }
  }
}

/*  RGB_HSV  --  Map R, G, B intensities in the range from 0 to 1 into
                 Hue, Saturation,  and  Value:  Hue  from  0  to  360,
                 Saturation  from  0  to  1,  and  Value  from 0 to 1.
                 Special case: if Saturation is 0 (it's a  grey  scale
                 tone), Hue is undefined and is returned as -1.

                 This follows Foley & van Dam, section 17.4.4.  */

static void rgb_hsv(double r, double g, double b,
  double *h, double *s, double *v)
{
  double imax = max(r, max(g, b)),
       imin = min(r, min(g, b)),
       rc, gc, bc;

  *v = imax;
  if (imax != 0)
    *s = (imax - imin) / imax;
  else
    *s = 0;

  if (*s == 0) {
    *h = -1;
  } else {
    rc = (imax - r) / (imax - imin);
    gc = (imax - g) / (imax - imin);
    bc = (imax - b) / (imax - imin);
    if (r == imax)
      *h = bc - gc;
    else if (g == imax)
      *h = 2.0 + rc - bc;
    else
      *h = 4.0 + gc - rc;
    *h *= 60.0;
    if (*h < 0.0)
      *h += 360.0;
  }
}

/*  RGB_HLS  --  Map R, G, B intensities in the range from 0 to 1 into
                 Hue, Lightness, and Saturation: Hue from  0  to  360,
                 Lightness  from  0  to 1, and Saturation from 0 to 1.
                 Special case: if Saturation is 0 (it's a  grey  scale
                 tone), Hue is undefined and is returned as -1.

                 This follows Foley & van Dam, section 17.4.5.  */

static void rgb_hls(double r, double g, double b,
  double *h, double *l, double *s)
{
  double imax = max(r, max(g, b)),
       imin = min(r, min(g, b)),
       rc, gc, bc;

  *l = (imax + imin) / 2;

  if (imax == imin) {
    *s = 0;
    *h = -1;
  } else {
    if (*l <= 0.5)
      *s = (imax - imin) / (imax + imin);
    else
      *s = (imax - imin) /
         (2.0 - imax - imin);

    rc = (imax - r) / (imax - imin);
    gc = (imax - g) / (imax - imin);
    bc = (imax - b) / (imax - imin);
    if (r == imax)
      *h = bc - gc;
    else if (g == imax)
      *h = 2.0 + rc - bc;
    else
      *h = 4.0 + gc - rc;
    *h *= 60.0;
    if (*h < 0)
      *h += 360.0;
  }
}

/*  HLS_RGB  --  Convert HLS colour specification to RGB  intensities.
                 Hue  is  specified  as  a  real  value from 0 to 360;
                 Lightness and Saturation as reals from 0 to  1.   The
                 RGB components are returned as reals from 0 to 1.      */

static double hlsval(double n1, double n2, double hue)
{
  if (hue > 360.0)
    hue -= 360.0;
  else if (hue < 0.0)
    hue += 360.0;
  if (hue < 60.0) {
    return n1 + ((n2 - n1) * hue) / 60.0;
  } else if (hue < 180.0) {
    return n2;
  } else if (hue < 240.0) {
    return n1 + ((n2 - n1) * (240.0 - hue)) / 60.0;
  } else {
    return n1;
  }
}

static void hls_rgb(double h, double l, double s,
  double *r, double *g, double *b)
{
  double m1, m2;

  if (l <= 0.5)
    m2 = l * (1.0 + s);
  else
    m2 = l + s - (l * s);
  m1 = 2 * l - m2;

  if (s == 0) {
    *r = *g = *b = l;
  } else {
    *r = hlsval(m1, m2, h + 120.0);
    *g = hlsval(m1, m2, h);
    *b = hlsval(m1, m2, h - 120.0);
  }
}

/*  RGB_YIQ  --  Convert RGB colour specification, R, G, B ranging
                 from 0 to 1, to Y, I, Q colour specification.

                 |Y|   |0.30  0.59  0.11|   |R|
                 |I| = |0.60 -0.28 -0.32| . |G|
                 |Q|   |0.21 -0.52  0.31|   |B|
*/

static void rgb_yiq(double r, double g, double b,
  double *y, double *i, double *q)
{
  double ay = (r * 0.30 + g *  0.59 + b *  0.11),
       ai = (r * 0.60 + g * -0.28 + b * -0.32),
       aq = (r * 0.21 + g * -0.52 + b *  0.31);

  *y = ay;
  if (ay == 1.0) {          /* Prevent round-off on grey scale */
    ai = aq = 0.0;
  }
  *i = ai;
  *q = aq;
}

/*  YIQ_RGB  --  Convert YIQ colour specification, Y, I,  Q  given  as
                 reals,  Y  from  0  to  1, I from -0.6 to 0.6, Q from
                 -0.52 to 0.52, to R, G, B intensities  in  the  range
                 from  0 to 1.  The matrix below is the inverse of the
                 RGB_YIQ matrix above.

                 |R|   |1.00  0.948  0.624|   |Y|
                 |G| = |1.00 -0.276 -0.640| . |I|
                 |B|   |1.00 -1.105  1.730|   |Q|
*/

static void yiq_rgb(double y, double i, double q,
  double *r, double *g, double *b)
{
  double ar = (y + i *   0.948 + q *  0.624),
       ag = (y + i *  -0.276 + q * -0.640),
       ab = (y + i *  -1.105 + q *  1.730);

  *r = max(0, min(1.0, ar));
  *g = max(0, min(1.0, ag));
  *b = max(0, min(1.0, ab));
}

/*  RGB_CMY  --  Convert RGB colour specification,  R,  G,  B  ranging
                 from  0  to  1, to C, M, Y colour specification, also
                 ranging from 0 to 1.

                 |C|   |1|   |R|
                 |M| = |1| - |G|
                 |Y|   |1|   |B|
*/

static void rgb_cmy(double r, double g, double b,
  double *c, double *m, double *y)
{
  *c = 1.0 - r;
  *m = 1.0 - g;
  *y = 1.0 - b;
}

#ifdef NEEDED

/*  CMY_RGB  --  Convert CMY colour specification,  C,  M,  Y  ranging
                 from  0  to  1, to R, G, B colour specification, also
                 ranging from 0 to 1.

                 |R|   |1|   |C|
                 |G| = |1| - |M|
                 |B|   |1|   |Y|
*/

static void cmy_rgb(double c, double m, double y,
  double *r, double *g, double *b)
{
  *r = 1.0 - c;
  *g = 1.0 - m;
  *b = 1.0 - y;
}
#endif

/*  CTEMP_RGB  --  Calculate the relative R, G, and B components for a
                   black body emitting light at a  given  temperature.
                   The  Planck  radiation  equation is solved directly
                   for the R, G, and B wavelengths defined for the CIE
                   1931  Standard  Colorimetric  Observer.  The colour
                   temperature is specified in degrees Kelvin. */

static void ctemp_rgb(double temp, double *r, double *g, double *b)
{
  double c1 = 3.74183e10,
       c2 = 14388.0,
       er, eg, eb, es;

/* Lambda is the wavelength in microns: 5500 angstroms is 0.55 microns. */

#define Planck(lambda)  ((c1 * pow((double) lambda, -5.0)) /  \
             (pow(M_E, c2 / (lambda * temp)) - 1))

  er = Planck(0.7000);
  eg = Planck(0.5461);
  eb = Planck(0.4358);
#undef Planck

  es = 1.0 / max(er, max(eg, eb));

  *r = er * es;
  *g = eg * es;
  *b = eb * es;
}

/*  TOKEN  --  Scan next token from the CNS string and update the
               scan pointer.  */

static colourvocab token(char **icp)
{
  char ch;
  char *cp = *icp, *tch;
  int i, t = 0;

  /* Ignore leading space */

  while (true) {
    ch = *cp++;
    if (!isSpace(ch))
      break;
  }

  if (ch == EOS)
    return Period;

  if (ch == '-') {
    *icp = cp;
    return Hyphen;
  }

  tch = cp - 1;           /* Start of token pointer */
  if (!isalpha(ch)) {
    *cp = EOS;
    *icp = tch;
    return Huh;
  }

  while (isalpha(ch)) {
    if (isupper(ch))
      ch = tolower(ch);
    if (t < ((sizeof tokenb) - 2))
      tokenb[t++] = ch;
    ch = *cp++;
  }
  tokenb[t] = EOS;
  *icp = cp - 1;

  for (i = 0; i < ELEMENTS(cvocab); i++) {
    if (strcmp(tokenb, cvocab[i].cname) == 0) {
      return cvocab[i].ccode;
    }
  }
  **icp = EOS;
  *icp = tch;
  return Huh;
}

/*  CNS_RGB  --  Convert a CNS string to RGB intensities scaled from 0
                 to 1.  If an invalid specification is made,  0
                 is returned and an error message is pointed to by the
                 global character pointer  cnserr.   Otherwise,  1  is
                 returned.  */

static bool cns_rgb(char *cns, double *r, double *g, double *b)
{
  int i, j, k = 0, lightness, saturation;
  long tok = 0L, hue;
  colourvocab t;
  static char conflite[] = /*MSG31*/"Conflicting lightness specification.";
  /* Grey scale table */
  static int greyscale[] = {50, 17, 33, 50, 67, 83};
  /* Saturation percentage table */
  static int satab[] = {10000, 2500, 5000, 7500, 10000};
  /* Chromatic lightness table */
  static int litetab[] = {5000, 1300, 2500, 5000, 7500, 10000};

  cnserr = NULL;          /* Initially no error in CNS string */
  j = strlen(cns);
  if (j == 0) {
    cnserr = /*MSG32*/"Void specification.";
    return false;
  }

  /* Scan string and parse tokens */

  while (true) {
    t = token(&cns);
    if (t == Huh) {
      V sprintf(cnserb, /*MSG33*/"Unrecognised symbol: `%s'.", cns);
      cnserr = cnserb;
      return false;
    }
    if (Tbit(t)) {
      V sprintf(cnserb, /*MSG34*/"Duplicate symbol: `%s'.", tokenb);
      cnserr = cnserb;
      return false;
    }
    if (t == Period)
      break;
    tok |= 1L << ((int) t);
  }

  /* Try to obtain lightness from specification */

  if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
    if (Tbit(Medium)) {
      if (Tbit(Very)) {
        cnserr = /*MSG35*/"Very used with Medium.";
        return false;
      }
      if (Tbit(Light) || Tbit(Dark)) {
        cnserr = conflite;
        return false;
      }
      lightness = 3;
    } else if (Tbit(Dark)) {
      lightness = Tbit(Very) ? 1 : 2;
      if (Tbit(Light)) {
        cnserr = conflite;
        return false;
      }
    } else if (Tbit(Light)) {
      lightness = Tbit(Very) ? 5 : 4;
    } else {
      cnserr = /*MSG36*/"Very used without Light or Dark.";
      return false;
    }
  } else {
    lightness = 0;
  }

  /* Test for achromatic colour specification. */

  i = !!(Tbit(Black)) + !!(Tbit(Gray)) + !!(Tbit(White));
  if (i > 0) {

    /* Test for conflicting specification of more than
       one achromatic colour. */

    if (i != 1) {
      cnserr = /*MSG37*/"Conflicting black/gray/white specification.";
      return false;
    }

    /* Test for specification of chromatic colour with
       achromatic colour. */

    if (tok & (Tb(Red) | Tb(Orange) | Tb(Brown) | Tb(Yellow) |
           Tb(Green) | Tb(Blue) | Tb(Purple))) {
      cnserr = /*MSG38*/"Chromatic and achromatic shade mixed.";
      return false;
    }

    /* Test for specification of chromatic colour ish form with
       achromatic colour. */

    if (tok & (Tb(Reddish) | Tb(Orangish) |
           Tb(Brownish) | Tb(Yellowish) |
           Tb(Greenish) | Tb(Bluish) | Tb(Purplish) |
           Tb(Hyphen))) {
      cnserr = /*MSG39*/"Chromatic modifier and achromatic shade mixed.";
      return false;
    }

    /* Test for saturation specification with achromatic shade. */

    if (tok & (Tb(Grayish) | Tb(Moderate) | Tb(Strong) | Tb(Vivid))) {
      cnserr = /*MSG40*/"Saturation specified with achromatic shade.";
      return false;
    }

    /* Test for lightness specified with White or Black. */

    if (Tbit(White) || Tbit(Black)) {
      if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
        cnserr = /*MSG41*/"Lightness specified with black or white.";
        return false;
      }
      if (Tbit(White)) {
        *r = *g = *b = 1.0;   /* White */
      } else {
        *r = *g = *b = 0;   /* Black */
      }
      return true;
    }

    /* Calculate grey scale value from lightness specification. */

    *r = *g = *b = greyscale[lightness] / 100.0;
    return true;
  }

  /* It isn't a grey scale, so it must be a chromatic colour
     specification.  Before we tear into the hue, let's try and
     determine the saturation. */

  i = (!!Tbit(Grayish)) + (!!Tbit(Moderate)) +
    (!!Tbit(Strong)) + (!!Tbit(Vivid));
  if (i > 0) {
    if (i > 1) {
      cnserr = /*MSG42*/"Conflicting saturation specification.";
      return false;
    }
    saturation = Tbit(Grayish) ? 1 :
           (Tbit(Moderate) ? 2 :
            (Tbit(Strong) ? 3 : 4));
  } else {
    saturation = 0;
  }

  /* Count primary hue specifications. */

  i = (!!Tbit(Red)) + (!!Tbit(Orange)) + (!!Tbit(Brown)) +
    (!!Tbit(Yellow)) +
    (!!Tbit(Green)) + (!!Tbit(Blue)) + (!!Tbit(Purple));

  if (i == 0) {
    cnserr = /*MSG43*/"No hue specified.";
    return false;
  }
  if (i > 2) {
    cnserr = /*MSG44*/"More than two hues specified.";
    return false;
  }

  /* Count secondary hue specifications. */

  j = (!!Tbit(Reddish)) + (!!Tbit(Orangish)) + (!!Tbit(Brownish)) +
    (!!Tbit(Yellowish)) +
    (!!Tbit(Greenish)) + (!!Tbit(Bluish)) + (!!Tbit(Purplish));

  if (j > 1) {
    cnserr = /*MSG45*/"More than one secondary hue specified.";
    return false;
  }
  if (i == 2 && j > 0) {
    cnserr = /*MSG46*/"Secondary hue specified with two primary hues.";
    return false;
  }

  /* Obtain hue based on form of specification we've determined
     is being made.

     Case 1.  Pure hue specified by a single primary hue. */

  hue = -1;
  if (i == 1 && j == 0) {
    for (i = 0; i < ELEMENTS(colhue); i++) {
      if (tok & colhue[i].cbit) {
        hue = abs(colhue[i].chue) * 100L;
        /* If it's brown, impute saturation and lightness
           if none was explicitly specified. */
        if (colhue[i].chue < 0) {
          if (lightness == 0)
            lightness = BROWNLIGHT;
          if (saturation == 0)
            saturation = BROWNSAT;
        }
        break;
      }
    }
  } else if (i == 2) {

    /* Case 2.  Halfway hue specified by composing two adjacent
          primary hues. */

    j = k = -1;
    for (i = 0; i < ELEMENTS(colhue); i++) {
      if (tok & colhue[i].cbit) {
        if (j < 0)
          j = i;
        else {
          k = i;
          break;
        }
      }
    }
    if ((colhue[j].chue == -colhue[k].chue) ||
      (((j + 1) != k) &&
       !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
       (!(j == 0 && k == (ELEMENTS(colhue) - 2))))) {
      cnserr = /*MSG47*/"Two primary hues are not adjacent.";
      return false;
    }

    if (Tbit(Red) && Tbit(Purple))
      j = ELEMENTS(colhue) - 1;

    hue = (abs(colhue[j].chue) + abs(colhue[k].chue)) * 50L;
    /* If either is brown, impute saturation and lightness
       if none was explicitly specified. */
    if (colhue[j].chue < 0 || colhue[k].chue < 0) {
      if (lightness == 0)
        lightness = BROWNLIGHT;
      if (saturation == 0)
        saturation = BROWNSAT;
    }
  } else {

    /* Case 3.  Quarterway hue specified by one primary hue
          and one secondary hue. */

    for (i = 0; i < ELEMENTS(colhue); i++) {
      if (tok & colhue[i].cbit) {
        j = i;
        break;
      }
    }
    for (i = 0; i < ELEMENTS(ishhue); i++) {
      if (tok & ishhue[i].cbit) {
        k = i;
        break;
      }
    }
    if ((colhue[j].chue == -colhue[k].chue) || (
         ((j + 1) != k) && ((j - 1) != k) &&
         !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
         !(k == 0 && j == 2) && !(k == 1 && j == 3) &&
         (!(j == 0 && k == (ELEMENTS(ishhue) - 2))) &&
         (!(k == 0 && j == (ELEMENTS(ishhue) - 2)))
        )
       ) {
      cnserr = /*MSG48*/"Primary and secondary hues are not adjacent.";
      return false;
    }

    if (Tbit(Red) && Tbit(Purplish))
      j = ELEMENTS(colhue) - 1;
    else if (Tbit(Purple) && Tbit(Reddish))
      k = ELEMENTS(ishhue) - 1;

    hue = (abs(colhue[j].chue) * 3 + abs(ishhue[k].chue)) * 25L;

    /* If either is brown, impute saturation and lightness
       if none was explicitly specified. */

    if (colhue[j].chue < 0 || ishhue[k].chue < 0) {
      if (lightness == 0)
        lightness = BROWNLIGHT;
      if (saturation == 0)
        saturation = BROWNSAT;
    }
  }

  if (hue < 0) {
    cnserr = /*MSG49*/"Internal error--cannot determine hue.";
    return false;
  }

  if (lightness == 0)
    k = defcnslit;
  else
    k = litetab[lightness];

  hsv_rgb(hue / 100.0, satab[saturation] / 10000.0, k / 10000.0,
      r, g, b);
  return true;
}

/*  CIXNAME  --  Find name of colour vocabulary word from its index.  */

static char *cixname( colourvocab cx)
{
  int i;

  for (i = 0; i < ELEMENTS(cvocab); i++)
    if (cvocab[i].ccode == cx)
      break;
  return cvocab[i].cname;
}

/*  RGB_CNS  --  Find best CNS description for RGB colour expressed
                 in R, G, and B, from 0 to 1.  */

static void rgb_cns(double r, double g, double b, char *cnstr)
{
  int i, j = 0, k, d, s, v;
  long lh, ld, hd;
  double rh, rs, rv;

#define C(x)  ((char) (x))
#define CVB(x) ((colourvocab) (x))

  /* Grey scale name table */

  static struct {
    int intens;
    char gname[3];
  } gtab[] = {
    {0,     {C(Black),                  0}},
    {1700,  {C(Very),  C(Dark), C(Gray)  }},
    {3300,  {C(Dark),  C(Gray),         0}},
    {5000,  {C(Gray),                   0}},
    {6700,  {C(Light), C(Gray),         0}},
    {8300,  {C(Very),  C(Light), C(Gray) }},
    {10000, {C(White),                  0}}
  };

  /* Hue name table */

  static struct {
    long huecode;
    char purename,
         ishname;
  } huetab[] = {
    {0L,     C(Red),    C(Reddish)},
    {3000L,  C(Orange), C(Orangish)},
    {6000L,  C(Yellow), C(Yellowish)},
    {12000L, C(Green),  C(Greenish)},
    {24000L, C(Blue),   C(Bluish)},
    {30000L, C(Purple), C(Purplish)},
    {36000L, C(Red),    C(Reddish)}
  };

  /* Chromatic lightness table */

  static struct {
    int intens;
    char lname[2];
  } ltab[] = {
    {1250,  {C(Very), C(Dark)  }},
    {2500,  {C(Dark),         0}},
    {5000,  {C(Medium),       0}},
    {7500,  {C(Light),        0}},
    {10000, {C(Very), C(Light) }}
  };

  /* Chromatic saturation table */

  static struct {
    int satper;
    char sname;
  } stab[] = {
    {2500,  C(Grayish)  },
    {5000,  C(Moderate) },
    {7500,  C(Strong)   },
    {10000, C(Vivid)    }
  };

  cnstr[0] = EOS;

  rgb_hsv(r, g, b, &rh, &rs, &rv);
  lh = (long)(rh * 100L);
  s = (int)(rs * 10000);
  v = (int)(rv * 10000);

  if (s == 0) {

    /* Achromatic */

    d = 20000;
    for (i = 0; i < ELEMENTS(gtab); i++) {
      if (abs(gtab[i].intens - v) < d) {
        d = abs(gtab[i].intens - v);
        j = i;
      }
    }
    for (i = 0; i < 3; i++) {
      if (gtab[j].gname[i] == 0)
        break;
      if (strlen(cnstr))
        V strcat(cnstr, " ");
      V strcat(cnstr, cixname(CVB(gtab[j].gname[i])));
    }
  } else {

    /* Chromatic.  */

    /* Locate intensity.   If  the  closest  intensity  is  the
       default  intensity  in  DEFCNSLIT,  we  don't  edit  any
       intensity.  You can disable this by setting DEFCNSLIT to
       -1.  */

    d = 20000;
    for (i = 0; i < ELEMENTS(ltab); i++) {
      if (abs(ltab[i].intens - v) < d) {
        d = abs(ltab[i].intens - v);
        j = i;
      }
    }
    if (ltab[j].intens != defcnslit) {
      for (i = 0; i < 2; i++) {
        if (ltab[j].lname[i] == 0)
          break;
        if (strlen(cnstr))
          V strcat(cnstr, " ");
        V strcat(cnstr, cixname(CVB(ltab[j].lname[i])));
      }
    }

    /* Locate saturation.  If the saturation is vivid, nothing
       is edited. */

    d = 20000;
    for (i = 0; i < ELEMENTS(stab); i++) {
      if (abs(stab[i].satper - s) <= d) {
        d = abs(stab[i].satper - s);
        j = i;
      }
    }
    if (stab[j].satper != 10000) {
      if (strlen(cnstr))
        V strcat(cnstr, " ");
      V strcat(cnstr, cixname(CVB(stab[j].sname)));
    }

    if (strlen(cnstr))
      V strcat(cnstr, " ");

    /* Find closest hue name. */

    ld = 100000L;
    if (lh == 36000L)
      lh = 0;
    for (i = 0; i < ELEMENTS(huetab); i++) {
      if (abs(huetab[i].huecode - lh) < ld) {
        ld = abs(huetab[i].huecode - lh);
        j = i;
      }
    }

    /* Now we'll find the next hue in the direction of the
       actual hue from the specified hue. */

    if (lh > huetab[j].huecode) {
      if (j == (ELEMENTS(huetab) - 1))
        k = 1;
      else
        k = j + 1;
    } else {
      if (j == 0)
        k = ELEMENTS(huetab) - 2;
      else
        k = j - 1;
    }

    /* Next, compute the distance between the hue and the next
       neighbour in the hue's direction.  */

    hd = abs(huetab[j].huecode - huetab[k].huecode);

    /* The  form of the hue then  depends upon the relationship
       between the actual distance, D, and the total  distance,
       HD,  from the closest pure hue, J, and the next pure hue
       in the direction of the hue supplied,  K.   We  generate
       the following based upon the relationship:

         D / HD      Name
        ------------   --------
        0   - 0.125     J
        0.125 - 0.375   Kish J
        0.375 - 0.5    J-K
    */

    hd = (ld * 10000L) / hd;
    if (hd < 1250L) {
      V strcat(cnstr, cixname(CVB(huetab[j].purename)));
    } else if (hd < 3750L) {
      V strcat(cnstr, cixname(CVB(huetab[k].ishname)));
      V strcat(cnstr, " ");
      V strcat(cnstr, cixname(CVB(huetab[j].purename)));
    } else {
      V strcat(cnstr, cixname(CVB(huetab[j].purename)));
      V strcat(cnstr, "-");
      V strcat(cnstr, cixname(CVB(huetab[k].purename)));
    }
  }
}

/*  ACADRGB  --  Takes  an  AutoCAD  colour  number in hsv and returns
                 red, green, and blue intensities in rgp in the  range
                 0.0 to 1.0 */

static void acadrgb( int hsv, struct r_g_b *rgp)
{
  static double brightfac[5] = {  /* Brightness levels */
    1.0, 0.65, 0.5, 0.3, 0.15
  }, halfsat = .5;                /* Halfway saturation */
  int ih, vs;
  double h, s, f, value;

  roassert( 0 <= hsv );
  roassert( 256 > hsv );

  switch( hsv ) {
  case BLACK:
    rgp->red   = 0.0;
    rgp->blue  = 0.0;
    rgp->green = 0.0;
    value = 0.0;
    break;

  case RED:
    rgp->red   = SAT;
    rgp->green = 0.0;
    rgp->blue  = 0.0;
    value = 1.0;
    break;

  case YELLOW:
    rgp->red   = SAT;
    rgp->green = SAT;
    rgp->blue  = 0.0;
    value = 1.0;
    break;

  case GREEN:
    rgp->red   = 0.0;
    rgp->green = SAT;
    rgp->blue  = 0.0;
    value = 1.0;
    break;

  case CYAN:
    rgp->red   = 0.0;
    rgp->green = SAT;
    rgp->blue  = SAT;
    value = 1.0;
    break;

  case BLUE:
    rgp->red   = 0.0;
    rgp->green = 0.0;
    rgp->blue  = SAT;
    value = 1.0;
    break;

  case MAGENTA:
    rgp->red   = SAT;
    rgp->green = 0.0;
    rgp->blue  = SAT;
    value = 1.0;
    break;

  case WHITE:
  case 8:
  case 9:
    rgp->red   = SAT;
    rgp->green = SAT;
    rgp->blue  = SAT;
    value = 1.0;
    break;

  default:

    /*  The chromatic colors.  The  hue  resulting  from  an
      AutoCAD color 10-249 will be determined by its first
      two digits, and the saturation and  value  from  the
      last digit, as follows:

      Hues:

       10 -- Red
       50 -- Yellow
       90 -- Green
      130 -- Cyan
      170 -- Blue
      210 -- Magenta

      Between  each  of these are three intermediate hues,
      e.g., between red and yellow, we have:

       20 -- reddish orange
       30 -- orange
       40 -- yellowish orange

      To each hue number, 0, 2, 4, 6, or 8 can be added to
      give a different "value", or brightness, with 0  the
      brightest  and  8  the  weakest.   Finally, 1 can be
      added to  produce  a  "half-saturated",  or  pastel,
      color.  For example, color 18 is the dimmest red and
      10 the brightest red.  19 is the dimmest pink and 11
      the brightest pink.
    */

    if (hsv > 9 && hsv < 250) {

      /* Apply the algorithm from Foley & van Dam to turn
         HSV into RGB values */

      ih = (hsv - 10) / 10;   /* Integer hue value. */
      if (ih >= 24)       /* Range is 0-23. */
        ih -= 24;
      vs = hsv % 10;      /* Encoded value and saturation */
      h = ih / 4.;        /* Map into range [0.0,6.0) */
      ih = (int)h;        /* The integer part. */
      f = h - ih;         /* Fractional part. */
      value = brightfac[vs >> 1]; /* Value in [0,1] */
      s = vs & 1 ? halfsat : 1.0; /* Saturation */

      switch (ih) {
      case 0:
        rgp->red   = 1.0;
        rgp->green = (double) (1.0 - s * (1.0 - f));
        rgp->blue  = (double) (1.0 - s);
        break;

      case 1:
        rgp->red   = (double) (1.0 - s * f);
        rgp->green = 1.0;
        rgp->blue  = (double) (1 - s);
        break;

      case 2:
        rgp->red   = (double) (1.0 - s);
        rgp->green = 1.0;
        rgp->blue  = (double) (1.0 - s *(1.0 - f));
        break;

      case 3:
        rgp->red   = (double) (1.0 - s);
        rgp->green = (double) (1.0 - s * f);
        rgp->blue  = 1.0;
        break;

      case 4:
        rgp->red   = (double) (1.0 - s * (1.0 - f));
        rgp->green = (double) (1.0 - s);
        rgp->blue  = 1.0;
        break;

      case 5:
        rgp->red   = 1.0;
        rgp->green = (double) (1.0 - s);
        rgp->blue  = (double) (1.0 - s * f);
        break;
      }
    } else {
      /* Define some extra colours from dark grey to white
         in the 250 to 255 slots */
      value = 0.33 + (hsv - 250) * 0.134;
      rgp->red   = 1.0;
      rgp->green = 1.0;
      rgp->blue  = 1.0;
    }
    break;            /* Default */
  }
  rgp->red   *= value;        /* Apply lightness scale factor */
  rgp->green *= value;        /* to components resulting from */
  rgp->blue  *= value;        /* hue and saturation. */
}

/*  RGBACAD  --  Find the AutoCAD colour closest to in RGB space to a
                 specified RGB triple.  */

static int rgbacad(double r, double g, double b)
{
  int i, low, ccol;
  double closest = 1000.0;
  struct r_g_b rc;

  roassert(r >= 0.0 && r <= 1.0);
  roassert(g >= 0.0 && g <= 1.0);
  roassert(b >= 0.0 && b <= 1.0);

  /* If we're mapping to the 8 colour gamut, turn all grey scale
     colours into white and map the rest based on hue alone. */

  if (gamut ==  {
    double h, s, v;

    rgb_hsv(r, g, b, &h, &s, &v);
    return s == 0.0 ? WHITE :
         (RED + ((((int) (h + 30.0)) % 360) / 60));
  }

  /* Note  that we start with  colour 1 since 0 (black) is not a
     valid user-specified colour.  If this is a grey scale tone,
     map only to AutoCAD's grey scale indices.  */

  ccol = low = (r == g && r == b) ? 250 : 1;

  for (i = low; i < 256; i++) {
    double cdist;

    acadrgb(i, &rc);
    rc.red -= r;
    rc.green -= g;
    rc.blue -= b;
    cdist = rc.red * rc.red + rc.green * rc.green +
        rc.blue * rc.blue;
    if (cdist < closest) {
      ccol = i;
      if ((closest = cdist) == 0.0)
        break;
    }
  }
  if (ccol == 255)          /* If synonym for white... */
    ccol = 7;           /* ...make simple white. */
  return ccol;
}

#ifdef COLEXT_STANDALONE

/*  RETRGB  --  Return an RGB triple as either an RGB point or
        the closest AutoCAD standard colour.  */

static void retrgb(bool acad, double r, double g, double b)
{
  if (acad) {
    ads_retint(rgbacad(r, g, b));
  } else {
    ads_point p;

    Spoint(p, r, g, b);
    ads_retpoint(p);
  }
}

/*  TRIPLE  --  Scan  a  triple  of  real  arguments  into an array of
                reals.  Integers are accepted and converted to  reals.
                true  is  returned  if  valid  arguments are obtained;
                false otherwise.  */

static bool triple(double cdesc[3], bool rangecheck)
{
  int nargs;
  struct resbuf *rb1 = ads_getargs();

  ads_retnil();
  for (nargs = 0; nargs < 3; nargs++) {
    if (rb1 == NULL)
      break;
    if (rb1->restype == RTSHORT) {
      cdesc[nargs] = rb1->resval.rint;
    } else if (rb1->restype == RTREAL) {
      cdesc[nargs] = rb1->resval.rreal;
    } else if (nargs == 0 && rb1->restype == RT3DPOINT) {
      Cpoint(cdesc, rb1->resval.rpoint);
      nargs = 2;
    } else {
      ads_fail(/*MSG50*/"incorrect argument type");
      return false;
    }
    rb1 = rb1->rbnext;
  }

  /* Make sure there were enough arguments. */

  if (nargs < 3) {
    ads_fail(/*MSG51*/"too few arguments");
    return false;
  }

  /* Make sure there are no more arguments. */

  if (rb1 != NULL) {
    ads_fail(/*MSG52*/"too many arguments");
    return false;
  }

  /* Range check arguments if requested. */

  if (rangecheck) {
    for (nargs = 0; nargs < 3; nargs++) {
      if (rangecheck && (cdesc[nargs] < 0.0 || cdesc[nargs] > 1.0)) {
        ads_fail(/*MSG53*/"argument out of range");
        return false;
      }
    }
  }

  return true;
}

/*  CMY  --  Specify colour as CMY triple.  */

static void cmy(bool acad)
{
  double cdesc[3];

  if (triple(cdesc, true)) {
    retrgb(acad, 1.0 - cdesc[0], 1.0 - cdesc[1],
         1.0 - cdesc[2]);
  }
}

/*  CTEMP  --  Specify colour as a colour temperature.  */

static void ctemp(bool acad)
{
  struct resbuf *rb;

  ads_retnil();

  if ((rb = ads_getargs()) == NULL) {
    ads_fail(/*MSG63*/"too few arguments");
  } else {
    double degrees, ir, ig, ib;

    if (rb->restype == RTSHORT) {
      degrees = rb->resval.rint;
    } else if (rb->restype == RTREAL) {
      degrees = rb->resval.rreal;
    } else {
      ads_fail(/*MSG64*/"incorrect argument type");
      return;
    }

    /* Make sure there are no more arguments. */

    if (rb->rbnext != NULL) {
      ads_fail(/*MSG65*/"too many arguments");
      return;
    }

    ctemp_rgb(degrees, &ir, &ig, &ib);
    retrgb(acad, ir, ig, ib);
  }
}

/*  CNS  --  Specify colour as a CNS string.  */

static void cns(bool acad)
{
  struct resbuf *rb;

  ads_retnil();

  if ((rb = ads_getargs()) == NULL) {
    ads_fail(/*MSG54*/"too few arguments");
    return;
  } else {
    struct resbuf *rb1 = rb;
    double ir, ig, ib;

    if (rb1->restype != RTSTR) {
      ads_fail(/*MSG55*/"incorrect argument type");
      return;
    }

    /* Make sure there are no more arguments. */

    if (rb1->rbnext != NULL) {
      ads_fail(/*MSG56*/"too many arguments");
      return;
    }

    if (cns_rgb(rb1->resval.rstring, &ir, &ig, &ib)) {
      retrgb(acad, ir, ig, ib);
    }
  }
}

/*  CNSER  --  Return string describing last CNS error, if any.  */

static void cnser()
{
  if (cnserr == NULL)
    ads_retnil();
  else
    ads_retstr(cnserr);
}

/*  HLS  --  Specify colour as HLS triple.  */

static void hls(bool acad)
{
  double cdesc[3];

  if (triple(cdesc, true)) {
    double ir, ig, ib;

    hls_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
    retrgb(acad, ir, ig, ib);
  }
}

/*  HSV  --  Specify colour as HSV triple.  */

static void hsv(bool acad)
{
  double cdesc[3];

  if (triple(cdesc, true)) {
    double ir, ig, ib;

    hsv_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
    retrgb(acad, ir, ig, ib);
  }
}

/*  RGB  --  Specify colour as RGB triple.  */

static void rgb( bool acad)
{
  double cdesc[3];

  if (triple(cdesc, true)) {
    retrgb(acad, cdesc[0], cdesc[1], cdesc[2]);
  }
}

/*  YIQ  --  Specify colour as YIQ triple.  */

static void yiq(bool acad)
{
  double cdesc[3];

  if (triple(cdesc, false)) {
    double ir, ig, ib;

    if ((cdesc[0] < 0.0 || cdesc[0] > 1.0) &&
      (cdesc[1] < -0.6 || cdesc[0] > 0.6) &&
      (cdesc[2] < -0.52 || cdesc[2] > 0.52)) {
      ads_fail(/*MSG57*/"argument out of range");
    }

    yiq_rgb(cdesc[0], cdesc[1], cdesc[2], &ir, &ig, &ib);

    retrgb(acad, ir, ig, ib);
  }
}


/*  ACADCOL  --  Obtain AutoCAD colour.  We accept any of the following:

  1.  A single integer, representing an AutoCAD standard colour index.
  2.  A triple of reals and/or integers, representing RGB intensities.
  3.  A list of three reals and/or integers, representing RGB intensities.
*/

static bool acadcol(struct r_g_b *rp)
{
  double crgb[3];
  struct resbuf *rb = ads_getargs();

  ads_retnil();

  if (rb == NULL) {
    ads_fail(/*MSG58*/"too few arguments");
    return false;
  }

  if ((rb->restype == RTSHORT) && (rb->rbnext == NULL)) {
    int cindex = rb->resval.rint;

    if (cindex < 0 || cindex > 255) {
      ads_fail(/*MSG59*/"argument out of range");
      return false;
    }
    acadrgb(cindex, rp);
    return true;
  }

  if (triple(crgb, true)) {
    rp->red   = crgb[0];
    rp->green = crgb[1];
    rp->blue  = crgb[2];
  } else {
    return false;
  }

  return true;
}

/*  TORGB  --  Convert internal colour to RGB triple.  */

static void torgb()
{
  struct r_g_b rc;

  if (acadcol(&rc)) {
    ads_point p;

    Spoint(p, rc.red, rc.green, rc.blue);
    ads_retpoint(p);
  }
}

/*  TOCMY  --  Convert internal colour to CMY triple.  */

static void tocmy()
{
  struct r_g_b rc;

  if (acadcol(&rc)) {
    ads_point p;

    rgb_cmy(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
    ads_retpoint(p);
  }
}

/*  TOYIQ  --  Convert internal colour to YIQ triple.  */

static void toyiq()
{
  struct r_g_b rc;

  if (acadcol(&rc)) {
    ads_point p;

    rgb_yiq(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
    ads_retpoint(p);
  }
}

/*  TOHSV  --  Convert internal colour to HSV triple.  */

static void tohsv()
{
  struct r_g_b rc;

  if (acadcol(&rc)) {
    ads_point p;

    rgb_hsv(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
    p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
    ads_retpoint(p);
  }
}

/*  TOHLS  --  Convert internal colour to HLS triple.  */

static void tohls()
{
  struct r_g_b rc;

  if (acadcol(&rc)) {
    ads_point p;

    rgb_hls(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
    p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
    ads_retpoint(p);
  }
}

/*  TOCNS  --  Convert internal colour to CNS string.  */

static void tocns()
{
  struct r_g_b rc;

  if (acadcol(&rc)) {
    char cnstr[40];

    rgb_cns(rc.red, rc.green, rc.blue, cnstr);
    ads_retstr(cnstr);
  }
}

/*  COLSET  --  Set colour gamut available.  */

static void colset()
{
  struct resbuf *rb = ads_getargs();

  ads_retnil();

  if (rb == NULL) {
    ads_retint(gamut);
    return;
  }

  if (rb->rbnext != NULL) {
    ads_fail(/*MSG60*/"too many arguments");
    return;
  }

  if (rb->restype == RTSHORT) {
    int colsys = rb->resval.rint;

    switch (colsys) {
    case 8:
    case 256:
      gamut = colsys;
      ads_retint(gamut);
      break;

    default:
      ads_fail(/*MSG61*/"argument out of range");
    }
    return;
  }
  ads_fail(/*MSG62*/"incorrect argument type");
}
#endif // COLEXT_STANDALONE

typedef unsigned char uchar;
typedef unsigned long ulong;

inline ulong makergb( int r, int g, int b )
{
  roassert( 0 <= r && r < 256 );
  roassert( 0 <= g && g < 256 );
  roassert( 0 <= b && b < 256 );
  return ((ulong) ((uchar) (r)))
    | ((ulong) ((uchar) (g)) << 8)
    | ((ulong) ((uchar) (b)) << 16);
}

inline uchar makebyte( double x )
{
  roassert( 0.0 <= x && x <= 1.0 );
  int a = int( x * 255 + 0.5 );
  roassert( 0 <= a && a < 256 );
  return (unsigned char) a;
}

inline double makereal( int a )
{
  roassert( 0 <= a && a < 256 );
  return a / 255;
}

inline uchar getrvalue( ulong rgb )
{
  return uchar( rgb );
}

inline uchar getgvalue( ulong rgb )
{
  return uchar( rgb >> 8 );
}

inline uchar getbvalue( ulong rgb )
{
  return uchar( rgb >> 16 );
}

//
// exported functions:
//

//
// aci2colorref - convert AutoCAD colour index aci to Windows COLORREF:
//
// The COLORREF value is a 32-bit value used to specify an RGB color.
// When specifying an explicit RGB color, the COLORREF value has the
// following hexadecimal form:
//
// 0x00bbggrr
//
// The low-order byte contains a value for the relative intensity of red;
// the second byte contains a value for green; and the third byte contains
// a value for blue. The high-order byte must be zero. The maximum value
// for a single byte is 0xFF.
//
Ro::ulong aci2colorref( int color )
{
  r_g_b rgb;
  acadrgb( color, &rgb );
  return makergb( makebyte( rgb.red ), makebyte( rgb.green ), makebyte( rgb.green ) );
}

int colorref2aci( Ro::ulong colorref )
{
  return rgbacad( makereal( getrvalue( colorref ) ),
    makereal( getgvalue( colorref ) ),
    makereal( getbvalue( colorref ) ) );
}

bool aci2string( char * buf, int len, int color )
{
  roassert( 39 < len );

  bool rc = (0 <= color) && (256 > color);
  roassert( rc );
  if( rc ) {
    r_g_b rgb;
    acadrgb( color, &rgb );
    rgb_cns( rgb.red, rgb.green, rgb.blue, buf );
  }
  return rc;
}

const char * aci2string( int color )
{
  static char cnstr[40];
  return aci2string( cnstr, sizeof( cnstr ), color ) ? cnstr : 0;
}

bool aci2hsv(
  double & hue,
  double & saturation, 
  double & value, 
  int color )
{
  bool rc = (0 <= color) && (256 > color);
  roassert( rc );
  if( rc ) {
    r_g_b rgb;
    acadrgb( color, &rgb );
    rgb_hsv( rgb.red, rgb.green, rgb.blue,
      &hue, &saturation, &value );
  }
  return rc;
}

bool hsv2aci(
  int & color,
  double hue, 
  double saturation, 
  double value )
{
  roassert( 0.0 <= hue );
  roassert( 360.0 >= hue );
  roassert( 0.0 <= saturation );
  roassert( 1.0 >= saturation );
  roassert( 0.0 <= value );
  roassert( 1.0 >= value );

  double r, g, b;
  hsv_rgb( hue, saturation, value, &r, &g, &b );
  color = rgbacad( r, g, b );
  return true;
}

bool aci2rgb(
  double & red,
  double & green, 
  double & blue, 
  int color )
{
  bool rc = (0 <= color) && (256 > color);
  roassert( rc );
  if( rc ) {
    r_g_b rgb;
    acadrgb( color, &rgb );
    red = rgb.red;
    green = rgb.green;
    blue = rgb.blue;
  }
  return rc;
}

bool rgb2aci(
  int & color,
  double red,
  double green, 
  double blue )
{
  roassert( 0.0 <= red );
  roassert( 1.0 >= red );
  roassert( 0.0 <= green );
  roassert( 1.0 >= green );
  roassert( 0.0 <= blue );
  roassert( 1.0 >= blue );

  color = rgbacad( red, green, blue );
  return true;
}

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 7 of 9

jagostinho74
Collaborator
Collaborator

Thank you, @jeremy_tammik . 

Assistant BIM/CAD Manager

Manchester, UK


0 Likes
Message 8 of 9

jagostinho74
Collaborator
Collaborator

thank you @RPTHOMAS108 .

I think the code for converting the Integers is very useful.

Assistant BIM/CAD Manager

Manchester, UK


0 Likes
Message 9 of 9

jagostinho74
Collaborator
Collaborator

Manage to code it in python like this.

 

Now it is a matter of using the same functions to the renaming script

 

# Online Python compiler (interpreter) to run Python online.
# Write Python 3 code in this online editor and run it.

colorDic = {"240,248,255":"Alice Blue","250,235,215":"Antique White","0,255,255":"Aqua","127,255,212":"Aqua Marine","240,255,255":"Azure","245,245,220":"Beige","255,228,196":"Bisque","0,0,0":"Black","255,235,205":"Blanched Almond","0,0,255":"Blue","138,43,226":"Blue Violet","165,42,42":"Brown","222,184,135":"Burly Wood","95,158,160":"Cadet Blue","127,255,0":"Chart Reuse","210,105,30":"Chocolate","255,127,80":"Coral","100,149,237":"Corn Flower Blue","255,248,220":"Corn Silk","220,20,60":"Crimson","0,255,255":"Cyan","0,0,139":"Dark Blue","0,139,139":"Dark Cyan","184,134,11":"Dark Golden Rod","169,169,169":"Dark Grey","0,100,0":"Dark Green","189,183,107":"Dark Khaki","139,0,139":"Dark Magenta","85,107,47":"Dark Olive Green","255,140,0":"Dark Orange","153,50,204":"Dark Orchid","139,0,0":"Dark Red","233,150,122":"Dark Salmon","143,188,143":"Dark Sea Green","72,61,139":"Dark Slate Blue","47,79,79":"Dark Slate Grey","0,206,209":"Dark Turquoise","148,0,211":"Dark Violet","255,20,147":"Deep Pink","0,191,255":"Deep Sky Blue","105,105,105":"Dim Grey","30,144,255":"Dodger Blue","178,34,34":"Firebrick","255,250,240":"Floral White","34,139,34":"Forest Green","220,220,220":"Gainsboro","248,248,255":"Ghost White","255,215,0":"Gold","218,165,32":"Golden Rod","128,128,128":"Grey","0,128,0":"Green","173,255,47":"Green Yellow","240,255,240":"Honeydew","255,105,180":"Hot Pink","205,92,92":"Indian Red","75,0,130":"Indigo","255,255,240":"Ivory","240,230,140":"Khaki","230,230,250":"Lavender","255,240,245":"Lavender Blush","124,252,0":"Lawn Green","255,250,205":"Lemon Chiffon","173,216,230":"Light Blue","240,128,128":"Light Coral","224,255,255":"Light Cyan","250,250,210":"Light Golden Rod Yellow","211,211,211":"Light Grey","144,238,144":"Light Green","255,182,193":"Light Pink","255,160,122":"Light Salmon","32,178,170":"Light Sea Green","135,206,250":"Light Sky Blue","119,136,153":"Light Slate Grey","176,196,222":"Light Steel Blue","255,255,224":"Light Yellow","0,255,0":"Lime","50,205,50":"Lime Green","250,240,230":"Linen","255,0,255":"Magenta","128,0,0":"Maroon","102,205,170":"Medium Aqua Marine","0,0,205":"Medium Blue","186,85,211":"Medium Orchid","147,112,219":"Medium Purple","60,179,113":"Medium Sea Green","123,104,238":"Medium Slate Blue","0,250,154":"Medium Spring Green","72,209,204":"Medium Turquoise","199,21,133":"Medium Violet Red","25,25,112":"Midnight Blue","245,255,250":"Mint Cream","255,228,225":"Misty Rose","255,228,181":"Moccasin","255,222,173":"Navajo White","0,0,128":"Navy","253,245,230":"Old Lace","128,128,0":"Olive","107,142,35":"Olive Drab","255,165,0":"Orange","255,69,0":"Orange Red","218,112,214":"Orchid","238,232,170":"Pale Golden Rod","152,251,152":"Pale Green","175,238,238":"Pale Turquoise","219,112,147":"Pale Violet Red","255,239,213":"Papaya Whip","255,218,185":"Peach Puff","205,133,63":"Peru","255,192,203":"Pink","221,160,221":"Plum","176,224,230":"Powder Blue","128,0,128":"Purple","255,0,0":"Red","188,143,143":"Rosy Brown","65,105,225":"Royal Blue","139,69,19":"Saddle Brown","250,128,114":"Salmon","244,164,96":"Sandy Brown","46,139,87":"Sea Green","255,245,238":"Sea Shell","160,82,45":"Sienna","192,192,192":"Silver","135,206,235":"Sky Blue","106,90,205":"Slate Blue","112,128,144":"Slate Grey","255,250,250":"Snow","0,255,127":"Spring Green","70,130,180":"Steel Blue","210,180,140":"Tan","0,128,128":"Teal","216,191,216":"Thistle","255,99,71":"Tomato","64,224,208":"Turquoise","238,130,238":"Violet","245,222,179":"Wheat","255,255,255":"White","245,245,245":"White Smoke","255,255,0":"Yellow","154,205,50":"Yellow Green"}

def RGBToDecimal (r,g,b):
    num = b * 65536 + g * 256 + r
    return num

def DecimalToRGB(num):
    b = int(num / 65536)
    g = int((num - b * 65536) / 256)
    r = int(num - b * 65536 - g * 256)
    return ("%s,%s,%s" % (b, g, r))

def getColorName(rgb):
    if rgb in colorDic:
        color_Name = colorDic[rgb]
    else:
        color_Name = "(RGB("+rgb+"))"
    return color_Name

color = 255
colorRGB = DecimalToRGB(color)
print ("Decimal color is %s %s" % (color,type(color)))
print ("RGB color is %s %s" % (colorRGB, type(colorRGB)))
print ("Using function, Name is %s" % (getColorName(colorRGB)))
Assistant BIM/CAD Manager

Manchester, UK


0 Likes