• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nens / ThreeDiToolbox / #2589

19 Sep 2025 08:50AM UTC coverage: 35.01% (-0.1%) from 35.146%
#2589

push

coveralls-python

web-flow
Merge 38792c162 into f6f4be1e7

62 of 260 new or added lines in 40 files covered. (23.85%)

6 existing lines in 5 files now uncovered.

4859 of 13879 relevant lines covered (35.01%)

0.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.22
/tool_sideview/sideview_visualisation.py
1
from qgis.gui import QgsRubberBand, QgsVertexMarker
1✔
2
from threedi_results_analysis.tool_sideview.route import Route
1✔
3
from qgis.core import QgsDistanceArea, QgsProject, QgsCoordinateTransform, QgsWkbTypes, QgsPointXY
1✔
4
from qgis.PyQt.QtCore import Qt
1✔
5

6
import logging
1✔
7
logger = logging.getLogger(__name__)
1✔
8

9

10
class SideViewMapVisualisation(object):
1✔
11
    """
12
    Class managing the rubber band and vertex marker indicating the route of the
13
    sideview.
14
    """
15

16
    def __init__(self, iface, graph_layer_crs):
1✔
17
        self.iface = iface
×
18

19
        self.graph_layer_crs = graph_layer_crs
×
20

NEW
21
        self.rb = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.GeometryType.LineGeometry)
×
NEW
22
        self.rb.setColor(Qt.GlobalColor.red)
×
UNCOV
23
        self.rb.setWidth(2)
×
24

25
        self.point_markers = []
×
26
        self.active_route = None
×
27
        self.last_path = None
×
28

29
        self.hover_marker = QgsVertexMarker(self.iface.mapCanvas())
×
NEW
30
        self.hover_marker.setIconType(QgsVertexMarker.IconType.ICON_X)
×
NEW
31
        self.hover_marker.setColor(Qt.GlobalColor.red)
×
UNCOV
32
        self.hover_marker.setPenWidth(6)
×
33

34
        self.dist_calc = QgsDistanceArea()
×
35

36
    def close(self):
1✔
37
        self.reset()
×
38
        self.iface.mapCanvas().scene().removeItem(self.hover_marker)
×
39

40
    def set_sideview_route(self, route):
1✔
41

42
        self.reset()
×
43

44
        self.active_route = route
×
45
        transform = QgsCoordinateTransform(
×
46
            self.graph_layer_crs, QgsProject.instance().crs(), QgsProject.instance()
47
        )
48

49
        self.last_path = route.path.copy()
×
50

51
        for pnt in route.path_vertexes:
×
52
            t_pnt = transform.transform(pnt)
×
53
            self.rb.addPoint(t_pnt)
×
54

55
        for point, point_id, dist in route.path_points:
×
56

57
            marker = QgsVertexMarker(self.iface.mapCanvas())
×
NEW
58
            marker.setIconType(QgsVertexMarker.IconType.ICON_CIRCLE)
×
NEW
59
            marker.setColor(Qt.GlobalColor.red)
×
60
            marker.setPenWidth(4)
×
61
            marker.setCenter(transform.transform(point))
×
62
            self.point_markers.append(marker)
×
63

64
    def reset(self):
1✔
65
        self.rb.reset()
×
66
        self.active_route = None
×
67
        self.last_path = None
×
68

69
        for marker in self.point_markers:
×
70
            self.iface.mapCanvas().scene().removeItem(marker)
×
71

72
        self.point_markers = []
×
73

74
        self.hover_marker.setCenter(QgsPointXY(0.0, 0.0))
×
75

76
    def hover_graph(self, meters_from_start):  # meters_from_start is mouse_x
1✔
77

78
        if self.active_route is None:
×
79
            return
×
80

81
        transform = QgsCoordinateTransform(
×
82
            self.graph_layer_crs, QgsProject.instance().crs(), QgsProject.instance()
83
        )
84

85
        # Clamp meters_from_start to route endpoints
86
        if meters_from_start < 0.0:
×
87
            meters_from_start = 0.0
×
88
        elif (len(self.active_route.path) > 0 and meters_from_start > self.active_route.path[-1][-1][1]):
×
89
            meters_from_start = self.active_route.path[-1][-1][1]
×
90

91
        path = self.active_route.path if len(self.active_route.path) > 0 else self.last_path
×
92
        if not path:
×
93
            return
×
94

95
        for route_part in path:
×
96
            if meters_from_start <= route_part[-1][1]:
×
97
                for (begin_dist, end_dist, direction, feature) in Route.aggregate_route_parts(route_part):
×
98
                    if meters_from_start <= end_dist:
×
99

100
                        if direction == 1:
×
101
                            distance_on_line = meters_from_start - begin_dist
×
102
                        else:
103
                            distance_on_line = end_dist - meters_from_start
×
104

105
                        conversion_factor = 1
×
106
                        if self.graph_layer_crs.isGeographic():
×
107
                            raise Exception("Unsupported")
×
108

109
                        length = distance_on_line * conversion_factor
×
110

111
                        # Note that interpolate() uses absolute length (instead of normalized weight)
112
                        point = feature.geometry().interpolate(length)
×
113
                        if point.isEmpty():
×
114
                            # Because interpolation seems to happen cartesian, the ellipsoid length (used by GraphBuilder) can
115
                            # exceed the cartesian length, yielding an empty point at the end
116
                            return
×
117

118
                        self.hover_marker.setCenter(transform.transform(point.asPoint()))
×
119
                        return
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc