def test_inverse_projection(self): self.assertEqual(self.p.backproject(Point(0, 0)), SkyCoordDeg(0, 45)) self.assertEqual( self.p.backproject(self.p.project(SkyCoordDeg(15, 45))), SkyCoordDeg(15, 45)) self.assertEqual( self.p.backproject(self.p.project(SkyCoordDeg(-15, 45))), SkyCoordDeg(-15, 45), ) self.assertEqual( self.p.backproject(self.p.project(SkyCoordDeg(29, 32))), SkyCoordDeg(29, 32)) self.p.celestial = True self.assertEqual(self.p.backproject(Point(0, 0)), SkyCoordDeg(0, 45)) self.assertEqual( self.p.backproject(self.p.project(SkyCoordDeg(15, 45))), SkyCoordDeg(15, 45)) self.assertEqual( self.p.backproject(self.p.project(SkyCoordDeg(-15, 45))), SkyCoordDeg(-15, 45), ) self.assertEqual( self.p.backproject(self.p.project(SkyCoordDeg(29, 32))), SkyCoordDeg(29, 32))
def test_to_map_coordinates(self): dx = float(297 - 40) / (210 - 40) self.assertEqual(self.m.map_point(Point(0, 0)), Point(148.5, 105.0)) self.assertEqual(self.m.map_point(Point(dx, 1)), Point(277, 190)) self.assertEqual(self.m.map_point(Point(-dx, 1)), Point(20, 190)) self.assertEqual(self.m.map_point(Point(-dx, -1)), Point(20, 20)) self.assertEqual(self.m.map_point(Point(dx, -1)), Point(277, 20))
def set_origin(self, origin): self.origin = origin self.minx = self.p1.x - self.origin.x self.maxx = self.p2.x - self.origin.x self.miny = self.p1.y - self.origin.y self.maxy = self.p2.y - self.origin.y self.bounding_box = Rectangle(Point(self.minx, self.miny), Point(self.maxx, self.maxy))
def _longitude_latitude_boundaries(self): """Determines the min/max longitude and latitude displayed in the map.""" # The origin corresponds to center longitude and latitude if self.config.clip_at_border: # Clip points are map corners in paper coordinates: determine lat/long from those # TODO: This only works correctly for specific maps! pts = [ # Backproject all four map corner points self._map_to_sky(self.llcorner), self._map_to_sky(self.lrcorner), self._map_to_sky(self.urcorner), self._map_to_sky(self.ulcorner), # Backproject the top and bottom border points at the x-coordinate of the origin self._map_to_sky(Point(0, self.llcorner.y)), self._map_to_sky(Point(0, self.ulcorner.y)), ] # Determine minimum and maximum longitude and latitude longitudes = [s.ra.degree for s in pts] latitudes = [s.dec.degree for s in pts] else: # Clip points are sky coordinates longitudes = [self.config.min_longitude, self.config.max_longitude] latitudes = [self.config.min_latitude, self.config.max_latitude] # Make sure the center longitudes and latitudes are included longitudes.append(self.center_longitude) latitudes.append(self.center_latitude) # Make sure the longitudes do not include a discontinuity continuous_longitudes = [] for l in longitudes: if l - self.center_longitude > 180: continuous_longitudes.append(l - 360) elif l - self.center_longitude < -180: continuous_longitudes.append(l + 360) else: continuous_longitudes.append(l) self.min_longitude = min(continuous_longitudes) self.max_longitude = max(continuous_longitudes) self.min_latitude = min(latitudes) self.max_latitude = max(latitudes) # For azimuthal projections, make sure all longitudes are included if isinstance(self.projection, AzimuthalEquidistantProjection): self.min_longitude = 0 self.max_longitude = 360 print("Grid range") print(f"Longitude: {self.min_longitude} to {self.max_longitude}") print(f"Latitude: {self.min_latitude} to {self.max_latitude}")
def test_inverse_projection(self): self.assertEqual(self.p(Point(0, 0), inverse=True), SphericalPoint(0, 45)) self.assertEqual(self.p(self.p(SphericalPoint(15, 45)), inverse=True), SphericalPoint(15, 45)) self.assertEqual(self.p(self.p(SphericalPoint(-15, 45)), inverse=True), SphericalPoint(-15, 45)) self.assertEqual(self.p(self.p(SphericalPoint(29, 32)), inverse=True), SphericalPoint(29, 32)) self.p.celestial = True self.assertEqual(self.p(Point(0, 0), inverse=True), SphericalPoint(0, 45)) self.assertEqual(self.p(self.p(SphericalPoint(15, 45)), inverse=True), SphericalPoint(15, 45)) self.assertEqual(self.p(self.p(SphericalPoint(-15, 45)), inverse=True), SphericalPoint(-15, 45)) self.assertEqual(self.p(self.p(SphericalPoint(29, 32)), inverse=True), SphericalPoint(29, 32))
def legend(figure, chart_number): l = DrawingArea(f.llcorner + Point(264, 0), f.urcorner, f.llcorner + Point(264, 0)) figure.add(l) l.draw_label(Label(Point(8, 189), "Epoch", 90, "tiny")) l.draw_label(Label(Point(8, 185), "\\textbf{2000.0}", 90, "normalsize")) l.draw_line(Line(Point(2, 183.5), Point(14, 183.5))) l.draw_line(Line(Point(2, 15), Point(14, 15))) l.draw_label(Label(Point(8, 11), "Chart number", 90, "tiny")) l.draw_label( Label(Point(8, 2), "\\textbf{{{}}}".format(chart_number), 90, "Huge"))
def polar_tick(self): if not self.config.polar_tick: return None latitude = 90 delta = Point(0, 1) if self.config.center_latitude < 0: delta = Point(0, -1) latitude *= -1 p1 = self.projection.project(SkyCoordDeg(0, latitude)) p2 = p1 + self.config.marked_ticksize * delta return Line(p1, p2)
def test_projection(self): c = self.p(self.p.parallel_circle_center) self.assertEqual(self.p.cone_angle, 45) f = math.sin(math.radians(self.p.cone_angle)) print f self.assertEqual(self.p(SphericalPoint(0, 45)), Point(0, 0)) self.assertEqual(self.p(SphericalPoint(0, 50)), Point(0, 0.5)) self.assertEqual(self.p(SphericalPoint(0, 35)), Point(0, -1)) #a = 0.98861593*f*15 a = f*15 print a print c p = c + (Point(0, 0) - c).rotate(a)
def leftlegend(figure, chart_number): p1 = figure.llcorner p2 = figure.llcorner + Point(LEGEND_WIDTH, LEGEND_HEIGHT) l = DrawingArea(p1, p2, p1, box=False) figure.add(l) l.draw_bounding_box(0.4) p1 = figure.llcorner + Point(-EDGE_MARGIN, PAPERSIZE[1] - BOTTOM_MARGIN - 17) p2 = figure.llcorner + Point(EDGE_MARGIN, PAPERSIZE[1] - BOTTOM_MARGIN) l = DrawingArea(p1, p2, box=False) figure.add(l) l.draw_label( Label(Point(EDGE_MARGIN, -1.5), "\\textbf{{{}}}".format(chart_number), 90, "huge"))
def set_origin(self, origin): """ Sets the location of the origin of the coordinate system for the picture. The minimum and maximum x and y values for the picture, as well as the bounding box, are determined as well. Args: origin (skymap.geometry.Point): the location in absolute paper coordinates """ self.origin = origin self.minx = self.p1.x - self.origin.x self.maxx = self.p2.x - self.origin.x self.miny = self.p1.y - self.origin.y self.maxy = self.p2.y - self.origin.y self.bounding_box = Rectangle(Point(self.minx, self.miny), Point(self.maxx, self.maxy))
def map_parallel(self, latitude): c = Circle(SphericalPoint(0, self.projection.origin_latitude), self.projection.origin_latitude - latitude) c = self.map_circle(c) crossings = self.circle_intersect_borders(c) if crossings: parallels = [] for i in range(len(crossings)): a1, c1, b1 = crossings[i - 1] a2, c2, b2 = crossings[i] if a1 > a2: a2 += 360.0 aavg = math.radians(0.5 * (a1 + a2)) pavg = c.center + Point(c.radius * math.cos(aavg), c.radius * math.sin(aavg)) if self.inside_maparea(pavg): arc = Arc(c.center, c.radius, a1, a2) p = self.gridline_factory.parallel(latitude, arc) parallels.append(p) else: p = self.gridline_factory.parallel(latitude, c) parallels = [p] return parallels
def tickdelta(self, angle, border): a = math.radians(angle) if self.fixed_tick_reach: if border == 'right': delta = Point(1, math.tan(a)) elif border == 'left': delta = Point(-1, math.tan(math.pi - a)) elif border == 'top': delta = Point(math.tan(math.pi / 2 - a), 1) elif border == 'bottom': delta = Point(math.tan(a - 3 * math.pi / 2), -1) else: raise ValueError("Invalid border: {}".format(border)) else: delta = Point(math.cos(a), math.sin(a)) return delta
def __init__( self, center_longitude=0, center_latitude=90, standard_parallel1=None, standard_parallel2=None, reference_scale=45, horizontal_stretch=1.0, celestial=False, ): """Azimuthal equidistant map projection. Center of projection is the pole, which gets projected to the point (0, 0). Args: center_longitude: the longitude that points to the right center_latitude: the latitude at the center of the map (+ or - 90 degrees) standard_parallel1: not used standard_parallel2: not used reference_scale: degrees of latitude per unit distance horizontal_stretch: factor with which to expand the horizontal axis celestial: longitude increases clockwise around north pole """ Projection.__init__( self, center_longitude, center_latitude, standard_parallel1, standard_parallel2, reference_scale, horizontal_stretch, celestial, ) self.north = center_latitude > 0 self.origin = Point(0, 0) if self.north: if self.reference_scale >= 90: raise ProjectionError( f"Invalid reference scale {self.reference_scale} for north pole" ) else: self.reference_scale *= -1 if self.reference_scale <= -90: raise ProjectionError( f"Invalid reference scale {self.reference_scale} for south pole" )
def __init__( self, name="none", papersize=PaperSize(), margins=PaperMargin(), normalsize=11, template=None, ): self.logger = logging.getLogger(__name__) logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) self.name = name self.papersize = papersize self.margins = margins self.normalsize = normalsize self.fontsizes = FontSize(normalsize) self.template = template or "tikz_base.j2" # Landmark points self.llcorner = Point(self.margins.l, self.margins.b) self.ulcorner = Point(self.margins.l, self.papersize.height - self.margins.t) self.urcorner = Point( self.papersize.width - self.margins.r, self.papersize.height - self.margins.t, ) self.lrcorner = Point(self.papersize.width - self.margins.r, self.margins.b) self.center = 0.5 * (self.llcorner + self.urcorner) # Usable size self.width = self.papersize.width - self.margins.l - self.margins.r self.height = self.papersize.height - self.margins.b - self.margins.t self.texfile_name = f"{self.name}.tex" self.delayed = [] self.pictures = [] # Header/footer self.header = (f"{{% extends '{self.template}' %}}\n\n" "{% block content %}\n" "{{ super() }}\n") self.footer = "{% endblock %}\n" self.j2_env = jinja2.Environment( loader=jinja2.FileSystemLoader(JINJA_TEMPLATE_FOLDER), trim_blocks=True)
def project(self, skycoord): longitude = self.reduce_longitude(skycoord.ra.degree) latitude = skycoord.dec.degree return Point( self.horizontal_stretch * (longitude - self.center_longitude) / self.reference_scale, latitude / self.reference_scale, )
def test_latitude(self): self.assertEqual(self.p.project(SphericalPoint(0, 50)), Point(1, 0)) self.assertEqual(self.p.project(SphericalPoint(90, 50)), Point(0, 1)) self.assertEqual(self.p.project(SphericalPoint(180, 50)), Point(-1, 0)) self.assertEqual(self.p.project(SphericalPoint(270, 50)), Point(0, -1)) self.p.celestial = True self.assertEqual(self.p.project(SphericalPoint(0, 50)), Point(1, 0)) self.assertEqual(self.p.project(SphericalPoint(90, 50)), Point(0, -1)) self.assertEqual(self.p.project(SphericalPoint(180, 50)), Point(-1, 0)) self.assertEqual(self.p.project(SphericalPoint(270, 50)), Point(0, 1))
def test_latitude(self): self.assertEqual(self.p.project(SkyCoordDeg(0, 50)), Point(1, 0)) self.assertEqual(self.p.project(SkyCoordDeg(90, 50)), Point(0, 1)) self.assertEqual(self.p.project(SkyCoordDeg(180, 50)), Point(-1, 0)) self.assertEqual(self.p.project(SkyCoordDeg(270, 50)), Point(0, -1)) self.p.celestial = True self.assertEqual(self.p.project(SkyCoordDeg(0, 50)), Point(1, 0)) self.assertEqual(self.p.project(SkyCoordDeg(90, 50)), Point(0, -1)) self.assertEqual(self.p.project(SkyCoordDeg(180, 50)), Point(-1, 0)) self.assertEqual(self.p.project(SkyCoordDeg(270, 50)), Point(0, 1))
def __init__(self, tikz, chart_number, left=True): self.chart_number = chart_number self.left = left MapLegend.__init__( self, tikz, tikz.llcorner, tikz.llcorner + Point(LEGEND_WIDTH, LEGEND_HEIGHT), )
def pole_markers(self, frame): for latitude in [-90, 90]: sp = SkyCoordDeg(0, latitude, frame=frame).icrs p = self.projection.project(sp) if self.config.rotate_poles: delta1 = (self.projection.project( SkyCoordDeg(sp.ra.degree + 1, sp.dec.degree)) - p) delta2 = (self.projection.project( SkyCoordDeg(sp.ra.degree, sp.dec.degree + 1)) - p) else: delta1 = Point(1, 0) delta2 = Point(0, 1) delta1 *= self.config.pole_marker_size / delta1.norm delta2 *= self.config.pole_marker_size / delta2.norm if self.clipper.point_inside(p): yield Line(p + delta1, p - delta1) yield Line(p + delta2, p - delta2)
def project(self, skycoord): longitude = self.reduce_longitude(skycoord.ra.degree) latitude = skycoord.dec.degree x = (self.horizontal_stretch * (longitude - self.center_longitude) / self.reference_scale) if self.celestial: x *= -1 y = latitude / self.reference_scale return Point(x, y)
def project(self, spherical_point): if self.celestial: x = -self.lateral_scale * ( self.reduce_longitude(spherical_point.longitude) - self.center_longitude) / self.reference_scale else: x = self.lateral_scale * ( self.reduce_longitude(spherical_point.longitude) - self.center_longitude) / self.reference_scale y = spherical_point.latitude / self.reference_scale return Point(x, y)
def project(self, spherical_point): rho = (self.origin_latitude - spherical_point.latitude) / float( self.reference_scale) if self.reverse_polar_direction: theta = -self.reduce_longitude( spherical_point.longitude) + 90 + self.reference_longitude else: theta = self.reduce_longitude( spherical_point.longitude) + 90 - self.reference_longitude return Point(rho * math.sin(math.radians(theta)), -rho * math.cos(math.radians(theta)))
def project(self, skycoord): longitude = self.reduce_longitude(skycoord.ra.degree) latitude = skycoord.dec.degree rho = (self.center_latitude - latitude) / self.reference_scale theta = math.radians(longitude - self.center_longitude) if self.reverse_polar_direction: theta *= -1 return Point(self.horizontal_stretch * rho * math.cos(theta), rho * math.sin(theta))
def open(self): if self.origin != Point(0, 0): shift = "{([shift={" + self.point_to_coordinates( self.origin) + "}]current page.south west)}" else: shift = "{(current page.south west)}" self.fp.write( "\\begin{{tikzpicture}}[remember picture, overlay, shift={0}, every node/.style={{inner sep=0mm, outer sep=0mm, minimum size=0mm, text height=\\normaltextheight, text depth=\\normaltextdepth}}]\n" .format(shift)) if self.box: self.draw_bounding_box()
def build_label_database(): db = SkyMapDatabase() db.drop_table("skymap_labels") # Create table db.commit_query("""CREATE TABLE skymap_labels ( label_id INT PRIMARY KEY, label_text TEXT, fontsize TEXT, width REAL, height REAL)""") stars = [ Star(r) for r in db.query( """SELECT * FROM skymap_stars WHERE proper_name is not null""") ] p = Point(0, 0) i = 0 nstars = len(stars) for n, s in enumerate(stars): sys.stdout.write("\r{}%".format(int(round(100 * n / float(nstars))))) sys.stdout.flush() if not s.proper_name.strip() and not s.identifier_string.strip(): continue if s.proper_name: i += 1 if db.query_one( """SELECT * FROM skymap_labels WHERE label_text="{}" AND fontsize="{}" """ .format(s.proper_name, "tiny")) is None: l = Label(p, s.proper_name, fontsize="tiny", render_size=True) size = l.size db.commit_query( """INSERT INTO skymap_labels VALUES ({}, "{}", "{}", {}, {})""" .format(i, s.proper_name, "tiny", size[0], size[1])) if s.identifier_string: i += 1 if db.query_one( """SELECT * FROM skymap_labels WHERE label_text="{}" AND fontsize="{}" """ .format(s.identifier_string, "tiny")) is None: l = Label(p, s.identifier_string.strip(), fontsize="tiny", render_size=True) size = l.size db.commit_query( """INSERT INTO skymap_labels VALUES ({}, "{}", "{}", {}, {})""" .format(i, s.identifier_string, "tiny", size[0], size[1])) db.close()
def polar_label(self): if not self.config.polar_tick: return None latitude = 90 delta = Point(0, 1) pos = "above" text = "+90\\textdegree" if self.config.center_latitude < 0: delta = Point(0, -1) latitude *= -1 pos = "below" text = "--90\\textdegree" p1 = self.projection.project(SkyCoordDeg(0, latitude)) p2 = p1 + self.config.label_distance * delta return Label( p2, text=text, fontsize=self.config.parallel_config.fontsize, angle=0, position=pos, fill="white", )
def __init__(self, name, papersize=PAPERSIZES["A4"], left_margin=20, right_margin=20, top_margin=20, bottom_margin=20, landscape=False, fontsize=11): self.name = name self.papersize = papersize self.landscape = landscape if landscape: self.papersize = (self.papersize[1], self.papersize[0]) self.left_margin = left_margin self.right_margin = right_margin self.top_margin = top_margin self.bottom_margin = bottom_margin self.llcorner = Point(self.left_margin, self.bottom_margin) self.ulcorner = Point(self.left_margin, self.papersize[1] - self.top_margin) self.urcorner = Point(self.papersize[0] - self.right_margin, self.papersize[1] - self.top_margin) self.lrcorner = Point(self.papersize[0] - self.right_margin, self.bottom_margin) self.center = 0.5 * (self.llcorner + self.urcorner) self.fontsize = fontsize self.fontsizes = FONTSIZES[fontsize] if not os.path.exists(TEX_OUTPUT_FOLDER): os.makedirs(TEX_OUTPUT_FOLDER) self.fp = open(os.path.join(TEX_OUTPUT_FOLDER, "{0}.tex".format(name)), "w") self.delayed = [] self.current_drawing_area = None self.closed = False self.start_figure()
def test_picture(self): t = Tikz("tizk_test1") p = TikzPicture(t, Point(20, 20), Point(190, 277)) p.draw_circle(Circle(Point(85, 128.5), 30)) p.draw_rectangle(Rectangle(Point(55, 98.5), Point(115, 158.5))) p.draw_circle(Circle(Point(85, 128.5), 95)) t.render()
def test_arc(self): t = Tikz("tikz_test4") with TikzPicture(t, Point(20, 20), Point(190, 277)) as p: p.draw_arc(Arc(Point(0, 0), 50, 0, 45)) p.draw_arc(Arc(Point(0, 0), 46, -45, 45)) p.draw_arc(Arc(Point(0, 0), 42, 270, 45)) p.draw_arc(Arc(Point(0, 0), 38, 45, 270)) t.render()
def project(self, spherical_point): rho = (self.G - math.radians(spherical_point.latitude)) / self.reference_scale theta = math.radians( self.n * (self.reduce_longitude(spherical_point.longitude) - self.reference_longitude)) if self.celestial: x = -rho * math.sin(theta) else: x = rho * math.sin(theta) y = self.rho_0 - rho * math.cos(theta) return Point(x, y)