def _draw_cell(self,x,y,window):
		position = XY(self.position.x+ x * self.scale, self.position.y + y * self.scale)
		bounds = XY(self.position.x+ (x + 1) * self.scale, self.position.y + (y+ 1) * self.scale)
		box = self.image_class(position, bounds)
		box.setFill('red' if self.board.cells[x][y].is_alive == True else 'grey')
		box.draw(window)
		self.board.cells[x][y].changed = False
Example #2
0
 def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY):
     """For each track, draw it on the poster."""
     if self.poster.tracks is None:
         raise PosterError("No tracks to draw.")
     cell_size, counts = utils.compute_grid(len(self.poster.tracks), size)
     if cell_size is None or counts is None:
         raise PosterError("Unable to compute grid.")
     count_x, count_y = counts[0], counts[1]
     spacing_x = (0 if count_x <= 1 else
                  (size.x - cell_size * count_x) / (count_x - 1))
     spacing_y = (0 if count_y <= 1 else
                  (size.y - cell_size * count_y) / (count_y - 1))
     offset.x += (size.x - count_x * cell_size -
                  (count_x - 1) * spacing_x) / 2
     offset.y += (size.y - count_y * cell_size -
                  (count_y - 1) * spacing_y) / 2
     for (index, tr) in enumerate(self.poster.tracks):
         p = XY(index % count_x, index // count_x) * XY(
             cell_size + spacing_x, cell_size + spacing_y)
         self._draw_track(
             dr,
             tr,
             0.9 * XY(cell_size, cell_size),
             offset + 0.05 * XY(cell_size, cell_size) + p,
         )
Example #3
0
def project(
        bbox: s2.LatLngRect, size: XY, offset: XY,
        latlnglines: List[List[s2.LatLng]]) -> List[List[Tuple[float, float]]]:
    min_x = lng2x(bbox.lng_lo().degrees)
    d_x = lng2x(bbox.lng_hi().degrees) - min_x
    while d_x >= 2:
        d_x -= 2
    while d_x < 0:
        d_x += 2
    min_y = lat2y(bbox.lat_lo().degrees)
    max_y = lat2y(bbox.lat_hi().degrees)
    d_y = abs(max_y - min_y)

    scale = size.x / d_x if size.x / size.y <= d_x / d_y else size.y / d_y
    offset = offset + 0.5 * (size - scale * XY(d_x, -d_y)) - scale * XY(
        min_x, min_y)
    lines = []
    for latlngline in latlnglines:
        line = []
        for latlng in latlngline:
            if bbox.contains(latlng):
                line.append((offset + scale * latlng2xy(latlng)).tuple())
            else:
                if len(line) > 0:
                    lines.append(line)
                    line = []
        if len(line) > 0:
            lines.append(line)
    return lines
Example #4
0
 def draw(self, drawer, output):
     """Set the Poster's drawer and draw the tracks."""
     self.tracks_drawer = drawer
     d = svgwrite.Drawing(output, (f"{self.width}mm", f"{self.height}mm"))
     d.viewbox(0, 0, self.width, self.height)
     d.add(
         d.rect((0, 0), (self.width, self.height),
                fill=self.colors["background"]))
     self.__draw_header(d)
     self.__draw_footer(d)
     self.__draw_tracks(d, XY(self.width - 20, self.height - 30 - 30),
                        XY(10, 30))
     d.save()
Example #5
0
class XYTests(unittest.TestCase):
    def setUp(self):
        self.m = XY(-100, -100, 100, 100)

    def test_empty_map(self):
        self.assertEqual(len(self.m.areas), 1)
        self.assertEqual(self.m.get_area_count(), (0, 1))
        self.assertEqual(self.m.find_area(0, 0).name, None)

    def test_one_area_replace(self):
        self.m.add_area(-100, -100, 100, 100, 'test')
        self.assertEqual(len(self.m.areas), 1)
        self.assertEqual(self.m.get_area_count(), (1, 0))
        self.assertEqual(self.m.find_area(0, 0).name, 'test')

    def test_one_area(self):
        m = XY(-100, -100, 100, 100)
        m.add_area(10, 20, -30, -40, 'test')
        self.assertEqual(len(m.areas), 5)
        self.assertEqual(m.get_area_count(), (1, 4))
        self.assertEqual(m.find_area(0, 0).name, 'test')
        self.assertEqual(m.find_area(20, 10).name, None)

    def test_area_overlaps(self):
        self.m.add_area(-20, -20, 20, 20, 'test')
        self.assertRaises(Exception, self.m.add_area, -10, -10, 10, 10,
                          'test2')
        self.assertRaises(Exception, self.m.add_area, -30, -30, 30, 30,
                          'test3')
        self.assertRaises(Exception, self.m.add_area, -30, -30, 10, 10,
                          'test4')
Example #6
0
class XYTests(unittest.TestCase):
	def setUp(self):
		self.m = XY(-100, -100, 100, 100)

	def test_empty_map(self):
		self.assertEqual(len(self.m.areas), 1)
		self.assertEqual(self.m.get_area_count(), (0, 1))
		self.assertEqual(self.m.find_area(0, 0).name, None)

	def test_one_area_replace(self):
		self.m.add_area(-100, -100, 100, 100, 'test')
		self.assertEqual(len(self.m.areas), 1)
		self.assertEqual(self.m.get_area_count(), (1, 0))
		self.assertEqual(self.m.find_area(0, 0).name, 'test')

	def test_one_area(self):
		m = XY(-100, -100, 100, 100)
		m.add_area(10, 20, -30, -40, 'test')
		self.assertEqual(len(m.areas), 5)
		self.assertEqual(m.get_area_count(), (1, 4))
		self.assertEqual(m.find_area(0, 0).name, 'test')
		self.assertEqual(m.find_area(20, 10).name, None)

	def test_area_overlaps(self):
		self.m.add_area(-20, -20, 20, 20, 'test')
		self.assertRaises(Exception, self.m.add_area, -10, -10, 10, 10, 'test2')
		self.assertRaises(Exception, self.m.add_area, -30, -30, 30, 30, 'test3')
		self.assertRaises(Exception, self.m.add_area, -30, -30, 10, 10, 'test4')
Example #7
0
 def test_one_area(self):
     m = XY(-100, -100, 100, 100)
     m.add_area(10, 20, -30, -40, 'test')
     self.assertEqual(len(m.areas), 5)
     self.assertEqual(m.get_area_count(), (1, 4))
     self.assertEqual(m.find_area(0, 0).name, 'test')
     self.assertEqual(m.find_area(20, 10).name, None)
Example #8
0
 def draw(self, drawer, output):
     """Set the Poster's drawer and draw the tracks."""
     self.tracks_drawer = drawer
     height = self.height
     width = self.width
     if self.drawer_type == "plain":
         height = height - 100
         self.colors["background"] = "#1a1a1a"
         self.colors["track"] = "red"
         self.colors["special"] = "yellow"
         self.colors["text"] = "#e1ed5e"
     d = svgwrite.Drawing(output, (f"{width}mm", f"{height}mm"))
     d.viewbox(0, 0, self.width, height)
     d.add(d.rect((0, 0), (width, height), fill=self.colors["background"]))
     if not self.drawer_type == "plain":
         self.__draw_header(d)
         self.__draw_footer(d)
         self.__draw_tracks(d, XY(width - 20, height - 30 - 30), XY(10, 30))
     else:
         self.__draw_tracks(d, XY(width - 20, height), XY(10, 0))
     d.save()
Example #9
0
	def test_one_area(self):
		m = XY(-100, -100, 100, 100)
		m.add_area(10, 20, -30, -40, 'test')
		self.assertEqual(len(m.areas), 5)
		self.assertEqual(m.get_area_count(), (1, 4))
		self.assertEqual(m.find_area(0, 0).name, 'test')
		self.assertEqual(m.find_area(20, 10).name, None)
Example #10
0
    def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY):
        """Draw the circular Poster using distances broken down by time"""
        if self.poster.tracks is None:
            raise PosterError("No tracks to draw.")
        if self.poster.length_range_by_date is None:
            return

        years = self.poster.years.count()
        _, counts = utils.compute_grid(years, size)
        if counts is None:
            raise PosterError("Unable to compute grid.")
        count_x, count_y = counts[0], counts[1]
        x, y = 0, 0
        cell_size = size * XY(1 / count_x, 1 / count_y)
        margin = XY(4, 4)
        if count_x <= 1:
            margin.x = 0
        if count_y <= 1:
            margin.y = 0
        sub_size = cell_size - 2 * margin
        for year in range(self.poster.years.from_year,
                          self.poster.years.to_year + 1):
            self._draw_year(dr, sub_size,
                            offset + margin + cell_size * XY(x, y), year)
            x += 1
            if x >= count_x:
                x = 0
                y += 1
Example #11
0
    def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY):
        """Iterate through the Poster's years, creating a calendar for each."""
        if self.poster.tracks is None:
            raise PosterError("No tracks to draw.")
        years = self.poster.years.count()
        _, counts = utils.compute_grid(years, size)
        if counts is None:
            raise PosterError("Unable to compute grid.")
        count_x, count_y = counts[0], counts[1]
        x, y = 0, 0
        cell_size = size * XY(1 / count_x, 1 / count_y)
        margin = XY(4, 8)
        if count_x <= 1:
            margin.x = 0
        if count_y <= 1:
            margin.y = 0
        sub_size = cell_size - 2 * margin

        for year in range(self.poster.years.from_year,
                          self.poster.years.to_year + 1):
            self._draw(dr, sub_size, offset + margin + cell_size * XY(x, y),
                       year)
            x += 1
            if x >= count_x:
                x = 0
                y += 1
Example #12
0
 def _draw_rings(self, dr: svgwrite.Drawing, center: XY,
                 radius_range: ValueRange):
     length_range = self.poster.length_range_by_date
     ring_distance = self._determine_ring_distance()
     if ring_distance is None:
         return
     distance = ring_distance
     while distance < length_range.upper():
         radius = (
             radius_range.lower() +
             radius_range.diameter() * distance / length_range.upper())
         dr.add(
             dr.circle(
                 center=center.tuple(),
                 r=radius,
                 stroke=self._ring_color,
                 stroke_opacity="0.2",
                 fill="none",
                 stroke_width=0.3,
             ))
         distance += ring_distance
Example #13
0
def latlng2xy(latlng: s2.LatLng) -> XY:
    return XY(lng2x(latlng.lng().degrees), lat2y(latlng.lat().degrees))
Example #14
0
import json, sys
from os import path
from PIL import Image, ImageDraw
from argparse import ArgumentParser, ArgumentTypeError

from xy import XY

page_sizes = {
    'none': None,
    'a0': XY(33.11, 46.81),
    'a1': XY(23.39, 33.11),
    'a2': XY(16.54, 23.39),
    'a3': XY(11.69, 16.54),
    'a4': XY(8.27, 11.69),
    'letter': XY(8.5, 11),
    'legal': XY(8.5, 14),
    'ledger': XY(11, 17),
    'tabloid': XY(17, 11),
    '11x17': XY(11, 17)
}


def setupArgParser(parser=None):
    if not parser:
        parser = ArgumentParser(
            description=
            "Split an image for multi-page printing, based on DPI specified in the image"
        )
        parser.add_argument('source_image', help='The image to split')
        parser.add_argument('output_base',
                            nargs='?',
	def __init__(self,board, position = XY(0,0), scale = 5, image_class = Rectangle):
		self.board = board
		self.image_class= image_class
		self.position = position
		self.scale = scale
		self.bounds = XY(position.x + scale * board.size, position.y + scale * board.size)
Example #16
0
	def setUp(self):
		self.m = XY(-100, -100, 100, 100)
Example #17
0
try:
    travel = reload(travel)
except:
    import travel

import ga
import sys

if len(sys.argv) == 1:
    from xy import XY as Indiv
else:
    Indiv = travel.Travel
    Indiv.load('tsp.yaml')
print('Best:')
ga.ga(Indiv).display()

# compare to best out of 100
best = Indiv()
best.randomize()
best.compute_cost()
for i in xrange(10000):
    indiv = Indiv()
    indiv.randomize()
    indiv.compute_cost()
    if indiv.cost < best.cost:
        best = indiv
print('Random:')
best.display()
Example #18
0
def saveTiledImages(image,
                    basename,
                    pageXY_inches,
                    margin_inches,
                    overlap_inches,
                    ext='.png',
                    dpi=None,
                    register_marks=True):

    if not dpi:
        try:
            dpi = image.info['dpi'][0]
        except:
            sys.exit(
                "savedTiledImages: No DPI specified explicitly or found in image"
            )

    if not pageXY_inches:  # just save full size image
        fname = basename + ext
        image.save(fname, dpi=(dpi, dpi))
        return [fname]  # early return

    # create the split up images
    margin_px = int(margin_inches * dpi)
    overlap_px = int(overlap_inches * dpi)

    tileXY_px = (pageXY_inches * dpi - XY(1, 1) * 2 * margin_px).ints()

    fullXY_px = XY(*image.size)

    # Try tiling both portrait and landscape modes
    tiling1 = XY(subdivide(fullXY_px.x, tileXY_px.x, overlap_px),
                 subdivide(fullXY_px.y, tileXY_px.y, overlap_px))
    pages1 = XY(*map(len, tiling1))

    tiling2 = XY(subdivide(fullXY_px.x, tileXY_px.y, overlap_px),
                 subdivide(fullXY_px.y, tileXY_px.x, overlap_px))
    pages2 = XY(*map(len, tiling2))

    n1 = pages1.x * pages1.y
    n2 = pages2.x * pages2.y
    if n1 < n2:
        print "Using standard (portrait) tiling on %d pages (%dx%d vs %dx%d)" % (
            n1, pages1.x, pages1.y, pages2.x, pages2.y)
        tiling = tiling1
        pages = pages1
    else:
        print "Using rotated (landscape) tiling on %d pages (%dx%d vs %dx%d)" % (
            n2, pages2.x, pages2.y, pages1.x, pages1.y)
        tiling = tiling2
        pages = pages2
        tileXY_px = tileXY_px.swap()

    outputs = []
    for i, x in enumerate(map(int, tiling.x)):
        for j, y in enumerate(map(int, tiling.y)):
            tile = image.crop((x, y, min(fullXY_px.x, x + tileXY_px.x),
                               min(fullXY_px.y, y + tileXY_px.y)))
            tile.load()  # force a non-destructive copy

            # possibly draw register marks
            if register_marks:
                canvas = ImageDraw.Draw(tile)
                xt, yt = tile.size
                d = overlap_px / 10
                xo, yo = overlap_px / 2, overlap_px / 2
                if i > 0 or j > 0:
                    canvas.line((xo - d, yo, 0, yo), width=1, fill='black')
                    canvas.line((xo, yo - d, xo, 0), width=1, fill='black')

                xo, yo = overlap_px / 2, yt - overlap_px / 2
                if i > 0 or j + 1 < pages.y:
                    canvas.line((xo - d, yo, 0, yo), width=1, fill='black')
                    canvas.line((xo, yo + d, xo, yt), width=1, fill='black')

                xo, yo = xt - overlap_px / 2, overlap_px / 2
                if i + 1 < pages.x or j > 0:
                    canvas.line((xo + d, yo, xt, yo), width=1, fill='black')
                    canvas.line((xo, yo - d, xo, 0), width=1, fill='black')

                xo, yo = xt - overlap_px / 2, yt - overlap_px / 2
                if i + 1 < pages.x or j + 1 < pages.y:
                    canvas.line((xo + d, yo, xt, yo), width=1, fill='black')
                    canvas.line((xo, yo + d, xo, yt), width=1, fill='black')

            fname = basename + '%02d%02d' % (i + 1, j + 1) + ext
            outputs.append(fname)
            tile.save(fname, dpi=(dpi, dpi))

    return outputs
Example #19
0
    def _draw_year(self, dr: svgwrite.Drawing, size: XY, offset: XY,
                   year: int):
        min_size = min(size.x, size.y)
        outer_radius = 0.5 * min_size - 6
        radius_range = ValueRange.from_pair(outer_radius / 4, outer_radius)
        center = offset + 0.5 * size

        if self._rings:
            self._draw_rings(dr, center, radius_range)

        year_style = f"dominant-baseline: central; font-size:{min_size * 4.0 / 80.0}px; font-family:Arial;"
        month_style = f"font-size:{min_size * 3.0 / 80.0}px; font-family:Arial;"

        dr.add(
            dr.text(
                f"{year}",
                insert=center.tuple(),
                fill=self.poster.colors["text"],
                text_anchor="middle",
                alignment_baseline="middle",
                style=year_style,
            ))
        df = 360.0 / (366 if calendar.isleap(year) else 365)
        day = 0
        date = datetime.date(year, 1, 1)
        while date.year == year:
            text_date = date.strftime("%Y-%m-%d")
            a1 = math.radians(day * df)
            a2 = math.radians((day + 1) * df)
            if date.day == 1:
                (_, last_day) = calendar.monthrange(date.year, date.month)
                a3 = math.radians((day + last_day - 1) * df)
                sin_a1, cos_a1 = math.sin(a1), math.cos(a1)
                sin_a3, cos_a3 = math.sin(a3), math.cos(a3)
                r1 = outer_radius + 1
                r2 = outer_radius + 6
                r3 = outer_radius + 2
                dr.add(
                    dr.line(
                        start=(center + r1 * XY(sin_a1, -cos_a1)).tuple(),
                        end=(center + r2 * XY(sin_a1, -cos_a1)).tuple(),
                        stroke=self.poster.colors["text"],
                        stroke_width=0.3,
                    ))
                path = dr.path(
                    d=("M", center.x + r3 * sin_a1, center.y - r3 * cos_a1),
                    fill="none",
                    stroke="none",
                )
                path.push(
                    f"a{r3},{r3} 0 0,1 {r3 * (sin_a3 - sin_a1)},{r3 * (cos_a1 - cos_a3)}"
                )
                dr.add(path)
                tpath = svgwrite.text.TextPath(path,
                                               date.strftime("%B"),
                                               startOffset=(0.5 * r3 *
                                                            (a3 - a1)))
                text = dr.text(
                    "",
                    fill=self.poster.colors["text"],
                    text_anchor="middle",
                    style=month_style,
                )
                text.add(tpath)
                dr.add(text)
            if text_date in self.poster.tracks_by_date:
                self._draw_circle_segment(
                    dr,
                    self.poster.tracks_by_date[text_date],
                    a1,
                    a2,
                    radius_range,
                    center,
                )

            day += 1
            date += datetime.timedelta(1)
Example #20
0
 def setUp(self):
     self.m = XY(-100, -100, 100, 100)
Example #21
0
    def _draw(self, dr: svgwrite.Drawing, size: XY, offset: XY, year: int):
        min_size = min(size.x, size.y)
        year_size = min_size * 4.0 / 80.0
        year_style = f"font-size:{year_size}px; font-family:Arial;"
        month_style = f"font-size:{min_size * 3.0 / 80.0}px; font-family:Arial;"
        day_style = f"dominant-baseline: central; font-size:{min_size * 1.0 / 80.0}px; font-family:Arial;"
        day_length_style = f"font-size:{min_size * 1.0 / 80.0}px; font-family:Arial;"

        dr.add(
            dr.text(
                f"{year}",
                insert=offset.tuple(),
                fill=self.poster.colors["text"],
                alignment_baseline="hanging",
                style=year_style,
            ))
        offset.y += year_size
        size.y -= year_size
        count_x = 31
        for month in range(1, 13):
            date = datetime.date(year, month, 1)
            (_, last_day) = calendar.monthrange(year, month)
            count_x = max(count_x, date.weekday() + last_day)

        cell_size = min(size.x / count_x, size.y / 36)
        spacing = XY(
            (size.x - cell_size * count_x) / (count_x - 1),
            (size.y - cell_size * 3 * 12) / 11,
        )

        # chinese weekday key number is the third.
        keyword_num = 0
        if locale.getlocale()[0] == "zh_CN":
            keyword_num = 2
        # first character of localized day names, starting with Monday.
        dow = [
            locale.nl_langinfo(day)[keyword_num].upper() for day in [
                locale.DAY_2,
                locale.DAY_3,
                locale.DAY_4,
                locale.DAY_5,
                locale.DAY_6,
                locale.DAY_7,
                locale.DAY_1,
            ]
        ]

        for month in range(1, 13):
            date = datetime.date(year, month, 1)
            y = month - 1
            y_pos = offset.y + (y * 3 + 1) * cell_size + y * spacing.y
            dr.add(
                dr.text(
                    date.strftime("%B"),
                    insert=(offset.x, y_pos - 2),
                    fill=self.poster.colors["text"],
                    alignment_baseline="hanging",
                    style=month_style,
                ))

            day_offset = date.weekday()
            while date.month == month:
                x = date.day - 1
                x_pos = offset.x + (day_offset + x) * cell_size + x * spacing.x
                pos = (x_pos + 0.05 * cell_size, y_pos + 1.15 * cell_size)
                dim = (cell_size * 0.9, cell_size * 0.9)
                text_date = date.strftime("%Y-%m-%d")
                if text_date in self.poster.tracks_by_date:
                    tracks = self.poster.tracks_by_date[text_date]
                    length = sum([t.length for t in tracks])
                    has_special = len([t for t in tracks if t.special]) > 0
                    color = self.color(self.poster.length_range_by_date,
                                       length, has_special)
                    dr.add(dr.rect(pos, dim, fill=color))
                    dr.add(
                        dr.text(
                            utils.format_float(self.poster.m2u(length)),
                            insert=(
                                pos[0] + cell_size / 2,
                                pos[1] + cell_size + cell_size / 2,
                            ),
                            text_anchor="middle",
                            style=day_length_style,
                            fill=self.poster.colors["text"],
                        ))
                else:
                    dr.add(dr.rect(pos, dim, fill="#444444"))

                dr.add(
                    dr.text(
                        dow[date.weekday()],
                        insert=(
                            offset.x + (day_offset + x) * cell_size +
                            cell_size / 2,
                            pos[1] + cell_size / 2,
                        ),
                        text_anchor="middle",
                        alignment_baseline="middle",
                        style=day_style,
                    ))
                date += datetime.timedelta(1)
Example #22
0
    def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY):
        if self.poster.tracks is None:
            raise PosterError("No tracks to draw")
        year_size = 200 * 4.0 / 80.0
        year_style = f"font-size:{year_size}px; font-family:Arial;"
        year_length_style = f"font-size:{110 * 3.0 / 80.0}px; font-family:Arial;"
        month_names_style = f"font-size:2.5px; font-family:Arial"
        total_length_year_dict = self.poster.total_length_year_dict
        for year in self.poster.years:
            start_date_weekday, _ = calendar.monthrange(year, 1)
            github_rect_first_day = datetime.date(year, 1, 1)
            # Github profile the first day start from the last Monday of the last year or the first Monday of this year
            # It depands on if the first day of this year is Monday or not.
            github_rect_day = github_rect_first_day + datetime.timedelta(
                -start_date_weekday)
            year_length = total_length_year_dict.get(year, 0)
            month_names = [
                locale.nl_langinfo(day)[:3]  # Get only first three letters
                for day in [
                    locale.MON_1,
                    locale.MON_2,
                    locale.MON_3,
                    locale.MON_4,
                    locale.MON_5,
                    locale.MON_6,
                    locale.MON_7,
                    locale.MON_8,
                    locale.MON_9,
                    locale.MON_10,
                    locale.MON_11,
                    locale.MON_12,
                ]
            ]
            dr.add(
                dr.text(
                    f"{year}",
                    insert=offset.tuple(),
                    fill=self.poster.colors["text"],
                    alignment_baseline="hanging",
                    style=year_style,
                ))

            dr.add(
                dr.text(
                    f"{year_length} Likes",
                    insert=(offset.tuple()[0] + 160, offset.tuple()[1] + 4),
                    fill=self.poster.colors["text"],
                    alignment_baseline="hanging",
                    style=year_length_style,
                ))
            # add month name up to the poster one by one because of svg text auto trim the spaces.
            for num, name in enumerate(month_names):
                dr.add(
                    dr.text(
                        f"{name}",
                        insert=(offset.tuple()[0] + 15.5 * num,
                                offset.tuple()[1] + 14),
                        fill=self.poster.colors["text"],
                        style=month_names_style,
                    ))

            rect_x = 10.0
            dom = (2.6, 2.6)
            # add every day of this year for 53 weeks and per week has 7 days
            for i in range(54):
                rect_y = offset.y + year_size + 2
                for j in range(7):
                    if int(github_rect_day.year) > year:
                        break
                    rect_y += 3.5
                    color = "#444444"
                    date_title = str(github_rect_day)
                    if date_title in self.poster.tracks_by_date:
                        tracks = self.poster.tracks_by_date[date_title]
                        likes = sum([t["likes_count"] for t in tracks])
                        likes_gap = self.poster.special_likes["special_likes"]
                        likes_gap2 = self.poster.special_likes[
                            "special_likes2"]
                        if year < 2014:
                            likes_gap = likes_gap / 10
                            likes_gap2 = likes_gap2 / 10
                        has_special = likes_gap < likes < likes_gap2
                        color = self.color(self.poster.length_range_by_date,
                                           likes, has_special)
                        if likes >= likes_gap2:
                            color = self.poster.colors.get(
                                "special2") or self.poster.colors.get(
                                    "special")
                        str_likes = str(likes)
                        date_title = f"{date_title} {str_likes} Likes"

                    rect = dr.rect((rect_x, rect_y), dom, fill=color)
                    rect.set_desc(title=date_title)
                    dr.add(rect)
                    github_rect_day += datetime.timedelta(1)
                rect_x += 3.5
            offset.y += 3.5 * 9 + year_size + 1.5
Example #23
0
class Board:
    hexXY = XY(188,217)                 # size of tile images in pixels
    unitTL = XY(44,80)                  # top-left corner of unit symbol
    tagOffset = XY(39, -42)             # offset of medal tag center from hex center
    badgeSize = XY(64,64)               # size to scale unit badges to
#    background_color = (79,105,66)     # olive green
    background_color = (255,255,255)    # white
    border_color = (0,0,0)              # black
    border_width = 1                    # pixels
    marginXY = hexXY.doti((1/3., 1/2.)) # whitespace around tiles
    dash_color = (214,35,44)            # dark red
    dash_length = (36,9)                # black/white length in pixels
    dash_width = 7                      # pixels
    
    formats = {
        'standard' : XY(13,9),      # 2570 x 1737 px @ 90DPI = 28.6" x 19.3"
        'overlord' : XY(26,9),      # 5014 x 1737 px @ 90DPI = 55.7" x 19.3"
        'brkthru'  : XY(13,17)      # 2570 x 3039 px @ 90DPI = 28.6" x 33.8"
    }
    
    # the hexagon keys we can deal with, layered from bottom up
    drawing_layers = [
        'terrain',      # hexagonal terrain tile
        'lines',        # pseudo-layer to draw dotted lines between flanks
        'rect_terrain', # rectangular tile, like a bunker
        'obstacle',     # 3D obstacle like sandbags
        'unit',         # unit indicator, includes nbr_units and badge sublayers
        'tags',         # token like victory marker
        'text'          # map label
    ]
        
    # return a list of background terrain names based on board format/style
    @staticmethod
    def backgroundTerrain(face, format):
        faces = {
            'country' :     [['countryside']],
            'winter' :      [['snow']],
            'beach' :       [['countryside'],['beach'],['coast'],['ocean']],
            'desert' :      [['desert']]
            }   
                 
        names = faces[face]
        
        if face == 'beach':
            if format == 'brkthru':
                repeat = (11,3,1,2)
            else:
                repeat = (4,3,1,1)
        else:
            if format == 'brkthru':
                repeat = (17,)
            else:
                repeat = (9,)
    
        return sum(map(operator.mul, names, repeat),[])
            
    # coordinates - we use a system where each row and column counts 0,1,2,...
    # with top right starting from 0,0
    @staticmethod
    def coords(row, col):
      xy = Board.hexXY.doti((col + (row%2)/2., row * 3 / 4.))
      return xy + Board.marginXY
    
    # convert from  m44 format where even rows have even cols, odd rows have odd cols
    @staticmethod
    def coords2(row, col2):
      return Board.coords(row, (col2 - (row%2))/2)

    def __init__(self, m44file):
        scenario = json.load(open(m44file))
        self.info = scenario['board']
        # info is a dictionary with board details like:
        # u'labels': [], 
        # u'hexagons': [{u'terrain': {u'name': u'highground'}, u'col': 0, u'row': 0}, ... 
        # u'type': u'STANDARD', 
        # u'face': u'WINTER'}

        self.game_info = scenario['game_info']
        # Scenario name is in a localized block, so take first localization
        # (maybe better to prefer a specific language?)
        # scenario = { "text": { "en": { "name": "My title", ...
        try:
            self.text = scenario['text'].values()[0]
        except:
            self.text = {}
        
        if not self.text.has_key('name'):
            self.text['name'] = '(unnamed scenario'
        
        # get the size and background icon generator
        format,face = self.info['type'].lower(),self.info['face'].lower()
        
        self.cols, self.rows = Board.formats[format]
        self.rowStyles = Board.backgroundTerrain(face,format)

    def render(self, icons, skipLayers = [], hexWidth = 2.0866):
        # create a blank empty board image with correct size and scaling (DPI)
        size = Board.marginXY * 2 + \
            Board.hexXY.doti( (self.cols, (self.rows*3+1)/4.) )
        board = Image.new('RGB', size, Board.background_color)
        canvas = ImageDraw.Draw(board)
        
        # use hexWidthto choose a particular hex width in inches
        # actual M44 tiles are 2.0866" (53mm) across the flats
        dpi = int(round(Board.hexXY.x / hexWidth))
        
        try:
            font = ImageFont.truetype('verdanab.ttf',32)
        except:
            logging.warn("Couldn't open VerdanaBold TTF, using (ugly) system default")
            font = ImageFont.load_default()
            
        # paint the board background
        outline = icons.getImage('outline')
        for row in xrange(self.rows):
            name = self.rowStyles[row]
            image = icons.getImage(name)
            if not image:
                logging.warn("No background image for %s"%name)
                continue
            
            for col in xrange(self.cols - (row%2)): # skip last hex on odd rows
                xy = Board.coords(row,col)
                if outline: board.paste(outline, tuple(xy), outline)
                board.paste(image, tuple(xy), image)

        # medal1 - Allies Medal
        # medal2 - German Medal
        # <note there isn't a medal3>
        # medal4 - Victoria Cross
        # medal5 - Italian Medal of Valor
        # medal6 - Hero of the Soviet Union Medal
        # medal7 - Order of the Golden Kite Medal
		medal_dict = {
		    # Default axis / allies medals in side_player[1|2] value
		    'ALLIES' : 1, 'AXIS' : 2, 
		    # Country-specific medals, coded in country_player[1|2] value
		    'US' : 1, 'DE' : 2, 'GB' : 4, 'IT' : 5, 'RU' : 6, 'JP' : 7
		}
		
        # paint the victory medals, with player1 at the top (flipped)
        # and player2 at the bottom.
        for p in ['1','2']:
            vp = self.game_info.get('victory_player' + p, 6)
            
            side = self.game_info.get('side_player' + p, '')
            country = self.game_info.get('country_player' + p, '')
            
            medal_num = medal_dict.get(country, None)
            if not medal_num:
                medal_num = medal_dict.get(side, None)
                
            medal_name = 'medal' + (medal_num and `medal_num`) or p
            
            medal = icons.getImage(medal_name)
            if not medal:
                logging.warn("Couldn't find victory marker image %s"%name)
                continue
                
            medal = medal.crop(medal.getbbox())
            if p == '1':    # Draw top medals upside facing board edge
                medal = ImageOps.flip(medal)
            medal = medal.resize((XY(*medal.size) * 1.5).ints(),Image.ANTIALIAS)
            mxy = XY(*medal.size)
            for col in xrange(self.cols-vp,self.cols):
                xy = Board.coords(0, col) - mxy.doti((1/2.,3/4.))
                if p == '2':    # Position bottom medals by reflection
                    xy = - xy - mxy + board.size
                board.paste(medal,tuple(xy),medal)

        # label the scenario
        canvas.text(Board.marginXY.doti( (1/2., 1/3.) ),
            self.text['name'], fill = 'black', font=font)
        
        # warn about layers we won't deal with
        for hexagon in self.info['labels'] + self.info['hexagons']:
            if any(k not in Board.drawing_layers + ['col','row'] 
                    for k in hexagon.keys()):
                logging.warn('unknown key in %s'%`hexagon.keys()`)
                    
        # now paint on the overlay elements
        for key in Board.drawing_layers:
            if key in skipLayers:
                continue            # skipping this layer?
                
            if key is 'lines':      # placeholder for flank lines
                col = 0
                while col < self.cols:
                    for inc in [4,5,4]:
                       col += inc
                       if col >= self.cols:
                           break
                           
                       # Find starting point of dashed flank line
                       (x,y1) = Board.coords(0,col)
                       x -= Board.dash_width / 2 - 2
                       y1 += Board.hexXY.y/4
                       # Find ending point
                       y2 = Board.coords(self.rows,0).y
                       
                       # Draw the dashed line
                       y = y1
                       while y < y2:
                           ye = min(y2, y+Board.dash_length[0])
                           canvas.line([(x,y),(x,ye)], 
                               fill=Board.dash_color, width=Board.dash_width) 
                           y += sum(Board.dash_length)
                           
                continue            # on to next layer
                
            hexagons = self.info['labels' if key is 'text' else 'hexagons']
            for hexagon in hexagons:
                col,row = hexagon['col'],hexagon['row']

                content = hexagon.get(key,None)
                if not content: continue
                
                # make everything a list for simplicity
                if type(content) is not ListType:
                    contents = [content]
                else:
                    contents = content

                xy = Board.coords2(row,col)
                
                if key is 'text':
                    for (i,content) in enumerate(contents):
                        wh = XY(*canvas.textsize(content, font=font))
                        pos = xy + Board.hexXY.doti( (1/2., 3/4.) ) \
                            - wh.doti( (1/2., 1.1*(len(contents)/2. - i)) )
                        canvas.text(pos, content, fill="black", font=font)
                        
                    continue            # on to next hex
                
                # sort contents by name to get consistent order for tags
                contents.sort(key = lambda c: c['name'])
                for i,content in enumerate(contents):
                    name = content['name']
                    image = icons.getImage(name, content.get('orientation',1))
                    if not image:
                        logging.warn("(col=%d, row=%d): No image for %s"%(
                            col,row,name))
                        continue
                    
                    # hack to deal with multiple medal tags in a single hex
                    # but won't work for things like 'battle stars' (named "tag1")
                    # which is already centered in lower right
                    if i > 0:
                        offset = Board.tagOffset.dot(
                            [(1,1),(-1,-1),(-1,1),(1,-1)][i%4]) - Board.tagOffset
                        logging.debug("%s:%d:%s at (col=%d, row=%d) - offset by %s"%(
                            key,i,name, col, row, `offset`))
                        xy = xy + offset
                        if key is not 'tags':
                            logging.warn(
"Didn't expect multiple instances of [%s] at (col=%d, row=%d)"%(key, col, row))
                        elif i > 3:
                            logging.warn(
"Can't deal with more than four tags at (col=%d, row=%d)"%(col,row))
                        
                            
                    board.paste(image,tuple(xy),image)
                    
                    if i > 0: 
                        # center of medal tag is top-right, about XY(133,66),
                        #, i.e about +39, -42 from center of hex XY(188,217)
                        # for subsequent ones, move them around the hex 
                        # to bottom-left, bottom-right, top-left?
                        logging.debug('(col=%d,row=%d), name=%s, item #=%d'%(
                            col,row,name,i))
                    
                    # handle nbr_units and badge attributes within unit layer
                    if content.has_key('badge'):    # unit badges
                        # badges are not padded to hex size, and too small
                        # so resize and center on unit top left corner
                        image = icons.getImage(content['badge'])
                        image = image.resize(Board.badgeSize,Image.ANTIALIAS)
                        if image:
                            pos = xy + Board.unitTL - Board.badgeSize / 2
                            board.paste(image, tuple(pos), image)
                            
                    if content.has_key('nbr_units'):
                        image = icons.getImage('nbr_units', int(content['nbr_units']))
                        if image:
                            board.paste(image, tuple(xy), image)
              
        board = ImageOps.expand(
            board, border=Board.border_width, fill=Board.border_color)
        board.info['dpi'] = (dpi,dpi)
        
        return board
	def click(self,pos):
		if self._within_bounds(pos):
			self.board.toggle(XY(int((pos.x-self.position.x)//self.scale),int((pos.y-self.position.y)//self.scale)))
Example #25
0
    def render(self, icons, skipLayers = [], hexWidth = 2.0866):
        # create a blank empty board image with correct size and scaling (DPI)
        size = Board.marginXY * 2 + \
            Board.hexXY.doti( (self.cols, (self.rows*3+1)/4.) )
        board = Image.new('RGB', size, Board.background_color)
        canvas = ImageDraw.Draw(board)
        
        # use hexWidthto choose a particular hex width in inches
        # actual M44 tiles are 2.0866" (53mm) across the flats
        dpi = int(round(Board.hexXY.x / hexWidth))
        
        try:
            font = ImageFont.truetype('verdanab.ttf',32)
        except:
            logging.warn("Couldn't open VerdanaBold TTF, using (ugly) system default")
            font = ImageFont.load_default()
            
        # paint the board background
        outline = icons.getImage('outline')
        for row in xrange(self.rows):
            name = self.rowStyles[row]
            image = icons.getImage(name)
            if not image:
                logging.warn("No background image for %s"%name)
                continue
            
            for col in xrange(self.cols - (row%2)): # skip last hex on odd rows
                xy = Board.coords(row,col)
                if outline: board.paste(outline, tuple(xy), outline)
                board.paste(image, tuple(xy), image)

        # medal1 - Allies Medal
        # medal2 - German Medal
        # <note there isn't a medal3>
        # medal4 - Victoria Cross
        # medal5 - Italian Medal of Valor
        # medal6 - Hero of the Soviet Union Medal
        # medal7 - Order of the Golden Kite Medal
		medal_dict = {
		    # Default axis / allies medals in side_player[1|2] value
		    'ALLIES' : 1, 'AXIS' : 2, 
		    # Country-specific medals, coded in country_player[1|2] value
		    'US' : 1, 'DE' : 2, 'GB' : 4, 'IT' : 5, 'RU' : 6, 'JP' : 7
		}
		
        # paint the victory medals, with player1 at the top (flipped)
        # and player2 at the bottom.
        for p in ['1','2']:
            vp = self.game_info.get('victory_player' + p, 6)
            
            side = self.game_info.get('side_player' + p, '')
            country = self.game_info.get('country_player' + p, '')
            
            medal_num = medal_dict.get(country, None)
            if not medal_num:
                medal_num = medal_dict.get(side, None)
                
            medal_name = 'medal' + (medal_num and `medal_num`) or p
            
            medal = icons.getImage(medal_name)
            if not medal:
                logging.warn("Couldn't find victory marker image %s"%name)
                continue
                
            medal = medal.crop(medal.getbbox())
            if p == '1':    # Draw top medals upside facing board edge
                medal = ImageOps.flip(medal)
            medal = medal.resize((XY(*medal.size) * 1.5).ints(),Image.ANTIALIAS)
            mxy = XY(*medal.size)
            for col in xrange(self.cols-vp,self.cols):
                xy = Board.coords(0, col) - mxy.doti((1/2.,3/4.))
                if p == '2':    # Position bottom medals by reflection
                    xy = - xy - mxy + board.size
                board.paste(medal,tuple(xy),medal)

        # label the scenario
        canvas.text(Board.marginXY.doti( (1/2., 1/3.) ),
            self.text['name'], fill = 'black', font=font)
        
        # warn about layers we won't deal with
        for hexagon in self.info['labels'] + self.info['hexagons']:
            if any(k not in Board.drawing_layers + ['col','row'] 
                    for k in hexagon.keys()):
                logging.warn('unknown key in %s'%`hexagon.keys()`)
                    
        # now paint on the overlay elements
        for key in Board.drawing_layers:
            if key in skipLayers:
                continue            # skipping this layer?
                
            if key is 'lines':      # placeholder for flank lines
                col = 0
                while col < self.cols:
                    for inc in [4,5,4]:
                       col += inc
                       if col >= self.cols:
                           break
                           
                       # Find starting point of dashed flank line
                       (x,y1) = Board.coords(0,col)
                       x -= Board.dash_width / 2 - 2
                       y1 += Board.hexXY.y/4
                       # Find ending point
                       y2 = Board.coords(self.rows,0).y
                       
                       # Draw the dashed line
                       y = y1
                       while y < y2:
                           ye = min(y2, y+Board.dash_length[0])
                           canvas.line([(x,y),(x,ye)], 
                               fill=Board.dash_color, width=Board.dash_width) 
                           y += sum(Board.dash_length)
                           
                continue            # on to next layer
                
            hexagons = self.info['labels' if key is 'text' else 'hexagons']
            for hexagon in hexagons:
                col,row = hexagon['col'],hexagon['row']

                content = hexagon.get(key,None)
                if not content: continue
                
                # make everything a list for simplicity
                if type(content) is not ListType:
                    contents = [content]
                else:
                    contents = content

                xy = Board.coords2(row,col)
                
                if key is 'text':
                    for (i,content) in enumerate(contents):
                        wh = XY(*canvas.textsize(content, font=font))
                        pos = xy + Board.hexXY.doti( (1/2., 3/4.) ) \
                            - wh.doti( (1/2., 1.1*(len(contents)/2. - i)) )
                        canvas.text(pos, content, fill="black", font=font)
                        
                    continue            # on to next hex
                
                # sort contents by name to get consistent order for tags
                contents.sort(key = lambda c: c['name'])
                for i,content in enumerate(contents):
                    name = content['name']
                    image = icons.getImage(name, content.get('orientation',1))
                    if not image:
                        logging.warn("(col=%d, row=%d): No image for %s"%(
                            col,row,name))
                        continue
                    
                    # hack to deal with multiple medal tags in a single hex
                    # but won't work for things like 'battle stars' (named "tag1")
                    # which is already centered in lower right
                    if i > 0:
                        offset = Board.tagOffset.dot(
                            [(1,1),(-1,-1),(-1,1),(1,-1)][i%4]) - Board.tagOffset
                        logging.debug("%s:%d:%s at (col=%d, row=%d) - offset by %s"%(
                            key,i,name, col, row, `offset`))
                        xy = xy + offset
                        if key is not 'tags':
                            logging.warn(
"Didn't expect multiple instances of [%s] at (col=%d, row=%d)"%(key, col, row))
                        elif i > 3:
                            logging.warn(
"Can't deal with more than four tags at (col=%d, row=%d)"%(col,row))
                        
                            
                    board.paste(image,tuple(xy),image)
                    
                    if i > 0: 
                        # center of medal tag is top-right, about XY(133,66),
                        #, i.e about +39, -42 from center of hex XY(188,217)
                        # for subsequent ones, move them around the hex 
                        # to bottom-left, bottom-right, top-left?
                        logging.debug('(col=%d,row=%d), name=%s, item #=%d'%(
                            col,row,name,i))
                    
                    # handle nbr_units and badge attributes within unit layer
                    if content.has_key('badge'):    # unit badges
                        # badges are not padded to hex size, and too small
                        # so resize and center on unit top left corner
                        image = icons.getImage(content['badge'])
                        image = image.resize(Board.badgeSize,Image.ANTIALIAS)
                        if image:
                            pos = xy + Board.unitTL - Board.badgeSize / 2
                            board.paste(image, tuple(pos), image)
                            
                    if content.has_key('nbr_units'):
                        image = icons.getImage('nbr_units', int(content['nbr_units']))
                        if image:
                            board.paste(image, tuple(xy), image)
              
        board = ImageOps.expand(
            board, border=Board.border_width, fill=Board.border_color)
        board.info['dpi'] = (dpi,dpi)
        
        return board