class MeshAnalyzer

Public Class Methods

validate(model_doc, includes_material) click to toggle source
# File lib/ruby3mf/mesh_analyzer.rb, line 74
def self.validate(model_doc, includes_material)
  model_doc.css('model/resources/object').select { |object| ['model', 'solidsupport', ''].include?(object.attributes['type'].to_s) }.each do |object|
    validate_object(object, includes_material)
  end
end
validate_object(object, includes_material) click to toggle source
# File lib/ruby3mf/mesh_analyzer.rb, line 3
def self.validate_object(object, includes_material)
  Log3mf.context "verifying object" do |l|
    children = object.children.map { |child| child.name }
    have_override = object.attributes["pid"] or object.attributes["pindex"]
    l.error :object_with_components_and_pid if have_override && children.include?("components")
  end

  Log3mf.context "validating geometry" do |l|
    list = EdgeList.new

    # if a triangle has a pid, then the object needs a pid
    has_triangle_pid = false

    meshs = object.css('mesh')
    meshs.each do |mesh|

      num_vertices = mesh.css("vertex").count
      triangles = mesh.css("triangle")
      l.error :not_enough_triangles if triangles.count < 4

      if triangles
        triangles.each do |triangle|

          v1 = triangle.attributes["v1"].to_s.to_i
          v2 = triangle.attributes["v2"].to_s.to_i
          v3 = triangle.attributes["v3"].to_s.to_i

          l.error :invalid_vertex_index if [v1, v2, v3].select{|vertex| vertex >= num_vertices}.count > 0

          unless includes_material
            l.context "validating property overrides" do |l|
              property_overrides = []
              property_overrides << triangle.attributes['p1'].to_s.to_i if triangle.attributes['p1']
              property_overrides << triangle.attributes['p2'].to_s.to_i if triangle.attributes['p2']
              property_overrides << triangle.attributes['p3'].to_s.to_i if triangle.attributes['p3']

              property_overrides.reject! { |prop| prop.nil? }
              l.error :has_base_materials_gradient unless property_overrides.uniq.size <= 1
            end
          end

          if v1 == v2 || v2 == v3 || v3 == v1
            l.error :non_distinct_indices
          end

          list.add_edge(v1, v2)
          list.add_edge(v2, v3)
          list.add_edge(v3, v1)
          unless has_triangle_pid
            has_triangle_pid = triangle.attributes["pid"] != nil
          end
        end

        if has_triangle_pid && !(object.attributes["pindex"] && object.attributes["pid"])
          l.error :missing_object_pid
        end

        result = list.verify_edges
        if result == :bad_orientation
          l.error :resource_3dmodel_orientation
        elsif result == :hole
          l.error :resource_3dmodel_hole
        elsif result == :nonmanifold
          l.error :resource_3dmodel_nonmanifold
        end

      end
    end
  end
end