diff --git a/README.md b/README.md index b954daa..67ffbc6 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ A set of Python scripts and notebooks to help configure maps and manage data for - [Field Apps Deployment Using Python](notebooks/Field%20Apps%20Deployment%20Using%20Python.ipynb) - [Generate PDF Report](notebooks/Generate%20PDF%20Report/Generate%20PDF%20Report.ipynb) - [Add GPS Metadata Fields (Pro)](notebooks/Add%20GPS%20Metadata%20Fields.ipynb) -- [Add Offset Metadata Fields (Pro)](notebooks/Add%20Offset%20Metadata%20Fields.ipynb) - [Add GPS Metadata Fields](notebooks/Add%20GPS%20Metadata%20Fields_FS.ipynb) - [Configure Search](notebooks/Configure%20Search.ipynb) - [Location Sharing Status](notebooks/Location%20Sharing%20Status.ipynb) @@ -65,7 +64,7 @@ Please see our [guidelines for contributing](https://github.com/esri/contributin ## Licensing -Copyright 2022 Esri +Copyright 2026 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/notebooks/Add GPS Metadata Fields.ipynb b/notebooks/Add GPS Metadata Fields.ipynb index acba159..bf248bc 100644 --- a/notebooks/Add GPS Metadata Fields.ipynb +++ b/notebooks/Add GPS Metadata Fields.ipynb @@ -6,29 +6,31 @@ "source": [ "### Add GPS Metadata fields\n", "\n", - "This notebook is designed for use in ArcGIS Pro 2.9+. See [this topic](https://pro.arcgis.com/en/pro-app/2.8/arcpy/get-started/pro-notebooks.htm) For information on how to use Jupyter notebooks in ArcGIS Pro.\n", + "This notebook is designed for use in ArcGIS Pro 3.2+. See [this topic](https://doc.esri.com/en/arcgis-pro/latest/arcpy/get-started/pro-notebooks.html) For information on how to use Jupyter notebooks in ArcGIS Pro.\n", "\n", - "- Use this script to update an existing line or polygon feature class to support GPS metadata\n", - "- This adds a series of fields, necessary coded value domains, and enables attachments\n", + "- Use this script to update an existing point, line or polygon feature class to support GPS metadata\n", + "- This adds a series of fields, necessary coded value domains, and enables attachments (line and polygon layers only)\n", "\n", "### Steps\n", - "1. Update the `input_feaature_class` variable\n", + "1. Update the `input_feature_class`, `include_offset`, and `include_tilt` variables\n", "2. Run all cells" ] }, { "cell_type": "code", - "execution_count": 70, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "# update to location of line or polygon feature class\n", - "input_feature_class = r\"C:\\Users\\doug-m\\Documents\\ArcGIS\\Projects\\MyProject\\MyGDB.gdb\\service_lines\"" + "# update to location of point, line or polygon feature class\n", + "input_feature_class = r\"C:\\Users\\your_username\\Documents\\ArcGIS\\Projects\\MyProject\\MyGDB.gdb\\service_lines\"\n", + "include_offset = False # Set to True if offset GPS metadata fields desired (point layers only)\n", + "include_tilt = False # Set to True if tilt GPS metadata fields desired (point layers only)" ] }, { "cell_type": "code", - "execution_count": 71, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -50,31 +52,77 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def check_and_create_domains(geodatabase):\n", " \"\"\"\n", - " Checks if the Fix Type domain already exists.\n", + " Checks if the required domains already exists.\n", " If the domains do not exist, they are created\n", " :param geodatabase: (string) the path to the geodatabase to check\n", " :return:\n", " \"\"\"\n", " domains = arcpy.da.ListDomains(geodatabase)\n", " domain_names = [domain.name.lower() for domain in domains]\n", + "\n", + " \n", + " if 'esri_positionsourcetype_domain' in domain_names:\n", + " for domain in domains:\n", + " if domain.name.lower() == 'esri_positionsourcetype_domain':\n", + " # check if cvs 0,1,2,3,4,5 are in the codedValues\n", + " values = [cv for cv in domain.codedValues]\n", + " if not {0, 1, 2, 3, 4, 5}.issubset(values):\n", + " return \"esri_positionsourcetype_domain is missing a coded value pair.\"\n", + " else:\n", + " # Add the domain and values\n", + " \n", + " arcpy.CreateDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " domain_description=\"Position Source Type\",\n", + " field_type=\"SHORT\",\n", + " domain_type=\"CODED\",\n", + " split_policy=\"DEFAULT\",\n", + " merge_policy=\"DEFAULT\")\n", + "\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " code = 0,\n", + " code_description=\"Unknown\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " code = 1,\n", + " code_description=\"User defined\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " code = 2,\n", + " code_description=\"Integrated (System) Location Provider\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " code = 3,\n", + " code_description=\"External GNSS Receiver\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " code = 4,\n", + " code_description=\"Network Location Provider\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_positionsourcetype_domain\",\n", + " code = 5,\n", + " code_description=\"Snapped\")\n", + "\n", + " \n", " if 'esri_fix_type_domain' in domain_names:\n", " for domain in domains:\n", " if domain.name.lower() == 'esri_fix_type_domain':\n", " # check if cvs 0,1,2,4,5 are in the codedValues\n", " values = [cv for cv in domain.codedValues]\n", " if not {0, 1, 2, 4, 5}.issubset(values):\n", - " return \"ESRI_FIX_TYPE_DOMAIN is missing a coded value pair.\"\n", + " return \"esri_fix_type_domain is missing a coded value pair.\"\n", " else:\n", " # Add the domain and values\n", " \n", " arcpy.CreateDomain_management(in_workspace=geodatabase,\n", - " domain_name=\"ESRI_FIX_TYPE_DOMAIN\",\n", + " domain_name=\"esri_fix_type_domain\",\n", " domain_description=\"Fix Type\",\n", " field_type=\"SHORT\",\n", " domain_type=\"CODED\",\n", @@ -82,55 +130,162 @@ " merge_policy=\"DEFAULT\")\n", "\n", " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", - " domain_name=\"ESRI_FIX_TYPE_DOMAIN\",\n", - " code=\"0\",\n", + " domain_name=\"esri_fix_type_domain\",\n", + " code = 0,\n", " code_description=\"Fix not valid\")\n", " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", - " domain_name=\"ESRI_FIX_TYPE_DOMAIN\",\n", - " code=\"1\",\n", + " domain_name=\"esri_fix_type_domain\",\n", + " code = 1,\n", " code_description=\"GPS\")\n", " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", - " domain_name=\"ESRI_FIX_TYPE_DOMAIN\",\n", - " code=\"2\",\n", + " domain_name=\"esri_fix_type_domain\",\n", + " code = 2,\n", " code_description=\"Differential GPS\")\n", " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", - " domain_name=\"ESRI_FIX_TYPE_DOMAIN\",\n", - " code=\"4\",\n", + " domain_name=\"esri_fix_type_domain\",\n", + " code = 4,\n", " code_description=\"RTK Fixed\")\n", " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", - " domain_name=\"ESRI_FIX_TYPE_DOMAIN\",\n", - " code=\"5\",\n", - " code_description=\"RTK Float\")" + " domain_name=\"esri_fix_type_domain\",\n", + " code = 5,\n", + " code_description=\"RTK Float\")\n", + " \n", + " if 'esrignss_yesno_domain' in domain_names:\n", + " for domain in domains:\n", + " if domain.name.lower() == 'esrignss_yesno_domain':\n", + " # check if cvs 0,1 are in the codedValues\n", + " values = [cv for cv in domain.codedValues]\n", + " if not {0, 1}.issubset(values):\n", + " return \"esrignss_yesno_domain is missing a coded value pair.\"\n", + " else:\n", + " # Add the domain and values\n", + " arcpy.CreateDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_yesno_domain\",\n", + " domain_description=\" Yes/No\",\n", + " field_type=\"SHORT\",\n", + " domain_type=\"CODED\",\n", + " split_policy=\"DEFAULT\",\n", + " merge_policy=\"DEFAULT\")\n", + "\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_yesno_domain\",\n", + " code = 0,\n", + " code_description=\"No\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_yesno_domain\",\n", + " code = 1,\n", + " code_description=\"Yes\")\n", + " \n", + " if 'esrignss_correction_source_domain' in domain_names:\n", + " for domain in domains:\n", + " if domain.name.lower() == 'esrignss_correction_source_domain':\n", + " # check if cvs \"Unknown\", \"Direct IP\",\"NTRIP\",\"PPP\",\"Radio\",\"SBAS\" are in the codedValues\n", + " values = [cv for cv in domain.codedValues]\n", + " if not {\"Unknown\", \"Direct IP\",\"NTRIP\",\"PPP\",\"Radio\",\"SBAS\"}.issubset(values):\n", + " return \"esrignss_correction_source_domain is missing a coded value pair.\"\n", + " else:\n", + " # Add the domain and values\n", + " arcpy.CreateDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " domain_description=\" GNSS Correction Source Type\",\n", + " field_type=\"TEXT\",\n", + " domain_type=\"CODED\",\n", + " split_policy=\"DEFAULT\",\n", + " merge_policy=\"DEFAULT\")\n", + "\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " code=\"Unknown\",\n", + " code_description=\"Unknown\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " code=\"Direct IP\",\n", + " code_description=\"Direct IP\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " code=\"NTRIP\",\n", + " code_description=\"NTRIP\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " code=\"PPP\",\n", + " code_description=\"PPP\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " code=\"Radio\",\n", + " code_description=\"Radio\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esrignss_correction_source_domain\",\n", + " code=\"SBAS\",\n", + " code_description=\"SBAS\")\n", + " if include_offset:\n", + "\n", + " if 'esri_offset_method_domain' in domain_names:\n", + " for domain in domains:\n", + " if domain.name.lower() == 'esri_offset_method_domain':\n", + " # check if offset methods are in the codedValues\n", + " values = [cv for cv in domain.codedValues]\n", + " if not {'azimuth-azimuth', \n", + " 'distance-azimuth', \n", + " 'distance-distance', \n", + " 'distance-angle', \n", + " 'azimuth-azimuth-backsight', \n", + " 'distance-azimuth-backsight',\n", + " 'distance-distance-backsight',\n", + " 'user-defined'}.issubset(values):\n", + " return \"esri_offset_method_domain is missing a coded value pair.\"\n", + " else:\n", + " # Add the domain and values\n", + " \n", + " arcpy.CreateDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " domain_description=\"Offset Method Domain\",\n", + " field_type=\"TEXT\",\n", + " domain_type=\"CODED\",\n", + " split_policy=\"DEFAULT\",\n", + " merge_policy=\"DEFAULT\")\n", + "\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"azimuth-azimuth\",\n", + " code_description=\"Azimuth-Azimuth\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"distance-angle\",\n", + " code_description=\"Distance-Angle\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"distance-azimuth\",\n", + " code_description=\"Distance-Azimuth\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"distance-distance\",\n", + " code_description=\"Distance-Distance\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"azimuth-azimuth-backsight\",\n", + " code_description=\"Azimuth-Azimuth-Backsight\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"distance-azimuth-backsight\",\n", + " code_description=\"Distance-Azimuth-Backsight\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"distance-distance-backsight\",\n", + " code_description=\"Distance-Distance-Backsight\")\n", + " arcpy.AddCodedValueToDomain_management(in_workspace=geodatabase,\n", + " domain_name=\"esri_offset_method_domain\",\n", + " code=\"user-defined\",\n", + " code_description=\"User-defined\")\n", + " " ] }, { "cell_type": "code", - "execution_count": 73, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "def add_gnss_fields(feature_class):\n", - " \"\"\"\n", - " This adds specific fields required for GPS units to\n", - " auto-populate in the Field Maps application\n", - " This will report errors if:\n", - " 1) Any of the fields already exist\n", - " 2) The input layer is not a line or polygon layer\n", - " 3) The layer is not found\n", - " 4) The layer is a shapefile\n", - " \"\"\"\n", - "\n", - " if not arcpy.Exists(feature_class):\n", - " return \"Feature layer: {} not found!\".format(feature_class)\n", - " if arcpy.Describe(feature_class).shapeType != \"Polyline\" and arcpy.Describe(feature_class).shapeType != \"Polygon\":\n", - " return \"Feature layer: {} is not a line or polygon layer. Use AddGPSMetadataFields_management instead.\".format(feature_class)\n", - " if arcpy.Describe(feature_class).dataType == \"ShapeFile\":\n", - " return \"ShapeFiles are not supported.\"\n", - "\n", - " # Check the domains to see if they exist and are valid\n", - " # will update if necessary\n", - " geodatabase = get_geodatabase_path(feature_class)\n", - " check_and_create_domains(geodatabase) \n", + "def add_line_poly_gnss_fields(feature_class):\n", "\n", " # Enable Attachments\n", " arcpy.EnableAttachments_management(feature_class)\n", @@ -176,7 +331,6 @@ " field_type=\"SHORT\",\n", " field_alias='Worst Fix Type',\n", " field_is_nullable=\"NULLABLE\",\n", - " field_domain=\"ESRI_FIX_TYPE_DOMAIN\"\n", " )\n", "\n", " if 'esrignss_manual_locations' not in existing_fields:\n", @@ -185,16 +339,847 @@ " field_type=\"LONG\",\n", " field_alias='Number of manual locations',\n", " field_is_nullable=\"NULLABLE\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add_tilt_fields(feature_class):\n", + " \"\"\"\n", + " This adds specific fields required for laser offset workflows\n", + " This will report errors if:\n", + " 1) Any of the fields already exist\n", + " 2) The input layer is not a point layer\n", + " 3) The layer is not found\n", + " 4) The layer is a shapefile\n", + " \"\"\"\n", + "\n", + " if not arcpy.Exists(feature_class):\n", + " return \"Feature layer: {} not found!\".format(feature_class)\n", + " if arcpy.Describe(feature_class).shapeType != \"Point\":\n", + " return \"Feature layer: {} is not a point layer.\".format(feature_class)\n", + " if arcpy.Describe(feature_class).dataType == \"ShapeFile\":\n", + " return \"Shapefiles are not supported.\"\n", + "\n", + " # Check the domains to see if they exist and are valid\n", + " # will update if necessary\n", + " geodatabase = get_geodatabase_path(feature_class)\n", + " check_and_create_domains(geodatabase) \n", + "\n", + " # Add GNSS tilt metadata fields\n", + " existing_fields = [field.name.lower() for field in arcpy.ListFields(feature_class)]\n", + "\n", + " if 'esrignss_tilt_compensated' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_tilt_compensated',\n", + " field_type=\"SHORT\",\n", + " field_alias='Tilt compensated',\n", + " field_is_nullable=\"NULLABLE\"\n", " )\n", "\n", - " # Update GNSS metadata fields with Domains\n", - " domain_fields = [field for field in arcpy.ListFields(feature_class) if field.name == 'esrignss_worst_fixtype']\n", + " if 'esrisnsr_tilt_angle' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_tilt_angle',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Tilt angle (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrisnsr_tilt_angle_accuracy' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_tilt_angle_accuracy',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Tilt angle accuracy (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrisnsr_tilt_azimuth' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_tilt_azimuth',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Tilt azimuth (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrisnsr_tilt_azimuth_accuracy' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_tilt_azimuth_accuracy',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Tilt azimuth accuracy (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add_offset_fields(feature_class):\n", + " \n", + " # Add GNSS metadata fields\n", + " existing_fields = [field.name.lower() for field in arcpy.ListFields(feature_class)]\n", + "\n", + " if 'esrisnsr_offset_method' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_offset_method',\n", + " field_type=\"TEXT\",\n", + " field_alias='Offset method',\n", + " field_is_nullable=\"NULLABLE\",\n", + " field_domain=\"esri_offset_method_domain\"\n", + " )\n", + "\n", + " if 'esrisnsr_offset_device' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_offset_device',\n", + " field_type=\"TEXT\",\n", + " field_alias='Rangefinder name',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_antenna_height' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_antenna_height',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='GNSS Antenna height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrisnsr_offset_laser_height' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_offset_laser_height',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Rangefinder height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrisnsr_offset_laser_target_ht' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_offset_laser_target_ht',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Laser target height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrisnsr_offset_mag_var' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_offset_mag_var',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Rangefinder Magnetic variation (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_cp1_latitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_latitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Latitude',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp1_longitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_longitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Longitude',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_altitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_altitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Ellipsoidal height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp1_h_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_h_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Horizontal accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_v_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_v_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Vertical accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp1_fixdatetime' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_fixdatetime',\n", + " field_type=\"DATE\",\n", + " field_alias='CP1 Fix time',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_fixtype' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_fixtype',\n", + " field_type=\"SHORT\",\n", + " field_alias='CP1 Fix type',\n", + " field_is_nullable=\"NULLABLE\",\n", + " field_domain=\"esri_fix_type_domain\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_corr_age' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_corr_age',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Correction age',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp1_stationid' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_stationid',\n", + " field_type=\"SHORT\",\n", + " field_alias='CP1 Station ID',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_numsats' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_numsats',\n", + " field_type=\"SHORT\",\n", + " field_alias='CP1 Number of satellites',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp1_pdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_pdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 PDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_hdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_hdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 HDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrignss_cp1_vdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_vdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 VDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_avg_h_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_avg_h_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Average horizontal accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_avg_v_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_avg_v_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Average vertical accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp1_avg_positions' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_avg_positions',\n", + " field_type=\"INTEGER\",\n", + " field_alias='CP1 Averaged positions',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp1_h_stddev' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp1_h_stddev',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Standard deviation (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrisnsr_cp1_slope_dist' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_cp1_slope_dist',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Laser slope distance (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrisnsr_cp1_inclination' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_cp1_inclination',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Laser inclination (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrisnsr_cp1_azimuth' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_cp1_azimuth',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP1 Laser azimuth (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", "\n", + " if 'esrignss_cp2_latitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_latitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Latitude',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp2_longitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_longitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Longitude',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_altitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_altitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Ellipsoidal height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp2_h_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_h_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Horizontal accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_v_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_v_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Vertical accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp2_fixdatetime' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_fixdatetime',\n", + " field_type=\"DATE\",\n", + " field_alias='CP2 Fix time',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_fixtype' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_fixtype',\n", + " field_type=\"SHORT\",\n", + " field_alias='CP2 Fix type',\n", + " field_is_nullable=\"NULLABLE\",\n", + " field_domain=\"esri_fix_type_domain\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_corr_age' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_corr_age',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Correction age',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp2_stationid' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_stationid',\n", + " field_type=\"SHORT\",\n", + " field_alias='CP2 Station ID',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_numsats' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_numsats',\n", + " field_type=\"SHORT\",\n", + " field_alias='CP2 Number of satellites',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp2_pdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_pdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 PDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_hdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_hdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 HDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrignss_cp2_vdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_vdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 VDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_avg_h_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_avg_h_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Average horizontal accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_avg_v_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_avg_v_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Average vertical accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_cp2_avg_positions' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_avg_positions',\n", + " field_type=\"INTEGER\",\n", + " field_alias='CP2 Averaged positions',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_cp2_h_stddev' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_cp2_h_stddev',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Standard deviation (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrisnsr_cp2_slope_dist' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_cp2_slope_dist',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Laser slope distance (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrisnsr_cp2_inclination' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_cp2_inclination',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Laser inclination (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrisnsr_cp2_azimuth' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_cp2_azimuth',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='CP2 Laser azimuth (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add_point_gnss_fields(feature_class):\n", + "\n", + " # Add GNSS metadata fields\n", + " existing_fields = [field.name.lower() for field in arcpy.ListFields(feature_class)]\n", + "\n", + "\n", + " if 'esrignss_receiver' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_receiver',\n", + " field_type=\"TEXT\",\n", + " field_length=50,\n", + " field_alias='Receiver name',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_positionsourcetype' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_positionsourcetype',\n", + " field_type=\"SHORT\",\n", + " field_alias='Position source type',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_latitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_latitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Latitude',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_longitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_longitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Longitude',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_altitude' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_altitude',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Ellipsoidal height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_orthometric_height' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_orthometric_height',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Orthometric height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_h_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_h_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Horizontal accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_v_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_v_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Vertical accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " if 'esrignss_fixdatetime' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_fixdatetime',\n", + " field_type=\"DATE\",\n", + " field_alias='Fix time',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_fixtype' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_fixtype',\n", + " field_type=\"SHORT\",\n", + " field_alias='Fix type',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_numsats' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_numsats',\n", + " field_type=\"SHORT\",\n", + " field_alias='Number of satellites',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_correction_source_type' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_correction_source_type',\n", + " field_type=\"TEXT\",\n", + " field_length=25,\n", + " field_alias='Correction source type',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_correction_source_name' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_correction_source_name',\n", + " field_type=\"TEXT\",\n", + " field_length=100,\n", + " field_alias='Correction source name',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_correctionage' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_correctionage',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Correction age',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_ntrip_mount_point' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_ntrip_mount_point',\n", + " field_type=\"TEXT\",\n", + " field_length=100,\n", + " field_alias='NTRIP mount point',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_stationid' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_stationid',\n", + " field_type=\"SHORT\",\n", + " field_alias='Station ID',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_pdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_pdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='PDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_hdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_hdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='HDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_vdop' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_vdop',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='VDOP',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + " \n", + " if 'esrignss_direction' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_direction',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Direction of travel (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_speed' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_speed',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Speed (km/h)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrisnsr_azimuth' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrisnsr_azimuth',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Compass reading (°)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_antenna_height' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_antenna_height',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='GNSS Antenna height (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_receiver_gcs' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_receiver_gcs',\n", + " field_type=\"TEXT\",\n", + " field_length=60,\n", + " field_alias='Geographic coordinate system',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_receiver_gcs_wkid' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_receiver_gcs_wkid',\n", + " field_type=\"INTEGER\",\n", + " field_alias='Geographic coordinate system WKID',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_receiver_ref_epoch' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_receiver_ref_epoch',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Reference epoch',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_profile_has_hor_xform' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_profile_has_hor_xform',\n", + " field_type=\"SHORT\",\n", + " field_alias='Location profile horizontal datum transformation applied',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " if 'esrignss_profile_hor_xform' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_profile_hor_xform',\n", + " field_type=\"TEXT\",\n", + " field_length=255,\n", + " field_alias='Location profile horizontal datum transformation',\n", + " field_is_nullable=\"NULLABLE\"\n", + " ) \n", + "\n", + " if 'esrignss_receiver_geoid' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_receiver_geoid',\n", + " field_type=\"TEXT\",\n", + " field_length=60,\n", + " field_alias='Receiver geoid model',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " if 'esrignss_avg_h_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_avg_h_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Average horizontal accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_avg_v_rms' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_avg_v_rms',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Average vertical accuracy (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_avg_positions' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_avg_positions',\n", + " field_type=\"INTEGER\",\n", + " field_alias='Averaged positions',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " if 'esrignss_h_stddev' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_h_stddev',\n", + " field_type=\"DOUBLE\",\n", + " field_alias='Standard deviation (m)',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + " \n", + " if 'esrignss_h_95_status' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_h_95_status',\n", + " field_type=\"SHORT\",\n", + " field_alias='95% accuracy applied',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if 'esrignss_custom_attributes' not in existing_fields:\n", + " arcpy.AddField_management(feature_class,\n", + " 'esrignss_custom_attributes',\n", + " field_type=\"TEXT\",\n", + " field_length=2000,\n", + " field_alias='GNSS custom attributes',\n", + " field_is_nullable=\"NULLABLE\"\n", + " )\n", + "\n", + " if include_tilt:\n", + " add_tilt_fields(feature_class)\n", + "\n", + " if include_offset:\n", + " add_offset_fields(feature_class)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "def add_gnss_fields(feature_class):\n", + " \"\"\"\n", + " This adds specific fields required for GPS units to\n", + " auto-populate in the Field Maps app\n", + " This will report errors if:\n", + " 1) The layer is not found\n", + " 2) The layer is a shapefile\n", + " 3) The input layer is not a point, line or polygon layer\n", + " \"\"\"\n", + "\n", + " # Make sure we have a Geodatabase feature class\n", + " if not arcpy.Exists(feature_class):\n", + " return \"Feature layer: {} not found!\".format(feature_class)\n", + " if arcpy.Describe(feature_class).dataType == \"ShapeFile\":\n", + " return \"Shapefiles are not supported.\"\n", + "\n", + " shape_type = arcpy.Describe(feature_class).shapeType\n", + " \n", + " match shape_type:\n", + "\n", + " case \"Point\":\n", + " add_point_gnss_fields(feature_class)\n", + " \n", + " case \"Polyline\" | \"Polygon\":\n", + " add_line_poly_gnss_fields(feature_class)\n", + "\n", + " case _:\n", + " return \"Feature layer: {} is not a point, line or polygon layer\".format(feature_class)\n", + "\n", + " # Check the domains to see if they exist and are valid\n", + " # will update if necessary\n", + " geodatabase = get_geodatabase_path(feature_class)\n", + " check_and_create_domains(geodatabase) \n", + "\n", + " domain_fields = [field for field in arcpy.ListFields(feature_class)]\n", + "\n", + " # Update GNSS metadata fields with Domains\n", " for field in domain_fields:\n", + "\n", + " if field.name == 'esrignss_positionsourcetype' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esri_positionsourcetype_domain')\n", + "\n", + " if field.name == 'esrignss_fixtype' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esri_fix_type_domain')\n", + "\n", + " if field.name == 'esrignss_correction_source_type' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esrignss_correction_source_domain')\n", + " \n", + " if field.name == 'esrignss_profile_has_hor_xform' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esrignss_yesno_domain')\n", + " \n", + " if field.name == 'esrignss_h_95_status' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esrignss_yesno_domain')\n", + "\n", " if field.name == 'esrignss_worst_fixtype' and not field.domain:\n", - " arcpy.AssignDomainToField_management(feature_class, field, 'ESRI_FIX_TYPE_DOMAIN')\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esri_fix_type_domain')\n", "\n", - " return \"Successfully added offset metadata fields and domains.\"" + " if include_offset:\n", + " if field.name == 'esrisnsr_offset_method' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esri_offset_method_domain')\n", + "\n", + " if field.name == 'esrignss_cp1_fixtype' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esri_fix_type_domain')\n", + "\n", + " if field.name == 'esrignss_cp2_fixtype' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esri_fix_type_domain')\n", + "\n", + " if include_tilt: \n", + " if field.name == 'esrignss_tilt_compensated' and not field.domain:\n", + " arcpy.AssignDomainToField_management(feature_class, field.name, 'esrignss_yesno_domain')\n", + "\n", + " return \"Successfully added domains and associated with metadata fields.\"" ] }, { @@ -208,20 +1193,18 @@ } ], "metadata": { - "interpreter": { - "hash": "2f7d5e7f44707441fdf59f9ea9e91257aa419b0f47527e9654c7357783801722" - }, "kernelspec": { "display_name": "ArcGISPro", - "language": "Python", + "language": "python", "name": "python3" }, "language_info": { "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.7.13" + "version": "3.13.5" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/notebooks/Add GPS Metadata Fields_FS.ipynb b/notebooks/Add GPS Metadata Fields_FS.ipynb index eb326a3..456539c 100644 --- a/notebooks/Add GPS Metadata Fields_FS.ipynb +++ b/notebooks/Add GPS Metadata Fields_FS.ipynb @@ -24,6 +24,7 @@ " - `item_id`\n", " - `feature_layer_index`\n", " - `include_offset_fields`\n", + " - `include_tilt_fields`\n", "2. Run all cells\n" ] }, @@ -38,10 +39,11 @@ "\n", "# update this information prior to running\n", "org_url = \"https://www.arcgis.com\"\n", - "username = \"doug_nitro\"\n", - "item_id = \"7984f1a3089c47eaad07086b19f6fe92\" # item_id of feature layer\n", + "username = \"your_username\"\n", + "item_id = \"9272c98953db4f5aa580f99e7a529404\" # item_id of feature layer\n", "feature_layer_index = 0 #index of layer you want to update\n", "include_offset_fields = False # indicate if you want offset fields added (point feature layers only)\n", + "include_tilt_fields = False # indicate if you want tilt fields added (point feature layers only)\n", "\n", "gis = GIS(org_url, username)" ] @@ -64,6 +66,12 @@ "\n", "feature_layer_collection = FeatureLayerCollection.fromitem(item)\n", "\n", + "if feature_layer_collection.properties.get('isView') == True:\n", + " raise TypeError(\"Feature layer is a view. Cannot update fields on a view\")\n", + "\n", + "if feature_layer_collection.properties.get('subtypeField') is not None:\n", + " raise TypeError(\"Feature layer has subtypes. Cannot update fields on a feature layer with subtypes\")\n", + "\n", "feature_layer = feature_layer_collection.layers[feature_layer_index]\n", "\n", "# get the geometry type\n", @@ -81,13 +89,13 @@ " print (\"Enabled attachments\")\n", "\n", "# Extract existing fields from Feature layer service definition\n", - "feature_layer_fields = feature_layer.properties.fields\n", + "feature_layer_fields = feature_layer.properties.get(\"fields\", [])\n", "\n", - "# New fields which need to be added\n", + "# Fields which need to be added\n", "gnss_metadata_fields = {'fields': []}\n", "\n", - "# Operations list - Add or Update GNSS Metadata fields.\n", - "operations = []" + "# Fields which need to be updated\n", + "gnss_metadata_fields_updated = {'fields': []}" ] }, { @@ -157,21 +165,22 @@ " worst_fixtype_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_worst_fixtype']\n", "\n", " if worst_fixtype_field:\n", - " # Field does exist check if the domain is set.\n", - " if worst_fixtype_field[0]['domain'] is None:\n", - " #if ([operation for operation in operations if operation == 'updateDefinition']):\n", - " operations.append('updateDefinition')\n", - "\n", - " worst_fixtype_field_index = feature_layer_fields.index(worst_fixtype_field[0])\n", - " fixtype_domain = {'type': 'codedValue',\n", - " 'name': 'esri_fix_type_domain',\n", - " 'codedValues': [{'name': 'Fix not valid',\n", - " 'code': 0},\n", - " {'name': 'GPS', 'code': 1},\n", - " {'name': 'Differential GPS', 'code': 2},\n", - " {'name': 'RTK Fixed', 'code': 4},\n", - " {'name': 'RTK Float', 'code': 5}]}\n", - " feature_layer_fields[worst_fixtype_field_index]['domain'] = fixtype_domain\n", + " # Field does exist check if the domain is correct\n", + "\n", + " fixtype_domain = {'type': 'codedValue',\n", + " 'name': 'esri_fix_type_domain',\n", + " 'codedValues': [{'name': 'Fix not valid',\n", + " 'code': 0},\n", + " {'name': 'GPS', 'code': 1},\n", + " {'name': 'Differential GPS', 'code': 2},\n", + " {'name': 'RTK Fixed', 'code': 4},\n", + " {'name': 'RTK Float', 'code': 5}]}\n", + "\n", + " if worst_fixtype_field[0]['domain'] is None or worst_fixtype_field[0]['domain']['codedValues'] != fixtype_domain['codedValues']:\n", + "\n", + " worst_fixtype_field[0]['domain'] = fixtype_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(worst_fixtype_field[0])\n", "\n", " else:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_worst_fixtype',\n", @@ -203,25 +212,41 @@ " 'domain': None,\n", " 'defaultValue': None})\n", "else:\n", + " # esrignss_receiver\n", + " receiver_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_receiver']\n", + " \n", + " if not receiver_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_receiver',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'Receiver name',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 50,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", " # esrignss_positionsourcetype\n", " positionsourcetype_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_positionsourcetype']\n", "\n", " if positionsourcetype_field:\n", - " # Field does exist; check if the domain is set\n", - " if positionsourcetype_field[0]['domain'] is None:\n", - " operations.append('updateDefinition')\n", - "\n", - " positionsourcetype_field_index = feature_layer_fields.index(positionsourcetype_field[0])\n", - " positionsourcetype_domain = {'type': 'codedValue',\n", + " # Field does exist; check if the domain is correct\n", + " \n", + " positionsourcetype_domain = {'type': 'codedValue',\n", " 'name': 'esri_positionsourcetype_domain',\n", - " 'codedValues': [{'name': 'Unknown',\n", - " 'code': 0},\n", + " 'codedValues': [{'name': 'Unknown', 'code': 0},\n", " {'name': 'User defined', 'code': 1},\n", " {'name': 'Integrated (System) Location Provider', 'code': 2},\n", " {'name': 'External GNSS Receiver', 'code': 3},\n", " {'name': 'Network Location Provider', 'code': 4},\n", - " {'name': 'Snapped', 'code': 5}]},\n", - " feature_layer_fields[positionsourcetype_field_index]['domain'] = positionsourcetype_domain\n", + " {'name': 'Snapped', 'code': 5}]}\n", + "\n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if positionsourcetype_field[0]['domain'] is None or positionsourcetype_field[0]['domain']['codedValues'] != positionsourcetype_domain['codedValues']:\n", + "\n", + " positionsourcetype_field[0]['domain'] = positionsourcetype_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(positionsourcetype_field[0])\n", "\n", " else:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_positionsourcetype',\n", @@ -241,20 +266,6 @@ " {'name': 'Snapped', 'code': 5}]},\n", " 'defaultValue': None})\n", "\n", - " # esrignss_receiver\n", - " receiver_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_receiver']\n", - " \n", - " if not receiver_field:\n", - " gnss_metadata_fields['fields'].append({'name': 'esrignss_receiver',\n", - " 'type': 'esriFieldTypeString',\n", - " 'alias': 'Receiver name',\n", - " 'sqlType': 'sqlTypeOther',\n", - " 'length': 50,\n", - " 'nullable': True,\n", - " 'editable': True,\n", - " 'domain': None,\n", - " 'defaultValue': None})\n", - "\n", " # esrignss_latitude\n", " latitude_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_latitude']\n", "\n", @@ -287,13 +298,25 @@ " if not altitude_field:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_altitude',\n", " 'type': 'esriFieldTypeDouble',\n", - " 'alias': 'Altitude',\n", + " 'alias': 'Ellipsoidal height (m)',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", " 'editable': True,\n", " 'domain': None,\n", " 'defaultValue': None})\n", "\n", + " # esrignss_orthometric_height\n", + " altitude_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_orthometric_height']\n", + "\n", + " if not altitude_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_orthometric_height',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'Orthometric height (m)',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", " # esrignss_h_rms\n", " horizontal_accuracy_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_h_rms']\n", "\n", @@ -337,25 +360,27 @@ " fix_type_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_fixtype']\n", "\n", " if fix_type_field:\n", - " # Field does exist; check if the domain is set\n", - " if fix_type_field[0]['domain'] == None:\n", - " if ([operation for operation in operations if operation == 'updateDefinition']):\n", - " operations.append('updateDefinition')\n", - "\n", - " fix_type_field_index = feature_layer_fields.index(fix_type_field[0])\n", - " fix_type_domain = {'type': 'codedValue',\n", - " 'name': 'esri_fix_type_domain',\n", - " 'codedValues': [{'name': 'Fix not valid',\n", - " 'code': 0},\n", - " {'name': 'GPS', 'code': 1},\n", - " {'name': 'Differential GPS', 'code': 2},\n", - " {'name': 'RTK Fixed', 'code': 4},\n", - " {'name': 'RTK Float', 'code': 5}]}\n", - " feature_layer_fields[fix_type_field_index]['domain'] = fix_type_domain\n", + " # Field does exist; check if the domain is correct\n", + "\n", + " fix_type_domain = {'type': 'codedValue',\n", + " 'name': 'esri_fix_type_domain',\n", + " 'codedValues': [{'name': 'Fix not valid',\n", + " 'code': 0},\n", + " {'name': 'GPS', 'code': 1},\n", + " {'name': 'Differential GPS', 'code': 2},\n", + " {'name': 'RTK Fixed', 'code': 4},\n", + " {'name': 'RTK Float', 'code': 5}]}\n", + "\n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if fix_type_field[0]['domain'] is None or fix_type_field[0]['domain']['codedValues'] != fix_type_domain['codedValues']:\n", + "\n", + " fix_type_field[0]['domain'] = fix_type_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(fix_type_field[0])\n", "\n", " else:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_fixtype',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'Fix type',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -370,6 +395,74 @@ " {'name': 'RTK Float', 'code': 5}]},\n", " 'defaultValue': None})\n", "\n", + " # esrignss_numsats\n", + " num_sats_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_numsats']\n", + "\n", + " if not num_sats_field: \n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_numsats',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", + " 'alias': 'Number of satellites',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", + " # esrignss_correction_source_type\n", + " correction_source_type_field = [field for field in feature_layer_fields if \n", + " field['name'].lower() == 'esrignss_correction_source_type']\n", + "\n", + " if correction_source_type_field:\n", + " # Field does exist; check if the domain is correct\n", + "\n", + " corr_source_type_domain = {'type': 'codedValue',\n", + " 'name': 'esrignss_correction_source_domain',\n", + " 'codedValues': [{'name': 'Unknown', 'code': 'Unknown'},\n", + " {'name': 'Direct IP', 'code': 'Direct IP'},\n", + " {'name': 'NTRIP', 'code': 'NTRIP'},\n", + " {'name': 'PPP', 'code': 'PPP'},\n", + " {'name': 'Radio', 'code': 'Radio'},\n", + " {'name': 'SBAS', 'code': 'SBAS'}]}\n", + "\n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if correction_source_type_field[0]['domain'] is None or correction_source_type_field[0]['domain']['codedValues'] != corr_source_type_domain['codedValues']:\n", + "\n", + " correction_source_type_field[0]['domain'] = corr_source_type_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(correction_source_type_field[0])\n", + "\n", + " else:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_correction_source_type',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'Correction source type',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 25,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': {'type': 'codedValue',\n", + " 'name': 'esrignss_correction_source_domain',\n", + " 'codedValues': [{'name': 'Unknown', 'code': 'Unknown'},\n", + " {'name': 'Direct IP', 'code': 'Direct IP'},\n", + " {'name': 'NTRIP', 'code': 'NTRIP'},\n", + " {'name': 'PPP', 'code': 'PPP'},\n", + " {'name': 'Radio', 'code': 'Radio'},\n", + " {'name': 'SBAS', 'code': 'SBAS'}]},\n", + " 'defaultValue': None})\n", + "\n", + " # esrignss_correction_source_name\n", + " corr_source_name_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_correction_source_name']\n", + " \n", + " if not corr_source_name_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_correction_source_name',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'Correction source name',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 100,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", " # esrignss_correctionage\n", " correction_age_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_correctionage']\n", "\n", @@ -383,26 +476,27 @@ " 'domain': None,\n", " 'defaultValue': None})\n", "\n", - " # esrignss_stationid\n", - " station_id_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_stationid']\n", - "\n", - " if not station_id_field:\n", - " gnss_metadata_fields['fields'].append({'name': 'esrignss_stationid',\n", - " 'type': 'esriFieldTypeInteger',\n", - " 'alias': 'Station ID',\n", + " # esrignss_ntrip_mount_point\n", + " ntrip_mountpoint_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_ntrip_mount_point']\n", + " \n", + " if not ntrip_mountpoint_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_ntrip_mount_point',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'NTRIP mount point',\n", " 'sqlType': 'sqlTypeOther',\n", + " 'length': 100,\n", " 'nullable': True,\n", " 'editable': True,\n", " 'domain': None,\n", " 'defaultValue': None})\n", "\n", - " # esrignss_numsats\n", - " num_sats_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_numsats']\n", + " # esrignss_stationid\n", + " station_id_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_stationid']\n", "\n", - " if not num_sats_field: \n", - " gnss_metadata_fields['fields'].append({'name': 'esrignss_numsats',\n", - " 'type': 'esriFieldTypeInteger',\n", - " 'alias': 'Number of satellites',\n", + " if not station_id_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_stationid',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", + " 'alias': 'Station ID',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", " 'editable': True,\n", @@ -487,6 +581,121 @@ " 'domain': None,\n", " 'defaultValue': None})\n", "\n", + " # esrignss_antenna_height\n", + " antenna_height_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_antenna_height']\n", + "\n", + " if not antenna_height_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_antenna_height',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'GNSS Antenna height (m)',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", + " # esrignss_receiver_gcs\n", + " corr_source_name_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_receiver_gcs']\n", + " \n", + " if not corr_source_name_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_receiver_gcs',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'Geographic coordinate system',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 60,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + " \n", + " # esrignss_receiver_gcs_wkid\n", + " receiver_gcs_wkid_field = [field for field in feature_layer_fields if\n", + " field['name'].lower() == 'esrignss_receiver_gcs_wkid']\n", + "\n", + " if not receiver_gcs_wkid_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_receiver_gcs_wkid',\n", + " 'type': 'esriFieldTypeInteger',\n", + " 'alias': 'Geographic coordinate system WKID',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + " \n", + " # esrignss_receiver_ref_epoch\n", + " reciever_ref_epoch_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_receiver_ref_epoch']\n", + "\n", + " if not reciever_ref_epoch_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_receiver_ref_epoch',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'Reference epoch',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + " \n", + " # esrignss_profile_has_hor_xform\n", + " has_hor_xform_field = [field for field in feature_layer_fields if \n", + " field['name'].lower() == 'esrignss_profile_has_hor_xform']\n", + "\n", + " if has_hor_xform_field:\n", + " # Field does exist; check if the domain is correct\n", + "\n", + " has_xform_status_domain = {'type': 'codedValue',\n", + " 'name': 'esrignss_yesno_domain',\n", + " 'codedValues': [{'name': 'No', 'code': 0},\n", + " {'name': 'Yes', 'code': 1}]}\n", + " \n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if has_hor_xform_field[0]['domain'] is None or has_hor_xform_field[0]['domain']['codedValues'] != has_xform_status_domain['codedValues']:\n", + "\n", + " has_hor_xform_field[0]['domain'] = has_xform_status_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(has_hor_xform_field[0])\n", + "\n", + " else:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_profile_has_hor_xform',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", + " 'alias': 'Location profile horizontal datum transformation applied',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': {'type': 'codedValue',\n", + " 'name': 'esrignss_yesno_domain',\n", + " 'codedValues': [\n", + " {'name': 'No', 'code': 0},\n", + " {'name': 'Yes', 'code': 1}]},\n", + " 'defaultValue': None})\n", + "\n", + " # esrignss_profile_hor_xform\n", + " loc_profile_hor_xform_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_profile_hor_xform']\n", + " \n", + " if not loc_profile_hor_xform_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_profile_hor_xform',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'Location profile horizontal datum transformation',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 255,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", + " # esrignss_receiver_geoid\n", + " receiver_geoid_ield = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_receiver_geoid']\n", + " \n", + " if not receiver_geoid_ield:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_receiver_geoid',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'Receiver geoid model',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 60,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", " # esrignss_avg_h_rms\n", " average_horizontal_accuracy_field = [field for field in feature_layer_fields if\n", " field['name'].lower() == 'esrignss_avg_h_rms']\n", @@ -541,7 +750,54 @@ " 'nullable': True,\n", " 'editable': True,\n", " 'domain': None,\n", - " 'defaultValue': None}) \n" + " 'defaultValue': None}) \n", + "\n", + " # esrignss_h_95_status\n", + " h_95_status_field = [field for field in feature_layer_fields if \n", + " field['name'].lower() == 'esrignss_h_95_status']\n", + "\n", + " if h_95_status_field:\n", + " # Field does exist; check if the domain is correct\n", + "\n", + " h_95_status_domain = {'type': 'codedValue',\n", + " 'name': 'esrignss_yesno_domain',\n", + " 'codedValues': [{'name': 'No', 'code': 0},\n", + " {'name': 'Yes', 'code': 1}]}\n", + "\n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if h_95_status_field[0]['domain'] is None or h_95_status_field[0]['domain']['codedValues'] != h_95_status_domain['codedValues']:\n", + "\n", + " h_95_status_field[0]['domain'] = h_95_status_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(h_95_status_field[0])\n", + "\n", + " else:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_h_95_status',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", + " 'alias': '95% accuracy applied',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': {'type': 'codedValue',\n", + " 'name': 'esrignss_yesno_domain',\n", + " 'codedValues': [\n", + " {'name': 'No', 'code': 0},\n", + " {'name': 'Yes', 'code': 1}]},\n", + " 'defaultValue': None})\n", + "\n", + " # esrignss_custom_attributes\n", + " custom_attributes_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_custom_attributes']\n", + " \n", + " if not custom_attributes_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_custom_attributes',\n", + " 'type': 'esriFieldTypeString',\n", + " 'alias': 'GNSS custom attributes',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'length': 2000,\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})" ] }, { @@ -551,27 +807,33 @@ "outputs": [], "source": [ "# Add metadata fields for laser offset workflows \n", - "if include_offset_fields == True and geometry_type == 'esriGeometryPoint':\n", + "if include_offset_fields and geometry_type == 'esriGeometryPoint':\n", "\n", "\n", " # esrisnsr_offset_method\n", " offset_method_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrisnsr_offset_method']\n", "\n", " if offset_method_field:\n", - " # Field does exist; check if the domain is set\n", - " if offset_method_field[0]['domain'] == None:\n", - " if ([operation for operation in operations if operation == 'updateDefinition']):\n", - " operations.append('updateDefinition')\n", + " # Field does exist; check if the domain is correct\n", "\n", - " offset_method_field_index = feature_layer_fields.index(offset_method_field[0])\n", - " offset_method_domain = {'type': 'codedValue',\n", + " offset_method_domain = {'type': 'codedValue',\n", " 'name': 'esri_offset_method_domain',\n", - " 'codedValues': [{'name': 'Fix not valid', 'code': 0},\n", - " {'name': 'GPS', 'code': 1},\n", - " {'name': 'Differential GPS', 'code': 2},\n", - " {'name': 'RTK Fixed', 'code': 4},\n", - " {'name': 'RTK Float', 'code': 5}]}\n", - " feature_layer_fields[fix_type_field_index]['domain'] = offset_method_domain\n", + " 'codedValues': [\n", + " {'name': 'Azimuth-Azimuth', 'code': 'azimuth-azimuth'}, \n", + " {'name': 'Distance-Angle', 'code': 'distance-angle'},\n", + " {'name': 'Distance-Azimuth', 'code': 'distance-azimuth'},\n", + " {'name': 'Distance-Distance', 'code': 'distance-distance'},\n", + " {'name': 'Azimuth-Azimuth-Backsight', 'code': 'azimuth-azimuth-backsight'},\n", + " {'name': 'Distance-Azimuth-Backsight', 'code': 'distance-azimuth-backsight'},\n", + " {'name': 'Distance-Distance-Backsight', 'code': 'distance-distance-backsight'},\n", + " {'name': 'User-defined', 'code': 'user-defined'}]}\n", + " \n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if offset_method_field[0]['domain'] is None or offset_method_field[0]['domain']['codedValues'] != offset_method_domain['codedValues']:\n", + "\n", + " offset_method_field[0]['domain'] = offset_method_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(offset_method_field[0])\n", "\n", " else:\n", " gnss_metadata_fields['fields'].append({'name': 'esrisnsr_offset_method',\n", @@ -594,7 +856,6 @@ " {'name': 'User-defined', 'code': 'user-defined'}]},\n", " 'defaultValue': None})\n", "\n", - "\n", " # esrisnsr_offset_device\n", " offset_device_field = [field for field in feature_layer_fields if\n", " field['name'].lower() == 'esrisnsr_offset_device']\n", @@ -609,21 +870,6 @@ " 'domain': None,\n", " 'defaultValue': None})\n", "\n", - "\n", - " # esrignss_antenna_height\n", - " antenna_height_field = [field for field in feature_layer_fields if\n", - " field['name'].lower() == 'esrignss_antenna_height']\n", - "\n", - " if not antenna_height_field:\n", - " gnss_metadata_fields['fields'].append({'name': 'esrignss_antenna_height',\n", - " 'type': 'esriFieldTypeDouble',\n", - " 'alias': 'GNSS Antenna height (m)',\n", - " 'sqlType': 'sqlTypeOther',\n", - " 'nullable': True,\n", - " 'editable': True,\n", - " 'domain': None,\n", - " 'defaultValue': None})\n", - "\n", " # esrisnsr_offset_laser_height\n", " laser_height_field = [field for field in feature_layer_fields if\n", " field['name'].lower() == 'esrisnsr_offset_laser_height']\n", @@ -752,24 +998,26 @@ "\n", " if cp1_fix_type_field:\n", " # Field does exist; check if the domain is set\n", - " if fix_type_field[0]['domain'] == None:\n", - " if ([operation for operation in operations if operation == 'updateDefinition']):\n", - " operations.append('updateDefinition')\n", - "\n", - " fix_type_field_index = feature_layer_fields.index(fix_type_field[0])\n", - " fix_type_domain = {'type': 'codedValue',\n", - " 'name': 'esri_fix_type_domain',\n", - " 'codedValues': [{'name': 'Fix not valid',\n", - " 'code': 0},\n", - " {'name': 'GPS', 'code': 1},\n", - " {'name': 'Differential GPS', 'code': 2},\n", - " {'name': 'RTK Fixed', 'code': 4},\n", - " {'name': 'RTK Float', 'code': 5}]}\n", - " feature_layer_fields[fix_type_field_index]['domain'] = fix_type_domain\n", "\n", + " fix_type_domain = {'type': 'codedValue',\n", + " 'name': 'esri_fix_type_domain',\n", + " 'codedValues': [{'name': 'Fix not valid',\n", + " 'code': 0},\n", + " {'name': 'GPS', 'code': 1},\n", + " {'name': 'Differential GPS', 'code': 2},\n", + " {'name': 'RTK Fixed', 'code': 4},\n", + " {'name': 'RTK Float', 'code': 5}]}\n", + "\n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if cp1_fix_type_field[0]['domain'] is None or cp1_fix_type_field[0]['domain']['codedValues'] != fix_type_domain['codedValues']:\n", + "\n", + " cp1_fix_type_field[0]['domain'] = fix_type_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(cp1_fix_type_field[0])\n", + " \n", " else:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_cp1_fixtype',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'CP1 Fix type',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -802,7 +1050,7 @@ "\n", " if not station_id_field:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_cp1_stationid',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'CP1 Station ID',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -815,7 +1063,7 @@ "\n", " if not cp1_num_sats_field: \n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_cp1_numsats',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'CP1 Number of satellites',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -1047,25 +1295,27 @@ " cp2_fix_type_field = [field for field in feature_layer_fields if field['name'].lower() == 'esrignss_cp2_fixtype']\n", "\n", " if cp2_fix_type_field:\n", - " # Field does exist; check if the domain is set\n", - " if fix_type_field[0]['domain'] == None:\n", - " if ([operation for operation in operations if operation == 'updateDefinition']):\n", - " operations.append('updateDefinition')\n", - "\n", - " fix_type_field_index = feature_layer_fields.index(fix_type_field[0])\n", - " fix_type_domain = {'type': 'codedValue',\n", - " 'name': 'esri_fix_type_domain',\n", - " 'codedValues': [{'name': 'Fix not valid',\n", - " 'code': 0},\n", - " {'name': 'GPS', 'code': 1},\n", - " {'name': 'Differential GPS', 'code': 2},\n", - " {'name': 'RTK Fixed', 'code': 4},\n", - " {'name': 'RTK Float', 'code': 5}]}\n", - " feature_layer_fields[fix_type_field_index]['domain'] = fix_type_domain\n", + " # Field does exist; check if the domain is correct\n", + "\n", + " fix_type_domain = {'type': 'codedValue',\n", + " 'name': 'esri_fix_type_domain',\n", + " 'codedValues': [{'name': 'Fix not valid',\n", + " 'code': 0},\n", + " {'name': 'GPS', 'code': 1},\n", + " {'name': 'Differential GPS', 'code': 2},\n", + " {'name': 'RTK Fixed', 'code': 4},\n", + " {'name': 'RTK Float', 'code': 5}]}\n", + "\n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if cp2_fix_type_field[0]['domain'] is None or cp2_fix_type_field[0]['domain']['codedValues'] != fix_type_domain['codedValues']:\n", + "\n", + " cp2_fix_type_field[0]['domain'] = fix_type_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(cp2_fix_type_field[0])\n", "\n", " else:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_cp2_fixtype',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'CP2 Fix type',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -1098,7 +1348,7 @@ "\n", " if not cp2_station_id_field:\n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_cp2_stationid',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'CP2 Station ID',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -1111,7 +1361,7 @@ "\n", " if not cp2_num_sats_field: \n", " gnss_metadata_fields['fields'].append({'name': 'esrignss_cp2_numsats',\n", - " 'type': 'esriFieldTypeInteger',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", " 'alias': 'CP2 Number of satellites',\n", " 'sqlType': 'sqlTypeOther',\n", " 'nullable': True,\n", @@ -1265,38 +1515,124 @@ "metadata": {}, "outputs": [], "source": [ - "# Check if AddToDefinition operation needs to be added.\n", - "initial_featurelayer_fields_count = len(feature_layer_fields)\n", - "if (len(gnss_metadata_fields[\n", - " 'fields']) + initial_featurelayer_fields_count\n", - " ) > initial_featurelayer_fields_count:\n", - " operations.append('addToDefinition')\n", - " \n", - "# Check if any changes are required\n", - "if not operations:\n", - " print(\"No changes to GPS metadata fields.\")\n", - "else:\n", - " # Add or update service definition\n", - " for operation in operations:\n", + "# Add tilt fields for tilt compensation workflows \n", + "if include_tilt_fields and geometry_type == 'esriGeometryPoint':\n", "\n", - " # Add\n", - " if operation == 'addToDefinition':\n", - " response = feature_layer.manager.add_to_definition(\n", - " gnss_metadata_fields)\n", - " print(\"Successfully added GPS metadata fields.\")\n", + " # esrignss_tilt_compensated\n", + " tilt_compensated_field = [field for field in feature_layer_fields if \n", + " field['name'].lower() == 'esrignss_tilt_compensated']\n", "\n", - " # Modify\n", - " else:\n", - " response = feature_layer.manager.update_definition(\n", - " feature_layer_fields)\n", - " print(\"Successfully updated GPS metadata fields.\")\n", + " if tilt_compensated_field:\n", + " # Field does exist; check if the domain is correct\n", + "\n", + " tilt_compensated_domain = {'type': 'codedValue',\n", + " 'name': 'esrignss_yesno_domain',\n", + " 'codedValues': [{'name': 'No', 'code': 0},\n", + " {'name': 'Yes', 'code': 1}]}\n", + " \n", + " # Check if the domain exists and if it matches the expected domain codes\n", + " if tilt_compensated_field[0]['domain'] is None or tilt_compensated_field[0]['domain']['codedValues'] != tilt_compensated_domain['codedValues']:\n", + "\n", + " tilt_compensated_field[0]['domain'] = tilt_compensated_domain\n", + "\n", + " gnss_metadata_fields_updated['fields'].append(tilt_compensated_field[0])\n", "\n", - " result = response['success']\n", + " else:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrignss_tilt_compensated',\n", + " 'type': 'esriFieldTypeSmallInteger',\n", + " 'alias': 'Tilt compensated',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': {'type': 'codedValue',\n", + " 'name': 'esrignss_yesno_domain',\n", + " 'codedValues': [\n", + " {'name': 'No', 'code': 0},\n", + " {'name': 'Yes', 'code': 1}]},\n", + " 'defaultValue': None})\n", + " \n", + " # esrisnsr_tilt_angle\n", + " tilt_angle_field = [field for field in feature_layer_fields if\n", + " field['name'].lower() == 'esrisnsr_tilt_angle']\n", + "\n", + " if not tilt_angle_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrisnsr_tilt_angle',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'Tilt angle (°)',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", + " # esrisnsr_tilt_angle_accuracy\n", + " tilt_angle_accuracy_field = [field for field in feature_layer_fields if\n", + " field['name'].lower() == 'esrisnsr_tilt_angle_accuracy']\n", + "\n", + " if not tilt_angle_accuracy_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrisnsr_tilt_angle_accuracy',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'Tilt angle accuracy (°)',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", + " # esrisnsr_tilt_azimuth\n", + " tilt_azimuth_field = [field for field in feature_layer_fields if\n", + " field['name'].lower() == 'esrisnsr_tilt_azimuth']\n", + "\n", + " if not tilt_azimuth_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrisnsr_tilt_azimuth',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'Tilt azimuth (°)',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n", + "\n", + " # esrisnsr_tilt_azimuth_accuracy\n", + " tilt_azimuth_accuracy_field = [field for field in feature_layer_fields if\n", + " field['name'].lower() == 'esrisnsr_tilt_azimuth_accuracy']\n", + "\n", + " if not tilt_azimuth_accuracy_field:\n", + " gnss_metadata_fields['fields'].append({'name': 'esrisnsr_tilt_azimuth_accuracy',\n", + " 'type': 'esriFieldTypeDouble',\n", + " 'alias': 'Tilt azimuth accuracy (°)',\n", + " 'sqlType': 'sqlTypeOther',\n", + " 'nullable': True,\n", + " 'editable': True,\n", + " 'domain': None,\n", + " 'defaultValue': None})\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "addToDefinition = bool(gnss_metadata_fields[\"fields\"])\n", + "updateDefinition = bool(gnss_metadata_fields_updated[\"fields\"])\n", + "\n", + "if not (addToDefinition or updateDefinition):\n", + " print(\"No changes to GPS metadata fields.\")\n", + "else:\n", + " if addToDefinition:\n", + " response = feature_layer.manager.add_to_definition(gnss_metadata_fields)\n", + " if not response.get(\"success\", False):\n", + " print(\"Failed to add to feature layer service definition.\")\n", + " else:\n", + " print(\"Successfully added GPS metadata fields.\")\n", "\n", - " if not result:\n", - " print('Failed to update Feature layer service definition.')\n", + " if updateDefinition:\n", + " response = feature_layer.manager.update_definition(gnss_metadata_fields_updated)\n", + " if not response.get(\"success\", False):\n", + " print(\"Failed to update feature layer service definition.\")\n", " else:\n", - " print('Service definition updated successfully.') " + " print(\"Successfully updated GPS metadata fields.\")" ] } ], diff --git a/notebooks/Add Offset Metadata Fields.ipynb b/notebooks/Add Offset Metadata Fields.ipynb index 99feb80..451655a 100644 --- a/notebooks/Add Offset Metadata Fields.ipynb +++ b/notebooks/Add Offset Metadata Fields.ipynb @@ -5,10 +5,9 @@ "metadata": {}, "source": [ "### Add Offset Metadata fields\n", + "This notebook is designed for use in ArcGIS Pro 3.2-3.4. See [this topic](https://doc.esri.com/en/arcgis-pro/latest/arcpy/get-started/pro-notebooks.html) For information on how to use Jupyter notebooks in ArcGIS Pro.\n", "\n", - "This notebook is designed for use in ArcGIS Pro 2.9+. See [this topic](https://pro.arcgis.com/en/pro-app/2.8/arcpy/get-started/pro-notebooks.htm) For information on how to use Jupyter notebooks in ArcGIS Pro.\n", - "\n", - "- Prior to running this script you should ensure that the [Add GPS Metadata Fields](https://pro.arcgis.com/en/pro-app/latest/tool-reference/data-management/add-gps-metadata-fields.htm) Geoprocessing tool has been run on the `input_feature_class`. \n", + "- For Pro 3.5+ use the [Add GPS Metadata Fields](https://pro.arcgis.com/en/pro-app/latest/tool-reference/data-management/add-gps-metadata-fields.htm) Geoprocessing tool instead of this notebook.\n", "- Use this script to update an existing point feature class to support offset workflows\n", "- This adds a series of fields and necessary coded value domains\n", "\n",