Is there a maximum limit to the # of entities a script can process?


#1

I wrote a script that the makes every face in the model a 2-sided face by copying the front material and texture position to the backface.
When I import the entire file, which contains about 430,000 faces, the script wont do a thing. When I import 1/2 of the file, it won’t work. When I import any 1/4 of the file, the script will work flawlessly. There are no bad objects or anything stopping the script in the imported file because I can import each separate quarter with no problem and run the script on each of them.

I have a similar routine set up the exact same way that scrolls through every object and puts them on different layers which works on the entire model in one shot.

Is this too much for Sketchup Ruby script to handle ?


#2

If it does not do anything, it might be worth to look at the script again: Either stops with an error (look at the console) or it skips faces intentionally (then it is useful to log for yourself why they were skipped).

If it does (a lot of) processing and SketchUp is just unresponsive, then take a look at the algorithm: Algorithm complexity does not necessarily grow linearly with input data, it may be cubic or even exponential!

SketchUp does not impose a limit, it only depends on what the computer can handle, and it miht take longer.


#3

Another thing to consider is that there are many different ways to do things via Ruby - which will perform very differently. Even in the API there are some methods that perform better than others.
If you have a sample snippet to share we can see if there are alternative ways to do what you do.


#4

The issue is that it will work on every object in the model - in PIECES, it will not work in one shot which is the ultimate goal. I thought for sure I had a “bad” object somewhere but its not the case.

No need to share snippit, here’s the whole thing:
“cnt” is a tally of the components
"cnt2" is a tally of all faces combined

require 'sketchup.rb’
UI.menu (“PlugIns”).add_item(“Make 2-sided”){
result = UI.messagebox “Make 2-sided ?” ,MB_OKCANCEL
if result == 1
model=Sketchup.active_model
val = "Layer0"
oblay = Sketchup.active_model.active_entities.find_all {|e| e.layer.name == val }
cnt = 0
cnt2 =0
for ent in oblay
if ent.is_a? Sketchup::ComponentInstance
vertp = nil
uvq = nil
temd = ent.definition
tement = temd.entities
for entc in tement
if entc.is_a? Sketchup::Face
mat = entc.material
if mat == nil
mat = entc.back_material
end
entc.back_material = mat
pts =[]
entc.outer_loop.vertices.each do |vert|
pts.push(vert.position)
tw = Sketchup.create_texture_writer
uvHelp = entc.get_UVHelper true, false, tw
uvq = uvHelp.get_front_UVQ(vert.position)
pts.push(uvq)
end
entc.position_material(mat, pts, false)
cnt2 = cnt2 + 1
end #is face
end #end foreach
cnt = cnt + 1
end #end iscomp
end #end oblay
UI.messagebox cnt ,MB_OKCANCEL
UI.messagebox cnt2 ,MB_OKCANCEL
end #result

}


#5

Can you put the code in code formatting block please? For easier reading.


#6

You can make use of code-highlighting when using the </> icon on the formatting toolbar or by using triple back ticks ```.

Corrected missing or superfluous spaces (arguments should be in brackets, although not required there are cases of operator precedence where it can cause errors; between method name and brackets is no space). Ruby is a human language, and most rubyists prefer full-written names for variables, so they are not so cryptic but self-explaining. For example it is hard to understand “temd” as “temporary definition”, “temp_def” is better. This reduces errors enormously.

Put your code into methods in your module. This way you get reasonable error messages in SketchUp’s Ruby console and you can reload the file to see changes. Your previous version would create a new menu item for every reloading.

require 'sketchup.rb'

module SteelDunnage

# Copies for all faces the texture from front- to backface.
# @param entities [Sketchup::Entities] The entities collection to process.
# @return [Fixnum, Fixnum] two debugging numbers
def self.copy_texture_to_both_sides(entities)
  val = "Layer0"
  oblay = entities.find_all{ |e| e.layer.name == val }
  cnt = 0
  cnt2 = 0
  for ent in oblay
    if ent.is_a?(Sketchup::ComponentInstance)
      vertp = nil
      uvq = nil
      temd = ent.definition
      tement = temd.entities
      for entc in tement
        if entc.is_a?(Sketchup::Face)
          mat = entc.material
          if mat == nil
            mat = entc.back_material
          end
          entc.back_material = mat
          pts = []
          entc.outer_loop.vertices.each{ |vert|
            pts.push(vert.position)
            tw = Sketchup.create_texture_writer
            uvHelp = entc.get_UVHelper(true, false, tw)
            uvq = uvHelp.get_front_UVQ(vert.position)
            pts.push(uvq)
          }
          entc.position_material(mat, pts, false)
          cnt2 = cnt2 + 1
        end #is face
      end #end foreach
      cnt = cnt + 1
    end #end iscomp
  end #end oblay
  return cnt, cnt2
end

unless loaded?(__FILE__)
  UI.menu("Plugins").add_item("Make faces textured on both sides"){
    if 1 == UI.messagebox("Make 2-sided ?", MB_OKCANCEL)
      entities = Sketchup.active_model.active_entities
      cnt, cnt2 = SteelDunnage.copy_texture_to_both_sides(entities)
      UI.messagebox(cnt, MB_OKCANCEL)
      UI.messagebox(cnt2, MB_OKCANCEL)
    end
  }
  loaded(__FILE__)
end

end # module SteelDunnage

#7
tw = Sketchup.create_texture_writer

This is slow, and you do it for every vertex of every face. Instead, get the texture writer once before the loop.

uvHelp = entc.get_UVHelper(true, false, tw)

Similarly, get the UVHelper once per face, before you loop over the vertices.

String comparison is slow!

val = "Layer0"
oblay = entities.find_all{ |e| e.layer == val }

Instead comparing the layer name, get a reference to the layer object and compare that. Make it configurable as a second argument of the method (default to Layer0):

def self.copy_texture_to_both_sides(entities, layer_name="Layer0")
  layer = entities.model.layers[layer_name]
  oblay = entities.find_all{ |e| layer == e.layer }

#8

Thanks for all that info, I meant to ask about the tw & uvhelp if that needed to be in the loop. Time really isn’t an issue, it takes a good 30 minutes total to import, then change all the material x & y sizes (via script), then move all objects to correct layers (via script), then make everything 2-sided via this script. 30 minutes - 40 minutes, doesn’t matter.
As for the script formatting, sorry about that, umm lets say that I not actually typing it in, I have 3dStudio & AutoCAD actually writing the scripts :smile:

I will make all these changes, see if it will run smoothly.


#9

Also, wrapping it all up in an operation that disabled the UI will also improve performance: model.start_operation("Copy Textures, true) and model.commit_operation.


#10

I finally figured it out after 3 weeks of staring at 20 lines of code. It was all the ‘points’ part of the the position_material method. The instructions say 2,4,6, or 8 pairs of points. I tested the code on what I thought was the most complicated faces in the drawing, that being a spline like curve with a projected material mapping, which is really a series of faces with 4 vertices each. 95% of my drawing has faces with only 4 points. There are many that have more BUT do not have a texture map, then there are a few that more then 4 vertices AND a texture map. That is where the code failed and why it seemed to work on only sections of the drawing, the sections that had these textured objects that had faces with more then 4 vertices. I simply capped the points array at 4 vertices which still applies the correct mapping regardless of how many vertices the face has, what a pain in the ass.

476,352 faces, 7 minutes plus to make them all 2-sided, respectable.

Next up (and last I hope) taking a spline drawn in 3dsMax that has camera attached to follow, having it write a Ruby script of the position and angle of the camera at specified points along that path, then having Sketchup create all the scenes automatically.

By the way, back to my original question about a maximum limit. Sketch up has a mind of its own, if I import my entire project at one time, it will arbitrarily skip whatever it wants, its a joke, I imported the SAME exact 3ds file 5 times, each time it left out dozens of elements, I am talking boxes, not complex objects or whatnot, and everytime it was different. Sometimes one element came in, then the next import, it was gone, then it came back, etc. etc. it was funny, I was showing my boss this because he insists on using Sketchup so he can walkthrough buildings with his clients. Any thoughts about why it does this ? It is remedied by turning off about a third of the layers and importing 3 separate files.


#11

Do you have some sample models you can share with us? PM me if you don’t have to share publicly and I’ll log it internally.


#12

I really don’t want to share the 3ds file but here is what is happening. this is the definition of random.

Post 1 of 3.


#13

Post 2 of 3


#14

Post 3 of 3


#15

I’m no doubting it doesn’t happen - but if we had a sample model to reproduce in house we can investigate.


#16

You don’t need to post the original file (to retain the data for you, and to avoid overhead for us). It would be enough to extract the set of entities that reproduces the issue. Think in the direction of a “MCVE”.


#17

Sorry for the late reply, I was trying to recreate the issue without posting all the models within the project I don’t want to “give” away. I cant just post the items that seem to be the problem, it is RANDOM, look at the images, if I just import all those hanging light fixtures by themselves, they come in perfectly. It is when you import the entire project at once, which contains 470,000 faces all told. I did a massive array in 3dsmax to match the face count of a box with mapping and material, all came in perfectly into Sketchup so I could not send that. I then imported all individually by layer (I made separate 3ds files out of 3dsmax), imported them one at a time, all came in perfectly. It is simply baffling. Every single object can be imported with no problems BUT not at one time, Sketchup is messing with me.


#18

Does 3d Max have a COLLADA exporter? I know there is the OpenCOLLADA exporter for 3ds Max. The reason I suggest this is because SketchUp has a first-class COLLADA import.