added spirograph extension, fix in vpypetools, adjusted polyhedra, some changes in styles to layers
This commit is contained in:
parent
5d87b2cd13
commit
6d27ef1a30
@ -1,18 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Animate Order - Kopfteil-Laser.svg</title>
|
||||
<meta name="description" content="SVG Drawing Animation">
|
||||
</head>
|
||||
<body>
|
||||
<button onclick="vi.reset().play();">replay</button>
|
||||
<br/>
|
||||
<object id="animate_order" type="image/svg+xml" data="drawing.svg"></object>
|
||||
<script src="./vivus-0.4.6/dist/vivus.js"></script>
|
||||
<script>
|
||||
var vi = new Vivus('animate_order', {type: 'oneByOne', duration:7200.0, reverseStack:false});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 504 KiB |
1307
extensions/fablabchemnitz/inkscapeMadeEasy/inkscapeMadeEasy_Base.py
Normal file
1307
extensions/fablabchemnitz/inkscapeMadeEasy/inkscapeMadeEasy_Base.py
Normal file
File diff suppressed because it is too large
Load Diff
2231
extensions/fablabchemnitz/inkscapeMadeEasy/inkscapeMadeEasy_Draw.py
Normal file
2231
extensions/fablabchemnitz/inkscapeMadeEasy/inkscapeMadeEasy_Draw.py
Normal file
File diff suppressed because it is too large
Load Diff
1632
extensions/fablabchemnitz/inkscapeMadeEasy/inkscapeMadeEasy_Plot.py
Normal file
1632
extensions/fablabchemnitz/inkscapeMadeEasy/inkscapeMadeEasy_Plot.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -150,9 +150,9 @@ class Polyhedra(inkex.EffectExtension):
|
||||
gsub_attribs = {inkex.addNS('label','inkscape'):'Polygon ' + str( poly ) + 'border' }
|
||||
gsub = etree.SubElement(g, 'g', gsub_attribs)
|
||||
|
||||
# Create SVG Path for gear
|
||||
cutStyle = { 'stroke': '#0000FF', 'fill': 'none' }
|
||||
perfStyle = { 'stroke': '#FF0000', 'fill': 'none' }
|
||||
# Create SVG Path
|
||||
cutStyle = { 'stroke': '#0000FF', 'stroke-width': '1px', 'fill': 'none' }
|
||||
perfStyle = { 'stroke': '#FF0000', 'stroke-width': '1px', 'fill': 'none' }
|
||||
textStyle = {
|
||||
'font-size': str( size/4 ),
|
||||
'font-family': 'arial',
|
||||
|
34
extensions/fablabchemnitz/spirograph.inx
Normal file
34
extensions/fablabchemnitz/spirograph.inx
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>SpiroGraph</name>
|
||||
<id>fablabchemnitz.de.spirograph</id>
|
||||
<param name="tab" type="notebook">
|
||||
<page name="Cartesian plot" appearance="minimal" gui-text="Data">
|
||||
<param name="curveType" type="optiongroup" appearance="combo" gui-text="Curve type:">
|
||||
<option value="Epitrochoid">Epitrochoid</option>
|
||||
<option value="Hypotrochoid">Hypotrochoid</option>
|
||||
</param>
|
||||
<label appearance="header">Curve parameters</label>
|
||||
<param name="radius_R" type="int" min="0" max="1000" gui-text="Fixed circle radius (R):">10.0</param>
|
||||
<param name="radius_r" type="int" min="-1000" max="1000" gui-text="Rolling circle radius (r):">5.0</param>
|
||||
<param name="pencil_distance" type="int" min="-1000" max="1000" gui-text="Pencil distance¹ (d):">2</param>
|
||||
<label>¹ use d=r for Epi/Hypocycloid. </label>
|
||||
<label appearance="header">Plot parameters</label>
|
||||
<param name="detailLevel" type="int" min="1" max="10" gui-text="Detail level:">1.0</param>
|
||||
<param name="drawBaseCircles" type="bool" gui-text="Draw base circles">false</param>
|
||||
<param name="animate" type="bool" gui-text="Animate">false</param>
|
||||
<param type="path" name="directory" gui-text="Animation directory:" mode="folder"/>
|
||||
</page>
|
||||
</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu name="FabLab Chemnitz">
|
||||
<submenu name="Shape/Pattern from Generator"/>
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
<command location="inx" interpreter="python">spirograph.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
251
extensions/fablabchemnitz/spirograph.py
Normal file
251
extensions/fablabchemnitz/spirograph.py
Normal file
@ -0,0 +1,251 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import math
|
||||
import os
|
||||
import numpy as np
|
||||
import scipy.signal as scipySignal
|
||||
|
||||
import inkscapeMadeEasy.inkscapeMadeEasy_Base as inkBase
|
||||
import inkscapeMadeEasy.inkscapeMadeEasy_Draw as inkDraw
|
||||
import inkscapeMadeEasy.inkscapeMadeEasy_Plot as inkPlot
|
||||
|
||||
|
||||
# least common multiplier
|
||||
def myLcm(x, y):
|
||||
return x * y / math.gcd(int(x), int(y))
|
||||
|
||||
|
||||
# ---------------------------------------------
|
||||
# noinspection PyAttributeOutsideInit
|
||||
class Spirograph(inkBase.inkscapeMadeEasy):
|
||||
def __init__(self):
|
||||
inkBase.inkscapeMadeEasy.__init__(self)
|
||||
|
||||
self.arg_parser.add_argument("--tab", type=str, dest="tab", default="object")
|
||||
self.arg_parser.add_argument("--curveType", type=str, dest="curveType", default='resistor')
|
||||
self.arg_parser.add_argument("--radius_R", type=float, dest="radius_R", default=10.0)
|
||||
self.arg_parser.add_argument("--radius_r", type=float, dest="radius_r", default=5.0)
|
||||
self.arg_parser.add_argument("--detailLevel", type=float, dest="detailLevel", default=1.0)
|
||||
self.arg_parser.add_argument("--adaptiveTheta", type=self.bool, dest="adaptiveTheta", default=False)
|
||||
self.arg_parser.add_argument("--pencil_distance", type=float, dest="pencil_distance", default=1.0)
|
||||
self.arg_parser.add_argument("--drawBaseCircles", type=self.bool, dest="drawBaseCircles", default=False)
|
||||
self.arg_parser.add_argument("--animate", type=self.bool, dest="animate", default=False)
|
||||
self.arg_parser.add_argument("--directory", type=str, dest="directory", default='./')
|
||||
|
||||
def effect(self):
|
||||
so = self.options
|
||||
|
||||
# sets the position to the viewport center, round to next 10.
|
||||
position = [self.svg.namedview.center[0], self.svg.namedview.center[1]]
|
||||
position[0] = int(math.ceil(position[0] / 10.0)) * 10
|
||||
position[1] = int(math.ceil(position[1] / 10.0)) * 10
|
||||
|
||||
root_layer = self.document.getroot()
|
||||
group = self.createGroup(root_layer, 'Spiro')
|
||||
|
||||
so.tab = so.tab.replace('"', '') # removes de exceeding double quotes from the string
|
||||
|
||||
# curve parameters
|
||||
R = so.radius_R
|
||||
r = so.radius_r
|
||||
d = so.pencil_distance
|
||||
finalTheta = 2 * np.pi * myLcm(abs(r), R) / R
|
||||
|
||||
if 'hypo' in so.curveType.lower():
|
||||
typeCurve = 'hypo'
|
||||
if 'epi' in so.curveType.lower():
|
||||
typeCurve = 'epi'
|
||||
|
||||
# markers and linestyles
|
||||
Lgray = inkDraw.color.gray(0.8)
|
||||
Dgray = inkDraw.color.gray(0.3)
|
||||
# wheel
|
||||
markerCenterDisk = inkDraw.marker.createDotMarker(self, nameID='diskCenter', scale=0.3, RenameMode=1, strokeColor=Dgray,
|
||||
fillColor=inkDraw.color.defined('white'))
|
||||
markerPen = inkDraw.marker.createDotMarker(self, nameID='diskPen', scale=0.3, RenameMode=1, strokeColor=Dgray,
|
||||
fillColor=inkDraw.color.defined('white'))
|
||||
[startArrowMarker, endArrowMarker] = inkDraw.marker.createArrow1Marker(self, nameID='arrowRot', RenameMode=1, scale=0.3, strokeColor=Dgray,
|
||||
fillColor=Dgray)
|
||||
|
||||
if typeCurve == 'hypo':
|
||||
self.lineStyleArrow = inkDraw.lineStyle.set(lineWidth=r / 40, lineColor=Dgray, markerStart=startArrowMarker, markerEnd=None)
|
||||
else:
|
||||
self.lineStyleArrow = inkDraw.lineStyle.set(lineWidth=r / 40, lineColor=Dgray, markerStart=None, markerEnd=endArrowMarker)
|
||||
|
||||
self.lineStyleARM = inkDraw.lineStyle.set(lineWidth=r / 40, lineColor=Dgray, markerStart=markerCenterDisk, markerEnd=markerPen)
|
||||
self.lineStyleDisk = inkDraw.lineStyle.set(lineWidth=r / 40, lineColor=None, fillColor=Lgray)
|
||||
|
||||
# curve
|
||||
self.lineStyleCurve = inkDraw.lineStyle.set(lineWidth=0.8, lineColor=inkDraw.color.defined('red'), markerStart=None, markerEnd=None,
|
||||
markerMid=None)
|
||||
self.lineStyleCurve2 = inkDraw.lineStyle.set(lineWidth=0.8, lineColor=inkDraw.color.defined('Dgreen'), markerStart=None, markerEnd=None,
|
||||
markerMid=None)
|
||||
self.lineStyleCurve3 = inkDraw.lineStyle.set(lineWidth=0.8, lineColor=inkDraw.color.defined('blue'), markerStart=None, markerEnd=None,
|
||||
markerMid=None)
|
||||
|
||||
self.lineStylePre = inkDraw.lineStyle.set(lineWidth=1, lineColor=inkDraw.color.defined('red'))
|
||||
self.constructionLine = inkDraw.lineStyle.set(lineWidth=0.5, lineColor=Dgray)
|
||||
|
||||
# draft Points
|
||||
if so.adaptiveTheta:
|
||||
nPrePoints = 10 * so.detailLevel # number of pre points per turn
|
||||
thetasDraft = np.linspace(0, finalTheta, int(nPrePoints * finalTheta / (2 * np.pi)))
|
||||
|
||||
[pointsDraft, _, curvatureDraft] = self.calcCurve__trochoid(typeCurve, R, r, d, thetasDraft)
|
||||
|
||||
# find sampling points based on local curvature
|
||||
nSamples = np.ones(curvatureDraft.shape)*min(2,so.detailLevel)
|
||||
detailFactor=5
|
||||
# treshold normalized curvatures
|
||||
nSamples[curvatureDraft>0.8] *=detailFactor
|
||||
detailFactor = 2.5
|
||||
# check if vector changed direction abuptly
|
||||
for i,p in enumerate(pointsDraft):
|
||||
if i==0:
|
||||
v1=pointsDraft[i+1]-pointsDraft[i]
|
||||
v2=pointsDraft[i]-pointsDraft[-1]
|
||||
elif i < len(pointsDraft)-1:
|
||||
v1=pointsDraft[i+1]-pointsDraft[i]
|
||||
v2=pointsDraft[i]-pointsDraft[i-1]
|
||||
else:
|
||||
v1=pointsDraft[0]-pointsDraft[i]
|
||||
v2=pointsDraft[i]-pointsDraft[i-1]
|
||||
|
||||
v1=v1/np.linalg.norm(v1)
|
||||
v2=v2/np.linalg.norm(v2)
|
||||
if np.dot(v1,v2)<0.5:
|
||||
nSamples[i] *=detailFactor
|
||||
|
||||
thetasFinal = np.array([])
|
||||
for i in range(len(nSamples) - 1):
|
||||
thetasFinal = np.append(thetasFinal, np.linspace(thetasDraft[i], thetasDraft[i + 1], int(nSamples[i]), endpoint=False))
|
||||
|
||||
thetasFinal = np.append(thetasFinal, finalTheta)
|
||||
# filter the sampled angles to have a smooth transition.
|
||||
Ntaps = 5
|
||||
gaussWindow = scipySignal.gaussian(Ntaps, std=5)
|
||||
gaussWindow = gaussWindow / np.sum(gaussWindow)
|
||||
|
||||
# inkPlot.plot.cartesian(self, root_layer, np.arange(thetasFinal.shape[0]), thetasFinal * 180 / np.pi, position, xTicks=False, yTicks=True, xTickStep=thetasFinal.shape[0]/10, yTickStep=120.0, xScale=10, yScale=10,xGrid=True, yGrid=True, forceXlim=None, forceYlim=None)
|
||||
thetasFinal = scipySignal.filtfilt(gaussWindow, np.array([1]), thetasFinal)
|
||||
|
||||
# inkPlot.plot.cartesian(self, root_layer, np.arange(thetasFinal.shape[0]), thetasFinal * 180 / np.pi, position, xTicks=False, yTicks=True,xTickStep=thetasFinal.shape[0]/10, yTickStep=120.0, xScale=10, yScale=10, xGrid=True, yGrid=True, forceXlim=None, forceYlim=None,drawAxis=False)
|
||||
else:
|
||||
nPrePoints = 20 * so.detailLevel # number of pre points per turn
|
||||
thetasFinal = np.linspace(0, finalTheta, int(nPrePoints * finalTheta / (2 * np.pi)))
|
||||
|
||||
# final shape
|
||||
[PointsFinal, CentersFinal, curvatureFinal] = self.calcCurve__trochoid(typeCurve, R, r, d, thetasFinal)
|
||||
[PointsFinal2, CentersFinal2, curvatureFinal2] = self.calcCurve__trochoid(typeCurve, R, r, -d, thetasFinal)
|
||||
[PointsFinal3, CentersFinal3, curvatureFinal3] = self.calcCurve__trochoid(typeCurve, R, r, r, thetasFinal)
|
||||
|
||||
if so.animate:
|
||||
animGroup = self.createGroup(group, 'Anim')
|
||||
|
||||
circle_R = inkDraw.circle.centerRadius(parent=animGroup, centerPoint=[0, 0], radius=R, offset=position, lineStyle=self.constructionLine)
|
||||
|
||||
# draw planetary wheel
|
||||
wheelGroup = self.createGroup(animGroup, 'Anim')
|
||||
circle_r = inkDraw.circle.centerRadius(wheelGroup, centerPoint=CentersFinal[0], radius=r, offset=position, lineStyle=self.lineStyleDisk)
|
||||
arms1 = inkDraw.line.absCoords(wheelGroup, coordsList=[CentersFinal[0], PointsFinal[0]], offset=position, lineStyle=self.lineStyleARM)
|
||||
arms2 = inkDraw.line.absCoords(wheelGroup, coordsList=[CentersFinal2[0], PointsFinal2[0]], offset=position, lineStyle=self.lineStyleARM)
|
||||
arms3 = inkDraw.line.absCoords(wheelGroup, coordsList=[CentersFinal3[0], PointsFinal3[0]], offset=position, lineStyle=self.lineStyleARM)
|
||||
|
||||
arc1 = inkDraw.arc.centerAngStartAngEnd(wheelGroup, centerPoint=CentersFinal[0], radius=r * 0.6, angStart=40, angEnd=80, offset=position,
|
||||
lineStyle=self.lineStyleArrow)
|
||||
arc2 = inkDraw.arc.centerAngStartAngEnd(wheelGroup, centerPoint=CentersFinal[0], radius=r * 0.6, angStart=160, angEnd=200,
|
||||
offset=position, lineStyle=self.lineStyleArrow)
|
||||
arc3 = inkDraw.arc.centerAngStartAngEnd(wheelGroup, centerPoint=CentersFinal[0], radius=r * 0.6, angStart=280, angEnd=320,
|
||||
offset=position, lineStyle=self.lineStyleArrow)
|
||||
|
||||
self.exportSVG(animGroup, os.path.join(so.directory,'outSVG_%1.5d.svg' % 0))
|
||||
|
||||
for i in range(1, len(thetasFinal)):
|
||||
|
||||
self.moveElement(wheelGroup, [CentersFinal[i][0] - CentersFinal[i - 1][0], CentersFinal[i][1] - CentersFinal[i - 1][1]])
|
||||
if typeCurve == 'hypo':
|
||||
self.rotateElement(wheelGroup, [position[0] + CentersFinal[i][0], position[1] + CentersFinal[i][1]],
|
||||
(thetasFinal[i] - thetasFinal[i - 1]) * (R - r) / r * 180 / np.pi)
|
||||
else:
|
||||
self.rotateElement(wheelGroup, [position[0] + CentersFinal[i][0], position[1] + CentersFinal[i][1]],
|
||||
- (thetasFinal[i] - thetasFinal[i - 1]) * (R + r) / r * 180 / np.pi)
|
||||
|
||||
curve1 = inkDraw.line.absCoords(parent=animGroup, coordsList=PointsFinal[:i + 1], offset=position, lineStyle=self.lineStyleCurve,
|
||||
closePath=False)
|
||||
curve2 = inkDraw.line.absCoords(parent=animGroup, coordsList=PointsFinal2[:i + 1], offset=position, lineStyle=self.lineStyleCurve2,
|
||||
closePath=False)
|
||||
curve3 = inkDraw.line.absCoords(parent=animGroup, coordsList=PointsFinal3[:i + 1], offset=position, lineStyle=self.lineStyleCurve3,
|
||||
closePath=False)
|
||||
|
||||
self.exportSVG(animGroup, os.path.join(so.directory , 'outSVG_%1.5d.svg' % i))
|
||||
|
||||
self.removeElement(curve1)
|
||||
self.removeElement(curve2)
|
||||
self.removeElement(curve3)
|
||||
self.removeElement(animGroup)
|
||||
else:
|
||||
if so.drawBaseCircles:
|
||||
inkDraw.circle.centerRadius(parent=group, centerPoint=position, radius=R, offset=[0, 0], lineStyle=self.constructionLine)
|
||||
|
||||
if typeCurve == 'hypo':
|
||||
inkDraw.circle.centerRadius(parent=group, centerPoint=position, radius=r, offset=[R - r, 0], lineStyle=self.constructionLine)
|
||||
if typeCurve == 'epi':
|
||||
inkDraw.circle.centerRadius(parent=group, centerPoint=position, radius=r, offset=[R + r, 0], lineStyle=self.constructionLine)
|
||||
|
||||
inkDraw.line.absCoords(group, PointsFinal, position, 'spiro', self.lineStyleCurve, closePath=True)
|
||||
|
||||
# plot curvatures
|
||||
if False:
|
||||
inkPlot.plot.polar(self, group, curvatureFinal, thetasFinal * 180 / np.pi, [position[0] + 3 * R, position[1]], rTicks=False,
|
||||
tTicks=False, rTickStep=0.2, tTickStep=45.0, rScale=20, rGrid=True, tGrid=True, lineStylePlot=self.lineStyleCurve,
|
||||
forceRlim=[0.0, 1.0])
|
||||
|
||||
return
|
||||
|
||||
# typeCurve: 'hypo', 'epi'
|
||||
def calcCurve__trochoid(self, typeCurve, R, r, d, thetas):
|
||||
j = complex(0, 1)
|
||||
if typeCurve.lower() == 'hypo':
|
||||
# https://www.mathcurve.com/courbes2d.gb/hypotrochoid/hypotrochoid.shtml
|
||||
P_complex = (R - r) * np.exp(j * thetas) + d * np.exp(-j * thetas * (R - r) / r)
|
||||
dP_complex = (R - r) * j * np.exp(j * thetas) + d * (-j) * (R - r) / r * np.exp(-j * thetas * (R - r) / r)
|
||||
ddP_complex = (R - r) * (-1) * np.exp(j * thetas) + d * (-1) * ((R - r) / r) ** 2 * np.exp(-j * thetas * (R - r) / r)
|
||||
centerGear = (R - r) * np.exp(j * thetas)
|
||||
if typeCurve.lower() == 'epi':
|
||||
# https://www.mathcurve.com/courbes2d.gb/epitrochoid/epitrochoid.shtml
|
||||
P_complex = (R + r) * np.exp(j * thetas) - d * np.exp(j * thetas * (R + r) / r)
|
||||
dP_complex = (R + r) * j * np.exp(j * thetas) - d * j * (R + r) / r * np.exp(j * thetas * (R + r) / r)
|
||||
ddP_complex = (R + r) * (-1) * np.exp(j * thetas) - d * (-1) * ((R + r) / r) ** 2 * np.exp(j * thetas * (R + r) / r)
|
||||
centerGear = (R + r) * np.exp(j * thetas)
|
||||
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
curvature = np.divide(abs(dP_complex.real * ddP_complex.imag - dP_complex.imag * ddP_complex.real),
|
||||
(dP_complex.real ** 2 + dP_complex.imag ** 2) ** (2 / 3))
|
||||
|
||||
# remove Nan=0/0
|
||||
np.nan_to_num(curvature, copy=False)
|
||||
|
||||
# remove values too large
|
||||
curvature[curvature > 10 * np.mean(curvature)] = 0.0
|
||||
|
||||
# self.Dump(curvature, '/home/fernando/lixo.txt', 'w')
|
||||
# normalize curvature
|
||||
curvature = self._normalizeCurvatures(curvature, 0.0, 1.0)
|
||||
|
||||
Points = np.column_stack((P_complex.real, P_complex.imag))
|
||||
Centers = np.column_stack((centerGear.real, centerGear.imag))
|
||||
|
||||
return [Points, Centers, curvature]
|
||||
|
||||
def _normalizeCurvatures(self, curvatures, normMin=0.0, normMax=1.0):
|
||||
y1 = normMin
|
||||
y2 = normMax
|
||||
x1 = np.min(curvatures)
|
||||
x2 = np.max(curvatures)
|
||||
alpha = (y2 - y1) / (x2 - x1)
|
||||
return alpha * (curvatures - x1) + y1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sp = Spirograph()
|
||||
sp.run()
|
@ -23,7 +23,7 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
def findLayer(self, layerName):
|
||||
svg_layers = self.document.xpath('//svg:g[@inkscape:groupmode="layer"]', namespaces=inkex.NSS)
|
||||
for layer in svg_layers:
|
||||
#inkex.utils.debug(str(layer.get('inkscape:label')) + " == " + layerName)
|
||||
#self.msg(str(layer.get('inkscape:label')) + " == " + layerName)
|
||||
if layer.get('inkscape:label') == layerName:
|
||||
return layer
|
||||
return None
|
||||
@ -31,7 +31,7 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
def createLayer(self, layerNodeList, layerName):
|
||||
svg = self.document.xpath('//svg:svg',namespaces=inkex.NSS)[0]
|
||||
for layer in layerNodeList:
|
||||
#inkex.utils.debug(str(layer[0].get('inkscape:label')) + " == " + layerName)
|
||||
#self.msg(str(layer[0].get('inkscape:label')) + " == " + layerName)
|
||||
if layer[0].get('inkscape:label') == layerName:
|
||||
return layer[0] #already exists. Do not create duplicate
|
||||
layer = etree.SubElement(svg, 'g')
|
||||
@ -68,8 +68,8 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
import applytransform
|
||||
applyTransformAvailable = True
|
||||
except Exception as e:
|
||||
# inkex.utils.debug(e)
|
||||
inkex.utils.debug("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
|
||||
# self.msg(e)
|
||||
self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
|
||||
|
||||
layer_name = None
|
||||
layerNodeList = [] #list with layer, neutral_value, element and self.options.separateby type
|
||||
@ -175,12 +175,11 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
layer_name = "fill-opacity-none"
|
||||
|
||||
else:
|
||||
inkex.utils.debug("No proper option selected.")
|
||||
self.msg("No proper option selected.")
|
||||
exit(1)
|
||||
|
||||
|
||||
if neutral_value is not None: #apply decimals filter
|
||||
neutral_value = float(round(neutral_value, self.options.decimals))
|
||||
|
||||
if layer_name is not None:
|
||||
layer_name = layer_name.split(";")[0] #cut off existing semicolons to avoid duplicated layers with/without semicolon
|
||||
currentLayer = self.findLayer(layer_name)
|
||||
@ -188,13 +187,16 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
layerNodeList.append([self.createLayer(layerNodeList, layer_name), neutral_value, element, self.options.separateby])
|
||||
else:
|
||||
layerNodeList.append([currentLayer, neutral_value, element, self.options.separateby]) #layer is existent. append items to this later
|
||||
elif layer_name is None and self.options.put_unfiltered:
|
||||
layer_name = 'without-' + self.options.separateby + '-in-style-attribute'
|
||||
else: #if no style attribute in element and not a group
|
||||
if isinstance(element, inkex.Group) is False:
|
||||
if self.options.show_info:
|
||||
inkex.utils.debug(element.get('id') + ' has no style attribute')
|
||||
self.msg(element.get('id') + ' has no style attribute')
|
||||
if self.options.put_unfiltered:
|
||||
layer_name = 'without-style-attribute'
|
||||
currentLayer = self.findLayer(layer_name)
|
||||
|
||||
if currentLayer is None: #layer does not exist, so create a new one
|
||||
layerNodeList.append([self.createLayer(layerNodeList, layer_name), None, element, None])
|
||||
else:
|
||||
@ -235,11 +237,11 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
maxval = max(minmax_range)
|
||||
sliceinterval = (maxval - minval) / self.options.subdividethreshold
|
||||
|
||||
#inkex.utils.debug("neutral values (sorted) = " + str(minmax_range))
|
||||
#inkex.utils.debug("min neutral_value = " + str(minval))
|
||||
#inkex.utils.debug("max neutral_value = " + str(maxval))
|
||||
#inkex.utils.debug("slice value (divide step size) = " + str(sliceinterval))
|
||||
#inkex.utils.debug("subdivides (parent layers) = " + str(self.options.subdividethreshold))
|
||||
#self.msg("neutral values (sorted) = " + str(minmax_range))
|
||||
#self.msg("min neutral_value = " + str(minval))
|
||||
#self.msg("max neutral_value = " + str(maxval))
|
||||
#self.msg("slice value (divide step size) = " + str(sliceinterval))
|
||||
#self.msg("subdivides (parent layers) = " + str(self.options.subdividethreshold))
|
||||
|
||||
for layerNode in layerNodeList:
|
||||
for x in range(0, self.options.subdividethreshold): #loop through the sorted neutral_values and determine to which layer they should belong
|
||||
@ -276,8 +278,8 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
|
||||
#finally append the sublayers to the slices
|
||||
#for layer in topLevelLayerNodeList:
|
||||
#inkex.utils.debug(layer[0].get('inkscape:label'))
|
||||
#inkex.utils.debug(layer[1])
|
||||
#self.msg(layer[0].get('inkscape:label'))
|
||||
#self.msg(layer[1])
|
||||
for newLayerNode in topLevelLayerNodeList:
|
||||
newLayerNode[0].append(newLayerNode[1]) #append newlayer to layer
|
||||
|
||||
@ -286,7 +288,7 @@ class StylesToLayers(inkex.EffectExtension):
|
||||
import cleangroups
|
||||
cleangroups.CleanGroups.effect(self)
|
||||
except:
|
||||
inkex.utils.debug("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
|
||||
self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
|
||||
|
||||
if __name__ == '__main__':
|
||||
StylesToLayers().run()
|
@ -30,7 +30,7 @@ Extension for InkScape 1.X
|
||||
Author: Mario Voigt / FabLab Chemnitz
|
||||
Mail: mario.voigt@stadtfabrikanten.org
|
||||
Date: 02.04.2021
|
||||
Last patch: 08.04.2021
|
||||
Last patch: 24.04.2021
|
||||
License: GNU GPL v3
|
||||
|
||||
This piece of spaghetti-code, called "vpypetools", is a wrapper to pass (pipe) line elements from InkScape selection (or complete canvas) to vpype.
|
||||
@ -180,7 +180,7 @@ class vpypetools (inkex.EffectExtension):
|
||||
for csp in subPath:
|
||||
if len(csp[1]) > 0: #we need exactly two points per straight line segment
|
||||
points.append(Point(round(csp[1][0], self.options.decimals), round(csp[1][1], self.options.decimals)))
|
||||
if subPath[-1][0] == 'Z' or subPath[0][1] == subPath[-1][1]: #check if path is closed by Z or first pont == last point
|
||||
if len(subPath) > 2 and (subPath[-1][0] == 'Z' or subPath[0][1] == subPath[-1][1]): #check if path has more than 2 points and is closed by Z or first pont == last point
|
||||
points.append(Point(round(subPath[0][1][0], self.options.decimals), round(subPath[0][1][1], self.options.decimals))) #if closed, we add the first point again
|
||||
lc.append(LineString(points))
|
||||
|
||||
@ -365,7 +365,7 @@ class vpypetools (inkex.EffectExtension):
|
||||
|
||||
# convert vpype polylines/lines/polygons to regular paths again. We need to use "--with-gui" to respond to "WARNING: ignoring verb FileSave - GUI required for this verb."
|
||||
if self.options.strokes_to_paths is True:
|
||||
cli_output = inkscape(output_file, "--with-gui", actions="EditSelectAllInAllLayers;EditUnlinkClone;ObjectToPath;FileSave;FileQuit")
|
||||
cli_output = inkscape(output_file, "--with-gui", actions="EditSelectAllInAllLayers;EditUnlinkClone;ObjectToPath;FileSave;FileQuit") #we do not use StrokeToPath because it will convert svg:line to a svg:path, but as closed path with four points
|
||||
if len(cli_output) > 0:
|
||||
self.debug(_("Inkscape returned the following output when trying to run the vpype object to path back-conversion:"))
|
||||
self.debug(cli_output)
|
||||
@ -436,7 +436,7 @@ class vpypetools (inkex.EffectExtension):
|
||||
if self.options.input_handling == "layers":
|
||||
if self_viewBox is not None:
|
||||
element.set('transform', 'scale(' + str(scaleX) + ',' + str(scaleY) + ')') #imported groups need to be transformed. Or they have wrong size. Reason: different viewBox sizes/units in namedview definitions
|
||||
if self.options.apply_transformations is True and applyTransformAvailable is True: #we apply the transforms directly after adding them
|
||||
if self.options.apply_transformations is True and applyTransformAvailable is True and self.options.strokes_to_paths is True: #we apply the transforms directly after adding them, but we need to have strokes_to_paths enabled!
|
||||
applytransform.ApplyTransform().recursiveFuseTransform(element)
|
||||
|
||||
# Delete the temporary file again because we do not need it anymore
|
||||
|
Reference in New Issue
Block a user