Import Sketchup scenes to Layout Ruby API

Hi everyone! How can I import my Sketchup scenes to Layout with Ruby Api? I need to put some scenes to my Layout document and I don’t know how.

Within LayOut, go to File then Insert. Find and select the skp model that you would like to use.
Within SketchUp, go to File then Send to LayOut… Once in LayOut select the template that you would like to use. Select the desired scene for each viewport with the SketchUp Model tray in Layout.

(To my knowledge, LayOut Ruby API is not useful yet and/or not in common enough use.)

The LayOut API is not for controlling the LayOut application (functions, user interface, import), but currently only for editing LayOut files (.layout) from within SketchUp. The Ruby API is (currently) located within SketchUp.

It hasn’t been used a lot, so you won’t find many people with experience with it. But the general procedure is to open SketchUp → Window → Ruby Console (or Ruby Console+), and load the layout document.

I would expect you can use it somewhat similar to this:

# Get a reference to your current (saved) SketchUp model:
model = Sketchup.active_model
# Open your LayOut file.
doc = Layout::Document.open("C:/path/to/document.layout")
# Create an instance of the model in LayOut (model.path should contain the file path of the saved .skp)
bounds = Geom::Bounds2d.new(1, 1, 3, 3)
layout_model = Layout::SketchUpModel.new(model.path, bounds)
# Add the model to the first layer on the first page
doc.add_entity(layout_model , doc.layers.first, doc.pages.first)
# Select the same scene as in SketchUp and render a view of the model
current_sketchup_scene = model.pages.selected_page
current_sketchup_scene_index = model.pages.index(current_sketchup_scene)
layout_model.current_scene = current_sketchup_scene_index 
layout_model.render

Just for a general FYI, … the SketchUp Extensibility Team has an example extension that does this automatically. (It is a compiled C extension, but stills does what the OP asked but creates a new LayOut file. The OP seems be be asking to import model scenes as new viewports into an existing .layout file. The extension example linked below will not do this)

https://extensions.sketchup.com/en/content/create-layout-file

Hi! thanks for your help but this code gets me an error in the line:
current_sketchup_scene_index = model.pages.index(current_sketchup_scene)
Error:
Error: #<NoMethodError: undefined method index' for #<Sketchup::Pages:0x00015396a34ce8>>

I think the class ‘Pages’ from module ‘Sketchup’ doesn’t have any method called ‘index’. Anyway I have tried to put the index manually and it doesn’t work still.
On the other hand, the method ‘render’ doesn’t seem to work. When I use ‘render’ should I get the view of Sketchup in the layout document?

Thanks

As it seems, index is from Ruby Array, not Enumerable (which SketchUp classes mix-in). If you convert the enumerable pages collection into an array with to_a, does it work then?

Yes, it seems the problem of index is solved, but I don’t understand the function ‘render’, it doesn’t seem to work.
When I use ‘render’ should I get the view of Sketchup in the layout document?
I open an empty Layout file (I tried to create it from the option “Send to Layout” or just creating an empty Layout file from the Layout app), then I render from Sketchup (with all that code you sent me) and it does nothing…

Me neither, and I don’t have any experience with it yet. @adam

The current LayOut API is not a “live” application API. It is a file object API. You are modifying a file in memory and saving it to storage (which you have to do with a Layout::Document#save API call.)

I don’t think you can modify a .layout file that is already open for edit in the LayOut application.

[Ie, the operating system will put file lock on the file and it can only be opened as read only by other application processes.]

So do what you do to the file, THEN load it into LayOut manually.

(There is no methods yet defined for the Layout module, so no way to yet control a “live” LayOut application process. They’re working on it. Might be a year or two before it becomes a “live” API.)

EDIT: Actually it appears there is, but it must be done from Sketchup and it’s API …

However it is unclear what happens if LayOut is already open, or an attempt is made to reload the same .layout file that is already open for edit in the LayOut application.

I guess you’ll need to experiment.

Actually, I remembered that @adam weighed in on this issue and that they specifically raise an error if trying to save if the same file is open in LayOut … read more

The Layout::SketchUpModel#render method is used to update the raster, vector, or hybrid data of the SketchUp model reference in a LayOut document. You would use this method any time that you change something about the model reference (render mode, size, scene, etc).

If you want to see the SketchUp model in a LayOut document, you have to add it using Layout::Document#add_entity.

Just to be clear, when you create a LayOut file with these methods, you need to save and close the document prior to opening it in the API with Layout::Document.open. You would then retrieve your Layout::SketchUpModel entity from that document object to update it. Then save the document again with Layout::Document#save and open it again in LayOut.

Hope that helps,
Adam

3 Likes

It would be nice if these words of wisdom were included in the API documentation.


Why does the Layout::SketchUpModel class not have a path getter or setter ?

If we had a SketchUp extension that started with an empty model, and the extension accessed a .layout file, and wished to open a SKP model (for edit in SketchUp) from a LayOut viewport, how could we do this ?

How could the extension open the model object and apply changes using the SketchUp Ruby API, save it, and then rerender the viewports in the .layout file and save it ?

(I do not see a way to get a reference to the actual SKP model nor a path to it on disk.)

We are still in the process of determining how to best expose this functionality in the future. However, these methods would likely not reside on Layout::SketchUpModel anyways as there could be many references to the same model.

You would need to open the SketchUp model in SketchUp somehow so that your extension could access the Sketchup.active_model object.

No, you can’t get a reference to the Ruby SketchUp model object. This is complicated due to the fact that the SketchUp Ruby API operates on the active model, which in your case would be the empty model you started in.

If you can work with the C API, you can get an SUModelRef from an LOSketchUpModelRef with the LOSketchUpModelGetModel method and proceed from there. Actually, you could probably then use SUModelGetPath to retrieve the file path of the model. Note that the path may end up pointing to the internal LayOut copy if the external .skip file can’t be found.

Adam

This is the point of my questions above.

I know, but the reason I said empty was because it should be obvious that we would want to do a Sketchup::open_file() making the LayOut viewport file the active model within SketchUp.

(In other words … I wanted to remove the complexity of there being an open model in SketchUp that might need saving.)

I really hate C myself and always have. Too much low level memory manipulation.

So really we have no API parity in this regard. (Yet.)

BRAINSTORMING:

Perhaps a Layout::Document.models enumerable collection with getters, filters, iterators, Etc. ?

I think what throws me off given the one to many relation, is that the class name y’all chose was Layout::SketchUpModel. It is confusing.
It might make more sense if it was named Layout::ModelViewport.
(Because as it really is not a model it now makes it more confusing when you have to add a reference model class to the API.)

It is likely that any particular instance would NOT be added multiple times (with the same 2D bounds, current scene, scale and style) to different places (pages) in the same LayOut document.

But multiple viewports, each using a different scene (and possible style) but each using the same internal copy of a Layout::ModelReference class. (Along with perhaps other viewports that use other reference models loaded into the document.)

Anyway, let say that code identifies a viewport whose model we wish to edit.

Rhetorical: How would we (in the future) ask a document’s collection of model references for the path of the one used by a specific Layout::ModelViewport (ie, currently called Layout::SketchUpModel) instance ?

Perhaps (following my above logic,) we ask the viewport (whatever it is called) for it’s Layout::ModelReference object (which points at a member of the Document’s LayOut::ModelReferences collection,) and from that instance object use a #path getter (and perhaps setter) and it could have query methods such as #internal? if an external path was no longer valid.

Each Layout::ModelReference object has a collection of viewport references that render one of it’s scenes.

It might be nice to have a #write method to save out an internal model to an SKP (unless original author locked it.) This in the case where only a .layout file was given or sent to someone else.

So, one thing I’m getting at the likely scenario of class and object relations I brainstorm, shows how the current class name Layout::SketchUpModel doesn’t really make sense because it is not actually a SketchUp model.
If you don’t like Layout::ModelViewport even Layout::ModelScene makes more sense.

1 Like

What I was trying to say is that this is a gap in the current APIs; there currently is no way to get the correct model open in SketchUp to make modifications to it through the API.

Correct. I would love to be able to do this, but there are technical difficulties that must be addressed for it to be possible.

We will probably need to expose the File Reference Manager and various File Reference classes (SketchUp Model, Image, RTF Text, Table). Individual objects (Layout::SketchUpModel, Layout::FormattedText, etc.) will then provide access to their file reference. A Layout::FileReference would provide the external path, whether the reference is embedded, and unlink/relink methods. It would also be nice if you could create a new Layout::SketchUpModel by providing the Layout::SkpFileReference rather than the path to the .skp.

I don’t see us allowing an embedded .skp to be saved externally directly. You would still be able to open an embedded .skp file in SketchUp anyways.

I agree in hindsight that we would have been better off naming it Layout::SkpModelViewport or something similar. However, I believe we are past the point of no return on that subject.

Adam

1 Like

Not really. Ruby doesn’t care how many identifiers a class object has.

Within the Layout module simply the following will alias an existing class …

SkpModelViewport = SketchUpModel

or … redefine the “base” class identifier as SkpModelViewport
… and then create a (deprecated) alias for backward compatibility …

SketchUpModel = SkpModelViewport

I don’t think there is very many LayOut Ruby API extensions to upset if you change the classnames for the better. But it needs to be done now before many more do begin using the LO API.

A rule to create a deprecated warning can be added to SURubocop to remind coders to use the newer better identifier.

Yes, but I also must consider the C API. If I make this change in the Ruby API, then there will be an inconsistency between the two LayOut APIs. If I want to make the change to the C API as well, that requires me to duplicate all of the LOSketchUpModel* methods and rename them LOSkpModelViewport, and have a duplicate header file. In the end, I feel that the result would not be worth the effort.

Adam