Exemple #1
0
    def draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group, size: XY,
             offset: XY) -> None:
        """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 self.poster.years.iter():
            g_year = dr.g(id=f"year{year}")
            g.add(g_year)
            self._draw_year(dr, g_year, sub_size,
                            offset + margin + cell_size * XY(x, y), year)
            x += 1
            if x >= count_x:
                x = 0
                y += 1
Exemple #2
0
def project(
    bbox: s2sphere.LatLngRect, size: XY, offset: XY, latlnglines: typing.List[typing.List[s2sphere.LatLng]]
) -> typing.List[typing.List[typing.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
    def draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group, size: XY,
             offset: XY) -> None:
        """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 self.poster.years.iter():
            g_year = dr.g(id=f"year{year}")
            g.add(g_year)
            self._draw(dr, g_year, sub_size,
                       offset + margin + cell_size * XY(x, y), year)
            x += 1
            if x >= count_x:
                x = 0
                y += 1
Exemple #4
0
 def draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group, size: XY,
          offset: XY) -> None:
     """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
     year_groups: typing.Dict[int, svgwrite.container.Group] = {}
     for (index, tr) in enumerate(self.poster.tracks):
         year = tr.start_time().year
         if year not in year_groups:
             g_year = dr.g(id=f"year{year}")
             g.add(g_year)
             year_groups[year] = g_year
         else:
             g_year = year_groups[year]
         p = XY(index % count_x, index // count_x) * XY(
             cell_size + spacing_x, cell_size + spacing_y)
         self._draw_track(
             dr,
             g_year,
             tr,
             0.9 * XY(cell_size, cell_size),
             offset + 0.05 * XY(cell_size, cell_size) + p,
         )
 def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY) -> None:
     """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,
         )
    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
Exemple #7
0
 def draw(self, drawer: "TracksDrawer", output: str) -> None:
     """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()
Exemple #8
0
    def _draw_year(self, dr: svgwrite.Drawing, g: svgwrite.container.Group,
                   size: XY, offset: XY, year: int) -> None:
        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, g, 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;"

        g.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
                g.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)}"
                )
                g.add(path)
                tpath = svgwrite.text.TextPath(
                    path,
                    self.poster.month_name(date.month),
                    startOffset=(0.5 * r3 * (a3 - a1)))
                text = dr.text(
                    "",
                    fill=self.poster.colors["text"],
                    text_anchor="middle",
                    style=month_style,
                )
                text.add(tpath)
                g.add(text)
            if text_date in self.poster.tracks_by_date:
                self._draw_circle_segment(
                    dr,
                    g,
                    self.poster.tracks_by_date[text_date],
                    a1,
                    a2,
                    radius_range,
                    center,
                )

            day += 1
            date += datetime.timedelta(1)
    def _draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group,
              size: XY, offset: XY, year: int) -> None:
        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;"

        g.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,
        )

        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
            g.add(
                dr.text(
                    self.poster.month_name(month),
                    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)
                    g.add(dr.rect(pos, dim, fill=color))
                    g.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:
                    g.add(dr.rect(pos, dim, fill="#444444"))

                g.add(
                    dr.text(
                        localized_day_of_week_name(date.weekday(), short=True),
                        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)
Exemple #10
0
def latlng2xy(latlng: s2sphere.LatLng) -> XY:
    return XY(lng2x(latlng.lng().degrees), lat2y(latlng.lat().degrees))
    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)