+ fprintf(out, ")\n");
+
+ if (!is_uninit(&out_name)) {
+ try {
+ close(out);
+ twixt(file result = open(out_name, "w"); close(result)) {
+ while (!end(reread)) {
+ putb(getb(reread), result);
+ }
+ }
+ } catch open_error (string message, error_type error, string name) {
+ fprintf(stderr, "%s: %s\n", name, message);
+ exit(1);
+ }
+ }
+ }
+
+ public typedef struct {
+ real center_x; /* center of pad */
+ real center_y;
+
+ real width; /* size of pad */
+ real height;
+
+ real spacing; /* space between pad and other traces */
+ real soldermask; /* space between pad and solder mask */
+ string name; /* pad name */
+ string number; /* pad number */
+ string options; /* pad options */
+
+ /* normally computed, but can be provided */
+ real x1; /* start of pad "line" */
+ real y1;
+ real x2; /* end of pad "line" */
+ real y2;
+ real thickness; /* thickness of pad "line" */
+ real clearance; /* twice the spacing between pad and other traces */
+ real mask; /* thickness of pad and solder mask */
+ } pad_t;
+
+ pad_t fill_pad(pad_t pad) {
+ if (is_uninit(&pad.x1))
+ pad.x1 = pad.center_x - max(0, (pad.width - pad.height) / 2);
+ if (is_uninit(&pad.x2))
+ pad.x2 = pad.center_x + max(0, (pad.width - pad.height) / 2);
+
+ if (is_uninit(&pad.y1))
+ pad.y1 = pad.center_y - max(0, (pad.height - pad.width) / 2);
+ if (is_uninit(&pad.y2))
+ pad.y2 = pad.center_y + max(0, (pad.height - pad.width) / 2);
+
+ if (is_uninit(&pad.spacing))
+ pad.spacing = process_space;
+ if (is_uninit(&pad.soldermask))
+ pad.soldermask = process_soldermask;
+ if (is_uninit(&pad.number))
+ pad.number = pad.name;
+ if (is_uninit(&pad.options))
+ pad.options = pad_options;
+
+ if (is_uninit(&pad.thickness))
+ pad.thickness = min(pad.width, pad.height);
+
+ if (is_uninit(&pad.clearance))
+ pad.clearance = pad.spacing * 2;
+
+ if (is_uninit(&pad.mask))
+ pad.mask = pad.thickness + pad.soldermask * 2;
+
+# fprintf(out, "pad %v\n", pad);
+
+ return pad;
+ }
+
+ public exception violation(string rule, real min, real val);
+
+ public check(string rule, real min, real val, bool zero_ok) {
+
+ if (overridden(rule))
+ return;
+ if (zero_ok && val <= 0)
+ return;
+ if (val < min) {
+ Debug::trace(Thread::current());
+ File::fprintf(stderr, "rule %s violated (%fmm %fmils < %fmm %fmils)\n",
+ rule,
+ val, mm2mils100(val)/100.0,
+ min, mm2mils100(min)/100.0);
+ exit(1);
+ }
+ }
+
+ public void pad(pad_t pad)
+ {
+ pad = fill_pad(pad);
+
+ check("pad trace", process_trace, pad.thickness, false);
+ check("pad space", process_space, pad.clearance / 2, true);
+ check("pad mask", process_soldermask, (pad.mask - pad.thickness) / 2, true);
+
+ fprintf(out, " Pad[");
+ fprintf(out, " %6d %6d %6d %6d",
+ mm2mils100(pad.x1),
+ mm2mils100(pad.y1),
+ mm2mils100(pad.x2),
+ mm2mils100(pad.y2));
+ fprintf(out, " %6d %6d %6d",
+ mm2mils100(pad.thickness),
+ mm2mils100(pad.clearance),
+ mm2mils100(pad.mask));
+ fprintf(out, " \"%s\" \"%s\" \"%s\"]\n",
+ pad.name, pad.number, pad.options);