ruby3mf 0.2.6 → 0.2.7

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