Last active
March 20, 2024 17:10
-
-
Save kohlerm/0337f7c64df42f21f96405b3f8e895f2 to your computer and use it in GitHub Desktop.
convex hull plugin inkscape
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() | |
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
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?