Skip to content

Instantly share code, notes, and snippets.

@kohlerm
Last active March 20, 2024 17:10
Show Gist options
  • Save kohlerm/0337f7c64df42f21f96405b3f8e895f2 to your computer and use it in GitHub Desktop.
Save kohlerm/0337f7c64df42f21f96405b3f8e895f2 to your computer and use it in GitHub Desktop.
convex hull plugin inkscape
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<_name>ConvexHull</_name>
<id>org.simarilius.filter.ConvexHull</id>
<dependency type="executable" location="extensions">ConvexHull.py</dependency>
<dependency type="executable" location="extensions">inkex.py</dependency>
<effect needs-live-preview="false">
<object-type>all</object-type>
<effects-menu>
<submenu _name="Convex_Hull"/>
</effects-menu>
</effect>
<script>
<command reldir="extensions" interpreter="python">ConvexHull.py</command>
</script>
</inkscape-extension>
#!/usr/bin/env python
import inkex
import sys
import numpy as n
# for more power
import simpletransform
import cubicsuperpath
import simplepath
import simplestyle
import cspsubdiv
import bezmisc
link = lambda a,b: n.concatenate((a,b[1:]))
edge = lambda a,b: n.concatenate(([a],[b]))
# Python Q_hull routine from here; https://github.com/flengyel/REST/blob/master/quickhull.py
# See copyright disclaimer in original file.
def qhull(sample):
def dome(sample,base):
h, t = base
dists = n.dot(sample-h, n.dot(((0,-1),(1,0)),(t-h)))
outer = n.repeat(sample, dists>0, 0)
if len(outer):
pivot = sample[n.argmax(dists)]
return link(dome(outer, edge(h, pivot)),
dome(outer, edge(pivot, t)))
else:
return base
if len(sample) > 2:
axis = sample[:,0]
base = n.take(sample, [n.argmin(axis), n.argmax(axis)], 0)
return link(dome(sample, base),
dome(sample, base[::-1]))
else:
return sample
class TemplateEffect(inkex.Effect):
def __init__(self):
# Call base class construtor.
inkex.Effect.__init__(self)
self.paths = {}
self.paths_clone_transform = {}
def joinWithNode ( self, node, path, makeGroup=False, cloneTransform=None ):
if ( not path ) or ( len( path ) == 0 ):
return
g = self.document.getroot()
# Now make a <path> element which contains the twist & is a child
# of the new <g> element
style = { 'stroke': '#000000', 'fill': 'none', 'stroke-width': '1' }
line_attribs = { 'style':simplestyle.formatStyle( style ), 'd': path }
if ( cloneTransform != None ) and ( cloneTransform != '' ):
line_attribs['transform'] = cloneTransform
inkex.etree.SubElement( g, inkex.addNS( 'path', 'svg' ), line_attribs )
def effect(self):
global output_nodes, points
#Loop through all the selected items in Inkscape
for node in self.selected.values():
#create numpy array of nodes
n_array = []
#Iterate through all the selected objects in Inkscape
for node in self.selected.values():
#Check if the node is a path ( "svg:path" node in XML )
#id = node.id
if node.tag == inkex.addNS('path','svg'):
# bake (or fuse) transform
simpletransform.fuseTransform(node)
#turn into cubicsuperpath
d = node.get('d')
p = cubicsuperpath.parsePath(d)
for subpath in p: # there may be several paths joined together (e.g. holes)
for csp in subpath: # groups of three to handle control points.
# just the points no control points (handles)
n_array.append(csp[1][0])
n_array.append(csp[1][1])
k = n.asarray(n_array)
length = int(len(k)/2)
c = k.reshape(length,2)
hull_pts = qhull(c)
pdata = ''
for vertex in hull_pts:
if pdata == '':
pdata = 'M%f,%f' % ( vertex[0], vertex[1] )
else:
pdata += 'L %f,%f' % ( vertex[0], vertex[1] )
pdata += ' Z'
path = 'polygon'
makeGroup = False
paths_clone_transform = None
self.joinWithNode( path, pdata, makeGroup, paths_clone_transform )
# Create effect instance and apply it.
effect = TemplateEffect()
effect.affect()
@gabrieldelaparra
Copy link

gabrieldelaparra commented Apr 29, 2023

Hi hi, thanks for sharing this extensions.
I am new to inkscape, and tried adding it to my extensions folder, but I get the following message:
ImportWarning: DynamicImporter.exec_module() not found; falling back to load_module()
Do you know if this might be related to a version change?
Or maybe better, could you please provide some instruction on how to add/use this in inkscape?

@Foxxey
Copy link

Foxxey commented Mar 20, 2024

As far as I can tell this code is copied from an old forum post on Inkscape back in 2013: https://alpha.inkscape.org/vectors/www.inkscapeforum.com/viewtopiccf3d.html?t=13622#p52785
It is reasonable to assume that it wouldn't work today. It doesn't work for me at least when I click on Extensions->ConvexHull->ConvexHull with the appropriate path elements selected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment