#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <helianthus.h>
#include "svg-save.inc.h"
char codes[10][2][10] = {
{ "0001101", "0100111" }, // 0
{ "0011001", "0110011" }, // 1
{ "0010011", "0011011" }, // 2
{ "0111101", "0100001" }, // 3
{ "0100011", "0011101" }, // 4
{ "0110001", "0111001" }, // 5
{ "0101111", "0000101" }, // 6
{ "0111011", "0010001" }, // 7
{ "0110111", "0001001" }, // 8
{ "0001011", "0010111" }, // 9
};
int seed;
double pb = 10;
double pw = 298;
double ph = 210;
double bh = 15;
double th = 5;
double step = 0.5;
unsigned long long genNum()
{ return rand()%1000000ull*1000000 + rand()%1000000; }
void drawCode(FILE *f, unsigned long long num, double x, double y, double w, double h, double hh) {
char numA[10] = {};
char numB[10] = {};
char code[] =
"101" // prefix
"[digit][digit][digit][digit][digit][digit]"
"01010" // separator
"[digit][digit][digit][digit][digit][digit]"
"101"; // suffix
int count = sizeof(code) - 1;
char path[2048] = {};
sprintf(numA, "%06d", (int)(num/1000000ull%1000000));
sprintf(numB, "%06d", (int)(num%1000000));
for(int i = 0; i < 6; ++i) {
memcpy(code + 3 + i*7 , codes[numA[i]-'0'][0], 6);
memcpy(code + 3 + 6*7 + 5 + i*7, codes[numB[i]-'0'][1], 6);
}
saveState();
noFill();
strokeWidth(w);
char *p = path;
for(int i = 0; i < count; ++i) {
if (code[i] != '1') continue;
int xl = i < 3
|| (i >= 3 + 6*7 && i < 3 + 6*7 + 5)
|| i >= 3 + 6*7 + 5 + 6*7;
double hhh = xl ? h + hh : h;
if (f) {
p += sprintf(p, "M %g %g l 0 %g ", x+i*w, y, hhh);
} else {
line(x+i*w, y, x+i*w, y + hhh);
}
}
if (f) {
svgAddPath(f, path, w, FALSE);
svgAddText(f, x + (3+2)*w, y + h + hh, hh, numA);
svgAddText(f, x + (3+6*7+5+2)*w, y + h + hh, hh, numB);
} else {
textSize(hh);
textAlign(HALIGN_CENTER, VALIGN_TOP);
text(x + (3+3*7)*w, y + h, numA);
text(x + (3+6*7+5+3*7)*w, y + h, numB);
}
restoreState();
}
void drawAllCodes(FILE *f) {
srand(seed);
double cw = step*(3 + 6*7 + 5 + 6*7 + 3);
double minSpace = 9*step;
double w = pw - 2*pb;
double h = ph - 2*pb;
int cols = (int)(w/(cw + minSpace) + 0.001);
int rows = (int)(h/(bh + th + th) + 0.001);
if (cols <= 0 || rows <= 0) return;
double exw = w - cols*cw;
double exh = h - rows*(bh+th);
if (cols > 1) exw /= cols - 1;
if (rows > 1) exh /= rows - 1;
double cww = cw + exw;
double chh = bh + th + exh;
for(int r = 0; r < rows; ++r)
for(int c = 0; c < cols; ++c)
drawCode(f, genNum(), pb + c*cww, pb + r*chh, step, bh, th);
}
void generate() {
seed = rand();
FILE *f = svgBegin("data/output/generated-barcode.svg", pw, ph, 1);
drawAllCodes(f);
svgEnd(f);
}
void init() {
generate();
}
void draw() {
double w = windowGetWidth();
double h = windowGetHeight();
double kw = w/pw;
double kh = h/ph;
double k = kw < kh ? kw : kh;
if (keyWentDown("space"))
generate();
saveState();
translate(w/2, h/2);
zoom(k);
translate(-pw/2, -ph/2);
noFill();
strokeWidth(1);
rect(0, 0, pw, ph);
drawAllCodes(NULL);
restoreState();
}
int main() {
windowSetVariableFrameRate();
windowSetResizable(TRUE);
windowSetInit(&init);
windowSetDraw(&draw);
windowRun();
}