Any way to speed up adding faces and edges?

I am creating an importer. I use entities.add_face and entities.add_edge to import a model, but they are much time-consuming.

54234 faces spend 11 seconds for add_face
85417 edges spend 9 seconds for add_edge

It is a simple model though. For complex models, the time to create faces and edges is too long to be acceptable. How can I speed it up? Thanks.

Did you create an undo operation and switch off the UI during the operation ?

Have you looked at creating a virtual polymesh …

… and afterward adding it within an operation ?

4 Likes

A long time ago, I wrote a plugin that imported/exported data for a few external applications. I also updated it a few years ago.

I always used start_operation/commit_operation, and I tried all sorts of things.

Bottom line, the first 200 faces are added much quicker that adding the same after importing 10k faces.

start_operation/commit_operation is a given, but SU must still be performing some checks, and the checks slow down as the number of entities grows.

Normal users of the plugin were modeling reasonably sized spaces, normally houses of worship.

The ‘special users’ were modeling the largest houses of worship, and also large transportation spaces, like the largest airport terminals, train stations, etc. These models had a lot of faces.

I implemented a rather crazy fiber based progress bar, and it was a waste of time because the faces vs time curve was so nonlinear…

The import code pulled in metadata from the external apps, so I couldn’t use PolygonMesh…

I tried polygonmesh. It was much faster than add_face. However, I was stumped by material. PolygonMesh could not apply material in individual face, here is a clear explanation. . I am wondering if it is possible to add material to faces after Entities#fill_from_mesh.

What is the common approach to make an importer/exporter for Sketchup models? I exported a model with its entities and imported it - restoring entities by add_face, add_edges, add_group, etc. It seems inefficient, especially for complex models. What is the correct approach to implement export/import functionality?

Exported to and imported from what file format ?

At the moment Geom::PolygonMesh is the fastest way to create bulk geometry. It has however it’s own limitations. Recently we improved further the performance of PolygonMesh. See related forum post: Using PolygonMesh? Read this to ensure best performance - Developers / Developer Announcements - SketchUp Community

1 Like

Because you needed more control of per-face and per-edge properties? (Such as adding attributes?)

Correct depends. Since PolygonMesh makes it hard to control material and properties per-face/per-edge add_edge and add_face might be your only option even though it’s slow.

For the open source STL importer PolygonMesh is used - however that data format is very simple and doesn’t carry material information.

sketchup-stl/importer.rb at master · SketchUp/sketchup-stl (github.com)

As a side-note, I have in my own extension been able to use PolygonMesh and entities.fill_from_mesh and relying that the order I’m able to iterate faces is the same as the order of mesh.add_polygon. However, note that this is relying on internal implementation detail and is not part of the API contract. And in some cases if the polygons you try to create are too small they will silently be ignored, and then you don’t have a 1:1 mapping to rely on.

1 Like

Yes.

JFYI, I think I experimented with adding one or more faces to the model separate from the existing model, then after some pre-defined qty of faces were added, I moved them into the correct position. Have to see if I left that in my code or not, as I wouldn’t have kept it if it didn’t speed things up…

Thinking out loud here, but the fact that PolygonMesh.add_point is now highly optimized could help you.

If you use entities.fill_from_mesh(polygon_mesh.. and then extract a random vertex from the resulting geometry you can use PolygonMesh.add_point(vertex.position) to get the point’s index in the Polygon Mesh, so you have a rather quick link from the Sketchup geometry to the abstract representation in the Polygon Mesh which means that the pairing between faces in the Polygon Mesh with faces in Sketchup should be feasible from a performance standpoint.

Of course, relying on order as @tt_su mentions is way faster, but if you get out of synch you’re doomed.

And that is also only relevant if you are able to recover from being unable to create small faces. For instance if your extension tries to create manifolds then it’d be game over anyway.

A custom format including json and binary files for vertices and uvs.

Okay, are you using Ruby’s JSON library to read the data directly into a Ruby Hash ?

My point would be that the JSON library parser and generator are compiled C, so should be faster than writing a read file loop in Ruby.

I tried entities.fill_from_mesh again. But PolygonMesh::set_uv applies uv to points one by one. Is it possible to apply uv array to point array?

Yes, I read a file and use JSON.parse to get Ruby Hash:

json_str = File.read filename
hash_data = JSON.parse(json_str)
1 Like

It needs to be to an index array. You can use a refinement to add methods for only your extension.

module HenryNamspace
  module ImporterExtensionName

    module RefinedPolygonMesh

      refine ::Geom::PolygonMesh do

        def set_uvs(indices, uvs, front = true)
          indices.each_with_index do |point_index, index|
            self.set_uv(point_index, uvs[index], front)
          end
        end

      end # class refinement

    end # refinement module

    using RefinedPolygonMesh

    # Code or methods that use the refinement method ...

  end # extension submodule
end # top level namespace module

EDITED to allow for indices and uvs that are not listed in index order.