Assign material to entity existing in a component instance (imported dwg)

Hi Everyone,
I got few queries. I’m having a Revit family (.rfa) that I need to use in sketchup (Version 2023). in other wors I need to create a skp file out of the rfa file with all the visible properties (Material/ transparency/ color etc.) preserved.

I can’t directly import the rfa file into sketchup. Hence I’m first exporting a dwg from rfa file and then to import the dwg in SketchUp model. In this process it then loses the properties like material and transparency etc. which is required to remain same. Though I’ve successfully imported the dwg file using ruby API.

Now I’m trying to assign a material for imported family (dwg) in SketchUp but I’m not getting how to access all different entities available in the imported component (dwg) like different faces, or solids (entities) maybe.

Can anyone please suggest something here or maybe if you can tell me an alternative and preferable approach?

Test.dwg (1.5 MB)

In the attached drawing of a door I have multiple glass panels and Metallic frame for the door and for the multiple glass panels. All I want is to assign different materials to frame and glass panels here using ruby API.

If you are using the Model #import method, check the Importer Options file for information on creating a valid hash for the various importers.

For 3D Autocad (DWG/DXF) the following options are there:

  • import_materials - Boolean to indicate whether to import materials. Added in SU2019.
  • merge_coplanar_faces - Boolean to indicate whether to merge coplanar faces.
  • orient_faces - Boolean to indicate whether to orient faces consistently.
  • preserve_origin - Boolean to indicate whether to preserve drawing origin.

If you set the import_materials to true you should get the material imported, eg:

def import_my_dwg(path)
  model = Sketchup.active_model
  options = { :import_materials  => true,
              :merge_coplanar_faces => true,
              :orient_faces => true,
              :preserve_origin => false,
              :show_summary => false}
  status = model.import(path, options)
end
import_my_dwg(path)

(Where: path (String) — The file path )

Actulally, it is similar to the option you can reach from UI:

Actulally, it is similar to the option you can reach from UI:

image

Thanks for your prompt response!

I missed to communicate that I’m able to import the dwg file using ruby API but I’m not sure how can I assign different materials to the entities existing in the component instance (imported dwg). Now I’ve edited the question as well for avoiding such confusion further.

I see. You can assign materials of the faces of the component definition entities.
You need to define some criteria’s to be able to decide which faces are the panel and which one is the frame.

:bulb: My idea below is to get the faces in a component definition in a question (here the name of the component “Family_Test - Family_Test-67707-3D) , check the area of faces, determine the maximum.
Then iterate all faces and set different material ( here is “red” & “black” ) if its area is above or below of the 90% of the max area.

You need to know the definition name

def color_my_componet( name, panel_material, frame_material )
  model = Sketchup.active_model
  definitions = model.definitions
  my_defi = definitions.find{|d| 
    #d.name = name   edited:
    d.name == name
  }
  faces = my_defi.entities.grep(Sketchup::Face)
  max_area = faces.map(&:area).max
  model.start_operation('Color my component', true)
  faces.each{|f|
    if f.area > 0.9 * max_area
      f.material = panel_material
      f.back_material = panel_material
    else
      f.material = frame_material
      f.back_material = frame_material
    end
  }
  model.commit_operation
end
color_my_componet( "Family_Test - Family_Test-67707-_3D_", "red", "black" )

col_by_area

1 Like

BTW:

I’m not sure if it is relevant ( I have no experience with Revit) and if you are aware that .rvt file can be imported:
SketchUp Desktop 2023.0 release-notes | SketchUp Help

Revit Importer | SketchUp Extension Warehouse

Thanks for helping!
yes, I’m aware that .rvt files can be imported directly in SketchUp but there’s no support for .rfa files.

Hi,
This code works fine only if I close sketchup after importing the dwg and saving the file. I’m not able to do import and material assignment task in one go without closing and reopening the file again.
Any guess, What’s I’m missing? I’ve use “model.commit_operation” after both the tasks.

Two things:

  1. Upps… there is a mistake in a code above: ( :blush:)
  1. I guess you imported the same dwg second time which will give an unique name for newly implored definition : “Family_Test - Family_Test-67707-3D#1”), because there is a definition there with a same name already.
    Since you are calling again the color_my_componet method with the original name it will color the original component definition entities, not the newly imported one.

To avoid it, you can rename the definition after colored, so the new definition can get its original name.

E.g:

def color_my_componet( name, panel_material, frame_material )
  model = Sketchup.active_model
  definitions = model.definitions
  my_defi = definitions.find{|d| 
    d.name == name
  }
  faces = my_defi.entities.grep(Sketchup::Face)
  max_area = faces.map(&:area).max
  model.start_operation('Color my component', true)
  faces.each{|f|
    if f.area > 0.9 * max_area
      f.material = panel_material
      f.back_material = panel_material
    else
      f.material = frame_material
      f.back_material = frame_material
    end
  }
  my_defi.name = name + "-colored"
  model.commit_operation
end
color_my_componet( "Family_Test - Family_Test-67707-_3D_", "red", "black" )

I’ve found the issue. Actually, when I print the available definitions, it shows that the definition “Test_Project - 3D View - {3D}.dwg” is available, but the code says that available faces for the definition is zero. It happens when the code is run for first time.

If the script is run further (after doing undo the operation of this material assignment), it shows that there’s no definition for “Test_Project - 3D View - {3D}.dwg”. How is it possible that the entity is available in model, has a definition but has no faces at all?

As I’m not getting how I can setup a debug functioning for the code with SU, I’m getting nowhere. Below is the code I’m using as per your suggestion. Though there are a few changes to track the execution as I’m unable to debug it.

def color_my_componet( name, panel_material, frame_material )
  model = Sketchup.active_model

  puts "\n************* \navailable definitions are:"
  definitions = model.definitions
  definitions.each{|definition|
      puts definition.name
     }
  my_defi = definitions.find{|d| 
    d.name == name
  }

  if my_defi == nil
   puts "Nil definition"
  else    
    faces = my_defi.entities.grep(Sketchup::Face)
    # puts my_defi.name  + "has a total faces => " 
    puts faces.length
    max_area = faces.map(&:area).max
    model.start_operation('Color my component', true)
    materials = model.materials
    number = materials.length
    puts number
    materials.each{|mat|
    puts mat.name
    }
    
    areaInStr = max_area.to_s()
    puts "Max area is "+areaInStr
    if faces.length > 0

      faces.each{|f|   
      if f.area > 0.1 * max_area
        f.material = panel_material
        f.back_material = panel_material
        puts "Face color updated"
      else
        f.material = frame_material
        f.back_material = frame_material
      end
      }
    else
        puts "Zero faces are available for definition"
    end
  end
      model.commit_operation
end

entityName = "Test_Project - 3D View - {3D}.dwg"
color_my_componet( entityName, "red", "black")
model.commit_operation  

Output for 1st attempt:


************* 
available definitions are:
Family_Test - Family_Test-67707-_3D_
Heather
Test_Project - 3D View - {3D}.dwg
0
21
Heather_Hair2
Heather_Shirt
Heather_PantShadow
Heather_Band
Heather_Stripe1
Heather_Stripe2
Heather_ShirtShadow
Heather_Hair
Heather_Soles
Heather_Jeans
Heather_Hat
Heather_Cuffs
Heather_Shoes
Heather_Brim
Heather_Skin
Lily_Dark
Lily_Blonde
Lily_Light
Heather_Brim1
<auto>
Translucent Glass Tinted
Max area is 
Zero faces are available for definition

Output in next attempts:


************* 
available definitions are:
Family_Test - Family_Test-67707-_3D_
Heather
Test_Project - 3D View - {3D}.dwg
Nil definition

even if I use below it doesn’t change anything.

entityName = "Family_Test - Family_Test-67707-_3D_"
color_my_componet( entityName, "red", "black")
model.commit_operation  

Untitled.skp (884.1 KB)

Note 1:
Please edit your post and format it to see the code properly.! Use this guideline:
[How to] Post correctly formatted and colorized code on the forum? - Developers - SketchUp Community
code


Note 2:

The “debug functioning” you are using here - writing a puts inside the code to some “critical” place - is totally fine. I’m using that too and never ever used VScode or any other debugger… :innocent:


Back to topic:

No.
It is modified code!
Also I do not see how did you called (witch parameters you used for) the def color_my_componet method.

I guess you used “Test_Project - 3D View - {3D}.dwg” as a first parameter.
Therefore, certainly there are no faces, because that definition does contains only a instance of the “Family_Test - Family_Test-67707-3D” definition. The faces are in the second (nested) one.
image

I’ve used both as parameter. When passing “Family_Test - Family_Test-67707-3D” as parameter faces are available but when I pass “Test_Project - 3D View - {3D}.dwg” as first parameter of color_my_component function I get zero faces. So, I understood the point that DWG will not contain the faces but the exported family from rfa to dwg.

color_my_componet( "Family_Test - Family_Test-67707-_3D_", "red", "black")

Now the function works well when the code is run for first time.
Still, If the script is run further (after doing undo the operation of this material assignment), it shows that there’s no definition for “Family_Test - Family_Test-67707-3D”. How is it possible that the entity is available in model, but not the definition?

Below is the code I’m using as per your suggestion. Though there are a few changes to track the execution as I’m unable to debug it.

def color_my_componet( name, panel_material, frame_material )
  model = Sketchup.active_model

  puts "\n************* \navailable definitions are:"
  definitions = model.definitions
  definitions.each{|definition|
      puts definition.name
     }
  my_defi = definitions.find{|d| 
    d.name == name
  }

  if my_defi == nil
   puts "Nil definition"
  else    
    faces = my_defi.entities.grep(Sketchup::Face)
    # puts my_defi.name  + "has a total faces => " 
    puts faces.length
    max_area = faces.map(&:area).max
    model.start_operation('Color my component', true)
    materials = model.materials
    number = materials.length
    puts number
    materials.each{|mat|
    puts mat.name
    }
    
    areaInStr = max_area.to_s()
    puts "Max area is "+areaInStr
    if faces.length > 0

      faces.each{|f|   
      if f.area > 0.1 * max_area
        f.material = panel_material
        f.back_material = panel_material
        puts "Face color updated"
      else
        f.material = frame_material
        f.back_material = frame_material
      end
      }
    else
        puts "Zero faces are available for definition"
    end
  end
      model.commit_operation
end

entityName = "Family_Test - Family_Test-67707-_3D_"
color_my_componet( entityName, "red", "black")
model.commit_operation  

Output for 1st attempt:


************* 
available definitions are:
Family_Test - Family_Test-67707-_3D_
Heather
Test_Project - 3D View - {3D}.dwg
8302
21
Heather_Hair2
Heather_Shirt
Heather_PantShadow
Heather_Band
Heather_Stripe1
Heather_Stripe2
Heather_ShirtShadow
Heather_Hair
Heather_Soles
Heather_Jeans
Heather_Hat
Heather_Cuffs
Heather_Shoes
Heather_Brim
Heather_Skin
Lily_Dark
Lily_Blonde
Lily_Light
Heather_Brim1
<auto>
Translucent Glass Tinted
Max area is 3867.792825117733
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated
Face color updated

Output in next attempts:


************* 
available definitions are:
Family_Test - Family_Test-67707-_3D_
Heather
Test_Project - 3D View - {3D}.dwg
Nil definition

Untitled.skp (884.1 KB)

Always code defensively. And always check to be sure that you have objects or entities to operate upon before your code starts an undo operation.

This means that following the grep for faces, your code should “bail out” from the method if faces.empty? and then an operation would not be started (because there would be nothing to undo.)

Instead, your code above, does not check the number of faces until after the operation is started.


Also, a bit of coding style.

faces.each{|f|
… should be typed as …
faces.each { |f|

Ie, the spacing of { should be the same as if you used doend.

faces.each do |f|
  puts face.material.name
end
faces.each { |f|
  puts face.material.name
}

You are not gaining speed and are suffering readability by running everything together.

Lastly, all statements within the block should be indented.

Lets examine your model. (You posted above)
Open the Entity Info and Outliner Tray. And don’t lose sight of what it shows. (Never)

Your dwg file imported as a component. The component definition name is Test_Project - 3D View - {3D}.dwg Select its instance and double click on it to go to its editing context. (You are editing now the instance definition, and can see its entities).

If you select all (e.g. Ctrl + A) you will be realized the selection is contains only one entity (or its superclass: drawingelment) which is an instance of the component named: Family_Test - Family_Test-67707-_3D_. There is no other entities , like face or edge there.
You need to double click on it to go to its editing context to be able to access the faces to paint.

The definition list of the model (Sketchup.active_model.definitions) contains all the definition of the model, independently how deeply nested their instances in a model. Even (can) contain the definitions which don’t have its instance in a model. So if you are deleting the component (instance) from the model the definition still can be there. You need to purge it (most of the case).