home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-02-18 | 71.3 KB | 2,325 lines |
- /* Next available MSG number is 66 */
-
- /* COLEXT.C
- ¬⌐┼v (C) 1990-1992 Autodesk ñ╜Ñq
-
- Ñ╗│n┼ΘºK╢O¿╤▒z╢iªµÑ⌠ª≤Ñ╬│~╗▌¿D¬║½■¿⌐íB¡╫º∩ñ╬╡oªµ, ª²¼O░╚╜╨┐φ┤`ñU¡z
- ¡∞½h :
-
- 1) ñWªC¬║¬⌐┼v│qºi░╚╗▌ÑX▓{ªb¿Cñ@Ñ≈½■¿⌐∙╪íC
- 2) ¼█├÷¬║╗í⌐·ñσÑ≤ñ]Ñ▓╢╖⌐·╕ⁿ¬⌐┼v│qºiñ╬Ñ╗╢╡│\Ñi│qºiíC
-
- Ñ╗│n┼Θ╢╚┤ú¿╤º@¼░└│Ñ╬ñW¬║░╤ª╥, ª╙Ñ╝┴n⌐·⌐╬┴⌠ºtÑ⌠ª≤½O├╥; ╣∩⌐≤Ñ⌠ª≤»S«φ
- Ñ╬│~ñº╛A║┘⌐╩, ÑHñ╬░╙╖~╛P░Γ⌐╥┴⌠ºtÑX¿π¬║½O├╥, ªbª╣ñ@╖ºñ⌐ÑHº_╗{íC
-
-
-
- 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)
- Yellowish green
- 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(ads_real r, ads_real g, ads_real b,
- ads_real *c, ads_real *m, ads_real *y)
- Converts r, g, b (0 to 1) to c, m, y (0 to 1).
-
- void cmy_rgb(ads_real c, ads_real m, ads_real y,
- ads_real *r, ads_real *g, ads_real *b)
- Converts c, m, y (0 to 1) to r, g, b (0 to 1).
-
- CTEMP
-
- void ctemp_rgb(ads_real temperature,
- ads_real *r, ads_real *g, ads_real *b)
- Converts a colour temperature specified in degrees Kelvin,
- to r, g, b (0 to 1).
-
- YIQ
-
- void rgb_yiq(ads_real r, ads_real g, ads_real b,
- ads_real *y, ads_real *i, ads_real *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(ads_real y, ads_real i, ads_real q,
- ads_real *r, ads_real *g, ads_real *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(ads_real r, ads_real g, ads_real b,
- ads_real *h, ads_real *s, ads_real *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(ads_real h, ads_real s, ads_real v,
- ads_real *r, ads_real *g, ads_real *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(ads_real r, ads_real g, ads_real b,
- ads_real *h, ads_real *l, ads_real *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(ads_real h, ads_real l, ads_real s,
- ads_real *r, ads_real *g, ads_real *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(ads_real r, ads_real g, ads_real 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.
-
- Boolean cns_rgb(char *cns, ads_real *r, ads_real *g, ads_real *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 <string.h>
- #include <ctype.h>
- #include <math.h>
-
- #include "adslib.h"
-
- #ifdef lint
- extern char *sprintf(); /* Adjust for Sun's strange stdio.h */
- #endif
-
- /* Special assertion handler for ADS applications. */
-
- #ifndef NDEBUG
- #define assert(ex) {if (!(ex)){ads_printf( \
- /*MSG1*/"COLEXT: ┴n⌐· (%s) Ñó▒╤: └╔«╫íu%sív, \
- ▓─ %d ªC\n", /*MSG0*/" ex ",__FILE__,__LINE__); \
- ads_abort(/*MSG2*/"íu┴n⌐·ívÑó▒╤íC");}}
- #else
- #define assert(ex)
- #endif
-
- /* Data types */
-
- typedef enum {False = 0, True = 1} Boolean;
- #define V (void)
-
- /* 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 */
- ads_real 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 */
-
- void main _((int, char **));
- void funcload _((void));
- void hsv_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- void rgb_hsv _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- void rgb_hls _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- ads_real hlsval _((ads_real, ads_real, ads_real));
- void hls_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- void rgb_yiq _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- void yiq_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- void rgb_cmy _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- void ctemp_rgb _((ads_real, ads_real *,ads_real *,ads_real *));
- #ifdef NEEDED
- void cmy_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
- #endif
- colourvocab token _((char **));
- Boolean cns_rgb _((char *, ads_real *, ads_real *, ads_real *));
- char *cixname _((colourvocab));
- void rgb_cns _((ads_real, ads_real, ads_real, char *));
- void acadrgb _((int, struct r_g_b *));
- int rgbacad _((ads_real, ads_real, ads_real));
- void retrgb _((Boolean, ads_real, ads_real, ads_real));
- Boolean triple _((ads_real *, Boolean));
- void cmy _((Boolean));
- void cns _((Boolean));
- void cnser _((void));
- void ctemp _((Boolean));
- void hls _((Boolean));
- void hsv _((Boolean));
- void rgb _((Boolean));
- void yiq _((Boolean));
- void cmyac _((void));
- void ctempac _((void));
- void yiqac _((void));
- void hsvac _((void));
- void rgbac _((void));
- void hlsac _((void));
- void cnsac _((void));
- void cmyrgb _((void));
- void ctemprgb _((void));
- void yiqrgb _((void));
- void hsvrgb _((void));
- void hlsrgb _((void));
- void cnsrgb _((void));
- Boolean acadcol _((struct r_g_b *));
- void torgb _((void));
- void tocmy _((void));
- void toyiq _((void));
- void tohsv _((void));
- void tohls _((void));
- void tocns _((void));
- void colset _((void));
-
-
- /* Command definition and dispatch table. */
-
- struct {
- char *cmdname;
- void (*cmdfunc)();
- } cmdtab[] = {
- /* 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}
- };
-
- /* MAIN -- Main ADS dispatch loop. */
-
- void main(argc, argv)
- int argc;
- char *argv[];
- {
- int stat, cindex, scode = RSRSLT;
-
- ads_init(argc, argv); /* Initialise the application */
-
- /* Main dispatch loop. */
-
- while (True) {
-
- if ((stat = ads_link(scode)) < 0) {
- V printf(/*MSG30*/"\
- COLEXT: Ñ╤ ads_link() ╢╟ª^¬║ñú¿╬¬¼║A = %d\n", stat);
- exit(1);
- }
-
- scode = RSRSLT; /* Default return code */
-
- switch (stat) {
-
- case RQXLOAD: /* Load functions. Called at the start
- of the drawing editor. */
- funcload();
- break;
-
- case RQSUBR: /* Evaluate external lisp function */
- cindex = ads_getfuncode();
-
- /* Execute the command from the command table with
- the index associated with this function. */
-
- if (cindex > 0) {
- cindex--;
- assert(cindex < ELEMENTS(cmdtab));
- (*cmdtab[cindex].cmdfunc)();
- }
- break;
-
- default:
- break;
- }
- }
- }
-
- /* FUNCLOAD -- Load external functions into AutoLisp. */
-
- static void funcload()
- {
- int i;
-
- for (i = 0; i < ELEMENTS(cmdtab); i++) {
- ads_defun(cmdtab[i].cmdname, i + 1);
- }
- }
-
- /* ***************************************************
- ** **
- ** 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(h, s, v, r, g, b)
- ads_real h, s, v;
- ads_real *r, *g, *b;
- {
- int i;
- ads_real f, p, q, t;
-
- if (s == 0) {
- *r = *g = *b = v;
- } else {
- if (h == 360.0)
- h = 0;
- h /= 60.0;
-
- i = h;
- f = h - i;
- p = v * (1.0 - s);
- q = v * (1.0 - (s * f));
- t = v * (1.0 - (s * (1.0 - f)));
- assert(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(r, g, b, h, s, v)
- ads_real r, g, b;
- ads_real *h, *s, *v;
- {
- ads_real 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(r, g, b, h, l, s)
- ads_real r, g, b;
- ads_real *h, *l, *s;
- {
- ads_real 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 ads_real hlsval(n1, n2, hue)
- ads_real n1, n2, 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(h, l, s, r, g, b)
- ads_real h, l, s;
- ads_real *r, *g, *b;
- {
- ads_real 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(r, g, b, y, i, q)
- ads_real r, g, b;
- ads_real *y, *i, *q;
- {
- ads_real 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(y, i, q, r, g, b)
- ads_real y, i, q;
- ads_real *r, *g, *b;
- {
- ads_real 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(r, g, b, c, m, y)
- ads_real r, g, b;
- ads_real *c, *m, *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(c, m, y, r, g, b)
- ads_real c, m, y;
- ads_real *r, *g, *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(temp, r, g, b)
- double temp;
- double *r, *g, *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(icp)
- 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 Boolean cns_rgb(cns, r, g, b)
- char *cns;
- ads_real *r, *g, *b;
- {
- int i, j, k = 0, lightness, saturation;
- long tok = 0L, hue;
- colourvocab t;
- static char conflite[] = /*MSG31*/"íu⌐·½G½╫│W«µív╜─¼≡íC";
- /* 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*/"íu│W«µív╡L«─íC";
- return False;
- }
-
- /* Scan string and parse tokens */
-
- while (True) {
- t = token(&cns);
- if (t == Huh) {
- V sprintf(cnserb, /*MSG33*/"╡L¬k┐δ╗{¬║▓┼╕╣:íu%sívíC", cns);
- cnserr = cnserb;
- return False;
- }
- if (Tbit(t)) {
- V sprintf(cnserb, /*MSG34*/"¡½╜╞¬║▓┼╕╣:íu%sívíC", 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*/"½D▒`▓▀║Díuññ╢í½G½╫ívíC";
- 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*/"½D▒`▓▀║DñúÑ╬íu⌐·½Gív⌐╬íu╖t▓HívíC";
- 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*/"íu╢┬/ª╟/Ñ╒ív¬║│W«µ╜─¼≡íC";
- 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*/"íu▒mªΓív╗Píu«°ªΓív┤y╝v▓VÑ╬íC";
- 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*/"íuªΓ▒m¡╫Ñ┐ív╗Píu«°ªΓív┤y╝v▓VÑ╬íC";
- return False;
- }
-
- /* Test for saturation specification with achromatic shade. */
-
- if (tok & (Tb(Grayish) | Tb(Moderate) | Tb(Strong) | Tb(Vivid))) {
- cnserr = /*MSG40*/"ÑHíu«°ªΓív┤y╝v│]⌐wíu╣íªX½╫ívíC";
- 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*/"ÑHíu╢┬/Ñ╒ív¿╙│]⌐wíu½G½╫ívíC";
- 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*/"íu╣íªX½╫ív¬║│W«µ╜─¼≡íC";
- 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*/"Ñ╝½ⁿ⌐wíuªΓ╜╒ívíC";
- return False;
- }
- if (i > 2) {
- cnserr = /*MSG44*/"½ⁿ⌐w¬║íuªΓ╜╒ív╢W╣L 2 ║╪íC";
- 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*/"½ⁿ⌐w¬║íuª╕ªΓ╜╒ív╢W╣L 1 ║╪íC";
- return False;
- }
- if (i == 2 && j > 0) {
- cnserr = /*MSG46*/"ÑH 2 ║╪íuÑDªΓ╜╒ív½ⁿ⌐wíuª╕ªΓ╜╒ívíC";
- 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*/"2 ║╪íuÑDªΓ╜╒ívñú▒╡╛FíC";
- 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*/"íuÑDªΓ╜╒ív╗Píuª╕ªΓ╜╒ívñú▒╡╛FíC";
- 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*/"ñ║│í┐∙╗~ í╨ ╡L¬k¿M⌐wíuªΓ╜╒ívíC";
- 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(cx)
- 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(r, g, b, cnstr)
- ads_real r, g, b;
- char *cnstr;
- {
- int i, j = 0, k, d, s, v;
- long lh, ld, hd;
- ads_real rh, rs, rv;
-
- #define C(x) ((char) (x))
- #define CV(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 = rh * 100L;
- s = rs * 10000;
- v = 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) > 0)
- V strcat(cnstr, " ");
- V strcat(cnstr, cixname(CV(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) > 0)
- V strcat(cnstr, " ");
- V strcat(cnstr, cixname(CV(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) > 0)
- V strcat(cnstr, " ");
- V strcat(cnstr, cixname(CV(stab[j].sname)));
- }
-
- if (strlen(cnstr) > 0)
- 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(CV(huetab[j].purename)));
- } else if (hd < 3750L) {
- V strcat(cnstr, cixname(CV(huetab[k].ishname)));
- V strcat(cnstr, " ");
- V strcat(cnstr, cixname(CV(huetab[j].purename)));
- } else {
- V strcat(cnstr, cixname(CV(huetab[j].purename)));
- V strcat(cnstr, "-");
- V strcat(cnstr, cixname(CV(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(hsv, rgp)
- int hsv;
- struct r_g_b *rgp;
- {
- static ads_real brightfac[5] = { /* Brightness levels */
- 1.0, 0.65, 0.5, 0.3, 0.15
- }, halfsat = .5; /* Halfway saturation */
- int ih, vs;
- ads_real h, s, f, value;
-
- assert(hsv > 0 || hsv < 256);
-
- 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 = 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 = (ads_real) (1.0 - s * (1.0 - f));
- rgp->blue = (ads_real) (1.0 - s);
- break;
-
- case 1:
- rgp->red = (ads_real) (1.0 - s * f);
- rgp->green = 1.0;
- rgp->blue = (ads_real) (1 - s);
- break;
-
- case 2:
- rgp->red = (ads_real) (1.0 - s);
- rgp->green = 1.0;
- rgp->blue = (ads_real) (1.0 - s *(1.0 - f));
- break;
-
- case 3:
- rgp->red = (ads_real) (1.0 - s);
- rgp->green = (ads_real) (1.0 - s * f);
- rgp->blue = 1.0;
- break;
-
- case 4:
- rgp->red = (ads_real) (1.0 - s * (1.0 - f));
- rgp->green = (ads_real) (1.0 - s);
- rgp->blue = 1.0;
- break;
-
- case 5:
- rgp->red = 1.0;
- rgp->green = (ads_real) (1.0 - s);
- rgp->blue = (ads_real) (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(r, g, b)
- ads_real r, g, b;
- {
- int i, low, ccol;
- ads_real closest = 1000.0;
- struct r_g_b rc;
-
- assert(r >= 0.0 && r <= 1.0);
- assert(g >= 0.0 && g <= 1.0);
- assert(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 == 8) {
- ads_real 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++) {
- ads_real 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;
- }
-
- /* RETRGB -- Return an RGB triple as either an RGB point or
- the closest AutoCAD standard colour. */
-
- static void retrgb(acad, r, g, b)
- Boolean acad;
- ads_real r, g, 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 Boolean triple(cdesc, rangecheck)
- ads_real cdesc[3];
- Boolean 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*/"íuñ▐╝╞½¼║Aívª│╗~");
- return False;
- }
- rb1 = rb1->rbnext;
- }
-
- /* Make sure there were enough arguments. */
-
- if (nargs < 3) {
- ads_fail(/*MSG51*/"íuñ▐╝╞ív╣Lñ╓");
- return False;
- }
-
- /* Make sure there are no more arguments. */
-
- if (rb1 != NULL) {
- ads_fail(/*MSG52*/"íuñ▐╝╞ív╣Lªh");
- 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*/"íuñ▐╝╞ív╢WÑX╜d│≥");
- return False;
- }
- }
- }
-
- return True;
- }
-
- /* CMY -- Specify colour as CMY triple. */
-
- static void cmy(acad)
- Boolean acad;
- {
- ads_real 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(acad)
- Boolean acad;
- {
- struct resbuf *rb;
-
- ads_retnil();
-
- if ((rb = ads_getargs()) == NULL) {
- ads_fail(/*MSG63*/"íuñ▐╝╞ív╣Lñ╓");
- } else {
- ads_real 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*/"íuñ▐╝╞½¼║Aívª│╗~");
- return;
- }
-
- /* Make sure there are no more arguments. */
-
- if (rb->rbnext != NULL) {
- ads_fail(/*MSG65*/"íuñ▐╝╞ív╣Lªh");
- return;
- }
-
- ctemp_rgb(degrees, &ir, &ig, &ib);
- retrgb(acad, ir, ig, ib);
- }
- }
-
- /* CNS -- Specify colour as a CNS string. */
-
- static void cns(acad)
- Boolean acad;
- {
- struct resbuf *rb;
-
- ads_retnil();
-
- if ((rb = ads_getargs()) == NULL) {
- ads_fail(/*MSG54*/"íuñ▐╝╞ív╣Lñ╓");
- return;
- } else {
- struct resbuf *rb1 = rb;
- ads_real ir, ig, ib;
-
- if (rb1->restype != RTSTR) {
- ads_fail(/*MSG55*/"íuñ▐╝╞½¼║Aívª│╗~");
- return;
- }
-
- /* Make sure there are no more arguments. */
-
- if (rb1->rbnext != NULL) {
- ads_fail(/*MSG56*/"íuñ▐╝╞ív╣Lªh");
- 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(acad)
- Boolean acad;
- {
- ads_real cdesc[3];
-
- if (triple(cdesc, True)) {
- ads_real 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(acad)
- Boolean acad;
- {
- ads_real cdesc[3];
-
- if (triple(cdesc, True)) {
- ads_real 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(acad)
- Boolean acad;
- {
- ads_real cdesc[3];
-
- if (triple(cdesc, True)) {
- retrgb(acad, cdesc[0], cdesc[1], cdesc[2]);
- }
- }
-
- /* YIQ -- Specify colour as YIQ triple. */
-
- static void yiq(acad)
- Boolean acad;
- {
- ads_real cdesc[3];
-
- if (triple(cdesc, False)) {
- ads_real 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*/"íuñ▐╝╞ív╢WÑX╜d│≥");
- }
-
- yiq_rgb(cdesc[0], cdesc[1], cdesc[2], &ir, &ig, &ib);
-
- retrgb(acad, ir, ig, ib);
- }
- }
-
- /* 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); }
-
- /* 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 Boolean acadcol(rp)
- struct r_g_b *rp;
- {
- ads_real crgb[3];
- struct resbuf *rb = ads_getargs();
-
- ads_retnil();
-
- if (rb == NULL) {
- ads_fail(/*MSG58*/"íuñ▐╝╞ív╣Lñ╓");
- return False;
- }
-
- if ((rb->restype == RTSHORT) && (rb->rbnext == NULL)) {
- int cindex = rb->resval.rint;
-
- if (cindex < 0 || cindex > 255) {
- ads_fail(/*MSG59*/"íuñ▐╝╞ív╢WÑX╜d│≥");
- 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*/"íuñ▐╝╞ív╣Lªh");
- 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*/"íuñ▐╝╞ív╢WÑX╜d│≥");
- }
- return;
- }
- ads_fail(/*MSG62*/"íuñ▐╝╞½¼║Aívª│╗~");
- }