|
9 | 9 | from scipy.interpolate import griddata, LinearNDInterpolator |
10 | 10 | from scipy.ndimage import gaussian_filter |
11 | 11 | from scipy.spatial import Delaunay |
12 | | -from scipy.spatial.distance import cdist |
13 | | -from typing import List, Tuple, Dict, Optional, Union |
| 12 | +from typing import List, Tuple, Optional |
14 | 13 |
|
15 | 14 | import math |
16 | 15 | import numpy as np |
17 | 16 |
|
18 | | - |
19 | | -def apply_minimum_distance_filter(coordinates, min_distance): |
20 | | - """ |
21 | | - Filter contour points to maintain the minimum distance between points |
22 | | - """ |
23 | | - if len(coordinates) < 3 or min_distance <= 0: |
24 | | - return coordinates |
25 | | - |
26 | | - filtered_coords = [coordinates[0]] # Always keep the first point |
27 | | - |
28 | | - for i in range(1, len(coordinates)): |
29 | | - current_point = coordinates[i] |
30 | | - last_kept_point = filtered_coords[-1] |
31 | | - |
32 | | - # Calculate distance to the last kept point |
33 | | - distance = np.sqrt((current_point[0] - last_kept_point[0]) ** 2 + |
34 | | - (current_point[1] - last_kept_point[1]) ** 2) |
35 | | - |
36 | | - if distance >= min_distance: |
37 | | - filtered_coords.append(current_point) |
38 | | - |
39 | | - # Always keep the last point if it's not already kept |
40 | | - if len(filtered_coords) > 1 and not np.array_equal(filtered_coords[-1], coordinates[-1]): |
41 | | - filtered_coords.append(coordinates[-1]) |
42 | | - |
43 | | - return filtered_coords |
44 | | - |
45 | | -def calculate_average_point_spacing(x, y): |
46 | | - """Calculate average distance between survey points""" |
47 | | - if len(x) < 2: |
48 | | - return 0 |
49 | | - |
50 | | - points = np.column_stack((x, y)) |
51 | | - distances = cdist(points, points) |
52 | | - |
53 | | - # Get non-zero distances (exclude self-distances) |
54 | | - non_zero_distances = distances[distances > 0] |
55 | | - |
56 | | - return np.mean(non_zero_distances) if len(non_zero_distances) > 0 else 0 |
57 | | - |
58 | | - |
59 | 17 | class TopographicPlan(PlanProps): |
60 | 18 | _drawer: SurveyDXFManager = PrivateAttr() |
61 | 19 |
|
@@ -114,6 +72,17 @@ def _setup_topo_points(self): |
114 | 72 | pts = [(coord.easting, coord.northing, coord.elevation) for coord in self.coordinates] |
115 | 73 | return np.array(pts) |
116 | 74 |
|
| 75 | + def _get_drawing_extent(self) -> float: |
| 76 | + # get bounding box |
| 77 | + min_x, min_y, max_x, max_y = self._bounding_box |
| 78 | + if min_x is None or min_y is None or max_x is None or max_y is None: |
| 79 | + return 0.0 |
| 80 | + |
| 81 | + width = max_x - min_x |
| 82 | + height = max_y - min_y |
| 83 | + extent = math.sqrt(width ** 2 + height ** 2) |
| 84 | + return extent |
| 85 | + |
117 | 86 | def draw_beacons(self): |
118 | 87 | if not self.topographic_boundary: |
119 | 88 | return |
@@ -155,16 +124,16 @@ def add_leg_labels(self, leg, orientation: str): |
155 | 124 | angle_deg = math.degrees(angle_rad) |
156 | 125 |
|
157 | 126 | # Fractional positions |
158 | | - first_x = leg.from_.easting + 0.2 * (leg.to.easting - leg.from_.easting) |
159 | | - first_y = leg.from_.northing + 0.2 * (leg.to.northing - leg.from_.northing) |
160 | | - last_x = leg.from_.easting + 0.8 * (leg.to.easting - leg.from_.easting) |
161 | | - last_y = leg.from_.northing + 0.8 * (leg.to.northing - leg.from_.northing) |
| 127 | + first_x = leg.from_.easting + (0.2 * (leg.to.easting - leg.from_.easting)) |
| 128 | + first_y = leg.from_.northing + (0.2 * (leg.to.northing - leg.from_.northing)) |
| 129 | + last_x = leg.from_.easting + (0.8 * (leg.to.easting - leg.from_.easting)) |
| 130 | + last_y = leg.from_.northing + (0.8 * (leg.to.northing - leg.from_.northing)) |
162 | 131 | mid_x = (leg.from_.easting + leg.to.easting) / 2 |
163 | 132 | mid_y = (leg.from_.northing + leg.to.northing) / 2 |
164 | 133 |
|
165 | 134 | # Offset text above/below the line |
166 | 135 | normals = line_normals((leg.from_.easting, leg.from_.northing), (leg.to.easting, leg.to.northing), orientation) |
167 | | - offset_distance = 1 * self.get_drawing_scale() |
| 136 | + offset_distance = self._get_drawing_extent() * 0.005 |
168 | 137 | offset_inside_x = (normals[0][0] / math.hypot(*normals[0])) * offset_distance |
169 | 138 | offset_inside_y = (normals[0][1] / math.hypot(*normals[0])) * offset_distance |
170 | 139 | offset_outside_x = (normals[1][0] / math.hypot(*normals[1])) * offset_distance |
@@ -542,16 +511,24 @@ def draw_topo_map(self): |
542 | 511 | if self.topographic_setting.grid: |
543 | 512 | self._drawer.toggle_layer("GRID_MESH", self.topographic_setting.show_mesh) |
544 | 513 |
|
| 514 | + def draw_north_arrow(self): |
| 515 | + if len(self.topographic_boundary.coordinates) == 0: |
| 516 | + return |
| 517 | + |
| 518 | + coord = self._coord_dict[self.topographic_boundary.coordinates[0].id] |
| 519 | + height = (self._frame_coords[3] - self._frame_coords[1]) * 0.07 |
| 520 | + self._drawer.draw_north_arrow(coord.easting, self._frame_coords[3] - height, height) |
545 | 521 |
|
546 | 522 | def draw(self): |
547 | 523 | # Draw elements |
548 | | - self.draw_topo_points() |
549 | 524 | self.draw_beacons() |
| 525 | + self.draw_topo_points() |
550 | 526 | self.draw_boundary() |
551 | 527 | self.draw_frames() |
552 | 528 | self.draw_title_block() |
553 | 529 | self.draw_footer_boxes() |
554 | 530 | self.draw_topo_map() |
| 531 | + self.draw_north_arrow() |
555 | 532 |
|
556 | 533 | def save_dxf(self, file_path: str): |
557 | 534 | self._drawer.save_dxf(file_path) |
|
0 commit comments