In this post I will create QGIS plugin that allows you to easily create point which is defined in 'polar coordinates' way, that means: by distance and bearing against reference point with known coordinates and magnetic variation. This is also the first post of post series that are related to 'local coordinates' issue', quite common used in aviation data publication
Result is stored in memory point layer, example:
with following attributes:
Layer can be convert into any format served by QGIS using save as option from context menu in Layer panel.
Before we start calculation let's create code that cover creating memory layer, checks input data and...
Creating memory layer is done by method:
@staticmethod def create_mem_lyr(lyr_name): """ Create temporary 'memory' layer to store results. :param lyr_name: string, layer name """ mlyr = QgsVectorLayer('Point?crs=epsg:4326', lyr_name, 'memory') mprov = mlyr.dataProvider() mlyr.startEditing() mprov.addAttributes([QgsField("R_ID", QVariant.String), # Reference point ID QgsField("R_LATSRC", QVariant.String), # Reference point latitude (source) QgsField("R_LONSRC", QVariant.String), # Reference point longitude (source) QgsField("PP_NAME", QVariant.String), # 'Polar point' name QgsField("PP_LATDD", QVariant.String), # 'Polar point' latitude (decimal degrees) QgsField("PP_LONDD", QVariant.String), # 'Polar point' longitude (decimal degrees) QgsField("PP_DEF", QVariant.String)]) # 'Polar point'in polar coordinates 'definition' mlyr.commitChanges() QgsProject.instance().addMapLayer(mlyr)
Adding data into this layer will be done by method:
def add_point_to_layer(self, point, attributes): out_lyr = self.iface.activeLayer() out_lyr.startEditing() out_prov = out_lyr.dataProvider() feat = QgsFeature() feat.setGeometry(QgsGeometry.fromPointXY(point)) feat.setAttributes(attributes) out_prov.addFeatures([feat]) out_lyr.commitChanges() out_lyr.updateExtents() self.iface.mapCanvas().setExtent(out_lyr.extent()) self.iface.mapCanvas().refresh()
where point - is QgsPoint object, attributes - list of attributes. They will be create in method that calculates 'polar point' coordinates
So, we have function that creates layer that will keeps result of calculation and function that adds calculated point.
We need distance unit of measure, it require to check which item is chosen on the combobox:
def get_distance_uom(self): """ Returns distance unit of measure from calculated point to reference """ if self.dlg.comboBoxDistUOM.currentIndex() == 0: # m return lct.UOM_M elif self.dlg.comboBoxDistUOM.currentIndex() == 1: # km return lct.UOM_KM elif self.dlg.comboBoxDistUOM.currentIndex() == 2: # NM return lct.UOM_NM elif self.dlg.comboBoxDistUOM.currentIndex() == 3: # feet return lct.UOM_FEET elif self.dlg.comboBoxDistUOM.currentIndex() == 4: # SM return lct.UOM_SM
Distance and bearing are expressed against reference point, so now we create method that checks if data for reference point is valid, and if it is, it create BasePoint object:
def check_ref_point_input(self): """ Check if input data for reference point is correct :return check_result: bool, True if input data is valid, False otherwise :return err_msg: bool, True if input data is valid, False otherwise """ check_result = True err_msg = '' # Get input data from Qt LineEdit ref_point_id = self.dlg.lineEditRefId.text() src_ref_lat = self.dlg.lineEditRefLat.text() src_ref_lon = self.dlg.lineEditRefLon.text() src_ref_mag_var = self.dlg.lineEditRefMagVar.text() self.ref_point = lct.BasePoint(src_ref_lat, src_ref_lon, src_ref_mag_var, ref_point_id) if self.ref_point.is_valid is False: check_result = False err_msg += self.ref_point.err_msg return check_result, err_msg
Now, its time to check if polar coordinates are correct, and it they are, assign appropriate variables that will be use to calculate latitude and longitude:
def check_polar_point_input(self): """ Check if input data for calculated point is correct :return check_result: bool, True if input data is valid, False otherwise :return err_msg: bool, True if input data is valid, False otherwise """ # Check reference (origin) point input and assign results to variables check_result, err_msg = self.check_ref_point_input() # Get input dat from Qt LineEdit self.ep_name = self.dlg.lineEditEndPointName.text() ep_brng = self.dlg.lineEditEndPointBrng.text() ep_dist = self.dlg.lineEditEndPointDist.text() if self.ep_name == '': check_result = False err_msg += 'Enter end point name!\n' self.ep_brng = lct.Bearing(ep_brng) if self.ep_brng.is_valid is False: check_result = False err_msg += self.ep_brng.err_msg if ep_dist == '': check_result = False err_msg += 'Enter distance!\n' else: self.ep_dist = lct.check_distance2(ep_dist) if self.ep_dist == lct.NOT_VALID: check_result = False err_msg += 'Distance wrong value!\n' if not check_result: QMessageBox.critical(w, "Message", err_msg) return check_result
Finally we are able to calculate location of point:
def calc_point(self): if self.check_polar_point_input_point_input(): dist_m = lct.to_meters(float(self.ep_dist), self.get_distance_uom()) polar_point = lct.PolarCoordPoint(self.ref_point, self.ep_brng, dist_m) true_mag = 'MAG' if self.ref_point.mag_var.src_value == '': true_mag = 'TRUE' # Calculated point 'definition': expressed in polar coordinates pp_def = 'Ref point: {} Bearing {} {} Distance: {} {}'.format(self.ref_point.origin_id, self.ep_brng.src_value, true_mag, self.ep_dist, self.get_distance_uom()) pp_qgs_point = QgsPointXY(polar_point.ep_lon_dd, polar_point.ep_lat_dd) pp_attributes = [self.ref_point.origin_id, self.ref_point.src_lat, self.ref_point.src_lon, self.ep_name, polar_point.ep_lat_dd, polar_point.ep_lon_dd, pp_def] 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 = lct.get_tmp_name() if self.mlyr_name not in layers_list: self.create_mem_lyr(self.mlyr_name) self.add_point_to_layer(pp_qgs_point, pp_attributes) else: self.add_point_to_layer(pp_qgs_point, pp_attributes)
No comments:
Post a Comment