def __init__(self, d): Command.__init__(self, d) try: self.mode = get_or_default(d, 'mode', 'absolute') self.unit = get_or_default(d, 'unit', 'no-unit') self.line = get_or_default(d, 'line', None) if self.line: self.line_style = get_or_default(self.line, 'style', 'default-line-style') self.symbol = get_or_default(d, 'symbol', None) self.label = get_or_default(d, 'label', None) if self.label: self.label_style = get_or_default(self.label, 'style', 'default-text-style') self.fmt = get_or_default(self.label, 'format', 'default-label-format') self.nudge = [ _ * pi / 180 for _ in get_or_default(self.label, 'nudge', [0.0, 0.0]) ] self.at = d['at'] self.points = len(self.at) // 2 except KeyError as ke: raise MapperException(MX_MISSING_PARAMETER, 'Place.__init__', str(ke), 'place') except ValueError as ve: raise MapperException(MX_WRONG_VALUE, 'Marks.__init__', ve.message, 'place') if isinstance(self.mode, basestring): self.mode = {self.mode} else: self.mode = set(self.mode) logger.info(u'Loaded marks {}'.format(self.symbol))
def __init__(self, d): Command.__init__(self, d) try: self.mode = get_or_default(d, 'mode', 'absolute') self.unit = get_or_default(d, 'unit', 'no-unit') self.line = get_or_default(d, 'line', None) if self.line: self.line_style = get_or_default(self.line, 'style', 'default-line-style') self.symbol = get_or_default(d, 'symbol', None) self.label = get_or_default(d, 'label', None) if self.label: self.label_style = get_or_default(self.label, 'style', 'default-text-style') self.fmt = get_or_default(self.label, 'format', 'default-label-format') self.nudge = [_*pi/180 for _ in get_or_default(self.label, 'nudge', [0.0, 0.0])] self.at = d['at'] self.points = len(self.at)//2 except KeyError as ke: raise MapperException(MX_MISSING_PARAMETER, 'Place.__init__', str(ke), 'place') except ValueError as ve: raise MapperException(MX_WRONG_VALUE, 'Marks.__init__', ve.message, 'place') if isinstance(self.mode, basestring): self.mode = {self.mode} else: self.mode = set(self.mode) logger.info(u'Loaded marks {}'.format(self.symbol))
def run(self, the_map): """ Select the matching items and project them to the output file. """ self.style = self.require_style(self.style, the_map) self.match = self.require_match(self.match, the_map) self.match.set_svg_type(self.content_types[self.what]) if self.replacement is not None: self.replacement = the_map.get_symbol(self.replacement) for p in self.match.iter(the_map.input_svg): #TODO: handle multiple and nested transforms. pp = p.clone() if pp.t == 'path': # Paths are easy, since svgfig does most of the work for us # Caution: any svg transformations are passed on unchanged # (although the style attribute could be used in a sneaky way to override that) if the_map.clip(pp): continue self.style.apply(pp) pp = svgfig_mc.pathtoPath(pp).SVG(the_map.project) elif pp.t == 'text': # for texts, we have to consider existing transforms try: x, y = float(pp.attr['x']), float(pp.attr['y']) except KeyError: logger.error( 'Project.run: skipping text element {} without coordinates.' .format(pp.attr['id'])) continue m = svg_get_matrix(get_or_default(pp.attr, 'transform', '')) x0, y0 = m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5] if the_map.clip((x0, y0)): continue x1, y1 = the_map.project(x0, y0) m[4] += x1 - x0 m[5] += y1 - y0 pp.attr[ 'transform'] = 'matrix({:f},{:f},{:f},{:f},{:f},{:f})'.format( *m) elif pp.t == 'g': # For markers, the Symbol class together with svg_transform # does most of the work of sizing, centering and placing the symbol #TODO: change the logic: a symbol is anything that matches the selection criteria x0, y0 = svg_center(pp) if the_map.clip((x0, y0)): continue x1, y1 = the_map.project(x, y) if self.replacement: pp = svg_transform(self.replacement.get_svg(), self.replacement.anchor[0], self.replacement.anchor[1], x1, y1, self.replacement.scale, self.replacement.scale) else: pp = svg_transform(pp, x, y, x1, y1) the_map.add_to_layer(self.target, pp) logger.info(u'Project.run: finished mapping: {}'.format(self.what))
def __init__(self, d): Command.__init__(self, d) try: self.what = d['what'] self.match = d['match'] self.replacement = get_or_default(d, 'replacement-symbol', None) except KeyError as ke: raise MapperException(MX_MISSING_PARAMETER, 'Project.__init__', 'project', ke) if not self.what in self.content_types: raise MapperException(MX_WRONG_VALUE, 'Project.__init__', name='Project', value=self.what) logger.info(u'Loaded Project {}'.format(self.what))
def run(self, the_map): """ Draws meridians or parallels on the named layer. dt gives the degree separation of major to, subdiv gives the number of subdivisions. If r is given, the graticules are clipped this rectangle, otherwise the entire viewport is used. Subdiv is assumed to be (and in fact silently coerced to) an integer. Labels can be 'none', 'minor', 'major' or 'both'. """ # If the clipping rectangle is not given, default to the viewport. if self.clip is None: self.clip = the_map.rect_world else: self.clip = the_map.get_rectangle(self.clip) # Set up the clipping values in a way that is neutral with respect to direction # t0, t1 are the starting and ending values, s0, s1 are the endpoints of each line if self.horizontal: t0, t1, s0, s1 = self.clip.y0, self.clip.y1, self.clip.x0 * pi / 180, self.clip.x1 * pi / 180 else: t0, t1, s0, s1 = self.clip.x0, self.clip.x1, self.clip.y0 * pi / 180, self.clip.y1 * pi / 180 # Initialize the lines and the format strings for l in self.lines: l.initialize(the_map, s0, s1) strings = {} strings.update(the_map.strings) # walk over the interval [t0 .. t1] using the smallest subdivision and draw the highest-level line # at each division. We use degrees for iteration and convert to radians for drawing span = self.lines[-1].span for n in xrange(int(ceil(t0 / span)), int(floor(t1 / span)) + 1): # find the highest level line that is evenly divided into current position for l in self.lines: if (span * n) % l.span == 0: break t = span * n * pi / 180 strings.update({'pos': span * n}) strings.update(float_to_dms(span * n, self.horizontal, the_map)) if self.horizontal: the_map.add_to_layer(self.target, l.hline(t).SVG(the_map.project_inner)) if l.labels: x, y = the_map.project_inner(l.pos, t) the_map.add_to_layer(self.target, l.get_label(x, y, strings)) else: the_map.add_to_layer(self.target, l.vline(t).SVG(the_map.project_inner)) if l.labels: x, y = the_map.project_inner(t, l.pos) the_map.add_to_layer(self.target, l.get_label(x, y, strings)) logger.info('Graticules.run: drew {} graticules'.format( 'horizontal' if self.horizontal else 'vertical'))
def run(self, the_map): """ Select the matching items and project them to the output file. """ self.style = self.require_style(self.style, the_map) self.match = self.require_match(self.match, the_map) self.match.set_svg_type(self.content_types[self.what]) if self.replacement is not None: self.replacement = the_map.get_symbol(self.replacement) for p in self.match.iter(the_map.input_svg): #TODO: handle multiple and nested transforms. pp = p.clone() if pp.t == 'path': # Paths are easy, since svgfig does most of the work for us # Caution: any svg transformations are passed on unchanged # (although the style attribute could be used in a sneaky way to override that) if the_map.clip(pp): continue self.style.apply(pp) pp = svgfig_mc.pathtoPath(pp).SVG(the_map.project) elif pp.t == 'text': # for texts, we have to consider existing transforms try: x, y = float(pp.attr['x']), float(pp.attr['y']) except KeyError: logger.error('Project.run: skipping text element {} without coordinates.'.format(pp.attr['id'])) continue m = svg_get_matrix(get_or_default(pp.attr, 'transform', '')) x0, y0 = m[0]*x + m[2]*y + m[4], m[1]*x + m[3]*y + m[5] if the_map.clip((x0, y0)): continue x1, y1 = the_map.project(x0, y0) m[4] += x1 - x0 m[5] += y1 - y0 pp.attr['transform'] = 'matrix({:f},{:f},{:f},{:f},{:f},{:f})'.format(*m) elif pp.t == 'g': # For markers, the Symbol class together with svg_transform # does most of the work of sizing, centering and placing the symbol #TODO: change the logic: a symbol is anything that matches the selection criteria x0, y0 = svg_center(pp) if the_map.clip((x0, y0)): continue x1, y1 = the_map.project(x, y) if self.replacement: pp = svg_transform(self.replacement.get_svg(), self.replacement.anchor[0], self.replacement.anchor[1], x1, y1, self.replacement.scale, self.replacement.scale) else: pp = svg_transform(pp, x, y, x1, y1) the_map.add_to_layer(self.target, pp) logger.info(u'Project.run: finished mapping: {}'.format(self.what))
def run(self, the_map): """ Draws meridians or parallels on the named layer. dt gives the degree separation of major to, subdiv gives the number of subdivisions. If r is given, the graticules are clipped this rectangle, otherwise the entire viewport is used. Subdiv is assumed to be (and in fact silently coerced to) an integer. Labels can be 'none', 'minor', 'major' or 'both'. """ # If the clipping rectangle is not given, default to the viewport. if self.clip is None: self.clip = the_map.rect_world else: self.clip = the_map.get_rectangle(self.clip) # Set up the clipping values in a way that is neutral with respect to direction # t0, t1 are the starting and ending values, s0, s1 are the endpoints of each line if self.horizontal: t0, t1, s0, s1 = self.clip.y0, self.clip.y1, self.clip.x0*pi/180, self.clip.x1*pi/180 else: t0, t1, s0, s1 = self.clip.x0, self.clip.x1, self.clip.y0*pi/180, self.clip.y1*pi/180 # Initialize the lines and the format strings for l in self.lines: l.initialize(the_map, s0, s1) strings = {} strings.update(the_map.strings) # walk over the interval [t0 .. t1] using the smallest subdivision and draw the highest-level line # at each division. We use degrees for iteration and convert to radians for drawing span = self.lines[-1].span for n in xrange(int(ceil(t0/span)), int(floor(t1/span))+1): # find the highest level line that is evenly divided into current position for l in self.lines: if (span * n) % l.span == 0: break t = span*n*pi/180 strings.update({'pos': span*n}) strings.update(float_to_dms(span*n, self.horizontal, the_map)) if self.horizontal: the_map.add_to_layer(self.target, l.hline(t).SVG(the_map.project_inner)) if l.labels: x, y = the_map.project_inner(l.pos, t) the_map.add_to_layer(self.target, l.get_label(x, y, strings)) else: the_map.add_to_layer(self.target, l.vline(t).SVG(the_map.project_inner)) if l.labels: x, y = the_map.project_inner(t, l.pos) the_map.add_to_layer(self.target, l.get_label(x, y, strings)) logger.info('Graticules.run: drew {} graticules'.format('horizontal' if self.horizontal else 'vertical'))
def __init__(self, d): Command.__init__(self, d) try: self.horizontal = get_or_default(d, 'direction', 'horizontal') == 'horizontal' self.clip = get_or_default(d, 'clip-to', None) self.lines = [] last_span = None for div in d['divisions']: l = self.OneLine(div) self.lines.append(l) # Succeeding spans must evenly divide each other if last_span and last_span % l.span != 0: raise MapperException(MX_WRONG_VALUE, 'Graticules.__init__', l.span, 'span') last_span = l.span except KeyError as ke: raise MapperException(MX_MISSING_PARAMETER, 'Graticules.__init__', str(ke), 'graticules') logger.info(u'Loaded {} graticules'.format('horizontal' if self.horizontal else 'vertical'))
def __init__(self, d): Command.__init__(self, d) try: self.horizontal = get_or_default(d, 'direction', 'horizontal') == 'horizontal' self.clip = get_or_default(d, 'clip-to', None) self.lines = [] last_span = None for div in d['divisions']: l = self.OneLine(div) self.lines.append(l) # Succeeding spans must evenly divide each other if last_span and last_span % l.span != 0: raise MapperException(MX_WRONG_VALUE, 'Graticules.__init__', l.span, 'span') last_span = l.span except KeyError as ke: raise MapperException(MX_MISSING_PARAMETER, 'Graticules.__init__', str(ke), 'graticules') logger.info(u'Loaded {} graticules'.format( 'horizontal' if self.horizontal else 'vertical'))
def run(self, the_map): """ Draw the lines and place the symbols and the labels. Lines are drawn first, followed by symbols and finally text. """ # Start by building a list of absolute positions in world coordinates. self.unit = the_map.get_unit(self.unit) x, y = self.at[0]*pi/180, self.at[1]*pi/180 world = [(x, y, 0)] for l in pairwise(self.at[2:]): try: if 'absolute' in self.mode: x1 = l[0]*pi/180 y1 = l[1]*pi/180 d = self.unit.measure(x, y, x1, y1) else: d = l[0] x1, y1 = self.unit.move_to(x, y, l[0], l[1]*pi/180) except IndexError: raise MapperException(MX_WRONG_VALUE, 'Place.run', 'at array', self.at) world.append((x1, y1, d)) if 'sequential' in self.mode: x, y = x1, y1 # Draw the lines, if any, in world coordinates and project it, so it's curved if it needs to be. if self.line: self.line_style = self.require_style(self.line_style, the_map) x, y, d = world[0] for w in world[1:]: path = svgfig_mc.Line(x, y, w[0], w[1], **self.line_style.attributes) the_map.add_to_layer(self.target, path.SVG(the_map.project_inner)) if 'sequential' in self.mode: x, y = w[0], w[1] # Place the symbols next #TODO: handle <defs> in the symbol source file to get blends right. if self.symbol: # replace symbol names with objects and make the list of symbols as long as the list of points if isinstance(self.symbol, basestring): self.symbol = [self.symbol] if len(self.symbol) > len(world): logger.warn('More symbols than points, discarding extra symbols') self.symbol = self.symbol[:len(world)] for i, s in enumerate(self.symbol): if s == '': self.symbol[i] = None else: sym = the_map.get_symbol(s) if sym is None: raise MapperException(MX_UNRESOLVED_REFERENCE, 'Place.run', 'symbol', s) else: self.symbol[i] = the_map.get_symbol(s) # place the symbols for s, (x, y, d) in izip_longest(self.symbol, world, fillvalue=self.symbol[-1]): if s is None: continue x, y = the_map.project_inner(x, y) svg = svg_transform(s.get_svg(), s.anchor[0], s.anchor[1], x, y, s.scale, s.scale) the_map.add_to_layer(self.target, svg) # then the labels if self.label: if isinstance(self.fmt, basestring): self.fmt = [self.fmt] if len(self.fmt) > len(world): logger.warn('More labels than points, discarding extra labels') self.fmt = self.fmt[:len(world)] for i, s in enumerate(self.fmt): self.fmt[i] = the_map.translate_string(s) self.label_style = self.require_style(self.label_style, the_map) # prepare the list of page coordinates and label strings and place the labels strings = {} strings.update(the_map.strings) for (i, (x, y, d)), f in izip_longest(enumerate(world), self.fmt, fillvalue=self.fmt[-1]): strings.update({'length': d, 'unit': self.unit, 'count': i, 'x-pos': x*180/pi, 'y-pos': y*180/pi}) strings.update(float_to_dms(x, False, the_map, prefix='x-')) strings.update(float_to_dms(y, True, the_map, prefix='y-')) x, y = the_map.project_inner(x + self.nudge[0], y + self.nudge[1]) try: txt = f.format(**strings) except KeyError as ke: raise MapperException(MX_UNRESOLVED_REFERENCE, 'Project.run', 'label format value', str(ke)) svg = svgfig_mc.Text(x, y, txt, **self.label_style.attributes).SVG(None) the_map.add_to_layer(self.target, svg) logger.info(u'Place.run: drew {} points'.format(len(world)))
def run(self, the_map): """ Draw the lines and place the symbols and the labels. Lines are drawn first, followed by symbols and finally text. """ # Start by building a list of absolute positions in world coordinates. self.unit = the_map.get_unit(self.unit) x, y = self.at[0] * pi / 180, self.at[1] * pi / 180 world = [(x, y, 0)] for l in pairwise(self.at[2:]): try: if 'absolute' in self.mode: x1 = l[0] * pi / 180 y1 = l[1] * pi / 180 d = self.unit.measure(x, y, x1, y1) else: d = l[0] x1, y1 = self.unit.move_to(x, y, l[0], l[1] * pi / 180) except IndexError: raise MapperException(MX_WRONG_VALUE, 'Place.run', 'at array', self.at) world.append((x1, y1, d)) if 'sequential' in self.mode: x, y = x1, y1 # Draw the lines, if any, in world coordinates and project it, so it's curved if it needs to be. if self.line: self.line_style = self.require_style(self.line_style, the_map) x, y, d = world[0] for w in world[1:]: path = svgfig_mc.Line(x, y, w[0], w[1], **self.line_style.attributes) the_map.add_to_layer(self.target, path.SVG(the_map.project_inner)) if 'sequential' in self.mode: x, y = w[0], w[1] # Place the symbols next #TODO: handle <defs> in the symbol source file to get blends right. if self.symbol: # replace symbol names with objects and make the list of symbols as long as the list of points if isinstance(self.symbol, basestring): self.symbol = [self.symbol] if len(self.symbol) > len(world): logger.warn( 'More symbols than points, discarding extra symbols') self.symbol = self.symbol[:len(world)] for i, s in enumerate(self.symbol): if s == '': self.symbol[i] = None else: sym = the_map.get_symbol(s) if sym is None: raise MapperException(MX_UNRESOLVED_REFERENCE, 'Place.run', 'symbol', s) else: self.symbol[i] = the_map.get_symbol(s) # place the symbols for s, (x, y, d) in izip_longest(self.symbol, world, fillvalue=self.symbol[-1]): if s is None: continue x, y = the_map.project_inner(x, y) svg = svg_transform(s.get_svg(), s.anchor[0], s.anchor[1], x, y, s.scale, s.scale) the_map.add_to_layer(self.target, svg) # then the labels if self.label: if isinstance(self.fmt, basestring): self.fmt = [self.fmt] if len(self.fmt) > len(world): logger.warn('More labels than points, discarding extra labels') self.fmt = self.fmt[:len(world)] for i, s in enumerate(self.fmt): self.fmt[i] = the_map.translate_string(s) self.label_style = self.require_style(self.label_style, the_map) # prepare the list of page coordinates and label strings and place the labels strings = {} strings.update(the_map.strings) for (i, (x, y, d)), f in izip_longest(enumerate(world), self.fmt, fillvalue=self.fmt[-1]): strings.update({ 'length': d, 'unit': self.unit, 'count': i, 'x-pos': x * 180 / pi, 'y-pos': y * 180 / pi }) strings.update(float_to_dms(x, False, the_map, prefix='x-')) strings.update(float_to_dms(y, True, the_map, prefix='y-')) x, y = the_map.project_inner(x + self.nudge[0], y + self.nudge[1]) try: txt = f.format(**strings) except KeyError as ke: raise MapperException(MX_UNRESOLVED_REFERENCE, 'Project.run', 'label format value', str(ke)) svg = svgfig_mc.Text(x, y, txt, **self.label_style.attributes).SVG(None) the_map.add_to_layer(self.target, svg) logger.info(u'Place.run: drew {} points'.format(len(world)))