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.
- checksums.yaml +7 -0
- data/.gitignore +97 -2
- data/.gitlab-ci.yml +21 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -2
- data/{MIT-LICENSE → LICENSE.txt} +3 -1
- data/README.md +33 -7
- data/Rakefile +4 -21
- data/examples/fiducials.rb +31 -0
- data/examples/panelize.rb +36 -0
- data/joseph.gemspec +25 -18
- data/lib/core_extensions/float/conversions.rb +13 -0
- data/lib/core_extensions/integer/conversions.rb +9 -0
- data/lib/joseph.rb +25 -29
- data/lib/joseph/aperture.rb +12 -0
- data/lib/joseph/bridge.rb +45 -0
- data/lib/joseph/cirseg.rb +11 -0
- data/lib/joseph/file_info.rb +17 -0
- data/lib/joseph/gdk_color.rb +35 -0
- data/lib/joseph/image.rb +143 -0
- data/lib/joseph/image_info.rb +25 -0
- data/lib/joseph/knockout.rb +13 -0
- data/lib/joseph/layer.rb +11 -0
- data/lib/joseph/net.rb +38 -0
- data/lib/joseph/project.rb +87 -0
- data/lib/joseph/render_info.rb +11 -0
- data/lib/joseph/render_size.rb +50 -0
- data/lib/joseph/step_and_repeat.rb +9 -0
- data/lib/joseph/user_transformation.rb +18 -0
- data/lib/joseph/version.rb +1 -1
- data/spec/assets/3_hat.boardoutline.ger +1628 -0
- data/spec/assets/3_hat.bottomlayer.ger +2038 -0
- data/spec/assets/3_hat.toplayer.ger +3103 -0
- data/spec/assets/test.EXTREP +20 -0
- data/spec/assets/test_wrong.GBL +20 -0
- data/spec/assets/vesc-capbank.topsilkscreen.ger +520 -0
- data/spec/bridge_spec.rb +10 -0
- data/spec/image_spec.rb +75 -0
- data/spec/project_spec.rb +48 -0
- data/spec/render_size_spec.rb +25 -0
- data/spec/results/bottomlayer_mirrored.png +0 -0
- data/spec/results/toplayer_as_png.png +0 -0
- data/spec/spec_helper.rb +16 -0
- metadata +172 -79
- data/Gemfile.lock +0 -26
- data/example.rb +0 -32
- data/spec/joseph_spec.rb +0 -32
@@ -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
|
data/lib/joseph/image.rb
ADDED
@@ -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
|
data/lib/joseph/layer.rb
ADDED
data/lib/joseph/net.rb
ADDED
@@ -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,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
|