1 /*****************************************************************************
2 
3   Example program for vtzero library.
4 
5   vtzero-encode-geom - Encode geometry on command line
6 
7   This can be used for debugging. Uses internals of vtzero!
8 
9 *****************************************************************************/
10 
11 #include "utils.hpp"
12 
13 #include <vtzero/geometry.hpp>
14 
15 #include <cctype>
16 #include <cstdlib>
17 #include <iostream>
18 #include <stdexcept>
19 #include <string>
20 #include <vector>
21 
get_int(const char * arg)22 int64_t get_int(const char* arg) {
23     char* endptr = nullptr;
24     const int64_t value = std::strtoll(arg, &endptr, 10);
25 
26     if (*endptr == '\0') {
27         return value;
28     }
29 
30     throw std::runtime_error{"not a valid number"};
31 }
32 
move_to(const char * arg)33 uint32_t move_to(const char* arg) {
34     if (!std::isdigit(arg[0])) {
35         throw std::runtime_error{"need count after M command"};
36     }
37 
38     const auto scount = get_int(arg);
39     if (scount <= 0) {
40         throw std::runtime_error{"count after M command must be 1 or larger"};
41     }
42     const auto count = static_cast<uint32_t>(scount);
43     std::cout << "MOVE_TO(" << count << ")\t" << vtzero::detail::command_move_to(count) << '\n';
44 
45     return vtzero::detail::command_move_to(count);
46 }
47 
line_to(const char * arg)48 uint32_t line_to(const char* arg) {
49     if (!std::isdigit(arg[0])) {
50         throw std::runtime_error{"need count after L command"};
51     }
52 
53     const auto scount = get_int(arg);
54     if (scount <= 0) {
55         throw std::runtime_error{"count after L command must be 1 or larger"};
56     }
57     const auto count = static_cast<uint32_t>(scount);
58     std::cout << "LINE_TO(" << count << ")\t" << vtzero::detail::command_line_to(count) << '\n';
59 
60     return vtzero::detail::command_line_to(count);
61 }
62 
close_path(const char * arg)63 uint32_t close_path(const char* arg) {
64     if (arg[0] != '\0') {
65         throw std::runtime_error{"extra data after C command"};
66     }
67     std::cout << "CLOSE_PATH\t" << vtzero::detail::command_close_path() << '\n';
68 
69     return vtzero::detail::command_close_path();
70 }
71 
number(const char * arg)72 uint32_t number(const char* arg) {
73     const auto num = static_cast<int32_t>(get_int(arg));
74     std::cout << "number(" << num << ")\t" << protozero::encode_zigzag32(num) << '\n';
75 
76     return protozero::encode_zigzag32(num);
77 }
78 
main(int argc,char * argv[])79 int main(int argc, char* argv[]) {
80     if (argc < 2) {
81         std::cerr << "Usage: " << argv[0] << " GEOMETRY ELEMENTS...\n"
82                   << "GEOMETRY ELEMENTS are:\n"
83                   << "  M[count] -- MOVE_TO count\n"
84                   << "  L[count] -- LINE_TO count\n"
85                   << "  C        -- CLOSE_PATH\n"
86                   << "  [number] -- number that will be zigzag encoded\n";
87         return 1;
88     }
89 
90     std::vector<uint32_t> values;
91 
92     std::cout << "raw data\tencoded\n-----------------------------------\n";
93     for (int i = 1; i < argc; ++i) {
94         try {
95             switch (argv[i][0]) {
96                 case '\0':
97                     break;
98                 case 'M':
99                     values.push_back(move_to(argv[i] + 1));
100                     break;
101                 case 'L':
102                     values.push_back(line_to(argv[i] + 1));
103                     break;
104                 case 'C':
105                     values.push_back(close_path(argv[i] + 1));
106                     break;
107                 case '-':
108                 case '0':
109                 case '1':
110                 case '2':
111                 case '3':
112                 case '4':
113                 case '5':
114                 case '6':
115                 case '7':
116                 case '8':
117                 case '9':
118                     values.push_back(number(argv[i]));
119                     break;
120                 default:
121                     throw std::runtime_error{std::string{"unknown data: "} + argv[i]};
122                     return 1;
123             }
124         } catch (const std::runtime_error& e) {
125             std::cerr << "error(" << i << "): " << e.what() << '\n';
126             return 1;
127         }
128     }
129 
130     std::string out{"["};
131 
132     for (auto value : values) {
133         out += ' ';
134         out += std::to_string(value);
135         out += ',';
136     }
137 
138     out.back() = ' ';
139 
140     std::cout << '\n' << out << "]\n";
141 }
142 
143