Problem with overlapping faces

I am working on a method to calculate the area of the projection of a group or component (in this example, only for the selected elements), and I have written this method for that purpose.
test caras.skp (205.9 KB)


# Selection footprint

def drop_faces_to_zero(faces)
  model = Sketchup.active_model
  entities = model.active_entities

  # Group as a container
  common_group = entities.add_group
  common_group_entities = common_group.entities


  faces.each_with_index do |face, index|
    # groups for each face
    individual_group = common_group_entities.add_group

    begin
      # outer loop vertex z to 0
      outer_loop_vertices = face.outer_loop.vertices.map do |vertex|
        position = vertex.position
        Geom::Point3d.new(position.x, position.y, 0.0)  # Forzar Z a 0
      end


      # outer loop face
      new_face = individual_group.entities.add_face(outer_loop_vertices)

      if new_face.nil?
        individual_group.erase!
        next
      end

      # Inner lop faces substraction
      face.loops.each do |loop|
        next if loop == face.outer_loop  # avoid outer loop
        # inner loop vertex z to 0
        inner_loop_points = loop.vertices.map do |vertex|
          position = vertex.position
          Geom::Point3d.new(position.x, position.y, 0.0)  # Forzar Z a 0
        end


        # inner loop faces
        inner_face = individual_group.entities.add_face(inner_loop_points)

        if inner_face
          # delete face and maintain edges
          inner_face.erase!
        end
      end

    rescue StandardError => e
      puts "Error not able to generate faces in group"
      individual_group.erase!
    end
  end

  # Explode individual groups inside common group
  common_group_entities.grep(Sketchup::Group).each do |group|
    group.explode
  end


  # Select interior edges in order to delete them.
  model.selection.clear
  common_group_entities.grep(Sketchup::Edge).each do |edge|
    if edge.faces.length == 2
      model.selection.add(edge)
    end
  end

end


model = Sketchup.active_model
selection = model.selection

selected_faces = selection.grep(Sketchup::Face)

if selected_faces.empty?
  UI.messagebox("Please select almost one face")
else
  drop_faces_to_zero(selected_faces)
end

The goal is to delete the interior edges, but in the test I conducted, overlapping faces are generated, and some exterior edges seem to belong to two faces.

How can I avoid this? I’ve noticed that if I select everything and perform an intersection of the selection with itself, the problem is solved. Does such a method exist?

yes
The Entities #intersect_with method is used to intersect an entities, component instance, or group object with a entities object.

(not an easy to understand… and see some notes on GitHub:
Issues · SketchUp/api-issue-tracker · GitHub )

1 Like

Thanks @dezmo I’ll try to make it work…

Please check that Sketchup.break_edges? is set to true.

If it isn’t then make it so

Sketchup.break_edges = true

Yes, is set to true.

Sorry for the bad lead. I thought that break_edges was the source of problem but I see now that the order in which the faces are selected changes the result of the operation.

The two overlapping faces would best be kept inside a group.
Overlap them as you wish…
Then use the Class: Sketchup::Entities — SketchUp Ruby API Documentation as explained by @dezmo - to ‘merge’ their faces and edges.
It’s the most convoluted method around but is capable of doing what you want…
After the ‘merging’ you might then wish to remove any coplanar edges that result between two created faces - tip: collect all of the available edges and check in turn if they support two or more faces - if so, then keep a record of them, and at the end delete those edges… Now you have a combination of the two original faces with any unwanted edges removed…

Thanks @sWilliams & @TIG .

Merge faces as @dezmo said was successful. I could obtain the footprin face required to obtain the area and outer perimeter.

This is the final script.

# Selection footprint area and perimeter

def drop_faces_to_zero(faces)
  model = Sketchup.active_model
  entities = model.active_entities

  # Group as a container
  common_group = entities.add_group
  common_group_entities = common_group.entities

  faces.each_with_index do |face, index|
    # groups for each face
    individual_group = common_group_entities.add_group

    begin
      # outer loop vertex z to 0
      outer_loop_vertices = face.outer_loop.vertices.map do |vertex|
        position = vertex.position
        Geom::Point3d.new(position.x, position.y, 0.0)  # Forzar Z a 0
      end

      # outer loop face
      new_face = individual_group.entities.add_face(outer_loop_vertices)

      if new_face.nil?
        individual_group.erase!
        next
      end

      # Inner lop faces substraction
      face.loops.each do |loop|
        next if loop == face.outer_loop  # avoid outer loop
        # inner loop vertex z to 0
        inner_loop_points = loop.vertices.map do |vertex|
          position = vertex.position
          Geom::Point3d.new(position.x, position.y, 0.0)  # Forzar Z a 0
        end

        # inner loop faces
        inner_face = individual_group.entities.add_face(inner_loop_points)

        if inner_face
          # delete face and maintain edges
          inner_face.erase!
        end
      end

    rescue StandardError => e
      puts "Error not able to generate faces in group"
      individual_group.erase!
    end
  end

  # Explode individual groups inside common group
  common_group_entities.grep(Sketchup::Group).each do |group|
    group.explode
  end
  
  #intersec with selection
  model = Sketchup.active_model

  # temporary group
  temp_group = common_group_entities

  temp_group.intersect_with(
    false,    # avoid hiden geometry
    Geom::Transformation.new,   # entities transformation
    temp_group,         # target entities
    Geom::Transformation.new,   # result transformation
    true,   # all tags
    temp_group.to_a # entities to intersect
  )

  #delete useless edges
  temp_group.grep(Sketchup::Edge).each do |edge|
    next if edge.deleted?
    if edge.faces.length == 2
      edge.erase!
    end
  end
  
  temp_group.grep(Sketchup::Edge).each do |edge|
    next if edge.deleted?
    if edge.faces.length == 0
      edge.erase! 
    end
  end

  #Resulted area and outer perimeter
  puts "Footprint Area " + Sketchup.format_area(temp_group.grep(Sketchup::Face).first.area)
  perimeter = 0
  temp_group.grep(Sketchup::Face).first.outer_loop.edges.each do |e|
    perimeter += e.length
  end
  puts "Footprint Outer Perimter" + Sketchup.format_length(perimeter)

  model = Sketchup.active_model
  entities = model.active_entities
  entities.erase_entities(temp_group.to_a)

end

model = Sketchup.active_model
selection = model.selection
selected_faces = selection.grep(Sketchup::Face)

if selected_faces.empty?
  UI.messagebox("Please select almost one face")
else
  drop_faces_to_zero(selected_faces)
end
1 Like