kartrak.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * kartrak.c
  3. *
  4. * This code generates KarTrak codes as were previously used in the rail industry of the US
  5. * (description below). Output is as an SVG file. This system is now obsolete but perhaps
  6. * this will be of interest to model railway enthusiasts.
  7. *
  8. * "KarTrak, sometimes KarTrak ACI (for Automatic Car Identification) is a colored
  9. * bar code system designed to automatically identify rail cars and other rolling stock.
  10. * KarTrak was made a requirement in North America, but technical problems led to
  11. * abandonment of the system in the late 1970s."
  12. *
  13. * https://en.wikipedia.org/wiki/KarTrak
  14. *
  15. */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. void print_head(char car_number[], double bordersize) {
  20. printf("<?xml version=\"1.0\" standalone=\"no\"?>\n");
  21. printf("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n");
  22. printf(" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
  23. printf("<svg width=\"%.2fin\" height=\"%.2fin\" version=\"1.1\"\n", 5.75 + (2 * bordersize), 17.5 + (2 * bordersize));
  24. printf(" xmlns=\"http://www.w3.org/2000/svg\">\n");
  25. printf(" <desc>KarTrak ACI %s</desc>\n\n", car_number);
  26. printf(" <g id=\"kartrak\" fill = \"#000000\">\n");
  27. printf(" <rect x=\"0in\" y=\"0in\" width=\"%.2fin\" height=\"%.2fin\" fill=\"#000000\" />\n", 5.75 + (2 * bordersize), 17.5 + (2 * bordersize));
  28. }
  29. void print_foot() {
  30. printf(" </g>\n");
  31. printf("</svg>\n");
  32. }
  33. void print_check(double x, double y) {
  34. /* Print checkerboard */
  35. int w, h;
  36. for (h = 0; h < 6; h++) {
  37. for (w = 0; w < 69; w++) {
  38. if (((w + h) % 2) == 0) {
  39. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"0.08in\" height=\"0.08in\" fill=\"#ffffff\" />\n", x + (0.083 * w), y + (0.083 * h));
  40. }
  41. }
  42. }
  43. }
  44. void hrt(double x, double y, char c[]) {
  45. /* Add text to the left */
  46. printf(" <text x=\"%.2fin\" y=\"%.2fin\" font-family=\"Verdana\" font-size=\"25\">%s</text>\n", x + 0.2, y + 0.9, c);
  47. }
  48. void back_square(double x, double y) {
  49. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"0.17in\" height=\"0.25in\" fill=\"#ffffff\" />\n", x + 0.2, y + 0.7);
  50. }
  51. void print_zero(double x, double y) {
  52. print_check(x, y);
  53. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#0000e0\" />\n", x, y + 0.5);
  54. hrt(x, y, "0");
  55. }
  56. void print_one(double x, double y) {
  57. print_check(x, y);
  58. print_check(x, y + 0.5);
  59. back_square(x, y);
  60. hrt(x, y, "1");
  61. }
  62. void print_two(double x, double y) {
  63. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#ef0000\" />\n", x, y);
  64. print_check(x, y + 0.5);
  65. back_square(x, y);
  66. hrt(x, y, "2");
  67. }
  68. void print_three(double x, double y) {
  69. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#ef0000\" />\n", x, y + 0.5);
  70. hrt(x, y, "3");
  71. }
  72. void print_four(double x, double y) {
  73. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"1.00in\" fill=\"#ef0000\" />\n", x, y);
  74. hrt(x, y, "4");
  75. }
  76. void print_five(double x, double y) {
  77. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#0000e0\" />\n", x, y + 0.5);
  78. hrt(x, y, "5");
  79. }
  80. void print_six(double x, double y) {
  81. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#0000e0\" />\n", x, y);
  82. print_check(x, y + 0.5);
  83. back_square(x, y);
  84. hrt(x, y, "6");
  85. }
  86. void print_seven(double x, double y) {
  87. print_check(x, y);
  88. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#ef0000\" />\n", x, y + 0.5);
  89. hrt(x, y, "7");
  90. }
  91. void print_eight(double x, double y) {
  92. print_check(x, y + 0.5);
  93. back_square(x, y);
  94. hrt(x, y, "8");
  95. }
  96. void print_nine(double x, double y) {
  97. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"1.00in\" fill=\"#0000e0\" />\n", x, y);
  98. hrt(x, y, "9");
  99. }
  100. void print_ten(double x, double y) {
  101. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#ef0000\" />\n", x, y);
  102. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"5.75in\" height=\"0.5in\" fill=\"#0000e0\" />\n", x, y + 0.5);
  103. hrt(x, y, "10");
  104. }
  105. void print_start(double bordersize) {
  106. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"4.50in\" height=\"0.5in\" fill=\"#0000e0\" />\n", bordersize, 16.5 + bordersize);
  107. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"4.50in\" height=\"0.5in\" fill=\"#ef0000\" />\n", bordersize + 1.25, 17.0 + bordersize);
  108. hrt(bordersize, 16.0 + bordersize, "START");
  109. }
  110. void print_stop(double bordersize) {
  111. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"4.50in\" height=\"0.5in\" fill=\"#0000e0\" />\n", bordersize + 1.25, 1.35 + bordersize);
  112. printf(" <rect x=\"%.2fin\" y=\"%.2fin\" width=\"4.50in\" height=\"0.5in\" fill=\"#ef0000\" />\n", bordersize, 1.85 + bordersize);
  113. hrt(bordersize, 1.35 + bordersize, "STOP");
  114. }
  115. void print_label(int posn, double bordersize, int digit) {
  116. double y = ((17.5 + bordersize + 0.375) - ((posn + 1) * 1.375));
  117. switch (digit) {
  118. case 0: print_zero(bordersize, y); break;
  119. case 1: print_one(bordersize, y); break;
  120. case 2: print_two(bordersize, y); break;
  121. case 3: print_three(bordersize, y); break;
  122. case 4: print_four(bordersize, y); break;
  123. case 5: print_five(bordersize, y); break;
  124. case 6: print_six(bordersize, y); break;
  125. case 7: print_seven(bordersize, y); break;
  126. case 8: print_eight(bordersize, y); break;
  127. case 9: print_nine(bordersize, y); break;
  128. case 10: print_ten(bordersize, y); break;
  129. }
  130. }
  131. int main(int argc, char** argv) {
  132. int in_length;
  133. char car_number[12];
  134. int i;
  135. int checksum = 0;
  136. int checkdigit;
  137. double bordersize = 3.0;
  138. if (argc != 2) {
  139. /* Only command line input should be the number to encode */
  140. printf("Usage: kartrak {number}\n");
  141. printf("Where {number} is the number to be encoded, up to 10 digits\n");
  142. return 0;
  143. } else {
  144. in_length = strlen(argv[1]);
  145. if (in_length > 10) {
  146. /* Check maximum length */
  147. printf("Input data too long\n");
  148. return 0;
  149. } else {
  150. /* Add padding if needed */
  151. strcpy(car_number, "");
  152. for(i = in_length; i < 10; i++) {
  153. strcat(car_number, "0");
  154. }
  155. strcat(car_number, argv[1]);
  156. }
  157. }
  158. /* Check input is numeric */
  159. for (i = 0; i < 10; i++) {
  160. if ((car_number[i] < '0') || (car_number[i] > '9')) {
  161. printf("Invalid character(s) in input data\n");
  162. return 0;
  163. }
  164. checksum += (car_number[i] - '0') * (1 << i);
  165. }
  166. /* Calculate check digit */
  167. checkdigit = checksum % 11;
  168. print_head(car_number, bordersize);
  169. /* Start character */
  170. print_start(bordersize);
  171. /* Data */
  172. for (i = 0; i < 10; i++) {
  173. print_label((i + 1), bordersize, car_number[i] - '0');
  174. }
  175. /* Stop character */
  176. print_stop(bordersize);
  177. /* Check digit */
  178. print_label(12, bordersize, checkdigit);
  179. print_foot();
  180. return (EXIT_SUCCESS);
  181. }