Implement McNames color maps, but discourage their use.
[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     mcnamessequential = 5
43 };
44
45 int main(int argc, char* argv[])
46 {
47     bool print_version = false;
48     bool print_help = false;
49     int type = -1;
50     int n = -1;
51     float hue = -1.0f;
52     float divergence = -1.0f;
53     float contrast = -1.0f;
54     float saturation = -1.0f;
55     float brightness = -1.0f;
56     float warmth = -1.0f;
57     float rotations = NAN;
58     float gamma = -1.0f;
59     bool have_color0 = false;
60     unsigned char color0[3];
61     bool have_color1 = false;
62     unsigned char color1[3];
63     float periods = NAN;
64     struct option options[] = {
65         { "version",    no_argument,       0, 'v' },
66         { "help",       no_argument,       0, 'H' },
67         { "type",       required_argument, 0, 't' },
68         { "n",          required_argument, 0, 'n' },
69         { "hue",        required_argument, 0, 'h' },
70         { "divergence", required_argument, 0, 'd' },
71         { "contrast",   required_argument, 0, 'c' },
72         { "saturation", required_argument, 0, 's' },
73         { "brightness", required_argument, 0, 'b' },
74         { "warmth",     required_argument, 0, 'w' },
75         { "rotations",  required_argument, 0, 'r' },
76         { "gamma",      required_argument, 0, 'g' },
77         { "color0",     required_argument, 0, 'A' },
78         { "color1",     required_argument, 0, 'O' },
79         { "periods",    required_argument, 0, 'p' },
80         { 0, 0, 0, 0 }
81     };
82
83     for (;;) {
84         int c = getopt_long(argc, argv, "vHt:n:h:d:c:s:b:w:r:g:A:O:p:", options, NULL);
85         if (c == -1)
86             break;
87         switch (c) {
88         case 'v':
89             print_version = true;
90             break;
91         case 'H':
92             print_help = true;
93             break;
94         case 't':
95             type = (strcmp(optarg, "brewer-sequential") == 0 ? brewer_sequential
96                     : strcmp(optarg, "brewer-diverging") == 0 ? brewer_diverging
97                     : strcmp(optarg, "brewer-qualitative") == 0 ? brewer_qualitative
98                     : strcmp(optarg, "cubehelix") == 0 ? cubehelix
99                     : strcmp(optarg, "morelanddiverging") == 0 ? morelanddiverging
100                     : strcmp(optarg, "mcnamessequential") == 0 ? mcnamessequential
101                     : -2);
102             break;
103         case 'n':
104             n = atoi(optarg);
105             break;
106         case 'h':
107             hue = atof(optarg) * M_PI / 180.0;
108             break;
109         case 'd':
110             divergence = atof(optarg) * M_PI / 180.0;
111             break;
112         case 'c':
113             contrast = atof(optarg);
114             break;
115         case 's':
116             saturation = atof(optarg);
117             break;
118         case 'b':
119             brightness = atof(optarg);
120             break;
121         case 'w':
122             warmth = atof(optarg);
123             break;
124         case 'r':
125             rotations = atof(optarg);
126             break;
127         case 'g':
128             gamma = atof(optarg);
129             break;
130         case 'A':
131             std::sscanf(optarg, "%hhu,%hhu,%hhu", color0 + 0, color0 + 1, color0 + 2);
132             have_color0 = true;
133             break;
134         case 'O':
135             std::sscanf(optarg, "%hhu,%hhu,%hhu", color1 + 0, color1 + 1, color1 + 2);
136             have_color1 = true;
137             break;
138         case 'p':
139             periods = atof(optarg);
140             break;
141         default:
142             return 1;
143         }
144     }
145
146     if (print_version) {
147         printf("gencolormap version 0.3\n"
148                 "Copyright (C) 2016 Computer Graphics Group, University of Siegen.\n"
149                 "Written by Martin Lambers <martin.lambers@uni-siegen.de>.\n"
150                 "This is free software under the terms of the MIT/Expat License.\n"
151                 "There is NO WARRANTY, to the extent permitted by law.\n");
152         return 0;
153     }
154
155     if (print_help) {
156         printf("Usage: %s\n"
157                 "  Common options, required for all types:\n"
158                 "    -n|--n=N                      Set number of colors in the map\n"
159                 "  Brewer-like color maps:\n"
160                 "    -t|--type=brewer-sequential   Generate a sequential color map\n"
161                 "    -t|--type=brewer-diverging    Generate a diverging color map\n"
162                 "    -t|--type=brewer-qualitative  Generate a qualitative color map\n"
163                 "    [-h|--hue=H]                  Set default hue in [0,360] degrees\n"
164                 "    [-c|--contrast=C]             Set contrast in [0,1]\n"
165                 "    [-s|--saturation=S]           Set saturation in [0,1]\n"
166                 "    [-b|--brightness=B]           Set brightness in [0,1]\n"
167                 "    [-w|--warmth=W]               Set warmth in [0,1] for seq. and div. maps\n"
168                 "    [-d|--divergence=D]           Set divergence for div. and qual. maps\n"
169                 "  CubeHelix color maps:\n"
170                 "    -t|--type=cubehelix           Generate a CubeHelix color map\n"
171                 "    [-r|--rotations=R]            Set number of rotations, in (-infty,infty)\n"
172                 "    [-s|--saturation=S]           Set saturation, in [0,1]\n"
173                 "    [-g|--gamma=G]                Set gamma correction, in (0,infty)\n"
174                 "  Moreland diverging color maps:\n"
175                 "    -t|--type=morelanddiverging   Generate a Moreland diverging color map\n"
176                 "    [-A|--color0=sr,sg,sb         Set the first color as sRGB values in [0,255]\n"
177                 "    [-O|--color1=sr,sg,sb         Set the last color as sRGB values in [0,255]\n"
178                 "  McNames sequential color maps:\n"
179                 "    -t|--type=mcnamessequential   Generate a McNames sequential color map\n"
180                 "    [-p|--periods=p]              Set the number of periods in (0, infty)\n"
181                 "Generates a color map and prints it to standard output as sRGB triplets.\n"
182                 "Report bugs to <martin.lambers@uni-siegen.de>.\n", argv[0]);
183         return 0;
184     }
185
186     if (type < 0) {
187         fprintf(stderr, "Invalid or missing option -t|--type.\n");
188         return 1;
189     }
190     if (n < 2) {
191         fprintf(stderr, "Invalid or missing option -n|--n.\n");
192         return 1;
193     }
194     if (hue < 0.0f) {
195         if (type == brewer_sequential)
196             hue = ColorMap::BrewerSequentialDefaultHue;
197         else if (type == brewer_diverging)
198             hue = ColorMap::BrewerDivergingDefaultHue;
199         else if (type == brewer_qualitative)
200             hue = ColorMap::BrewerQualitativeDefaultHue;
201         else if (type == cubehelix)
202             hue = ColorMap::CubeHelixDefaultHue;
203     }
204     if (divergence < 0.0f) {
205         if (type == brewer_diverging)
206             divergence = ColorMap::BrewerDivergingDefaultDivergence;
207         else if (type == brewer_qualitative)
208             divergence = ColorMap::BrewerQualitativeDefaultDivergence;
209     }
210     if (contrast < 0.0f) {
211         if (type == brewer_sequential)
212             contrast = (n <= 9 ? ColorMap::BrewerSequentialDefaultContrastForSmallN(n)
213                     : ColorMap::BrewerSequentialDefaultContrast);
214         else if (type == brewer_diverging)
215             contrast = (n <= 9 ? ColorMap::BrewerDivergingDefaultContrastForSmallN(n)
216                     : ColorMap::BrewerDivergingDefaultContrast);
217         else if (type == brewer_qualitative)
218             contrast = ColorMap::BrewerQualitativeDefaultContrast;
219     }
220     if (saturation < 0.0f) {
221         if (type == brewer_sequential)
222             saturation = ColorMap::BrewerSequentialDefaultSaturation;
223         else if (type == brewer_diverging)
224             saturation = ColorMap::BrewerDivergingDefaultSaturation;
225         else if (type == brewer_qualitative)
226             saturation = ColorMap::BrewerQualitativeDefaultSaturation;
227         else if (type == cubehelix)
228             saturation = ColorMap::CubeHelixDefaultSaturation;
229     }
230     if (brightness < 0.0f) {
231         if (type == brewer_sequential)
232             brightness = ColorMap::BrewerSequentialDefaultBrightness;
233         else if (type == brewer_diverging)
234             brightness = ColorMap::BrewerDivergingDefaultBrightness;
235         else if (type == brewer_qualitative)
236             brightness = ColorMap::BrewerQualitativeDefaultBrightness;
237     }
238     if (warmth < 0.0f) {
239         if (type == brewer_sequential)
240             brightness = ColorMap::BrewerSequentialDefaultWarmth;
241         else if (type == brewer_diverging)
242             brightness = ColorMap::BrewerDivergingDefaultWarmth;
243     }
244     if (std::isnan(rotations)) {
245         if (type == cubehelix)
246             rotations = ColorMap::CubeHelixDefaultRotations;
247     }
248     if (gamma < 0.0f) {
249         if (type == cubehelix)
250             gamma = ColorMap::CubeHelixDefaultGamma;
251     }
252     if (!have_color0) {
253         if (type == morelanddiverging) {
254             color0[0] = ColorMap::MorelandDivergingDefaultR0;
255             color0[1] = ColorMap::MorelandDivergingDefaultG0;
256             color0[2] = ColorMap::MorelandDivergingDefaultB0;
257         }
258     }
259     if (!have_color1) {
260         if (type == morelanddiverging) {
261             color1[0] = ColorMap::MorelandDivergingDefaultR1;
262             color1[1] = ColorMap::MorelandDivergingDefaultG1;
263             color1[2] = ColorMap::MorelandDivergingDefaultB1;
264         }
265     }
266     if (std::isnan(periods)) {
267         if (type == mcnamessequential)
268             periods = ColorMap::McNamesSequentialDefaultPeriods;
269     }
270
271     std::vector<unsigned char> colormap(3 * n);
272     switch (type) {
273     case brewer_sequential:
274         ColorMap::BrewerSequential(n, &(colormap[0]), hue, contrast, saturation, brightness, warmth);
275         break;
276     case brewer_diverging:
277         ColorMap::BrewerDiverging(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness, warmth);
278         break;
279     case brewer_qualitative:
280         ColorMap::BrewerQualitative(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness);
281         break;
282     case cubehelix:
283         ColorMap::CubeHelix(n, &(colormap[0]), hue, rotations, saturation, gamma);
284         break;
285     case morelanddiverging:
286         ColorMap::MorelandDiverging(n, &(colormap[0]),
287                 color0[0], color0[1], color0[2],
288                 color1[0], color1[1], color1[2]);
289         break;
290     case mcnamessequential:
291         ColorMap::McNamesSequential(n, &(colormap[0]), periods);
292         break;
293     }
294
295     for (int i = 0; i < n; i++) {
296         printf("%d, %d, %d\n", colormap[3 * i + 0], colormap[3 * i + 1], colormap[3 * i + 2]);
297     }
298
299     return 0;
300 }