joseph 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +97 -2
  3. data/.gitlab-ci.yml +21 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +2 -2
  6. data/{MIT-LICENSE → LICENSE.txt} +3 -1
  7. data/README.md +33 -7
  8. data/Rakefile +4 -21
  9. data/examples/fiducials.rb +31 -0
  10. data/examples/panelize.rb +36 -0
  11. data/joseph.gemspec +25 -18
  12. data/lib/core_extensions/float/conversions.rb +13 -0
  13. data/lib/core_extensions/integer/conversions.rb +9 -0
  14. data/lib/joseph.rb +25 -29
  15. data/lib/joseph/aperture.rb +12 -0
  16. data/lib/joseph/bridge.rb +45 -0
  17. data/lib/joseph/cirseg.rb +11 -0
  18. data/lib/joseph/file_info.rb +17 -0
  19. data/lib/joseph/gdk_color.rb +35 -0
  20. data/lib/joseph/image.rb +143 -0
  21. data/lib/joseph/image_info.rb +25 -0
  22. data/lib/joseph/knockout.rb +13 -0
  23. data/lib/joseph/layer.rb +11 -0
  24. data/lib/joseph/net.rb +38 -0
  25. data/lib/joseph/project.rb +87 -0
  26. data/lib/joseph/render_info.rb +11 -0
  27. data/lib/joseph/render_size.rb +50 -0
  28. data/lib/joseph/step_and_repeat.rb +9 -0
  29. data/lib/joseph/user_transformation.rb +18 -0
  30. data/lib/joseph/version.rb +1 -1
  31. data/spec/assets/3_hat.boardoutline.ger +1628 -0
  32. data/spec/assets/3_hat.bottomlayer.ger +2038 -0
  33. data/spec/assets/3_hat.toplayer.ger +3103 -0
  34. data/spec/assets/test.EXTREP +20 -0
  35. data/spec/assets/test_wrong.GBL +20 -0
  36. data/spec/assets/vesc-capbank.topsilkscreen.ger +520 -0
  37. data/spec/bridge_spec.rb +10 -0
  38. data/spec/image_spec.rb +75 -0
  39. data/spec/project_spec.rb +48 -0
  40. data/spec/render_size_spec.rb +25 -0
  41. data/spec/results/bottomlayer_mirrored.png +0 -0
  42. data/spec/results/toplayer_as_png.png +0 -0
  43. data/spec/spec_helper.rb +16 -0
  44. metadata +172 -79
  45. data/Gemfile.lock +0 -26
  46. data/example.rb +0 -32
  47. data/spec/joseph_spec.rb +0 -32
@@ -0,0 +1,11 @@
1
+ module Joseph
2
+ class Cirseg < FFI::Struct
3
+ layout :cp_x, :double,
4
+ :cp_y, :double,
5
+ :width, :double,
6
+ :height, :double,
7
+ :angle1, :double,
8
+ :angle2, :double
9
+
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Joseph
2
+ class FileInfo < FFI::Struct
3
+ layout :image, Image.by_ref,
4
+ :color, GdkColor.by_value,
5
+ :alpha, :uint16,
6
+ :is_visible, :int,
7
+ :private_render_data, :pointer,
8
+ :full_pathname, :string,
9
+ :name, :string,
10
+ :transform, UserTransformation.by_value,
11
+ :layer_dirty, :int
12
+
13
+ def image
14
+ self[:image]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module Joseph
2
+ class GdkColor < FFI::Struct
3
+ def self.create(r, g, b)
4
+ color = self.new
5
+ color.red = r
6
+ color.green = g
7
+ color.blue = b
8
+ color
9
+ end
10
+
11
+ layout :pixel, :uint32,
12
+ :red, :uint16,
13
+ :green, :uint16,
14
+ :blue, :uint16
15
+
16
+ def red=(val)
17
+ self[:red] = val.to_gdk_color
18
+ end
19
+
20
+ def green=(val)
21
+ self[:green] = val.to_gdk_color
22
+ end
23
+
24
+ def blue=(val)
25
+ self[:blue] = val.to_gdk_color
26
+ end
27
+
28
+ def hex=(val)
29
+ val.sub! /#/, ''
30
+ self.red = val[0..1].to_i(16)
31
+ self.green = val[2..3].to_i(16)
32
+ self.blue = val[4..5].to_i(16)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,143 @@
1
+ module Joseph
2
+ class Image < FFI::Struct
3
+ def self.create
4
+ Bridge.gerbv_create_image nil, nil
5
+ end
6
+
7
+ def self.memory_map
8
+ f = {}
9
+ f[:layertype] = :int
10
+
11
+ # Ugly as hell but works
12
+ 9999.times do |ix|
13
+ sym = "aperture_#{ix}".to_sym
14
+ f[sym] = Aperture.by_ref
15
+ end
16
+
17
+ f[:layers] = :pointer
18
+ f[:states] = :pointer
19
+ f[:amacro] = :pointer
20
+ f[:format] = :pointer
21
+ f[:info] = ImageInfo.by_ref
22
+ f[:netlist] = :pointer
23
+ f[:gerbv_stats] = :pointer
24
+ f[:drill_stats] = :pointer
25
+ f
26
+ end
27
+ layout memory_map
28
+
29
+
30
+ def add(image, transformation = UserTransformation.new)
31
+ Bridge.gerbv_image_copy_image(image.pointer, transformation.pointer, self.pointer)
32
+
33
+ # Check if polarity reset is necessary
34
+ return if image.last_layer[:polarity] == 2
35
+ # As Gerbv does not reset polarity, we add another 'dummy' layer with dark polarity
36
+ # Afterwards a zero flash is created and associated to the new created layer
37
+ # Otherwise some strange memory issue occours when dumping the image
38
+
39
+ # Reset polarity of both images
40
+ layer = Bridge.gerbv_image_return_new_layer(last_layer)
41
+ layer[:polarity] = 2 # Default polarity
42
+
43
+ each_net do |net|
44
+ if net[:next].null?
45
+ dummy = Bridge.gerber_create_new_net(net, layer, nil)
46
+ dummy[:interpolation] = 8 # Do not draw net / GERBV_INTERPOLATION_DELETED
47
+ end
48
+ end
49
+
50
+ nil
51
+ end
52
+
53
+ def duplicate(transformation = nil)
54
+ Bridge.gerbv_image_duplicate_image(self, transformation)
55
+ end
56
+
57
+ def to_output(store = Ramdo::Store.new)
58
+ if rs274x?
59
+ Bridge.gerbv_export_rs274x_file_from_image(store.file, self, UserTransformation.new)
60
+ elsif drill?
61
+ Bridge.gerbv_export_drill_file_from_image(store.file, self, UserTransformation.new)
62
+ end
63
+
64
+ store
65
+ end
66
+
67
+ def each_net(&block)
68
+ address = self[:netlist]
69
+ loop do
70
+ net = Net.new(address)
71
+ yield(net) unless net[:aperture_state] == 0
72
+
73
+ # Keep address of next net and return if not available
74
+ address = net[:next]
75
+ break if address.null?
76
+ end
77
+ end
78
+
79
+ def net_count
80
+ c = 0
81
+ each_net { c += 1 }
82
+ c
83
+ end
84
+
85
+ def last_net
86
+ net = nil
87
+ each_net { |n| net = n }
88
+ net
89
+ end
90
+
91
+ def each_layer(&block)
92
+ address = self[:layers]
93
+ loop do
94
+ layer = Layer.new(address)
95
+ yield(layer)
96
+
97
+ address = layer[:next]
98
+ break if address.null?
99
+ end
100
+ end
101
+
102
+ def layer_count
103
+ c = 0
104
+ each_layer { c += 1 }
105
+ c
106
+ end
107
+
108
+ def last_layer
109
+ layer = nil
110
+ each_layer { |l| layer = l }
111
+ layer
112
+ end
113
+
114
+ def crop!(bb)
115
+ each_net do |net|
116
+ net[:start_y] = [bb[:bottom], net[:start_y]].min
117
+ net[:stop_y] = [bb[:bottom], net[:stop_y]].min
118
+ net[:start_x] = [bb[:left], net[:start_x]].max
119
+ net[:stop_x] = [bb[:left], net[:stop_x]].max
120
+ net[:start_y] = [bb[:top], net[:start_y]].max
121
+ net[:stop_y] = [bb[:top], net[:stop_y]].max
122
+ net[:start_x] = [bb[:right], net[:start_x]].min
123
+ net[:stop_x] = [bb[:right], net[:stop_x]].min
124
+ end
125
+ end
126
+
127
+ def rs274x?
128
+ self[:layertype] == 0
129
+ end
130
+
131
+ def drill?
132
+ self[:layertype] == 1
133
+ end
134
+
135
+ def info
136
+ self[:info]
137
+ end
138
+
139
+ def destroy!
140
+ Bridge.gerbv_destroy_image(self)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,25 @@
1
+ module Joseph
2
+ class ImageInfo < FFI::Struct
3
+ layout :name, :string,
4
+ :polarity, :int,
5
+ :min_x, :double,
6
+ :min_y, :double,
7
+ :max_x, :double,
8
+ :max_y, :double,
9
+ :offset_a, :double,
10
+ :offset_b, :double,
11
+ :encoding, :int,
12
+ :rotation, :double,
13
+ :justify_type_a, :int,
14
+ :justify_type_b, :int,
15
+ :justify_offset_a, :double,
16
+ :justify_offset_b, :double,
17
+ :justify_offset_actual_a, :double,
18
+ :justify_offset_actual_a, :double,
19
+ :plotter_film, :string,
20
+ :type, :string,
21
+ :hid_attribute, :pointer,
22
+ :n_attr, :int
23
+
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module Joseph
2
+ class Knockout < FFI::Struct
3
+ layout :first_instance, :bool,
4
+ :type, :int,
5
+ :polarity, :int,
6
+ :lower_left_x, :double,
7
+ :lower_left_y, :double,
8
+ :width, :double,
9
+ :height, :double,
10
+ :border, :double
11
+
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Joseph
2
+ class Layer < FFI::Struct
3
+ layout :step_and_repeat, StepAndRepeat.by_value,
4
+ :knockout, Knockout.by_value,
5
+ :rotation, :double,
6
+ :polarity, :int,
7
+ :name, :string,
8
+ :next, :pointer
9
+
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ module Joseph
2
+ class Net < FFI::Struct
3
+ layout :start_x, :double,
4
+ :start_y, :double,
5
+ :stop_x, :double,
6
+ :stop_y, :double,
7
+ :bounding_box, RenderSize.by_value,
8
+ :aperture, :int,
9
+ :aperture_state, :int,
10
+ :interpolation, :int,
11
+ :cirseg, Cirseg.by_ref,
12
+ :next, :pointer,
13
+ :label, :string,
14
+ :layer, :pointer,
15
+ :state, :pointer
16
+
17
+ def hash
18
+ [
19
+ self[:start_x],
20
+ self[:start_y],
21
+ self[:stop_x],
22
+ self[:stop_y]
23
+ ].hash
24
+ end
25
+
26
+ def length
27
+ (Vector[self[:start_x], self[:start_y]] - Vector[self[:stop_x], self[:stop_y]]).r
28
+ end
29
+
30
+ def flash?
31
+ self[:aperture_state] == 2
32
+ end
33
+
34
+ def destroy!
35
+ Bridge.gerbv_image_delete_net(self)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,87 @@
1
+ module Joseph
2
+ class Project < FFI::Struct
3
+ def self.create(r = 0x00, g = 0x00, b = 0x00)
4
+ project = Bridge.gerbv_create_project
5
+ project[:background].red = r
6
+ project[:background].green = g
7
+ project[:background].blue = b
8
+ project
9
+ end
10
+
11
+ attr_reader :index
12
+
13
+ layout :background, GdkColor.by_value,
14
+ :max_files, :int,
15
+ :file, :pointer,
16
+ :curr_index, :int,
17
+ :last_loaded, :int,
18
+ :render_type, :int,
19
+ :check_before_delete, :bool,
20
+ :path, :string,
21
+ :execpath, :string,
22
+ :execname, :string,
23
+ :project, :string
24
+
25
+ def initialize(address)
26
+ super(address)
27
+ @index = Hash.new
28
+ end
29
+
30
+ def file(ix)
31
+ ix = @index[ix] if ix.is_a? Symbol
32
+ return nil if ix.nil? || ix > self[:last_loaded]
33
+
34
+ FileInfo.new((self[:file] + (ix * FFI::Type::POINTER.size)).read_pointer)
35
+ end
36
+
37
+ def add_file(file, name, color = {})
38
+ file = file.file if file.is_a? Ramdo::Store
39
+ [:red, :green, :blue, :alpha].each { |k, v| color[k] ||= 0xFF.to_gdk_color }
40
+
41
+ last_ix = self[:last_loaded]
42
+ Bridge.gerbv_open_layer_from_filename_with_color(self, file, color[:red], color[:green], color[:blue], color[:alpha])
43
+ return false if self[:last_loaded] == last_ix # Return if file is invalid
44
+
45
+ @index[name] = self[:last_loaded]
46
+ end
47
+
48
+ def each_file(&block)
49
+ 0.upto(self[:last_loaded]) do |ix|
50
+ file = FileInfo.new((self[:file] + (ix * FFI::Type::POINTER.size)).read_pointer)
51
+ yield(file)
52
+ end
53
+ end
54
+
55
+ def to_png(args = {})
56
+ store = args[:store] || Ramdo::Store.new
57
+ dpi = args[:dpi] || 600 # HiDPI setting for high resolution screens
58
+
59
+ if args[:bb] && args[:bb].valid?
60
+ Bridge.gerbv_export_png_file_from_project(self, render_info(args[:bb], dpi, !!args[:mirror]), store.file)
61
+ else
62
+ Bridge.gerbv_export_png_file_from_project_autoscaled(self, 1920, 1080, store.file)
63
+ end
64
+
65
+ store
66
+ end
67
+
68
+ def destroy!
69
+ Bridge.gerbv_destroy_project(self)
70
+ end
71
+
72
+ private
73
+ def render_info(bb, dpi, mirror)
74
+ info = RenderInfo.new
75
+ info[:render_type] = 3
76
+
77
+ info[:display_width] = dpi * bb.width
78
+ info[:display_height] = dpi * bb.height
79
+ info[:scale_factor_x] = dpi
80
+ info[:scale_factor_y] = dpi
81
+ info[:lower_left_x] = mirror ? -bb.right : bb.left
82
+ info[:lower_left_y] = bb.top
83
+
84
+ info
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,11 @@
1
+ module Joseph
2
+ class RenderInfo < FFI::Struct
3
+ layout :scale_factor_x, :double,
4
+ :scale_factor_y, :double,
5
+ :lower_left_x, :double,
6
+ :lower_left_y, :double,
7
+ :render_type, :uint,
8
+ :display_width, :int,
9
+ :display_height, :int
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ module Joseph
2
+ class RenderSize < FFI::Struct
3
+ def self.from_image(image)
4
+ rs = self.new
5
+ rs[:left] = image.info[:min_x]
6
+ rs[:right] = image.info[:max_x]
7
+ rs[:top] = image.info[:min_y]
8
+ rs[:bottom] = image.info[:max_y]
9
+ rs
10
+ end
11
+
12
+ layout :left, :double,
13
+ :right, :double,
14
+ :bottom, :double,
15
+ :top, :double
16
+
17
+ def valid?
18
+ !(self[:right].infinite? || self[:left].infinite? || self[:top].infinite? || self[:bottom].infinite?)
19
+ end
20
+
21
+ def to_s
22
+ "Right #{self[:right]} / Left #{self[:left]} / Top #{self[:top]} / Bottom #{self[:bottom]}"
23
+ end
24
+
25
+ def width
26
+ (self[:right] - self[:left]).abs
27
+ end
28
+
29
+ def height
30
+ (self[:top] - self[:bottom]).abs
31
+ end
32
+
33
+ def left
34
+ self[:left]
35
+ end
36
+
37
+ def right
38
+ self[:right]
39
+ end
40
+
41
+ def top
42
+ self[:top]
43
+ end
44
+
45
+ def bottom
46
+ self[:bottom]
47
+ end
48
+ end
49
+
50
+ end