Wait for model to print pdf

I am writing a simple plugin that plots every layer separately into a pdf file - architects then use those for vector postprocessing. Essentially it is a simple loop, and it works perfectly on a simple model, but on a heavy model
it looks like it plots pdf before the view is updated, or something, resulting in empty or semi-empty pdfs…
I obviously can hard-code some wait time, but what would be the best way to guarantee the proper result?
(I am quite new to rubi and skp api so general code-wise suggestions are also welcome!)

 visible.each do |lname|
    	
    	layers.each do |l|
    		current = l.name == lname
    		l.visible = current
    		if(current)
    			model.active_layer = l
    		end
    	end

    	path = dirname + "/#{lname}.pdf"
    	status = model.export(path, options_hash)
    	count = count + 1
    	
    end

It sounds like the issue is that refreshing the view is asynchronous, and when you change the visibility of a lot of layers the pdf export starts before the refresh has completed. Ruby generally blocks the main SketchUp engine while it runs, and this makes it hard to assure completion of a side-effect such as redrawing the view before Ruby proceeds. You might try a View#refresh to force an immediate redraw, but be wary of the warnings about possible crashes in the API docs. Calling View#invalidate won’t help, as it just schedules the view for a redraw, it does not assure when that redraw will happen.

Here are a couple of ideas to speed up the crucial block of your code. They may or may not actually help with the issue (I don’t have a model on hand with enough layers to check).

  • Don’t bother setting the model’s active_layer. It only affects what will be used by default for adding new geometry (same as checking the box at the left in the layers inspector window). It has no effect on what’s visible in the view. It’s a user GUI thing that is irrelevant to what you are doing.
  • Try setting all layers visible to false before the start of your loop over the visible Array and adding a variable for last_layer initialized to nil (you could save the state of each layer and restore them when finished so that the user’s view isn’t altered). In the visible loop, simply fetch the current target layer by name (Layers#[ ]) instead of looping over all layers, which takes time. Save the prior layer in last_layer and turn off its visibility in the next pass.

Edit: another thought:

While turning off visibility of the layers, you could save the index into the Layers collection for each one in the visible array. Then use that index instead of the name when retrieving them in the loop. Retrieval by index is much faster than by name because there is no string compare required.

1 Like

you need to be careful of control layers…

for example in an ifc import I need to leave some layers on to see the others…

model  = Sketchup.active_model
lays = model.layers
@view  = model.active_view

def layer_pdf(name)
	Sketchup.active_model.export("/tmp/layers/#{name}.pdf") 
   true
end

def off(l)
p l.name
 l.visible = false
end

def on(l)
  l.visible = true
  @view.refresh
  layer_pdf(l.name)
  sleep 1
  off(l)
end

lays.each do |l|
  next if l.name =~ /Layer0/
  next if l.name =~ /BuildingStorey/
  off(l)
end

lays.each do |l|
  next if l.name =~ /Layer0/
  next if l.name =~ /BuildingStorey/
  on(l)
end

layer_pdfs

john