BRL-CAD
color.c
Go to the documentation of this file.
1 /* C O L O R . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1997-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <stdlib.h>
24 #include <math.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include "bio.h"
29 
30 #include "bu/color.h"
31 #include "bu/log.h"
32 #include "bu/malloc.h"
33 
34 
35 /* libfb defines replicated here to avoid a libfb dependency */
36 #define ACHROMATIC -1.0
37 
38 #define HUE 0
39 #define SAT 1
40 #define VAL 2
41 
42 #define RED 0
43 #define GRN 1
44 #define BLU 2
45 
46 
47 /* vmath/libbu routines replicated here to avoid a libbn dependency */
48 enum axis {
49  X = 0,
50  Y = 1,
51  Z = 2
52 };
53 #define VSET(a, b, c, d) { (a)[X] = (b); (a)[Y] = (c); (a)[Z] = (d); }
54 #define VSETALL(a, s) { (a)[X] = (a)[Y] = (a)[Z] = (s); }
55 #define NEAR_ZERO(val, epsilon) (((val) > -epsilon) && ((val) < epsilon))
56 #define V3ARGS(a) (a)[X], (a)[Y], (a)[Z]
57 
58 
59 void
60 bu_rgb_to_hsv(unsigned char *rgb, fastf_t *hsv)
61 {
62  fastf_t red, grn, blu;
63  fastf_t *hue = &hsv[HUE];
64  fastf_t *sat = &hsv[SAT];
65  fastf_t *val = &hsv[VAL];
66  fastf_t max, min;
67  fastf_t chroma;
68 
69  /*
70  * Compute value
71  */
72  max = min = red = ((fastf_t)rgb[RED]) / 255.0;
73 
74  grn = ((fastf_t)rgb[GRN]) / 255.0;
75  if (grn < min)
76  min = grn;
77  else if (grn > max)
78  max = grn;
79 
80  blu = ((fastf_t)rgb[BLU]) / 255.0;
81  if (blu < min)
82  min = blu;
83  else if (blu > max)
84  max = blu;
85 
86  *val = max;
87 
88  /*
89  * Compute saturation
90  */
91  chroma = max - min;
92  if (max > 0.0)
93  *sat = chroma / max;
94  else
95  *sat = 0.0;
96 
97  /*
98  * Compute hue
99  */
100  if (NEAR_ZERO(*sat, SMALL_FASTF)) {
101  *hue = ACHROMATIC;
102  } else {
103  if (NEAR_ZERO(red - max, SMALL_FASTF)) /* red == max */
104  *hue = (grn - blu) / chroma;
105  else if (NEAR_ZERO(grn - max, SMALL_FASTF)) /* grn == max */
106  *hue = 2.0 + (blu - red) / chroma;
107  else if (NEAR_ZERO(blu - max, SMALL_FASTF)) /* blu == max */
108  *hue = 4.0 + (red - grn) / chroma;
109 
110  /*
111  * Convert hue to degrees
112  */
113  *hue *= 60.0;
114  if (*hue < 0.0)
115  *hue += 360.0;
116  }
117 }
118 
119 
120 int
121 bu_hsv_to_rgb(fastf_t *hsv, unsigned char *rgb)
122 {
123  fastf_t float_rgb[3] = { 0.0, 0.0, 0.0 };
124  fastf_t hue, sat, val;
125  fastf_t hue_frac;
126  fastf_t p, q, t;
127  long int hue_int;
128 
129  hue = hsv[HUE];
130  sat = hsv[SAT];
131  val = hsv[VAL];
132 
133  if ((((hue < 0.0) || (hue > 360.0)) && (!NEAR_ZERO(hue - ACHROMATIC, SMALL_FASTF))) /* hue != ACHROMATIC */
134  || (sat < 0.0) || (sat > 1.0)
135  || (val < 0.0) || (val > 1.0)
136  || ((NEAR_ZERO(hue - ACHROMATIC, SMALL_FASTF)) && (sat > 0.0))) /* hue == ACHROMATIC */
137  {
138  bu_log("bu_hsv_to_rgb: Illegal HSV (%g, %g, %g)\n",
139  V3ARGS(hsv));
140  return 0;
141  }
142 
143  /* so hue == ACHROMATIC (or is ignored) */
144  if (NEAR_ZERO(sat, SMALL_FASTF)) {
145  VSETALL(float_rgb, val);
146  } else {
147  if (NEAR_ZERO(hue - 360.0, SMALL_FASTF))
148  hue = 0.0;
149  hue /= 60.0;
150  hue_int = lrint(floor((double)hue));
151  hue_frac = hue - hue_int;
152  p = val * (1.0 - sat);
153  q = val * (1.0 - (sat * hue_frac));
154  t = val * (1.0 - (sat * (1.0 - hue_frac)));
155  switch (hue_int) {
156  case 0: VSET(float_rgb, val, t, p); break;
157  case 1: VSET(float_rgb, q, val, p); break;
158  case 2: VSET(float_rgb, p, val, t); break;
159  case 3: VSET(float_rgb, p, q, val); break;
160  case 4: VSET(float_rgb, t, p, val); break;
161  case 5: VSET(float_rgb, val, p, q); break;
162  default:
163  bu_log("%s:%d: This shouldn't happen\n",
164  __FILE__, __LINE__);
165  bu_bomb("unexpected condition encountered in bu_hsv_to_rgb\n");
166  }
167  }
168 
169  rgb[RED] = (unsigned char)lrint(float_rgb[RED] * 255.0);
170  rgb[GRN] = (unsigned char)lrint(float_rgb[GRN] * 255.0);
171  rgb[BLU] = (unsigned char)lrint(float_rgb[BLU] * 255.0);
172 
173  return 1;
174 }
175 
176 
177 int
178 bu_str_to_rgb(char *str, unsigned char *rgb)
179 {
180  int num;
181  unsigned int r = 0;
182  unsigned int g = 0;
183  unsigned int b = 0;
184 
185  if (UNLIKELY(!str || !rgb)) {
186  return 0;
187  }
188 
189  while (isspace((int)(*str)))
190  ++str;
191 
192  if (*str == '#') {
193  if (strlen(++str) != 6)
194  return 0;
195  sscanf(str, "%02x%02x%02x", (unsigned int *)&r, (unsigned int *)&g, (unsigned int *)&b);
196  } else if (isdigit((int)(*str))) {
197  num = sscanf(str, "%u/%u/%u", &r, &g, &b);
198  if (num == 1) {
199  num = sscanf(str, "%u %u %u", &r, &g, &b);
200  if (num != 3)
201  return 0;
202  }
203  if (r > 255)
204  r = 255;
205  if (g > 255)
206  g = 255;
207  if (b > 255)
208  b = 255;
209  } else {
210  return 0;
211  }
212 
213  VSET(rgb, (fastf_t)r, (fastf_t)g, (fastf_t)b);
214 
215  return 1;
216 }
217 
218 
219 int
221 {
222  if (UNLIKELY(!cp || !rgb)) {
223  return 0;
224  }
225 
226  rgb[0] = cp->buc_rgb[RED];
227  rgb[1] = cp->buc_rgb[GRN];
228  rgb[2] = cp->buc_rgb[BLU];
229 
230  return 1;
231 }
232 
233 
234 int
236 {
237  if (UNLIKELY(!cp || !rgb)) {
238  return 0;
239  }
240 
241  cp->buc_rgb[RED] = rgb[0];
242  cp->buc_rgb[GRN] = rgb[1];
243  cp->buc_rgb[BLU] = rgb[2];
244 
245  return 1;
246 }
247 
248 /*
249  * Local Variables:
250  * mode: C
251  * tab-width: 8
252  * indent-tabs-mode: t
253  * c-file-style: "stroustrup"
254  * End:
255  * ex: shiftwidth=4 tabstop=8
256  */
Definition: db_flip.c:35
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define HUE
Definition: color.c:38
int bu_hsv_to_rgb(fastf_t *hsv, unsigned char *rgb)
Definition: color.c:121
int bu_str_to_rgb(char *str, unsigned char *rgb)
Definition: color.c:178
#define VAL
Definition: color.c:40
fastf_t buc_rgb[3]
Definition: color.h:52
#define VSET(a, b, c, d)
Definition: color.c:53
#define VSETALL(a, s)
Definition: color.c:54
#define SMALL_FASTF
Definition: defines.h:342
#define RED
Definition: color.c:42
Header file for the BRL-CAD common definitions.
void bu_rgb_to_hsv(unsigned char *rgb, fastf_t *hsv)
Definition: color.c:60
Definition: color.c:49
#define ACHROMATIC
Definition: color.c:36
int bu_color_to_rgb_floats(struct bu_color *cp, fastf_t *rgb)
Definition: color.c:220
#define V3ARGS(a)
Definition: color.c:56
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
int bu_color_from_rgb_floats(struct bu_color *cp, fastf_t *rgb)
Definition: color.c:235
#define SAT
Definition: color.c:39
axis
Definition: color.c:48
Definition: color.c:51
#define GRN
Definition: color.c:43
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
double fastf_t
Definition: defines.h:300
Definition: color.h:49
Definition: color.c:50
#define BLU
Definition: color.c:44
#define UNLIKELY(expression)
Definition: common.h:282