1f7f4fc74899d0953b9152a0c2985f8e36f1c9e3
[gencolormap.git] / cmdline.cpp
1 /*
2  * Copyright (C) 2015, 2016 Computer Graphics Group, University of Siegen
3  * Written by Martin Lambers <martin.lambers@uni-siegen.de>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 #include <vector>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28 #include <cmath>
29
30 #include <getopt.h>
31 extern char *optarg;
32 extern int optind;
33
34 #include "colormap.hpp"
35
36 enum type {
37     brewer_sequential = 0,
38     brewer_diverging = 1,
39     brewer_qualitative = 2,
40     cubehelix = 3,
41     morelanddiverging = 4
42 };
43
44 int main(int argc, char* argv[])
45 {
46     bool print_version = false;
47     bool print_help = false;
48     int type = -1;
49     int n = -1;
50     float hue = -1.0f;
51     float divergence = -1.0f;
52     float contrast = -1.0f;
53     float saturation = -1.0f;
54     float brightness = -1.0f;
55     float warmth = -1.0f;
56     float rotations = NAN;
57     float gamma = -1.0f;
58     bool have_color0 = false;
59     unsigned char color0[3];
60     bool have_color1 = false;
61     unsigned char color1[3];
62     struct option options[] = {
63         { "version",    no_argument,       0, 'v' },
64         { "help",       no_argument,       0, 'H' },
65         { "type",       required_argument, 0, 't' },
66         { "n",          required_argument, 0, 'n' },
67         { "hue",        required_argument, 0, 'h' },
68         { "divergence", required_argument, 0, 'd' },
69         { "contrast",   required_argument, 0, 'c' },
70         { "saturation", required_argument, 0, 's' },
71         { "brightness", required_argument, 0, 'b' },
72         { "warmth",     required_argument, 0, 'w' },
73         { "rotations",  required_argument, 0, 'r' },
74         { "gamma",      required_argument, 0, 'g' },
75         { "color0",     required_argument, 0, 'A' },
76         { "color1",     required_argument, 0, 'O' },
77         { 0, 0, 0, 0 }
78     };
79
80     for (;;) {
81         int c = getopt_long(argc, argv, "vHt:n:h:d:c:s:b:w:r:g:A:O:", options, NULL);
82         if (c == -1)
83             break;
84         switch (c) {
85         case 'v':
86             print_version = true;
87             break;
88         case 'H':
89             print_help = true;
90             break;
91         case 't':
92             type = (strcmp(optarg, "brewer-sequential") == 0 ? brewer_sequential
93                     : strcmp(optarg, "brewer-diverging") == 0 ? brewer_diverging
94                     : strcmp(optarg, "brewer-qualitative") == 0 ? brewer_qualitative
95                     : strcmp(optarg, "cubehelix") == 0 ? cubehelix
96                     : strcmp(optarg, "morelanddiverging") == 0 ? morelanddiverging
97                     : -2);
98             break;
99         case 'n':
100             n = atoi(optarg);
101             break;
102         case 'h':
103             hue = atof(optarg) * M_PI / 180.0;
104             break;
105         case 'd':
106             divergence = atof(optarg) * M_PI / 180.0;
107             break;
108         case 'c':
109             contrast = atof(optarg);
110             break;
111         case 's':
112             saturation = atof(optarg);
113             break;
114         case 'b':
115             brightness = atof(optarg);
116             break;
117         case 'w':
118             warmth = atof(optarg);
119             break;
120         case 'r':
121             rotations = atof(optarg);
122             break;
123         case 'g':
124             gamma = atof(optarg);
125             break;
126         case 'A':
127             std::sscanf(optarg, "%hhu,%hhu,%hhu", color0 + 0, color0 + 1, color0 + 2);
128             have_color0 = true;
129             break;
130         case 'O':
131             std::sscanf(optarg, "%hhu,%hhu,%hhu", color1 + 0, color1 + 1, color1 + 2);
132             have_color1 = true;
133             break;
134         default:
135             return 1;
136         }
137     }
138
139     if (print_version) {
140         printf("gencolormap version 0.2\n"
141                 "Copyright (C) 2016 Computer Graphics Group, University of Siegen.\n"
142                 "Written by Martin Lambers <martin.lambers@uni-siegen.de>.\n"
143                 "This is free software under the terms of the MIT/Expat License.\n"
144                 "There is NO WARRANTY, to the extent permitted by law.\n");
145         return 0;
146     }
147
148     if (print_help) {
149         printf("Usage: %s\n"
150                 "  Common options, required for all types:\n"
151                 "    -n|--n=N                      Set number of colors in the map\n"
152                 "  Brewer-like color maps:\n"
153                 "    -t|--type=brewer-sequential   Generate a sequential color map\n"
154                 "    -t|--type=brewer-diverging    Generate a diverging color map\n"
155                 "    -t|--type=brewer-qualitative  Generate a qualitative color map\n"
156                 "    [-h|--hue=H]                  Set default hue in [0,360] degrees\n"
157                 "    [-c|--contrast=C]             Set contrast in [0,1]\n"
158                 "    [-s|--saturation=S]           Set saturation in [0,1]\n"
159                 "    [-b|--brightness=B]           Set brightness in [0,1]\n"
160                 "    [-w|--warmth=W]               Set warmth in [0,1] for seq. and div. maps\n"
161                 "    [-d|--divergence=D]           Set divergence for div. and qual. maps\n"
162                 "  CubeHelix color maps:\n"
163                 "    -t|--type=cubehelix           Generate a CubeHelix color map\n"
164                 "    [-r|--rotations=R]            Set number of rotations, in (-infty,infty)\n"
165                 "    [-s|--saturation=S]           Set saturation, in [0,1]\n"
166                 "    [-g|--gamma=G]                Set gamma correction, in (0,infty)\n"
167                 "  MorelandDiverging color maps:\n"
168                 "    -t|--type=morelanddiverging   Generate a Moreland diverging color map\n"
169                 "    [-A|--color0=sr,sg,sb         Set the first color as sRGB values in [0,255]\n"
170                 "    [-O|--color1=sr,sg,sb         Set the last color as sRGB values in [0,255]\n"
171                 "Generates a color map and prints it to standard output as sRGB triplets.\n"
172                 "Report bugs to <martin.lambers@uni-siegen.de>.\n", argv[0]);
173         return 0;
174     }
175
176     if (type < 0) {
177         fprintf(stderr, "Invalid or missing option -t|--type.\n");
178         return 1;
179     }
180     if (n < 2) {
181         fprintf(stderr, "Invalid or missing option -n|--n.\n");
182         return 1;
183     }
184     if (hue < 0.0f) {
185         if (type == brewer_sequential)
186             hue = ColorMap::BrewerSequentialDefaultHue;
187         else if (type == brewer_diverging)
188             hue = ColorMap::BrewerDivergingDefaultHue;
189         else if (type == brewer_qualitative)
190             hue = ColorMap::BrewerQualitativeDefaultHue;
191         else if (type == cubehelix)
192             hue = ColorMap::CubeHelixDefaultHue;
193     }
194     if (divergence < 0.0f) {
195         if (type == brewer_diverging)
196             divergence = ColorMap::BrewerDivergingDefaultDivergence;
197         else if (type == brewer_qualitative)
198             divergence = ColorMap::BrewerQualitativeDefaultDivergence;
199     }
200     if (contrast < 0.0f) {
201         if (type == brewer_sequential)
202             contrast = (n <= 9 ? ColorMap::BrewerSequentialDefaultContrastForSmallN(n)
203                     : ColorMap::BrewerSequentialDefaultContrast);
204         else if (type == brewer_diverging)
205             contrast = (n <= 9 ? ColorMap::BrewerDivergingDefaultContrastForSmallN(n)
206                     : ColorMap::BrewerDivergingDefaultContrast);
207         else if (type == brewer_qualitative)
208             contrast = ColorMap::BrewerQualitativeDefaultContrast;
209     }
210     if (saturation < 0.0f) {
211         if (type == brewer_sequential)
212             saturation = ColorMap::BrewerSequentialDefaultSaturation;
213         else if (type == brewer_diverging)
214             saturation = ColorMap::BrewerDivergingDefaultSaturation;
215         else if (type == brewer_qualitative)
216             saturation = ColorMap::BrewerQualitativeDefaultSaturation;
217         else if (type == cubehelix)
218             saturation = ColorMap::CubeHelixDefaultSaturation;
219     }
220     if (brightness < 0.0f) {
221         if (type == brewer_sequential)
222             brightness = ColorMap::BrewerSequentialDefaultBrightness;
223         else if (type == brewer_diverging)
224             brightness = ColorMap::BrewerDivergingDefaultBrightness;
225         else if (type == brewer_qualitative)
226             brightness = ColorMap::BrewerQualitativeDefaultBrightness;
227     }
228     if (warmth < 0.0f) {
229         if (type == brewer_sequential)
230             brightness = ColorMap::BrewerSequentialDefaultWarmth;
231         else if (type == brewer_diverging)
232             brightness = ColorMap::BrewerDivergingDefaultWarmth;
233     }
234     if (std::isnan(rotations)) {
235         if (type == cubehelix)
236             rotations = ColorMap::CubeHelixDefaultRotations;
237     }
238     if (gamma < 0.0f) {
239         if (type == cubehelix)
240             gamma = ColorMap::CubeHelixDefaultGamma;
241     }
242     if (!have_color0) {
243         if (type == morelanddiverging) {
244             color0[0] = ColorMap::MorelandDivergingDefaultR0;
245             color0[1] = ColorMap::MorelandDivergingDefaultG0;
246             color0[2] = ColorMap::MorelandDivergingDefaultB0;
247         }
248     }
249     if (!have_color1) {
250         if (type == morelanddiverging) {
251             color1[0] = ColorMap::MorelandDivergingDefaultR1;
252             color1[1] = ColorMap::MorelandDivergingDefaultG1;
253             color1[2] = ColorMap::MorelandDivergingDefaultB1;
254         }
255     }
256
257     std::vector<unsigned char> colormap(3 * n);
258     switch (type) {
259     case brewer_sequential:
260         ColorMap::BrewerSequential(n, &(colormap[0]), hue, contrast, saturation, brightness, warmth);
261         break;
262     case brewer_diverging:
263         ColorMap::BrewerDiverging(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness, warmth);
264         break;
265     case brewer_qualitative:
266         ColorMap::BrewerQualitative(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness);
267         break;
268     case cubehelix:
269         ColorMap::CubeHelix(n, &(colormap[0]), hue, rotations, saturation, gamma);
270         break;
271     case morelanddiverging:
272         ColorMap::MorelandDiverging(n, &(colormap[0]),
273                 color0[0], color0[1], color0[2],
274                 color1[0], color1[1], color1[2]);
275         break;
276     }
277
278     for (int i = 0; i < n; i++) {
279         printf("%d, %d, %d\n", colormap[3 * i + 0], colormap[3 * i + 1], colormap[3 * i + 2]);
280     }
281
282     return 0;
283 }