def _create_clip_paths( self ): paths = svg.element( 'g', { 'class' : 'clip_paths' } ) key_edge = self.radius / 2 edge = svg.format_value( key_edge ) for ( index, shape ) in enumerate( _key_shapes ): key_width = self.xscale * shape[ 0 ] key_height = self.yscale * shape[ 1 ] width = svg.format_value( key_width - ( 2 * key_edge ) ) height = svg.format_value( key_height - ( 2 * key_edge ) ) paths.append_child( svg.element( 'clipPath', { 'id' : ( 'clip_%d' % index ) }, [ # ZIH - messy since it depends on _make_key_paths() svg.element( 'rect', { 'x' : edge, 'y' : edge, 'rx' : edge, 'ry' : edge, 'width' : width, 'height' : height } ) ] ) ) return paths
def create_svg( self, title = 'keyboard' ): width = self.xscale * keyboard._unit_columns height = self.yscale * ( _row_offsets[ -1 ] + 1.0 ) image = svg.create_image( width, height, title ) image.append_child( svg.element( 'link', { 'rel' : 'icon', 'href' : '#key_0', 'xmlns' : 'http://www.w3.org/1999/xhtml' } ) ) image.append_child( svg.element( 'style', { 'type' : 'text/css' }, str( self.style ) ) ) image.append_child( self._create_key_shapes() ) image.append_child( self._create_clip_paths() ) image.append_child( self._create_layout() ) return image
def patch_path(patch, colour): pathd = [ 'M', ] for point in PATCHES[patch]: coord = get_coord(point) pathd.append(coord.x) pathd.append(coord.y) pathd.append('z') return svg.element('path', id=patch, d=pathd, fill=gc.COLOURS[colour])
def oll(x, rotate=0, filename="oll.svg"): """ Generates OLL images. x: state code. rotate: rotation angle, clockwise, in [-270, -180, -90, 0, 90, 180, 270]. filename: SVG filename. State code (x) syntax: 1. int, OLL code, 1~57. 2. 9-char string, specifying orientation of the 9 pieces (ULB, UB, URB, ..., ULR), for example OLL20 (X-shaped) = 'ubulurufu'. Case-insensitive. 3. list of 3-char strings. Each string specifies a 'colour patch', for example OLL20 = ['lbu', 'mbb', 'rbu', 'lsl', ..., 'rfu']. Format: [lmr][bsf][ulrbf] The 1st and 2nd char specifies the position of the corner/edge/centre piece, and the 3rd char specifies its orientation. Case-insensitive. """ states = [] for bsf in 'bsf': for lmr in 'lmr': states.append(lmr+bsf) if isinstance(x, int): if x > 57 or x < 0: raise Exception("OLL code is %d, not in [1, 57]."%x) code = OLL_STD_CODES[x] for i in range(9): states[i] = states[i] + code[i] elif isinstance(x, str) and len(x) == 9: for i in range(9): states[i] = states[i] + x[i] elif isinstance(x, list): states = x else: raise Exception('Invalid OLL state code "%s".'%str(x)) if rotate not in [-270, -180, -90, 0, 90, 180, 270]: raise Exception('Invalid angle: "%s".'%str(rotate)) rect_str = '' for state in states: rect_coord = op.rect_top_coord(state) rect_str = rect_str + svg.element('rect', id=state, x=rect_coord[0], y=rect_coord[1], width=rect_coord[2], height=rect_coord[3], rotate=rotate) with open(filename, 'w') as f: f.write(op.SVG_HEAD) f.write(op.SVG_BG) f.write(op.GRID_STR) f.write(rect_str) f.write(svg.TAIL)
def _create_key_shapes( self ): shapes = svg.element( 'g', { 'class' : 'key_shapes' } ) for ( index, shape ) in enumerate( _key_shapes ): shapes.append_child( svg.element( 'g', { 'id' : ( 'key_%d' % index ) }, _make_key_paths( ( shape[ 0 ] * self.xscale ), ( shape[ 1 ] * self.yscale ), self.radius ) ) ) return shapes
def _create_layout( self ): # generate a group of key display groups keyboard = svg.element( 'g', { 'class' : 'layout' } ) # iterate through each key requested for rendering for k in self.keys: # add its SVG representation to the layout keyboard.append_child( k.create_svg( self.xscale, self.yscale, self.radius ) ) # return the constructed layout return keyboard
def grid_path(): ''' Generates a 'path' element of the U face grid. ''' grid_d = square_d(GRID_UL, GRID_UL, GRID_STROKE_WIDTH * 4 + GRID_PATCH_SIZE * 3) for i in range(3): for j in range(3): x = GRID_UL + GRID_STROKE_WIDTH + i * (GRID_PATCH_SIZE + GRID_STROKE_WIDTH) y = GRID_UL + GRID_STROKE_WIDTH + j * (GRID_PATCH_SIZE + GRID_STROKE_WIDTH) grid_d.extend(square_d(x, y, GRID_PATCH_SIZE, anticlockwise=True)) return svg.element('path', id="grid", d=grid_d)
def pll(x, rotate=0, filename="pll.svg"): """ Generates PLL images. x: state code, 1~21. rotate: rotation angle, clockwise, in [-270, -180, -90, 0, 90, 180, 270]. filename: SVG filename. """ arrow_str = '' arrows = '' if isinstance(x, int): if x > 21 or x < 0: raise Exception("PLL code is %d, not in [1, 21]." % x) arrows = PLL_STD_CODES[x][1:] else: raise Exception('Invalid PLL state code "%s".' % str(x)) if rotate not in [-270, -180, -90, 0, 90, 180, 270]: raise Exception('Invalid angle: "%s".' % str(rotate)) for arrow in arrows: arrow_str += arrow_path(arrow[0], arrow[1], arrow[2], arrow[3], rotate) rect_str = '' for rect in PLL_STD_CODES[x][0]: rect_coord = op.rect_top_coord(rect) rect_str = rect_str + svg.element('rect', id=rect, x=rect_coord[0], y=rect_coord[1], width=rect_coord[2], height=rect_coord[3], rotate=rotate) with open(filename, 'w') as f: f.write(op.SVG_HEAD) f.write(op.SVG_BG) f.write(arrow_str) f.write(rect_str) f.write(op.GRID_STR) f.write(svg.TAIL)
def grid_path(): ''' Generates the grid in F2L ''' grid_str = '' for fc, fcpoints in FACES_AND_CUTS.items(): pathd = [ 'M', ] for p in fcpoints: coord = get_coord(p) pathd.append(coord.x) pathd.append(coord.y) grid_str += svg.element('path', id=fc, d=pathd, fill='none', stroke="#000000", stroke_width="2") return grid_str
def f2l(x, basestate='slot', filename='f2l.svg'): ''' Generates F2L SVG. x: F2L number, or a dict containing 'u1', 'u2', 'u3', ..., 'r9' items specifying the colours of each visible patch. For example {'f6':'r', 'f9':'b', 'r4':'b', 'r7':'r'} (if based on 'slot', =F2l 1). basestate: the default state of the cube, 'u' = all gray, 'w' = all white, 'cross' = cross solved, 'f2l' = F2L solved, 'oll' = OLL solved, 'complete' = all complete, default 'slot', F2L except RF slot solved. ''' patches_str = '' if isinstance(x, int): if x > 41 or x < 0: raise Exception("F2L code is %d, not in [1, 41]." % x) patches = F2L_STD_CODES[x] elif isinstance(x, dict): patches = x else: raise Exception('Invalid F2L state code "%s".' % str(x)) for patch in PATCHES.keys(): if patch in patches: colour = patches[patch] else: colour = BASESTATES[basestate][patch] patches_str += patch_path(patch, colour) with open(filename, 'w') as f: f.write(svg.head(256, 256, 256, 256)) f.write( svg.element('rect', id='bg', width="256", height="256", fill="#ffffff")) f.write(patches_str) f.write(grid_path()) f.write(svg.TAIL)
def arrow_path(x, double=False, scale=1, offset=0, rotate=0): """ x: 2 char string. Specifying the start and the end of the arrow in numeric codes: --- |123| |456| |789| --- double: arrow is bi-directional if true. scale: factor the arrow is scaled. offset: distance the arrow moved outside from the standard position. rotate: rotation angle output: svg_str of arrow(s) """ corner_straight_cw = ('71', '13', '39', '97') corner_straight_acw = ('93', '79', '17', '31') edge_straight = ('82', '46', '28', '64') corner_slant = ('91', '73', '19', '37') edge_slant_cw = ('42', '26', '68', '84') edge_slant_acw = ('62', '86', '48', '24') corner_straight_x = 125 - offset corner_straight_y = 85 corner_straight_len = 280 + offset edge_straight_x = 570 // 2 edge_straight_y = 85 - offset edge_straight_len = 270 corner_slant_x = 100 - offset corner_slant_y = corner_slant_x corner_slant_len = 410 + offset * 1.4 edge_slant_y = 100 - offset edge_slant_len = 175 if x in corner_straight_cw: spikex = corner_straight_x spikey = corner_straight_y arrow_len = corner_straight_len rotate_arrow = 90 * corner_straight_cw.index(x) + rotate elif x in corner_straight_acw: spikex = 570 - corner_straight_x spikey = corner_straight_y arrow_len = corner_straight_len rotate_arrow = 90 * corner_straight_acw.index(x) + rotate elif x in edge_straight: spikex = edge_straight_x spikey = edge_straight_y arrow_len = edge_straight_len rotate_arrow = 90 * edge_straight.index(x) + rotate elif x in corner_slant: spikex = corner_slant_x spikey = corner_slant_y arrow_len = corner_slant_len rotate_arrow = (90 * corner_slant.index(x) + rotate, 285, 285, -45, spikex, spikey) elif x in edge_slant_cw: spikey = edge_slant_y spikex = 360 + 50 - edge_slant_y arrow_len = edge_slant_len rotate_arrow = (90 * edge_slant_cw.index(x) + rotate, 285, 285, 45, spikex, spikey) elif x in edge_slant_acw: spikey = edge_slant_y spikex = 210 - 50 + edge_slant_y arrow_len = edge_slant_len rotate_arrow = (90 * edge_slant_acw.index(x) + rotate, 285, 285, -45, spikex, spikey) else: raise Exception("Invalid arrow code.") res = svg.element('path', id=x, d=arrow_d(spikex, spikey, arrow_len, scale), rotate=rotate_arrow) if double == True: res += arrow_path(x[1] + x[0], False, scale, offset, rotate) return res
def create_svg( self, xscale = 42.0, yscale = 42.0, radius = 4 ): # determine position in the layout xpos = self[ 'offset' ] * xscale ypos = _row_offsets[ self[ 'row' ] ] * yscale # set the transform attribute for the group to position the key self.attributes[ 'transform' ] = \ 'translate(%s)' % svg.format_coord( xpos, ypos ) # create a group to display the key group = svg.element( 'g', self.attributes ) # create a use element to "clone" the appropriate shape group.append_child( svg.element( 'use', { 'xlink:href' : ( '#key_%d' % self[ 'shape' ] ) } ) ) # create a sub-group to contain/limit descendents subgroup = svg.element( 'g', { 'clip-path' : ( 'url(#clip_%d)' % self[ 'shape' ] ) } ) # find the height of this key height = _key_shapes[ self[ 'shape' ] ][ 1 ] * yscale # determine text baseline position values edge = radius / 2.0 xpad = svg.format_value( edge + 1 ) y0pad = svg.format_value( height - ( edge + 2 ) ) y1pad = svg.format_value( ( height / 2.0 ) - ( edge + 1 ) ) # see if the user wants to see the default label if ( self.flags & key.LABEL ) == key.LABEL: # create and position the key label subgroup.append_child( svg.element( 'text', { 'x' : xpad, 'y' : y0pad }, xml.sax.saxutils.escape( self[ 'label' ] ) ) ) # see if the user wants to see the shift label (if it exists) if ( self[ 'shift' ] is not None ) \ and ( ( self.flags & key.SHIFT ) == key.SHIFT ): # create and position the shift label subgroup.append_child( svg.element( 'text', { 'x' : xpad, 'y' : y1pad }, xml.sax.saxutils.escape( self[ 'shift' ] ) ) ) # display any other labels for label in self.labels: # create and position this label subgroup.append_child( svg.element( 'text', { 'x' : svg.format_value( label[ 'x' ] ), 'y' : svg.format_value( label[ 'y' ] ) }, xml.sax.saxutils.escape( label[ 'text' ] ) ) ) # append the container group group.append_child( subgroup ) # return the group element return group
h = 'v' v = 'h' return ['M', x, y, h, a, v, a, h, -a, v, -a, 'z'] def grid_path(): ''' Generates a 'path' element of the U face grid. ''' grid_d = square_d(GRID_UL, GRID_UL, GRID_STROKE_WIDTH * 4 + GRID_PATCH_SIZE * 3) for i in range(3): for j in range(3): x = GRID_UL + GRID_STROKE_WIDTH + i * (GRID_PATCH_SIZE + GRID_STROKE_WIDTH) y = GRID_UL + GRID_STROKE_WIDTH + j * (GRID_PATCH_SIZE + GRID_STROKE_WIDTH) grid_d.extend(square_d(x, y, GRID_PATCH_SIZE, anticlockwise=True)) return svg.element('path', id="grid", d=grid_d) GRID_STR = grid_path() SVG_HEAD = svg.head(SVG_SIZE, SVG_SIZE, VIEWBOX_SIZE, VIEWBOX_SIZE) SVG_BG = svg.element('rect', id="bg", width=VIEWBOX_SIZE, height=VIEWBOX_SIZE, fill="#ffffff")