spakin / SimpInkScr

Simple Inkscape Scripting
https://inkscape.org/~pakin/%E2%98%85simple-inkscape-scripting
GNU General Public License v3.0
320 stars 31 forks source link

Is there a way to Union? #60

Closed williamsokol closed 1 year ago

williamsokol commented 1 year ago

Hi, I was trying to union 2 rect's with this extension and I don't see any command for that.

I know I can do it manually selecting both objects and going Path->union. Is that something we can do with the extension right now?

spakin commented 1 year ago

Unfortunately, the inkex library, on which Simple Inkscape Scripting is based, does not provide a path-union function. Fortunately, there is an alternative: the non-destructive Boolean live path effect (PathPath Effects…Boolean operation in the Inkscape GUI).

It takes quite a bit of code to instantiate a non-destructive Boolean live path effect, but at least it can be done:

# Define a filter to make the target of the Boolean union invisible.  As
# far as I can tell, this *has* to have the ID "selectable_hidder_filter".
invisible = filter_effect(name='Visibility',
                          pt1=(-0.005, -0.005),
                          pt2=(1.005, 1.005),
                          color_interpolation_filters='sRGB')
invisible.add('Composite',
              src1='BackgroundImage',
              src2='SourceGraphic',
              operator='arithmetic')
invisible.get_inkex_object().set_id('selectable_hidder_filter')

# Create the target object, marking it invisible.
b = rect((50, 50), (150, 150),
         stroke='black',
         fill='cyan',
         filter=invisible)

# Instantiate a live path effect for Boolean union.  We use keyword
# arguments to preserve hyphens in key names.
b_ref = '#' + b.get_inkex_object().get_id()
union_args = {
    'operation': 'union',
    'operand-path': b_ref,
}
union = path_effect('bool_op', **union_args)

# Create the source object (which must be a path) and apply the live path
# effect to it.
a = rect((0, 0), (100, 100),
         stroke='black',
         fill='green').to_path()
a.apply_path_effect(union)

I hope you find that helpful.

williamsokol commented 1 year ago

Thank you very much! I was looking for a way to do this and was going down the route of using inkex.command.inkscape to call a union from the command line. It was looking impossible.

I can turn this code into a function and It will act effectively the same as a traditional union. Awesome

williamsokol commented 1 year ago

After working with it some, It seems like you cannot union multiple shapes together with the live path effect. If one is unioned the others will break off.

spakin commented 1 year ago

I just did a quick test in the Inkscape GUI, and I was able to union multiple shapes by chaining the Boolean operation. That is, I assigned a Boolean-union path effect to object A, pointing to object B. Then, I assigned a Boolean-union path effect to object B, pointing to object C. And likewise for a few more objects. Although I haven't yet tried this with Simple Inkscape Scripting, there's at least some hope you may be able to union multiple shapes together programmatically.