#include <stdio.h> #include <math.h> #include <time.h> #include <stdlib.h> #include "gpc.h" #include "svg.h" // outside dimensions of tray - eventually these may be command-line parameters... float wood = 4.65; #define W 142 /* left-right */ //#define H 380 /* top-bottom */ #define H 10 /* top-bottom */ #define D 52 /* front-back */ // -------------------------------------------------------- int mm(int m) { return m*100; } int in(int m) { return m*2540; } int ft(int m) { return in(m*12); } int mm_f(float m) { return (int)roundf(m*100.0); } int in_f(float m) { return (int)roundf(m*2540.0); } int ft_f(float m) { return in_f(m*12.0); } #define RED "#FF0000" #define GREEN "#00FF00" #define BLUE "#0000FF" #define PINK "#FFAAAA" #define WHITE "#FFFFFF" #define BLACK "#000000" #define BACKGROUND "#DDDDFF" #define ENGRAVE_TEXT BLACK #define COMMENT_TEXT BLUE #define HAIRLINE_f 0.01 #define VISIBLE_LINE_f 0.2 #define LIVE_FILL WHITE #define PREVIEW_FILL PINK static svg* psvg; int PREVIEW; // value of these depends on PREVIEW float linewidth_f; char *fill; float stage_width = 0.0, stage_height = 0.0; void hole_mm_f(float w, float h, float x, float y) { if (x+w > stage_width) stage_width = x+w; if (y+h > stage_height) stage_height = y+h; if (PREVIEW) { svg_rectangle(psvg, /* size */ mm_f(w), mm_f(h), /* at */ mm_f(x), mm_f(y), BACKGROUND, /* outline */ BACKGROUND, /* border-width */mm_f(linewidth_f), /* radius x,y */ 0,0); } else { svg_rectangle(psvg, /* size */ mm_f(w), mm_f(h), /* at */ mm_f(x), mm_f(y), WHITE, /* outline */ RED, /* border-width */mm_f(linewidth_f), /* radius x,y */ 0,0); } } void face(int w, int h, int x, int y) { if (x+w > stage_width) stage_width = x+w; if (y+h > stage_height) stage_height = y+h; svg_rectangle(psvg, /* size */ mm(w), mm(h), /* at */ mm(x), mm(y), fill, /* outline */ RED, /* border-width */mm_f(linewidth_f), /* radius x,y */ 0,0); } #ifdef NEVER svg_text(psvg, /* at */ mm(x+10), mm(y+25+1), "sans-serif", mm(3), /* fill colour */ COMMENT_TEXT, /* stroke colour */ COMMENT_TEXT, "5cm x 5cm square", ""); #endif void toothcomb(float center_x, float center_y, int cuts, float spacing, int cut_depth) { int i; float start_x; if ((cuts & 1) == 0) { // even number of cuts start_x = center_x - spacing/2 - ((cuts-1)>>1)*spacing; } else { // odd number of cuts start_x = center_x - (cuts>>1)*spacing; } for (i = 0; i < cuts; i++) { svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm_f(start_x), mm_f(center_y), /* to */ mm_f(start_x), mm_f(center_y+cut_depth)); start_x += spacing; } } int xpos, ypos; void front_face(int x, int y) { int order; int steps = (W - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides xpos = x+5; ypos = y+5; for (order = 0; order <= 1; order++) { // preview actions then live actions // cut before the face falls out if (order == (PREVIEW&1)) { //hole_mm_f(wood, H/2, /* at */ x+5 /*+ wood*/, y+5 + H/2); //hole_mm_f(wood, H/2, /* at */ x+5 + W-wood/*-wood*/, y+5 + H/2); hole_mm_f(wood, H/3.0, /* at */ xpos /*+ wood*/, ypos + H/2.0 - H/6.0); hole_mm_f(wood, H/3.0, /* at */ xpos + W-wood/*-wood*/, ypos + H/2.0 - H/6.0); //hole_mm_f(W - 20, H - 10, x+5+10, y+5+10); toothcomb(xpos + W/2.0, ypos, steps, 2.0, 2); } if (order == 0) face(W, H, xpos, ypos); } } void back_face(int x, int y) { int order; int steps = (W - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides xpos = x+5/*+W+5*/; ypos = y+5+H+5; for (order = 0; order <= 1; order++) { // preview actions then live actions if (order == (PREVIEW&1)) { hole_mm_f(wood, H/3.0, /* at */ xpos /*+ wood*/, ypos + H/2.0 - H/6.0); hole_mm_f(wood, H/3.0, /* at */ xpos + W-wood/*-wood*/, ypos + H/2.0 - H/6.0); //hole_mm_f(W - 20, H - 10, x+5+W+5+10, y+5+10); toothcomb(xpos + W/2.0, ypos, steps, 2.0, 2); } if (order == 0) face(W, H, xpos, ypos); } } void left_face(int x, int y) { int order; int steps = (D - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides xpos = x+5/*+W+5+W+5*/; ypos = y+5+H+5+H+5; for (order = 0; order <= 1; order++) { // preview actions then live actions if (order == (PREVIEW&1)) { hole_mm_f(wood, H/3.0, /* at */ xpos /*+ wood*/, ypos); hole_mm_f(wood, H/3.0, /* at */ xpos + D-wood/*-wood*/, ypos); hole_mm_f(wood, H/3.0, /* at */ xpos /*+ wood*/, ypos - H/3.0 + H); hole_mm_f(wood, H/3.0, /* at */ xpos + D-wood/*-wood*/, ypos - H/3.0 + H); //toothcomb(x+5+W+5+W+5 + D/2.0, y+5, steps, 2, 3); } if (order == 0) face(D, H/*+10*/, xpos, ypos); } } void right_face(int x, int y) { int order; int steps = (D - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides xpos = x+5 /*+W+5+W+5*/ +D+5; ypos = y+5+H+5+H+5; for (order = 0; order <= 1; order++) { // preview actions then live actions if (order == (PREVIEW&1)) { hole_mm_f(wood, H/3.0, /* at */ xpos /*+ wood*/, ypos); hole_mm_f(wood, H/3.0, /* at */ xpos + D-wood/*-wood*/, ypos); hole_mm_f(wood, H/3.0, /* at */ xpos /*+ wood*/, ypos - H/3.0 + H); hole_mm_f(wood, H/3.0, /* at */ xpos + D-wood/*-wood*/, ypos - H/3.0 + H); //toothcomb(x+5+W+5+W+5+D+5 + D/2.0, y+5, steps, 2, 3); } if (order == 0) face(D, H/*+10*/, xpos, ypos); } } #define margin 7.0 void struts(int x, int y) { int order; int steps = (D - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides xpos = x+5; ypos = y+5; for (order = 0; order <= 1; order++) { // preview actions then live actions if (order == (PREVIEW&1)) { } if (order == 0) { face(D, margin, xpos, ypos); face(D, margin, xpos+wood+D, ypos); face(D-margin-margin+2.0-0.6, 3.0, /* at */ xpos + D + wood + D + wood, ypos); } } } void base(int x, int y) { // face(D, W, x+5+W+5+W+5+D+5+D+5, y+5); int order; int steps = (W - (margin + /* 10 + 10 +*/ margin))/2 ; // NO /*1 cm*/ gap from internal sides xpos = x+5; ypos = y+5; for (order = 0; order <= 1; order++) { // preview actions then live actions // cut before the face falls out if (order == (PREVIEW&1)) { hole_mm_f(3.0, D-margin-margin+2.0, /* at */ xpos + margin + ((W-margin-margin)/3.0)-1.5, ypos + margin - 1.0); hole_mm_f(3.0, D-margin-margin+2.0, /* at */ xpos + margin + ((W-margin-margin)/2.0)-1.5, ypos + margin - 1.0); hole_mm_f(3.0, D-margin-margin+2.0, /* at */ xpos + margin + (2.0 * (W-margin-margin) / 3.0)-1.5, ypos + margin - 1.0); hole_mm_f(W-margin-margin, D-margin-margin, /* at */ xpos + margin, ypos + margin); toothcomb(xpos + W/2.0, ypos, steps+1, 2.0, 2); toothcomb(xpos + W/2.0, ypos+D-2.0, steps+1, 2.0, 2); } if (order == 0) { face(W, D, xpos, ypos); hole_mm_f(3.0, D-margin-margin+2.0-0.6, /* at */ xpos + W + wood, ypos + margin - 1.0); } } } void ruler(int x, int y) { svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm(x), mm(y), /* to */ mm(x+50), mm(y)); svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm(x), mm(y), /* to */ mm(x), mm(y-5)); svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm(x+50), mm(y), /* to */ mm(x+50), mm(y-5)); svg_text(psvg, /* at */ mm(x+10), mm(y-1), "sans-serif", mm(3), /* fill colour */ BLACK, /* stroke colour */ BLACK, "5cm line", ""); } void tray(int x, int y) { // base(x,y); skip base for threading test... base(x,y); struts(x, y + D + wood); } int main(void) { stage_width = 3600.0-5.0; stage_height = 2400.0-5.0; for (PREVIEW = 1; PREVIEW >= -1; PREVIEW--) { // do preview first to get size linewidth_f = PREVIEW ? VISIBLE_LINE_f : HAIRLINE_f; fill = PREVIEW ? PREVIEW_FILL : LIVE_FILL; psvg = svg_create(mm_f(stage_width+5), mm_f(stage_height+5)); // size of laser cutter bed stage_width = 0.0; stage_height = 0.0; if (psvg == NULL) { puts("psvg is NULL"); exit(EXIT_FAILURE); } else { if (PREVIEW) svg_fill(psvg, BACKGROUND); } tray(0,0); if (PREVIEW) svg_text(psvg, /* at */ mm(2), mm(4), "sans-serif", mm(3), /* fill colour */ COMMENT_TEXT, /* stroke colour */ COMMENT_TEXT, "THIS IS A PREVIEW-OPTIMISED VERSION. CUT THE OTHER FILE.", ""); svg_finalize(psvg); svg_save(psvg, PREVIEW ? "base-preview.svg" : "base.svg"); svg_free(psvg); } exit(EXIT_SUCCESS); return EXIT_FAILURE; }