219 lines
4.6 KiB
C++
219 lines
4.6 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <cmath>
|
|
#include <bitset>
|
|
#include <string>
|
|
#include <stdio.h>
|
|
#include <getopt.h>
|
|
|
|
using namespace std;
|
|
|
|
#define SECTION_COUNT 6
|
|
#define LAYERS 4
|
|
#define OUTLINE 1
|
|
|
|
typedef struct point
|
|
{
|
|
double x;
|
|
double y;
|
|
} point;
|
|
|
|
void add_hex(char *data, ofstream& file, double height,
|
|
int layer_order[4], int x_count = 0, int y_count = 0)
|
|
{
|
|
point pts[LAYERS + 1][SECTION_COUNT];
|
|
point center;
|
|
double layer_mod[LAYERS + 1] = {1.0, 0.9, 0.5, 0.4, 0.0};
|
|
double section_rad[SECTION_COUNT] = {90, 30, 330, 270, 210, 150};
|
|
double offset;
|
|
int layer;
|
|
int section;
|
|
bitset<LAYERS * SECTION_COUNT> bits;
|
|
|
|
if (NULL == data)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < LAYERS * SECTION_COUNT / 8; ++i)
|
|
{
|
|
for (int j = 0; j < 8; ++j)
|
|
{
|
|
bits[i * 8 + j] = data[i] & (0x80 >> j);
|
|
}
|
|
}
|
|
|
|
offset = height * 1.1;
|
|
center.x = height / 2;
|
|
center.y = height / 2;
|
|
center.x += offset * x_count;
|
|
center.y += offset * y_count;
|
|
|
|
// Calculate Points
|
|
for (layer = 0; layer < LAYERS + 1; ++layer)
|
|
{
|
|
for (section = 0; section < SECTION_COUNT; ++section)
|
|
{
|
|
pts[layer][section].x = cos(section_rad[section] * M_PI / 180.0) *
|
|
layer_mod[layer] * height / 2 + center.x;
|
|
pts[layer][section].y = -sin(section_rad[section] * M_PI / 180.0) *
|
|
layer_mod[layer] * height / 2 + center.y;
|
|
}
|
|
}
|
|
|
|
#if OUTLINE
|
|
// Draw Outline
|
|
file <<
|
|
"\t<g id=\"hex\" fill=\"none\" stroke=\"#000000\" stroke-width=\"" <<
|
|
height / 100 << "\">" << endl;
|
|
for (layer = 0; layer < LAYERS; ++layer)
|
|
{
|
|
file << "\t\t<path d=\"M " << pts[layer][0].x << " " << pts[layer][0].y;
|
|
for (section = 1; section < SECTION_COUNT; ++section)
|
|
{
|
|
file << " L " << pts[layer][section].x <<
|
|
" " << pts[layer][section].y;
|
|
}
|
|
file << " Z\"/>" << endl;
|
|
}
|
|
|
|
for (section = 0; section < SECTION_COUNT / 2; ++section)
|
|
{
|
|
file << "\t\t<path d=\"M " << pts[0][section].x <<
|
|
" " << pts[0][section].y <<
|
|
" L " << pts[0][section + SECTION_COUNT / 2].x <<
|
|
" " << pts[0][section + SECTION_COUNT / 2].y <<
|
|
" Z\"/>" << endl;
|
|
}
|
|
|
|
file << "\t</g>" << endl;
|
|
#endif
|
|
// Fill Hexes
|
|
file << "\t<g id=\"fill\">" << endl;
|
|
for (section = 0; section < SECTION_COUNT; ++section)
|
|
{
|
|
for (int i = 0; i < LAYERS; ++i)
|
|
{
|
|
layer = layer_order[i];
|
|
if (bits.test(section * LAYERS + i))
|
|
{
|
|
file << "\t\t<path d=\"" <<
|
|
"M " << pts[layer][section].x <<
|
|
" " << pts[layer][section].y <<
|
|
" L " << pts[layer][(section + 1) % SECTION_COUNT].x <<
|
|
" " << pts[layer][(section + 1) % SECTION_COUNT].y <<
|
|
" L " << pts[layer + 1][(section + 1) % SECTION_COUNT].x <<
|
|
" " << pts[layer + 1][(section + 1) % SECTION_COUNT].y <<
|
|
" L " << pts[layer + 1][section].x <<
|
|
" " << pts[layer + 1][section].y <<
|
|
" Z\" fill=\"#000000\"/>" << endl;
|
|
}
|
|
}
|
|
}
|
|
file << "\t</g>" << endl;
|
|
}
|
|
|
|
void print_usage(const char *name)
|
|
{
|
|
printf("Usage: %s [options] <data>\n", name);
|
|
printf("\t-o <output filename> (default - out.svg)\n");
|
|
printf("\t-s <size> (default - 300)\n");
|
|
printf("'data' must be at least 3 bytes in hex format.\n"
|
|
"More than that will be ignored\n"
|
|
"E.g. '97C1A3'\n");
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int order[4] = {1,3,0,2};
|
|
double height = 300;
|
|
char data[3] = {0, 0, 0};
|
|
string data_str;
|
|
string filename = "out.svg";
|
|
ofstream file;
|
|
|
|
const char optstr[] = "o:s:";
|
|
int opt;
|
|
|
|
// Parse arguments
|
|
opt = getopt(argc, argv, optstr);
|
|
while (opt != -1)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'o':
|
|
if (NULL == optarg)
|
|
{
|
|
printf("'o' requires a filename\n");
|
|
return -1;
|
|
}
|
|
filename = optarg;
|
|
break;
|
|
|
|
case 's':
|
|
if (NULL == optarg)
|
|
{
|
|
printf("'s' requires a size\n");
|
|
return -1;
|
|
}
|
|
height = stod(optarg);
|
|
break;
|
|
|
|
case '?':
|
|
print_usage(argv[0]);
|
|
return 0;
|
|
break;
|
|
|
|
default:
|
|
printf("Unknown parameter '%c'\n", opt);
|
|
print_usage(argv[0]);
|
|
return -1;
|
|
break;
|
|
}
|
|
opt = getopt(argc, argv, optstr);
|
|
}
|
|
|
|
if (optind >= argc)
|
|
{
|
|
printf("Missing 'data'\n");
|
|
print_usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
// Parse data
|
|
data_str = argv[optind];
|
|
if (data_str.size() < 6)
|
|
{
|
|
printf("Not enough data\n");
|
|
print_usage(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
try
|
|
{
|
|
data[i] = stoi(data_str.substr(i * 2, 2), NULL, 16);
|
|
}
|
|
catch (exception &e)
|
|
{
|
|
printf("Bad data for byte %d\n", i);
|
|
}
|
|
}
|
|
|
|
// Write file
|
|
file.open(filename, ios_base::out);
|
|
file << "<svg xmlns=\"http://www.w3.org/2000/svg\" " <<
|
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" " <<
|
|
"width=\"100%\" height=\"100%\" " <<
|
|
"viewBox=\"" << -height * 0.05 << " " << -height * 0.05 << " " <<
|
|
height * 1.1 << " " << height * 1.1 << "\">" << endl;
|
|
|
|
add_hex(data, file, height, order);
|
|
|
|
file << "</svg>" << endl;
|
|
file.close();
|
|
|
|
return 0;
|
|
}
|