Пример #1
0
    def drawGraticuleMask(self, theTopOffset):
        """A helper function to mask out graticule labels on the right side
           by over painting a white rectangle with white border on them.

        Args:
            theTopOffset - vertical offset at which the map should be drawn
        Returns:
            None
        Raises:
            None
        """
        LOGGER.debug('InaSAFE Map drawGraticuleMask called')
        myLeftOffset = self.pageMargin + self.mapWidth
        myRect = QgsComposerShape(myLeftOffset + 0.5, theTopOffset,
                                  self.pageWidth - myLeftOffset,
                                  self.mapHeight + 1, self.composition)

        myRect.setShapeType(QgsComposerShape.Rectangle)
        myRect.setLineWidth(0.1)
        myRect.setFrame(False)
        myRect.setOutlineColor(QtGui.QColor(255, 255, 255))
        myRect.setFillColor(QtGui.QColor(255, 255, 255))
        myRect.setOpacity(100)
        # These two lines seem superfluous but are needed
        myBrush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        myRect.setBrush(myBrush)
        self.composition.addItem(myRect)
Пример #2
0
    def draw_graticule_mask(self, top_offset):
        """A helper function to mask out graticule labels.

         It will hide labels on the right side by over painting a white
         rectangle with white border on them. **kludge**

        :param top_offset: Vertical offset at which the logo should be drawn.
        :type top_offset: int
        """
        LOGGER.debug('InaSAFE Map drawGraticuleMask called')
        left_offset = self.page_margin + self.mapWidth
        rect = QgsComposerShape(left_offset + 0.5, top_offset,
                                self.page_width - left_offset,
                                self.map_height + 1, self.composition)

        rect.setShapeType(QgsComposerShape.Rectangle)
        pen = QtGui.QPen()
        pen.setColor(QtGui.QColor(0, 0, 0))
        pen.setWidthF(0.1)
        rect.setPen(pen)
        rect.setBackgroundColor(QtGui.QColor(255, 255, 255))
        rect.setTransparency(100)
        #rect.setLineWidth(0.1)
        #rect.setFrameEnabled(False)
        #rect.setOutlineColor(QtGui.QColor(255, 255, 255))
        #rect.setFillColor(QtGui.QColor(255, 255, 255))
        #rect.setOpacity(100)
        # These two lines seem superfluous but are needed
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        rect.setBrush(brush)
        self.composition.addItem(rect)
Пример #3
0
    def __init__(self, methodName):
        """Run once on class initialisation."""
        unittest.TestCase.__init__(self, methodName)

        # create composition
        self.mMapRenderer = QgsMapRenderer()
        self.mComposition = QgsComposition(self.mMapRenderer)
        self.mComposition.setPaperSize(297, 210)

        self.mComposerRect1 = QgsComposerShape(20, 20, 150, 100, self.mComposition)
        self.mComposerRect1.setShapeType(QgsComposerShape.Rectangle)
        self.mComposerRect1.setBackgroundColor(QColor.fromRgb(255, 150, 0))
        self.mComposition.addComposerShape(self.mComposerRect1)

        self.mComposerRect2 = QgsComposerShape(50, 50, 150, 100, self.mComposition)
        self.mComposerRect2.setShapeType(QgsComposerShape.Rectangle)
        self.mComposerRect2.setBackgroundColor(QColor.fromRgb(0, 100, 150))
        self.mComposition.addComposerShape(self.mComposerRect2)
Пример #4
0
    def __init__(self, methodName):
        """Run once on class initialization."""
        unittest.TestCase.__init__(self, methodName)

        # create composition
        self.mComposition = QgsComposition(QgsProject.instance())
        self.mComposition.setPaperSize(297, 210)

        self.mComposerShape = QgsComposerShape(20, 20, 150, 100, self.mComposition)
        self.mComposerShape.setBackgroundColor(QColor.fromRgb(255, 150, 0))
        self.mComposition.addComposerShape(self.mComposerShape)
    def __init__(self, methodName):
        """Run once on class initialisation."""
        unittest.TestCase.__init__(self, methodName)

        self.mapSettings = QgsMapSettings()

        # create composition
        self.mComposition = QgsComposition(self.mapSettings)
        self.mComposition.setPaperSize(297, 210)

        self.mComposerShape = QgsComposerShape(20, 20, 150, 100,
                                               self.mComposition)
        self.mComposerShape.setBackgroundColor(QColor.fromRgb(255, 150, 0))
        self.mComposition.addComposerShape(self.mComposerShape)
Пример #6
0
    def drawScaleBar(self, theComposerMap, theTopOffset):
        """Add a numeric scale to the bottom left of the map

        We draw the scale bar manually because QGIS does not yet support
        rendering a scalebar for a geographic map in km.

        .. seealso:: :meth:`drawNativeScaleBar`

        Args:
            * theComposerMap - QgsComposerMap instance used as the basis
              scale calculations.
            * theTopOffset - vertical offset at which the map should be drawn
        Returns:
            None
        Raises:
            Any exceptions raised by the InaSAFE library will be propagated.
        """
        LOGGER.debug('InaSAFE Map drawScaleBar called')
        myCanvas = self.iface.mapCanvas()
        myRenderer = myCanvas.mapRenderer()
        #
        # Add a linear map scale
        #
        myDistanceArea = QgsDistanceArea()
        myDistanceArea.setSourceCrs(myRenderer.destinationCrs().srsid())
        myDistanceArea.setProjectionsEnabled(True)
        # Determine how wide our map is in km/m
        # Starting point at BL corner
        myComposerExtent = theComposerMap.extent()
        myStartPoint = QgsPoint(myComposerExtent.xMinimum(),
                                myComposerExtent.yMinimum())
        # Ending point at BR corner
        myEndPoint = QgsPoint(myComposerExtent.xMaximum(),
                              myComposerExtent.yMinimum())
        myGroundDistance = myDistanceArea.measureLine(myStartPoint, myEndPoint)
        # Get the equivalent map distance per page mm
        myMapWidth = self.mapWidth
        # How far is 1mm on map on the ground in meters?
        myMMToGroundDistance = myGroundDistance / myMapWidth
        #print 'MM:', myMMDistance
        # How long we want the scale bar to be in relation to the map
        myScaleBarToMapRatio = 0.5
        # How many divisions the scale bar should have
        myTickCount = 5
        myScaleBarWidthMM = myMapWidth * myScaleBarToMapRatio
        myPrintSegmentWidthMM = myScaleBarWidthMM / myTickCount
        # Segment width in real world (m)
        # We apply some logic here so that segments are displayed in meters
        # if each segment is less that 1000m otherwise km. Also the segment
        # lengths are rounded down to human looking numbers e.g. 1km not 1.1km
        myUnits = ''
        myGroundSegmentWidth = myPrintSegmentWidthMM * myMMToGroundDistance
        if myGroundSegmentWidth < 1000:
            myUnits = 'm'
            myGroundSegmentWidth = round(myGroundSegmentWidth)
            # adjust the segment width now to account for rounding
            myPrintSegmentWidthMM = myGroundSegmentWidth / myMMToGroundDistance
        else:
            myUnits = 'km'
            # Segment with in real world (km)
            myGroundSegmentWidth = round(myGroundSegmentWidth / 1000)
            myPrintSegmentWidthMM = ((myGroundSegmentWidth * 1000) /
                                     myMMToGroundDistance)
        # Now adjust the scalebar width to account for rounding
        myScaleBarWidthMM = myTickCount * myPrintSegmentWidthMM

        #print "SBWMM:", myScaleBarWidthMM
        #print "SWMM:", myPrintSegmentWidthMM
        #print "SWM:", myGroundSegmentWidthM
        #print "SWKM:", myGroundSegmentWidthKM
        # start drawing in line segments
        myScaleBarHeight = 5  # mm
        myLineWidth = 0.3  # mm
        myInsetDistance = 7  # how much to inset the scalebar into the map by
        myScaleBarX = self.pageMargin + myInsetDistance
        myScaleBarY = (theTopOffset + self.mapHeight - myInsetDistance -
                       myScaleBarHeight)  # mm

        # Draw an outer background box - shamelessly hardcoded buffer
        myRect = QgsComposerShape(
            myScaleBarX - 4,  # left edge
            myScaleBarY - 3,  # top edge
            myScaleBarWidthMM + 13,  # right edge
            myScaleBarHeight + 6,  # bottom edge
            self.composition)

        myRect.setShapeType(QgsComposerShape.Rectangle)
        myRect.setLineWidth(myLineWidth)
        myRect.setFrame(False)
        myBrush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        # workaround for missing setTransparentFill missing from python api
        myRect.setBrush(myBrush)
        self.composition.addItem(myRect)
        # Set up the tick label font
        myFontWeight = QtGui.QFont.Normal
        myFontSize = 6
        myItalicsFlag = False
        myFont = QtGui.QFont('verdana', myFontSize, myFontWeight,
                             myItalicsFlag)
        # Draw the bottom line
        myUpshift = 0.3  # shift the bottom line up for better rendering
        myRect = QgsComposerShape(myScaleBarX,
                                  myScaleBarY + myScaleBarHeight - myUpshift,
                                  myScaleBarWidthMM, 0.1, self.composition)

        myRect.setShapeType(QgsComposerShape.Rectangle)
        myRect.setLineWidth(myLineWidth)
        myRect.setFrame(False)
        self.composition.addItem(myRect)

        # Now draw the scalebar ticks
        for myTickCountIterator in range(0, myTickCount + 1):
            myDistanceSuffix = ''
            if myTickCountIterator == myTickCount:
                myDistanceSuffix = ' ' + myUnits
            myRealWorldDistance = (
                '%.0f%s' %
                (myTickCountIterator * myGroundSegmentWidth, myDistanceSuffix))
            #print 'RW:', myRealWorldDistance
            myMMOffset = myScaleBarX + (myTickCountIterator *
                                        myPrintSegmentWidthMM)
            #print 'MM:', myMMOffset
            myTickHeight = myScaleBarHeight / 2
            # Lines are not exposed by the api yet so we
            # bodge drawing lines using rectangles with 1px height or width
            myTickWidth = 0.1  # width or rectangle to be drawn
            myUpTickLine = QgsComposerShape(
                myMMOffset, myScaleBarY + myScaleBarHeight - myTickHeight,
                myTickWidth, myTickHeight, self.composition)

            myUpTickLine.setShapeType(QgsComposerShape.Rectangle)
            myUpTickLine.setLineWidth(myLineWidth)
            myUpTickLine.setFrame(False)
            self.composition.addItem(myUpTickLine)
            #
            # Add a tick label
            #
            myLabel = QgsComposerLabel(self.composition)
            myLabel.setFont(myFont)
            myLabel.setText(myRealWorldDistance)
            myLabel.adjustSizeToText()
            myLabel.setItemPosition(myMMOffset - 3, myScaleBarY - myTickHeight)
            myLabel.setFrame(self.showFramesFlag)
            self.composition.addItem(myLabel)
Пример #7
0
    def draw_scalebar(self, composer_map, top_offset):
        """Add a numeric scale to the bottom left of the map.

        We draw the scale bar manually because QGIS does not yet support
        rendering a scale bar for a geographic map in km.

        .. seealso:: :meth:`drawNativeScaleBar`

        :param composer_map: Composer map on which to draw the scalebar.
        :type composer_map: QgsComposerMap

        :param top_offset: Vertical offset at which the logo should be drawn.
        :type top_offset: int
        """
        LOGGER.debug('InaSAFE Map drawScaleBar called')
        canvas = self.iface.mapCanvas()
        renderer = canvas.mapRenderer()
        #
        # Add a linear map scale
        #
        distance_area = QgsDistanceArea()
        distance_area.setSourceCrs(renderer.destinationCrs().srsid())
        distance_area.setEllipsoidalMode(True)
        # Determine how wide our map is in km/m
        # Starting point at BL corner
        composer_extent = composer_map.extent()
        start_point = QgsPoint(composer_extent.xMinimum(),
                               composer_extent.yMinimum())
        # Ending point at BR corner
        end_point = QgsPoint(composer_extent.xMaximum(),
                             composer_extent.yMinimum())
        ground_distance = distance_area.measureLine(start_point, end_point)
        # Get the equivalent map distance per page mm
        map_width = self.mapWidth
        # How far is 1mm on map on the ground in meters?
        mm_to_ground = ground_distance / map_width
        #print 'MM:', myMMDistance
        # How long we want the scale bar to be in relation to the map
        scalebar_to_map_ratio = 0.5
        # How many divisions the scale bar should have
        tick_count = 5
        scale_bar_width_mm = map_width * scalebar_to_map_ratio
        print_segment_width_mm = scale_bar_width_mm / tick_count
        # Segment width in real world (m)
        # We apply some logic here so that segments are displayed in meters
        # if each segment is less that 1000m otherwise km. Also the segment
        # lengths are rounded down to human looking numbers e.g. 1km not 1.1km
        units = ''
        ground_segment_width = print_segment_width_mm * mm_to_ground
        if ground_segment_width < 1000:
            units = 'm'
            ground_segment_width = round(ground_segment_width)
            # adjust the segment width now to account for rounding
            print_segment_width_mm = ground_segment_width / mm_to_ground
        else:
            units = 'km'
            # Segment with in real world (km)
            ground_segment_width = round(ground_segment_width / 1000)
            print_segment_width_mm = ((ground_segment_width * 1000) /
                                      mm_to_ground)
        # Now adjust the scalebar width to account for rounding
        scale_bar_width_mm = tick_count * print_segment_width_mm

        #print "SBWMM:", scale_bar_width_mm
        #print "SWMM:", print_segment_width_mm
        #print "SWM:", myGroundSegmentWidthM
        #print "SWKM:", myGroundSegmentWidthKM
        # start drawing in line segments
        scalebar_height = 5  # mm
        line_width = 0.3  # mm
        inset_distance = 7  # how much to inset the scalebar into the map by
        scalebar_x = self.page_margin + inset_distance
        scalebar_y = (top_offset + self.map_height - inset_distance -
                      scalebar_height)  # mm

        # Draw an outer background box - shamelessly hardcoded buffer
        rectangle = QgsComposerShape(
            scalebar_x - 4,  # left edge
            scalebar_y - 3,  # top edge
            scale_bar_width_mm + 13,  # right edge
            scalebar_height + 6,  # bottom edge
            self.composition)

        rectangle.setShapeType(QgsComposerShape.Rectangle)
        pen = QtGui.QPen()
        pen.setColor(QtGui.QColor(255, 255, 255))
        pen.setWidthF(line_width)
        rectangle.setPen(pen)
        #rectangle.setLineWidth(line_width)
        rectangle.setFrameEnabled(False)
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        # workaround for missing setTransparentFill missing from python api
        rectangle.setBrush(brush)
        self.composition.addItem(rectangle)
        # Set up the tick label font
        font_weight = QtGui.QFont.Normal
        font_size = 6
        italics_flag = False
        font = QtGui.QFont('verdana', font_size, font_weight, italics_flag)
        # Draw the bottom line
        up_shift = 0.3  # shift the bottom line up for better rendering
        rectangle = QgsComposerShape(scalebar_x,
                                     scalebar_y + scalebar_height - up_shift,
                                     scale_bar_width_mm, 0.1, self.composition)

        rectangle.setShapeType(QgsComposerShape.Rectangle)
        pen = QtGui.QPen()
        pen.setColor(QtGui.QColor(255, 255, 255))
        pen.setWidthF(line_width)
        rectangle.setPen(pen)
        #rectangle.setLineWidth(line_width)
        rectangle.setFrameEnabled(False)
        self.composition.addItem(rectangle)

        # Now draw the scalebar ticks
        for tick_counter in range(0, tick_count + 1):
            distance_suffix = ''
            if tick_counter == tick_count:
                distance_suffix = ' ' + units
            real_world_distance = (
                '%.0f%s' %
                (tick_counter * ground_segment_width, distance_suffix))
            #print 'RW:', myRealWorldDistance
            mm_offset = scalebar_x + (tick_counter * print_segment_width_mm)
            #print 'MM:', mm_offset
            tick_height = scalebar_height / 2
            # Lines are not exposed by the api yet so we
            # bodge drawing lines using rectangles with 1px height or width
            tick_width = 0.1  # width or rectangle to be drawn
            uptick_line = QgsComposerShape(
                mm_offset, scalebar_y + scalebar_height - tick_height,
                tick_width, tick_height, self.composition)

            uptick_line.setShapeType(QgsComposerShape.Rectangle)
            pen = QtGui.QPen()
            pen.setWidthF(line_width)
            uptick_line.setPen(pen)
            #uptick_line.setLineWidth(line_width)
            uptick_line.setFrameEnabled(False)
            self.composition.addItem(uptick_line)
            #
            # Add a tick label
            #
            label = QgsComposerLabel(self.composition)
            label.setFont(font)
            label.setText(real_world_distance)
            label.adjustSizeToText()
            label.setItemPosition(mm_offset - 3, scalebar_y - tick_height)
            label.setFrameEnabled(self.show_frames)
            self.composition.addItem(label)