#!/usr/bin/env python
#
# File: graphpaper.py (Version 0.6)
# Author: Warren Weckesser
#
# This program generates graph paper. That is, it creates
# a PDF file containing just a simple pattern of one of the
# following:
# o a grid of horizontal and vertical lines
# o a grid of dots
# o a honeycomb pattern
#
# It uses the Python libraries reportlab and pygtk.
#
#
# Copyright (c) 2007 Warren Weckesser
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License Version 2 as
# published by the Free Software Foundation.
#
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
#
# You can find the complete text of the GNU General Public License
# Version 2 and other common licenses on Debian systems under
# /usr/share/common-licenses/
#
import pygtk
pygtk.require('2.0')
import gtk
import string
class GraphPaperGUI:
paper_sizes = (("letter","Letter (8.5 x 11 inch)"),
("legal", "Legal (11 x 17 inch)"),
("A4", "A4 (210 x 297 mm)"))
def close_application(self, widget, event, data=None):
gtk.main_quit()
return False
def destroy(self, widget, data=None):
gtk.main_quit()
def about(self, widget, data=None):
self.about_dialog.show()
def close_about(self, widget, data=None):
self.about_dialog.hide()
return True
def select_pattern(self, widget, data=None):
if (widget.get_active()):
self.pattern = data
if data == "square":
self.heavierline_box.set_sensitive(True)
else:
self.heavierline_box.set_sensitive(False)
def select_papersize(self, widget, data=None):
if (widget.get_active()):
self.papersize = data
def toggle_no_heavier_lines(self, widget, data=None):
if (widget.get_active()):
self.use_heavier_line_every = False
self.hl_spin_units_hbox.set_sensitive(False)
def toggle_heavier_line_every(self, widget, data=None):
if (widget.get_active()):
self.use_heavier_line_every = True
self.hl_spin_units_hbox.set_sensitive(True)
def toggle_gridspacing(self, widget, data=None):
if (widget.get_active()):
self.use_custom_grid_spacing = False
self.gridspacing = data
self.gs_spin_units_hbox.set_sensitive(False)
def toggle_custom_grid_spacing(self, widget, data=None):
if (widget.get_active()):
self.use_custom_grid_spacing = True
self.gs_spin_units_hbox.set_sensitive(True)
def toggle_bordersize(self, widget, data=None):
if (widget.get_active()):
self.borderspace = data
self.use_custom_border_size = False
self.bs_spin_units_hbox.set_sensitive(False)
def toggle_custom_border_size(self,widget, data=None):
if (widget.get_active()):
self.use_custom_border_size = True
self.bs_spin_units_hbox.set_sensitive(True)
def select_color(self, widget, data=None):
if (widget.get_active()):
self.color = data
def create(self, widget, data=None):
# Show the file dialog
self.filew.show()
def file_ok_sel(self, widget, data=None):
# OK was clicked in the file dialog.
self.filew.hide()
filename = self.filew.get_filename()
#
# Get papersize from the ComboBox cb_ps
#
ps_selection = self.cb_ps.get_active_text()
for p in GraphPaperGUI.paper_sizes:
if p[1] == ps_selection:
papersize = p[0]
break
#
# Get linecolor from the CombBox cb_clr
#
linecolor = self.cb_clr.get_active_text()
#
# Get the heavierline option
#
if self.use_heavier_line_every == True:
heavierline = self.hl_spin.get_value_as_int()
else:
heavierline = -1
#
# Get gridspacing
#
if (self.use_custom_grid_spacing == True):
gridspacing = self.gs_spin.get_value()
if self.gs_units.get_active_text() == "cm" :
gridspacing = -gridspacing
else:
gridspacing = self.gridspacing
#
# Get bordersize
#
if self.use_custom_border_size == True:
bordersize = self.bs_spin.get_value()
if self.bs_units.get_active_text() == "cm":
bordersize = -bordersize
else:
bordersize = self.borderspace
#
# Call the appropriate function to create the PDF file
#
if (self.pattern == "square"):
graphpaper(filename, papersize, heavierline, gridspacing, bordersize, linecolor)
elif (self.pattern == "dots_square"):
dots_squaregrid(filename, papersize, gridspacing, bordersize, linecolor)
else:
hexagonal(filename, papersize, gridspacing, bordersize, linecolor)
def file_cancel(self, widget, data=None):
self.filew.hide()
return True
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.close_application)
self.window.connect("destroy", self.destroy)
self.window.set_title("Graph Paper")
self.window.set_border_width(10)
icon_ok = True
try:
pb = gtk.gdk.pixbuf_new_from_file('/usr/share/pixmaps/graphpaper.xpm')
except:
icon_ok = False
if icon_ok:
self.window.set_icon(pb)
framesep = 2
itemsep = 2
bw = 4
#
# Variable name mnemonics:
# ps: papersize
# clr: line color
# hl: heavier line
# gs: grid spacing
# bs: border spacing
#
main_box = gtk.VBox(False, 0)
self.window.add(main_box)
main_box.show()
# --- Pattern -----------------------------------
pattern_frame = gtk.Frame("Pattern")
pattern_frame.show()
main_box.pack_start(pattern_frame,True,True,framesep)
boxp = gtk.VBox(False, bw)
boxp.set_border_width(bw)
boxp.show()
pattern_frame.add(boxp)
button = gtk.RadioButton(None, "Square Grid (graph paper)")
button.connect("toggled", self.select_pattern, "square")
button.set_active(True)
self.pattern = "square"
boxp.pack_start(button, True, True, 0)
button.show()
button = gtk.RadioButton(button, "Dots, Square Grid")
button.connect("toggled", self.select_pattern, "dots_square")
boxp.pack_start(button, True, True, 0)
button.show()
button = gtk.RadioButton(button, "Hexagonal Grid (honeycomb)")
button.connect("toggled", self.select_pattern, "hexagonal")
boxp.pack_start(button, True, True, 0)
button.show()
# --- Paper Size and Line Color container ----------
ps_and_clr_hbox = gtk.HBox(False,0)
main_box.pack_start(ps_and_clr_hbox,True,True,framesep)
ps_and_clr_hbox.show()
# --- Paper Size -----------------------------------
papersize_frame = gtk.Frame("Paper Size")
papersize_frame.show()
ps_and_clr_hbox.pack_start(papersize_frame,True,True,framesep)
self.cb_ps = gtk.combo_box_new_text()
for p in GraphPaperGUI.paper_sizes:
self.cb_ps.append_text(p[1])
self.cb_ps.set_active(0)
self.cb_ps.show()
papersize_frame.add(self.cb_ps)
# --- Line Color -----------------------------------
linecolor_frame = gtk.Frame("Line Color")
linecolor_frame.show()
ps_and_clr_hbox.pack_start(linecolor_frame,True,True,framesep)
self.cb_clr = gtk.combo_box_new_text()
self.cb_clr.append_text("Black")
self.cb_clr.append_text("Gray")
self.cb_clr.append_text("Red")
self.cb_clr.append_text("Green")
self.cb_clr.append_text("Blue")
self.cb_clr.append_text("Cyan")
self.cb_clr.append_text("Magenta")
self.cb_clr.append_text("Yellow")
self.cb_clr.set_active(0)
self.cb_clr.show()
linecolor_frame.add(self.cb_clr)
# --- Heavier Lines -----------------------------------
heavierline_frame = gtk.Frame("Heavier Line (for Square Grid only)")
heavierline_frame.show()
main_box.pack_start(heavierline_frame,True,True,framesep)
self.heavierline_box = gtk.VBox(False, 0)
self.heavierline_box.set_border_width(bw)
self.heavierline_box.show()
heavierline_frame.add(self.heavierline_box)
self.no_heavier_lines_btn = gtk.RadioButton(None,"No heavier lines")
self.no_heavier_lines_btn.connect("toggled", self.toggle_no_heavier_lines, -1)
self.no_heavier_lines_btn.set_active(True)
self.use_heavier_line_every = False
self.heavierline_box.pack_start(self.no_heavier_lines_btn, False, False, 0)
self.no_heavier_lines_btn.show()
custom_hl_box = gtk.HBox(False,bw)
custom_hl_box.show()
self.heavierline_box.pack_start(custom_hl_box,False,False,0)
hl_btn = gtk.RadioButton(self.no_heavier_lines_btn,"Heavier line every ")
hl_btn.connect("toggled",self.toggle_heavier_line_every,0)
custom_hl_box.pack_start(hl_btn,False,False,0)
hl_btn.show()
self.hl_spin_units_hbox = gtk.HBox(False,0)
custom_hl_box.pack_start(self.hl_spin_units_hbox,False,False,0)
self.hl_spin_units_hbox.set_sensitive(False)
self.hl_spin_units_hbox.show()
hl_adj = gtk.Adjustment(4,1,20,1,1,1)
self.hl_spin = gtk.SpinButton(hl_adj)
self.hl_spin_units_hbox.pack_start(self.hl_spin,False,False,0)
self.hl_spin.show()
hl_txt2 = gtk.Label(" lines")
self.hl_spin_units_hbox.pack_start(hl_txt2,False,False,0)
hl_txt2.show()
# --- Grid Spacing -----------------------------------
gridspacing_frame = gtk.Frame("Grid Spacing")
gridspacing_frame.show()
main_box.pack_start(gridspacing_frame,True,True,framesep)
gs_box = gtk.VBox(False,bw)
gs_box.show();
gridspacing_frame.add(gs_box)
gs_table = gtk.Table(2,4)
gs_table.set_border_width(bw)
gs_table.show()
gs_box.pack_start(gs_table,False,False,0)
button = gtk.RadioButton(None, "1/4 inch")
button.connect("toggled", self.toggle_gridspacing, 0.25)
button.set_active(True)
self.use_custom_grid_spacing = False
self.gridspacing = 0.25
gs_table.attach(button, 0,1,0,1)
button.show()
button = gtk.RadioButton(button, "1/2 inch")
button.connect("toggled", self.toggle_gridspacing, 0.5)
gs_table.attach(button,1,2,0,1)
button.show()
button = gtk.RadioButton(button, "1 inch")
button.connect("toggled", self.toggle_gridspacing, 1.0)
gs_table.attach(button,2,3,0,1)
button.show()
button = gtk.RadioButton(button, "2 inch")
button.connect("toggled", self.toggle_gridspacing, 2)
gs_table.attach(button,3,4,0,1)
button.show()
button = gtk.RadioButton(button, "0.5 cm")
button.connect("toggled", self.toggle_gridspacing, -0.5)
gs_table.attach(button,0,1,1,2)
button.show()
button = gtk.RadioButton(button, "1 cm")
button.connect("toggled", self.toggle_gridspacing, -1.0)
gs_table.attach(button,1,2,1,2)
button.show()
button = gtk.RadioButton(button, "2 cm")
button.connect("toggled", self.toggle_gridspacing, -2.0)
gs_table.attach(button,2,3,1,2)
button.show()
button = gtk.RadioButton(button, "4 cm")
button.connect("toggled", self.toggle_gridspacing, -4.0)
gs_table.attach(button,3,4,1,2)
button.show()
gs_hbox = gtk.HBox(False,0)
gs_box.pack_start(gs_hbox,False,False,0)
gs_hbox.show()
button = gtk.RadioButton(button,"Custom grid spacing ")
button.connect("toggled",self.toggle_custom_grid_spacing,0)
gs_hbox.pack_start(button,False,False,bw)
button.show()
self.gs_spin_units_hbox = gtk.HBox(False,0)
gs_hbox.pack_start(self.gs_spin_units_hbox,False,False,0)
self.gs_spin_units_hbox.set_sensitive(False)
self.gs_spin_units_hbox.show()
gs_adj = gtk.Adjustment(0.25,0.01,10.0,0.005,0.5,0.5)
self.gs_spin = gtk.SpinButton(gs_adj)
self.gs_spin.set_digits(3)
self.gs_spin_units_hbox.pack_start(self.gs_spin,False,False,0)
self.gs_spin.show()
self.gs_units = gtk.combo_box_new_text()
self.gs_units.append_text("inch")
self.gs_units.append_text("cm")
self.gs_units.set_active(0)
self.gs_spin_units_hbox.pack_start(self.gs_units,False,False,0)
self.gs_units.show()
# --- Border Size -----------------------------------
bordersize_frame = gtk.Frame("Border Size (minimum)")
bordersize_frame.show()
main_box.pack_start(bordersize_frame,True,True,framesep)
bs_box = gtk.VBox(False,0)
bordersize_frame.add(bs_box)
bs_box.show()
bs_table = gtk.Table(2,4)
bs_table.set_border_width(bw)
bs_table.show()
bs_box.pack_start(bs_table,False,False,0)
button = gtk.RadioButton(None, "1/4 inch")
button.connect("toggled", self.toggle_bordersize, 0.25)
button.set_active(True)
self.use_custom_border_size = False
self.borderspace = 0.25
bs_table.attach(button,0,1,0,1)
button.show()
button = gtk.RadioButton(button, "1/2 inch")
button.connect("toggled", self.toggle_bordersize, 0.5)
bs_table.attach(button,1,2,0,1)
button.show()
button = gtk.RadioButton(button, "1 inch")
button.connect("toggled", self.toggle_bordersize, 1.0)
bs_table.attach(button,2,3,0,1)
button.show()
button = gtk.RadioButton(button, "2 inch")
button.connect("toggled", self.toggle_bordersize, 2.0)
bs_table.attach(button,3,4,0,1)
button.show()
button = gtk.RadioButton(button, "0.5 cm")
button.connect("toggled", self.toggle_bordersize, -0.5)
bs_table.attach(button,0,1,1,2)
button.show()
button = gtk.RadioButton(button, "1 cm")
button.connect("toggled", self.toggle_bordersize, -1.0)
bs_table.attach(button,1,2,1,2)
button.show()
button = gtk.RadioButton(button, "2 cm")
button.connect("toggled", self.toggle_bordersize, -2.0)
bs_table.attach(button,2,3,1,2)
button.show()
button = gtk.RadioButton(button, "4 cm")
button.connect("toggled", self.toggle_bordersize, -4.0)
bs_table.attach(button,3,4,1,2)
button.show()
bs_hbox = gtk.HBox(False,0)
bs_box.pack_start(bs_hbox,False,False,0)
bs_hbox.show()
button = gtk.RadioButton(button,"Custom border size ")
button.connect("toggled",self.toggle_custom_border_size,0)
bs_hbox.pack_start(button,False,False,bw)
button.show()
self.bs_spin_units_hbox = gtk.HBox(False,0)
bs_hbox.pack_start(self.bs_spin_units_hbox,False,False,0)
self.bs_spin_units_hbox.set_sensitive(False)
self.bs_spin_units_hbox.show()
bs_adj = gtk.Adjustment(0.0,0,10.0,0.005,0.5,0.5)
self.bs_spin_units_hbox.show()
self.bs_spin = gtk.SpinButton(bs_adj)
self.bs_spin.set_digits(3)
self.bs_spin_units_hbox.pack_start(self.bs_spin,False,False,0)
self.bs_spin.show()
self.bs_units = gtk.combo_box_new_text()
self.bs_units.append_text("inch")
self.bs_units.append_text("cm")
self.bs_units.set_active(0)
self.bs_spin_units_hbox.pack_start(self.bs_units,False,False,0)
self.bs_units.show()
# --- Buttons -----------------------------------
bbox = gtk.HButtonBox()
bbox.set_border_width(bw)
main_box.pack_start(bbox,True,True,framesep)
bbox.set_layout(gtk.BUTTONBOX_START)
bbox.set_spacing(bw)
button = gtk.Button("Create")
button.connect("clicked",self.create, None)
button.show()
bbox.add(button)
button = gtk.Button("Close")
button.connect("clicked", self.destroy, None)
button.show()
bbox.add(button)
button = gtk.Button("About")
button.connect("clicked", self.about, None)
button.show()
bbox.add(button)
bbox.show()
self.window.show()
# --- File Selection -----------------------------------
self.filew = gtk.FileSelection("File selection")
self.filew.connect("destroy", self.file_cancel)
self.filew.connect("delete_event", self.file_cancel)
self.filew.ok_button.connect("clicked", self.file_ok_sel)
self.filew.cancel_button.connect("clicked", self.file_cancel)
self.filew.set_filename("graph.pdf")
# --- About Dialog -----------------------------------
self.about_dialog = gtk.Dialog("Graph Paper")
self.about_dialog.connect("destroy", self.close_about)
self.about_dialog.connect("delete_event", self.close_about)
abouttext = gtk.Label()
txt = "Graph Paper\n"
txt = txt + "(Version 0.6)\n"
txt = txt + "\n"
txt = txt + "Built with\nPython * ReportLab * PyGtk\n"
txt = txt + "\n"
txt = txt + "Copyright (c) 2007 Warren Weckesser\n"
txt = txt + "This program is free software; you can redistribute it and/or\n"
txt = txt + " modify it under the terms of the GNU General Public License\n"
txt = txt + " Version 2 as published by the Free Software Foundation.\n"
abouttext.set_markup(txt)
abouttext.set_justify(gtk.JUSTIFY_CENTER)
self.about_dialog.vbox.pack_start(abouttext,True,True,0)
abouttext.show()
button = gtk.Button("Close")
button.connect("clicked",self.close_about)
self.about_dialog.action_area.pack_start(button,False,False,0)
button.show()
self.about_dialog.resize(280,160)
def main(self):
gtk.main()
#
# The function graphpaper uses ReportLab to generate the PDF document.
# This function does not use any GTK code.
#
# Inputs:
# filename: This is given to the ReportLab Canvas object without being
# checked or modified.
# papersize : Must be either "letter", "legal", or "A4" (case sensitive). Actually,
# if the argument is not "letter" or "legal", the code assumes that the
# paper is A4; it does not check if the argument is actually "A4".
# heavierline: An integer. If heaverierline > 0, then every heavierline lines
# will be drawn thicker than the others. This applies to both the
# vertical and horizontal lines. Also, the size of the grid is
# adjust so the each of the number of vertical and horizontal
# grids is a multiple of heavierline, so the outermost lines will
# be drawn thicker.
# gridspacing: The spacing of the grid lines. If gridspacing > 0, the units
# are inches. If gridspacing < 0, then the units are centimeters.
# border: The size of the border to leave around the grid. Positive values
# are inches, negative values are cm.
# color: The color, as a string. It must be one of "black", "gray",
# "red", "green", "blue", "cyan", "magenta", "yellow"
#
def graphpaper(filename,papersize, heavierline, gridspacing, border, color_str):
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, legal, A4
from reportlab.lib.units import inch, cm
from reportlab.lib.colors import black, gray, red, green, blue, cyan, magenta, yellow
exec("clr = "+string.lower(color_str))
#
# Currently only three papersize options: letter, legal, or A4
#
if (papersize == "letter"):
ps = letter
elif (papersize == "legal"):
ps = legal
else:
ps = A4
#
# Negative gridspacing means cm
#
if (gridspacing < 0):
unit = cm
gs = -gridspacing
else:
unit = inch
gs = gridspacing
if (border < 0):
bunit = cm
bs = -border
else:
bunit = inch
bs = border
#
# Create the reportlab canvas
#
c = canvas.Canvas(filename,pagesize=ps)
paperwidth, paperheight = ps
spacing = gs*unit
#
# Compute the horizontal and vertical grid sizes.
#
hgrid = int((paperwidth-2*bs*bunit)/spacing)
vgrid = int((paperheight-2*bs*bunit)/spacing)
#
# If heavier lines will be drawn, we adjust hgrid and vgrid to
# be multiples of heavierline. Then the outer most grid lines
# around the whole grid will be heavy lines.
#
if (heavierline > 0):
hgrid = heavierline*(hgrid/heavierline)
vgrid = heavierline*(vgrid/heavierline)
#
# These are the actual width and height of the grid (in points)
#
actualgraphwidth = hgrid*spacing
actualgraphheight = vgrid*spacing
#
# If we are not filling the page, we move the origin so that
# the grid is centered.
#
hoffset = (paperwidth-actualgraphwidth)/2.0
voffset = (paperheight-actualgraphheight)/2.0
c.translate(hoffset,voffset)
#
# The next two if statements check if we might end up trying to
# draw the lines across the entire page. If so, subtract one
# from the lengths.
#
if (actualgraphheight == paperheight):
actualgraphheight = actualgraphheight - 1
if (actualgraphwidth == paperwidth):
actualgraphwidth = actualgraphwidth - 1
c.setStrokeColor(clr)
c.setLineWidth(0.5)
m = heavierline
#
# Draw the vertical lines
#
for i in range(hgrid+1):
if (m > 0 and i % m == 0):
c.setLineWidth(1.0)
else:
c.setLineWidth(0.5)
if (i*spacing == paperwidth):
x = i*spacing-1
else:
x = i*spacing
c.line(x,0,x,actualgraphheight)
#
# Draw the horizontal lines
#
for i in range(vgrid+1):
if (m > 0 and i % m == 0):
c.setLineWidth(1.0)
else:
c.setLineWidth(0.5)
if (i*spacing == paperheight):
y = i*spacing - 1
else:
y = i*spacing
c.line(0,y,actualgraphwidth,y)
#
# Call the ReportLab canvas functions to create the file.
#
c.showPage()
c.save()
#
# The function dots_squaregrid uses ReportLab to generate the PDF document.
# This function does not use any GTK code.
#
# Inputs:
# filename: This is given to the ReportLab Canvas object without being
# checked or modified.
# papersize : Must be either "letter", "legal", or "A4" (case sensitive). Actually,
# if the argument is not "letter" or "legal", the code assumes that the
# paper is A4; it does not check if the argument is actually "A4".
# gridspacing: The spacing of the grid lines. If gridspacing > 0, the units
# are inches. If gridspacing < 0, then the units are centimeters.
# border: The size of the border to leave around the grid. Positive values
# are inches, negative values are cm.
# color: The color, as a string. It must be one of "black", "gray",
# "red", "green", "blue", "cyan", "magenta", "yellow"
#
def dots_squaregrid(filename,papersize, gridspacing, border, color_str):
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, legal, A4
from reportlab.lib.units import inch, cm
from reportlab.lib.colors import black, gray, red, green, blue, cyan, magenta, yellow
#
# For now, the dot size is hardwired.
#
dotsize = 1;
exec("clr = "+string.lower(color_str))
#
# Currently only three papersize options: letter, legal, or A4
#
if (papersize == "letter"):
ps = letter
elif (papersize == "legal"):
ps = legal
else:
ps = A4
#
# Negative gridspacing means cm
#
if (gridspacing < 0):
unit = cm
gs = -gridspacing
else:
unit = inch
gs = gridspacing
if (border < 0):
bunit = cm
bs = -border
else:
bunit = inch
bs = border
#
# Create the reportlab canvas
#
c = canvas.Canvas(filename,pagesize=ps)
paperwidth, paperheight = ps
spacing = gs*unit
#
# Compute the horizontal and vertical grid sizes.
#
hgrid = int((paperwidth-2*bs*bunit)/spacing)
vgrid = int((paperheight-2*bs*bunit)/spacing)
#
# These are the actual width and height of the grid (in points)
#
actualgraphwidth = hgrid*spacing
actualgraphheight = vgrid*spacing
#
# If we are not filling the page, we move the origin so that
# the grid is centered.
#
hoffset = (paperwidth-actualgraphwidth)/2.0
voffset = (paperheight-actualgraphheight)/2.0
c.translate(hoffset,voffset)
c.setStrokeColor(clr)
c.setFillColor(clr)
c.setLineWidth(0.5)
#
# Draw the vertical lines
#
for i in range(hgrid+1):
for j in range(vgrid+1):
x = i*spacing;
y = j*spacing;
c.circle(x,y,dotsize,stroke=0,fill=1)
#
# Call the ReportLab canvas functions to create the file.
#
c.showPage()
c.save()
#
#
# The function hexagonal uses ReportLab to generate the PDF document.
# This function does not use any GTK code.
#
# Inputs:
# filename: This is given to the ReportLab Canvas object without being
# checked or modified.
# papersize: Must be either "letter", "legal", or "A4" (case sensitive). Actually,
# if the argument is not "letter" or "legal", the code assumes that the
# paper is A4; it does not check if the argument is actually "A4".
# gridspacing: The spacing of the hexagonal pattern. This is the distance
# between the left and right vertical sides of a hexagon.
# If gridspacing > 0, the units are inches. If gridspacing < 0,
# then the units are centimeters.
# border : The size of the border to leave around the grid. Positive values
# are inches, negative values are cm.
# color: The color, as a string. It must be one of "black", "gray",
# "red", "green", "blue", "cyan", "magenta", "yellow" (case sensitive).
#
def hexagonal(filename, papersize, gridspacing, border, color_str):
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, legal, A4
from reportlab.lib.units import inch, cm
from reportlab.lib.colors import black, gray, red, green, blue, cyan, magenta, yellow
sqrt3 = 1.732
exec("clr = "+string.lower(color_str))
#
# Currently only three papersize options: letter, legal, or A4
#
if (papersize == "letter"):
ps = letter
elif (papersize == "legal"):
ps = legal
else:
ps = A4
#
# Negative gridspacing means cm
#
if (gridspacing < 0):
unit = cm
gs = -gridspacing
else:
unit = inch
gs = gridspacing
if (border < 0):
bunit = cm
bs = -border
else:
bunit = inch
bs = border
#
# Create the reportlab canvas
#
c = canvas.Canvas(filename,pagesize=ps)
paperwidth, paperheight = ps
spacing = gs*unit
#
# Adjust hgrid and vgrid to provide a border of width at least the
# size of gridborder multiples of the grid spacing.
#
uwidth = paperwidth - 2*bs*bunit
uheight = paperheight - 2*bs*bunit
hgrid = int(uwidth/spacing)
# vgrid = int(2*paperheight/(sqrt3*spacing)) - 2*gridborder
vgrid = int((uheight-spacing/(2*sqrt3))*2*sqrt3/(3*spacing))
#
# These are the actual width and height of the grid (in points)
#
actualgraphwidth = hgrid*spacing
## actualgraphheight = vgrid*sqrt3*spacing/2.0
actualgraphheight = (1.5*vgrid + 0.5)*spacing/sqrt3
#
# Translate the coordinates so that the origin is at the center
# of the lower left hexagon.
#
hoffset = (paperwidth-actualgraphwidth)/2.0 + spacing/2.0
voffset = (paperheight-actualgraphheight)/2.0 + spacing/sqrt3
c.translate(hoffset,voffset)
c.setStrokeColor(clr)
c.setLineWidth(0.5)
d = spacing
for j in range(vgrid):
if (j % 2 == 1):
xc_offset = d/2
m = hgrid - 1
else:
xc_offset = 0.0
m = hgrid
for i in range(m):
if (j % 2 == 1):
xc = i*d+d/2
else:
xc = i*d
yc = j*sqrt3*d/2
if ((i == 0 and j % 2 == 0) or j == vgrid-1):
c.line(xc,yc+d/sqrt3,xc-d/2, yc+sqrt3*d/6)
c.line(xc-d/2, yc+sqrt3*d/6, xc-d/2.0, yc-sqrt3*d/6.0)
c.line(xc-d/2, yc-sqrt3*d/6, xc, yc-d/sqrt3)
c.line(xc, yc-d/sqrt3, xc+d/2.0, yc-sqrt3*d/6)
if (i == m-1):
c.line(xc+d/2.0, yc-sqrt3*d/6, xc+d/2.0, yc+sqrt3*d/6)
if ((i == m-1 and j % 2 == 0) or j == vgrid-1):
c.line(xc+d/2.0,yc+sqrt3*d/6,xc,yc+d/sqrt3)
#
# Call the ReportLab canvas functions to create the file.
#
c.showPage()
c.save()
if __name__ == "__main__":
base = GraphPaperGUI()
base.main()