def __init__(self, spatialreference, extent, nnodes=51, cliplat=0.0, lat_tick_interval=5, mapscale=1000000,
                lon_minor_ticks=[12.5], lon_major_ticks=[25, 50, 75],
                symmetrical=True, height = 4.0, fontsize=12, padding=1.0, outputname='scalebar.svg',
                latlon=False):

        nnodes = self._checknnodes(nnodes)

        self.fontsize = fontsize
        self.height = height
        self.nnodes = nnodes
        self.outputname = outputname
        self.padding = padding
        self._dwg = None
        self.spatialreference = spatialreference.__str__()
        self.mapscale = 1/float(mapscale)

        (xmin, ymin, xmax, ymax) = extent
        projstr = spatialreference.ExportToProj4()
        semimajor = spatialreference.GetSemiMajor()
        semiminor = spatialreference.GetSemiMinor()

        self.name = emd.get_projection_name(spatialreference)
        parallels = emd.get_standard_parallels(spatialreference)

        #Create proj4 projection
        proj = pyproj.Proj(projstr)
        #Setup start and stop nodes

        self.coords = np.empty((nnodes, 2))
        self.coords[:,0] = xmin
        self.coords[:,1] = np.linspace(ymin, ymax, self.nnodes)


        if latlon:
            #This is intentionally inverting lat/lon to match how GDAL returns image extents
            lat = self.coords[:,1]
            lon = np.empty(len(lat))
            lon[:] = xmin
        else:
            #Convert to pixel grid to latlon grid
            lon, lat =  proj(self.coords[:,0], self.coords[:,1], inverse=True)


        self.minlat = np.min(lat)
        self.minlon = np.min(lon)
        self.maxlat = np.max(lat)
        self.maxlon = np.max(lon)

        self.latlon_bounds = ((self.minlat, self.minlon),
                              (self.maxlat, self.maxlon))
        #Parallels
        if parallels[0] >= lat[0] and parallels[0] <= lat[1]:
            p = parallels[0]
        else:
            p = parallels[1]

        if 'Transverse_Mercator' in self.name:

            clat = emd.get_latitude_of_origin(spatialreference)
            clon = emd.get_central_meridian(spatialreference)

            if clat > 0:
                self.coords[:,1] = lat = np.linspace(np.min(lat), clat, self.nnodes)
            else:
                self.coords[:,1] = lat = np.linspace(np.max(lat), clat, self.nnodes)

            distance = np.empty(len(lat))
            k_naught = emd.get_scale_factor(spatialreference)
            for i, l in enumerate(lat):
                B = math.cos(math.radians(clon)) * math.sin(math.radians(clat) - math.radians(l))
                distance[i] = k_naught / math.sqrt(1.0 - B ** 2.0)
            distance = distance[::-1]
            self.mask = self.coords[:,1] >= cliplat

        elif 'Mercator' in self.name:
            self.mask = lat >= cliplat
            distance = 1.0 / np.cos(np.radians(lat[self.mask]))
            distance = distance[::-1]

        #elif 'Sinusoidal' in self.name:

        elif (('Equirectangular' in self.name) or ('Equidistant_Cylindrical' in self.name) \
              or ('Plate_Carree' in self.name) or ('Simple_Cylindrical' in self.name)):

            p1 = parallels[0]
            clon = emd.get_central_meridian(spatialreference)

            if p1 > 0:
                self.coords[:,1] = lat = np.linspace(np.min(lat), p1, self.nnodes)
            else:
                self.coords[:,1] = lat = np.linspace(np.max(lat), p1, self.nnodes)

            distance = np.empty(len(lat))
            for i, l in enumerate(lat):
                distance[i] = math.cos(math.radians(p1))/math.cos(math.radians(l))
            distance = distance[::-1]
            self.mask = self.coords[:,1] >= cliplat

        elif 'Lambert_Conformal' in self.name:
            self.mask = lat >= cliplat
            parallels.sort()

            p1 = math.radians(parallels[0])
            p2 = math.radians(parallels[1])

            cp1 = math.cos(p1)
            cp2 = math.cos(p2)
            n = np.log(cp1 / cp2) / np.log( math.tan((math.pi / 4) + (math.radians(parallels[1] / 2))) / math.tan((math.pi / 4) + (math.radians(parallels[0] / 2)) ))
            num = cp1 * np.tan(math.pi / 4 + math.radians(parallels[0] / 2)) ** n
            den = np.cos(np.radians(lat)) * np.tan(math.pi / 4 + np.radians(lat / 2.0)) ** n
            distance = num / den
            distance = distance[::-1]

        elif 'Stereographic' in self.name:
            clat = emd.get_latitude_of_origin(spatialreference)
            clon = emd.get_central_meridian(spatialreference)

            if clat > 0:
                self.coords[:,1] = lat = np.linspace(np.min(lat), clat, self.nnodes)
            else:
                self.coords[:,1] = lat = np.linspace(np.max(lat), clat, self.nnodes)
            distance = np.empty(len(lat))
            k_naught = emd.get_scale_factor(spatialreference)
            for i, l in enumerate(lat):
                distance[i] = (2 * k_naught) / (1.0 + math.sin(math.radians(clat)) * math.sin(math.radians(l)) +\
                            math.cos(math.radians(clat))*math.cos(math.radians(l))*math.cos(math.radians(180 - clon)))
            distance = distance[::-1]
            self.mask = self.coords[:,1] >= cliplat


        lon_major_ticks = list(map(lambda x: x * 1000, lon_major_ticks)) #km to m
        lon_minor_ticks = list(map(lambda x: x * 1000, lon_minor_ticks))

        ticks = lon_major_ticks + lon_minor_ticks
        ticks.sort()
        ticks = ticks[::-1]

        south = False
        if lat[0] > lat[-1]:
            south = True

        #Vertical distance line logic
        for l in ticks:
            line_coords = ((l * 100) *  self.mapscale) * distance
            if self._dwg == None:
                length = np.max(line_coords)
                size = (length * 2, self.height)
                self.createdrawing(size)
                if symmetrical == True:
                    size = list(size)
                    size[0] /= 2
                    size = tuple(size)
                self.createvertical(size)

                #Check hemisphere
                if south == True:
                    ytext = self.y[0]
                else:
                    ytext = self.y[-1]

                #Label the vertical
                center = (size[0]  + self.padding)* 0.995 # Offset left for font size
                dist = self._dwg.text('0', (center * cm, (ytext + self.padding * 1.3) * cm))
                self._dwg.add(dist)

            nodes = list(zip(line_coords[::-1] + size[0], self.y[::-1]))
            for i, start in enumerate(nodes[:-1]):
                coords = self._pad_and_convert(start, nodes[i + 1])
                self.drawline(coords, group=self.vertical)
                if i == 0 and l in lon_major_ticks:
                    dist = self._dwg.text('{}km'.format(l / 1000), (coords[0][0], (ytext  + self.padding * 1.3) * cm))
                    self._dwg.add(dist)
            if symmetrical:
                nline_coords = (line_coords * -1)
                nodes = list(zip(nline_coords[::-1] + size[0], self.y[::-1]))
                for i, start in enumerate(nodes[:-1]):
                    coords = self._pad_and_convert(start, nodes[i + 1])
                    self.drawline(coords, group=self.vertical)
                    if i == 0 and l in lon_major_ticks:
                        dist = self._dwg.text('{}km'.format(l / 1000), (coords[0][0], (ytext +self.padding * 1.3) * cm ))
                        self._dwg.add(dist)


        #Compute the latrange and labels
        latrange = lat[self.mask]
        if latrange[0] > latrange[-1]: #Ghetto monotonic check for southern hemisphere...
            ticks = np.arange(util.integerround(latrange[-2]), latrange[0] + lat_tick_interval, lat_tick_interval)
        else:
            ticks = np.arange(util.integerround(latrange[0] + lat_tick_interval) ,latrange[-2], lat_tick_interval)
        ticks = labels = np.hstack((round(latrange[0], 1), ticks, round(latrange[-1], 1)))
        horizontal_ticks = self._dwg.add(self._dwg.g(id='horizontal_tick', stroke='black'))
        #Compute the y coordinate values in scalebar space
        horizontals = self.height / (np.max(ticks) - np.min(ticks)) *(ticks - np.min(ticks))
        horizontals = np.abs(horizontals - self.height)
        for i, h in enumerate(horizontals):
            x = [(size[0] + self.padding) * cm, (size[0] * 2 + self.padding) * cm]
            y = [(h + self.padding)  * cm] * 2
            xy = list(zip(x, y))
            line = self._dwg.line(start=xy[0], end=xy[1])
            horizontal_ticks.add(line)
            if i % 2 == 0:
                ytext = y[1]
                lat = self._dwg.text(u'{}\u00b0'.format(labels[i]), ((size[0] * 2 + 1.0) * cm, ytext))
                self.text.add(lat)

            if symmetrical:
                x = [self.padding * cm, (size[0] + self.padding) * cm]
                xy = list(zip(x, y))
                line = self._dwg.line(start=xy[0], end=xy[1])
                horizontal_ticks.add(line)
                if i % 2 == 0:
                    lat = self._dwg.text(u'{}\u00b0'.format(labels[i]), (0.0 * cm, y[1]))
                    self.text.add(lat)

        self._dwg.save()
 def standardparallels(self):
     if not getattr(self, '_standardparallels', None):
         self._standardparallels = em.get_standard_parallels(self.spatialreference)
     return self._standardparallels
Example #3
0
    def __init__(self, spatialreference, extent, nnodes=51, cliplat=0.0, lat_tick_interval=5, mapscale=1000000,
                lon_minor_ticks=[12.5], lon_major_ticks=[25, 50, 75],
                symmetrical=True, height = 4.0, fontsize=12, padding=1.0, outputname='scalebar.svg',
                latlon=False):

        nnodes = self._checknnodes(nnodes)

        self.fontsize = fontsize
        self.height = height
        self.nnodes = nnodes
        self.outputname = outputname
        self.padding = padding
        self._dwg = None
        self.spatialreference = spatialreference.__str__()
        self.mapscale = 1/float(mapscale)

        (xmin, ymin, xmax, ymax) = extent
        projstr = spatialreference.ExportToProj4()
        semimajor = spatialreference.GetSemiMajor()
        semiminor = spatialreference.GetSemiMinor()

        self.name = emd.get_projection_name(spatialreference)
        parallels = emd.get_standard_parallels(spatialreference)

        #Create proj4 projection
        proj = pyproj.Proj(projstr)
        #Setup start and stop nodes

        self.coords = np.empty((nnodes, 2))
        self.coords[:,0] = xmin
        self.coords[:,1] = np.linspace(ymin, ymax, self.nnodes)


        if latlon:
            #This is intentionally inverting lat/lon to match how GDAL returns image extents
            lat = self.coords[:,1]
            lon = np.empty(len(lat))
            lon[:] = xmin
        else:
            #Convert to pixel grid to latlon grid
            lon, lat =  proj(self.coords[:,0], self.coords[:,1], inverse=True)
        

        self.minlat = np.min(lat)
        self.minlon = np.min(lon)
        self.maxlat = np.max(lat)
        self.maxlon = np.max(lon)

        self.latlon_bounds = ((self.minlat, self.minlon),
                              (self.maxlat, self.maxlon))
        #Parallels
        if parallels[0] >= lat[0] and parallels[0] <= lat[1]:
            p = parallels[0]
        else:
            p = parallels[1]

        if 'Transverse_Mercator' in self.name:

            clat = emd.get_latitude_of_origin(spatialreference)
            clon = emd.get_central_meridian(spatialreference)

            if clat > 0:
                self.coords[:,1] = lat = np.linspace(np.min(lat), clat, self.nnodes)
            else:
                self.coords[:,1] = lat = np.linspace(np.max(lat), clat, self.nnodes)

            distance = np.empty(len(lat))
            k_naught = emd.get_scale_factor(spatialreference)
            for i, l in enumerate(lat):
                B = math.cos(math.radians(clon)) * math.sin(math.radians(clat) - math.radians(l))
                distance[i] = k_naught / math.sqrt(1.0 - B ** 2.0)
            distance = distance[::-1]
            self.mask = self.coords[:,1] >= cliplat
           
        elif 'Mercator' in self.name:
            self.mask = lat >= cliplat
            distance = 1.0 / np.cos(np.radians(lat[self.mask]))
            distance = distance[::-1]

        #elif 'Sinusoidal' in self.name:

        elif (('Equirectangular' in self.name) or ('Equidistant_Cylindrical' in self.name) \
              or ('Plate_Carree' in self.name) or ('Simple_Cylindrical' in self.name)):

            p1 = parallels[0]
            clon = emd.get_central_meridian(spatialreference)

            if p1 > 0:
                self.coords[:,1] = lat = np.linspace(np.min(lat), p1, self.nnodes)
            else:
                self.coords[:,1] = lat = np.linspace(np.max(lat), p1, self.nnodes)

            distance = np.empty(len(lat))
            for i, l in enumerate(lat):
                distance[i] = math.cos(math.radians(p1))/math.cos(math.radians(l))
            distance = distance[::-1]
            self.mask = self.coords[:,1] >= cliplat

        elif 'Lambert_Conformal' in self.name:
            self.mask = lat >= cliplat
            parallels.sort()

            p1 = math.radians(parallels[0])
            p2 = math.radians(parallels[1])

            cp1 = math.cos(p1)
            cp2 = math.cos(p2)
            n = np.log(cp1 / cp2) / np.log( math.tan((math.pi / 4) + (math.radians(parallels[1] / 2))) / math.tan((math.pi / 4) + (math.radians(parallels[0] / 2)) ))
            num = cp1 * np.tan(math.pi / 4 + math.radians(parallels[0] / 2)) ** n
            den = np.cos(np.radians(lat)) * np.tan(math.pi / 4 + np.radians(lat / 2.0)) ** n
            distance = num / den
            distance = distance[::-1]

        elif 'Stereographic' in self.name:
            clat = emd.get_latitude_of_origin(spatialreference)
            clon = emd.get_central_meridian(spatialreference)

            if clat > 0:
                self.coords[:,1] = lat = np.linspace(np.min(lat), clat, self.nnodes)
            else:
                self.coords[:,1] = lat = np.linspace(np.max(lat), clat, self.nnodes)
            distance = np.empty(len(lat))
            k_naught = emd.get_scale_factor(spatialreference)
            for i, l in enumerate(lat):
                distance[i] = (2 * k_naught) / (1.0 + math.sin(math.radians(clat)) * math.sin(math.radians(l)) +\
                            math.cos(math.radians(clat))*math.cos(math.radians(l))*math.cos(math.radians(180 - clon)))
            distance = distance[::-1]
            self.mask = self.coords[:,1] >= cliplat

            
        lon_major_ticks = map(lambda x: x * 1000, lon_major_ticks) #km to m
        lon_minor_ticks = map(lambda x: x * 1000, lon_minor_ticks)

        ticks = lon_major_ticks + lon_minor_ticks
        ticks.sort()
        ticks = ticks[::-1]

        south = False
        if lat[0] > lat[-1]:
            south = True
    
        #Vertical distance line logic
        for l in ticks:
            line_coords = ((l * 100) *  self.mapscale) * distance
            if self._dwg == None:
                length = np.max(line_coords)
                size = (length * 2, self.height)
                self.createdrawing(size)
                if symmetrical == True:
                    size = list(size)
                    size[0] /= 2
                    size = tuple(size)
                self.createvertical(size)
               
                #Check hemisphere
                if south == True:
                    ytext = self.y[0]
                else:
                    ytext = self.y[-1]
                #Label the vertical 
                center = (size[0]  + self.padding)* 0.995 # Offset left for font size
                dist = self._dwg.text('0', (center * cm, (ytext + self.padding * 1.3) * cm)) 
                self._dwg.add(dist)
               
            nodes = zip(line_coords[::-1] + size[0], self.y[::-1])
            for i, start in enumerate(nodes[:-1]):
                coords = self._pad_and_convert(start, nodes[i + 1])
                self.drawline(coords, group=self.vertical)
                if i == 0 and l in lon_major_ticks:
                    dist = self._dwg.text('{}km'.format(l / 1000), (coords[0][0], (ytext  + self.padding * 1.3) * cm))
                    self._dwg.add(dist)
            if symmetrical:
                nline_coords = (line_coords * -1)
                nodes = zip(nline_coords[::-1] + size[0], self.y[::-1])
                for i, start in enumerate(nodes[:-1]):
                    coords = self._pad_and_convert(start, nodes[i + 1])
                    self.drawline(coords, group=self.vertical)
                    if i == 0 and l in lon_major_ticks:
                        dist = self._dwg.text('{}km'.format(l / 1000), (coords[0][0], (ytext +self.padding * 1.3) * cm ))
                        self._dwg.add(dist)

        
        #Compute the latrange and labels
        latrange = lat[self.mask]
        if latrange[0] > latrange[-1]: #Ghetto monotonic check for southern hemisphere...
            ticks = np.arange(util.integerround(latrange[-2]), latrange[0] + lat_tick_interval, lat_tick_interval)
        else:
            ticks = np.arange(util.integerround(latrange[0] + lat_tick_interval) ,latrange[-2], lat_tick_interval)
        ticks = labels = np.hstack((round(latrange[0], 1), ticks, round(latrange[-1], 1)))
        horizontal_ticks = self._dwg.add(self._dwg.g(id='horizontal_tick', stroke='black'))
        #Compute the y coordinate values in scalebar space
        horizontals = self.height / (np.max(ticks) - np.min(ticks)) *(ticks - np.min(ticks))
        horizontals = np.abs(horizontals - self.height)
        for i, h in enumerate(horizontals):
            x = [(size[0] + self.padding) * cm, (size[0] * 2 + self.padding) * cm]
            y = [(h + self.padding)  * cm] * 2
            xy = zip(x, y)
            line = self._dwg.line(start=xy[0], end=xy[1])
            horizontal_ticks.add(line)
            if i % 2 == 0:
                ytext = y[1]
                lat = self._dwg.text(u'{}\u00b0'.format(labels[i]), ((size[0] * 2 + 1.0) * cm, ytext))
                self.text.add(lat)
            
            if symmetrical:
                x = [self.padding * cm, (size[0] + self.padding) * cm]
                xy = zip(x, y)
                line = self._dwg.line(start=xy[0], end=xy[1])
                horizontal_ticks.add(line)
                if i % 2 == 0:
                    lat = self._dwg.text(u'{}\u00b0'.format(labels[i]), (0.0 * cm, y[1]))
                    self.text.add(lat)

        self._dwg.save()
Example #4
0
 def standardparallels(self):
     if not getattr(self, '_standardparallels', None):
         self._standardparallels = em.get_standard_parallels(
             self.spatialreference)
     return self._standardparallels