示例#1
0
    def processAlgorithm(self, parameters, context, feedback):
        segments_layer = self.parameterAsLayer(parameters, self.IN_SEGMENTS,
                                               context)

        t = self.parameterAsDouble(parameters, self.THRESHOLD, context)

        index = QgsSpatialIndex()  # Spatial index

        index.addFeatures(segments_layer.getFeatures())

        todel = []
        for ln in segments_layer.getFeatures():
            index.deleteFeature(ln)

            cands = index.intersects(ln.geometry().boundingBox())

            ln1 = ln.geometry()
            for ca in cands:
                totest = segments_layer.getFeature(ca)
                ln2 = totest.geometry()

                are_equal = self.equal_segments(ln1, ln2, t)
                if are_equal:
                    index.deleteFeature(totest)
                    todel.append(ca)

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            segments_layer.fields(
            ),  # QgsFields() for an empty fields list or source_lines.fields()
            QgsWkbTypes.MultiLineString,
            segments_layer.sourceCrs())

        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        for feature in segments_layer.getFeatures():
            if feature.id() not in todel:
                sink.addFeature(feature, QgsFeatureSink.FastInsert)

        return {"OUTPUT": dest_id}
示例#2
0
class GridGeometry:

    """
    Triangular grid geometry
    """

    def __init__(self, extent, x_segments, y_segments, values=None):
        self.extent = extent
        self.x_segments = x_segments
        self.y_segments = y_segments
        self.values = values

        center = extent.center()
        self.width, self.height = (extent.width(), extent.height())
        self.xmin, self.ymin = (center.x() - self.width / 2,
                                center.y() - self.height / 2)
        self.xmax, self.ymax = (center.x() + self.width / 2,
                                center.y() + self.height / 2)
        self.xres = self.width / x_segments
        self.yres = self.height / y_segments

        self.vbands = self.hbands = None

    def setupBands(self):
        xmin, ymin, xmax, ymax = (self.xmin, self.ymin, self.xmax, self.ymax)
        xres, yres = (self.xres, self.yres)

        vrects = []
        hrects = []
        vbands = []
        hbands = []

        for x in range(self.x_segments):
            f = QgsFeature(x)
            r = QgsRectangle(xmin + x * xres, ymin,
                             xmin + (x + 1) * xres, ymax)
            f.setGeometry(QgsGeometry.fromRect(r))
            vrects.append(r)
            vbands.append(f)

        for y in range(self.y_segments):
            f = QgsFeature(y)
            r = QgsRectangle(xmin, ymax - (y + 1) * yres,
                             xmax, ymax - y * yres)
            f.setGeometry(QgsGeometry.fromRect(r))
            hrects.append(r)
            hbands.append(f)

        self.vrects = vrects
        self.hrects = hrects
        self.vbands = vbands
        self.hbands = hbands

        self.vidx = QgsSpatialIndex()
        self.vidx.addFeatures(vbands)

        self.hidx = QgsSpatialIndex()
        self.hidx.addFeatures(hbands)

    def vSplit(self, geom):
        """split polygon vertically"""
        for idx in self.vidx.intersects(geom.boundingBox()):
            geometry = geom.clipped(self.vrects[idx])
            if geometry:
                yield idx, geometry

    def hSplit(self, geom):
        """split polygon horizontally"""
        for idx in self.hidx.intersects(geom.boundingBox()):
            geometry = geom.clipped(self.hrects[idx])
            if geometry:
                yield idx, geometry

    # OBSOLETE
    def hIntersects(self, geom):
        """indices of horizontal bands that intersect with geom"""
        for idx in self.hidx.intersects(geom.boundingBox()):
            if geom.intersects(self.hrects[idx]):
                yield idx

    def splitPolygonXY(self, geom):
        return QgsGeometry.fromMultiPolygonXY(list(self._splitPolygon(geom)))

    def splitPolygon(self, geom):
        z_func = lambda x, y: self.valueOnSurface(x, y) or 0
        cache = FunctionCacheXY(z_func)
        z_func = cache.func

        polygons = QgsMultiPolygon()
        for poly in self._splitPolygon(geom):
            p = QgsPolygon()
            ring = QgsLineString()
            for pt in poly[0]:
                ring.addVertex(QgsPoint(pt.x(), pt.y(), z_func(pt.x(), pt.y())))
            p.setExteriorRing(ring)

            for bnd in poly[1:]:
                ring = QgsLineString()
                for pt in bnd:
                    ring.addVertex(QgsPoint(pt.x(), pt.y(), z_func(pt.x(), pt.y())))
                p.addInteriorRing(ring)
            polygons.addGeometry(p)
        return QgsGeometry(polygons)

    def _splitPolygon(self, geom):
        if self.vbands is None:
            self.setupBands()

        for x, vc in self.vSplit(geom):
            for y, c in self.hSplit(vc):
                if c.isEmpty():
                    continue

                for poly in PolygonGeometry.nestedPointXYList(c):
                    bnds = [[[pt.x(), pt.y()] for pt in bnd] for bnd in poly]
                    data = earcut.flatten(bnds)
                    v = data["vertices"]
                    triangles = earcut.earcut(v, data["holes"], data["dimensions"])
                    vertices = [QgsPointXY(v[2 * i], v[2 * i + 1]) for i in triangles]

                    for i in range(0, len(vertices), 3):
                        yield [vertices[i:i + 3]]

    def segmentizeBoundaries(self, geom):
        """geom: QgsGeometry (polygon or multi-polygon)"""

        xmin, ymax = (self.xmin, self.ymax)
        xres, yres = (self.xres, self.yres)
        z_func = self.valueOnSurface

        polys = []
        for polygon in PolygonGeometry.nestedPointXYList(geom):
            rings = QgsMultiLineString()
            for i, bnd in enumerate(polygon):
                if GeometryUtils.isClockwise(bnd) ^ (i > 0):   # xor
                    bnd.reverse()       # outer boundary should be ccw. inner boundaries should be cw.

                ring = QgsLineString()

                v = bnd[0]     # QgsPointXY
                x0, y0 = (v.x(), v.y())
                nx0 = (x0 - xmin) / xres
                ny0 = (ymax - y0) / yres
                ns0 = abs(ny0 + nx0)

                for v in bnd[1:]:
                    x1, y1 = (v.x(), v.y())
                    nx1 = (x1 - xmin) / xres
                    ny1 = (ymax - y1) / yres
                    ns1 = abs(ny1 + nx1)

                    p = set([0])
                    for v0, v1 in [[nx0, nx1], [ny0, ny1], [ns0, ns1]]:
                        k = ceil(min(v0, v1))
                        n = floor(max(v0, v1))
                        for j in range(k, n + 1):
                            p.add((j - v0) / (v1 - v0))

                    if 1 in p:
                        p.remove(1)

                    for m in sorted(p):
                        x = x0 + (x1 - x0) * m
                        y = y0 + (y1 - y0) * m
                        ring.addVertex(QgsPoint(x, y, z_func(x, y)))

                    x0, y0 = (x1, y1)
                    nx0, ny0, ns0 = (nx1, ny1, ns1)

                ring.addVertex(QgsPoint(x0, y0, z_func(x0, y0)))    # last vertex
                rings.addGeometry(ring)
            polys.append(QgsGeometry(rings))
        return polys

    def value(self, x, y):
        return self.values[x + y * (self.x_segments + 1)]

    def valueOnSurface(self, x, y):
        x = (x - self.xmin) / self.width
        y = (y - self.ymin) / self.height
        if x < 0 or 1 < x or y < 0 or 1 < y:
            return None

        mx = x * self.x_segments
        my = (1 - y) * self.y_segments     # inverted. top is 0.
        mx0 = floor(mx)
        my0 = floor(my)
        sdx = mx - mx0
        sdy = my - my0

        if mx0 == self.x_segments:  # on right edge
            mx0 -= 1
            sdx = 1

        if my0 == self.y_segments:  # on bottom edge
            my0 -= 1
            sdy = 1

        z0, z1 = (self.value(mx0, my0), self.value(mx0 + 1, my0))
        z2, z3 = (self.value(mx0, my0 + 1), self.value(mx0 + 1, my0 + 1))

        if sdx <= sdy:
            return z0 + (z1 - z0) * sdx + (z2 - z0) * sdy
        return z3 + (z2 - z3) * (1 - sdx) + (z1 - z3) * (1 - sdy)
示例#3
0
class PointTool(QgsMapToolEdit):
    '''
    Implementation of interactions of the user with the main map.
    Will called every time the user clicks on the map
    or hovers the mouse over the map.
    '''
    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()

    def __init__(self, canvas, iface, turn_off_snap, smooth=False):
        '''
        canvas - link to the QgsCanvas of the application
        iface - link to the Qgis Interface
        turn_off_snap - flag sets snapping to the nearest color
        smooth - flag sets smoothing of the traced path
        '''

        self.iface = iface

        # list of Anchors for current line
        self.anchors = []

        # for keeping track of mouse event for rubber band updating
        self.last_mouse_event_pos = None

        self.tracing_mode = TracingModes.PATH

        self.turn_off_snap = turn_off_snap
        self.smooth_line = smooth

        # possible variants: gray_diff, as_is, color_diff (using v from hsv)
        self.grid_conversion = "gray_diff"

        # QApplication.restoreOverrideCursor()
        # QApplication.setOverrideCursor(Qt.CrossCursor)
        QgsMapToolEmitPoint.__init__(self, canvas)

        self.rlayer = None
        self.grid_changed = None
        self.snap_tolerance = None  # snap to color
        self.snap2_tolerance = None  # snap to itself
        self.vlayer = None
        self.grid = None
        self.sample = None

        self.tracking_is_active = False

        # False = not a polygon
        self.rubber_band = QgsRubberBand(self.canvas(), False)
        self.markers = []
        self.marker_snap = QgsVertexMarker(self.canvas())
        self.marker_snap.setColor(QColor(255, 0, 255))

        self.find_path_task = None

        self.change_state(WaitingFirstPointState)

        self.last_vlayer = None

    def display_message(
        self,
        title,
        message,
        level='Info',
        duration=2,
    ):
        '''
        Shows message bar to the user.
        `level` receives one of four possible string values:
            Info, Warning, Critical, Success
        '''

        LEVELS = {
            'Info': Qgis.Info,
            'Warning': Qgis.Warning,
            'Critical': Qgis.Critical,
            'Success': Qgis.Success,
        }

        self.iface.messageBar().pushMessage(title, message, LEVELS[level],
                                            duration)

    def change_state(self, state):
        self.state = state(self)

    def snap_tolerance_changed(self, snap_tolerance):
        self.snap_tolerance = snap_tolerance
        if snap_tolerance is None:
            self.marker_snap.hide()
        else:
            self.marker_snap.show()

    def snap2_tolerance_changed(self, snap_tolerance):
        self.snap2_tolerance = snap_tolerance**2
        # if snap_tolerance is None:
        #     self.marker_snap.hide()
        # else:
        #     self.marker_snap.show()

    def trace_color_changed(self, color):
        r, g, b = self.sample

        if color is False:
            self.grid_changed = None
        else:
            r0, g0, b0, t = color.getRgb()
            self.grid_changed = np.abs((r0 - r)**2 + (g0 - g)**2 + (b0 - b)**2)

    def get_current_vector_layer(self):
        try:
            vlayer = self.iface.layerTreeView().selectedLayers()[0]
            if isinstance(vlayer, QgsVectorLayer):
                if vlayer.wkbType() == QgsWkbTypes.MultiLineString:
                    # if self.last_vlayer:
                    #     if vlayer != self.last_vlayer:
                    #         self.create_spatial_index_for_vlayer(vlayer)
                    # else:
                    #     self.create_spatial_index_for_vlayer(vlayer)
                    # self.last_vlayer = vlayer
                    return vlayer
                else:
                    self.display_message(
                        " ",
                        "The active layer must be" +
                        " a MultiLineString vector layer",
                        level='Warning',
                        duration=2,
                    )
                    return None
            else:
                self.display_message(
                    "Missing Layer",
                    "Please select vector layer to draw",
                    level='Warning',
                    duration=2,
                )
                return None
        except IndexError:
            self.display_message(
                "Missing Layer",
                "Please select vector layer to draw",
                level='Warning',
                duration=2,
            )
            return None

    def raster_layer_has_changed(self, raster_layer):
        self.rlayer = raster_layer
        if self.rlayer is None:
            self.display_message(
                "Missing Layer",
                "Please select raster layer to trace",
                level='Warning',
                duration=2,
            )
            return

        try:
            sample, to_indexes, to_coords, to_coords_provider, \
                to_coords_provider2 = \
                get_whole_raster(self.rlayer,
                                 QgsProject.instance(),
                                 )
        except PossiblyIndexedImageError:
            self.display_message(
                "Missing Layer",
                "Can't trace indexed or gray image",
                level='Critical',
                duration=2,
            )
            return

        r = sample[0].astype(float)
        g = sample[1].astype(float)
        b = sample[2].astype(float)
        where_are_NaNs = np.isnan(r)
        r[where_are_NaNs] = 0
        where_are_NaNs = np.isnan(g)
        g[where_are_NaNs] = 0
        where_are_NaNs = np.isnan(b)
        b[where_are_NaNs] = 0

        self.sample = (r, g, b)
        self.grid = r + g + b
        self.to_indexes = to_indexes
        self.to_coords = to_coords
        self.to_coords_provider = to_coords_provider
        self.to_coords_provider2 = to_coords_provider2

    def remove_last_anchor_point(self, undo_edit=True, redraw=True):
        '''
        Removes last anchor point and last marker point
        '''

        # check if we have at least one feature to delete
        vlayer = self.get_current_vector_layer()
        if vlayer is None:
            return
        if vlayer.featureCount() < 1:
            return

        # remove last marker
        if self.markers:
            last_marker = self.markers.pop()
            self.canvas().scene().removeItem(last_marker)

        # remove last anchor
        if self.anchors:
            self.anchors.pop()

        if undo_edit:
            # it's a very ugly way of triggering single undo event
            self.iface.editMenu().actions()[0].trigger()

        if redraw:
            self.update_rubber_band()
            self.redraw()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Backspace or e.key() == Qt.Key_B:
            # delete last segment if backspace is pressed
            self.remove_last_anchor_point()
        elif e.key() == Qt.Key_A:
            # change tracing mode
            self.tracing_mode = self.tracing_mode.next()
            self.update_rubber_band()
        elif e.key() == Qt.Key_S:
            # toggle snap mode
            self.turn_off_snap()
        elif e.key() == Qt.Key_Escape:
            # Abort tracing process
            self.abort_tracing_process()

    def add_anchor_points(self, x1, y1, i1, j1):
        '''
        Adds anchor points and markers to self.
        '''

        anchor = Anchor(x1, y1, i1, j1)
        self.anchors.append(anchor)

        marker = QgsVertexMarker(self.canvas())
        marker.setCenter(QgsPointXY(x1, y1))
        self.markers.append(marker)

    def trace_over_image(self, start, goal, do_it_as_task=False, vlayer=None):
        '''
        performs tracing
        '''

        i0, j0 = start
        i1, j1 = goal

        r, g, b, = self.sample

        try:
            r0 = r[i1, j1]
            g0 = g[i1, j1]
            b0 = b[i1, j1]
        except IndexError:
            raise OutsideMapError

        if self.grid_changed is None:
            grid = np.abs((r0 - r)**2 + (g0 - g)**2 + (b0 - b)**2)
        else:
            grid = self.grid_changed

        if do_it_as_task:
            # dirty hack to avoid QGIS crashing
            self.find_path_task = FindPathTask(
                grid.astype(np.dtype('l')),
                start,
                goal,
                self.draw_path,
                vlayer,
            )

            QgsApplication.taskManager().addTask(self.find_path_task, )
            self.tracking_is_active = True
        else:
            path, cost = FindPathFunction(
                grid.astype(np.dtype('l')),
                (i0, j0),
                (i1, j1),
            )
            return path, cost

    def trace(self, x1, y1, i1, j1, vlayer):
        '''
        Traces path from last point to given point.
        In case tracing is inactive just creates
        straight line.
        '''

        if self.tracing_mode.is_tracing():
            if self.snap_tolerance is not None:
                try:
                    i1, j1 = self.snap(i1, j1)
                except OutsideMapError:
                    return

            _, _, i0, j0 = self.anchors[-2]
            start_point = i0, j0
            end_point = i1, j1
            try:
                self.trace_over_image(start_point,
                                      end_point,
                                      do_it_as_task=True,
                                      vlayer=vlayer)
            except OutsideMapError:
                pass
        else:
            self.draw_path(
                None,
                vlayer,
                was_tracing=False,
                x1=x1,
                y1=y1,
            )

    def snap_to_itself(self, x, y, sq_tolerance=1):
        '''
        finds a nearest segment line to the current vlayer
        '''

        pt = QgsPointXY(x, y)
        # nearest_feature_id = self.spIndex.nearestNeighbor(pt, 1, tolerance)[0]
        vlayer = self.get_current_vector_layer()
        # feature = vlayer.getFeature(nearest_feature_id)
        for feature in vlayer.getFeatures():
            closest_point, _, _, _, sq_distance = feature.geometry(
            ).closestVertex(pt)
            if sq_distance < sq_tolerance:
                return closest_point.x(), closest_point.y()
        return x, y

    def snap(self, i, j):
        if self.snap_tolerance is None:
            return i, j
        if not self.tracing_mode.is_tracing():
            return i, j
        if self.grid_changed is None:
            return i, j

        size_i, size_j = self.grid.shape
        size = self.snap_tolerance

        if i < size or j < size or i + size > size_i or j + size > size_j:
            raise OutsideMapError

        grid_small = self.grid_changed
        grid_small = grid_small[i - size:i + size, j - size:j + size]

        smallest_cells = np.where(grid_small == np.amin(grid_small))
        coordinates = list(zip(smallest_cells[0], smallest_cells[1]))

        if len(coordinates) == 1:
            delta_i, delta_j = coordinates[0]
            delta_i -= size
            delta_j -= size
        else:
            # find the closest to the center
            deltas = [(i - size, j - size) for i, j in coordinates]
            lengths = [(i**2 + j**2) for i, j in deltas]
            i = lengths.index(min(lengths))
            delta_i, delta_j = deltas[i]

        return i + delta_i, j + delta_j

    def canvasReleaseEvent(self, mouseEvent):
        '''
        Method where the actual tracing is performed
        after the user clicked on the map
        '''

        vlayer = self.get_current_vector_layer()

        if vlayer is None:
            return

        if not vlayer.isEditable():
            self.display_message(
                "Edit mode",
                "Please begin editing vector layer to trace",
                level='Warning',
                duration=2,
            )
            return

        if self.rlayer is None:
            self.display_message(
                "Missing Layer",
                "Please select raster layer to trace",
                level='Warning',
                duration=2,
            )
            return

        if mouseEvent.button() == Qt.RightButton:
            self.state.click_rmb(mouseEvent, vlayer)
        elif mouseEvent.button() == Qt.LeftButton:
            self.state.click_lmb(mouseEvent, vlayer)

        return

    def draw_path(self, path, vlayer, was_tracing=True,\
                  x1=None, y1=None):
        '''
        Draws a path after tracer found it.
        '''

        transform = QgsCoordinateTransform(QgsProject.instance().crs(),
                                           vlayer.crs(), QgsProject.instance())
        if was_tracing:
            if self.smooth_line:
                path = smooth(path, size=5)
                path = simplify(path)
            vlayer = self.get_current_vector_layer()
            current_last_point = self.to_coords(*path[-1])
            path_ref = [
                transform.transform(*self.to_coords_provider(i, j))
                for i, j in path
            ]
            x0, y0, _, _ = self.anchors[-2]
            last_point = transform.transform(*self.to_coords_provider2(x0, y0))
            path_ref = [last_point] + path_ref[1:]
        else:
            x0, y0, _i, _j = self.anchors[-2]
            current_last_point = (x1, y1)
            path_ref = [
                transform.transform(*self.to_coords_provider2(x0, y0)),
                transform.transform(*self.to_coords_provider2(x1, y1))
            ]

        self.ready = False
        if len(self.anchors) == 2:
            vlayer.beginEditCommand("Adding new line")
            add_feature_to_vlayer(vlayer, path_ref)
            vlayer.endEditCommand()
        else:
            vlayer.beginEditCommand("Adding new segment to the line")
            add_to_last_feature(vlayer, path_ref)
            vlayer.endEditCommand()
        _, _, current_last_point_i, current_last_point_j = self.anchors[-1]
        self.anchors[-1] = current_last_point[0], current_last_point[
            1], current_last_point_i, current_last_point_j
        self.redraw()
        self.tracking_is_active = False

    def update_rubber_band(self):
        # this is very ugly but I can't make another way
        if self.last_mouse_event_pos is None:
            return

        if not self.anchors:
            return

        x0, y0, _, _ = self.anchors[-1]
        qgsPoint = self.toMapCoordinates(self.last_mouse_event_pos)
        x1, y1 = qgsPoint.x(), qgsPoint.y()
        points = [QgsPoint(x0, y0), QgsPoint(x1, y1)]

        self.rubber_band.setColor(QColor(255, 0, 0))
        self.rubber_band.setWidth(3)

        self.rubber_band.setLineStyle(
            RUBBERBAND_LINE_STYLES[self.tracing_mode], )

        vlayer = self.get_current_vector_layer()
        if vlayer is None:
            return

        self.rubber_band.setToGeometry(
            QgsGeometry.fromPolyline(points),
            self.vlayer,
        )

    def canvasMoveEvent(self, mouseEvent):
        '''
        Store the mouse position for the correct
        updating of the rubber band
        '''

        # we need at least one point to draw
        if not self.anchors:
            return

        if self.snap_tolerance is not None and self.tracing_mode.is_tracing():
            qgsPoint = self.toMapCoordinates(mouseEvent.pos())
            x1, y1 = qgsPoint.x(), qgsPoint.y()
            # i, j = get_indxs_from_raster_coords(self.geo_ref, x1, y1)
            i, j = self.to_indexes(x1, y1)
            try:
                i1, j1 = self.snap(i, j)
            except OutsideMapError:
                return
            # x1, y1 = get_coords_from_raster_indxs(self.geo_ref, i1, j1)
            x1, y1 = self.to_coords(i1, j1)
            self.marker_snap.setCenter(QgsPointXY(x1, y1))

        self.last_mouse_event_pos = mouseEvent.pos()
        self.update_rubber_band()
        self.redraw()

    def abort_tracing_process(self):
        '''
        Terminate background process of tracing raster
        after the user hits Esc.
        '''

        # check if we have any tasks
        if self.find_path_task is None:
            return

        self.tracking_is_active = False

        try:
            # send terminate signal to the task
            self.find_path_task.cancel()
            self.find_path_task = None
        except RuntimeError:
            return
        else:
            self.remove_last_anchor_point(undo_edit=False, )

    def redraw(self):
        # If caching is enabled, a simple canvas refresh might not be
        # sufficient to trigger a redraw and you must clear the cached image
        # for the layer
        if self.iface.mapCanvas().isCachingEnabled():
            vlayer = self.get_current_vector_layer()
            if vlayer is None:
                return
            vlayer.triggerRepaint()

        self.iface.mapCanvas().refresh()
        QgsApplication.processEvents()

    def pan(self, x, y):
        '''
        Move the canvas to the x, y position
        '''
        currExt = self.iface.mapCanvas().extent()
        canvasCenter = currExt.center()
        dx = x - canvasCenter.x()
        dy = y - canvasCenter.y()
        xMin = currExt.xMinimum() + dx
        xMax = currExt.xMaximum() + dx
        yMin = currExt.yMinimum() + dy
        yMax = currExt.yMaximum() + dy
        newRect = QgsRectangle(xMin, yMin, xMax, yMax)
        self.iface.mapCanvas().setExtent(newRect)

    def add_last_feature_to_spindex(self, vlayer):
        '''
        Adds last feature to spatial index
        '''
        features = list(vlayer.getFeatures())
        last_feature = features[-1]
        self.spIndex.insertFeature(last_feature)

    def create_spatial_index_for_vlayer(self, vlayer):
        '''
        Creates spatial index for the vlayer
        '''

        self.spIndex = QgsSpatialIndex()
        # features = [f for f in vlayer]
        self.spIndex.addFeatures(vlayer.getFeatures())
示例#4
0
class Generate:
    # for test purporses
    SHOW_WARNINGS = True

    def __init__(self, iface):
        self.iface = iface
        self.lyr = False  # reference layer to get extent
        self.dir_path = ''  # path to catalog with ref layer

        self.atlas = False  # QgsVectorLayer with atlas
        self.atlasPr = False  # dataProvider
        self.line = False  # QgsVectorLayer with lilne to enumerate panes
        self.linePr = False  # dataProvider

        self.gsize = [0, 0]  # size of pane on the ground withou scale

        self.inter_only = False  # generate only panes that intersect with lyr
        self.si = QgsSpatialIndex()  # spatial index from self.lyr

    def generate(self):
        """Perform all steps and generate layers with atlas"""

        if not self.choose_reference_layer():
            return
        if not self.check_crs_in_meters():
            return

        self.get_data_from_user()
        self.create_atlas_layer()

        self.generate_panes()
        self.save_layers()

    def check_crs_in_meters(self):
        """check if layer source crs is in meters, other way it atlas will
        be generated incorectly"""

        if self.lyr.sourceCrs().mapUnits() != 0:
            self.show_warning(
                'Layer crs map unit is diffret from meters, Aborting')
            return False
        return True

    def get_data_from_user(self):
        """Show dialog to user what size of atlas should be generated"""

        self.dlg = Dialog()
        self.dlg.exec_()

        # get calculated size on ground from dialog
        self.gsize = self.dlg.ground_size
        self.inter_only = self.dlg.ui.checkBox_inter.isChecked()

    def choose_reference_layer(self, lyr=False):
        """ Point to reference layer to get it boundingBox, it should be
        currently selected layer
        there is an option to point to layer - testing
        """

        if lyr is False:
            self.lyr = self.iface.activeLayer()
        else:
            self.lyr = lyr

        if self.lyr in [False, None]:
            self.show_warning('No suitable layer!')
            self.lyr = False
            return False

        # check if layer is valid
        if not self.lyr.isValid():
            self.show_warning('Not valid layer, choose another!')
            self.lyr = False
            return False

        try:
            self.dir_path = os.path.dirname(
                self.lyr.dataProvider().dataSourceUri().split("|")[0])
        except Exception:
            return False

        return True

    def create_atlas_layer(self):
        """Creates atlas layer and save it do disk in catalog with referenced
        layer

        """
        if self.lyr is False:
            return False

        # check what kind of crs is defined in layer
        crs = self.lyr.sourceCrs().authid()
        if 'EPSG:' not in crs:
            crs_txt = ''
        else:
            crs_txt = 'crs=' + crs + '&'

        self.atlas = QgsVectorLayer("Polygon?" + crs_txt + "index=yes",
                                    "ATLAS_AFT", "memory")
        self.atlasPr = self.atlas.dataProvider()
        self.atlas.startEditing()
        self.atlasPr.addAttributes([
            QgsField("SITE", QVariant.Int),
            QgsField("Left", QVariant.Int),
            QgsField("Up", QVariant.Int),
            QgsField("Right", QVariant.Int),
            QgsField("Down", QVariant.Int),
            QgsField("ISSUES", QVariant.String, len=50),
        ])
        self.atlas.updateFields()
        self.atlas.commitChanges()

        # Generate line vector layer to easy show order and calculate order
        # from vertex of Line
        self.line = QgsVectorLayer("LineString?" + crs_txt + "&index=yes",
                                   "LineAtlas", "memory")
        self.linePr = self.line.dataProvider()

    def generate_si(self):
        """Generate Spatial index from original layer"""
        if self.lyr.geometryType() in [
                QgsWkbTypes.Polygon, QgsWkbTypes.PolygonGeometry,
                QgsWkbTypes.MultiPolygon
        ]:
            self.si.addFeatures(self.lyr.getFeatures())
        else:
            # if geometry type other than poly, omit spatial index
            self.inter_only = False

    def generate_panes(self):
        """Generate panes of atlas to cover all extent of reference layer
        if layer is Polygon or Multipolygon type it is option to generate
        panes only there panes overlap with references
        """

        # pobierz rozmiary warstwy którą będziemy atlasować
        xmin = self.lyr.extent().xMinimum()
        xmax = self.lyr.extent().xMaximum()
        ymin = self.lyr.extent().yMinimum()
        ymax = self.lyr.extent().yMaximum()

        # generate SpatialIndex only if checkbox in checked and reference layer
        # is at certain type (poly, multipoly)
        if self.inter_only:
            self.generate_si()

        x = xmin
        y = ymin
        panes_poly = []
        ita = 0  # no more than 999 tile in any direction!!!

        while x < xmax and ita < 999:
            while y < ymax and ita < 999:
                f = self.generate_pane(x, y)
                if f is not False:
                    panes_poly.append(f)
                y += self.gsize[1]
                ita += 1

            x += self.gsize[0]
            ita += 1
            y = ymin

        self.atlas.startEditing()
        self.atlas.addFeatures(panes_poly)
        self.atlas.commitChanges()

    def generate_pane(self, x, y):
        """generate one pane of atlas in given x,y position
            if spatialindex is added there will be returning False if pane
            not intersect with SI
        """
        poly = [
            QgsPointXY(x, y),
            QgsPointXY(x, y + self.gsize[1]),
            QgsPointXY(x + self.gsize[0], y + self.gsize[1]),
            QgsPointXY(x + self.gsize[0], y),
            QgsPointXY(x, y),
        ]
        g = QgsGeometry().fromPolygonXY([poly])

        # if SpatialIndex not intersects with generated geometry, return False
        if self.inter_only:
            if len(self.si.intersects(g.boundingBox())) == 0:
                return False

        f = QgsFeature()
        f.setFields(self.atlas.fields())
        f.setGeometry(g)
        return f

    def save_layers(self):
        """Save atlas layer to disk, and add atlas and line vector layer to
        TOC
        """
        crs = self.lyr.sourceCrs()

        QgsVectorFileWriter.writeAsVectorFormat(
            self.atlas,
            os.path.join(os.path.join(self.dir_path, "ATLAS_AFT.shp")),
            "UTF-8", crs, "ESRI Shapefile")

        self.atlasF = QgsVectorLayer(
            os.path.join(self.dir_path, "ATLAS_AFT.shp"), "ATLAS_AFT", "ogr")

        QgsProject.instance().addMapLayer(self.atlasF)
        QgsProject.instance().addMapLayer(self.line)

        plugin_dir = os.path.dirname(__file__)
        self.atlasF.loadNamedStyle(
            os.path.join(plugin_dir, '..', 'qml', 'ATLAS_AFT_check.qml'))
        self.line.loadNamedStyle(
            os.path.join(plugin_dir, '..', 'qml', 'ATLAS_LINE.qml'))

        self.show_success()

    def show_success(self):
        # show confirmation to user on message bar
        if not self.SHOW_WARNINGS:
            return

        self.iface.messageBar().pushMessage("OK",
                                            'Atlas Panes generated correctly',
                                            Qgis.Success, 5)

    def show_warning(self, text):
        """Show warning to user if something is wrong"""
        if not self.SHOW_WARNINGS:
            return

        message = QMessageBox()
        message.setIcon(QMessageBox.Information)
        message.setWindowTitle('Błąd')
        message.setText(text)
        message.addButton("Close", QMessageBox.ActionRole)
        message.exec_()