diff --git a/speckle_connector/src/convertors/to_speckle.rb b/speckle_connector/src/convertors/to_speckle.rb index 001747c..f13db71 100644 --- a/speckle_connector/src/convertors/to_speckle.rb +++ b/speckle_connector/src/convertors/to_speckle.rb @@ -2,6 +2,7 @@ require_relative 'converter' require_relative '../speckle_objects/geometry/line' +require_relative '../speckle_objects/geometry/mesh' module SpeckleConnector module Converters @@ -13,7 +14,7 @@ module SpeckleConnector def convert(obj) return SpeckleObjects::Geometry::Line.from_edge(obj, @units).to_h if obj.is_a?(Sketchup::Edge) - return face_to_speckle(obj) if obj.is_a?(Sketchup::Face) + return SpeckleObjects::Geometry::Mesh.from_face(obj, @units) if obj.is_a?(Sketchup::Face) return group_to_speckle(obj) if obj.is_a?(Sketchup::Group) return component_definition_to_speckle(obj) if obj.is_a?(Sketchup::ComponentDefinition) @@ -223,19 +224,6 @@ module SpeckleConnector uvs_array end - def face_to_speckle(face) - mesh = face.loops.count > 1 ? face.mesh : nil - { - speckle_type: 'Objects.Geometry.Mesh', - units: @units, - renderMaterial: face.material.nil? ? nil : material_to_speckle(face.material), - bbox: bounds_to_speckle(face.bounds), - '@(31250)vertices' => mesh.nil? ? face_vertices_to_array(face) : mesh_points_to_array(mesh), - '@(62500)faces' => mesh.nil? ? face_indices_to_array(face, 0) : mesh_faces_to_array(mesh, -1), - '@(31250)faceEdgeFlags' => mesh.nil? ? face_edge_flags_to_array(face) : mesh_edge_flags_to_array(mesh) - } - end - def vertex_to_speckle(vertex) point = vertex.position { diff --git a/speckle_connector/src/speckle_objects/geometry/mesh.rb b/speckle_connector/src/speckle_objects/geometry/mesh.rb new file mode 100644 index 0000000..cdef46e --- /dev/null +++ b/speckle_connector/src/speckle_objects/geometry/mesh.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require_relative '../geometry/bounding_box' +require_relative '../other/render_material' +require_relative '../../typescript/typescript_object' + +module SpeckleConnector + module SpeckleObjects + module Geometry + # Mesh object definition for Speckle. + class Mesh < Typescript::TypescriptObject + SPECKLE_TYPE = 'Objects.Geometry.Mesh' + ATTRIBUTES = { + speckle_type: String, + units: String, + renderMaterial: [NilClass, Other::RenderMaterial], + bbox: Geometry::BoundingBox, + '@(31250)vertices': Array, + '@(62500)faces': Array, + '@(31250)faceEdgeFlags': Array + }.freeze + + # @param face [Sketchup::Face] face to convert mesh + def self.from_face(face, units) + mesh = face.loops.count > 1 ? face.mesh : nil + Mesh.new( + speckle_type: SPECKLE_TYPE, + units: units, + renderMaterial: face.material.nil? ? nil : Other::RenderMaterial.from_material(face.material), + bbox: Geometry::BoundingBox.from_bounds(face.bounds, units), + '@(31250)vertices': mesh.nil? ? face_vertices_to_array(face, units) : mesh_points_to_array(mesh, units), + '@(62500)faces': mesh.nil? ? face_indices_to_array(face, 0) : mesh_faces_to_array(mesh, -1), + '@(31250)faceEdgeFlags': mesh.nil? ? face_edge_flags_to_array(face) : mesh_edge_flags_to_array(mesh) + ) + end + + # get a flat array of vertices from a list of sketchup vertices + def self.face_vertices_to_array(face, units) + pts_array = [] + face.vertices.each do |v| + pt = v.position + pts_array.push(Geometry.length_to_speckle(pt[0], units), + Geometry.length_to_speckle(pt[1], units), + Geometry.length_to_speckle(pt[2], units)) + end + pts_array + end + + # get a flat array of vertices from a sketchup polygon mesh + def self.mesh_points_to_array(mesh, units) + pts_array = [] + mesh.points.each do |pt| + pts_array.push( + Geometry.length_to_speckle(pt[0], units), + Geometry.length_to_speckle(pt[1], units), + Geometry.length_to_speckle(pt[2], units) + ) + end + pts_array + end + + # get a flat array of face indices from a sketchup face + def self.face_indices_to_array(face, offset) + face_array = [face.vertices.count] + face_array.push(*face.vertices.count.times.map { |index| index + offset }) + face_array + end + + # get an array of face indices from a sketchup polygon mesh + def self.mesh_faces_to_array(mesh, offset = 0) + faces = [] + mesh.polygons.each do |poly| + faces.push( + poly.count, *poly.map { |index| index.abs + offset } + ) + end + faces + end + + def self.face_edge_flags_to_array(face) + face.outer_loop.edges.map(&:soft?) + end + + def self.mesh_edge_flags_to_array(mesh) + edge_flags = [] + mesh.polygons.each do |poly| + edge_flags.push( + *poly.map(&:negative?) + ) + end + edge_flags + end + + def attribute_types + ATTRIBUTES + end + end + end + end +end diff --git a/speckle_connector/src/speckle_objects/other/render_material.rb b/speckle_connector/src/speckle_objects/other/render_material.rb new file mode 100644 index 0000000..5360b52 --- /dev/null +++ b/speckle_connector/src/speckle_objects/other/render_material.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require_relative '../../typescript/typescript_object' + +module SpeckleConnector + module SpeckleObjects + module Other + # RenderMaterial object definition for Speckle. + class RenderMaterial < Typescript::TypescriptObject + SPECKLE_TYPE = 'Objects.Other.RenderMaterial' + ATTRIBUTE_TYPES = { + speckle_type: String, + name: String, + diffuse: Numeric, + opacity: Numeric, + emissive: Numeric, + metalness: Numeric, + roughness: Numeric + }.freeze + + def self.from_material(material) + rgba = material.color.to_a + RenderMaterial.new( + speckle_type: SPECKLE_TYPE, + name: material.name, + diffuse: [rgba[3] << 24 | rgba[0] << 16 | rgba[1] << 8 | rgba[2]].pack('l').unpack1('l'), + opacity: material.alpha, + emissive: -16_777_216, + metalness: 0, + roughness: 1 + ) + end + + private + + def attribute_types + ATTRIBUTE_TYPES + end + end + end + end +end