Inkscape.org
Creating New Extensions extension to automate the creation of new layers from classes
  1. #1
    Eduardo Schilling Eduardo Schilling @elschilling
    TylerDurden

    As far as workflow goes: I'd select all in a class, then right-click and select "Move to..." (displays a menu of layers to select from). The selects objects can be in any layer prior to the move. I'm confident an extension could be made to automate this.

    I'm attempting to create an extension to automate the creation of new layers from classes containing a specific string, and them moving the group containing that class to the new layer. I've managed to get it working for simple demo files, but for larger files, it appears to create the layers correctly but inconsistently crashes. Sometimes it crashes right after the script execution ends, sometimes when trying to save the file, and occasionally it runs perfectly on Windows. Any help would be greatly appreciated.

    Video demonstrating the extension working and crashing

    Extension source code repository

     

  2. #2
    inklinea inklinea @inklinea⛰️

    I don't know how the original file causing is generated. 

    Is it possible the same class name could be duplicated on the element ? 

    <path class="class1 class1 class2".....

     

     

     

  3. #3
    Eduardo Schilling Eduardo Schilling @elschilling

    Hi @inklinea thanks for answering!

    The files were generated from BlenderBIM addon, that creates 2d svg drawings from an IFC 3d model and stores a bunch of information in the class attribute (including a unique Ifc(Class) for each group element.

    I've attached the 2 demo files working and 2 that are crashing.

    inklinea

    Is it possible the same class name could be duplicated on the element ? 

    No, each element gets only one IfcClass. Some elements have more than one class containing 'Ifc' like class="IfcWall ... material-327866IfcMaterialLayerSet327862327864327865poche" but the code is selecting only the first one:

    import inkex
    from inkex import Group
    
    def class2layer(svg):
        layer_list = []
        xpath_expr = "//*[contains(concat(' ', normalize-space(@class), ' '), ' Ifc')]"
        elements = svg.xpath(xpath_expr)
        for element in elements:
            classes = element.get('class').split()
            IfcClass = [string for string in classes if string.startswith('Ifc')][0]
            # inkex.utils.debug(IfcClass)
            if IfcClass not in layer_list:
                layer = svg.add(Group(id=IfcClass))
                layer.set('inkscape:groupmode', 'layer')
                layer.set('inkscape:label', IfcClass)
                layer_list.append(IfcClass)
            else:
                layer = svg.getElementById(IfcClass)
            layer.add(element)
            # inkex.utils.debug(IfcClass)
        return svg
    
    class CreateLayersFromClasses(inkex.EffectExtension):
        def effect(self):
            self.svg = class2layer(self.svg)
    
    if __name__ == '__main__':
        CreateLayersFromClasses().run()

    This is the Effect type extension that creates the layers and returns to the inkscape editor

    For some workflows, the goal is to directly export the svg to dxf with the layers information, so I created an Output extension that uses the same class2layer function above but is beeing called from the

    save instead of effect method. The output extension works perfectly both from GUI and CLI with all test files

    https://github.com/elschilling/class2layer/blob/master/ifc2layer2dxf.py

    Still couldn't find the pattern generating the crash behavior.

    My Storey Plan 2 Work
    My Storey Plan 1 Work
    Demo   Option 1 (Crash)
    Demo Plan (Crash)
  4. #4
    inklinea inklinea @inklinea⛰️

    I think the crash file Demo Option 1 has a complex css section that Inkscape cannot handle properly.

    However, also in this section there is a comment line, if you delete the comment line 

    /* [class*="surface"][class*="PsetCommon-StatusEXISTING"]{ fill: #c2ceda; stroke: #2C5573; stroke-width: 0.05px;} */

    The file seems to load - but does not display correctly

    [class*="PsetCommon-StatusNEW"] { fill: rgb(199, 199, 199); }
    [class*="PsetCommon-StatusEXISTING"] { fill: #5D6E7F; stroke: #2C5573; }
    /* [class*="surface"][class*="PsetCommon-StatusEXISTING"]{ fill: #c2ceda; stroke: #2C5573; stroke-width: 0.05px;} */
    [class*="PsetCommon-StatusEXISTINGDEMOLISH"], [class*="ODOptions-ODOption2D"] { fill: url(#demolish); stroke: red; stroke-dasharray: 2, 1; }
    [class*="IfcDoor"][class*="PsetCommon-StatusEXISTING"] {fill: none;}
    [class*="IfcDoor"][class*="PsetCommon-StatusNEW"] {fill: none;}
    [class*="PsetCommon-FireRating2HR"] { fill: url(#2HR); }

     

    Also this file seems to have a <style> block inside a <defs> block

    Is that the original file, or has it already been processed once by Inkscape ? it already contains inkscape and sodipodi tags.

    Do you have the original file ? 

     

  5. #5
    Eduardo Schilling Eduardo Schilling @elschilling
    inklinea

    Is that the original file, or has it already been processed once by Inkscape ? it already contains inkscape and sodipodi tags. Do you have the original file ? 

    The files are public available from http://openingdesign.com/. The extension ideia is from Ryan Schultz @Theoryshaw

    https://community.osarch.org/discussion/1942/an-inkscape-script-to-translate-svg-classes-to-svg-layers-for-ultimate-dxf-export-with-these-layers

    https://inkscape.org/forums/beyond/a-workflow-to-translate-or-map-certain-svg-classes-to-dxf-layers/

    I can open the files and despiste the fact that they display differently on inkscape and other viewers, I was focused on making the layers creation process work. After removing the styles and defs tags both files stopped crashing so you are right, probably the changes made after the BlenderBIM export corrupted the files in some way. @Theoryshaw do you have the original svg exported from BB for testing?

    Screenshot From 2024 02 06 21 18 38
    Screenshot From 2024 02 06 21 17 47
  6. #6
    Ryan Schultz Ryan Schultz @Theoryshaw
    *

    Thanks @elschilling for the ping. 

     

    Any the SVG's here, could work I guess...

    https://hub.openingdesign.com/OpeningDesign/Restaurant_Sun_Prairie/src/branch/main/Models/BlenderBIM/drawings

     

    Maybe specifically, maybe the following svgs... 

  7. #7
    inklinea inklinea @inklinea⛰️
    *

    I had a look at the original files on the website.

    I noticed a few things:

    The namespaces ns0 and ns1 appear. This is usually the case when Inkscape ( or some other program using etree ) cannot link the namespace prefix to the url or there are conflicts.

    The style section is wrapped in def, it should be outside.

    Some of the class names contain dollar signs. I don't believe xml (svg) ids should contain dollar signs, may cause random parsing errors later ? 

    I think it would require looking at BlenderBIM to get to the bottom of the problem. Or use 'slugfiy' on the class names as a start.

    edit: As another point, it's not actually necessary to return svg then assign the svg to self.svg as self.svg  has already been operated on in the function

  8. #8
    Eduardo Schilling Eduardo Schilling @elschilling

    Thanks @inklinea for spending time helping us.

    Inspecting each file involved in the BlenderBIM svg creation I found a pattern.svg containing a <sodipodi:namedview /> tag that when removed, generated a BlenderBIM drawing that when opened with Inkscape and running the extension doesn't crash anymore.

    The only bug that remains is when running from the CLI with the command: 

     

    ╰─± inkscape MY\ STOREY\ PLAN.svg --actions=effect.class2layer.noprefs                
    
    Emergency save activated!
    Emergency save completed. Inkscape will close now.
    If you can reproduce this crash, please file a bug at https://inkscape.org/report
    with a detailed description of the steps leading to the crash, so we can fix it.
    ** Message: 20:04:48.749: Error: 
     0# Inkscape::Application::crash_handler(int) in /usr/bin/../lib64/inkscape/libinkscape_base.so.1.3.2.0
     1# 0x00007F893625C9A0 in /lib64/libc.so.6
     2# Inkscape::Extension::ExecutionEnv::ExecutionEnv(Inkscape::Extension::Effect*, Inkscape::UI::View::View*, Inkscape::Extension::Implementation::ImplementationDocumentCache*, bool, bool) in /usr/bin/../lib64/inkscape/libinkscape_base.so.1.3.2.0
     3# Inkscape::Extension::Effect::effect(Inkscape::UI::View::View*) in /usr/bin/../lib64/inkscape/libinkscape_base.so.1.3.2.0
     4# 0x00007F89369FBC59 in /lib64/libgiomm-2.4.so.1
     5# g_closure_invoke in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
     6# 0x00007F893583F3A5 in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
     7# 0x00007F893582FD59 in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
     8# g_signal_emit_valist in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
     9# g_signal_emit in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
    10# 0x00007F8935D17815 in /usr/bin/../lib64/inkscape/../libgio-2.0.so.0
    11# InkscapeApplication::process_document(SPDocument*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) in /usr/bin/../lib64/inkscape/libinkscape_base.so.1.3.2.0
    12# InkscapeApplication::on_open(std::vector<Glib::RefPtr<Gio::File>, std::allocator<Glib::RefPtr<Gio::File> > > const&, Glib::ustring const&) in /usr/bin/../lib64/inkscape/libinkscape_base.so.1.3.2.0
    13# 0x00007F893699A194 in /lib64/libgiomm-2.4.so.1
    14# g_closure_invoke in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
    15# 0x00007F893583F3A5 in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
    16# 0x00007F893582FD59 in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
    17# g_signal_emit_valist in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
    18# g_signal_emit in /usr/bin/../lib64/inkscape/../libgobject-2.0.so.0
    19# 0x00007F8935D125E2 in /usr/bin/../lib64/inkscape/../libgio-2.0.so.0
    20# g_application_run in /usr/bin/../lib64/inkscape/../libgio-2.0.so.0
    21# main in inkscape
    22# 0x00007F893624614A in /lib64/libc.so.6
    23# __libc_start_main in /lib64/libc.so.6
    24# _start in inkscape
    [1]    5874 segmentation fault (core dumped)  inkscape MY\ STOREY\ PLAN.svg --actions=effect.class2layer.noprefs
    

    Maybe related to this known issue?

  9. #9
    inklinea inklinea @inklinea⛰️
    *

    Yes. 

    For historical context, when the Inkscape command line used to have verbs as well as actions.

    Verbs always required the gui to be triggered, either with the --with-gui option (which loads the gui), or with the --batch-process option (which opens and closes the gui in the background)

    When we moved to actions only in the newer versions of Inkscape, that workaround was not required.

    Except ---- in the case of extensions. 

    Extensions still require --batch-process if you want to use the .noprefs option.

    This means that they cannot be used headless, and cannot be used in the faster Inkscape --shell mode.

    Hence the crash.

Inkscape Inkscape.org Inkscape Forum Creating New Extensions extension to automate the creation of new layers from classes