From b8237b1be7e08e1d2e001c2ecbabfd111efee51f Mon Sep 17 00:00:00 2001 From: oguzhankoral Date: Tue, 13 Dec 2022 10:32:59 +0300 Subject: [PATCH 1/2] Send meshes separately under the group --- .../src/convertors/base_object_serializer.rb | 4 +-- .../src/convertors/to_speckle.rb | 2 +- .../src/speckle_objects/geometry/mesh.rb | 4 +-- .../speckle_objects/other/block_definition.rb | 26 +++++++++---------- .../speckle_objects/other/block_instance.rb | 11 +++++--- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/speckle_connector/src/convertors/base_object_serializer.rb b/speckle_connector/src/convertors/base_object_serializer.rb index c0cd2386..f57dd0e7 100644 --- a/speckle_connector/src/convertors/base_object_serializer.rb +++ b/speckle_connector/src/convertors/base_object_serializer.rb @@ -174,7 +174,7 @@ def traverse_base_props(base, traversed_base) # rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/PerceivedComplexity - # rubocop:disable Style/OptionalBooleanParamete + # rubocop:disable Style/OptionalBooleanParameter def traverse_value(value, is_detach = false) # 1. Return same value if value is primitive type (string, numeric, boolean) return value unless value.is_a?(Hash) || value.is_a?(Array) @@ -214,7 +214,7 @@ def traverse_value(value, is_detach = false) # rubocop:enable Metrics/MethodLength # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/PerceivedComplexity - # rubocop:enable Style/OptionalBooleanParamete + # rubocop:enable Style/OptionalBooleanParameter def detach_helper(reference_id) @lineage.each do |parent| diff --git a/speckle_connector/src/convertors/to_speckle.rb b/speckle_connector/src/convertors/to_speckle.rb index bb7fda6b..fbc9f830 100644 --- a/speckle_connector/src/convertors/to_speckle.rb +++ b/speckle_connector/src/convertors/to_speckle.rb @@ -54,7 +54,7 @@ def convert(entity) return SpeckleObjects::Other::BlockInstance.from_group(entity, @units, @definitions, &convert) end if entity.is_a?(Sketchup::ComponentInstance) - return SpeckleObjects::Other::BlockInstance.from_component_instance(entity, @units, @definitions) + return SpeckleObjects::Other::BlockInstance.from_component_instance(entity, @units, @definitions, &convert) end if entity.is_a?(Sketchup::ComponentDefinition) return SpeckleObjects::Other::BlockDefinition.from_definition(entity, @units, @definitions, &convert) diff --git a/speckle_connector/src/speckle_objects/geometry/mesh.rb b/speckle_connector/src/speckle_objects/geometry/mesh.rb index 52541643..0c34c823 100644 --- a/speckle_connector/src/speckle_objects/geometry/mesh.rb +++ b/speckle_connector/src/speckle_objects/geometry/mesh.rb @@ -59,8 +59,8 @@ def self.to_native(sketchup_model, mesh, layer, entities) entities.add_faces_from_mesh(native_mesh, smooth_flags, material) added_faces = entities.grep(Sketchup::Face).last(native_mesh.polygons.length) added_faces.each { |face| face.layer = layer } - # Do not merge coplanar faces if they comes from already sketchup. - Converters::CleanUp.merge_coplanar_faces(entities) if mesh['sketchup_attributes'].nil? + # Merge only added faces in this scope + Converters::CleanUp.merge_coplanar_faces(added_faces) native_mesh end diff --git a/speckle_connector/src/speckle_objects/other/block_definition.rb b/speckle_connector/src/speckle_objects/other/block_definition.rb index 68c37a9a..c3278dbc 100644 --- a/speckle_connector/src/speckle_objects/other/block_definition.rb +++ b/speckle_connector/src/speckle_objects/other/block_definition.rb @@ -43,7 +43,7 @@ def self.from_definition(definition, units, definitions, &convert) # TODO: Solve logic geometry = if definition.entities[0].is_a?(Sketchup::Edge) | definition.entities[0].is_a?(Sketchup::Face) - group_mesh_to_speckle(definition, units, definitions) + group_entities_to_speckle(definition, units, definitions, &convert) else definition.entities.map { |entity| convert.call(entity) } end @@ -77,23 +77,21 @@ def self.to_native(sketchup_model, geometry, layer, name, application_id = '', & # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/ParameterLists - def self.group_mesh_to_speckle(definition, units, definitions) - # {material_id => Mesh} - mat_groups = {} - nested_blocks = [] - lines = [] + def self.group_entities_to_speckle(definition, units, definitions, &convert) + orphan_edges = definition.entities.grep(Sketchup::Edge).filter { |edge| edge.faces.none? } + lines = orphan_edges.collect do |orphan_edge| + Geometry::Line.from_edge(orphan_edge, units) + end - definition.entities.each do |entity| - if entity.is_a?(Sketchup::ComponentInstance) - nested_blocks.push(BlockInstance.from_component_instance(entity, units, definitions)) - end - next unless entity.is_a?(Sketchup::Face) + nested_blocks = definition.entities.grep(Sketchup::ComponentInstance).collect do |component_instance| + BlockInstance.from_component_instance(component_instance, units, definitions, &convert) + end - group_meshes_by_material(definition, entity, mat_groups, units) + meshes = definition.entities.grep(Sketchup::Face).collect do |face| + Geometry::Mesh.from_face(face, units) end - mat_groups.values.map { |group| group.delete(:pt_count) } - mat_groups.values + lines + nested_blocks + lines + nested_blocks + meshes end # rubocop:disable Metrics/AbcSize diff --git a/speckle_connector/src/speckle_objects/other/block_instance.rb b/speckle_connector/src/speckle_objects/other/block_instance.rb index 1a0e2144..6987953a 100644 --- a/speckle_connector/src/speckle_objects/other/block_instance.rb +++ b/speckle_connector/src/speckle_objects/other/block_instance.rb @@ -57,16 +57,21 @@ def self.from_group(group, units, component_defs, &convert) end # @param component_instance [Sketchup::ComponentInstance] component instance to convert Speckle BlockInstance - def self.from_component_instance(component_instance, units, component_defs) + def self.from_component_instance(component_instance, units, component_defs, &convert) BlockInstance.new( units: units, application_id: component_instance.guid, is_sketchup_group: false, bbox: Geometry::BoundingBox.from_bounds(component_instance.bounds, units), name: component_instance.name == '' ? nil : component_instance.name, - render_material: component_instance.material.nil? ? nil : RenderMaterial.from_material(group.material), + render_material: if component_instance.material.nil? + nil + else + RenderMaterial.from_material(component_instance.material) + end, transform: Other::Transform.from_transformation(component_instance.transformation, units), - block_definition: BlockDefinition.from_definition(component_instance.definition, units, component_defs) + block_definition: BlockDefinition.from_definition(component_instance.definition, units, component_defs, + &convert) ) end From 6ccb03c557fe4749eabeb5e2fd3e280ee845f87a Mon Sep 17 00:00:00 2001 From: oguzhankoral Date: Tue, 13 Dec 2022 11:48:32 +0300 Subject: [PATCH 2/2] Improve clean up with scoped faces --- speckle_connector/src/convertors/clean_up.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/speckle_connector/src/convertors/clean_up.rb b/speckle_connector/src/convertors/clean_up.rb index 116a29ba..6a6c321b 100644 --- a/speckle_connector/src/convertors/clean_up.rb +++ b/speckle_connector/src/convertors/clean_up.rb @@ -15,8 +15,8 @@ def self.merge_coplanar_faces(entities) edges = [] faces = entities.collect { |entity| entity if entity.is_a? Sketchup::Face }.compact faces.each { |face| face.edges.each { |edge| edges << edge } } - edges.compact! - edges.each { |edge| remove_edge_have_coplanar_faces(edge, false) } + edges.uniq! + edges.each { |edge| remove_edge_have_coplanar_faces(edge, faces, false) } end # Detect edges to remove by checking following controls respectively; @@ -28,13 +28,23 @@ def self.merge_coplanar_faces(entities) # - Whether UV texture map is aligned between faces or not. # - Finally, if faces are coplanar by correcting these checks, then removes edge from Sketchup.active_model. # @param edge [Sketchup::Edge] edge to check. + # @param faces [Array] scoped faces to check 'edge.faces' both (first and second) + # belongs to this faces or not. If any of this faces does not involve this scoped faces, then do not delete. # @param ignore_materials [Boolean] whether ignore materials or not. # Returns true if the given edge separating two coplanar faces. # Return false otherwise. - def self.remove_edge_have_coplanar_faces(edge, ignore_materials) + # rubocop:disable Metrics/AbcSize + def self.remove_edge_have_coplanar_faces(edge, faces, ignore_materials) return false unless edge.valid? && edge.is_a?(Sketchup::Edge) return false unless edge.faces.size == 2 + # Check scoped faces have this edges + if edge.faces.size == 2 + is_first = faces.include?(edge.faces[0]) + is_second = faces.include?(edge.faces[1]) + return false unless is_first && is_second + end + face_1, face_2 = edge.faces return false if face_duplicate?(face_1, face_2) @@ -54,6 +64,7 @@ def self.remove_edge_have_coplanar_faces(edge, ignore_materials) edge.erase! true end + # rubocop:enable Metrics/AbcSize # Determines if two faces are overlapped. def self.face_duplicate?(face_1, face_2, overlapping: false)