Exemplo n.º 1
0
class SedimentalLayerModel(QtCore.QAbstractListModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.file = None

    def setLayer(self, layer):
        self.beginResetModel()
        self.file = PreCourlisFileLine(layer)
        self.endResetModel()

    def rowCount(self, parent=QtCore.QModelIndex()):
        if self.file is None:
            return 0
        if self.file.layer() is None:
            return 0
        return len(self.file.layers()) + 1

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            if index.row() == 0:
                if index.column() == 0:
                    return "zfond"
            layers = self.file.layers()
            if index.row() - 1 < len(layers):
                layer = self.file.layers()[index.row() - 1]
                if index.column() == 0:
                    return layer
Exemplo n.º 2
0
 def test_interpolate_lines_multiple_layers(self):
     layer = QgsVectorLayer(PROFILE_LINES_PATH, "multiple_layers", "ogr")
     file = PreCourlisFileLine(layer)
     file.add_sedimental_layer("Layer2", "Layer1", -1.0)
     self.check_algorithm(
         {"SECTIONS": layer},
         {"OUTPUT": "interpolate_lines_multiple_layers.gml"},
     )
Exemplo n.º 3
0
 def set_sections(
     self, layer, feature, previous_section, current_section, next_section
 ):
     self.position = None
     self.file = PreCourlisFileLine(layer)
     self.feature = feature
     self.previous_section = previous_section
     self.current_section = current_section
     self.next_section = next_section
     self.refresh()
Exemplo n.º 4
0
    def processAlgorithm(self, parameters, context, feedback):
        input_layer = self.parameterAsVectorLayer(parameters, self.INPUT,
                                                  context)
        reach_name = (self.parameterAsString(parameters, self.REACH_NAME,
                                             context) or input_layer.name())
        output_path = self.parameterAsString(parameters, self.OUTPUT, context)

        precourlis_file = PreCourlisFileLine(input_layer)
        reach = precourlis_file.get_reach(reach_name)

        output_file = MascaretGeoFile(output_path, mode="write")
        output_file.has_ref = "ref" in os.path.splitext(output_path)[1][1:]
        output_file.add_reach(reach)
        output_file.save(output_path)

        return {self.OUTPUT: output_path}
Exemplo n.º 5
0
    def processAlgorithm(self, parameters, context, feedback):
        input_path = self.parameterAsString(parameters, self.INPUT, context)
        crs = self.parameterAsCrs(parameters, self.CRS, context)

        file = MascaretGeoFile(input_path)

        fields = PreCourlisFileLine.base_fields()

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            fields,
            QgsWkbTypes.LineString,
            crs,
        )
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        # Compute the number of steps to display within the progress bar and
        count = sum([len(r.sections) for r in file.reaches.values()])
        total = 100.0 / count if count else 0

        current = 0
        for reach in file.reaches.values():
            for section in reach.sections.values():
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    break

                feature = PreCourlisFileLine.feature_from_section(
                    section, fields)

                # Add a feature in the sink
                sink.addFeature(feature, QgsFeatureSink.FastInsert)

                # Update the progress bar
                feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Exemplo n.º 6
0
    def prepare_sections(self, parameters, context, feedback):
        sections = self.parameterAsSource(parameters, self.SECTIONS, context)

        # Prefix layer fields by "Z" for TatooineMesher
        file = PreCourlisFileLine(sections)
        alg_params = {
            "INPUT":
            parameters[self.SECTIONS],
            "FIELDS_MAPPING": [
                {
                    "name": "sec_id",
                    "type": QVariant.Int,
                    "expression": '"sec_id"'
                },
                {
                    "name": "p_id",
                    "type": QVariant.Int,
                    "expression": '"p_id"'
                },
                {
                    "name": "Zzfond",
                    "type": QVariant.Double,
                    "expression": '"zfond"'
                },
            ] + [{
                "name": "Z{}".format(layer),
                "type": QVariant.Double,
                "expression": '"{}"'.format(layer),
            } for layer in file.layers()],
            "OUTPUT":
            QgsProcessingUtils.generateTempFilename("tatooine_input.shp"),
        }
        outputs = processing.run(
            "qgis:refactorfields",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )
        return outputs["OUTPUT"]
Exemplo n.º 7
0
    def line_feature_from_points(self, point_features, sec_id, abs_long):
        points = [
            point_feature.geometry().constGet().clone()
            for point_feature in point_features
        ]
        line = QgsGeometry(QgsLineString(points))

        intersection_point = None
        if self.axis:
            intersection = line.intersection(self.axis.geometry())
            # Take only the first parts (QgsMultiPoint => QgsPoint)
            intersection_point = next(intersection.constParts()).clone()

        layers = PreCourlisFileLine(None).layers(point_features[0])

        line_feature = QgsFeature()
        line_feature.setAttributes([
            # sec_id
            point_features[0].attribute("sec_id") or sec_id,
            # sec_name
            point_features[0].attribute("sec_name")
            or "{}_{:04.3f}".format("P" if abs_long >= 0 else "N", abs_long),
            # abs_long
            abs_long,
            # axis_x
            intersection_point.x(
            ) if self.axis else point_features[0].attribute("axis_x"),
            # axis_y
            intersection_point.y(
            ) if self.axis else point_features[0].attribute("axis_y"),
            # layers
            point_features[0].attribute("layers") or "",
            # p_id
            ",".join([str(id_ + 1) for id_ in range(0, len(points))]),
            # topo_bat
            ",".join([f.attribute("topo_bat") for f in point_features]),
            # abs_lat
            ",".join([
                str(line.lineLocatePoint(f.geometry())) for f in point_features
            ]),
            # zfond
            ",".join([
                str(self.to_float(f.attribute("zfond")))
                for f in point_features
            ]),
        ] + [
            ",".join([
                str(self.to_float(f.attribute(layer))) for f in point_features
            ]) for layer in layers
        ])
        line_feature.setGeometry(line)
        return line_feature
    def processAlgorithm(self, parameters, context, feedback):
        input_layer = self.parameterAsVectorLayer(parameters, self.INPUT,
                                                  context)
        reach_name = (self.parameterAsString(parameters, self.REACH_NAME,
                                             context) or input_layer.name())
        output_path = self.parameterAsString(parameters, self.OUTPUT, context)

        # Processing GUI does not correctly handle uppercase characters in file extensions before
        # QGIS 3.14
        if Qgis.QGIS_VERSION_INT < 31400:
            output_path = output_path.replace(".georefc", ".georefC")
            output_path = output_path.replace(".geoc", ".geoC")

        precourlis_file = PreCourlisFileLine(input_layer)
        reach = precourlis_file.get_reach(reach_name)

        output_file = MascaretGeoFile(output_path, mode="write")
        output_file.has_ref = "ref" in os.path.splitext(output_path)[1][1:]
        output_file.add_reach(reach)
        output_file.nlayers = len(precourlis_file.layers())
        output_file.save(output_path)

        return {self.OUTPUT: output_path}
Exemplo n.º 9
0
    def create_widget(self):
        request = QgsFeatureRequest()
        request.setLimit(1)
        feature = next(self.layer.getFeatures(request))

        section = PreCourlisFileLine(self.layer).section_from_feature(feature)
        section.feature = feature

        widget = GraphWidget(None)

        model = PointsTableModel(widget)
        model.set_section(section)
        sel_model = QtCore.QItemSelectionModel(model, widget)
        widget.set_selection_model(sel_model)

        widget.set_sections(
            layer=self.layer,
            feature=feature,
            previous_section=None,
            current_section=section,
            next_section=None,
        )
        return widget
Exemplo n.º 10
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.TRACKS, context)
        axis = self.parameterAsSource(parameters, self.AXIS, context)
        self.name_field = self.parameterAsString(parameters, self.NAME_FIELD, context)
        self.axis = next(axis.getFeatures())
        self.name_field_index = source.fields().indexFromName(self.name_field)

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            PreCourlisFileLine.base_fields(),
            QgsWkbTypes.LineString,
            source.sourceCrs(),
        )
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        features = source.getFeatures()

        for current, feature in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            intersection = feature.geometry().intersection(self.axis.geometry())
            assert not intersection.isNull()

            abs_long = self.axis.geometry().lineLocatePoint(intersection)

            # Take only the first parts (QgsMultiLineString => QgsLineString)
            axis_line = next(self.axis.geometry().constParts()).clone()
            track_line = next(feature.geometry().constParts()).clone()

            intersection_point = intersection.constGet()
            track_angle = qgslinestring_angle(track_line, intersection_point) * (
                180 / math.pi
            )
            axis_angle = qgslinestring_angle(axis_line, intersection_point) * (
                180 / math.pi
            )
            d_angle = (track_angle - axis_angle) % 360

            out = QgsFeature()
            out.setAttributes(
                [
                    # sec_id
                    None,
                    # sec_name
                    feature.attribute(self.name_field_index)
                    if self.name_field
                    else None,
                    # abs_long
                    abs_long,
                    # axis_x
                    intersection_point.x(),
                    # axis_y
                    intersection_point.y(),
                    # layers
                    "",
                    # p_id
                    QVariant(),
                    # topo_bat
                    "B",
                    # abs_lat
                    QVariant(),
                    # zfond
                    QVariant(),
                ]
            )
            if d_angle < 180:
                out.setGeometry(QgsGeometry(track_line.reversed()))
            else:
                out.setGeometry(QgsGeometry(feature.geometry()))

            # Add a feature in the sink
            sink.addFeature(out, QgsFeatureSink.FastInsert)

            # Update the progress bar
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Exemplo n.º 11
0
class GraphWidget(FigureCanvas):

    editing_finished = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        self.figure = plt.figure(figsize=(15, 7), constrained_layout=True)
        super().__init__(self.figure)

        self.graph = plt.subplot(111)

        self.selection_tool = SelectionTool(self, self.graph)
        self.selection_tool.activate()

        self.zoom_tool = ZoomTool(self, self.graph)
        self.zoom_tool.activate()

        self.file = None
        self.feature = None
        self.previous_section = None
        self.current_section = None
        self.next_section = None

        self.position = None
        self.pointing_line = None
        self.layers_lines = []
        self.layers_fills = []
        self.legend = None
        self.current_layer_name = None

    def close_figure(self):
        plt.close(self.figure)

    def set_selection_model(self, model):
        self.selection_tool.set_selection_model(model)

    def set_sections(
        self, layer, feature, previous_section, current_section, next_section
    ):
        self.position = None
        self.file = PreCourlisFileLine(layer)
        self.feature = feature
        self.previous_section = previous_section
        self.current_section = current_section
        self.next_section = next_section
        self.refresh()

    def set_current_layer(self, layer_name):
        self.current_layer_name = layer_name
        self.refresh_current_section()
        self.refresh_legend()
        self.draw()

    def axis_position(self, section):
        """
        Return linear referencing of axis intersection for passed section.
        """
        f = section.feature
        intersection = QgsGeometry(
            QgsPoint(f.attribute("axis_x"), f.attribute("axis_y"))
        )
        return f.geometry().lineLocatePoint(intersection)

    def draw_section(self, section, offset, **kwargs):
        if section.distances[0] is None:
            return
        return self.graph.plot(
            [d + offset for d in section.distances],
            section.z,
            label=section.name,
            **kwargs,
        )

    def clear(self):
        self.graph.clear()
        self.pointing_line = None
        self.layers_lines = []
        self.layers_fills = []
        self._legend = None

    def refresh(self):
        self.clear()

        axis_pos = self.axis_position(self.current_section)

        if self.previous_section:
            self.draw_section(
                self.previous_section,
                axis_pos - self.axis_position(self.previous_section),
                color="green",
                linewidth=0.5,
            )

        self.refresh_current_section(False)

        if self.next_section:
            self.draw_section(
                self.next_section,
                axis_pos - self.axis_position(self.next_section),
                color="blue",
                linewidth=0.5,
            )

        # Draw axis position
        self.graph.axvline(axis_pos, color="black")

        self.graph.grid(True)
        self.graph.set_ylabel("Z (m)")
        self.graph.set_xlabel("Abscisse en travers (m)")

        self.refresh_legend()

        self.draw()

    def refresh_legend(self):
        if self.legend is not None:
            self.legend.remove()
        lines, labels = self.graph.get_legend_handles_labels()
        self.legend = self.graph.legend(
            lines,
            labels,
            bbox_to_anchor=(1, 0.5),
            loc="center left",
            fancybox=True,
            shadow=True,
            prop={"size": 10},
        )

    def refresh_current_section(self, draw=True):
        [line.remove() for line in self.layers_lines]
        self.layers_lines = []

        [poly.remove() for poly in self.layers_fills]
        self.layers_fills = []

        section = self.current_section
        if section is None:
            return
        if section.distances[0] is None:
            return

        previous_values = None
        current_column = None
        for i, layer in enumerate(["zfond"] + section.layer_names):
            if layer == "zfond":
                values = self.current_section.z
            else:
                values = section.layers_elev[i - 1]

            color = self.file.layer_color(layer)

            if previous_values is not None:
                self.layers_fills.append(
                    self.graph.fill_between(
                        section.distances,
                        previous_values,
                        values,
                        where=values <= previous_values,
                        facecolor=color,
                        alpha=0.3,
                    )
                )
            previous_values = values

            (line,) = self.graph.plot(
                section.distances,
                values,
                label=layer,
                color=color,
                marker="." if self.current_layer_name == layer else None,
                zorder=10 if self.current_layer_name == layer else 1,
            )
            self.layers_lines.append(line)

            if self.current_layer_name == layer:
                current_column = i + 1

        self.selection_tool.set_data(
            section.distances,
            [section.z] + list(section.layers_elev),
            current_column,
        )

        if draw:
            self.draw()
Exemplo n.º 12
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)

        fields = PreCourlisFilePoint.base_fields()

        file = PreCourlisFileLine(source)
        layers = file.layers()
        for layer in layers:
            fields.append(QgsField(layer, QVariant.Double))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            fields,
            QgsWkbTypes.PointZ,
            source.sourceCrs(),
        )
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        features = source.getFeatures()
        for current, line_feature in enumerate(features):

            # Take only the first parts (QgsMultiLineString => QgsLineString)
            line = next(line_feature.geometry().constParts()).clone()
            line_layers_values = [
                line_feature.attribute(layer).split(",") for layer in layers
            ]

            for point, p_id, topo_bat, abs_lat, zfond, point_layers_values, in zip(
                    line.points(),
                    line_feature.attribute("p_id").split(","),
                    line_feature.attribute("topo_bat").split(","),
                    line_feature.attribute("abs_lat").split(","),
                    line_feature.attribute("zfond").split(","),
                    list(zip(*line_layers_values)) or [[]] * line.numPoints(),
            ):
                point_feature = QgsFeature()
                point_feature.setAttributes([
                    line_feature.attribute("sec_id"),
                    line_feature.attribute("sec_name"),
                    line_feature.attribute("abs_long"),
                    line_feature.attribute("axis_x"),
                    line_feature.attribute("axis_y"),
                    line_feature.attribute("layers"),
                    int(p_id),
                    topo_bat,
                    self.to_float(abs_lat),
                    self.to_float(point.x()),
                    self.to_float(point.y()),
                    self.to_float(zfond),
                ] + [self.to_float(v) for v in point_layers_values])
                point_feature.setGeometry(
                    QgsGeometry(QgsPoint(point.x(), point.y(), 0.0)))
                sink.addFeature(point_feature, QgsFeatureSink.FastInsert)

            # Update the progress bar
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Exemplo n.º 13
0
 def create_file(self):
     layer = QgsVectorLayer(PROFILE_LINES_PATH, "profiles", "ogr")
     assert layer.isValid()
     return PreCourlisFileLine(layer)
Exemplo n.º 14
0
 def setLayer(self, layer):
     self.beginResetModel()
     self.file = PreCourlisFileLine(layer)
     self.endResetModel()
Exemplo n.º 15
0
 def section(self):
     request = QgsFeatureRequest()
     request.setLimit(1)
     feature = next(self.layer.getFeatures(request))
     return PreCourlisFileLine(self.layer).section_from_feature(feature)
Exemplo n.º 16
0
processing.run(
    "precourlis:import_tracks",
    {
        "TRACKS": TRACKS_PATH,
        "AXIS": AXIS_PATH,
        "FIRST_POS": 0.0,
        "NAME_FIELD": "nom_profil",
        "DISTANCE": 100.0,
        "DEM": DEM_PATH,
        "OUTPUT": PROFILE_LINES_PATH,
    },
)
layer = QgsVectorLayer(PROFILE_LINES_PATH, "profile_lines", "ogr")
assert layer.isValid()

copyfile(
    PROFILE_LINES_PATH,
    os.path.join(DATA_PATH, "input", "profiles_lines_zero_layers.geojson"))

layer.startEditing()
PreCourlisFileLine(layer).add_sedimental_layer("Layer1", "zfond", -1)
layer.commitChanges()

processing.run(
    "precourlis:lines_to_points",
    {
        "INPUT": PROFILE_LINES_PATH,
        "OUTPUT": PROFILE_POINTS_PATH,
    },
)
Exemplo n.º 17
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        axis = self.parameterAsSource(parameters, self.AXIS, context)
        self.first_section_abs_long = self.parameterAsDouble(
            parameters, self.FIRST_SECTION_ABS_LONG, context)
        if parameters.get(self.FIRST_AXIS_POINT_ABS_LONG, None) is None:
            self.first_axis_point_abs_long = None
        else:
            self.first_axis_point_abs_long = self.parameterAsDouble(
                parameters, self.FIRST_AXIS_POINT_ABS_LONG, context)
        group_field = self.parameterAsString(parameters, self.GROUP_FIELD,
                                             context)
        order_field = self.parameterAsString(parameters, self.ORDER_FIELD,
                                             context)

        self.axis = next(axis.getFeatures()) if axis else None

        request = QgsFeatureRequest()
        request.addOrderBy('"{}"'.format(group_field), True, True)

        file = PreCourlisFileLine(source)
        fields = PreCourlisFileLine.base_fields()
        for layer in file.layers():
            fields.append(QgsField(layer, QVariant.String, len=100000))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            fields,
            QgsWkbTypes.LineString,
            source.sourceCrs(),
        )
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        features = source.getFeatures(request)

        group = None
        point_features = []
        sec_id = 0
        abs_long_offset = 0
        for current, point_feature in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            if current == 0:
                if self.first_axis_point_abs_long is not None:
                    abs_long_offset = self.first_axis_point_abs_long
                else:
                    abs_long_offset = (self.first_section_abs_long -
                                       point_feature.attribute("abs_long"))

            if group is not None and point_feature.attribute(
                    group_field) != group:
                sec_id += 1
                sink.addFeature(
                    self.line_feature_from_points(
                        sorted(point_features,
                               key=lambda f: f.attribute(order_field)),
                        sec_id,
                        point_features[0].attribute("abs_long") +
                        abs_long_offset,
                    ),
                    QgsFeatureSink.FastInsert,
                )
                group = None
                point_features = []

            group = point_feature.attribute(group_field)
            point_features.append(point_feature)

            # Update the progress bar
            feedback.setProgress(int(current * total))

        if group is not None:
            sec_id += 1
            sink.addFeature(
                self.line_feature_from_points(
                    sorted(point_features,
                           key=lambda f: f.attribute(order_field)),
                    sec_id,
                    point_features[0].attribute("abs_long") + abs_long_offset,
                ),
                QgsFeatureSink.FastInsert,
            )
            group = None

        return {self.OUTPUT: dest_id}