15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
# File 'lib/ruby3mf/model3mf.rb', line 15
def self.parse(document, zip_entry)
model_doc = nil
Log3mf.context "parsing model" do |l|
begin
model_doc = XmlVal.validate_parse(zip_entry, SchemaFiles::SchemaTemplate)
rescue Nokogiri::XML::SyntaxError => e
l.fatal_error :model_invalid_xml, e: e
end
l.context "verifying supported extensions" do |l|
model_doc.css("//model").first.namespaces.each do |prefix, uri|
unless prefix == "xmlns"
ext = KNOWN_EXTENSIONS[uri]
if ext.nil? || !ext[:supported]
l.warning :unsupported_extension, ext: (ext.nil? ? uri : ext[:name])
end
end
end
end
l.context "verifying requiredextensions" do |l|
model_doc.css("//model").map { |node| node.attributes["requiredextensions"] }.compact.each do |required_extension|
required_extension.value.split(" ").each do |ns|
namespace_uri = model_doc.namespaces["xmlns:#{ns}"]
l.error :missing_extension_namespace_uri, ns: ns unless namespace_uri
end
end
end
l.context "verifying 3D payload required resources" do |l|
required_resources = model_doc.css("//model//resources//*[path]").collect { |n| n["path"] }
required_resources += model_doc.css("//model//resources//object[thumbnail]").collect { |n| n["thumbnail"] }
relationship_resources = []
rel_file = "#{Pathname(zip_entry.name).dirname.to_s}/_rels/#{File.basename(zip_entry.name)}.rels"
relationships = document.relationships[rel_file]
unless (relationships.nil?)
relationship_resources = relationships.map { |relationship| relationship[:target] }
end
missing_resources = (required_resources - relationship_resources)
if missing_resources.empty?
l.info "All model required resources are defined in .rels relationship files."
else
missing_resources.each { |mr|
l.error :model_resource_not_in_rels, mr: mr
}
end
end
l.context 'verifying resources' do |l|
resources = model_doc.root.css("resources")
if resources
ids = resources.children.map { |child| child.attributes['id'].to_s if child.attributes['id'] }
l.error :resource_id_collision if ids.uniq.size != ids.size
pids = resources.children.map { |child| child.attributes['pid'].to_s }
missing_pids = pids.select { |pid| !pid.empty? and !ids.include? pid }
missing_pids.each do |p|
l.error :resource_pid_missing, pid: p
end
end
end
l.context "verifying build items" do |l|
build_items = model_doc.css('build/item')
object_ids = build_items.map { |x| x.attributes["objectid"].value }
other_build_items = object_ids.map { |id| find_model_object(model_doc, id, 'other') }.flatten
l.error :build_with_other_item if other_build_items.any?
end
l.context "checking metadata" do |l|
metadata_names = model_doc.root.css("metadata").map { |met| met['name'] }
l.error :metadata_elements_with_same_name unless metadata_names.uniq!.nil?
unless (metadata_names - VALID_CORE_METADATA_NAMES).empty?
= metadata_names - VALID_CORE_METADATA_NAMES
ns_names = .select { |n| n.include? ':' }
l.error :invalid_metadata_under_defaultns unless ( - ns_names).empty?
unless ns_names.empty?
prefixes = model_doc.root.namespace_definitions.map { |defs| defs.prefix }.reject { |pre| pre.nil? }
l.error :invalid_metadata_name unless (ns_names.collect { |i| i.split(':').first } - prefixes).empty?
end
end
end
includes_material = model_doc.namespaces.values.include?(MATERIAL_EXTENSION)
MeshAnalyzer.validate(model_doc, includes_material)
l.context "verifying triangle normal" do |l|
model_doc.css('model/resources/object').select { |object| ['model', 'solidsupport', ''].include?(object.attributes['type'].to_s) }.each do |object|
meshes = object.css('mesh')
meshes.each do |mesh|
processor = MeshNormalAnalyzer.new(mesh)
l.error :inward_facing_normal if processor.found_inward_triangle
end
end
end
end
model_doc
end
|