joseph 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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