Monday 10 December 2018

QGIS Plugin: Circle sector polygon

This plugins creates circle sector polygon. Input data is: center of circle coordinates, bearing from and baring to values and radius of circle.

Functions and classes for calculations on ellipsoid, validation of coordinates are in circ_tools.py, that is in the maine plugin catalog. This module has been imported as ct.

First, let's calculates coordinates of vertices where arc starts and ends:

# Calculate radius in m
self.radius_m = ct.convert_distance(dist_check, self.get_radius_uom(), ct.UOM_M)
# Calculate true brng from and true brng to
self.brng_from.calc_tbrng(mag_var.dd_value)
self.brng_to.calc_tbrng(mag_var.dd_value)
# Calculate point from
lat_from, lon_from = ct.vincenty_direct_solution(self.circ_center.dd_lat,
                                                 self.circ_center.dd_lon,
                                                 self.brng_from.dd_tbrng,
                                                 self.radius_m,
                                                 ct.WGS84_A,
                                                 ct.WGS84_B,
                                                 ct.WGS84_F)
self.point_from = ct.CoordinatesPair(lat_from, lon_from)

# Calculate point to
lat_to, lon_to = ct.vincenty_direct_solution(self.circ_center.dd_lat,
                                             self.circ_center.dd_lon,
                                             self.brng_to.dd_tbrng,
                                             self.radius_m,
                                             ct.WGS84_A,
                                             ct.WGS84_B,
                                             ct.WGS84_F)
self.point_to = ct.CoordinatesPair(lat_to, lon_to)

Now, let's start creating polygon. List poly_vertices keeps vertices that forms polygons. Our circle sector polygon begins in circle center, the next vertex is from vertex:

# Create circle sector polygon
poly_vertices = []
c_vertex = QgsPointXY(self.circ_center.dd_lon, self.circ_center.dd_lat)  # Center of circle segment
from_vertex = QgsPointXY(self.point_from.dd_lon, self.point_from.dd_lat)  # Point from
to_vertex = QgsPointXY(self.point_to.dd_lon, self.point_to.dd_lat)  # Point to

poly_vertices.append(c_vertex)
poly_vertices.append(from_vertex)

Vertices on arc will be created in for loop. First, we need to get angle 'size' to know when stop for loop. Because for loop accepts integers, I need to round angles before calculating angle. This 'trick' might lead to some inaccuracy in result polygon:

arc_angle = math.floor(self.brng_to.dd_tbrng) - math.ceil(self.brng_from.dd_tbrng)
if arc_angle < 0:
    arc_angle += 360
elif arc_angle > 360:
    arc_angle -= 360

Now I am ready to calculate vertices that form arc part of polygon:

for i in range(0, arc_angle):
    vertex_lat, vertex_lon = ct.vincenty_direct_solution(self.circ_center.dd_lat,
                                                         self.circ_center.dd_lon,
                                                         math.ceil(self.brng_from.dd_tbrng) + i,
                                                         self.radius_m,
                                                         ct.WGS84_A,
                                                         ct.WGS84_B,
                                                         ct.WGS84_F)

    poly_vertex = QgsPointXY(vertex_lon, vertex_lat)
    poly_vertices.append(poly_vertex)

When arc part is finished, last part of polygon is 'strait segment' (NOTE: is should be calculated as geodesic lines which will be covered in the future):

poly_vertices.append(to_vertex)
poly_vertices.append(c_vertex)

When I have all vertices, I can create polygon:

layers = QgsProject.instance().layerTreeRoot().children()
layers_list = []  # List of layers in current (opened) QGIS project
for layer in layers:
    layers_list.append(layer.name())

if self.mlyr_name == '':
    self.mlyr_name = ct.get_tmp_name()
self.polygon_name = self.dlg.lineEditPolyName.text()

if self.mlyr_name not in layers_list:
    self.create_mem_lyr(self.mlyr_name)
    self.add_feature_to_layer(poly_vertices)
else:
    self.add_feature_to_layer(poly_vertices)

No comments:

Post a Comment