added polygen
This commit is contained in:
parent
150c077ad7
commit
a2b9c744f9
@ -1,6 +1,6 @@
|
|||||||
# MightyScape for Inkscape 1.0+
|
# MightyScape for Inkscape 1.0+
|
||||||
|
|
||||||
In short: A maintained extension collection for Inkscape 1.0+, working on Windows and Linux. There are **204 extension folders** with **366 .inx files** inside. We also take part at https://inkscape.org/gallery/=extension/ (with single extension uploads).
|
In short: A maintained extension collection for Inkscape 1.0+, working on Windows and Linux. There are **210 extension folders** with **372 .inx files** inside. We also take part at https://inkscape.org/gallery/=extension/ (with single extension uploads).
|
||||||
|
|
||||||
# About MightyScape
|
# About MightyScape
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<param name="collarparts" type="int" min="1" max="10" gui-text="Number of parts to divide collar into:">1</param>
|
<param name="collarparts" type="int" min="1" max="10" gui-text="Number of parts to divide collar into:">1</param>
|
||||||
<param name="tabangle" type="float" min="0.0" max="90.0" gui-text="Angle of tab edges (degrees):">45.0</param>
|
<param name="tabangle" type="float" min="0.0" max="90.0" gui-text="Angle of tab edges (degrees):">45.0</param>
|
||||||
<param name="tabheight" type="float" min="0.01" max="9999.0" gui-text="Height of tab (in Dimensional Units):">0.4</param>
|
<param name="tabheight" type="float" min="0.01" max="9999.0" gui-text="Height of tab (in Dimensional Units):">0.4</param>
|
||||||
<param name="dashlength" type="float" precision="3" min="0.0" max="9999.0" gui-text="Length of dashline(zero for solid line) (in Dimensional Units):">0.1</param>
|
<param name="dashlength" type="float" precision="3" min="0.0" max="9999.0" gui-text="Length of dashline (zero for solid line) (in Dimensional Units):">0.1</param>
|
||||||
<param name="unit" type="optiongroup" appearance="combo" gui-text="Dimensional units:">
|
<param name="unit" type="optiongroup" appearance="combo" gui-text="Dimensional units:">
|
||||||
<option value="mm">mm</option>
|
<option value="mm">mm</option>
|
||||||
<option value="cm">cm</option>
|
<option value="cm">cm</option>
|
||||||
|
2
extensions/fablabchemnitz/extruder/.gitattributes
vendored
Normal file
2
extensions/fablabchemnitz/extruder/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
47
extensions/fablabchemnitz/extruder/extruder.inx
Normal file
47
extensions/fablabchemnitz/extruder/extruder.inx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<name>Extruder</name>
|
||||||
|
<id>fablabchemnitz.de.extruder</id>
|
||||||
|
<param name="usermenu" type="notebook">
|
||||||
|
<page name="settings" gui-text="Settings">
|
||||||
|
<label appearance="header">General</label>
|
||||||
|
<param name="extrude" type="float" min="0.2" precision="2" max="9999.0" gui-text="Width of extrusion:">1.0</param>
|
||||||
|
<param name="maxstrip" type="float" min="0.5" precision="2" max="9999.0" gui-text="Maximum length of extrusion:">11.5</param>
|
||||||
|
<param name="tabangle" type="float" min="0.01" precision="2" max="90.0" gui-text="Angle of tab edges (degrees):">45.0</param>
|
||||||
|
<param name="tabheight" type="float" min="0.01" precision="3" max="9999.0" gui-text="Height of tab:">0.4</param>
|
||||||
|
<param name="dashlength" type="float" precision="3" min="0.0" max="9999.0" gui-text="Length of dashline (zero for solid line):">0.1</param>
|
||||||
|
<param name="unit" type="optiongroup" appearance="combo" gui-text="Dimensional units:">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="m">m</option>
|
||||||
|
<option value="km">km</option>
|
||||||
|
<option value="px">px</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="ft">ft</option>
|
||||||
|
<option value="yd">yd</option>
|
||||||
|
</param>
|
||||||
|
<label appearance="header">Styles</label>
|
||||||
|
<param name="generate_decorative_wrapper" type="bool" gui-text="Generate decorative wrapper">false</param>
|
||||||
|
<param name="cosmetic_dash_style" type="bool" gui-text="Cosmetic dash lines" gui-description="If entered dash line length is zero we can apply some cosmetic style only">false</param>
|
||||||
|
<param name="color_solid" type="color" appearance="colorbutton" gui-text="Solid line color">4278190335</param>
|
||||||
|
<param name="color_dash" type="color" appearance="colorbutton" gui-text="Dash line color">65535</param>
|
||||||
|
<label appearance="header">Other settings</label>
|
||||||
|
<param name="print_debug" type="bool" gui-text="Print debug info">true</param>
|
||||||
|
</page>
|
||||||
|
<page name="help" gui-text="Help">
|
||||||
|
<label xml:space="preserve">Given a closed path of straight lines, this program generates a paper model of (1) another copy of the closed path; (2) an extrusion (or more if it exceeds the maximum length) represented by a strip with tabs and score lines; and (3) strips for covering the tabbed strips.</label>
|
||||||
|
</page>
|
||||||
|
</param>
|
||||||
|
<effect needs-live-preview="true">
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu name="FabLab Chemnitz">
|
||||||
|
<submenu name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command location="inx" interpreter="python">extruder.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
719
extensions/fablabchemnitz/extruder/extruder.py
Normal file
719
extensions/fablabchemnitz/extruder/extruder.py
Normal file
@ -0,0 +1,719 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) [2021] [Joseph Zakar], [observing@gmail.com]
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
"""
|
||||||
|
Given a closed path of straight lines, this program generates a paper model of
|
||||||
|
(1) another copy of the closed path; (2) an extrusion (or more if it exceeds the
|
||||||
|
maximum length) represented by a strip with tabs and score lines; and (3) strips
|
||||||
|
for covering the tabbed strips.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import inkex
|
||||||
|
from inkex import Path, Color
|
||||||
|
import math
|
||||||
|
import copy
|
||||||
|
|
||||||
|
class pathStruct(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.id="path0000"
|
||||||
|
self.path=[]
|
||||||
|
self.enclosed=False
|
||||||
|
def __str__(self):
|
||||||
|
return self.path
|
||||||
|
|
||||||
|
class pnPoint(object):
|
||||||
|
# This class came from https://github.com/JoJocoder/PNPOLY
|
||||||
|
def __init__(self,p):
|
||||||
|
self.p=p
|
||||||
|
def __str__(self):
|
||||||
|
return self.p
|
||||||
|
def InPolygon(self,polygon,BoundCheck=False):
|
||||||
|
inside=False
|
||||||
|
if BoundCheck:
|
||||||
|
minX=polygon[0][0]
|
||||||
|
maxX=polygon[0][0]
|
||||||
|
minY=polygon[0][1]
|
||||||
|
maxY=polygon[0][1]
|
||||||
|
for p in polygon:
|
||||||
|
minX=min(p[0],minX)
|
||||||
|
maxX=max(p[0],maxX)
|
||||||
|
minY=min(p[1],minY)
|
||||||
|
maxY=max(p[1],maxY)
|
||||||
|
if self.p[0]<minX or self.p[0]>maxX or self.p[1]<minY or self.p[1]>maxY:
|
||||||
|
return False
|
||||||
|
j=len(polygon)-1
|
||||||
|
for i in range(len(polygon)):
|
||||||
|
if ((polygon[i][1]>self.p[1])!=(polygon[j][1]>self.p[1]) and (self.p[0]<(polygon[j][0]-polygon[i][0])*(self.p[1]-polygon[i][1])/( polygon[j][1] - polygon[i][1] ) + polygon[i][0])):
|
||||||
|
inside =not inside
|
||||||
|
j=i
|
||||||
|
return inside
|
||||||
|
|
||||||
|
class Extruder(inkex.EffectExtension):
|
||||||
|
|
||||||
|
def add_arguments(self, pars):
|
||||||
|
pars.add_argument("--usermenu")
|
||||||
|
pars.add_argument("--extrude", type=float, default=1.0, help="Width of extrusion in dimensional units")
|
||||||
|
pars.add_argument("--maxstrip", type=float, default=11.5, help="Maximum length of extrusion in dimensional units")
|
||||||
|
pars.add_argument("--tabangle", type=float, default=45.0, help="Angle of tab edges in degrees")
|
||||||
|
pars.add_argument("--tabheight", type=float, default=0.4, help="Height of tab in dimensional units")
|
||||||
|
pars.add_argument("--dashlength", type=float, default=0.1, help="Length of dashline in dimensional units (zero for solid line)")
|
||||||
|
pars.add_argument("--generate_decorative_wrapper", type=inkex.Boolean, default=False, help="Generate decorative wrapper")
|
||||||
|
pars.add_argument("--cosmetic_dash_style", type=inkex.Boolean, default=False, help="Cosmetic dash lines")
|
||||||
|
pars.add_argument("--unit", default="in", help="Dimensional units")
|
||||||
|
pars.add_argument("--color_solid", type=Color, default='4278190335', help="Solid line color")
|
||||||
|
pars.add_argument("--color_dash", type=Color, default='65535', help="Solid line dash")
|
||||||
|
pars.add_argument("--print_debug", type=inkex.Boolean, default=True, help="Print debug info")
|
||||||
|
|
||||||
|
#draw SVG line segment(s) between the given (raw) points
|
||||||
|
def drawline(self, dstr, name, parent, sstr=None):
|
||||||
|
line_style = {'stroke':'{}','stroke-width':'1','fill':'none'.format(self.options.color_solid)}
|
||||||
|
if sstr == None:
|
||||||
|
stylestr = str(inkex.Style(line_style))
|
||||||
|
else:
|
||||||
|
stylestr = sstr
|
||||||
|
el = parent.add(inkex.PathElement())
|
||||||
|
el.path = dstr
|
||||||
|
el.style = stylestr
|
||||||
|
el.label = name
|
||||||
|
|
||||||
|
def add_doc(self, path, apt1, apt2, offset, layer):
|
||||||
|
stylestr = "font-size:{0};line-height:1.25;font-family:sans-serif;stroke-width:0.264583".format(offset*2)
|
||||||
|
te = layer.add(inkex.TextElement())
|
||||||
|
te.style = stylestr
|
||||||
|
te.label = te.get_id()
|
||||||
|
te.text = "1"
|
||||||
|
te.set('x', apt1.x)
|
||||||
|
te.set('y', apt1.y)
|
||||||
|
te = layer.add(inkex.TextElement())
|
||||||
|
te.style = stylestr
|
||||||
|
te.label = te.get_id()
|
||||||
|
te.text = "2"
|
||||||
|
te.set('x', apt2.x)
|
||||||
|
te.set('y', apt2.y)
|
||||||
|
|
||||||
|
def pathInsidePath(self, path, testpath):
|
||||||
|
enclosed = True
|
||||||
|
for tp in testpath:
|
||||||
|
# If any point in the testpath is outside the path, it's not enclosed
|
||||||
|
if self.insidePath(path, tp) == False:
|
||||||
|
enclosed = False
|
||||||
|
return enclosed # True if testpath is fully enclosed in path
|
||||||
|
return enclosed
|
||||||
|
|
||||||
|
def insidePath(self, path, p):
|
||||||
|
point = pnPoint((p.x, p.y))
|
||||||
|
pverts = []
|
||||||
|
for pnum in path:
|
||||||
|
pverts.append((pnum.x, pnum.y))
|
||||||
|
isInside = point.InPolygon(pverts, True)
|
||||||
|
return isInside # True if point p is inside path
|
||||||
|
|
||||||
|
def makescore(self, pt1, pt2, dashlength):
|
||||||
|
# Draws a dashed line of dashlength between two points
|
||||||
|
# Dash = dashlength (in inches) space followed by dashlength mark
|
||||||
|
# if dashlength is zero, we want a solid line
|
||||||
|
apt1 = inkex.paths.Line(0.0,0.0)
|
||||||
|
apt2 = inkex.paths.Line(0.0,0.0)
|
||||||
|
ddash = ''
|
||||||
|
if math.isclose(dashlength, 0.0):
|
||||||
|
#inkex.utils.debug("Draw solid dashline")
|
||||||
|
ddash = ' M '+str(pt1.x)+','+str(pt1.y)+' L '+str(pt2.x)+','+str(pt2.y)
|
||||||
|
else:
|
||||||
|
if math.isclose(pt1.y, pt2.y):
|
||||||
|
#inkex.utils.debug("Draw horizontal dashline")
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
xcushion = pt2.x - dashlength
|
||||||
|
xpt = pt1.x
|
||||||
|
ypt = pt1.y
|
||||||
|
else:
|
||||||
|
xcushion = pt1.x - dashlength
|
||||||
|
xpt = pt2.x
|
||||||
|
ypt = pt2.y
|
||||||
|
ddash = ''
|
||||||
|
done = False
|
||||||
|
while not(done):
|
||||||
|
if (xpt + dashlength*2) <= xcushion:
|
||||||
|
xpt = xpt + dashlength
|
||||||
|
ddash = ddash + ' M ' + str(xpt) + ',' + str(ypt)
|
||||||
|
xpt = xpt + dashlength
|
||||||
|
ddash = ddash + ' L ' + str(xpt) + ',' + str(ypt)
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
elif math.isclose(pt1.x, pt2.x):
|
||||||
|
#inkex.utils.debug("Draw vertical dashline")
|
||||||
|
if pt1.y < pt2.y:
|
||||||
|
ycushion = pt2.y - dashlength
|
||||||
|
xpt = pt1.x
|
||||||
|
ypt = pt1.y
|
||||||
|
else:
|
||||||
|
ycushion = pt1.y - dashlength
|
||||||
|
xpt = pt2.x
|
||||||
|
ypt = pt2.y
|
||||||
|
ddash = ''
|
||||||
|
done = False
|
||||||
|
while not(done):
|
||||||
|
if(ypt + dashlength*2) <= ycushion:
|
||||||
|
ypt = ypt + dashlength
|
||||||
|
ddash = ddash + ' M ' + str(xpt) + ',' + str(ypt)
|
||||||
|
ypt = ypt + dashlength
|
||||||
|
ddash = ddash + ' L ' + str(xpt) + ',' + str(ypt)
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
else:
|
||||||
|
#inkex.utils.debug("Draw sloping dashline")
|
||||||
|
if pt1.y > pt2.y:
|
||||||
|
apt1.x = pt1.x
|
||||||
|
apt1.y = pt1.y
|
||||||
|
apt2.x = pt2.x
|
||||||
|
apt2.y = pt2.y
|
||||||
|
else:
|
||||||
|
apt1.x = pt2.x
|
||||||
|
apt1.y = pt2.y
|
||||||
|
apt2.x = pt1.x
|
||||||
|
apt2.y = pt1.y
|
||||||
|
m = (apt1.y-apt2.y)/(apt1.x-apt2.x)
|
||||||
|
theta = math.atan(m)
|
||||||
|
msign = (m>0) - (m<0)
|
||||||
|
ycushion = apt2.y + dashlength*math.sin(theta)
|
||||||
|
xcushion = apt2.x + msign*dashlength*math.cos(theta)
|
||||||
|
ddash = ''
|
||||||
|
xpt = apt1.x
|
||||||
|
ypt = apt1.y
|
||||||
|
done = False
|
||||||
|
while not(done):
|
||||||
|
nypt = ypt - dashlength*2*math.sin(theta)
|
||||||
|
nxpt = xpt - msign*dashlength*2*math.cos(theta)
|
||||||
|
if (nypt >= ycushion) and (((m<0) and (nxpt <= xcushion)) or ((m>0) and (nxpt >= xcushion))):
|
||||||
|
# move to end of space / beginning of mark
|
||||||
|
xpt = xpt - msign*dashlength*math.cos(theta)
|
||||||
|
ypt = ypt - msign*dashlength*math.sin(theta)
|
||||||
|
ddash = ddash + ' M ' + str(xpt) + ',' + str(ypt)
|
||||||
|
# draw the mark
|
||||||
|
xpt = xpt - msign*dashlength*math.cos(theta)
|
||||||
|
ypt = ypt - msign*dashlength*math.sin(theta)
|
||||||
|
ddash = ddash + ' L ' + str(xpt) + ',' + str(ypt)
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
return ddash
|
||||||
|
|
||||||
|
def detectIntersect(self, x1, y1, x2, y2, x3, y3, x4, y4):
|
||||||
|
td = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
|
||||||
|
if td == 0:
|
||||||
|
# These line segments are parallel
|
||||||
|
return False
|
||||||
|
t = ((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/td
|
||||||
|
if (0.0 <= t) and (t <= 1.0):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def makeTab(self, tpath, pt1, pt2, tabht, taba):
|
||||||
|
# tpath - the pathstructure containing pt1 and pt2
|
||||||
|
# pt1, pt2 - the two points where the tab will be inserted
|
||||||
|
# tabht - the height of the tab
|
||||||
|
# taba - the angle of the tab sides
|
||||||
|
# returns the two tab points in order of closest to pt1
|
||||||
|
tpt1 = inkex.paths.Line(0.0,0.0)
|
||||||
|
tpt2 = inkex.paths.Line(0.0,0.0)
|
||||||
|
currTabHt = tabht
|
||||||
|
currTabAngle = taba
|
||||||
|
testAngle = 1.0
|
||||||
|
testHt = currTabHt * 0.001
|
||||||
|
adjustTab = 0
|
||||||
|
tabDone = False
|
||||||
|
while not tabDone:
|
||||||
|
# Let's find out the orientation of the tab
|
||||||
|
if math.isclose(pt1.x, pt2.x):
|
||||||
|
# It's vertical. Let's try the right side
|
||||||
|
if pt1.y < pt2.y:
|
||||||
|
tpt1.x = pt1.x + testHt
|
||||||
|
tpt2.x = pt2.x + testHt
|
||||||
|
tpt1.y = pt1.y + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.y = pt2.y - testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.x = pt1.x - currTabHt
|
||||||
|
tpt2.x = pt2.x - currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.x = pt1.x + currTabHt
|
||||||
|
tpt2.x = pt2.x + currTabHt
|
||||||
|
tpt1.y = pt1.y + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.y = pt2.y - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
else: # pt2.y < pt1.y
|
||||||
|
tpt1.x = pt1.x + testHt
|
||||||
|
tpt2.x = pt2.x + testHt
|
||||||
|
tpt1.y = pt1.y - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.y = pt2.y + testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.x = pt1.x - currTabHt
|
||||||
|
tpt2.x = pt2.x - currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.x = pt1.x + currTabHt
|
||||||
|
tpt2.x = pt2.x + currTabHt
|
||||||
|
tpt1.y = pt1.y - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.y = pt2.y + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
elif math.isclose(pt1.y, pt2.y):
|
||||||
|
# It's horizontal. Let's try the top
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
else: # pt2.x < pt1.x
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
|
||||||
|
else: # the orientation is neither horizontal nor vertical
|
||||||
|
# Let's get the slope of the line between the points
|
||||||
|
# Because Inkscape's origin is in the upper-left corner,
|
||||||
|
# a positive slope (/) will yield a negative value
|
||||||
|
slope = (pt2.y - pt1.y)/(pt2.x - pt1.x)
|
||||||
|
# Let's get the angle to the horizontal
|
||||||
|
theta = math.degrees(math.atan(slope))
|
||||||
|
# Let's construct a horizontal tab
|
||||||
|
seglength = math.sqrt((pt1.x-pt2.x)**2 +(pt1.y-pt2.y)**2)
|
||||||
|
if slope < 0.0:
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
else: # pt1.x > pt2.x
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
else: # slope > 0.0
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
else: # pt1.x > pt2.x
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
# Check to see if any tabs intersect each other
|
||||||
|
if self.detectIntersect(pt1.x, pt1.y, tpt1.x, tpt1.y, pt2.x, pt2.y, tpt2.x, tpt2.y):
|
||||||
|
# Found an intersection.
|
||||||
|
if adjustTab == 0:
|
||||||
|
# Try increasing the tab angle in one-degree increments
|
||||||
|
currTabAngle = currTabAngle + 1.0
|
||||||
|
if currTabAngle > 88.0: # We're not increasing the tab angle above 89 degrees
|
||||||
|
adjustTab = 1
|
||||||
|
currTabAngle = taba
|
||||||
|
if adjustTab == 1:
|
||||||
|
# So, try reducing the tab height in 20% increments instead
|
||||||
|
currTabHt = currTabHt - tabht*0.2 # Could this lead to a zero tab_height?
|
||||||
|
if currTabHt <= 0.0:
|
||||||
|
# Give up
|
||||||
|
currTabHt = tabht
|
||||||
|
adjustTab = 2
|
||||||
|
if adjustTab == 2:
|
||||||
|
tabDone = True # Just show the failure
|
||||||
|
else:
|
||||||
|
tabDone = True
|
||||||
|
|
||||||
|
return tpt1,tpt2
|
||||||
|
|
||||||
|
def effect(self):
|
||||||
|
layer = self.svg.get_current_layer()
|
||||||
|
doc_layer = self.svg.add(inkex.elements._groups.Layer.new('Layer Doc'))
|
||||||
|
scale = self.svg.unittouu('1'+self.options.unit)
|
||||||
|
extrude = float(self.options.extrude) * scale
|
||||||
|
maxstrip = float(self.options.maxstrip) * scale
|
||||||
|
tab_angle = float(self.options.tabangle)
|
||||||
|
tab_height = float(self.options.tabheight) * scale
|
||||||
|
dashlength = float(self.options.dashlength) * scale
|
||||||
|
#tabsets = self.options.tabsets <-- for a future feature
|
||||||
|
npaths = []
|
||||||
|
elems = []
|
||||||
|
for selem in self.svg.selection.filter(inkex.PathElement):
|
||||||
|
elems.append(selem)
|
||||||
|
if len(elems) == 0:
|
||||||
|
raise inkex.AbortExtension("Nothing selected")
|
||||||
|
for elem in elems:
|
||||||
|
backend = elem.copy() # Make a copy of it
|
||||||
|
layer.append(backend)
|
||||||
|
escale = 1.0
|
||||||
|
if 'transform' in elem.attrib:
|
||||||
|
transforms = elem.attrib['transform'].split()
|
||||||
|
for tf in transforms:
|
||||||
|
if tf.startswith('scale'):
|
||||||
|
escale = float(tf.split('(')[1].split(')')[0])
|
||||||
|
# Get style of original polygon
|
||||||
|
if 'style' in elem.attrib:
|
||||||
|
sstr = elem.attrib['style']
|
||||||
|
if not math.isclose(escale, 1.0):
|
||||||
|
lsstr = sstr.split(';')
|
||||||
|
for stoken in range(len(lsstr)):
|
||||||
|
if lsstr[stoken].startswith('stroke-width'):
|
||||||
|
swt = lsstr[stoken].split(':')[1]
|
||||||
|
swf = str(float(swt)*escale)
|
||||||
|
lsstr[stoken] = lsstr[stoken].replace(swt, swf)
|
||||||
|
if lsstr[stoken].startswith('stroke-miterlimit'):
|
||||||
|
swt = lsstr[stoken].split(':')[1]
|
||||||
|
swf = str(float(swt)*escale)
|
||||||
|
lsstr[stoken] = lsstr[stoken].replace(swt, swf)
|
||||||
|
sstr = ";".join(lsstr)
|
||||||
|
else:
|
||||||
|
sstr = None
|
||||||
|
last_letter = 'Z'
|
||||||
|
savid = elem.get_id()
|
||||||
|
idmod = 0
|
||||||
|
parent = elem.getparent()
|
||||||
|
#if parent != self.svg.root:
|
||||||
|
# elem.path.transform = elem.path.transform(parent.composed_transform())
|
||||||
|
elementPath = elem.path.to_non_shorthand().to_absolute()
|
||||||
|
isClosed = False
|
||||||
|
raw = elementPath.to_arrays()
|
||||||
|
if raw[-1][0] == 'Z' or \
|
||||||
|
(raw[-1][0] == 'L' and raw[0][1] == raw[-1][1]) or \
|
||||||
|
(raw[-1][0] == 'C' and raw[0][1] == [raw[-1][1][-2], raw[-1][1][-1]]) \
|
||||||
|
: #if first is last point the path is also closed. The "Z" command is not required
|
||||||
|
isClosed = True
|
||||||
|
if isClosed is False:
|
||||||
|
if self.options.print_debug is True:
|
||||||
|
self.msg("Warning! Path {} is not closed. Skipping ...".format(elem.get('id')))
|
||||||
|
continue
|
||||||
|
npaths.clear()
|
||||||
|
|
||||||
|
for ptoken in elementPath: # For each point in the path
|
||||||
|
ptx2 = None
|
||||||
|
pty2 = None
|
||||||
|
if ptoken.letter == 'M': # Starting point
|
||||||
|
# Hold this point in case we receive a Z
|
||||||
|
ptx1 = mx = ptoken.x * escale
|
||||||
|
pty1 = my = ptoken.y * escale
|
||||||
|
'''
|
||||||
|
Assign a structure to the new path. We assume that there is
|
||||||
|
only one path and, therefore, it isn't enclosed by a
|
||||||
|
sub-path. However, we'll suffix the ID, if we find a
|
||||||
|
sub-path.
|
||||||
|
'''
|
||||||
|
npath = pathStruct()
|
||||||
|
npath.enclosed = False
|
||||||
|
npath.id = elem.get_id()+"-"+str(idmod)
|
||||||
|
idmod += 1
|
||||||
|
npath.path.append(inkex.paths.Move(ptx1,pty1))
|
||||||
|
else:
|
||||||
|
if last_letter != 'M':
|
||||||
|
ptx1 = ptx2
|
||||||
|
pty1 = pty2
|
||||||
|
if ptoken.letter == 'L':
|
||||||
|
ptx2 = ptoken.x * escale
|
||||||
|
pty2 = ptoken.y * escale
|
||||||
|
elif ptoken.letter == 'H':
|
||||||
|
ptx2 = ptoken.x * escale
|
||||||
|
pty2 = pty1
|
||||||
|
elif ptoken.letter == 'V':
|
||||||
|
ptx2 = ptx1
|
||||||
|
pty2 = ptoken.y * escale
|
||||||
|
elif ptoken.letter == 'Z':
|
||||||
|
ptx2 = mx
|
||||||
|
pty2 = my
|
||||||
|
else:
|
||||||
|
raise inkex.AbortExtension("Unrecognized path command {0}. Please convert to polyline before!".format(ptoken.letter))
|
||||||
|
npath.path.append(inkex.paths.Line(ptx2,pty2))
|
||||||
|
if ptoken.letter == 'Z':
|
||||||
|
npaths.append(npath)
|
||||||
|
last_letter = ptoken.letter
|
||||||
|
# check for cutouts
|
||||||
|
if idmod > 1:
|
||||||
|
for apath in npaths: # We test these paths to see if they are fully enclosed
|
||||||
|
for bpath in npaths: # by these paths
|
||||||
|
if self.pathInsidePath(bpath.path, apath.path):
|
||||||
|
apath.enclosed = True
|
||||||
|
for opath in npaths:
|
||||||
|
if True: # We'll handle outside paths and the cutouts, too
|
||||||
|
# create the extruded path
|
||||||
|
xpos = ypos = 0.0
|
||||||
|
segs = pathStruct()
|
||||||
|
segs.enclosed = False
|
||||||
|
segs.id = opath.id+"x"
|
||||||
|
segs.path.append(inkex.paths.Move(xpos,ypos))
|
||||||
|
strips = [] # Needed because a single strip might be larger than the paper
|
||||||
|
scores = [] # holds lists of individual score lines per strip
|
||||||
|
score = [] # holds a list of individual score lines
|
||||||
|
spaths = ''
|
||||||
|
# create left edge of path
|
||||||
|
for jnode in range(0,len(opath.path)-1):
|
||||||
|
if jnode == 0:
|
||||||
|
# Let's draw the first two node numbers to show the starting point and direction
|
||||||
|
self.add_doc(opath.path, opath.path[jnode], opath.path[jnode+1], 0.5*tab_height, doc_layer)
|
||||||
|
# calculate length of segment between jnode and jnode+1
|
||||||
|
seglength = math.sqrt((opath.path[jnode].x - opath.path[jnode+1].x)**2 + (opath.path[jnode].y - opath.path[jnode+1].y)**2)
|
||||||
|
if ypos + seglength + tab_height >= maxstrip:
|
||||||
|
# have to cut it at last segment
|
||||||
|
strips.append(copy.deepcopy(segs))
|
||||||
|
segs = pathStruct() # start a new segment
|
||||||
|
segs.enclosed = False
|
||||||
|
segs.id = opath.id+"x"
|
||||||
|
ypos = 0
|
||||||
|
scores.append(copy.deepcopy(score))
|
||||||
|
score.clear()
|
||||||
|
spaths = ''
|
||||||
|
segs.path.append(inkex.paths.Move(xpos,ypos))
|
||||||
|
ypos = ypos + seglength
|
||||||
|
segs.path.append(inkex.paths.Move(xpos,ypos))
|
||||||
|
if jnode < len(opath.path)-1:
|
||||||
|
# Generate score lines across extrusion
|
||||||
|
score.append(self.makescore(inkex.paths.Move(xpos,ypos), inkex.paths.Move(extrude, ypos),dashlength))
|
||||||
|
strips.append(copy.deepcopy(segs))
|
||||||
|
scores.append(copy.deepcopy(score))
|
||||||
|
score.clear()
|
||||||
|
# create right edge of path
|
||||||
|
for knode in range(len(strips)):
|
||||||
|
rsegs = strips[knode].path[::-1]
|
||||||
|
for jnode in range(0,len(rsegs)):
|
||||||
|
strips[knode].path.append(inkex.paths.Move(extrude, rsegs[jnode].y))
|
||||||
|
rsegs.clear()
|
||||||
|
# Generate the deco strips from the extruded paths
|
||||||
|
for stripcnt in range(len(strips)):
|
||||||
|
for nodes in range(len(strips[stripcnt].path)):
|
||||||
|
if nodes == 0:
|
||||||
|
dprop = 'M '
|
||||||
|
else:
|
||||||
|
dprop = dprop + ' L '
|
||||||
|
dprop = dprop + str(strips[stripcnt].path[nodes].x) + ',' + str(strips[stripcnt].path[nodes].y)
|
||||||
|
## and close the path
|
||||||
|
dprop = dprop + ' Z'
|
||||||
|
spaths = ''
|
||||||
|
for scorecnt in range(len(scores[stripcnt])-1): # each list of individual scorelines across extrusion per strip
|
||||||
|
scorex = scores[stripcnt][scorecnt]
|
||||||
|
for sc in scorex:
|
||||||
|
spaths += sc
|
||||||
|
if math.isclose(dashlength, 0.0) and spaths != '':
|
||||||
|
group = inkex.elements._groups.Group()
|
||||||
|
group.label = 'g'+opath.id+'ws'+str(stripcnt)
|
||||||
|
if self.options.generate_decorative_wrapper is True:
|
||||||
|
self.drawline(dprop,'wrapper'+str(stripcnt),group,sstr) # Output the model
|
||||||
|
self.drawline(spaths[1:],'score'+str(stripcnt)+'m',group,sstr) # Output the scorelines separately
|
||||||
|
layer.append(group)
|
||||||
|
else:
|
||||||
|
dprop = dprop + spaths
|
||||||
|
self.drawline(dprop,opath.id+'d'+str(stripcnt),layer,sstr)
|
||||||
|
# Generate the tabbed strips from the extruded paths
|
||||||
|
dprop = ''
|
||||||
|
for stripcnt in range(len(strips)):
|
||||||
|
strip = strips[stripcnt]
|
||||||
|
mpath = [strip.path[0]]
|
||||||
|
for ptn in range(len(strip.path)-1):
|
||||||
|
tabpt1, tabpt2 = self.makeTab(strip, strip.path[ptn], strip.path[ptn+1], tab_height, tab_angle)
|
||||||
|
mpath.append(tabpt1)
|
||||||
|
mpath.append(tabpt2)
|
||||||
|
mpath.append(strip.path[ptn+1])
|
||||||
|
score.append(self.makescore(strip.path[ptn], strip.path[ptn+1],dashlength))
|
||||||
|
scores[stripcnt].append(copy.deepcopy(score))
|
||||||
|
score.clear()
|
||||||
|
for nodes in range(len(mpath)):
|
||||||
|
if nodes == 0:
|
||||||
|
dprop = 'M '
|
||||||
|
else:
|
||||||
|
dprop = dprop + ' L '
|
||||||
|
dprop = dprop + str(mpath[nodes].x) + ',' + str(mpath[nodes].y)
|
||||||
|
## and close the path
|
||||||
|
dprop = dprop + ' Z'
|
||||||
|
spaths = ''
|
||||||
|
for scorecnt in range(len(scores[stripcnt])): # each list of individual scorelines across extrusion and tabs per strip
|
||||||
|
scorex = scores[stripcnt][scorecnt]
|
||||||
|
for sc in scorex:
|
||||||
|
spaths += sc
|
||||||
|
if spaths != '':
|
||||||
|
group = inkex.elements._groups.Group()
|
||||||
|
group.label = 'g'+opath.id+'ms'+str(stripcnt)
|
||||||
|
self.drawline(dprop,'model'+str(stripcnt),group,sstr+';stroke:{}'.format(self.options.color_solid)) # Output the model
|
||||||
|
dscore_style = sstr+';stroke:{}'.format(self.options.color_dash)
|
||||||
|
if self.options.cosmetic_dash_style is True:
|
||||||
|
dscore_style += ';stroke-dasharray:{}'.format(3, 3)
|
||||||
|
self.drawline(spaths[1:],'score'+str(stripcnt)+'m',group,dscore_style) # Output the scorelines separately
|
||||||
|
layer.append(group)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Extruder().run()
|
2
extensions/fablabchemnitz/polygen/.gitattributes
vendored
Normal file
2
extensions/fablabchemnitz/polygen/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
44
extensions/fablabchemnitz/polygen/polygen.inx
Normal file
44
extensions/fablabchemnitz/polygen/polygen.inx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<name>Polygen</name>
|
||||||
|
<id>fablabchemnitz.de.polygen</id>
|
||||||
|
<param name="usermenu" type="notebook">
|
||||||
|
<page name="settings" gui-text="Settings">
|
||||||
|
<label appearance="header">General</label>
|
||||||
|
<param name ="polysides" type="int" min="3" max="360" gui-text="Number of Polygon Sides:">6</param>
|
||||||
|
<param name ="tabangle" type="float" precision="2" min="0.01" max="90.0" gui-text="Angle of tab edges (degrees):">45.0</param>
|
||||||
|
<param name="tabheight" type="float" precision="3" min="0.01" max="9999.0" gui-text="Height of tab:">0.4</param>
|
||||||
|
<param name="dashlength" type="float" precision="3" min="0.0" max="9999.0" gui-text="Length of dashline (zero for solid line):">0.1</param>
|
||||||
|
<param name="unit" type="optiongroup" appearance="combo" gui-text="Dimensional units of above parameters and the selected paths:">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="m">m</option>
|
||||||
|
<option value="km">km</option>
|
||||||
|
<option value="px">px</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="ft">ft</option>
|
||||||
|
<option value="yd">yd</option>
|
||||||
|
</param>
|
||||||
|
<label appearance="header">Styles</label>
|
||||||
|
<param name="generate_decorative_wrapper" type="bool" gui-text="Generate decorative wrapper">false</param>
|
||||||
|
<param name="cosmetic_dash_style" type="bool" gui-text="Cosmetic dash lines" gui-description="If entered dash line length is zero we can apply some cosmetic style only">false</param>
|
||||||
|
<param name="color_solid" type="color" appearance="colorbutton" gui-text="Solid line color">4278190335</param>
|
||||||
|
<param name="color_dash" type="color" appearance="colorbutton" gui-text="Dash line color">65535</param>
|
||||||
|
</page>
|
||||||
|
<page name="help" gui-text="Help">
|
||||||
|
<label xml:space="preserve">Given a closed path of straight lines, this program generates a paper model of tabs and score lines for each straight edge.</label>
|
||||||
|
</page>
|
||||||
|
</param>
|
||||||
|
<effect needs-live-preview="true">
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu name="FabLab Chemnitz">
|
||||||
|
<submenu name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command location="inx" interpreter="python">polygen.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
692
extensions/fablabchemnitz/polygen/polygen.py
Normal file
692
extensions/fablabchemnitz/polygen/polygen.py
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# #
|
||||||
|
# Copyright (C) [2021] [Joseph Zakar], [observing@gmail.com]
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
"""
|
||||||
|
Given the number of polygon sides, an outline to be generated perpendicular to
|
||||||
|
each side, and a straight line whose distance is the radius of the revolved
|
||||||
|
outline, this program generates (1) a paper model of one of the n sides with tabs
|
||||||
|
to assemble into a full 3D model; (2) the top and bottom lids for the generated
|
||||||
|
model; and (3) wrappers to cover each side of the generated model.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import inkex
|
||||||
|
from inkex import Color
|
||||||
|
from lxml import etree
|
||||||
|
import math
|
||||||
|
import copy
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
class pathStruct(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.id="path0000"
|
||||||
|
self.path=[]
|
||||||
|
self.enclosed=False
|
||||||
|
self.style = None
|
||||||
|
def __str__(self):
|
||||||
|
return self.path
|
||||||
|
|
||||||
|
class pnPoint(object):
|
||||||
|
# This class came from https://github.com/JoJocoder/PNPOLY
|
||||||
|
def __init__(self,p):
|
||||||
|
self.p=p
|
||||||
|
def __str__(self):
|
||||||
|
return self.p
|
||||||
|
def InPolygon(self,polygon,BoundCheck=False):
|
||||||
|
inside=False
|
||||||
|
if BoundCheck:
|
||||||
|
minX=polygon[0][0]
|
||||||
|
maxX=polygon[0][0]
|
||||||
|
minY=polygon[0][1]
|
||||||
|
maxY=polygon[0][1]
|
||||||
|
for p in polygon:
|
||||||
|
minX=min(p[0],minX)
|
||||||
|
maxX=max(p[0],maxX)
|
||||||
|
minY=min(p[1],minY)
|
||||||
|
maxY=max(p[1],maxY)
|
||||||
|
if self.p[0]<minX or self.p[0]>maxX or self.p[1]<minY or self.p[1]>maxY:
|
||||||
|
return False
|
||||||
|
j=len(polygon)-1
|
||||||
|
for i in range(len(polygon)):
|
||||||
|
if ((polygon[i][1]>self.p[1])!=(polygon[j][1]>self.p[1]) and (self.p[0]<(polygon[j][0]-polygon[i][0])*(self.p[1]-polygon[i][1])/( polygon[j][1] - polygon[i][1] ) + polygon[i][0])):
|
||||||
|
inside =not inside
|
||||||
|
j=i
|
||||||
|
return inside
|
||||||
|
|
||||||
|
class Polygen(inkex.EffectExtension):
|
||||||
|
|
||||||
|
def add_arguments(self, pars):
|
||||||
|
pars.add_argument("--usermenu")
|
||||||
|
pars.add_argument("--polysides", type=int, default=6, help="Number of Polygon Sides")
|
||||||
|
pars.add_argument("--tabangle", type=float, default=45.0, help="Angle of tab edges in degrees")
|
||||||
|
pars.add_argument("--tabheight", type=float, default=0.4,help="Height of tab in dimensional units")
|
||||||
|
pars.add_argument("--dashlength", type=float, default=0.1,help="Length of dashline in dimentional units (zero for solid line)")
|
||||||
|
pars.add_argument("--unit", default="in", help="Dimensional units of selected paths")
|
||||||
|
pars.add_argument("--generate_decorative_wrapper", type=inkex.Boolean, default=False, help="Generate decorative wrapper")
|
||||||
|
pars.add_argument("--cosmetic_dash_style", type=inkex.Boolean, default=False, help="Cosmetic dash lines")
|
||||||
|
pars.add_argument("--color_solid", type=Color, default='4278190335', help="Solid line color")
|
||||||
|
pars.add_argument("--color_dash", type=Color, default='65535', help="Solid line dash")
|
||||||
|
|
||||||
|
|
||||||
|
#draw SVG line segment(s) between the given (raw) points
|
||||||
|
def drawline(self, dstr, name, parent, sstr=None):
|
||||||
|
line_style = {'stroke':'{}','stroke-width':'1','fill':'none'.format(self.options.color_solid)}
|
||||||
|
if sstr == None:
|
||||||
|
stylestr = str(inkex.Style(line_style))
|
||||||
|
else:
|
||||||
|
stylestr = sstr
|
||||||
|
el = parent.add(inkex.PathElement())
|
||||||
|
el.path = dstr
|
||||||
|
el.style = sstr
|
||||||
|
el.label = name
|
||||||
|
|
||||||
|
def makepoly(self, toplength, numpoly):
|
||||||
|
r = toplength/(2*math.sin(math.pi/numpoly))
|
||||||
|
pstr = ''
|
||||||
|
for ppoint in range(0,numpoly):
|
||||||
|
xn = r*math.cos(2*math.pi*ppoint/numpoly)
|
||||||
|
yn = r*math.sin(2*math.pi*ppoint/numpoly)
|
||||||
|
if ppoint == 0:
|
||||||
|
pstr = 'M '
|
||||||
|
else:
|
||||||
|
pstr += ' L '
|
||||||
|
pstr += str(xn) + ',' + str(yn)
|
||||||
|
pstr = pstr + ' Z'
|
||||||
|
return pstr
|
||||||
|
|
||||||
|
def insidePath(self, path, p):
|
||||||
|
point = pnPoint((p.x, p.y))
|
||||||
|
pverts = []
|
||||||
|
for pnum in path:
|
||||||
|
pverts.append((pnum.x, pnum.y))
|
||||||
|
isInside = point.InPolygon(pverts, True)
|
||||||
|
return isInside # True if point p is inside path
|
||||||
|
|
||||||
|
def makescore(self, pt1, pt2, dashlength):
|
||||||
|
# Draws a dashed line of dashlength between two points
|
||||||
|
# Dash = dashlength (in inches) space followed by dashlength mark
|
||||||
|
# if dashlength is zero, we want a solid line
|
||||||
|
apt1 = inkex.paths.Line(0.0,0.0)
|
||||||
|
apt2 = inkex.paths.Line(0.0,0.0)
|
||||||
|
ddash = ''
|
||||||
|
if math.isclose(dashlength, 0.0):
|
||||||
|
#inkex.utils.debug("Draw solid dashline")
|
||||||
|
ddash = ' M '+str(pt1.x)+','+str(pt1.y)+' L '+str(pt2.x)+','+str(pt2.y)
|
||||||
|
else:
|
||||||
|
if math.isclose(pt1.y, pt2.y):
|
||||||
|
#inkex.utils.debug("Draw horizontal dashline")
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
xcushion = pt2.x - dashlength
|
||||||
|
xpt = pt1.x
|
||||||
|
ypt = pt1.y
|
||||||
|
else:
|
||||||
|
xcushion = pt1.x - dashlength
|
||||||
|
xpt = pt2.x
|
||||||
|
ypt = pt2.y
|
||||||
|
ddash = ''
|
||||||
|
done = False
|
||||||
|
while not(done):
|
||||||
|
if (xpt + dashlength*2) <= xcushion:
|
||||||
|
xpt = xpt + dashlength
|
||||||
|
ddash = ddash + ' M ' + str(xpt) + ',' + str(ypt)
|
||||||
|
xpt = xpt + dashlength
|
||||||
|
ddash = ddash + ' L ' + str(xpt) + ',' + str(ypt)
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
elif math.isclose(pt1.x, pt2.x):
|
||||||
|
#inkex.utils.debug("Draw vertical dashline")
|
||||||
|
if pt1.y < pt2.y:
|
||||||
|
ycushion = pt2.y - dashlength
|
||||||
|
xpt = pt1.x
|
||||||
|
ypt = pt1.y
|
||||||
|
else:
|
||||||
|
ycushion = pt1.y - dashlength
|
||||||
|
xpt = pt2.x
|
||||||
|
ypt = pt2.y
|
||||||
|
ddash = ''
|
||||||
|
done = False
|
||||||
|
while not(done):
|
||||||
|
if(ypt + dashlength*2) <= ycushion:
|
||||||
|
ypt = ypt + dashlength
|
||||||
|
ddash = ddash + ' M ' + str(xpt) + ',' + str(ypt)
|
||||||
|
ypt = ypt + dashlength
|
||||||
|
ddash = ddash + ' L ' + str(xpt) + ',' + str(ypt)
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
else:
|
||||||
|
#inkex.utils.debug("Draw sloping dashline")
|
||||||
|
if pt1.y > pt2.y:
|
||||||
|
apt1.x = pt1.x
|
||||||
|
apt1.y = pt1.y
|
||||||
|
apt2.x = pt2.x
|
||||||
|
apt2.y = pt2.y
|
||||||
|
else:
|
||||||
|
apt1.x = pt2.x
|
||||||
|
apt1.y = pt2.y
|
||||||
|
apt2.x = pt1.x
|
||||||
|
apt2.y = pt1.y
|
||||||
|
m = (apt1.y-apt2.y)/(apt1.x-apt2.x)
|
||||||
|
theta = math.atan(m)
|
||||||
|
msign = (m>0) - (m<0)
|
||||||
|
ycushion = apt2.y + dashlength*math.sin(theta)
|
||||||
|
xcushion = apt2.x + msign*dashlength*math.cos(theta)
|
||||||
|
ddash = ''
|
||||||
|
xpt = apt1.x
|
||||||
|
ypt = apt1.y
|
||||||
|
done = False
|
||||||
|
while not(done):
|
||||||
|
nypt = ypt - dashlength*2*math.sin(theta)
|
||||||
|
nxpt = xpt - msign*dashlength*2*math.cos(theta)
|
||||||
|
if (nypt >= ycushion) and (((m<0) and (nxpt <= xcushion)) or ((m>0) and (nxpt >= xcushion))):
|
||||||
|
# move to end of space / beginning of mark
|
||||||
|
xpt = xpt - msign*dashlength*math.cos(theta)
|
||||||
|
ypt = ypt - msign*dashlength*math.sin(theta)
|
||||||
|
ddash = ddash + ' M ' + str(xpt) + ',' + str(ypt)
|
||||||
|
# draw the mark
|
||||||
|
xpt = xpt - msign*dashlength*math.cos(theta)
|
||||||
|
ypt = ypt - msign*dashlength*math.sin(theta)
|
||||||
|
ddash = ddash + ' L ' + str(xpt) + ',' + str(ypt)
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
return ddash
|
||||||
|
|
||||||
|
def detectIntersect(self, x1, y1, x2, y2, x3, y3, x4, y4):
|
||||||
|
td = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
|
||||||
|
if td == 0:
|
||||||
|
# These line segments are parallel
|
||||||
|
return False
|
||||||
|
t = ((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/td
|
||||||
|
if (0.0 <= t) and (t <= 1.0):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def makeTab(self, tpath, pt1, pt2, tabht, taba):
|
||||||
|
# tpath - the pathstructure containing pt1 and pt2
|
||||||
|
# pt1, pt2 - the two points where the tab will be inserted
|
||||||
|
# tabht - the height of the tab
|
||||||
|
# taba - the angle of the tab sides
|
||||||
|
# returns the two tab points in order of closest to pt1
|
||||||
|
tpt1 = inkex.paths.Line(0.0,0.0)
|
||||||
|
tpt2 = inkex.paths.Line(0.0,0.0)
|
||||||
|
currTabHt = tabht
|
||||||
|
currTabAngle = taba
|
||||||
|
testAngle = 1.0
|
||||||
|
testHt = currTabHt * 0.001
|
||||||
|
adjustTab = 0
|
||||||
|
tabDone = False
|
||||||
|
while not tabDone:
|
||||||
|
# Let's find out the orientation of the tab
|
||||||
|
if math.isclose(pt1.x, pt2.x):
|
||||||
|
# It's vertical. Let's try the right side
|
||||||
|
if pt1.y < pt2.y:
|
||||||
|
tpt1.x = pt1.x + testHt
|
||||||
|
tpt2.x = pt2.x + testHt
|
||||||
|
tpt1.y = pt1.y + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.y = pt2.y - testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.x = pt1.x - currTabHt
|
||||||
|
tpt2.x = pt2.x - currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.x = pt1.x + currTabHt
|
||||||
|
tpt2.x = pt2.x + currTabHt
|
||||||
|
tpt1.y = pt1.y + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.y = pt2.y - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
else: # pt2.y < pt1.y
|
||||||
|
tpt1.x = pt1.x + testHt
|
||||||
|
tpt2.x = pt2.x + testHt
|
||||||
|
tpt1.y = pt1.y - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.y = pt2.y + testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.x = pt1.x - currTabHt
|
||||||
|
tpt2.x = pt2.x - currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.x = pt1.x + currTabHt
|
||||||
|
tpt2.x = pt2.x + currTabHt
|
||||||
|
tpt1.y = pt1.y - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.y = pt2.y + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
elif math.isclose(pt1.y, pt2.y):
|
||||||
|
# It's horizontal. Let's try the top
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
else: # pt2.x < pt1.x
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
|
||||||
|
else: # the orientation is neither horizontal nor vertical
|
||||||
|
# Let's get the slope of the line between the points
|
||||||
|
# Because Inkscape's origin is in the upper-left corner,
|
||||||
|
# a positive slope (/) will yield a negative value
|
||||||
|
slope = (pt2.y - pt1.y)/(pt2.x - pt1.x)
|
||||||
|
# Let's get the angle to the horizontal
|
||||||
|
theta = math.degrees(math.atan(slope))
|
||||||
|
# Let's construct a horizontal tab
|
||||||
|
seglength = math.sqrt((pt1.x-pt2.x)**2 +(pt1.y-pt2.y)**2)
|
||||||
|
if slope < 0.0:
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
else: # pt1.x > pt2.x
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
else: # slope > 0.0
|
||||||
|
if pt1.x < pt2.x:
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
else: # pt1.x > pt2.x
|
||||||
|
tpt1.y = pt1.y - testHt
|
||||||
|
tpt2.y = pt2.y - testHt
|
||||||
|
tpt1.x = pt1.x - testHt/math.tan(math.radians(testAngle))
|
||||||
|
tpt2.x = pt2.x + testHt/math.tan(math.radians(testAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
pnpt1 = inkex.paths.Move(tpt1.x, tpt1.y)
|
||||||
|
pnpt2 = inkex.paths.Move(tpt2.x, tpt2.y)
|
||||||
|
if ((not tpath.enclosed) and (self.insidePath(tpath.path, pnpt1) or self.insidePath(tpath.path, pnpt2))) or \
|
||||||
|
(tpath.enclosed and ((not self.insidePath(tpath.path, pnpt1)) and (not self.insidePath(tpath.path, pnpt2)))):
|
||||||
|
tpt1.y = pt1.y + currTabHt
|
||||||
|
tpt2.y = pt2.y + currTabHt
|
||||||
|
else:
|
||||||
|
tpt1.y = pt1.y - currTabHt
|
||||||
|
tpt2.y = pt2.y - currTabHt
|
||||||
|
tpt1.x = pt1.x - currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tpt2.x = pt2.x + currTabHt/math.tan(math.radians(currTabAngle))
|
||||||
|
tl1 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl1 += [('L', [tpt1.x, tpt1.y])]
|
||||||
|
ele1 = inkex.Path(tl1)
|
||||||
|
tl2 = [('M', [pt1.x,pt1.y])]
|
||||||
|
tl2 += [('L', [tpt2.x, tpt2.y])]
|
||||||
|
ele2 = inkex.Path(tl2)
|
||||||
|
thetal1 = ele1.rotate(theta, [pt1.x,pt1.y])
|
||||||
|
thetal2 = ele2.rotate(theta, [pt2.x,pt2.y])
|
||||||
|
tpt1.x = thetal1[1].x
|
||||||
|
tpt1.y = thetal1[1].y
|
||||||
|
tpt2.x = thetal2[1].x
|
||||||
|
tpt2.y = thetal2[1].y
|
||||||
|
# Check to see if any tabs intersect each other
|
||||||
|
if self.detectIntersect(pt1.x, pt1.y, tpt1.x, tpt1.y, pt2.x, pt2.y, tpt2.x, tpt2.y):
|
||||||
|
# Found an intersection.
|
||||||
|
if adjustTab == 0:
|
||||||
|
# Try increasing the tab angle in one-degree increments
|
||||||
|
currTabAngle = currTabAngle + 1.0
|
||||||
|
if currTabAngle > 88.0: # We're not increasing the tab angle above 89 degrees
|
||||||
|
adjustTab = 1
|
||||||
|
currTabAngle = taba
|
||||||
|
if adjustTab == 1:
|
||||||
|
# So, try reducing the tab height in 20% increments instead
|
||||||
|
currTabHt = currTabHt - tabht*0.2 # Could this lead to a zero tab_height?
|
||||||
|
if currTabHt <= 0.0:
|
||||||
|
# Give up
|
||||||
|
currTabHt = tabht
|
||||||
|
adjustTab = 2
|
||||||
|
if adjustTab == 2:
|
||||||
|
tabDone = True # Just show the failure
|
||||||
|
else:
|
||||||
|
tabDone = True
|
||||||
|
|
||||||
|
return tpt1,tpt2
|
||||||
|
|
||||||
|
|
||||||
|
def effect(self):
|
||||||
|
scale = self.svg.unittouu('1'+self.options.unit)
|
||||||
|
layer = self.svg.get_current_layer()
|
||||||
|
polysides = int(self.options.polysides)
|
||||||
|
tab_angle = float(self.options.tabangle)
|
||||||
|
tab_height = float(self.options.tabheight) * scale
|
||||||
|
dashlength = float(self.options.dashlength) * scale
|
||||||
|
npaths = []
|
||||||
|
elems = []
|
||||||
|
sstr = None
|
||||||
|
radpath = 0 # Initial assumption is that first path is the radius
|
||||||
|
outlpath = 1 # and second path is the outline
|
||||||
|
yorient = True # assuming we are revolving around the Y axis
|
||||||
|
for selem in self.svg.selection.filter(inkex.PathElement):
|
||||||
|
elems.append(selem)
|
||||||
|
if len(elems) == 0:
|
||||||
|
raise inkex.AbortExtension("ERROR: Nothing selected")
|
||||||
|
elif len(elems) != 2:
|
||||||
|
raise inkex.AbortExtension("ERROR: Select only the outline and its radius line\n"\
|
||||||
|
+"Nothing more or less.")
|
||||||
|
for elem in elems: # for each path
|
||||||
|
escale = 1.0
|
||||||
|
if 'transform' in elem.attrib:
|
||||||
|
transforms = elem.attrib['transform'].split()
|
||||||
|
for tf in transforms:
|
||||||
|
if tf.startswith('scale'):
|
||||||
|
escale = float(tf.split('(')[1].split(')')[0])
|
||||||
|
last_letter = 'Z'
|
||||||
|
|
||||||
|
parent = elem.getparent()
|
||||||
|
#if parent != self.svg.root:
|
||||||
|
# elem.path.transform = elem.path.transform(parent.composed_transform())
|
||||||
|
elementPath = elem.path.to_non_shorthand().to_absolute()
|
||||||
|
|
||||||
|
for ptoken in elementPath: # For each point in the path
|
||||||
|
ptx2 = None
|
||||||
|
pty2 = None
|
||||||
|
if ptoken.letter == 'M': # Starting point
|
||||||
|
# Hold this point in case we receive a Z
|
||||||
|
ptx1 = mx = ptoken.x * escale
|
||||||
|
pty1 = my = ptoken.y * escale
|
||||||
|
'''
|
||||||
|
Assign a structure to the new path. We assume that there is
|
||||||
|
only one path and, therefore, it isn't enclosed by a
|
||||||
|
sub-path. However, we'll suffix the ID, if we find a
|
||||||
|
sub-path.
|
||||||
|
'''
|
||||||
|
npath = pathStruct()
|
||||||
|
npath.enclosed = False
|
||||||
|
npath.id = elem.get_id()
|
||||||
|
if 'style' in elem.attrib:
|
||||||
|
npath.style = elem.attrib['style']
|
||||||
|
if not math.isclose(escale, 1.0):
|
||||||
|
lsstr = npath.style.split(';')
|
||||||
|
for stoken in range(len(lsstr)):
|
||||||
|
if lsstr[stoken].startswith('stroke-width'):
|
||||||
|
swt = lsstr[stoken].split(':')[1]
|
||||||
|
swf = str(float(swt)*escale)
|
||||||
|
lsstr[stoken] = lsstr[stoken].replace(swt, swf)
|
||||||
|
if lsstr[stoken].startswith('stroke-miterlimit'):
|
||||||
|
swt = lsstr[stoken].split(':')[1]
|
||||||
|
swf = str(float(swt)*escale)
|
||||||
|
lsstr[stoken] = lsstr[stoken].replace(swt, swf)
|
||||||
|
npath.style = ";".join(lsstr)
|
||||||
|
npath.path.append(inkex.paths.Move(ptx1,pty1))
|
||||||
|
else:
|
||||||
|
if last_letter != 'M':
|
||||||
|
ptx1 = ptx2
|
||||||
|
pty1 = pty2
|
||||||
|
if ptoken.letter == 'L':
|
||||||
|
ptx2 = ptoken.x * escale
|
||||||
|
pty2 = ptoken.y * escale
|
||||||
|
elif ptoken.letter == 'H':
|
||||||
|
ptx2 = ptoken.x * escale
|
||||||
|
pty2 = pty1
|
||||||
|
elif ptoken.letter == 'V':
|
||||||
|
ptx2 = ptx1
|
||||||
|
pty2 = ptoken.y * escale
|
||||||
|
elif ptoken.letter == 'Z':
|
||||||
|
raise inkex.AbortExtension("ERROR: Paths must be open")
|
||||||
|
else:
|
||||||
|
raise inkex.AbortExtension("ERROR: Unrecognized path command {0}. Please convert to polyline before!".format(ptoken.letter))
|
||||||
|
npath.path.append(inkex.paths.Line(ptx2,pty2))
|
||||||
|
last_letter = ptoken.letter
|
||||||
|
npaths.append(npath)
|
||||||
|
|
||||||
|
# Let's validate the input
|
||||||
|
if len(npaths[1].path) == 2:
|
||||||
|
# Our initial assumption was wrong
|
||||||
|
radpath = 1
|
||||||
|
outlpath = 0
|
||||||
|
if math.isclose(npaths[radpath].path[0].y,npaths[radpath].path[1].y):
|
||||||
|
# Guessed wrong. For now, we're just going to abort
|
||||||
|
# TODO: Support revolving around the X axis
|
||||||
|
raise inkex.AbortExtension("ERROR: This extension can only revolve about the Y axis")
|
||||||
|
'''
|
||||||
|
The model will be open at the top and the bottom, so we have to calculate
|
||||||
|
the size of the polygons that will cover them. We were given the number
|
||||||
|
of sides.
|
||||||
|
'''
|
||||||
|
dscore = '' # Used for building dashlines for model
|
||||||
|
dwscore = '' # Used for building dashlines for wrapper
|
||||||
|
if yorient:
|
||||||
|
# Make sure the outline's points are ordered in ascending Y
|
||||||
|
if npaths[outlpath].path[0].y < npaths[outlpath].path[0].y:
|
||||||
|
npaths[outlpath].path.reverse()
|
||||||
|
# construct the side panel
|
||||||
|
xpos = ypos = 0.0
|
||||||
|
lhs = [] # Left hand side of panel
|
||||||
|
rhs = [] # Right hand side of panel
|
||||||
|
for npoint in range(len(npaths[outlpath].path)):
|
||||||
|
pr = abs(npaths[radpath].path[0].x - npaths[outlpath].path[npoint].x)
|
||||||
|
pwidth = 2.0*pr*math.tan(math.pi/polysides)
|
||||||
|
pR = pr/math.cos(math.pi/polysides)
|
||||||
|
if npoint == 0:
|
||||||
|
topR = pR
|
||||||
|
topw = pwidth
|
||||||
|
lhs.append(inkex.paths.Move(xpos - pwidth/2,ypos))
|
||||||
|
rhs.append(inkex.paths.Line(xpos + pwidth/2,ypos))
|
||||||
|
else:
|
||||||
|
seglength = math.sqrt((npaths[outlpath].path[npoint-1].x - npaths[outlpath].path[npoint].x)**2 + \
|
||||||
|
(npaths[outlpath].path[npoint-1].y - npaths[outlpath].path[npoint].y)**2)
|
||||||
|
ypos += seglength
|
||||||
|
lhs.append(inkex.paths.Line(xpos - pwidth/2,ypos))
|
||||||
|
rhs.append(inkex.paths.Line(xpos + pwidth/2,ypos))
|
||||||
|
if npoint == len(npaths[outlpath].path)-1:
|
||||||
|
bottomR = pR
|
||||||
|
bottomw = pwidth
|
||||||
|
# Put score marks across the panel
|
||||||
|
for pcnt in range(len(lhs)):
|
||||||
|
if (pcnt != 0) and (pcnt != (len(lhs)-1)):
|
||||||
|
dscore += self.makescore(lhs[pcnt], rhs[pcnt], dashlength)
|
||||||
|
dwscore = dscore # wrapper only needs these scorelines
|
||||||
|
|
||||||
|
rhs.reverse() # Reverse the order so we can
|
||||||
|
cpath = pathStruct()
|
||||||
|
cpath.enclosed = False
|
||||||
|
cpath.id = 'panel'
|
||||||
|
cpath.path = lhs + rhs
|
||||||
|
# add tabs to panel
|
||||||
|
dprop = '' # Used for building the main path
|
||||||
|
dwrap = ''
|
||||||
|
for ptn in range(len(cpath.path)):
|
||||||
|
if ptn == 0:
|
||||||
|
dprop = 'M '+str(cpath.path[ptn].x)+','+str(cpath.path[ptn].y)
|
||||||
|
dwrap = 'M '+str(cpath.path[ptn].x)+','+str(cpath.path[ptn].y)
|
||||||
|
else:
|
||||||
|
if ptn > (len(npaths[outlpath].path)-1):
|
||||||
|
dscore += self.makescore(cpath.path[ptn-1], cpath.path[ptn],dashlength)
|
||||||
|
tabpt1, tabpt2 = self.makeTab(cpath, cpath.path[ptn-1], cpath.path[ptn], tab_height, tab_angle)
|
||||||
|
dprop += ' L '+str(tabpt1.x)+','+str(tabpt1.y)
|
||||||
|
dprop += ' L '+str(tabpt2.x)+','+str(tabpt2.y)
|
||||||
|
dprop += ' L '+str(cpath.path[ptn].x)+','+str(cpath.path[ptn].y)
|
||||||
|
dwrap += ' L '+str(cpath.path[ptn].x)+','+str(cpath.path[ptn].y)
|
||||||
|
if ptn == len(cpath.path)-1:
|
||||||
|
tabpt1, tabpt2 = self.makeTab(cpath, cpath.path[ptn], cpath.path[0], tab_height, tab_angle)
|
||||||
|
dprop += ' L '+str(tabpt1.x)+','+str(tabpt1.y)
|
||||||
|
dprop += ' L '+str(tabpt2.x)+','+str(tabpt2.y)
|
||||||
|
dprop += 'Z'
|
||||||
|
dscore += self.makescore(cpath.path[ptn], cpath.path[0],dashlength)
|
||||||
|
dwrap += 'Z '
|
||||||
|
if npaths[outlpath].style != None:
|
||||||
|
lsstr = npaths[outlpath].style.split(';')
|
||||||
|
for stoken in range(len(lsstr)):
|
||||||
|
if lsstr[stoken].startswith('fill'):
|
||||||
|
swt = lsstr[stoken].split(':')[1]
|
||||||
|
swf = '#eeeeee'
|
||||||
|
lsstr[stoken] = lsstr[stoken].replace(swt, swf)
|
||||||
|
else:
|
||||||
|
lsstr.append("\'fill\':\'#eeeeee\'")
|
||||||
|
sstr = ";".join(lsstr)
|
||||||
|
# lump together all the score lines
|
||||||
|
groupm = inkex.elements._groups.Group()
|
||||||
|
groupm.label = 'group0ms'
|
||||||
|
self.drawline(dprop,'model',groupm,sstr+';stroke:{}'.format(self.options.color_solid)) # Output the model
|
||||||
|
|
||||||
|
dscore_style = sstr+';stroke:{}'.format(self.options.color_dash)
|
||||||
|
if self.options.cosmetic_dash_style is True:
|
||||||
|
dscore_style += ';stroke-dasharray:{}'.format(3, 3)
|
||||||
|
self.drawline(dscore[1:],'mscore',groupm,dscore_style) # Output the scorelines separately
|
||||||
|
layer.append(groupm)
|
||||||
|
groupw = inkex.elements._groups.Group()
|
||||||
|
groupw.label = 'group0ws'
|
||||||
|
if self.options.generate_decorative_wrapper is True:
|
||||||
|
self.drawline(dwrap,'wrapper',groupw,sstr) # Output the model
|
||||||
|
self.drawline(dwscore[1:],'wscore',groupw,sstr) # Output the scorelines separately
|
||||||
|
layer.append(groupw)
|
||||||
|
|
||||||
|
# Finally, generate the top and bottom polygons
|
||||||
|
self.drawline(self.makepoly(topw, polysides),npaths[outlpath].id+"lid1",layer,sstr+';stroke:{}'.format(self.options.color_solid))
|
||||||
|
self.drawline(self.makepoly(bottomw, polysides),npaths[outlpath].id+"lid2",layer,sstr+';stroke:{}'.format(self.options.color_solid))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Polygen().run()
|
@ -585,7 +585,7 @@ class Tabgen(inkex.EffectExtension):
|
|||||||
ptx2 = mx
|
ptx2 = mx
|
||||||
pty2 = my
|
pty2 = my
|
||||||
else:
|
else:
|
||||||
raise inkex.AbortExtension("Unrecognized path command {0}".format(ptoken.letter))
|
raise inkex.AbortExtension("Unrecognized path command {0}. Please convert to polyline before!".format(ptoken.letter))
|
||||||
npath.path.append(inkex.paths.Line(ptx2,pty2))
|
npath.path.append(inkex.paths.Line(ptx2,pty2))
|
||||||
if ptoken.letter == 'Z':
|
if ptoken.letter == 'Z':
|
||||||
npaths.append(npath)
|
npaths.append(npath)
|
||||||
|
Reference in New Issue
Block a user