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.
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.
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
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 ?
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?
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
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
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.
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
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".....
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.
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:
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 ofeffect
method. The output extension works perfectly both from GUI and CLI with all test fileshttps://github.com/elschilling/class2layer/blob/master/ifc2layer2dxf.py
Still couldn't find the pattern generating the crash behavior.
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 ?
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?
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...
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
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:
Maybe related to this known issue?
Yes.
For historical context, when the Inkscape command line used to have
verbs
as well asactions
.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.