Ejemplo n.º 1
0
 def _assertCoordsAlmostEqual(self,
                              pt1: QgsPointXY,
                              pt2: QgsPointXY,
                              places=6):
     """Assert coordinates are the same within 0.000005 degrees"""
     self.assertAlmostEqual(pt1.x(), pt2.x(), places=places)
     self.assertAlmostEqual(pt1.y(), pt2.y(), places=places)
Ejemplo n.º 2
0
def Draw_Graph(G):
    # extraire Les Sommets du Graphe G
    Nodes = list(G.nodes)
    # extraire Les Segments  du Graphe G
    Segments = list(G.edges())
    # creer une couche de Sommets memoire
    Nodes_layer = QgsVectorLayer('Point', 'Nodes', "memory")
    Nodes_pr = Nodes_layer.dataProvider()
    # creer une couche de Segments memoire
    Segments_layer = QgsVectorLayer('LineString', 'Segments', "memory")
    Segments_pr = Segments_layer.dataProvider()
    # les Sommets
    for i in range(len(Nodes)):
        Node = QgsPointXY(Nodes[i][0], Nodes[i][1])
        # creer et ajouter le Sommet
        point = QgsFeature()
        point.setGeometry(QgsGeometry.fromPointXY(Node))
        Nodes_pr.addFeatures([point])
    # les Segments
    for i in range(len(Segments)):
        Start_Node = QgsPointXY(Segments[i][0][0], Segments[i][0][1])
        End_Node = QgsPointXY(Segments[i][1][0], Segments[i][1][1])
        if Start_Node.x() != End_Node.x() or Start_Node.y() != End_Node.y():
            # creer et ajouter la line
            segment = QgsFeature()
            segment.setGeometry(QgsGeometry.fromPolylineXY([Start_Node, End_Node]))
            Segments_pr.addFeatures([segment])
    Nodes_layer.updateExtents()
    Segments_layer.updateExtents()
    QgsProject.instance().addMapLayers([Nodes_layer, Segments_layer])
Ejemplo n.º 3
0
    def set_point(self, variable: str, point: QgsPointXY,
                  crs: QgsCoordinateReferenceSystem) -> list:
        """
        Produces R code that creates a variable from point input.

        :param variable: string. Name of the variable.
        :param point: QgsPointXY. Point to extract x and y coordinates from.
        :param crs: QgsCoordinateReferenceSystem. Coordinate reference system for the point.
        :return: string. R code that constructs the point.
        """

        commands = []

        if self.use_sf:

            commands.append('point_crs <- st_crs(\'{}\')'.format(crs.toWkt()))
            commands.append(
                '{0} <- st_sfc(st_point(c({1},{2})), crs = point_crs)'.format(
                    variable, point.x(), point.y()))

        else:

            commands.append('xy_df <- cbind(c({}), c({}))'.format(
                point.x(), point.y()))
            commands.append('point_crs <- CRS(\'{}\')'.format(crs.toProj4()))
            commands.append(
                '{} <- SpatialPoints(xy_df, proj4string = point_crs)'.format(
                    variable))

        return commands
    def transformedCornerCoordinates(self, center, rotation, xScale, yScale):
        # scale
        topLeft = QgsPointXY(
            -self.image.width() / 2.0 * xScale, self.image.height() / 2.0 * yScale
        )
        topRight = QgsPointXY(
            self.image.width() / 2.0 * xScale, self.image.height() / 2.0 * yScale
        )
        bottomLeft = QgsPointXY(
            -self.image.width() / 2.0 * xScale, -self.image.height() / 2.0 * yScale
        )
        bottomRight = QgsPointXY(
            self.image.width() / 2.0 * xScale, -self.image.height() / 2.0 * yScale
        )

        # rotate
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)

        topLeft = self._rotate(topLeft, cosRot, sinRot)
        topRight = self._rotate(topRight, cosRot, sinRot)
        bottomRight = self._rotate(bottomRight, cosRot, sinRot)
        bottomLeft = self._rotate(bottomLeft, cosRot, sinRot)

        topLeft.set(topLeft.x() + center.x(), topLeft.y() + center.y())
        topRight.set(topRight.x() + center.x(), topRight.y() + center.y())
        bottomRight.set(bottomRight.x() + center.x(), bottomRight.y() + center.y())
        bottomLeft.set(bottomLeft.x() + center.x(), bottomLeft.y() + center.y())

        return (topLeft, topRight, bottomRight, bottomLeft)
    def transformedCornerCoordinates(self, center, rotation, xScale, yScale):
        # scale
        topLeft = QgsPointXY(-self.image.width() / 2.0 * xScale,
                             self.image.height() / 2.0 * yScale)
        topRight = QgsPointXY(self.image.width() / 2.0 * xScale,
                              self.image.height() / 2.0 * yScale)
        bottomLeft = QgsPointXY(-self.image.width() / 2.0 * xScale,
                                - self.image.height() / 2.0 * yScale)
        bottomRight = QgsPointXY(self.image.width() / 2.0 * xScale,
                                 - self.image.height() / 2.0 * yScale)

        # rotate
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)

        topLeft = self._rotate(topLeft, cosRot, sinRot)
        topRight = self._rotate(topRight, cosRot, sinRot)
        bottomRight = self._rotate(bottomRight, cosRot, sinRot)
        bottomLeft = self._rotate(bottomLeft, cosRot, sinRot)

        topLeft.set(topLeft.x() + center.x(), topLeft.y() + center.y())
        topRight.set(topRight.x() + center.x(), topRight.y() + center.y())
        bottomRight.set(bottomRight.x() + center.x(),
                        bottomRight.y() + center.y())
        bottomLeft.set(bottomLeft.x() + center.x(),
                       bottomLeft.y() + center.y())

        return (topLeft, topRight, bottomRight, bottomLeft)
Ejemplo n.º 6
0
    def cut_point(self, section, xls_feature, side_dist_field = -1):
        feat = QgsFeature(xls_feature)
        points, bst, vst = self.calc_factor(section, xls_feature)

        p_old = QgsPointXY(points[0])

        sum_len = 0
        count_points = len(points)
        for i in range(count_points):
            p = QgsPointXY(points[i])
            dist = self.distanz.measureLine(p_old, p)
            sum_len += dist
            # print(str(sum_len) + " > " + str(vst))
            if sum_len > vst or i == count_points - 1:
                part = (sum_len - vst) / dist

                dx = p.x() - p_old.x()
                dy = p.y() - p_old.y()

                side_factor = 0
                if side_dist_field >= 0:
                    side_factor = xls_feature[side_dist_field] / dist

                x = p.x() - part * dx + dy * side_factor
                y = p.y() - part * dy - dx * side_factor

                feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))
                return feat
            p_old = p
Ejemplo n.º 7
0
    def getCell(self, point):
        """ get local coordinates for point based on baseRaster transform """
        topLeft = QgsPointXY(self.transform[0], self.transform[3])

        pointInRaster = QgsPointXY(point.x() - topLeft.x(),
                                   topLeft.y() - point.y())
        # swap axes
        cell = QgsPointXY(int(pointInRaster.y() / -self.transform[5]),
                          int(pointInRaster.x() / self.transform[1]))
        return cell
Ejemplo n.º 8
0
    def getGlobalPos(self, localPos):
        """ get global coordinates for local point based on baseRaster transform """
        topLeft = QgsPointXY(self.transform[0], self.transform[3])

        # swap axes
        pos = QgsPointXY(localPos.y() * (-self.transform[5]),
                         localPos.x() * (-self.transform[1]))
        globalPoint = QgsPointXY(pos.x() + topLeft.x(), pos.y() + topLeft.y())

        return globalPoint
Ejemplo n.º 9
0
    def syntheticFeatureSelection(self, startPoint: QgsPointXY,
                                  endPoint: QgsPointXY,
                                  modifiers: Qt.KeyboardModifiers) -> None:
        if startPoint is None or endPoint is None:
            raise Exception(
                'Something went very bad, unable to create selection without start or end point'
            )

        assert self.simplifiedSegmentsLayer

        if self.selectionMode != SelectionModes.LINES:
            self.simplifiedSegmentsLayer.removeSelection()

        # check the Shift and Control modifiers to reproduce the navive selection
        if modifiers & Qt.ShiftModifier:
            selectBehaviour = QgsVectorLayer.AddToSelection
        elif modifiers & Qt.ControlModifier:
            selectBehaviour = QgsVectorLayer.RemoveFromSelection
        else:
            selectBehaviour = QgsVectorLayer.SetSelection

        if startPoint.x() == endPoint.x() and startPoint.y() == endPoint.y():
            tolerance = QgsTolerance.defaultTolerance(iface.activeLayer(),
                                                      QgsMapSettings())
            tolerance = tolerance * self.canvas.mapUnitsPerPixel()
            startPoint = QgsPointXY(startPoint.x() - tolerance,
                                    startPoint.y() - tolerance)
            endPoint = QgsPointXY(endPoint.x() + tolerance,
                                  endPoint.y() + tolerance)

        lines = None
        rect = QgsRectangle(startPoint, endPoint)

        if self.selectionMode == SelectionModes.ENCLOSING:
            lines = self.getLinesSelectionModeEnclosing(selectBehaviour, rect)
        elif self.selectionMode == SelectionModes.LINES:
            lines = self.getLinesSelectionModeLines(selectBehaviour, rect)
        elif self.selectionMode == SelectionModes.NODES:
            lines = self.getLinesSelectionModeVertices(selectBehaviour, rect)

            if lines is None:
                return
        else:
            raise Exception(
                'Wrong selection mode selected, should never be the case')

        if not len(lines):
            show_info(__('No results found!'))
            self.deleteAllCandidates()
            return

        if not self.addCandidates(lines):
            show_info(__('Unable to add candidates'))
            return
Ejemplo n.º 10
0
    def get_rect_projection(self, rect_geom, cp, x_length=0, y_length=0):
        """
        Transforms the rectangle geometry to its projection on the real world, making all its angles 90º


        :param rect_geom: 4 point geometry
        :param cp: central point of the geometry
        :param x_length: distance between first and second points of the rect_geom
        :param y_length: distance between second and third points of the rect_geom
        :return: geometry projected to map
        """
        if x_length == 0 and y_length == 0:
            proj_geom = self.get_rect_by3_points(rect_geom.asPolygon()[0][0],
                                                 rect_geom.asPolygon()[0][1],
                                                 rect_geom.asPolygon()[0][2])

        else:
            point_two = endpoint(
                rect_geom.asPolygon()[0][0], x_length,
                degrees(
                    self.distance.bearing(rect_geom.asPolygon()[0][0],
                                          rect_geom.asPolygon()[0][1])))
            point_three = endpoint(
                rect_geom.asPolygon()[0][0], y_length,
                degrees(
                    self.distance.bearing(rect_geom.asPolygon()[0][1],
                                          rect_geom.asPolygon()[0][3])))

            proj_geom = self.get_rect_by3_points(rect_geom.asPolygon()[0][0],
                                                 point_two, point_three,
                                                 y_length)

        if proj_geom is not None:

            p1 = proj_geom.asPolygon()[0][0]
            p2 = proj_geom.asPolygon()[0][1]
            p3 = proj_geom.asPolygon()[0][2]
            p4 = proj_geom.asPolygon()[0][3]

            px = (p1.x() + p3.x()) / 2.0
            py = (p1.y() + p3.y()) / 2.0

            p1 = QgsPointXY(p1.x() - px + cp.x(), p1.y() - py + cp.y())
            p2 = QgsPointXY(p2.x() - px + cp.x(), p2.y() - py + cp.y())
            p3 = QgsPointXY(p3.x() - px + cp.x(), p3.y() - py + cp.y())
            p4 = QgsPointXY(p4.x() - px + cp.x(), p4.y() - py + cp.y())

            proj_geom = QgsGeometry.fromPolygonXY([[p1, p2, p3, p4]])

            return proj_geom

        else:
            return rect_geom
Ejemplo n.º 11
0
 def showRect(self, startPoint, param, rotAngle=0):
     """
     Draws a rectangle in the canvas
     """
     self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
     x = startPoint.x()  # center point x
     y = startPoint.y()  # center point y
     # rotation angle is always applied in reference to center point
     # to avoid unnecessary calculations
     c = cos(rotAngle)
     s = sin(rotAngle)
     # translating coordinate system to rubberband centroid
     point1 = QgsPointXY((-param), (-param))
     point2 = QgsPointXY((-param), (param))
     point3 = QgsPointXY((param), (param))
     point4 = QgsPointXY((param), (-param))
     # rotating and moving to original coord. sys.
     point1_ = QgsPointXY(point1.x() * c - point1.y() * s + x,
                          point1.y() * c + point1.x() * s + y)
     point2_ = QgsPointXY(point2.x() * c - point2.y() * s + x,
                          point2.y() * c + point2.x() * s + y)
     point3_ = QgsPointXY(point3.x() * c - point3.y() * s + x,
                          point3.y() * c + point3.x() * s + y)
     point4_ = QgsPointXY(point4.x() * c - point4.y() * s + x,
                          point4.y() * c + point4.x() * s + y)
     self.rubberBand.addPoint(point1_, False)
     self.rubberBand.addPoint(point2_, False)
     self.rubberBand.addPoint(point3_, False)
     self.rubberBand.addPoint(point4_, True)
     self.rubberBand.show()
     self.currentCentroid = startPoint
Ejemplo n.º 12
0
def rectangle2pCreate(firstPoint, secondPoint, azimutO):

    #     X1Y2 (1)        H2      secondPoint (2)
    #       +---------------------------+
    #       |                           |
    #       |                           |
    #    V1 |                           | V2
    #       |                           |
    #       |             H1            |
    #       +---------------------------+   ----------> AzimutO
    #     firstPoint (0 - 4)         X2Y1 (3)

    templinePoint = QgsPointXY(secondPoint.x() + 10 * math.sin(azimutO),
                               secondPoint.y() + 10 * math.cos(azimutO))
    p1 = pointToLine2D(firstPoint.x(), firstPoint.y(), secondPoint.x(),
                       secondPoint.y(), templinePoint.x(), templinePoint.y())

    ax = p1.x() - secondPoint.x()
    ay = p1.y() - secondPoint.y()
    width = math.sqrt(ax**2 + ay**2)
    ax = p1.x() - firstPoint.x()
    ay = p1.y() - firstPoint.y()
    height = math.sqrt(ax**2 + ay**2)

    centerX = (firstPoint.x() + secondPoint.x()) * 0.5
    centerY = (firstPoint.y() + secondPoint.y()) * 0.5

    tempLinePoint2 = QgsPointXY(firstPoint.x() + 10 * math.sin(azimutO),
                                firstPoint.y() + 10 * math.cos(azimutO))
    p3 = pointToLine2D(secondPoint.x(), secondPoint.y(), firstPoint.x(),
                       firstPoint.y(), tempLinePoint2.x(), tempLinePoint2.y())

    azP1 = normalizeAngle(lineAzimut2p(firstPoint, p1))
    azP3 = normalizeAngle(lineAzimut2p(firstPoint, p3))
    azimut100 = normalizeAngle(azimutO + math.pi * 0.5)

    if abs(azP3 - azimutO) <= 0.000001:
        if abs(azP1 - azimut100) <= 0.000001:
            # Cuadrante 2
            return [p1, firstPoint, p3, secondPoint]
        else:
            # Cuadrante 1
            return [firstPoint, p1, secondPoint, p3]
    else:
        if abs(azP1 - azimut100) <= 0.000001:
            # Cuadrante 3
            return [secondPoint, p3, firstPoint, p1]
        else:
            # Cuadrante 4
            return [p3, secondPoint, p1, firstPoint]
Ejemplo n.º 13
0
    def processAlgorithm(self, parameters, context, feedback):
        inputFrameLayer = self.parameterAsSource( parameters,self.INPUT_FRAME, context )
        boolVar = self.parameterAsBool( parameters,self.INPUT_FRAME, context )
        gridScaleParam = self.parameterAsInt(parameters, self.INPUT_SCALE, context)
        frameLayer = self.runAddCount(inputFrameLayer, boolVar)

        if (gridScaleParam==0):
            gridScale = 25000
        elif (gridScaleParam==1):
            gridScale = 50000
        if (gridScaleParam==2):
            gridScale = 100000
        elif (gridScaleParam==3):
            gridScale = 250000

        self.runCreateSpatialIndex(frameLayer)
        # Converter moldura para lat long
        crs = QgsCoordinateReferenceSystem("EPSG:4326")
        frameLayer4326 = self.reprojectLayer(frameLayer, crs)
        # Pegar centro da moldura  (se tiver mais de um polígono na camada de moldura pegar o centro dos centros)
        if frameLayer4326.featureCount()>1:
            xs=[]
            ys=[]
            for poly in frameLayer4326.getFeatures():
                centroid=QgsPointXY(poly.geometry().centroid().constGet())
                xs.append(centroid.x())
                ys.append(centroid.y())
            centroid= QgsPointXY(sum(xs)/len(xs), sum(ys)/len(ys))
        else:
            for poly in frameLayer4326.getFeatures():
                centroid=QgsPointXY(poly.geometry().centroid().constGet())
        # Descobrir o utm
        utmString = self.getSirgasAuthIdByPointLatLong(centroid.y(), centroid.x())
        utm = QgsCoordinateReferenceSystem(utmString)
        frameLayerReprojected = self.reprojectLayer(frameLayer, utm)
        # Criar a grade com 4cm (baseado na escala) de distancia entre as linhas no fuso
        gridSize = 4*gridScale/100
        ptLyrExt = frameLayerReprojected.extent()
        xmin = ptLyrExt.xMinimum()
        xmax = ptLyrExt.xMaximum()
        ymin = ptLyrExt.yMinimum()
        ymax = ptLyrExt.yMaximum()
        xmin, xmax, ymin, ymax = self.processExtent(xmin, xmax, ymin, ymax, gridSize)
        grid = self.makeGrid(gridSize, utm, xmin, xmax, ymin, ymax, parameters, context, feedback)
        # Reprojetar para CRS de destino (moldura)
        reprojectGrid = self.reprojectLayer(grid,inputFrameLayer.sourceCrs())
        lineLayer = self.convertPolygonToLines(reprojectGrid)
        newLayer = self.outLayer(parameters, context, lineLayer, 2)
        return {self.OUTPUT: newLayer}
    def testPoint(self):
        point = QgsReferencedPointXY(QgsPointXY(1.0, 2.0),
                                     QgsCoordinateReferenceSystem('epsg:3111'))
        self.assertEqual(point.x(), 1.0)
        self.assertEqual(point.y(), 2.0)
        self.assertEqual(point.crs().authid(), 'EPSG:3111')

        point.setCrs(QgsCoordinateReferenceSystem('epsg:28356'))
        self.assertEqual(point.crs().authid(), 'EPSG:28356')

        # in variant
        v = QVariant(
            QgsReferencedPointXY(QgsPointXY(3.0, 4.0),
                                 QgsCoordinateReferenceSystem('epsg:3111')))
        self.assertEqual(v.value().x(), 3.0)
        self.assertEqual(v.value().y(), 4.0)
        self.assertEqual(v.value().crs().authid(), 'EPSG:3111')

        # to QgsPointXY
        p = QgsPointXY(point)
        self.assertEqual(p.x(), 1.0)
        self.assertEqual(p.y(), 2.0)

        # equality
        point = QgsReferencedPointXY(QgsPointXY(1.0, 2.0),
                                     QgsCoordinateReferenceSystem('epsg:3111'))
        point2 = QgsReferencedPointXY(
            QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:3111'))
        self.assertEqual(point, point2)
        point2 = QgsReferencedPointXY(
            QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:4326'))
        self.assertNotEqual(point, point2)
        point2 = QgsReferencedPointXY(
            QgsPointXY(1.1, 2.0), QgsCoordinateReferenceSystem('epsg:3111'))
        self.assertNotEqual(point, point2)
    def capture_position(self, event):
        """
        Record the position of the mouse pointer and adjust if keyboard modifier is pressed

        :type event: qgis.gui.QgsMapMouseEvent
        """
        # adjust dimension on the fly if Shift is pressed
        if QApplication.keyboardModifiers() == Qt.ShiftModifier:
            end_point = QgsPointXY(self.toMapCoordinates(event.pos()))
            rect = QgsRectangle(self.startPoint, end_point)

            # return if start and endpoint are the same
            if rect.width() + rect.height() == 0:
                self.endPoint = self.toMapCoordinates(event.pos())
                return

            if rect.width() > rect.height():
                # make height (y) same as width in the correct direction
                if self.startPoint.y() < end_point.y():
                    end_point.setY(self.startPoint.y() + rect.width())
                else:
                    end_point.setY(self.startPoint.y() - rect.width())
            else:
                # make width (x) same as height in the correct direction
                if self.startPoint.x() < end_point.x():
                    end_point.setX(self.startPoint.x() + rect.height())
                else:
                    end_point.setX(self.startPoint.x() - rect.height())

            self.endPoint = end_point
        else:
            self.endPoint = self.toMapCoordinates(event.pos())
Ejemplo n.º 16
0
    def calculate_score(self, a_x, a_y, a_angle, a_scale, b_x, b_y, b_angle,
                        b_scale):
        """
        This calculates the score of this edge with custom parameter values (to be used by optimizer)
        """
        # We get the transform matrix (matrix to transform from A to B, as calculated by imreg_dft)
        tvec = QgsPointXY(self.tvec[0], self.tvec[1])
        tvec *= self.imageA.pixel_size * a_scale / DOWNSCALING_FACTOR
        edge_matrix = transform_matrix(self.scale, self.angle, tvec.x(),
                                       tvec.y())
        # We get the point A transform matrix (matrix to transform from local to A coordinates)
        ptA_matrix = transform_matrix(a_scale, a_angle, a_x, a_y)
        # We compute the A*edge matrix (matrix to get to B coordinates)
        ptA_edge_matrix = ptA_matrix * edge_matrix
        # We get the point B transform matrix (matrix to transform from local to B coordinates)
        ptB_matrix = transform_matrix(b_scale, b_angle, b_x, b_y)

        # Now we compare how well ptA_edge_matrix and ptB_matrix are similar using two sample points (in homogeneous coordinates)
        sample1 = [[10], [0], [1]]
        sample1_a = ptA_matrix * sample1
        sample1_b = ptB_matrix * sample1
        sample1_ab = ptA_edge_matrix * sample1

        sample2 = [[0], [10], [1]]
        sample2_a = ptA_matrix * sample2
        sample2_b = ptB_matrix * sample2
        sample2_ab = ptA_edge_matrix * sample2

        # The score is the distance between the two transformed points (summed)
        score1 = math.sqrt((sample1_b.item(0) - sample1_ab.item(0))**2 +
                           (sample1_b.item(1) - sample1_ab.item(1))**2)
        score2 = math.sqrt((sample2_b.item(0) - sample2_ab.item(0))**2 +
                           (sample2_b.item(1) - sample2_ab.item(1))**2)

        return score1 + score2
 def update(self, point: QgsPointXY):
     userCrsPoint = self.transform.transform(point)
     self.dockwidget.userCrsEdit.setText('{0:.{2}f}, {1:.{2}f}'.format(userCrsPoint.x(),
                                                                      userCrsPoint.y(),
                                                                      self.userCrsDisplayPrecision))
     self.dockwidget.canvasCrsEdit.setText('{0:.{2}f}, {1:.{2}f}'.format(point.x(),
                                                                     point.y(),
                                                                     self.canvasCrsDisplayPrecision))
Ejemplo n.º 18
0
 def normalizePoint(self, x, y):
     """Normalize given point. In result, lower-left is (0, 0) and upper-right is (1, 1)."""
     pt = QgsPointXY(x, y)
     if self._rotation:
         pt = self.rotatePoint(pt, -self._rotation, self._center)
     rect = self._unrotated_rect
     return QgsPointXY((pt.x() - rect.xMinimum()) / rect.width(),
                       (pt.y() - rect.yMinimum()) / rect.height())
Ejemplo n.º 19
0
    def testContains(self):
        rect1 = QgsRectangle(0.0, 0.0, 5.0, 5.0)
        rect2 = QgsRectangle(2.0, 2.0, 7.0, 7.0)
        pnt1 = QgsPointXY(4.0, 4.0)
        pnt2 = QgsPointXY(6.0, 2.0)

        rect3 = rect1.intersect(rect2)
        self.assertTrue(rect1.contains(rect3))
        self.assertTrue(rect2.contains(rect3))

        # test for point
        self.assertTrue(rect1.contains(pnt1))
        self.assertTrue(rect1.contains(pnt1.x(), pnt1.y()))
        self.assertTrue(rect2.contains(pnt1))
        self.assertTrue(rect2.contains(pnt1.x(), pnt1.y()))
        self.assertTrue(rect3.contains(pnt1))
        self.assertTrue(rect3.contains(pnt1.x(), pnt1.y()))
        self.assertFalse(rect1.contains(pnt2))
        self.assertFalse(rect1.contains(pnt2.x(), pnt2.y()))
        self.assertTrue(rect2.contains(pnt2))
        self.assertTrue(rect2.contains(pnt2.x(), pnt2.y()))
        self.assertFalse(rect3.contains(pnt2))
        self.assertFalse(rect3.contains(pnt2.x(), pnt2.y()))
        self.assertTrue(rect3.contains(pnt1))
        self.assertTrue(rect3.contains(pnt1.x(), pnt1.y()))
Ejemplo n.º 20
0
    def anglesBetweenLines(self, line1, line2, point):
        pointB = QgsPointXY(point.asPoint())
        pointA = self.adjacentPoint(line1, pointB)
        pointC = self.adjacentPoint(line2, pointB)
        angleRad = QgsGeometryUtils().angleBetweenThreePoints(
            pointA.x(), pointA.y(), pointB.x(), pointB.y(), pointC.x(),
            pointC.y())
        angle = math.degrees(angleRad)

        return abs(angle)
Ejemplo n.º 21
0
    def calculateSquare(self, point):
        '''
        point in layer coordinates(QgsPoint)
        '''
        mapCrs = self.canvas.mapSettings().destinationCrs()
        utmCrs = QgsCoordinateReferenceSystem()
        utmCrs.createFromProj4(self.proj4Utm(point))
        ctFwd = QgsCoordinateTransform(mapCrs, utmCrs, QgsProject.instance())
        ctBwd = QgsCoordinateTransform(utmCrs, mapCrs, QgsProject.instance())

        pointGeom = QgsGeometry.fromPointXY(point)
        pointGeom.transform(ctFwd)
        pointUtm = QgsPointXY(pointGeom.asPoint())

        # calculate d
        d = self.diagonal / (2 * (2**0.5))

        left = pointUtm.x() - d
        bottom = pointUtm.y() - d
        right = pointUtm.x() + d
        top = pointUtm.y() + d

        p1 = QgsGeometry.fromPointXY(QgsPointXY(left, bottom))
        p2 = QgsGeometry.fromPointXY(QgsPointXY(right, bottom))
        p3 = QgsGeometry.fromPointXY(QgsPointXY(right, top))
        p4 = QgsGeometry.fromPointXY(QgsPointXY(left, top))

        p1.transform(ctBwd)
        p2.transform(ctBwd)
        p3.transform(ctBwd)
        p4.transform(ctBwd)

        mapPol = [
            p1.asPoint(),
            p2.asPoint(),
            p3.asPoint(),
            p4.asPoint(),
            p1.asPoint()
        ]

        return mapPol
    def transformedCornerCoordinatesFromPoint(
        self, startPoint, rotation, xScale, yScale
    ):
        # startPoint is a fixed point for this new movement (rotation and
        # scale)
        # rotation is the global rotation of the image
        # xScale is the new xScale factor to be multiplied by self.xScale
        # idem for yScale
        # Calculate the coordinate of the center in a startPoint origin
        # coordinate system and apply scales
        dX = (self.center.x() - startPoint.x()) * xScale
        dY = (self.center.y() - startPoint.y()) * yScale
        # Half width and half height in the current transformation
        hW = (self.image.width() / 2.0) * self.xScale * xScale
        hH = (self.image.height() / 2.0) * self.yScale * yScale
        # Actual rectangle coordinates :
        pt1 = QgsPointXY(-hW, hH)
        pt2 = QgsPointXY(hW, hH)
        pt3 = QgsPointXY(hW, -hH)
        pt4 = QgsPointXY(-hW, -hH)
        # Actual rotation from the center
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -self.rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)
        pt1 = self._rotate(pt1, cosRot, sinRot)
        pt2 = self._rotate(pt2, cosRot, sinRot)
        pt3 = self._rotate(pt3, cosRot, sinRot)
        pt4 = self._rotate(pt4, cosRot, sinRot)
        # Second transformation
        # displacement of the origin
        pt1 = QgsPointXY(pt1.x() + dX, pt1.y() + dY)
        pt2 = QgsPointXY(pt2.x() + dX, pt2.y() + dY)
        pt3 = QgsPointXY(pt3.x() + dX, pt3.y() + dY)
        pt4 = QgsPointXY(pt4.x() + dX, pt4.y() + dY)
        # Rotation
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)
        pt1 = self._rotate(pt1, cosRot, sinRot)
        pt2 = self._rotate(pt2, cosRot, sinRot)
        pt3 = self._rotate(pt3, cosRot, sinRot)
        pt4 = self._rotate(pt4, cosRot, sinRot)
        # translate to startPoint
        pt1 = QgsPointXY(pt1.x() + startPoint.x(), pt1.y() + startPoint.y())
        pt2 = QgsPointXY(pt2.x() + startPoint.x(), pt2.y() + startPoint.y())
        pt3 = QgsPointXY(pt3.x() + startPoint.x(), pt3.y() + startPoint.y())
        pt4 = QgsPointXY(pt4.x() + startPoint.x(), pt4.y() + startPoint.y())

        return (pt1, pt2, pt3, pt4)
    def transformedCornerCoordinatesFromPoint(self, startPoint, rotation,
                                              xScale, yScale):
        # startPoint is a fixed point for this new movement (rotation and
        # scale)
        # rotation is the global rotation of the image
        # xScale is the new xScale factor to be multiplied by self.xScale
        # idem for yScale
        # Calculate the coordinate of the center in a startPoint origin
        # coordinate system and apply scales
        dX = (self.center.x() - startPoint.x()) * xScale
        dY = (self.center.y() - startPoint.y()) * yScale
        # Half width and half height in the current transformation
        hW = (self.image.width() / 2.0) * self.xScale * xScale
        hH = (self.image.height() / 2.0) * self.yScale * yScale
        # Actual rectangle coordinates :
        pt1 = QgsPointXY(-hW, hH)
        pt2 = QgsPointXY(hW, hH)
        pt3 = QgsPointXY(hW, -hH)
        pt4 = QgsPointXY(-hW, -hH)
        # Actual rotation from the center
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -self.rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)
        pt1 = self._rotate(pt1, cosRot, sinRot)
        pt2 = self._rotate(pt2, cosRot, sinRot)
        pt3 = self._rotate(pt3, cosRot, sinRot)
        pt4 = self._rotate(pt4, cosRot, sinRot)
        # Second transformation
        # displacement of the origin
        pt1 = QgsPointXY(pt1.x() + dX, pt1.y() + dY)
        pt2 = QgsPointXY(pt2.x() + dX, pt2.y() + dY)
        pt3 = QgsPointXY(pt3.x() + dX, pt3.y() + dY)
        pt4 = QgsPointXY(pt4.x() + dX, pt4.y() + dY)
        # Rotation
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)
        pt1 = self._rotate(pt1, cosRot, sinRot)
        pt2 = self._rotate(pt2, cosRot, sinRot)
        pt3 = self._rotate(pt3, cosRot, sinRot)
        pt4 = self._rotate(pt4, cosRot, sinRot)
        # translate to startPoint
        pt1 = QgsPointXY(pt1.x() + startPoint.x(), pt1.y() + startPoint.y())
        pt2 = QgsPointXY(pt2.x() + startPoint.x(), pt2.y() + startPoint.y())
        pt3 = QgsPointXY(pt3.x() + startPoint.x(), pt3.y() + startPoint.y())
        pt4 = QgsPointXY(pt4.x() + startPoint.x(), pt4.y() + startPoint.y())

        return (pt1, pt2, pt3, pt4)
Ejemplo n.º 24
0
 def set_center_from_canvas_point(self, point: QgsPointXY):
     """
     Sets the widget center point from a canvas point
     """
     ct = QgsCoordinateTransform(
         self.iface.mapCanvas().mapSettings().destinationCrs(),
         QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance())
     try:
         point = ct.transform(point)
         self.circular_lat_spinbox.setValue(point.y())
         self.circular_long_spinbox.setValue(point.x())
     except QgsCsException:
         pass
    def redrawRubberBand(self):
        self.canvas.scene().removeItem(self.rubberBand)
        self.prepareRubberBand()
        for i in range(len(self.capturedPoints)):
            point = self.capturedPoints[i]
            if point.__class__ == QgsPoint:
                vertexCoord = self.toMapCoordinatesV2(self.layer,
                                                      self.capturedPoints[i])
                vertexCoord = QgsPointXY(vertexCoord.x(), vertexCoord.y())
            else:
                vertexCoord = self.toMapCoordinates(self.layer,
                                                    self.capturedPoints[i])

            self.rubberBand.addPoint(vertexCoord)
Ejemplo n.º 26
0
    def point_clicked(self, point=None, button=None):
        if self.raster is None:
            self.uc.bar_warn("Choose a raster to work with...", dur=3)
            return

        if self.logger:
            self.logger.debug(f"Clicked point in canvas CRS: {point if point else self.last_point}")

        if point is None:
            ptxy_in_src_crs = self.last_point
        else:
            if self.crs_transform:
                if self.logger:
                    self.logger.debug(f"Transforming clicked point {point}")
                try:
                    ptxy_in_src_crs = self.crs_transform.transform(point)
                except QgsCsException as err:
                    self.uc.show_warn(
                        "Point coordinates transformation failed! Check the raster projection:\n\n{}".format(repr(err)))
                    return
            else:
                ptxy_in_src_crs = QgsPointXY(point.x(), point.y())

        if self.logger:
            self.logger.debug(f"Clicked point in raster CRS: {ptxy_in_src_crs}")
        self.last_point = ptxy_in_src_crs

        ident_vals = self.handler.provider.identify(ptxy_in_src_crs, QgsRaster.IdentifyFormatValue).results()
        cur_vals = list(ident_vals.values())

        # check if the point is within active raster extent
        if not self.rbounds[0] <= ptxy_in_src_crs.x() <= self.rbounds[2]:
            self.uc.bar_info("Out of x bounds", dur=3)
            return
        if not self.rbounds[1] <= ptxy_in_src_crs.y() <= self.rbounds[3]:
            self.uc.bar_info("Out of y bounds", dur=3)
            return

        if self.mode == 'draw':
            new_vals = self.spin_boxes.get_values()
            if self.logger:
                self.logger.debug(f"Applying const value {new_vals}")
            self.apply_values_single_cell(new_vals)
        else:
            self.spin_boxes.set_values(cur_vals)
            if 2 < self.handler.bands_nr < 5:
                self.color_picker_connection(connect=False)
                self.color_btn.setColor(QColor(*self.spin_boxes.get_values()[:4]))
                self.color_picker_connection(connect=True)
    def test_change_position(self):
        self.write_temp_mission_xml()
        self.mission_ctrl.load_mission(self.MISSION_NAME + ".xml")
        self.mission_track = self.mission_ctrl.mission_list[0]

        point = QgsPointXY(40.001, 3.002)
        self.mission_track.change_position(0, point)

        position = self.mission_track.get_step(0).get_maneuver().get_position()
        lat = position.get_latitude()
        lon = position.get_longitude()
        self.assertEqual(point.x(), lon)
        self.assertEqual(point.y(), lat)

        self.assertEqual(self.mission_track.is_modified(), True)
Ejemplo n.º 28
0
    def set_map_state(self,
                      center: QgsPointXY,
                      zoom: float,
                      bearing: int = 0,
                      drag_rotate: bool = False,
                      pitch: int = 0,
                      is_split: bool = False,
                      map_view_mode: str = MapState.map_view_mode):
        """ Set map state values """

        try:
            self._map_state = MapState(bearing, drag_rotate, center.y(),
                                       center.x(), pitch, zoom, is_split,
                                       map_view_mode, Globe.create_default())
        except Exception as e:
            raise InvalidInputException(
                tr('Check the map state configuration values'),
                bar_msg=bar_msg(e))
Ejemplo n.º 29
0
    def testPoint(self):
        point = QgsReferencedPointXY(QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:3111'))
        self.assertEqual(point.x(), 1.0)
        self.assertEqual(point.y(), 2.0)
        self.assertEqual(point.crs().authid(), 'EPSG:3111')

        point.setCrs(QgsCoordinateReferenceSystem('epsg:28356'))
        self.assertEqual(point.crs().authid(), 'EPSG:28356')

        # in variant
        v = QVariant(QgsReferencedPointXY(QgsPointXY(3.0, 4.0), QgsCoordinateReferenceSystem('epsg:3111')))
        self.assertEqual(v.value().x(), 3.0)
        self.assertEqual(v.value().y(), 4.0)
        self.assertEqual(v.value().crs().authid(), 'EPSG:3111')

        # to QgsPointXY
        p = QgsPointXY(point)
        self.assertEqual(p.x(), 1.0)
        self.assertEqual(p.y(), 2.0)
    def showRect(self, startPoint: QgsPointXY, endPoint: QgsPointXY) -> None:
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return
        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, True)    # true to update canvas
        self.rubberBand.show()
Ejemplo n.º 31
0
    def do_request(self, point: QgsPointXY) -> None:
        query = QUrlQuery()
        query.addQueryItem("lat", str(point.y()))
        query.addQueryItem("lon", str(point.x()))
        query.addQueryItem("format", "json")

        url = QUrl(self.URL)
        url.setQuery(query)

        request = QNetworkRequest(url)
        request.setHeader(QNetworkRequest.UserAgentHeader,
                          "*****@*****.**")

        response = self.nam.blockingGet(request)
        self._status_code = response.attribute(
            QNetworkRequest.HttpStatusCodeAttribute)
        self._content = json.loads(bytes(response.content()))
        if self._content.get("error"):
            self._error_string = self._content["error"]
            return
Ejemplo n.º 32
0
    def accept(self):
        """ Insert self.pont in the canvas"""
        self.set_format()
        if self.point is not None:
            new_point = QgsPointXY(float(self.get_coordinates()[1]),
                                   float(self.get_coordinates()[0]))
            if self.point_layer is None:
                self.add_new_landmark(self.point)

            self.point_layer.startEditing()
            self.point_layer.beginEditCommand("Move Point")  # for undo
            self.point_layer.moveVertex(new_point.x(), new_point.y(), self.feat.id() + 1, 0)
            self.point_layer.endEditCommand()
            self.point_layer.commitChanges()

            self.finish_add_landmark_signal.emit()
            super(PointFeatureDlg, self).accept()
        else:
            QMessageBox.warning(self,
                                "Invalid Point",
                                "Invalid point, make sure the coordinates are correct.",
                                QMessageBox.Close)
Ejemplo n.º 33
0
 def canvasMoveEvent(self, event):
     if self.snapCursorRubberBand:
         self.snapCursorRubberBand.hide()
         self.snapCursorRubberBand.reset(
             geometryType=QgsWkbTypes.PointGeometry)
         self.snapCursorRubberBand = None
     oldPoint = QgsPointXY(event.mapPoint())
     event.snapPoint()
     point = QgsPointXY(event.mapPoint())
     if oldPoint != point:
         self.createSnapCursor(point)
     if self.rubberBand:
         if self.qntPoint == 1:
             self.distanceToolTip.canvasMoveEvent(self.geometry[0], point)
             geom = QgsGeometry.fromPolylineXY([self.geometry[0], point])
             self.rubberBand.setToGeometry(geom, None)
         elif self.qntPoint >= 2:
             if self.free:
                 self.distanceToolTip.canvasMoveEvent(
                     self.geometry[-1], point)
                 geom = QgsGeometry.fromPolygonXY(
                     [self.geometry + [QgsPointXY(point.x(), point.y())]])
                 self.rubberBand.setToGeometry(geom, None)
             else:
                 if (self.qntPoint % 2 == 1):
                     self.setAvoidStyleSnapRubberBand()
                 else:
                     self.setAllowedStyleSnapRubberBand()
                 projectedMousePoint = self.projectPoint(
                     self.geometry[-2], self.geometry[-1], point)
                 self.distanceToolTip.canvasMoveEvent(
                     self.geometry[-1], projectedMousePoint)
                 if projectedMousePoint:
                     geom, pf = self.completePolygon(
                         self.geometry, projectedMousePoint)
                     self.rubberBand.setToGeometry(geom, None)
     else:
         self.initVariable()
Ejemplo n.º 34
0
    def checkPoint(self, point):
        state = 'yellow'

        if type(point) != QgsPointXY:
            try:
                if type(point) == list and len(point) == 2:
                    point = QgsPointXY(point[0], point[1])
                else:
                    point = QgsPointXY(point)
            except TypeError:
                return state, None
            
        if self.dhm != {}:
            extent = self.dhm['extent']
            [extLx, extHy, extHx, extLy] = extent
            
            if extLx <= float(point.x()) <= extHx \
                    and extLy <= float(point.y()) <= extHy:
                state = 'green'
            else:
                state = 'red'

        return state, point
def run(sources_layer_path, receivers_layer_path, emission_pts_layer_path, research_ray):
    sources_layer = QgsVectorLayer(sources_layer_path, "input layer", "ogr")
    receivers_layer = QgsVectorLayer(receivers_layer_path, "output layer", "ogr")

    sources_feat_all = sources_layer.dataProvider().getFeatures()

    receivers_feat_all_dict = {}
    receivers_feat_all = receivers_layer.dataProvider().getFeatures()
    receivers_spIndex = QgsSpatialIndex()
    for receivers_feat in receivers_feat_all:
        receivers_spIndex.insertFeature(receivers_feat)
        receivers_feat_all_dict[receivers_feat.id()] = receivers_feat

    emission_pts_fields = QgsFields()
    emission_pts_fields.append(QgsField("id_emi", QVariant.Int))
    emission_pts_fields.append(QgsField("id_emi_source", QVariant.Int))
    emission_pts_fields.append(QgsField("id_source", QVariant.Int))
    emission_pts_fields.append(QgsField("d_rTOe", QVariant.Double, len=10, prec=2))
    # update for QGIS 3 converting VectorWriter to QgsVectorFileWriter
    # emission_pts_writer = VectorWriter(emission_pts_layer_path, None, emission_pts_fields, 0, sources_layer.crs())

    emission_pts_writer = QgsVectorFileWriter(emission_pts_layer_path, "System",
                                              emission_pts_fields, QgsWkbTypes.Point, sources_layer.crs(),
                                              "ESRI Shapefile")

    # initializes ray and emission point id
    emission_pt_id = 0

    for sources_feat in sources_feat_all:

        # researches the receiver points in a rectangle created by the research_ray
        # creates the search rectangle
        rect = QgsRectangle()
        rect.setXMinimum(sources_feat.geometry().boundingBox().xMinimum() - research_ray)
        rect.setXMaximum(sources_feat.geometry().boundingBox().xMaximum() + research_ray)
        rect.setYMinimum(sources_feat.geometry().boundingBox().yMinimum() - research_ray)
        rect.setYMaximum(sources_feat.geometry().boundingBox().yMaximum() + research_ray)

        receiver_pts_request = receivers_spIndex.intersects(rect)

        distance_min = []
        for receiver_pts_id in receiver_pts_request:
            receiver_pts_feat = receivers_feat_all_dict[receiver_pts_id]
            result = sources_feat.geometry().closestSegmentWithContext(receiver_pts_feat.geometry().asPoint())
            distance_min_tmp = sqrt(result[0])

            if distance_min_tmp <= research_ray:
                distance_min.append(distance_min_tmp)

        # defines segment max length
        if len(distance_min) >= 1:
            segment_max = min(distance_min) / 2
            if segment_max < 2:
                segment_max = 2
        else:
            continue

        # splits the sources line in emission points at a fix distance (minimum distance/2) and create the emission point layer
        # gets vertex
        sources_geom = sources_feat.geometry()
        if sources_geom.isMultipart():
            sources_geom.convertToSingleType()
        sources_feat_vertex_pt_all = sources_geom.asPolyline()

        emission_pt_id_road = 0

        for i in range(0, len(sources_feat_vertex_pt_all)):

            pt1 = QgsPointXY(sources_feat_vertex_pt_all[i])

            add_point_to_layer(emission_pts_writer, pt1,
                               [emission_pt_id, emission_pt_id_road, sources_feat.id(), segment_max])

            emission_pt_id = emission_pt_id + 1
            emission_pt_id_road = emission_pt_id_road + 1

            if i < len(sources_feat_vertex_pt_all) - 1:

                pt2 = QgsPoint(sources_feat_vertex_pt_all[i + 1])

                x1 = pt1.x()
                y1 = pt1.y()
                x2 = pt2.x()
                y2 = pt2.y()

                if y2 == y1:
                    dx = segment_max
                    dy = 0
                    m = 0
                elif x2 == x1:
                    dx = 0
                    dy = segment_max
                else:
                    m = (y2 - y1) / (x2 - x1)
                    dx = sqrt((segment_max ** 2) / (1 + m ** 2))
                    dy = sqrt(((segment_max ** 2) * (m ** 2)) / (1 + m ** 2))

                pt = pt1

                while compute_distance(pt, pt2) > segment_max:
                    x_temp = pt.x()
                    y_temp = pt.y()
                    if x_temp < x2:
                        if m > 0:
                            pt = QgsPointXY(x_temp + dx, y_temp + dy)
                        elif m < 0:
                            pt = QgsPointXY(x_temp + dx, y_temp - dy)
                        elif m == 0:
                            pt = QgsPointXY(x_temp + dx, y_temp)
                    elif x_temp > x2:
                        if m > 0:
                            pt = QgsPointXY(x_temp - dx, y_temp - dy)
                        elif m < 0:
                            pt = QgsPointXY(x_temp - dx, y_temp + dy)
                        elif m == 0:
                            pt = QgsPointXY(x_temp - dx, y_temp)
                    elif x_temp == x2:
                        if y2 > y_temp:
                            pt = QgsPointXY(x_temp, y_temp + dy)
                        else:
                            pt = QgsPointXY(x_temp, y_temp - dy)

                    add_point_to_layer(emission_pts_writer, pt,
                                       [emission_pt_id, emission_pt_id_road, sources_feat.id(), segment_max])

                    emission_pt_id = emission_pt_id + 1
                    emission_pt_id_road = emission_pt_id_road + 1

    del emission_pts_writer
class FreehandRasterGeoreferencerLayer(QgsPluginLayer):

    LAYER_TYPE = "FreehandRasterGeoreferencerLayer"
    transformParametersChanged = pyqtSignal(tuple)

    def __init__(self, plugin, filepath, title, screenExtent):
        QgsPluginLayer.__init__(
            self, FreehandRasterGeoreferencerLayer.LAYER_TYPE, title)
        self.plugin = plugin
        self.iface = plugin.iface

        self.title = title
        self.filepath = filepath
        self.screenExtent = screenExtent
        self.history = []
        # set custom properties
        self.setCustomProperty("title", title)
        self.setCustomProperty("filepath", self.filepath)

        self.setValid(True)

        self.setTransparency(LayerDefaultSettings.TRANSPARENCY)
        self.setBlendModeByName(LayerDefaultSettings.BLEND_MODE)

        # dummy data: real init is done in intializeLayer
        self.center = QgsPointXY(0, 0)
        self.rotation = 0.0
        self.xScale = 1.0
        self.yScale = 1.0

        self.error = False
        self.initializing = False
        self.initialized = False
        self.initializeLayer(screenExtent)
        self._extent = None

        self.provider = FreehandRasterGeoreferencerLayerProvider(self)

    def dataProvider(self):
        # issue with DBManager if the dataProvider of the QgsLayerPlugin
        # returns None
        return self.provider

    def setScale(self, xScale, yScale):
        self.xScale = xScale
        self.yScale = yScale

    def setRotation(self, rotation):
        rotation = round(rotation, 1)
        # keep in -180,180 interval
        if rotation < -180:
            rotation += 360
        if rotation > 180:
            rotation -= 360
        self.rotation = rotation

    def setCenter(self, center):
        self.center = center

    def commitTransformParameters(self):
        QgsProject.instance().setDirty(True)
        self._extent = None
        self.setCustomProperty("xScale", self.xScale)
        self.setCustomProperty("yScale", self.yScale)
        self.setCustomProperty("rotation", self.rotation)
        self.setCustomProperty("xCenter", self.center.x())
        self.setCustomProperty("yCenter", self.center.y())
        self.transformParametersChanged.emit(
            (self.xScale, self.yScale, self.rotation, self.center))

    def reprojectTransformParameters(self, oldCrs, newCrs):
        transform = QgsCoordinateTransform(oldCrs, newCrs,
                                           QgsProject.instance())

        newCenter = transform.transform(self.center)
        newExtent = transform.transform(self.extent())

        # transform the parameters except rotation
        # TODO rotation could be better handled (maybe check rotation between
        # old and new extent)
        # but not really worth the effort ?
        self.setCrs(newCrs)
        self.setCenter(newCenter)
        self.resetScale(newExtent.width(), newExtent.height())

    def resetTransformParametersToNewCrs(self):
        """
        Attempts to keep the layer on the same region of the map when
        the map CRS is changed
        """
        oldCrs = self.crs()
        newCrs = self.iface.mapCanvas().mapSettings().destinationCrs()
        self.reprojectTransformParameters(oldCrs, newCrs)
        self.commitTransformParameters()

    def setupCrsEvents(self):
        layerId = self.id()

        def removeCrsChangeHandler(layerIds):
            if layerId in layerIds:
                try:
                    self.iface.mapCanvas().destinationCrsChanged.disconnect(
                        self.resetTransformParametersToNewCrs)
                except Exception:
                    pass
                try:
                    QgsProject.instance().disconnect(
                        removeCrsChangeHandler)
                except Exception:
                    pass

        self.iface.mapCanvas().destinationCrsChanged.connect(
            self.resetTransformParametersToNewCrs)
        QgsProject.instance().layersRemoved.connect(
            removeCrsChangeHandler)

    def setupCrs(self):
        mapCrs = self.iface.mapCanvas().mapSettings().destinationCrs()
        self.setCrs(mapCrs)

        self.setupCrsEvents()

    def repaint(self):
        self.repaintRequested.emit()

    def transformParameters(self):
        return (self.center, self.rotation, self.xScale, self.yScale)

    def initializeLayer(self, screenExtent=None):
        if self.error or self.initialized or self.initializing:
            return

        if self.filepath is not None:
            # not safe...
            self.initializing = True
            filepath = self.getAbsoluteFilepath()

            if not os.path.exists(filepath):
                # TODO integrate with BadLayerHandler ?
                loadErrorDialog = LoadErrorDialog(filepath)
                result = loadErrorDialog.exec_()
                if result == 1:
                    # absolute
                    filepath = loadErrorDialog.lineEditImagePath.text()
                    # to relative if needed
                    self.filepath = utils.toRelativeToQGS(filepath)
                    self.setCustomProperty("filepath", self.filepath)
                    QgsProject.instance().setDirty(True)
                else:
                    self.error = True

                del loadErrorDialog

            fileInfo = QFileInfo(filepath)
            ext = fileInfo.suffix()
            if ext == "pdf":
                s = QSettings()
                oldValidation = s.value("/Projections/defaultBehavior")
                s.setValue("/Projections/defaultBehavior", "useGlobal") # for not asking about crs
                path = fileInfo.filePath()
                baseName = fileInfo.baseName()
                layer = QgsRasterLayer(path, baseName)
                self.image = layer.previewAsImage(QSize(layer.width(),layer.height()))
                s.setValue("/Projections/defaultBehavior", oldValidation)
            else:
                reader = QImageReader(filepath)
                self.image = reader.read()

            self.initialized = True
            self.initializing = False

            self.setupCrs()

            if screenExtent:
                # constructor called from AddLayer action
                # if not, layer loaded from QGS project file

                # check if image already has georef info
                # use GDAL
                dataset = gdal.Open(filepath, gdal.GA_ReadOnly)
                georef = None
                if dataset:
                    georef = dataset.GetGeoTransform()

                if georef and not self.is_default_geotransform(georef):
                    self.initializeExistingGeoreferencing(dataset, georef)
                else:
                    # init to default params
                    self.setCenter(screenExtent.center())
                    self.setRotation(0.0)

                    sw = screenExtent.width()
                    sh = screenExtent.height()

                    self.resetScale(sw, sh)

                    self.commitTransformParameters()

    def initializeExistingGeoreferencing(self, dataset, georef):
        # georef can have scaling, rotation or translation
        rotation = 180 / math.pi * -math.atan2(georef[4], georef[1])
        sx = math.sqrt(georef[1] ** 2 + georef[4] ** 2)
        sy = math.sqrt(georef[2] ** 2 + georef[5] ** 2)
        i_center_x = self.image.width() / 2
        i_center_y = self.image.height() / 2
        center = QgsPointXY(georef[0] + georef[1] * i_center_x +
                            georef[2] * i_center_y,
                            georef[3] + georef[4] * i_center_x +
                            georef[5] * i_center_y)

        qDebug(repr(rotation) + " " + repr((sx, sy)) + " " +
               repr(center))

        self.setRotation(rotation)
        self.setCenter(center)
        # keep yScale positive
        self.setScale(sx, sy)
        self.commitTransformParameters()

        crs_wkt = dataset.GetProjection()
        message_shown = False
        if crs_wkt:
            qcrs = QgsCoordinateReferenceSystem(crs_wkt)
            if qcrs != self.crs():
                # reproject
                try:
                    self.reprojectTransformParameters(qcrs, self.crs())
                    self.commitTransformParameters()
                    self.showBarMessage(
                        "Transform parameters changed",
                        "Found existing georeferencing in raster but "
                        "its CRS does not match the CRS of the map. "
                        "Reprojected the extent.",
                        Qgis.Warning,
                        5)
                    message_shown = True
                except Exception as ex:
                    QgsMessageLog.logMessage(repr(ex))
                    self.showBarMessage(
                        "CRS does not match",
                        "Found existing georeferencing in raster but "
                        "its CRS does not match the CRS of the map. "
                        "Unable to reproject.",
                        Qgis.Warning,
                        5)
                    message_shown = True
        # if no projection info, assume it is the same CRS
        # as the map and no warning
        if not message_shown:
            self.showBarMessage(
                "Georeferencing loaded",
                "Found existing georeferencing in raster",
                Qgis.Info,
                3)

        # zoom (assume the user wants to work on the image)
        self.iface.mapCanvas().setExtent(self.extent())

    def is_default_geotransform(self, georef):
        """
        Check if there is really a transform or if it is just the default
        made up by GDAL
        """
        return (georef[0] == 0 and georef[3] == 0 and georef[1] == 1 and
                georef[5] == 1)

    def resetScale(self, sw, sh):
        iw = self.image.width()
        ih = self.image.height()
        wratio = sw / iw
        hratio = sh / ih

        if wratio > hratio:
            # takes all height of current extent
            self.setScale(hratio, hratio)
        else:
            # all width
            self.setScale(wratio, wratio)

    def replaceImage(self, filepath, title):
        self.title = title
        self.filepath = filepath

         # set custom properties
        self.setCustomProperty("title", title)
        self.setCustomProperty("filepath", self.filepath)
        self.setName(title)

        fileInfo = QFileInfo(filepath)
        ext = fileInfo.suffix()
        if ext == "pdf":
            s = QSettings()
            oldValidation = s.value("/Projections/defaultBehavior")
            s.setValue("/Projections/defaultBehavior", "useGlobal")  # for not asking about crs
            path = fileInfo.filePath()
            baseName = fileInfo.baseName()
            layer = QgsRasterLayer(path, baseName)
            self.image = layer.previewAsImage(QSize(layer.width(), layer.height()))
            s.setValue("/Projections/defaultBehavior", oldValidation)
        else:
            reader = QImageReader(filepath)
            self.image = reader.read()
        self.repaint()

    def clone(self):
        layer = FreehandRasterGeoreferencerLayer(self.plugin, self.filepath, self.title, self.screenExtent)
        layer.center = self.center
        layer.rotation = self.rotation
        layer.xScale = self.xScale
        layer.yScale = self.yScale
        layer.commitTransformParameters()
        return layer

    def getAbsoluteFilepath(self):
        if not os.path.isabs(self.filepath):
            # relative to QGS file
            qgsPath = QgsProject.instance().fileName()
            qgsFolder, _ = os.path.split(qgsPath)
            filepath = os.path.join(qgsFolder, self.filepath)
        else:
            filepath = self.filepath

        return filepath

    def extent(self):
        self.initializeLayer()
        if not self.initialized:
            qDebug("Not Initialized")
            return QgsRectangle(0, 0, 1, 1)

        if self._extent:
            return self._extent

        topLeft, topRight, bottomRight, bottomLeft = self.cornerCoordinates()

        left = min(topLeft.x(), topRight.x(), bottomRight.x(), bottomLeft.x())
        right = max(topLeft.x(), topRight.x(), bottomRight.x(), bottomLeft.x())
        top = max(topLeft.y(), topRight.y(), bottomRight.y(), bottomLeft.y())
        bottom = min(topLeft.y(), topRight.y(),
                     bottomRight.y(), bottomLeft.y())

        # recenter + create rectangle
        self._extent = QgsRectangle(left, bottom, right, top)
        return self._extent

    def cornerCoordinates(self):
        return self.transformedCornerCoordinates(self.center,
                                                 self.rotation,
                                                 self.xScale,
                                                 self.yScale)

    def transformedCornerCoordinates(self, center, rotation, xScale, yScale):
        # scale
        topLeft = QgsPointXY(-self.image.width() / 2.0 * xScale,
                             self.image.height() / 2.0 * yScale)
        topRight = QgsPointXY(self.image.width() / 2.0 * xScale,
                              self.image.height() / 2.0 * yScale)
        bottomLeft = QgsPointXY(-self.image.width() / 2.0 * xScale,
                                - self.image.height() / 2.0 * yScale)
        bottomRight = QgsPointXY(self.image.width() / 2.0 * xScale,
                                 - self.image.height() / 2.0 * yScale)

        # rotate
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)

        topLeft = self._rotate(topLeft, cosRot, sinRot)
        topRight = self._rotate(topRight, cosRot, sinRot)
        bottomRight = self._rotate(bottomRight, cosRot, sinRot)
        bottomLeft = self._rotate(bottomLeft, cosRot, sinRot)

        topLeft.set(topLeft.x() + center.x(), topLeft.y() + center.y())
        topRight.set(topRight.x() + center.x(), topRight.y() + center.y())
        bottomRight.set(bottomRight.x() + center.x(),
                        bottomRight.y() + center.y())
        bottomLeft.set(bottomLeft.x() + center.x(),
                       bottomLeft.y() + center.y())

        return (topLeft, topRight, bottomRight, bottomLeft)

    def transformedCornerCoordinatesFromPoint(self, startPoint, rotation,
                                              xScale, yScale):
        # startPoint is a fixed point for this new movement (rotation and
        # scale)
        # rotation is the global rotation of the image
        # xScale is the new xScale factor to be multiplied by self.xScale
        # idem for yScale
        # Calculate the coordinate of the center in a startPoint origin
        # coordinate system and apply scales
        dX = (self.center.x() - startPoint.x()) * xScale
        dY = (self.center.y() - startPoint.y()) * yScale
        # Half width and half height in the current transformation
        hW = (self.image.width() / 2.0) * self.xScale * xScale
        hH = (self.image.height() / 2.0) * self.yScale * yScale
        # Actual rectangle coordinates :
        pt1 = QgsPointXY(-hW, hH)
        pt2 = QgsPointXY(hW, hH)
        pt3 = QgsPointXY(hW, -hH)
        pt4 = QgsPointXY(-hW, -hH)
        # Actual rotation from the center
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -self.rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)
        pt1 = self._rotate(pt1, cosRot, sinRot)
        pt2 = self._rotate(pt2, cosRot, sinRot)
        pt3 = self._rotate(pt3, cosRot, sinRot)
        pt4 = self._rotate(pt4, cosRot, sinRot)
        # Second transformation
        # displacement of the origin
        pt1 = QgsPointXY(pt1.x() + dX, pt1.y() + dY)
        pt2 = QgsPointXY(pt2.x() + dX, pt2.y() + dY)
        pt3 = QgsPointXY(pt3.x() + dX, pt3.y() + dY)
        pt4 = QgsPointXY(pt4.x() + dX, pt4.y() + dY)
        # Rotation
        # minus sign because rotation is CW in this class and Qt)
        rotationRad = -rotation * math.pi / 180
        cosRot = math.cos(rotationRad)
        sinRot = math.sin(rotationRad)
        pt1 = self._rotate(pt1, cosRot, sinRot)
        pt2 = self._rotate(pt2, cosRot, sinRot)
        pt3 = self._rotate(pt3, cosRot, sinRot)
        pt4 = self._rotate(pt4, cosRot, sinRot)
        # translate to startPoint
        pt1 = QgsPointXY(pt1.x() + startPoint.x(), pt1.y() + startPoint.y())
        pt2 = QgsPointXY(pt2.x() + startPoint.x(), pt2.y() + startPoint.y())
        pt3 = QgsPointXY(pt3.x() + startPoint.x(), pt3.y() + startPoint.y())
        pt4 = QgsPointXY(pt4.x() + startPoint.x(), pt4.y() + startPoint.y())

        return (pt1, pt2, pt3, pt4)

    def moveCenterFromPointRotate(self, startPoint, rotation, xScale, yScale):
        cornerPoints = self.transformedCornerCoordinatesFromPoint(
            startPoint, rotation, xScale, yScale)
        self.center = QgsPointXY((cornerPoints[0].x(
        ) + cornerPoints[2].x()) / 2, (cornerPoints[0].y() +
                                       cornerPoints[2].y()) / 2)

    def _rotate(self, point, cosRot, sinRot):
        return QgsPointXY(point.x() * cosRot - point.y() * sinRot,
                          point.x() * sinRot + point.y() * cosRot)

    def createMapRenderer(self, rendererContext):
        return FreehandRasterGeoreferencerLayerRenderer(self, rendererContext)

    def setBlendModeByName(self, modeName):
        self.blendModeName = modeName
        blendMode = getattr(QPainter, "CompositionMode_" + modeName, 0)
        self.setBlendMode(blendMode)
        self.setCustomProperty("blendMode", modeName)

    def setTransparency(self, transparency):
        self.transparency = transparency
        self.setCustomProperty("transparency", transparency)

    def draw(self, renderContext):
        if renderContext.extent().isEmpty():
            qDebug("Drawing is skipped because map extent is empty.")
            return True

        self.initializeLayer()
        if not self.initialized:
            qDebug("Drawing is skipped because nothing to draw.")
            return True

        painter = renderContext.painter()
        painter.save()
        self.prepareStyle(painter)
        self.drawRaster(renderContext)
        painter.restore()

        return True

    def drawRaster(self, renderContext):
        painter = renderContext.painter()
        self.map2pixel = renderContext.mapToPixel()

        scaleX = self.xScale / self.map2pixel.mapUnitsPerPixel()
        scaleY = self.yScale / self.map2pixel.mapUnitsPerPixel()

        rect = QRectF(QPointF(-self.image.width() / 2.0,
                              - self.image.height() / 2.0),
                      QPointF(self.image.width() / 2.0,
                              self.image.height() / 2.0))
        mapCenter = self.map2pixel.transform(self.center)

        # draw the image on the map canvas
        painter.translate(QPoint(round(mapCenter.x()), round(mapCenter.y())))
        painter.rotate(self.rotation)
        painter.scale(scaleX, scaleY)
        painter.drawImage(rect, self.image)

        painter.setBrush(Qt.NoBrush)
        painter.setPen(QColor(0, 0, 0))
        painter.drawRect(rect)

    def prepareStyle(self, painter):
        painter.setOpacity(1.0 - self.transparency / 100.0)

    def readXml(self, node, context):
        self.readCustomProperties(node)
        self.title = self.customProperty("title", "")
        self.filepath = self.customProperty("filepath", "")
        self.xScale = float(self.customProperty("xScale", 1.0))
        self.yScale = float(self.customProperty("yScale", 1.0))
        self.rotation = float(self.customProperty("rotation", 0.0))
        xCenter = float(self.customProperty("xCenter", 0.0))
        yCenter = float(self.customProperty("yCenter", 0.0))
        self.center = QgsPointXY(xCenter, yCenter)
        self.setTransparency(int(self.customProperty(
            "transparency", LayerDefaultSettings.TRANSPARENCY)))
        self.setBlendModeByName(self.customProperty(
            "blendMode", LayerDefaultSettings.BLEND_MODE))
        return True

    def writeXml(self, node, doc, context):
        element = node.toElement()
        self.writeCustomProperties(node, doc)
        element.setAttribute("type", "plugin")
        element.setAttribute(
            "name", FreehandRasterGeoreferencerLayer.LAYER_TYPE)
        return True

    def metadata(self):
        lines = []
        fmt = "%s:\t%s"
        lines.append(fmt % (self.tr("Title"), self.title))
        filepath = self.getAbsoluteFilepath()
        filepath = os.path.normpath(filepath)
        lines.append(fmt % (self.tr("Path"), filepath))
        lines.append(fmt % (self.tr("Image Width"), str(self.image.width())))
        lines.append(fmt % (self.tr("Image Height"), str(self.image.height())))
        lines.append(fmt % (self.tr("Rotation (CW)"), str(self.rotation)))
        lines.append(fmt % (self.tr("X center"), str(self.center.x())))
        lines.append(fmt % (self.tr("Y center"), str(self.center.y())))
        lines.append(fmt % (self.tr("X scale"), str(self.xScale)))
        lines.append(fmt % (self.tr("Y scale"), str(self.yScale)))

        return "\n".join(lines)

    def log(self, msg):
        qDebug(msg)

    def dump(self, detail=False, bbox=None):
        pass

    def showStatusMessage(self, msg, timeout):
        self.iface.mainWindow().statusBar().showMessage(msg, timeout)

    def showBarMessage(self, title, text, level, duration):
        self.iface.messageBar().pushMessage(title, text, level, duration)

    def transparencyChanged(self, val):
        QgsProject.instance().setDirty(True)
        self.setTransparency(val)
        self.repaintRequested.emit()