#!/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()