Added Triangular Grid
This commit is contained in:
parent
bc15ac2023
commit
e1dfb1f4f8
47
extensions/fablabchemnitz_triangular_grid.inx
Normal file
47
extensions/fablabchemnitz_triangular_grid.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>Triangular Grid</name>
|
||||
<id>fablabchemnitz.de.triangular_grid</id>
|
||||
<param name="tabs" type="notebook">
|
||||
<page name="geometry" gui-text="Geometry">
|
||||
<param name="size_unit" type="optiongroup" gui-text="Spacing units">
|
||||
<option value="px">px</option>
|
||||
<option value="pt">pt</option>
|
||||
<option value="cm">cm</option>
|
||||
<option value="mm">mm</option>
|
||||
<option value="in">in</option>
|
||||
</param>
|
||||
<param name="dm" type="float" min="1" max="1000" precision="2" gui-text="Major grid division Spacing">100.00</param>
|
||||
<param name="y_divs" type="int" min="1" max="1000" gui-text="Major vertical divisions">3</param>
|
||||
<param name="x_divs" type="int" min="1" max="1000" gui-text="Major horizontal divisions">3</param>
|
||||
<param name="grid_angle" type="float" min="0" max="180" gui-text="Grid angle [deg]">30</param>
|
||||
<param name="subdivs" type="int" min="1" max="1000" gui-text="Subdivisions per Major grid division">2</param>
|
||||
<param name="subsubdivs" type="int" min="1" max="1000" gui-text="Subsubdivs. per grid subdivision">5</param>
|
||||
</page>
|
||||
<page name="border" gui-text="Border">
|
||||
<param name="border_color" type="color" gui-text="Color">#000000ff</param>
|
||||
<param name="border_th" type="float" min="0" max="1000" gui-text="Thickness [px]">3</param>
|
||||
</page>
|
||||
<page name="major" gui-text="Major divisions">
|
||||
<param name="major_color" type="color" gui-text="Color">black</param>
|
||||
<param name="major_th" type="float" min="0" max="1000" gui-text="Thickness [px]">2</param>
|
||||
</page>
|
||||
<page name="minor" gui-text="Minor divisions">
|
||||
<param name="subdiv_color" type="color" gui-text="Color">black</param>
|
||||
<param name="subdiv_th" type="float" min="0" max="1000" gui-text="Thickness [px]">2</param>
|
||||
</page>
|
||||
<page name="subminor" gui-text="Subminor divisions">
|
||||
<param name="subsubdiv_color" type="color" gui-text="Color">#000000ff</param>
|
||||
<param name="subsubdiv_th" type="float" min="0" max="1000" gui-text="Thickness [px]">2</param>
|
||||
</page>
|
||||
</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu _name="Render" />
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
<command reldir="extensions" interpreter="python">fablabchemnitz_triangular_grid.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
267
extensions/fablabchemnitz_triangular_grid.py
Normal file
267
extensions/fablabchemnitz_triangular_grid.py
Normal file
@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env python 3
|
||||
'''
|
||||
Copyright (C) 2013 Carl Sorensen carl.d.sorensen@gmail.com
|
||||
Derived from grid_cartesion.py copyright (C) 2007 John Beard john.j.beard@gmail.com
|
||||
|
||||
|
||||
##This extension allows you to draw a Triangular grid in Inkscape.
|
||||
##There is a wide range of options including subdivision, subsubdivions
|
||||
##and angles of the triangular axes.
|
||||
##Custom line widths are also possible.
|
||||
##All elements are grouped with similar elements (eg all x-subdivs)
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
'''
|
||||
|
||||
import inkex
|
||||
from lxml import etree
|
||||
from math import *
|
||||
|
||||
def draw_SVG_line(x1, y1, x2, y2, width, stroke, name, parent):
|
||||
style = { 'stroke': stroke, 'stroke-width':str(width), 'fill': 'none' }
|
||||
line_attribs = {'style':str(inkex.Style(style)),
|
||||
inkex.addNS('label','inkscape'):name,
|
||||
'd':'M '+str(x1)+','+ str(y1) +' L '+ str(x2) + ',' + str(y2)}
|
||||
etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
|
||||
|
||||
def draw_SVG_rect(x,y,w,h, width, stroke, fill, name, parent):
|
||||
style = { 'stroke': stroke, 'stroke-width':str(width), 'fill':fill}
|
||||
rect_attribs = {'style':str(inkex.Style(style)),
|
||||
inkex.addNS('label','inkscape'):name,
|
||||
'x':str(x), 'y':str(y), 'width':str(w), 'height':str(h)}
|
||||
etree.SubElement(parent, inkex.addNS('rect','svg'), rect_attribs )
|
||||
|
||||
def colorString(pickerColor):
|
||||
longcolor = int(pickerColor) & 0xFFFFFF00
|
||||
return '#' + format(longcolor >> 8, '06X')
|
||||
|
||||
|
||||
class Grid_Triangular(inkex.Effect):
|
||||
def __init__(self):
|
||||
inkex.Effect.__init__(self)
|
||||
self.arg_parser.add_argument("--tabs")
|
||||
self.arg_parser.add_argument("--size_unit", default="mm", help="Unit for grid size")
|
||||
self.arg_parser.add_argument("--y_divs", type=int, default=3, help="Major vertical divisions")
|
||||
self.arg_parser.add_argument("--x_divs", type=int, default=3, help="Major horizontal divisions")
|
||||
self.arg_parser.add_argument("--grid_angle", type=float, default=30.0, help="Angle between X axis and triangular grid lines")
|
||||
self.arg_parser.add_argument("--dm", type=float, default=100.0, help="Major grid division spacing")
|
||||
self.arg_parser.add_argument("--subdivs", type=int, default=5, help="Subdivisions per major grid division")
|
||||
self.arg_parser.add_argument("--subsubdivs", type=int, default=2, help="Subsubdivisions per minor grid subdivision")
|
||||
self.arg_parser.add_argument("--border_th", type=float, default=3.0, help="Border Line thickness")
|
||||
self.arg_parser.add_argument("--border_color", type=int, help="Border line color")
|
||||
self.arg_parser.add_argument("--major_th", type=float, default=2.0, help="Major grid division line thickness")
|
||||
self.arg_parser.add_argument("--major_color", type=int, help="Major grid division line color")
|
||||
self.arg_parser.add_argument("--subdiv_th", type=float, default=1.0, help="Minor grid subdivision line thickness")
|
||||
self.arg_parser.add_argument("--subdiv_color", type=int, help="Minor grid subdivision line color")
|
||||
self.arg_parser.add_argument("--subsubdiv_th", type=float, default=1.0, help="Subminor grid division line thickness")
|
||||
self.arg_parser.add_argument("--subsubdiv_color", type=int, help="Subminor grid division line color")
|
||||
|
||||
def EdgePoints(self,x0, y0, theta):
|
||||
# find the intersection points of the line with the extended
|
||||
# grid bounding box.
|
||||
# Note that y is positive DOWN, not up
|
||||
theta_r = radians(theta)
|
||||
r_bot = (self.ymax-y0)/sin(theta_r)
|
||||
r_top = -y0/sin(theta_r)
|
||||
r_left = -x0/cos(theta_r)
|
||||
r_right = (self.xmax-x0)/cos(theta_r)
|
||||
return [[x0+r_left*cos(theta_r),y0+r_left*sin(theta_r)],
|
||||
[x0+r_right*cos(theta_r), y0+r_right*sin(theta_r)],
|
||||
[x0+r_bot*cos(theta_r), y0+r_bot*sin(theta_r)],
|
||||
[x0+r_top*cos(theta_r), y0+r_top*sin(theta_r)]]
|
||||
|
||||
def trimmed_coords(self, x1, y1, theta):
|
||||
#find the start and end coordinates for a grid line
|
||||
#starting at (x1, y1) with an angle of theta
|
||||
border_points = self.EdgePoints(x1, y1, theta)
|
||||
left = 0
|
||||
right = 1
|
||||
top = 3
|
||||
bottom = 2
|
||||
x=0
|
||||
y=1
|
||||
if theta > 0:
|
||||
if border_points[left][y] < 0:
|
||||
start_x = border_points[top][x]
|
||||
start_y = border_points[top][y]
|
||||
else:
|
||||
start_x = border_points[left][x]
|
||||
start_y = border_points[left][y]
|
||||
if border_points[right][y] > self.ymax:
|
||||
end_x = border_points[bottom][x]
|
||||
end_y = border_points[bottom][y]
|
||||
else:
|
||||
end_x = border_points[right][x]
|
||||
end_y = border_points[right][y]
|
||||
else:
|
||||
if border_points[left][y] > self.ymax:
|
||||
start_x = border_points[bottom][x]
|
||||
start_y = border_points[bottom][y]
|
||||
else:
|
||||
start_x = border_points[left][x]
|
||||
start_y = border_points[left][y]
|
||||
if border_points[right][y] < 0:
|
||||
end_x = border_points[top][x]
|
||||
end_y = border_points[top][y]
|
||||
else:
|
||||
end_x = border_points[right][x]
|
||||
end_y = border_points[right][y]
|
||||
return [[start_x,start_y],[end_x, end_y]]
|
||||
|
||||
def drawAngledGridLine (self, x1, y1, theta, thickness, color,
|
||||
label, groupName):
|
||||
end_points = self.trimmed_coords(x1, y1, theta)
|
||||
x_start = end_points[0][0]
|
||||
y_start = end_points[0][1]
|
||||
x_end = end_points[1][0]
|
||||
y_end = end_points[1][1]
|
||||
|
||||
if (x_start >= 0 and x_start <= self.xmax and
|
||||
y_start >= 0 and y_start <= self.ymax and
|
||||
x_end >= 0 and x_end <= self.xmax and
|
||||
y_end >= 0 and y_end <= self.ymax):
|
||||
draw_SVG_line(x_start, y_start,
|
||||
x_end, y_end,
|
||||
thickness, colorString(color), label, groupName)
|
||||
|
||||
def effect(self):
|
||||
|
||||
#find the pixel dimensions of the overall grid
|
||||
dm = self.svg.unittouu(str(self.options.dm) + self.options.size_unit)
|
||||
self.ymax = dm * self.options.y_divs #grid spacing defined along vertical
|
||||
dx = dm / (2.0 * tan(radians(self.options.grid_angle)))
|
||||
self.xmax = dx * self.options.x_divs
|
||||
dy = dm
|
||||
|
||||
# Embed grid in group
|
||||
#Put in in the centre of the current view
|
||||
t = 'translate(' + str( self.svg.namedview.center[0]- self.xmax/2.0) + ',' + \
|
||||
str( self.svg.namedview.center[1]- self.ymax/2.0) + ')'
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'Grid_Triangular:Size' + \
|
||||
str( self.options.x_divs)+'x'+str(self.options.y_divs) +
|
||||
':Angle'+str( self.options.grid_angle ),
|
||||
'transform':t }
|
||||
grid = etree.SubElement(self.svg.get_current_layer(), 'g', g_attribs)
|
||||
|
||||
#Group for major x gridlines
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'MajorXGridlines'}
|
||||
majglx = etree.SubElement(grid, 'g', g_attribs)
|
||||
|
||||
#Group for major positive theta gridlines
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'MajorPosGridlines'}
|
||||
majglp = etree.SubElement(grid, 'g', g_attribs)
|
||||
|
||||
#Group for major negative theta gridlines
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'MajorNegGridLines'}
|
||||
majgln = etree.SubElement(grid, 'g', g_attribs)
|
||||
|
||||
#Groups for minor gridlines
|
||||
if self.options.subdivs > 1:#if there are any minor gridlines
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'MinorXGridlines'}
|
||||
minglx = etree.SubElement(grid, 'g', g_attribs)
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'MinorPosGridlines'}
|
||||
minglp = etree.SubElement(grid, 'g', g_attribs)
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'MinorNegGridlines'}
|
||||
mingln = etree.SubElement(grid, 'g', g_attribs)
|
||||
|
||||
#Groups for subminor gridlines
|
||||
if self.options.subsubdivs > 1:#if there are any minor minor gridlines
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'SubMinorXGridlines'}
|
||||
mminglx = etree.SubElement(grid, 'g', g_attribs)
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'SubMinorPosGridlines'}
|
||||
mminglp = etree.SubElement(grid, 'g', g_attribs)
|
||||
g_attribs = {inkex.addNS('label','inkscape'):'SubMinorNegGridlines'}
|
||||
mmingln = etree.SubElement(grid, 'g', g_attribs)
|
||||
|
||||
draw_SVG_rect(0, 0, self.xmax, self.ymax,
|
||||
self.options.border_th,
|
||||
colorString(self.options.border_color), 'none',
|
||||
'Border', grid) #border rectangle
|
||||
|
||||
sd = self.options.subdivs #sub divs per div
|
||||
ssd = self.options.subsubdivs #subsubdivs per subdiv
|
||||
|
||||
|
||||
#DO THE HORIZONTAL DIVISONS======================================
|
||||
|
||||
for i in range(0, self.options.x_divs): #Major x divisons
|
||||
if i>0: #dont draw first line (we made a proper border)
|
||||
# Draw the vertical line
|
||||
draw_SVG_line(dx*i, 0,
|
||||
dx*i,self.ymax,
|
||||
self.options.major_th,
|
||||
colorString(self.options.major_color),
|
||||
'MajorDiv'+str(i), majglx)
|
||||
|
||||
for j in range (0, sd):
|
||||
if j>0: #not for the first loop (this loop is for the subsubdivs before the first subdiv)
|
||||
draw_SVG_line(dx*(i+j/float(sd)), 0,
|
||||
dx*(i+j/float(sd)), self.ymax,
|
||||
self.options.subdiv_th,
|
||||
colorString(self.options.subdiv_color),
|
||||
'MinorDiv'+str(i)+':'+str(j), minglx)
|
||||
|
||||
for k in range (1, ssd): #subsub divs
|
||||
draw_SVG_line(dx*(i+(j*ssd+k)/((float(sd)*ssd))) , 0,
|
||||
dx*(i+(j*ssd+k)/((float(sd)*ssd))) , self.ymax,
|
||||
self.options.subsubdiv_th,
|
||||
colorString(self.options.subsubdiv_color),
|
||||
'SubminorDiv'+str(i)+':'+str(j)+':'+str(k), mminglx)
|
||||
|
||||
#DO THE VERTICAL DIVISONS========================================
|
||||
for i in range(-self.options.x_divs-self.options.y_divs,
|
||||
self.options.x_divs+self.options.y_divs): #Major y divisons
|
||||
self.drawAngledGridLine(0, dy*i, self.options.grid_angle,
|
||||
self.options.major_th,
|
||||
self.options.major_color,
|
||||
'MajorYDivP'+str(i),
|
||||
majglp)
|
||||
self.drawAngledGridLine(0, dy*i, -self.options.grid_angle,
|
||||
self.options.major_th,
|
||||
self.options.major_color,
|
||||
'MajorYDivN'+str(i),
|
||||
majgln)
|
||||
|
||||
for j in range (0, sd): #subdivs
|
||||
if j>0:#not for the first loop (this loop is for the subsubdivs before the first subdiv)
|
||||
self.drawAngledGridLine(0, dy*(i+j/float(sd)),
|
||||
self.options.grid_angle,
|
||||
self.options.subdiv_th,
|
||||
self.options.subdiv_color,
|
||||
'MinorYDivP'+str(i),
|
||||
minglp)
|
||||
self.drawAngledGridLine(0, dy*(i+j/float(sd)),
|
||||
-self.options.grid_angle,
|
||||
self.options.subdiv_th,
|
||||
self.options.subdiv_color,
|
||||
'MinorYDivN'+str(i),
|
||||
mingln)
|
||||
for k in range (1, ssd): #subsub divs
|
||||
self.drawAngledGridLine(0, dy*(i+(j*ssd+k)/((float(sd)*ssd))),
|
||||
self.options.grid_angle,
|
||||
self.options.subsubdiv_th,
|
||||
self.options.subsubdiv_color,
|
||||
'SubMinorYDivP'+str(i),
|
||||
mminglp)
|
||||
self.drawAngledGridLine(0, dy*(i+(j*ssd+k)/((float(sd)*ssd))),
|
||||
-self.options.grid_angle,
|
||||
self.options.subsubdiv_th,
|
||||
self.options.subsubdiv_color,
|
||||
'SubMinorYDivN'+str(i),
|
||||
mmingln)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Grid_Triangular().run()
|
Reference in New Issue
Block a user