1package main
2
3import (
4 "fmt"
5 "math"
6
7 "github.com/fogleman/gg"
8)
9
10type fcoords struct {
11 X float64
12 Y float64
13}
14
15func main() {
16 a4_dimensions := fcoords{210, 297} //mm
17 scale := 30. // px per mm
18 card_dimensions := fcoords{85.60, 53.98} //mm
19 stroke_width := 0.25 //mm
20 stitching_width := 5. //mm
21 hole_spacing := 4. //mm
22 hole_radius := 1. //mm
23 initial_hole_spacing_from_center := 4.1 //mm
24 hole_spacing_from_top := 3. //mm
25 leather_thickness := 2. //mm
26 optimal_angle := 90. //deg
27 rounding_radius := 4. //mm
28
29 layer_offset := 12. //mm
30 alternate_layer_offset := true
31
32 page_margins := 10. //mm
33
34 layer_count := 5
35
36 hole_counts := []int{44, 32}
37
38 font_path := "assets/iosevka-heavy.ttf"
39 font_size := 8.
40
41 ruler_count := []int{50, 4}
42 ruler_square_size := 2. //mm
43
44 // Code
45 anchor := fcoords{page_margins, page_margins} // mm
46
47 for layer := 0; layer < layer_count; layer++ {
48 dc := gg.NewContext(int(math.Round(a4_dimensions.X*scale)), int(math.Round(a4_dimensions.Y*scale)))
49 dc.SetRGB(1, 1, 1)
50 dc.Clear()
51 dc.SetRGB(0, 0, 0)
52 dc.LoadFontFace(font_path, font_size*scale)
53 dc.SetLineWidth(stroke_width * scale)
54
55 stencil_dimensions := fcoords{card_dimensions.X*2 + stitching_width*2 + float64(layer_count-layer-1)*math.Pi*leather_thickness*optimal_angle/360*2, card_dimensions.Y + layer_offset + stitching_width} //mm
56
57 dc.DrawRoundedRectangle(anchor.X*scale, anchor.Y*scale, stencil_dimensions.X*scale, stencil_dimensions.Y*scale, rounding_radius*scale)
58 dc.Stroke()
59 hole_spacing_from_center := initial_hole_spacing_from_center + math.Pi*leather_thickness*float64(layer_count-layer-1)*optimal_angle/360
60 for i := 0; i < hole_counts[0]; i++ {
61 dc.DrawCircle((anchor.X+stencil_dimensions.X/2+(hole_spacing_from_center+float64(i/2)*hole_spacing)*float64(i%2*2-1))*scale, (anchor.Y+stencil_dimensions.Y-stitching_width/2)*scale, hole_radius*scale)
62 dc.Stroke()
63 }
64
65 for i := 0; i < hole_counts[1]; i++ {
66 if i%2 == 0 {
67 dc.DrawCircle((anchor.X+stitching_width/2)*scale, (anchor.Y+hole_spacing_from_top+float64(i/2)*hole_spacing)*scale, hole_radius*scale)
68 } else {
69 dc.DrawCircle((anchor.X+stencil_dimensions.X-stitching_width/2)*scale, (anchor.Y+hole_spacing_from_top+float64(i/2)*hole_spacing)*scale, hole_radius*scale)
70 }
71 dc.Stroke()
72 }
73
74 if layer != 0 {
75 for i := 0; i < hole_counts[1]; i++ {
76 dc.DrawCircle((anchor.X+stencil_dimensions.X/2+hole_spacing_from_center*float64(i%2*2-1))*scale, (anchor.Y+hole_spacing_from_top+float64(i/2)*hole_spacing)*scale, hole_radius*scale)
77 dc.Stroke()
78 }
79 }
80
81 dc.DrawLine((anchor.X)*scale, (anchor.Y+stencil_dimensions.Y-stitching_width)*scale, (anchor.X+stencil_dimensions.X)*scale, (anchor.Y+stencil_dimensions.Y-stitching_width)*scale)
82 dc.Stroke()
83 dc.DrawLine((anchor.X+stitching_width)*scale, (anchor.Y)*scale, (anchor.X+stitching_width)*scale, (anchor.Y+stencil_dimensions.Y)*scale)
84 dc.Stroke()
85 dc.DrawLine((anchor.X+stencil_dimensions.X-stitching_width)*scale, (anchor.Y)*scale, (anchor.X+stencil_dimensions.X-stitching_width)*scale, (anchor.Y+stencil_dimensions.Y)*scale)
86 dc.Stroke()
87
88 if layer != 0 {
89 dc.DrawLine((anchor.X+stencil_dimensions.X/2+hole_spacing_from_center-stitching_width/2)*scale, (anchor.Y)*scale, (anchor.X+stencil_dimensions.X/2+hole_spacing_from_center-stitching_width/2)*scale, (anchor.Y+stencil_dimensions.Y)*scale)
90 dc.Stroke()
91 dc.DrawLine((anchor.X+stencil_dimensions.X/2-hole_spacing_from_center+stitching_width/2)*scale, (anchor.Y)*scale, (anchor.X+stencil_dimensions.X/2-hole_spacing_from_center+stitching_width/2)*scale, (anchor.Y+stencil_dimensions.Y)*scale)
92 dc.Stroke()
93
94 dc.DrawLine((anchor.X+stencil_dimensions.X/2+hole_spacing_from_center+stitching_width/2)*scale, (anchor.Y)*scale, (anchor.X+stencil_dimensions.X/2+hole_spacing_from_center+stitching_width/2)*scale, (anchor.Y+stencil_dimensions.Y)*scale)
95 dc.Stroke()
96 dc.DrawLine((anchor.X+stencil_dimensions.X/2-hole_spacing_from_center-stitching_width/2)*scale, (anchor.Y)*scale, (anchor.X+stencil_dimensions.X/2-hole_spacing_from_center-stitching_width/2)*scale, (anchor.Y+stencil_dimensions.Y)*scale)
97 dc.Stroke()
98 }
99
100 if layer > 1 {
101 effective_layer_index := layer - 1
102 ay := anchor.Y + layer_offset*float64(effective_layer_index)
103 by := anchor.Y + layer_offset*float64(effective_layer_index+1)
104 if alternate_layer_offset {
105 if layer%2 == 1 {
106 cy := by
107 by = ay
108 ay = cy
109 }
110 }
111 dc.DrawLine((anchor.X+stitching_width)*scale, ay*scale, (anchor.X+stencil_dimensions.X/2-hole_spacing_from_center-stitching_width/2)*scale, by*scale)
112 dc.Stroke()
113 dc.DrawLine((anchor.X+stencil_dimensions.X/2+hole_spacing_from_center+stitching_width/2)*scale, by*scale, (anchor.X+stencil_dimensions.X-stitching_width)*scale, ay*scale)
114 dc.Stroke()
115 dc.DrawLine(anchor.X*scale, ay*scale, (anchor.X+stitching_width)*scale, ay*scale)
116 dc.Stroke()
117 dc.DrawLine((anchor.X+stencil_dimensions.X/2-hole_spacing_from_center-stitching_width/2)*scale, by*scale, (anchor.X+stencil_dimensions.X/2+hole_spacing_from_center+stitching_width/2)*scale, by*scale)
118 dc.Stroke()
119 dc.DrawLine((anchor.X+stencil_dimensions.X-stitching_width)*scale, ay*scale, (anchor.X+stencil_dimensions.X)*scale, ay*scale)
120 dc.Stroke()
121 dc.DrawArc((anchor.X+rounding_radius)*scale, (ay+rounding_radius)*scale, rounding_radius*scale, 3*math.Pi/2, math.Pi)
122 dc.Stroke()
123 dc.DrawArc((anchor.X+stencil_dimensions.X-rounding_radius)*scale, (ay+rounding_radius)*scale, rounding_radius*scale, -math.Pi/2, 0)
124 dc.Stroke()
125 }
126
127 dc.DrawStringAnchored(fmt.Sprintf("Layer %d", layer), (anchor.X)*scale, (anchor.Y+stencil_dimensions.Y+page_margins)*scale, 0, 0)
128 for i := 0; i < ruler_count[0]; i++ {
129 for j := 0; j < ruler_count[1]; j++ {
130 dc.DrawRectangle((anchor.X+float64(i)*ruler_square_size)*scale, (anchor.Y+stencil_dimensions.Y+page_margins*2+font_size+float64(j)*ruler_square_size)*scale, ruler_square_size*scale, ruler_square_size*scale)
131 dc.Stroke()
132 }
133 }
134 dc.SavePNG(fmt.Sprintf("out-%04d.png", layer))
135 }
136}