ruby3mf 0.2.6 → 0.2.7

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.
@@ -1,135 +1,135 @@
1
- require 'singleton'
2
- require 'yaml'
3
-
4
- # Example usage:
5
-
6
- # Log3mf.context "box.3mf" do |l|
7
- # --do some stuff here
8
-
9
- # l.context "[Content-Types].xml" do |l|
10
- # -- try to parse file. if fail...
11
- # l.log(:fatal_error, "couldn't parse XML") <<<--- THIS WILL GENERATE FATAL ERROR EXCEPTION
12
- # end
13
-
14
- # l.context "examing Relations" do |l|
15
- # l.log(:error, "a non-fatal error")
16
- # l.log(:warning, "a warning")
17
- # l.log(:info, "it is warm today")
18
- # end
19
- # end
20
- #
21
- # Log3mf.to_json
22
-
23
-
24
- class Log3mf
25
- include Singleton
26
- include Interpolation
27
-
28
- LOG_LEVELS = [:fatal_error, :error, :warning, :info, :debug]
29
-
30
- SPEC_LINKS = {
31
- core: 'http://3mf.io/wp-content/uploads/2016/03/3MFcoreSpec_1.1.pdf',
32
- material: 'http://3mf.io/wp-content/uploads/2015/04/3MFmaterialsSpec_1.0.1.pdf',
33
- production: 'http://3mf.io/wp-content/uploads/2016/07/3MFproductionSpec.pdf',
34
- slice: 'http://3mf.io/wp-content/uploads/2016/07/3MFsliceSpec.pdf',
35
- #opc: 'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-376,%20Fourth%20Edition,%20Part%202%20-%20Open%20Packaging%20Conventions.zip'
36
- opc: 'http://3mf.io/wp-content/uploads/2016/03/3MFcoreSpec_1.1.pdf'
37
- }.freeze
38
-
39
- # Allows us to throw FatalErrors if we ever get errors of severity :fatal_error
40
- class FatalError < RuntimeError
41
- end
42
-
43
- def initialize
44
- @log_list = []
45
- @context_stack = []
46
- @ledger = []
47
- errormap_path = File.join(File.dirname(__FILE__), "errors.yml")
48
- @errormap = YAML.load_file(errormap_path)
49
- end
50
-
51
- def reset_log
52
- @log_list = []
53
- @context_stack = []
54
- end
55
-
56
- def self.reset_log
57
- Log3mf.instance.reset_log
58
- end
59
-
60
- def context (context_description, &block)
61
- @context_stack.push(context_description)
62
- retval = block.call(Log3mf.instance)
63
- @context_stack.pop
64
- retval
65
- end
66
-
67
- def self.context(context_description, &block)
68
- Log3mf.instance.context(context_description, &block)
69
- end
70
-
71
- def method_missing(name, *args, &block)
72
- if LOG_LEVELS.include? name.to_sym
73
- if [:fatal_error, :error, :debug].include? name.to_sym
74
- linenumber = caller_locations[0].to_s.split('/')[-1].split(':')[-2].to_s
75
- filename = caller_locations[0].to_s.split('/')[-1].split(':')[0].to_s
76
- options = {linenumber: linenumber, filename: filename}
77
- # Mike: do not call error or fatal_error without an entry in errors.yml
78
- raise "{fatal_}error called WITHOUT using error symbol from: #{filename}:#{linenumber}" if ( !(args[0].is_a? Symbol) && (name.to_sym != :debug) )
79
-
80
- puts "***** Log3mf.#{name} called from #{filename}:#{linenumber} *****" if $DEBUG
81
-
82
- options = options.merge(args[1]) if args[1]
83
- log(name.to_sym, args[0], options)
84
- else
85
- log(name.to_sym, *args)
86
- end
87
- else
88
- super
89
- end
90
- end
91
-
92
- def log(severity, message, options = {})
93
- error = @errormap.fetch(message.to_s) { {"msg" => message.to_s, "page" => nil} }
94
- options[:page] = error["page"] unless options[:page]
95
- options[:spec] = error["spec"] unless options[:spec]
96
- entry = {id: message,
97
- context: "#{@context_stack.join("/")}",
98
- severity: severity,
99
- message: interpolate(error["msg"], options)}
100
- entry[:spec_ref] = spec_link(options[:spec], options[:page]) if (options && options[:page])
101
- entry[:caller] = "#{options[:filename]}:#{options[:linenumber]}" if (options && options[:filename] && options[:linenumber])
102
- @log_list << entry
103
- raise FatalError if severity == :fatal_error
104
- end
105
-
106
- def count_entries(*levels)
107
- entries(*levels).count
108
- end
109
-
110
- def self.count_entries(*l)
111
- Log3mf.instance.count_entries(*l)
112
- end
113
-
114
- def entries(*levels)
115
- return @log_list if levels.size == 0
116
- @log_list.select { |i| levels.include? i[:severity] }
117
- end
118
-
119
- def self.entries(*l)
120
- Log3mf.instance.entries(*l)
121
- end
122
-
123
- def spec_link(spec, page)
124
- spec = :core unless spec
125
- "#{SPEC_LINKS[spec]}#page=#{page}"
126
- end
127
-
128
- def to_json
129
- @log_list.to_json
130
- end
131
-
132
- def self.to_json
133
- Log3mf.instance.to_json
134
- end
135
- end
1
+ require 'singleton'
2
+ require 'yaml'
3
+
4
+ # Example usage:
5
+
6
+ # Log3mf.context "box.3mf" do |l|
7
+ # --do some stuff here
8
+
9
+ # l.context "[Content-Types].xml" do |l|
10
+ # -- try to parse file. if fail...
11
+ # l.log(:fatal_error, "couldn't parse XML") <<<--- THIS WILL GENERATE FATAL ERROR EXCEPTION
12
+ # end
13
+
14
+ # l.context "examing Relations" do |l|
15
+ # l.log(:error, "a non-fatal error")
16
+ # l.log(:warning, "a warning")
17
+ # l.log(:info, "it is warm today")
18
+ # end
19
+ # end
20
+ #
21
+ # Log3mf.to_json
22
+
23
+
24
+ class Log3mf
25
+ include Singleton
26
+ include Interpolation
27
+
28
+ LOG_LEVELS = [:fatal_error, :error, :warning, :info, :debug]
29
+
30
+ SPEC_LINKS = {
31
+ core: 'http://3mf.io/wp-content/uploads/2016/03/3MFcoreSpec_1.1.pdf',
32
+ material: 'http://3mf.io/wp-content/uploads/2015/04/3MFmaterialsSpec_1.0.1.pdf',
33
+ production: 'http://3mf.io/wp-content/uploads/2016/07/3MFproductionSpec.pdf',
34
+ slice: 'http://3mf.io/wp-content/uploads/2016/07/3MFsliceSpec.pdf',
35
+ #opc: 'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-376,%20Fourth%20Edition,%20Part%202%20-%20Open%20Packaging%20Conventions.zip'
36
+ opc: 'http://3mf.io/wp-content/uploads/2016/03/3MFcoreSpec_1.1.pdf'
37
+ }.freeze
38
+
39
+ # Allows us to throw FatalErrors if we ever get errors of severity :fatal_error
40
+ class FatalError < RuntimeError
41
+ end
42
+
43
+ def initialize
44
+ @log_list = []
45
+ @context_stack = []
46
+ @ledger = []
47
+ errormap_path = File.join(File.dirname(__FILE__), "errors.yml")
48
+ @errormap = YAML.load_file(errormap_path)
49
+ end
50
+
51
+ def reset_log
52
+ @log_list = []
53
+ @context_stack = []
54
+ end
55
+
56
+ def self.reset_log
57
+ Log3mf.instance.reset_log
58
+ end
59
+
60
+ def context (context_description, &block)
61
+ @context_stack.push(context_description)
62
+ retval = block.call(Log3mf.instance)
63
+ @context_stack.pop
64
+ retval
65
+ end
66
+
67
+ def self.context(context_description, &block)
68
+ Log3mf.instance.context(context_description, &block)
69
+ end
70
+
71
+ def method_missing(name, *args, &block)
72
+ if LOG_LEVELS.include? name.to_sym
73
+ if [:fatal_error, :error, :debug].include? name.to_sym
74
+ linenumber = caller_locations[0].to_s.split('/')[-1].split(':')[-2].to_s
75
+ filename = caller_locations[0].to_s.split('/')[-1].split(':')[0].to_s
76
+ options = {linenumber: linenumber, filename: filename}
77
+ # Mike: do not call error or fatal_error without an entry in errors.yml
78
+ raise "{fatal_}error called WITHOUT using error symbol from: #{filename}:#{linenumber}" if ( !(args[0].is_a? Symbol) && (name.to_sym != :debug) )
79
+
80
+ puts "***** Log3mf.#{name} called from #{filename}:#{linenumber} *****" if $DEBUG
81
+
82
+ options = options.merge(args[1]) if args[1]
83
+ log(name.to_sym, args[0], options)
84
+ else
85
+ log(name.to_sym, *args)
86
+ end
87
+ else
88
+ super
89
+ end
90
+ end
91
+
92
+ def log(severity, message, options = {})
93
+ error = @errormap.fetch(message.to_s) { {"msg" => message.to_s, "page" => nil} }
94
+ options[:page] = error["page"] unless options[:page]
95
+ options[:spec] = error["spec"] unless options[:spec]
96
+ entry = {id: message,
97
+ context: "#{@context_stack.join("/")}",
98
+ severity: severity,
99
+ message: interpolate(error["msg"], options)}
100
+ entry[:spec_ref] = spec_link(options[:spec], options[:page]) if (options && options[:page])
101
+ entry[:caller] = "#{options[:filename]}:#{options[:linenumber]}" if (options && options[:filename] && options[:linenumber])
102
+ @log_list << entry
103
+ raise FatalError if severity == :fatal_error
104
+ end
105
+
106
+ def count_entries(*levels)
107
+ entries(*levels).count
108
+ end
109
+
110
+ def self.count_entries(*l)
111
+ Log3mf.instance.count_entries(*l)
112
+ end
113
+
114
+ def entries(*levels)
115
+ return @log_list if levels.size == 0
116
+ @log_list.select { |i| levels.include? i[:severity] }
117
+ end
118
+
119
+ def self.entries(*l)
120
+ Log3mf.instance.entries(*l)
121
+ end
122
+
123
+ def spec_link(spec, page)
124
+ spec = :core unless spec
125
+ "#{SPEC_LINKS[spec]}#page=#{page}"
126
+ end
127
+
128
+ def to_json
129
+ @log_list.to_json
130
+ end
131
+
132
+ def self.to_json
133
+ Log3mf.instance.to_json
134
+ end
135
+ end
@@ -1,80 +1,80 @@
1
- class MeshAnalyzer
2
-
3
- def self.validate_object(object, includes_material)
4
- Log3mf.context "verifying object" do |l|
5
- children = object.children.map { |child| child.name }
6
- have_override = object.attributes["pid"] or object.attributes["pindex"]
7
- l.error :object_with_components_and_pid if have_override && children.include?("components")
8
- end
9
-
10
- Log3mf.context "validating geometry" do |l|
11
- list = EdgeList.new
12
-
13
- # if a triangle has a pid, then the object needs a pid
14
- has_triangle_pid = false
15
-
16
- meshs = object.css('mesh')
17
- meshs.each do |mesh|
18
-
19
- num_vertices = mesh.css("vertex").count
20
- triangles = mesh.css("triangle")
21
- l.error :not_enough_triangles if triangles.count < 4
22
-
23
- if triangles
24
- triangles.each do |triangle|
25
-
26
- v1 = triangle.attributes["v1"].to_s.to_i
27
- v2 = triangle.attributes["v2"].to_s.to_i
28
- v3 = triangle.attributes["v3"].to_s.to_i
29
-
30
- l.error :invalid_vertex_index if [v1, v2, v3].select{|vertex| vertex >= num_vertices}.count > 0
31
-
32
- unless includes_material
33
- l.context "validating property overrides" do |l|
34
- property_overrides = []
35
- property_overrides << triangle.attributes['p1'].to_s.to_i if triangle.attributes['p1']
36
- property_overrides << triangle.attributes['p2'].to_s.to_i if triangle.attributes['p2']
37
- property_overrides << triangle.attributes['p3'].to_s.to_i if triangle.attributes['p3']
38
-
39
- property_overrides.reject! { |prop| prop.nil? }
40
- l.error :has_base_materials_gradient unless property_overrides.uniq.size <= 1
41
- end
42
- end
43
-
44
- if v1 == v2 || v2 == v3 || v3 == v1
45
- l.error :non_distinct_indices
46
- end
47
-
48
- list.add_edge(v1, v2)
49
- list.add_edge(v2, v3)
50
- list.add_edge(v3, v1)
51
- unless has_triangle_pid
52
- has_triangle_pid = triangle.attributes["pid"] != nil
53
- end
54
- end
55
-
56
- if has_triangle_pid && !(object.attributes["pindex"] && object.attributes["pid"])
57
- l.error :missing_object_pid
58
- end
59
-
60
- result = list.verify_edges
61
- if result == :bad_orientation
62
- l.error :resource_3dmodel_orientation
63
- elsif result == :hole
64
- l.error :resource_3dmodel_hole
65
- elsif result == :nonmanifold
66
- l.error :resource_3dmodel_nonmanifold
67
- end
68
-
69
- end
70
- end
71
- end
72
- end
73
-
74
- def self.validate(model_doc, includes_material)
75
- model_doc.css('model/resources/object').select { |object| ['model', 'solidsupport', ''].include?(object.attributes['type'].to_s) }.each do |object|
76
- validate_object(object, includes_material)
77
- end
78
- end
79
-
80
- end
1
+ class MeshAnalyzer
2
+
3
+ def self.validate_object(object, includes_material)
4
+ Log3mf.context "verifying object" do |l|
5
+ children = object.children.map { |child| child.name }
6
+ have_override = object.attributes["pid"] or object.attributes["pindex"]
7
+ l.error :object_with_components_and_pid if have_override && children.include?("components")
8
+ end
9
+
10
+ Log3mf.context "validating geometry" do |l|
11
+ list = EdgeList.new
12
+
13
+ # if a triangle has a pid, then the object needs a pid
14
+ has_triangle_pid = false
15
+
16
+ meshs = object.css('mesh')
17
+ meshs.each do |mesh|
18
+
19
+ num_vertices = mesh.css("vertex").count
20
+ triangles = mesh.css("triangle")
21
+ l.error :not_enough_triangles if triangles.count < 4
22
+
23
+ if triangles
24
+ triangles.each do |triangle|
25
+
26
+ v1 = triangle.attributes["v1"].to_s.to_i
27
+ v2 = triangle.attributes["v2"].to_s.to_i
28
+ v3 = triangle.attributes["v3"].to_s.to_i
29
+
30
+ l.error :invalid_vertex_index if [v1, v2, v3].select{|vertex| vertex >= num_vertices}.count > 0
31
+
32
+ unless includes_material
33
+ l.context "validating property overrides" do |l|
34
+ property_overrides = []
35
+ property_overrides << triangle.attributes['p1'].to_s.to_i if triangle.attributes['p1']
36
+ property_overrides << triangle.attributes['p2'].to_s.to_i if triangle.attributes['p2']
37
+ property_overrides << triangle.attributes['p3'].to_s.to_i if triangle.attributes['p3']
38
+
39
+ property_overrides.reject! { |prop| prop.nil? }
40
+ l.error :has_base_materials_gradient unless property_overrides.uniq.size <= 1
41
+ end
42
+ end
43
+
44
+ if v1 == v2 || v2 == v3 || v3 == v1
45
+ l.error :non_distinct_indices
46
+ end
47
+
48
+ list.add_edge(v1, v2)
49
+ list.add_edge(v2, v3)
50
+ list.add_edge(v3, v1)
51
+ unless has_triangle_pid
52
+ has_triangle_pid = triangle.attributes["pid"] != nil
53
+ end
54
+ end
55
+
56
+ if has_triangle_pid && !(object.attributes["pindex"] && object.attributes["pid"])
57
+ l.error :missing_object_pid
58
+ end
59
+
60
+ result = list.verify_edges
61
+ if result == :bad_orientation
62
+ l.error :resource_3dmodel_orientation
63
+ elsif result == :hole
64
+ l.error :resource_3dmodel_hole
65
+ elsif result == :nonmanifold
66
+ l.error :resource_3dmodel_nonmanifold
67
+ end
68
+
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.validate(model_doc, includes_material)
75
+ model_doc.css('model/resources/object').select { |object| ['model', 'solidsupport', ''].include?(object.attributes['type'].to_s) }.each do |object|
76
+ validate_object(object, includes_material)
77
+ end
78
+ end
79
+
80
+ end