diff options
| author | Ted Gould <ted@gould.cx> | 2010-01-01 04:39:28 +0000 |
|---|---|---|
| committer | Ted Gould <ted@gould.cx> | 2010-01-01 04:39:28 +0000 |
| commit | c22deac174d6b12cf55640f0f5336218cb36defb (patch) | |
| tree | bcb6da5aea8703ee9ee515d6112f3f6d0f6e49f5 /share | |
| parent | Fixing some warnings/errors (diff) | |
| parent | adding 'inductiveload' to AUTHORS (diff) | |
| download | inkscape-c22deac174d6b12cf55640f0f5336218cb36defb.tar.gz inkscape-c22deac174d6b12cf55640f0f5336218cb36defb.zip | |
Keeping up with trunk
(bzr r8254.1.49)
Diffstat (limited to 'share')
| -rw-r--r-- | share/extensions/Barcode/EAN5.py | 67 | ||||
| -rw-r--r-- | share/extensions/Barcode/Makefile.am | 1 | ||||
| -rw-r--r-- | share/extensions/Barcode/__init__.py | 3 | ||||
| -rw-r--r-- | share/extensions/Makefile.am | 4 | ||||
| -rw-r--r-- | share/extensions/render_barcode.inx | 53 | ||||
| -rw-r--r-- | share/extensions/render_barcode_datamatrix.inx | 20 | ||||
| -rw-r--r-- | share/extensions/render_barcode_datamatrix.py | 654 | ||||
| -rw-r--r-- | share/extensions/wireframe_sphere.inx | 24 | ||||
| -rw-r--r-- | share/extensions/wireframe_sphere.py | 221 |
9 files changed, 1021 insertions, 26 deletions
diff --git a/share/extensions/Barcode/EAN5.py b/share/extensions/Barcode/EAN5.py new file mode 100644 index 000000000..9113566a3 --- /dev/null +++ b/share/extensions/Barcode/EAN5.py @@ -0,0 +1,67 @@ +''' +Copyright (C) 2007 Martin Owens +Copyright (C) 2009 Aaron C Spike + +Thanks to Lineaire Chez of Inkbar ( www.inkbar.lineaire.net ) + +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 +''' + +from Base import Barcode +import sys + +mapLeftFamily = [ + [ "0001101","0011001","0010011","0111101","0100011","0110001","0101111","0111011","0110111","0001011" ], #L + [ "0100111","0110011","0011011","0100001","0011101","0111001","0000101","0010001","0001001","0010111" ], #G +] +mapFamily = [ '11000','10100','10010','10001','01100','00110','00011','01010','01001','00101' ] + +startBar = '01011'; +sepBar = '01'; + +class Object(Barcode): + def encode(self, number): + result = [] + self.x += 110.0 # horizontal offset so it does not overlap EAN13 + self.y -= self.height + 5 # move the text to the top + if len(number) != 5 or not number.isdigit(): + sys.stderr.write("Can not encode '" + number + "' into EAN5 Barcode, Size must be 5 numbers only\n") + return + + check = self.getChecksum(number) + family = mapFamily[check] + + for i in range(5): + mapLeft = mapLeftFamily[int(family[i])] + result.append(mapLeft[int(number[i])]) + + self.label = number[0] + for i in range(1,5): + self.label += ' ' + number[i] + self.inclabel = self.label + return startBar + '01'.join(result) + + def getChecksum(self, number): + return sum([int(n)*int(m) for n,m in zip(number, '39393')]) % 10 + + def getStyle(self, index): + result = { 'width' : '1', 'top' : int(self.y) + self.height + 5 + int(self.fontSize()), 'write' : True } + if index==0: # White Space + result['write'] = False + elif index==1: # Black Bar + result['height'] = int(self.height) + elif index==2: # Guide Bar + result['height'] = int(self.height) + 5 + return result diff --git a/share/extensions/Barcode/Makefile.am b/share/extensions/Barcode/Makefile.am index 338c01c10..fd5f1663b 100644 --- a/share/extensions/Barcode/Makefile.am +++ b/share/extensions/Barcode/Makefile.am @@ -9,6 +9,7 @@ barcode_SCRIPTS = \ Code93.py \ EAN13.py \ EAN8.py \ + EAN5.py \ __init__.py \ RM4CC.py \ UPCA.py \ diff --git a/share/extensions/Barcode/__init__.py b/share/extensions/Barcode/__init__.py index a455c3b7c..b2257ebcb 100644 --- a/share/extensions/Barcode/__init__.py +++ b/share/extensions/Barcode/__init__.py @@ -74,6 +74,9 @@ def getBarcode(format, param={}): elif format in ['ean13', 'ucc13','jan']: import EAN13 return EAN13.Object(param) + elif format == 'ean5': + import EAN5 + return EAN5.Object(param) elif format in ['ean8', 'ucc8']: import EAN8 return EAN8.Object(param) diff --git a/share/extensions/Makefile.am b/share/extensions/Makefile.am index 14238ad31..1650923e0 100644 --- a/share/extensions/Makefile.am +++ b/share/extensions/Makefile.am @@ -96,6 +96,7 @@ extensions = \ radiusrand.py \ restack.py \ render_barcode.py \ + render_barcode_datamatrix.py \ render_alphabetsoup.py \ render_alphabetsoup_config.py \ rtree.py \ @@ -131,6 +132,7 @@ extensions = \ web-set-att.py \ web-transmit-att.py \ whirl.py \ + wireframe_sphere.py \ wmf_output.py \ yocto_css.py @@ -222,6 +224,7 @@ modules = \ ps_input.inx \ radiusrand.inx \ render_barcode.inx \ + render_barcode_datamatrix.inx \ render_alphabetsoup.inx \ restack.inx \ rubberstretch.inx \ @@ -249,6 +252,7 @@ modules = \ web-set-att.inx \ web-transmit-att.inx \ whirl.inx \ + wireframe_sphere.inx \ wmf_input.inx \ wmf_output.inx \ xaml2svg.inx diff --git a/share/extensions/render_barcode.inx b/share/extensions/render_barcode.inx index 610c8bf19..91dd1bbe4 100644 --- a/share/extensions/render_barcode.inx +++ b/share/extensions/render_barcode.inx @@ -1,29 +1,30 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Barcode</_name> - <id>org.inkscape.render.barcode</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">render_barcode.py</dependency> - <param name="type" type="enum" _gui-text="Barcode Type:"> - <item value="ean8">EAN8</item> - <item value="ean13">EAN13</item> - <item value="upca">UPC-A</item> - <item value="upce">UPC-E</item> - <item value="code39">Code39</item> - <item value="code39ext">Code39Ext</item> - <item value="code93">Code93</item> - <item value="code128">Code128</item> - <item value="rm4scc">RM4CC / RM4SCC</item> - </param> - <param name="text" type="string" _gui-text="Barcode Data:"></param> - <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">render_barcode.py</command> - </script> + <_name>Barcode</_name> + <id>org.inkscape.render.barcode</id> + <dependency type="executable" location="extensions">inkex.py</dependency> + <dependency type="executable" location="extensions">render_barcode.py</dependency> + <param name="type" type="enum" _gui-text="Barcode Type:"> + <item value="ean8">EAN8</item> + <item value="ean13">EAN13</item> + <item value="ean5">EAN5</item> + <item value="upca">UPC-A</item> + <item value="upce">UPC-E</item> + <item value="code39">Code39</item> + <item value="code39ext">Code39Ext</item> + <item value="code93">Code93</item> + <item value="code128">Code128</item> + <item value="rm4scc">RM4CC / RM4SCC</item> + </param> + <param name="text" type="string" _gui-text="Barcode Data:"></param> + <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">render_barcode.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/render_barcode_datamatrix.inx b/share/extensions/render_barcode_datamatrix.inx new file mode 100644 index 000000000..ea2aa4705 --- /dev/null +++ b/share/extensions/render_barcode_datamatrix.inx @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Barcode - Datamatrix</_name> + <id>il.datamatrix</id> + <dependency type="executable" location="extensions">render_barcode_datamatrix.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="text" type="string" _gui-text="Text">Inkscape</param> + <param name="rows" type="int" min="8" max="144" _gui-text="Rows">10</param> + <param name="cols" type="int" min="10" max="144" _gui-text="Cols">10</param> + <param name="size" type="int" min="1" max="1000" _gui-text="Square Size / px">4</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">render_barcode_datamatrix.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/render_barcode_datamatrix.py b/share/extensions/render_barcode_datamatrix.py new file mode 100644 index 000000000..5db552d91 --- /dev/null +++ b/share/extensions/render_barcode_datamatrix.py @@ -0,0 +1,654 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +''' +Copyright (C) 2009 John Beard john.j.beard@gmail.com + +######DESCRIPTION###### + +This extension renders a DataMatrix 2D barcode, as specified in +BS ISO/IEC 16022:2006. Only ECC200 codes are considered, as these are the only +ones recommended for an "open" system. + +The size of the DataMatrix is variable between 10x10 to 144x144 + +The absolute size of the DataMatrix modules (the little squares) is also +variable. + +If more data is given than can be contained in one DataMatrix, +more than one DataMatrices will be produced. + +Text is encoded as ASCII (the standard provides for other options, but these are +not implemented). Consecutive digits are encoded in a compressed form, halving +the space required to store them. + +The basis processing flow is; + * Convert input string to codewords (modified ASCII and compressed digits) + * Split codewords into blocks of the right size for Reed-Solomon coding + * Interleave the blocks if required + * Apply Reed-Solomon coding + * De-interleave the blocks if required + * Place the codewords into the matrix bit by bit + * Render the modules in the matrix as squares + +######LICENCE####### +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 + +######VERSION HISTORY##### + Ver. Date Notes + + 0.50 2009-10-25 Full functionality, up to 144x144. + ASCII and compressed digit encoding only. +''' + +import inkex, simplestyle + +import gettext +_ = gettext.gettext + +#ENCODING ROUTINES =================================================== +# Take an input string and convert it to a sequence (or sequences) +# of codewords as specified in ISO/IEC 16022:2006 (section 5.2.3) +#===================================================================== + +#create a 2d list corresponding to the 1's and 0s of the DataMatrix +def encode(text, (nrow, ncol) ): + #retreive the parameters of this size of DataMatrix + data_nrow, data_ncol, reg_row, reg_col, nd, nc, inter = get_parameters( nrow, ncol ) + + if not ((nrow == 144) and (ncol == 144)): #we have a regular datamatrix + size144 = False + else: #special handling will be required by get_codewords() + size144 = True + + #generate the codewords including padding and ECC + codewords = get_codewords( text, nd, nc, inter, size144 ) + + # break up into separate arrays if more than one DataMatrix is needed + module_arrays = [] + for codeword_stream in codewords: #for each datamatrix + bit_array = place_bits(codeword_stream, (data_nrow*reg_row, data_ncol*reg_col)) #place the codewords' bits across the array as modules + module_arrays.append(add_finder_pattern( bit_array, data_nrow, data_ncol, reg_row, reg_col )) #add finder patterns around the modules + + return module_arrays + +#return parameters for the selected datamatrix size +# data_nrow number of rows in each data region +# data_ncol number of cols in each data region +# reg_row number of rows of data regions +# reg_col number of cols of data regions +# nd number of data codewords per reed-solomon block +# nc number of ECC codewords per reed-solomon block +# inter number of interleaved Reed-Solomon blocks +def get_parameters(nrow, ncol): + + #SQUARE SYMBOLS + if ( nrow == 10 and ncol == 10 ): + return 8, 8, 1, 1, 3, 5, 1 + elif ( nrow == 12 and ncol == 12 ): + return 10, 10, 1, 1, 5, 7, 1 + elif ( nrow == 14 and ncol == 14 ): + return 12, 12, 1, 1, 8, 10, 1 + elif ( nrow == 16 and ncol == 16 ): + return 14, 14, 1, 1, 12, 12, 1 + elif ( nrow == 18 and ncol == 18 ): + return 16, 16, 1, 1, 18, 14, 1 + elif ( nrow == 20 and ncol == 20 ): + return 18, 18, 1, 1, 22, 18, 1 + elif ( nrow == 22 and ncol == 22 ): + return 18, 18, 1, 1, 30, 20, 1 + elif ( nrow == 24 and ncol == 24 ): + return 22, 22, 1, 1, 36, 24, 1 + elif ( nrow == 26 and ncol == 26 ): + return 24, 24, 1, 1, 44, 28, 1 + elif ( nrow == 32 and ncol == 32 ): + return 14, 14, 2, 2, 62, 36, 1 + elif ( nrow == 36 and ncol == 36 ): + return 16, 16, 2, 2, 86, 42, 1 + elif ( nrow == 40 and ncol == 40): + return 18, 18, 2, 2, 114, 48, 1 + elif ( nrow == 44 and ncol == 44): + return 20, 20, 2, 2, 144, 56, 1 + elif ( nrow == 48 and ncol == 48 ): + return 22, 22, 2, 2, 174, 68, 1 + + elif ( nrow == 52 and ncol == 52 ): + return 24, 24, 2, 2, 102, 42, 2 + elif ( nrow == 64 and ncol == 64 ): + return 16, 16, 4, 4, 140, 56, 2 + + elif ( nrow == 72 and ncol == 72 ): + return 16, 16, 4, 4, 92, 36, 4 + elif ( nrow == 80 and ncol == 80 ): + return 18, 18, 4, 4, 114, 48, 4 + elif ( nrow == 88 and ncol == 88 ): + return 20, 20, 4, 4, 144, 56, 4 + elif ( nrow == 96 and ncol == 96 ): + return 22, 22, 4, 4, 174, 68, 4 + + elif ( nrow == 104 and ncol == 104 ): + return 24, 24, 4, 4, 136, 56, 6 + elif ( nrow == 120 and ncol == 120): + return 18, 18, 6, 6, 175, 68, 6 + + elif ( nrow == 132 and ncol == 132): + return 20, 20, 6, 6, 163, 62, 8 + + elif (nrow == 144 and ncol == 144): + return 22, 22, 6, 6, 0, 0, 0 #there are two separate sections of the data matrix with + #different interleaving and reed-solomon parameters. + #this will be handled separately + + #RECTANGULAR SYMBOLS + elif ( nrow == 8 and ncol == 18 ): + return 6, 16, 1, 1, 5, 7, 1 + elif ( nrow == 8 and ncol == 32 ): + return 6, 14, 1, 2, 10, 11, 1 + elif ( nrow == 12 and ncol == 26 ): + return 10, 24, 1, 1, 16, 14, 1 + elif ( nrow == 12 and ncol == 36 ): + return 10, 16, 1, 2, 22, 18, 1 + elif ( nrow == 16 and ncol == 36 ): + return 14, 16, 1, 2, 32, 24, 1 + elif ( nrow == 16 and ncol == 48 ): + return 14, 22, 1, 2, 49, 28, 1 + + #RETURN ERROR + else: + inkex.errormsg(_('Unrecognised DataMatrix size')) + + return None + +# CODEWORD STREAM GENERATION ========================================= +#take the text input and return the codewords, +#including the Reed-Solomon error-correcting codes. +#===================================================================== + +def get_codewords( text, nd, nc, inter, size144 ): + #convert the data to the codewords + data = encode_to_ascii( text ) + + if not size144: #render a "normal" datamatrix + data_blocks = partition_data(data, nd*inter) #partition into data blocks of length nd*inter -> inter Reed-Solomon block + + data_blocks = interleave( data_blocks, inter) # interleave consecutive inter blocks if required + + data_blocks = reed_solomon(data_blocks, nd, nc) #generate and append the Reed-Solomon codewords + + data_blocks = combine_interleaved(data_blocks, inter, nd, nc, False) #concatenate Reed-Solomon blocks bound for the same datamatrix + + else: #we have a 144x144 datamatrix + data_blocks = partition_data(data, 1558) #partition the data into datamtrix-sized chunks (1558 =156*8 + 155*2 ) + + for i in range(len(data_blocks)): #for each datamtrix + + + inter = 8 + nd = 156 + nc = 62 + block1 = data_blocks[i][0:156*8] + block1 = interleave( [block1], inter) # interleave into 8 blocks + block1 = reed_solomon(block1, nd, nc) #generate and append the Reed-Solomon codewords + + inter = 2 + nd = 155 + nc = 62 + block2 = data_blocks[i][156*8:] + block2 = interleave( [block2], inter) # interleave into 2 blocks + block2 = reed_solomon(block2, nd, nc) #generate and append the Reed-Solomon codewords + + blocks = block1 + blocks.extend(block2) + + blocks = combine_interleaved(blocks, 10, nd, nc, True) + + data_blocks[i] = blocks[0] + + + return data_blocks + + +#Takes a codeword stream and splits up into "inter" blocks. +#eg interleave( [1,2,3,4,5,6], 2 ) -> [1,3,5], [2,4,6] +def interleave( blocks, inter): + + if inter == 1: # if we don't have to interleave, just return the blocks + return blocks + else: + result = [] + for block in blocks: #for each codeword block in the stream + block_length = len(block)/inter #length of each interleaved block + inter_blocks = [[0] * block_length for i in xrange(inter)] #the interleaved blocks + + for i in range(block_length): #for each element in the interleaved blocks + for j in range(inter): #for each interleaved block + inter_blocks[j][i] = block[ i*inter + j ] + + result.extend(inter_blocks) #add the interleaved blocks to the output + + return result + +#Combine interleaved blocks into the groups for the same datamatrix +# +#e.g combine_interleaved( [[d1, d3, d5, e1, e3, e5], [d2, d4, d6, e2, e4, e6]], 2, 3, 3 ) +# --> [[d1, d2, d3, d4, d5, d6, e1, e2, e3, e4, e5, e6]] +def combine_interleaved( blocks, inter, nd, nc, size144): + if inter == 1: #the blocks aren't interleaved + return blocks + else: + result = [] + for i in range( len(blocks) / inter ): #for each group of "inter" blocks -> one full datamatrix + data_codewords = [] #interleaved data blocks + + if size144: + nd_range = 1558 #1558 = 156*8 + 155*2 + nc_range = 620 #620 = 62*8 + 62*2 + else: + nd_range = nd*inter + nc_range = nc*inter + + for j in range(nd_range): #for each codeword in the final list + data_codewords.append( blocks[i*inter + j%inter][j/inter] ) + + for j in range(nc_range): #for each block, add the ecc codewords + data_codewords.append( blocks[i*inter + j%inter][nd + j/inter] ) + + result.append(data_codewords) + return result + +#checks if an ASCII character is a digit from 0 - 9 +def is_digit( char ): + + if ord(char) >= 48 and ord(char) <= 57: + return True + else: + return False + +def encode_to_ascii( text): + + ascii = [] + i = 0 + while i < len(text): + #check for double digits + if is_digit( text[i] ) and ( i < len(text)-1) and is_digit( text[i+1] ): #if the next char is also a digit + + codeword = int( text[i] + text[i+1] ) + 130 + ascii.append( codeword ) + i = i + 2 #move on 2 characters + else: #encode as a normal ascii, + ascii.append( ord(text[i] ) + 1 ) #codeword is ASCII value + 1 (ISO 16022:2006 5.2.3) + i = i + 1 #next character + + return ascii + + +#partition data into blocks of the appropriate size to suit the +#Reed-Solomon block being used. +#e.g. partition_data([1,2,3,4,5], 3) -> [[1,2,3],[4,5,PAD]] +def partition_data( data , rs_data): + + PAD_VAL = 129 # PAD codeword (ISO 16022:2006 5.2.3) + data_blocks = [] + i = 0 + while i < len(data): + if len(data) >= i+rs_data: #we have a whole block in our data + data_blocks.append( data[i:i+rs_data] ) + i = i + rs_data + else: #pad out with the pad codeword + data_block = data[i:len(data)] #add any remaining data + pad_pos = len(data) + padded = False + while len(data_block) < rs_data:#and then pad with randomised pad codewords + if not padded: + data_block.append( PAD_VAL ) #add a normal pad codeword + padded = True + else: + data_block.append( randomise_pad_253( PAD_VAL, pad_pos) ) + pad_pos = pad_pos + 1 + data_blocks.append( data_block) + break + + return data_blocks + +#Pad character randomisation, to prevent regular patterns appearing +#in the data matrix +def randomise_pad_253(pad_value, pad_position ): + pseudo_random_number = ( ( 149 * pad_position ) % 253 )+ 1 + randomised = pad_value + pseudo_random_number + if ( randomised <= 254 ): + return randomised + else: + return randomised - 254 + +# REED-SOLOMON ENCODING ROUTINES ===================================== + +# "prod(x,y,log,alog,gf)" returns the product "x" times "y" +def prod(x, y, log, alog, gf): + + if ( x==0 or y==0): + return 0 + else: + result = alog[ ( log[x] + log[y] ) % (gf - 1) ] + return result + +# generate the log & antilog lists: +def gen_log_alog(gf, pp): + log = [0]*gf + alog = [0]*gf + + log[0] = 1-gf + alog[0] = 1 + + for i in range(1,gf): + alog[i] = alog[i-1] * 2 + + if (alog[i] >= gf): + alog[i] = alog[i] ^ pp + + log[alog[i]] = i + + return log, alog + +# generate the generator polynomial coefficients: +def gen_poly_coeffs(nc, log, alog, gf): + c = [0] * (nc+1) + c[0] = 1 + + for i in range(1,nc+1): + c[i] = c[i-1] + + j = i-1 + while j >= 1: + c[j] = c[j-1] ^ prod(c[j],alog[i],log,alog,gf) + j = j - 1 + + c[0] = prod(c[0],alog[i],log,alog,gf) + + return c + +# "ReedSolomon(wd,nd,nc)" takes "nd" data codeword values in wd[] +# and adds on "nc" check codewords, all within GF(gf) where "gf" is a +# power of 2 and "pp" is the value of its prime modulus polynomial */ +def reed_solomon(data, nd, nc): + #parameters of the polynomial arithmetic + gf = 256 #operating on 8-bit codewords -> Galois field = 2^8 = 256 + pp = 301 #prime modulus polynomial for ECC-200 is 0b100101101 = 301 (ISO 16022:2006 5.7.1) + + log, alog = gen_log_alog(gf,pp) + c = gen_poly_coeffs(nc, log, alog, gf) + + for block in data: #for each block of data codewords + + block.extend( [0]*(nc+1) ) #extend to make space for the error codewords + + #generate "nc" checkwords in the list block + for i in range(0, nd): + k = block[nd] ^ block[i] + + for j in range(0,nc): + block[nd+j] = block[nd+j+1] ^ prod(k,c[nc-j-1],log, alog,gf) + + block.pop() + + return data + +#MODULE PLACEMENT ROUTINES=========================================== +# These routines take a steam of codewords, and place them into the +# DataMatrix in accordance with Annex F of BS ISO/IEC 16022:2006 + +# bit() returns the bit'th bit of the byte +def bit(byte, bit): + #the MSB is bit 1, LSB is bit 8 + return ( byte >> (8-bit) ) %2 + +# "module" places a given bit with appropriate wrapping within array +def module(array, nrow, ncol, row, col, bit) : + if (row < 0) : + row = row + nrow + col = col + 4 - ((nrow+4)%8) + + if (col < 0): + col = col + ncol + row = row + 4 - ((ncol+4)%8) + + array[row][col] = bit + +def corner1(array, nrow, ncol, char): + module(array, nrow, ncol, nrow-1, 0, bit(char,1)); + module(array, nrow, ncol, nrow-1, 1, bit(char,2)); + module(array, nrow, ncol, nrow-1, 2, bit(char,3)); + module(array, nrow, ncol, 0, ncol-2, bit(char,4)); + module(array, nrow, ncol, 0, ncol-1, bit(char,5)); + module(array, nrow, ncol, 1, ncol-1, bit(char,6)); + module(array, nrow, ncol, 2, ncol-1, bit(char,7)); + module(array, nrow, ncol, 3, ncol-1, bit(char,8)); + +def corner2(array, nrow, ncol, char): + module(array, nrow, ncol, nrow-3, 0, bit(char,1)); + module(array, nrow, ncol, nrow-2, 0, bit(char,2)); + module(array, nrow, ncol, nrow-1, 0, bit(char,3)); + module(array, nrow, ncol, 0, ncol-4, bit(char,4)); + module(array, nrow, ncol, 0, ncol-3, bit(char,5)); + module(array, nrow, ncol, 0, ncol-2, bit(char,6)); + module(array, nrow, ncol, 0, ncol-1, bit(char,7)); + module(array, nrow, ncol, 1, ncol-1, bit(char,8)); + +def corner3(array, nrow, ncol, char): + module(array, nrow, ncol, nrow-3, 0, bit(char,1)); + module(array, nrow, ncol, nrow-2, 0, bit(char,2)); + module(array, nrow, ncol, nrow-1, 0, bit(char,3)); + module(array, nrow, ncol, 0, ncol-2, bit(char,4)); + module(array, nrow, ncol, 0, ncol-1, bit(char,5)); + module(array, nrow, ncol, 1, ncol-1, bit(char,6)); + module(array, nrow, ncol, 2, ncol-1, bit(char,7)); + module(array, nrow, ncol, 3, ncol-1, bit(char,8)); + +def corner4(array, nrow, ncol, char): + module(array, nrow, ncol, nrow-1, 0, bit(char,1)); + module(array, nrow, ncol, nrow-1, ncol-1, bit(char,2)); + module(array, nrow, ncol, 0, ncol-3, bit(char,3)); + module(array, nrow, ncol, 0, ncol-2, bit(char,4)); + module(array, nrow, ncol, 0, ncol-1, bit(char,5)); + module(array, nrow, ncol, 1, ncol-3, bit(char,6)); + module(array, nrow, ncol, 1, ncol-2, bit(char,7)); + module(array, nrow, ncol, 1, ncol-1, bit(char,8)); + +#"utah" places the 8 bits of a utah-shaped symbol character in ECC200 +def utah(array, nrow, ncol, row, col, char): + module(array, nrow, ncol,row-2, col-2, bit(char,1)) + module(array, nrow, ncol,row-2, col-1, bit(char,2)) + module(array, nrow, ncol,row-1, col-2, bit(char,3)) + module(array, nrow, ncol,row-1, col-1, bit(char,4)) + module(array, nrow, ncol,row-1, col, bit(char,5)) + module(array, nrow, ncol,row, col-2, bit(char,6)) + module(array, nrow, ncol,row, col-1, bit(char,7)) + module(array, nrow, ncol,row, col, bit(char,8)) + +#"place_bits" fills an nrow x ncol array with the bits from the +# codewords in data. +def place_bits(data, (nrow, ncol)): +# First, fill the array[] with invalid entries */ + INVALID = 2 + array = [[INVALID] * ncol for i in xrange(nrow)] #initialise and fill with -1's (invalid value) +# Starting in the correct location for character #1, bit 8,... + char = 0 + row = 4 + col = 0 + while True: + + #first check for one of the special corner cases, then... + if ((row == nrow) and (col == 0)): + corner1(array, nrow, ncol, data[char]) + char = char + 1 + if ((row == nrow-2) and (col == 0) and (ncol%4)) : + corner2(array, nrow, ncol, data[char]) + char = char + 1 + if ((row == nrow-2) and (col == 0) and (ncol%8 == 4)): + corner3(array, nrow, ncol, data[char]) + char = char + 1 + if ((row == nrow+4) and (col == 2) and ((ncol%8) == 0)): + corner4(array, nrow, ncol, data[char]) + char = char + 1 + + #sweep upward diagonally, inserting successive characters,... + while True: + if ((row < nrow) and (col >= 0) and (array[row][col] == INVALID)) : + utah(array, nrow, ncol,row,col,data[char]) + char = char+1 + row = row - 2 + col = col + 2 + + if not((row >= 0) and (col < ncol)): + break + + row = row + 1 + col = col + 3 + + # & then sweep downward diagonally, inserting successive characters,... + while True: + if ((row >= 0) and (col < ncol) and (array[row][col] == INVALID)) : + utah(array, nrow, ncol,row,col,data[char]) + char = char + 1 + row = row + 2 + col = col - 2 + + if not((row < nrow) and (col >= 0)): + break + + row = row + 3 + col = col + 1 + + #... until the entire array is scanned + if not((row < nrow) or (col < ncol)): + break + + # Lastly, if the lower righthand corner is untouched, fill in fixed pattern */ + if (array[nrow-1][ncol-1] == INVALID): + array[nrow-1][ncol-2] = 0 + array[nrow-1][ncol-1] = 1 + array[nrow-2][ncol-1] = 0 + array[nrow-2][ncol-2] = 1 + + return array #return the array of 1's and 0's + + +def add_finder_pattern( array, data_nrow, data_ncol, reg_row, reg_col ): + + #get the total size of the datamatrix + nrow = (data_nrow+2) * reg_row + ncol = (data_ncol+2) * reg_col + + datamatrix = [[0] * ncol for i in xrange(nrow)] #initialise and fill with 0's + + for i in range( reg_col ): #for each column of data regions + for j in range(nrow): + datamatrix[j][i*(data_ncol+2)] = 1 #vertical black bar on left + datamatrix[j][i*(data_ncol+2)+data_ncol+1] = (j)%2 # alternating blocks + + for i in range( reg_row): # for each row of data regions + for j in range(ncol): + datamatrix[i*(data_nrow+2)+data_nrow+1][j] = 1 #horizontal black bar at bottom + datamatrix[i*(data_nrow+2)][j] = (j+1)%2 # alternating blocks + + for i in range( data_nrow*reg_row ): + for j in range( data_ncol* reg_col ): + dest_col = j + 1 + 2*(j/(data_ncol)) #offset by 1, plus two for every addition block + dest_row = i + 1 + 2*(i/(data_nrow)) + + datamatrix[dest_row][dest_col] = array[i][j] #transfer from the plain bit array + + return datamatrix + +#RENDERING ROUTINES ================================================== +# Take the array of 1's and 0's and render as a series of black +# squares. A binary 1 is a filled square +#===================================================================== + +#SVG element generation routine +def draw_SVG_square((w,h), (x,y), parent): + + style = { 'stroke' : 'none', + 'width' : '1', + 'fill' : '#000000' + } + + attribs = { + 'style' :simplestyle.formatStyle(style), + 'height' : str(h), + 'width' : str(w), + 'x' : str(x), + 'y' : str(y) + } + circ = inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), attribs ) + +#turn a 2D array of 1's and 0's into a set of black squares +def render_data_matrix( module_arrays, size, spacing, parent): + + for i in range(len(module_arrays)): #for each data matrix + + height = len(module_arrays[i]) + width = len(module_arrays[i][0] ) + + for y in range(height): #loop over all the modules in the datamatrix + for x in range(width): + + if module_arrays[i][y][x] == 1: #A binary 1 is a filled square + draw_SVG_square((size,size), (x*size + i*spacing,y*size), parent) + elif module_arrays[i][y][x] != 0: #we have an invalid bit value + inkex.errormsg(_('Invalid bit value, this is a bug!')) + +class DataMatrix(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + + #PARSE OPTIONS + self.OptionParser.add_option("--text", + action="store", type="string", + dest="TEXT", default='Inkscape') + self.OptionParser.add_option("--rows", + action="store", type="int", + dest="ROWS", default=10) + self.OptionParser.add_option("--cols", + action="store", type="int", + dest="COLS", default=10) + self.OptionParser.add_option("--size", + action="store", type="int", + dest="SIZE", default=4) + + def effect(self): + + so = self.options + + if so.TEXT == '': #abort if converting blank text + inkex.errormsg(_('Please enter an input string')) + else: + + #INKSCAPE GROUP TO CONTAIN EVERYTHING + + centre = self.view_center #Put in in the centre of the current view + grp_transform = 'translate' + str( centre ) + grp_name = 'DataMatrix' + grp_attribs = {inkex.addNS('label','inkscape'):grp_name, + 'transform':grp_transform } + grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs)#the group to put everything in + + #GENERATE THE DATAMATRIX + encoded = encode( so.TEXT, (so.ROWS, so.COLS) ) #get the pattern of squares + render_data_matrix( encoded, so.SIZE, so.COLS*so.SIZE*1.5, grp ) # generate the SVG elements + +if __name__ == '__main__': + e = DataMatrix() + e.affect() + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 diff --git a/share/extensions/wireframe_sphere.inx b/share/extensions/wireframe_sphere.inx new file mode 100644 index 000000000..733ba8e11 --- /dev/null +++ b/share/extensions/wireframe_sphere.inx @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Wireframe Sphere</_name> + <id>il.wireframesphere</id> + <dependency type="executable" location="extensions">wireframe_sphere.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <dependency type="executable" location="extensions">simplestyle.py</dependency> + <dependency type="executable" location="extensions">simpletransform.py</dependency> + <param name="num_lat" type="int" min="0" max="1000" _gui-text="Lines of latitude">19</param> + <param name="num_long" type="int" min="0" max="1000" _gui-text="Lines of longitude">24</param> + <param name="tilt" type="float" min="-90" max="90" _gui-text="Tilt [deg]">35</param> + <param name="rotation" type="float" min="0" max="360" _gui-text="Rotation [deg]">4</param> + <param name="radius" type="float" min="1" max="1000" _gui-text="Radius [px]">100.0</param> + <param name="hide_back" type="boolean" _gui-text="Hide lines behind the sphere">false</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">wireframe_sphere.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/wireframe_sphere.py b/share/extensions/wireframe_sphere.py new file mode 100644 index 000000000..8fbd4d3f1 --- /dev/null +++ b/share/extensions/wireframe_sphere.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +''' +Copyright (C) 2009 John Beard john.j.beard@gmail.com + +######DESCRIPTION###### + +This extension renders a wireframe sphere constructed from lines of latitude +and lines of longitude. + +The number of lines of latitude and longitude is independently variable. Lines +of latitude and longtude are in separate subgroups. The whole figure is also in +its own group. + +The whole sphere can be tilted towards or away from the veiwer by a given +number of degrees. If the whole sphere is then rotated normally in Inkscape, +any position can be acheived. + +There is an option to hide the lines at the back of the sphere, as if the +sphere were opaque. + #FIXME: Lines of latitude only have an approximation of the function needed + to hide the back portion. If you can derive the proper equation, + please add it in. + Line of longitude have the exact method already. + Workaround: Use the Inkscape ellipse tool to edit the start and end + points of the lines of latitude to end at the horizon circle. + + +#TODO: Add support for odd numbers of lines of longitude. This means breaking + the line at the poles, and having two half ellipses for each line. + The angles at which the ellipse arcs pass the poles are not constant and + need to be derived before this can be implemented. +#TODO: Add support for prolate and oblate spheroids + +######LICENCE####### +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 + +######VERSION HISTORY##### + Ver. Date Notes + + 0.10 2009-10-25 First version. Basic spheres supported. + Hidden lines of latitude still not properly calculated. + Prolate and oblate spheroids not considered. +''' + +import inkex, simplestyle + +import gettext +_ = gettext.gettext + +from math import * + +#SVG OUTPUT FUNCTIONS ================================================ +def draw_SVG_ellipse((rx, ry), (cx, cy), parent, start_end=(0,2*pi),transform='' ): + + style = { 'stroke' : '#000000', + 'width' : '1', + 'fill' : 'none' } + circ_attribs = {'style':simplestyle.formatStyle(style), + inkex.addNS('cx','sodipodi') :str(cx), + inkex.addNS('cy','sodipodi') :str(cy), + inkex.addNS('rx','sodipodi') :str(rx), + inkex.addNS('ry','sodipodi') :str(ry), + inkex.addNS('start','sodipodi') :str(start_end[0]), + inkex.addNS('end','sodipodi') :str(start_end[1]), + inkex.addNS('open','sodipodi') :'true', #all ellipse sectors we will draw are open + inkex.addNS('type','sodipodi') :'arc', + 'transform' :transform + + } + circ = inkex.etree.SubElement(parent, inkex.addNS('path','svg'), circ_attribs ) + +class Wireframe_Sphere(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + + #PARSE OPTIONS + self.OptionParser.add_option("--num_lat", + action="store", type="int", + dest="NUM_LAT", default=19) + self.OptionParser.add_option("--num_long", + action="store", type="int", + dest="NUM_LONG", default=24) + self.OptionParser.add_option("--radius", + action="store", type="float", + dest="RADIUS", default=100.0) + self.OptionParser.add_option("--tilt", + action="store", type="float", + dest="TILT", default=35.0) + self.OptionParser.add_option("--rotation", + action="store", type="float", + dest="ROT_OFFSET", default=4) + self.OptionParser.add_option("--hide_back", + action="store", type="inkbool", + dest="HIDE_BACK", default=False) + + def effect(self): + + so = self.options + + #PARAMETER PROCESSING + + if so.NUM_LONG % 2 != 0: #lines of longitude are odd : abort + inkex.errormsg(_('Please enter an even number of lines of longitude.')) + else: + if so.TILT < 0: # if the tilt is backwards + flip = ' scale(1, -1)' # apply a vertical flip to the whole sphere + else: + flip = '' #no flip + + so.TILT = abs(so.TILT)*(pi/180) #Convert to radians + so.ROT_OFFSET = so.ROT_OFFSET*(pi/180) #Convert to radians + + EPSILON = 0.001 #add a tiny value to the ellipse radii, so that if we get a zero radius, the ellipse still shows up as a line + + #INKSCAPE GROUP TO CONTAIN EVERYTHING + + centre = self.view_center #Put in in the centre of the current view + grp_transform = 'translate' + str( centre ) + flip + grp_name = 'WireframeSphere' + grp_attribs = {inkex.addNS('label','inkscape'):grp_name, + 'transform':grp_transform } + grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs)#the group to put everything in + + #LINES OF LONGITUDE + + if so.NUM_LONG > 0: #only process longitudes if we actually want some + + #GROUP FOR THE LINES OF LONGITUDE + grp_name = 'Lines of Longitude' + grp_attribs = {inkex.addNS('label','inkscape'):grp_name} + grp_long = inkex.etree.SubElement(grp, 'g', grp_attribs) + + delta_long = 360.0/so.NUM_LONG #angle between neighbouring lines of longitude in degrees + + for i in range(0,so.NUM_LONG/2): + long_angle = so.ROT_OFFSET + (i*delta_long)*(pi/180.0); #The longitude of this particular line in radians + if long_angle > pi: + long_angle -= 2*pi + width = so.RADIUS * cos(long_angle) + height = so.RADIUS * sin(long_angle) * sin(so.TILT) #the rise is scaled by the sine of the tilt + # length = sqrt(width*width+height*height) #by pythagorean theorem + # inverse = sin(acos(length/so.RADIUS)) + inverse = abs(sin(long_angle)) * cos(so.TILT) + + minorRad = so.RADIUS * inverse + minorRad=minorRad + EPSILON + + #calculate the rotation of the ellipse to get it to pass through the pole (in degrees) + rotation = atan(height/width)*(180.0/pi) + transform = "rotate("+str(rotation)+')' #generate the transform string + #the rotation will be applied about the group centre (the centre of the sphere) + + # remove the hidden side of the ellipses if required + # this is always exactly half the ellipse, but we need to find out which half + start_end = (0, 2*pi) #Default start and end angles -> full ellipse + if so.HIDE_BACK: + if long_angle <= pi/2: #cut out the half ellispse that is hidden + start_end = (pi/2, 3*pi/2) + else: + start_end = (3*pi/2, pi/2) + + #finally, draw the line of longitude + #the centre is always at the centre of the sphere + draw_SVG_ellipse( ( minorRad, so.RADIUS ), (0,0), grp_long , start_end,transform) + + # LINES OF LATITUDE + if so.NUM_LAT > 0: + + #GROUP FOR THE LINES OF LATITUDE + grp_name = 'Lines of Latitude' + grp_attribs = {inkex.addNS('label','inkscape'):grp_name} + grp_lat = inkex.etree.SubElement(grp, 'g', grp_attribs) + + + so.NUM_LAT = so.NUM_LAT + 1 #Account for the fact that we loop over N-1 elements + delta_lat = 180.0/so.NUM_LAT #Angle between the line of latitude (subtended at the centre) + + for i in range(1,so.NUM_LAT): + lat_angle=((delta_lat*i)*(pi/180)) #The angle of this line of latitude (from a pole) + + majorRad=so.RADIUS*sin(lat_angle) #The width of the LoLat (no change due to projection) + minorRad=so.RADIUS*sin(lat_angle) * sin(so.TILT) #The projected height of the line of latitude + minorRad=minorRad + EPSILON + + cy=so.RADIUS*cos(lat_angle) * cos(so.TILT) #The projected y position of the LoLat + cx=0 #The x position is just the center of the sphere + + if so.HIDE_BACK: + if lat_angle > so.TILT: #this LoLat is partially or fully visible + if lat_angle > pi-so.TILT: #this LoLat is fully visible + draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat) + else: #this LoLat is partially visible + proportion = -(acos( tan(lat_angle - pi/2)/tan(pi/2 - so.TILT)) )/pi + 1 + start_end = ( pi/2 - proportion*pi, pi/2 + proportion*pi ) #make the start and end angles (mirror image around pi/2) + draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat, start_end) + + else: #just draw the full lines of latitude + draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat) + + + #THE HORIZON CIRCLE + draw_SVG_ellipse((so.RADIUS, so.RADIUS), (0,0), grp) #circle, centred on the sphere centre + +if __name__ == '__main__': + e = Wireframe_Sphere() + e.affect() + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 |
