def writeMessageFile() : global DEBUG_GEOMETRY_CONVERSION, appendFile, foundEmptySIDC, FORCE_UNIQUE_IDs try : arcpy.AddMessage("Starting: Write/Append Message File") # Get input feature class inputFC = arcpy.GetParameter(0) if (inputFC == "") or (inputFC is None): inputFC = os.path.join(MilitaryUtilities.geoDatabasePath, r"/test_inputs.gdb/FriendlyOperations/FriendlyUnits") desc = arcpy.Describe(inputFC) if desc == None : arcpy.AddError("Bad Input Feature Class") return shapeType = desc.shapeType # Get output filename outputFile = arcpy.GetParameterAsText(1) # Get standard standard = arcpy.GetParameterAsText(2) # Message Type Field messageTypeField = arcpy.GetParameterAsText(3) # Sort Order orderBy = arcpy.GetParameterAsText(4) # Disable Geo Transformation and use default SIDC disableGeoTransform = arcpy.GetParameterAsText(5) if not ((disableGeoTransform == "") or (disableGeoTransform is None)) : DEBUG_GEOMETRY_CONVERSION = (disableGeoTransform.upper() == "TRUE") arcpy.AddMessage("Running with Parameters:") arcpy.AddMessage("0 - Input FC: " + str(inputFC)) arcpy.AddMessage("1 - outputXMLFile: " + str(outputFile)) arcpy.AddMessage("2 - symbology standard: " + str(standard)) arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField) arcpy.AddMessage("4 - orderBy: " + orderBy) arcpy.AddMessage("5 - disableGeoTransform: " + disableGeoTransform) # initialize the standard MilitaryUtilities.getGeometryConverterStandard(standard) if DEBUG_GEOMETRY_CONVERSION : arcpy.AddWarning("Running in Debug Geo-Transformation Mode, symbol will use default/unknown SIDC for shape") if not ((messageTypeField == "") or (messageTypeField is None)) : # make sure the messageTypeField exists in the input if messageTypeField in [field.name for field in desc.Fields] : MilitaryUtilities.MessageTypeField = messageTypeField else : arcpy.AddWarning("MessageTypeField does not exist in input: " + messageTypeField + " , using default") # Check Output Filename & see handle case if we are appending if (outputFile == "") or (outputFile is None) : # For a standalone test (debug) if no output filename provided if DEBUG_GEOMETRY_CONVERSION : defaultOutputName = "Mil2525CMessages-NoTransform.xml" else : defaultOutputName = "Mil2525CMessages.xml" outputFile = os.path.join(os.path.dirname(__file__), defaultOutputName) messageFile=open(outputFile, "w") arcpy.AddWarning("No Output set, using default: " + str(outputFile)) else: arcpy.AddMessage("Append File set to " + str(appendFile)) if (not appendFile) : messageFile = open(outputFile, "w") elif (not os.path.isfile(outputFile)) : arcpy.AddWarning("Can't Append: Output File does not exist, creating new file") messageFile = open(outputFile, "w") else : arcpy.AddMessage("Appending Existing File...") # Appending the file is a bit more complicated because we have to remove the # "</messages>" from the end of the original file therefore it can't just be # opened as an append "a+"-we have to create a temp file, read the original file in, # except for the line "</messages>", and then write back out fileToAppend = open(outputFile, "r") # Workaround/Note: didn't work in ArcCatalog unless I opened temp file this way temporaryFile = tempfile.NamedTemporaryFile(mode="w", delete=False) # Copy the file line by line, but don't include last end tag ex. </messages> finalTag = "</%s>" % MilitaryUtilities.getMessageRootTag() finalTagFound = False while True: line = fileToAppend.readline() if line : if not finalTag in line : # ex. "</messages>" temporaryFile.write(line) else : finalTagFound = True else : break if (not finalTagFound) : arcpy.AddError("XML Append File will be corrupt: Could not find Tag: " + finalTag) # now write those lines back fileToAppend.close() temporaryFile.close() messageFile = open(outputFile, "w") temporaryFile = open(temporaryFile.name, "r") while True: line = temporaryFile.readline() if line : messageFile.write(line) else : break temporaryFile.close() if (messageFile is None) : arcpy.AddError("Output file can't be created, exiting") return ##################Setup for export############################ # We need to set overwriteOutput=true or the tools below may fail previousOverwriteOutputSetting = arcpy.env.overwriteOutput arcpy.env.overwriteOutput = True # Densify if this is a polygon FC if ("Polygon" == shapeType): try : densifiedFC = "in_memory/DensifiedFC" arcpy.CopyFeatures_management(inputFC, densifiedFC) arcpy.Densify_edit(densifiedFC, "ANGLE", "", "", 10) inputFC = densifiedFC except : arcpy.AddWarning("Could not densify polygons, skipping. Densify_edit tool failed - is Desktop Standard License available?") # Get fields and coded domains CODE_FIELD_NAME = "code" DESCRIPTION_FIELD_NAME = "description" fieldNameList = [] fieldNameToDomainName = {} for field in desc.Fields: if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST): fieldNameList.append(field.name) # Get domain if any if (field.domain is not None and field.domain != ""): fieldNameToDomainName[field.name] = field.domain dataPath = desc.path gdbPath = dataPath.split(".gdb")[0] gdbPath += ".gdb" arcpy.DomainToTable_management(gdbPath, field.domain, "in_memory/" + field.domain, CODE_FIELD_NAME, DESCRIPTION_FIELD_NAME) # print fieldNameList # restore this setting (set above) arcpy.env.overwriteOutput = previousOverwriteOutputSetting # Projected or geographic? xname = "lon" yname = "lat" isProjected = desc.spatialReference.type == "Projected" if (isProjected): xname = "x" yname = "y" wkid = desc.spatialReference.factoryCode ################Begin Export ########################## # Open a search cursor (if possible) try : rows = arcpy.SearchCursor(inputFC, "", "", "", orderBy) except : arcpy.AddError("Could not open Feature Class " + str(inputFC)) if (not ((orderBy == "") and not (orderBy is None))) : arcpy.AddError("OrderBy Search Option: " + orderBy) raise Exception("Bad Feature Class Input") # Dictionary to map unique designation to ID unitDesignationToId = dict() featureFields = desc.fields ###################### Write XML file ######################### if not appendFile : # Ex: Next line writes: messageFile.write("<geomessages>\n") messageFile.write("<%s>\n" % MilitaryUtilities.getMessageRootTag()) rowCount = 0 # Iterate through the rows in the cursor for row in rows: shape = row.shape.getPart(0) arcpy.AddMessage("Processing row: " + str(rowCount)) ############################################## # Map Unique Names to same Unique IDs # IMPORTANT: this section tries to keep Unique Designations mapped to the # same Message Unique ID (so they will move in Message Processor), so... # WARNING: if you have repeated Unique Designations, # they are going to get mapped to the same Unique ID uniqueId = "{%s}" % str(uuid.uuid4()) uniqueDesignation = str(rowCount) # fallback value in case field does not exist try : uniqueDesignation = row.getValue(MilitaryUtilities.UniqueDesignationField) if ((uniqueDesignation is None) or (uniqueDesignation == "")) : arcpy.AddWarning("Unique Designation is Empty") elif (DEBUG_GEOMETRY_CONVERSION or FORCE_UNIQUE_IDs) : pass else : # Otherwise, see if we have seen this Designation before if (uniqueDesignation in unitDesignationToId): arcpy.AddMessage("Creating update message for repeated Unique Designation: " + uniqueDesignation) uniqueId = unitDesignationToId[uniqueDesignation] else: unitDesignationToId[uniqueDesignation] = uniqueId except: arcpy.AddWarning("Could not find Unique Designation field in row: " + str(rowCount)) ############################################## # work with "sidc" or "sic" try : SymbolIdCodeVal = row.getValue(MilitaryUtilities.SidcFieldChoice1) # "sic" except: try : SymbolIdCodeVal = row.getValue(MilitaryUtilities.SidcFieldChoice2) # "sidc" except: SymbolIdCodeVal = None # Note/Important: attributes need to be set in converter so needs declared before geometrytoControlPoints attributes = { } conversionNotes = None attributes[DictionaryConstants.Tag_Wkid] = wkid # needed by conversion if (SymbolIdCodeVal is None) or (SymbolIdCodeVal == "") : SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType(shapeType) if not (DEBUG_GEOMETRY_CONVERSION) : foundEmptySIDC = True msg = "SIDC is not set, using default: " + SymbolIdCodeVal arcpy.AddWarning(msg) elif DEBUG_GEOMETRY_CONVERSION : print "Using Debug SIDC" conversionNotes = "Original SIDC: " + SymbolIdCodeVal uniqueDesignation = SymbolIdCodeVal # use this label for debugging SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType(shapeType) controlPointsString = MilitaryUtilities.parseGeometryToControlPoints(shape) requiresConversion = MilitaryUtilities.geoConverter.requiresConversion(SymbolIdCodeVal) if requiresConversion and not DEBUG_GEOMETRY_CONVERSION : msg = "SIC: " + SymbolIdCodeVal + " requires conversion/translation" print msg arcpy.AddMessage(msg) transformedPoints, conversionNotes = \ MilitaryUtilities.geoConverter.geometrytoControlPoints(SymbolIdCodeVal, controlPointsString, attributes) if (conversionNotes == DictionaryConstants.CONVERSION_IGNORE_SECOND_LINE) : continue elif (transformedPoints is None) : arcpy.AddWarning("Conversion FAILED for SIC: " + SymbolIdCodeVal + \ ", Notes: " + conversionNotes + " (using original points)") else : controlPointsString = transformedPoints # Write Output Message # Ex: Next line writes: ex. "\t<geomessage v=\"1.0\">\n" messageFile.write("\t<%s v=\"%s\">\n" % (MilitaryUtilities.getMessageTag(), \ MilitaryUtilities.getMessageVersion())) messageFile.write("\t\t<sic>%s</sic>\n" % SymbolIdCodeVal) # Try to get a message type if the field exists try : messageTypeVal = row.getValue(MilitaryUtilities.MessageTypeField) messageFile.write("\t\t<_type>%s</_type>\n" % messageTypeVal) except : # if not default to position_report messageFile.write("\t\t<_type>%s</_type>\n" % DictionaryConstants.DefaultMessageType) ##TODO: see if other actions are valid besides just "update" messageFile.write("\t\t<_action>%s</_action>\n" % DictionaryConstants.DefaultMessageAction) # = update messageFile.write("\t\t<_id>%s</_id>\n" % uniqueId) messageFile.write("\t\t<_control_points>%s</_control_points>\n" % controlPointsString) if not ((conversionNotes is None) or (conversionNotes == "")) : messageFile.write("\t\t<ConversionNotes>%s</ConversionNotes>\n" % conversionNotes) # Note: written with attributes below: messageFile.write("\t\t<_wkid>%i</_wkid>\n" % wkid) if not ((uniqueDesignation is None) or (uniqueDesignation == "")) : messageFile.write("\t\t<%s>%s</%s>\n" % (DictionaryConstants.Tag_UniqueDesignation, \ uniqueDesignation, DictionaryConstants.Tag_UniqueDesignation)) # Check on Military Geometries for Lines/Areas if (shapeType is "Point"): messageFile.write("\t\t<altitude_depth>%d</altitude_depth>\n" % shape.Z) rowCount = rowCount + 1 messageFile.write("\t\t<MessageCount>%s</MessageCount>\n" % str(rowCount)) for key in attributes : attrValAsString = str(attributes[key]) messageFile.write("\t\t<"+key+">" + attrValAsString + "</" + key + ">\n") ###################Common Fields/Attributes##################### # Write out remaining table fields as Tag attributes for field in fieldNameList: try : # But don't repeat existing tags we've created if field in DictionaryConstants.MESSAGES_TAG_LIST : rowVal = None else : rowVal = row.getValue(field) except : print "Could not get row val for field" + field rowVal = None if rowVal is not None: try: fieldValAsString = str(row.getValue(field)) messageFile.write("\t\t<"+field+">" + fieldValAsString + "</" + field + ">\n") except: #fixed issue #19 fieldValAsString = row.getValue(field) decodedstring = fieldValAsString.encode('ascii', 'ignore') arcpy.AddMessage("trying to fix unicode problem, changing " + fieldValAsString + " -> " + decodedstring) messageFile.write("\t\t<"+field+">" + decodedstring + "</" + field + ">\n") ###################Common Fields/Attributes##################### # Ex: messageFile.write("\t</geomessage>\n") messageFile.write("\t</%s>\n" % MilitaryUtilities.getMessageTag()) # Ex: messageFile.write("</geomessages>") messageFile.write("</%s>\n" % MilitaryUtilities.getMessageRootTag()) arcpy.AddMessage("Rows Processed: " + str(rowCount)) if foundEmptySIDC : arcpy.AddWarning("IMPORTANT: Some rows did not have SIDC set - you may need to run CalcSIDCField tool first.") arcpy.AddMessage("Write/Append Message File Complete") except: print "Exception: " tb = traceback.format_exc() print tb arcpy.AddError("Exception") arcpy.AddError(tb)
def writeFeaturesFromMessageFile() : foundEmptyRuleId = False # used to detect if we can not set a RuleID for any rows # Get the input message file inputFileName = arcpy.GetParameterAsText(0) if (inputFileName == "") or (inputFileName is None): inputFileName = os.path.join(MilitaryUtilities.dataPath, r"/messages/Mil2525CMessages.xml") if not os.path.isfile(inputFileName) : arcpy.AddError("Bad Input File: " + inputFileName) return inputFile=open(inputFileName, "r") if (inputFile is None) : arcpy.AddError("Input file can't be opened, exiting") return # Get the output feature class outputFC = arcpy.GetParameter(1) if (outputFC == "") or (outputFC is None): outputFC = os.path.join(MilitaryUtilities.dataPath, r"/test_outputs.gdb/FriendlyOperations/FriendlyUnits") desc = arcpy.Describe(outputFC) if desc is None : arcpy.AddError("Can't open Output Dataset: " + str(outputFC)) return shapeType = desc.shapeType # Get standard standard = arcpy.GetParameterAsText(2) # Message Type Field messageTypeField = arcpy.GetParameterAsText(3) arcpy.AddMessage("Running with Parameters:") arcpy.AddMessage("0 - input XML File: " + str(inputFileName)) arcpy.AddMessage("1 - output FC: " + str(outputFC)) arcpy.AddMessage("2 - symbology standard: " + str(standard)) arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField) if not ((messageTypeField == "") or (messageTypeField is None)) : if desc.Fields.contains(messageTypeField) : MilitaryUtilities.MessageTypeField = messageTypeField else : arcpy.AddWarning("MessageTypeField does not exist in output: " + MessageTypeField + " , using default") print "Exporting message objects from: " + str(inputFileName) print "To Feature Class: " + str(outputFC) print "That match shape type: " + shapeType # initialize the standard MilitaryUtilities.getGeometryConverterStandard(standard) ruleFieldName = MilitaryUtilities.symbolDictionary.initializeRulesByMilitaryFeatures(outputFC) if (ruleFieldName == "") or (ruleFieldName is None) : arcpy.AddError("RuleFieldName not found, exiting") return # Projected or geographic? xname = "lon" yname = "lat" isProjected = desc.spatialReference.type == "Projected" if (isProjected): xname = "x" yname = "y" outputWkid = desc.spatialReference.factoryCode ################Begin Export ########################## featureFields = desc.fields # Iterate through the messages and check the shape WRITE_OUTPUT = True # debug switch when output not needed newRow = None newRows = None try : if WRITE_OUTPUT : newRows = arcpy.InsertCursor(outputFC) messageCount = 0 # for each message in the message file, get its attributes and copy to the output FeatureClass for sic, controlPoints, attributes in MessageIterator.MessageIterator(inputFileName) : print sic, controlPoints, attributes geoType = MilitaryUtilities.geoConverter.expectedGeometryType(sic) if not DictionaryConstants.isCorrectShapeTypeForFeature(geoType, shapeType) : skipMsg = "Skipping SIC: " + sic + " - does not match feature type" + shapeType arcpy.AddMessage(skipMsg) continue # Used for those SICs that map to 2 lines (ex. Task Screen/Guard/Cover) repeatForPairFeatures = True repeatCount = 0 while repeatForPairFeatures : outputPointList, conversionNotes = MilitaryUtilities.geoConverter.controlPointsToGeometry(sic, controlPoints, attributes) if outputPointList is None : msg = "Failed to Convert Points from Military to MilFeature format for SIDC: " + sic arcpy.AddError(msg) arcpy.AddError("Conversion Notes: " + conversionNotes) repeatForPairFeatures = False continue inputWkid = 0 if attributes.has_key(DictionaryConstants.Tag_Wkid) : inputWkid = int(attributes[DictionaryConstants.Tag_Wkid]) if outputWkid != inputWkid : msg = "ERROR: Input Message and Output Feature WKIDs do not match (InsertFeature will fail)" arcpy.AddError(msg) msg = "Output WKID = " + str(outputWkid) + " , Input WKID = " + str(inputWkid) arcpy.AddError(msg) ruleId, symbolName = MilitaryUtilities.symbolDictionary.symbolIdToRuleId(sic) if ruleId < 0 : foundEmptyRuleId = True # arcpy.AddWarning("WARNING: Could not map ruleId to SIDC: " + sic) # For those SIC that map to 2 lines (ex. Task Screen/Guard/Cover) # will need to clone/repeat the message here for Left/Right Upper/Lower pair repeatForPairFeatures = False geoConversion = MilitaryUtilities.symbolDictionary.symbolIdToGeometryConversionType(sic) if (geoConversion == DictionaryConstants.GCT_TWOLINE) or \ (geoConversion == DictionaryConstants.GCT_TWOLINE3OR4PT) : if repeatCount > 0 : repeatForPairFeatures = False # Only do once ## TODO: find better way to set rule Id for 2nd line (Left/Right) version # This is quite kludgy, and relies on the 2nd ruleid code being the 1st + 1 # and this may not always be the case ruleId = ruleId + 1 else : repeatForPairFeatures = True attributes[DictionaryConstants.Tag_TwoLinesNeeded] = "True" # don't let id get repeated, so append "_2" if attributes.has_key(DictionaryConstants.Tag_Id) : attributes[DictionaryConstants.Tag_Id] = attributes[DictionaryConstants.Tag_Id] + "_2" repeatCount = repeatCount + 1 arcpy.AddMessage("Adding feature #" + str(messageCount) + " with SIDC: " + sic) if WRITE_OUTPUT : try : shape = MilitaryUtilities.pointsToArcPyGeometry(outputPointList, shapeType) newRow = newRows.newRow() newRow.setValue(desc.shapeFieldName, shape) newRow.setValue(ruleFieldName, ruleId) # both "sic" and "sidc" used try : newRow.setValue("sic", sic) except : try : newRow.setValue("sidc", sic) except : arcpy.AddWarning("Failed to set SIDC field in output") # add any extra fields for field in featureFields : if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST) : lowerFieldName = field.name.lower() # we don't the case of the attribute so have to search for key in attributes.keys() : lowerKey = key.lower() if (lowerKey == lowerFieldName) : try : newRow.setValue(field.name, attributes[key]) except : print "Could not add: Field: " + field.name + ", Value: " + str(attributes[key]) newRows.insertRow(newRow) arcpy.AddMessage("Message successfully added: " + str(messageCount)) except : arcpy.AddError("ERROR: Exception while adding new feature (does Spatial Ref match?)") tb = traceback.format_exc() print tb else : print "WRITING OUTPUT:" print "SIC: " + sic + ", Name: " + symbolName print "Adding geometry to feature, with points: " for point in outputPointList : x = point.split(',')[0] y = point.split(',')[1] print "(", x, ",", y, ")" messageCount += 1 if messageCount == 0 : arcpy.AddWarning("No Messages Found in Input") if foundEmptyRuleId : arcpy.AddWarning("IMPORTANT: Some rows do not have Symbol RuleId set - you may need to run CalcRepRuleField tool.") except : tb = traceback.format_exc() arcpy.AddError("Exception:") arcpy.AddError(tb) finally : # Delete cursor and row objects to remove locks on the data if not newRow is None : del newRow if not newRows is None : del newRows
def writeMessageFile(): global DEBUG_GEOMETRY_CONVERSION, appendFile, foundEmptySIDC, FORCE_UNIQUE_IDs try: arcpy.AddMessage("Starting: Write/Append Message File") # Get input feature class inputFC = arcpy.GetParameter(0) if (inputFC == "") or (inputFC is None): inputFC = os.path.join( MilitaryUtilities.dataPath, r"/test_inputs.gdb/FriendlyOperations/FriendlyUnits") desc = arcpy.Describe(inputFC) if desc is None: arcpy.AddError("Bad Input Feature Class") return shapeType = desc.shapeType # Get output filename outputFile = arcpy.GetParameterAsText(1) # Get standard standard = arcpy.GetParameterAsText(2) # Message Type Field messageTypeField = arcpy.GetParameterAsText(3) # Sort Order orderBy = arcpy.GetParameterAsText(4) # Disable Geo Transformation and use default SIDC disableGeoTransform = arcpy.GetParameterAsText(5) if not ((disableGeoTransform == "") or (disableGeoTransform is None)): DEBUG_GEOMETRY_CONVERSION = (disableGeoTransform.upper() == "TRUE") arcpy.AddMessage("Running with Parameters:") arcpy.AddMessage("0 - Input FC: " + str(inputFC)) arcpy.AddMessage("1 - outputXMLFile: " + str(outputFile)) arcpy.AddMessage("2 - symbology standard: " + str(standard)) arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField) arcpy.AddMessage("4 - orderBy: " + orderBy) arcpy.AddMessage("5 - disableGeoTransform: " + disableGeoTransform) # initialize the standard MilitaryUtilities.getGeometryConverterStandard(standard) if DEBUG_GEOMETRY_CONVERSION: arcpy.AddWarning( "Running in Debug Geo-Transformation Mode, symbol will use default/unknown SIDC for shape" ) if not ((messageTypeField == "") or (messageTypeField is None)): # make sure the messageTypeField exists in the input if messageTypeField in [field.name for field in desc.Fields]: MilitaryUtilities.MessageTypeField = messageTypeField else: arcpy.AddWarning("MessageTypeField does not exist in input: " + messageTypeField + " , using default") # Check Output Filename & see handle case if we are appending if (outputFile == "") or (outputFile is None): # For a standalone test (debug) if no output filename provided if DEBUG_GEOMETRY_CONVERSION: defaultOutputName = "Mil2525CMessages-NoTransform.xml" else: defaultOutputName = "Mil2525CMessages.xml" outputFile = os.path.join(os.path.dirname(__file__), defaultOutputName) messageFile = open(outputFile, "w") arcpy.AddWarning("No Output set, using default: " + str(outputFile)) else: arcpy.AddMessage("Append File set to " + str(appendFile)) if (not appendFile): messageFile = open(outputFile, "w") elif (not os.path.isfile(outputFile)): arcpy.AddWarning( "Can't Append: Output File does not exist, creating new file" ) messageFile = open(outputFile, "w") else: arcpy.AddMessage("Appending Existing File...") # Appending the file is a bit more complicated because we have to remove the # "</messages>" from the end of the original file therefore it can't just be # opened as an append "a+"-we have to create a temp file, read the original file in, # except for the line "</messages>", and then write back out fileToAppend = open(outputFile, "r") # Workaround/Note: didn't work in ArcCatalog unless I opened temp file this way temporaryFile = tempfile.NamedTemporaryFile(mode="w", delete=False) # Copy the file line by line, but don't include last end tag ex. </messages> finalTag = "</%s>" % MilitaryUtilities.getMessageRootTag() finalTagFound = False while True: line = fileToAppend.readline() if line: if not finalTag in line: # ex. "</messages>" temporaryFile.write(line) else: finalTagFound = True else: break if (not finalTagFound): arcpy.AddError( "XML Append File will be corrupt: Could not find Tag: " + finalTag) # now write those lines back fileToAppend.close() temporaryFile.close() messageFile = open(outputFile, "w") temporaryFile = open(temporaryFile.name, "r") while True: line = temporaryFile.readline() if line: messageFile.write(line) else: break temporaryFile.close() if (messageFile is None): arcpy.AddError("Output file can't be created, exiting") return ##################Setup for export############################ # We need to set overwriteOutput=true or the tools below may fail previousOverwriteOutputSetting = arcpy.env.overwriteOutput arcpy.env.overwriteOutput = True # Densify if this is a polygon FC if (shapeType == "Polygon"): try: densifiedFC = "in_memory/DensifiedFC" arcpy.CopyFeatures_management(inputFC, densifiedFC) arcpy.Densify_edit(densifiedFC, "ANGLE", "", "", 10) inputFC = densifiedFC except: arcpy.AddWarning( "Could not densify polygons, skipping. Densify_edit tool failed - is Desktop Standard License available?" ) # Get fields and coded domains CODE_FIELD_NAME = "code" DESCRIPTION_FIELD_NAME = "description" fieldNameList = [] fieldNameToDomainName = {} for field in desc.Fields: if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST): fieldNameList.append(field.name) # Get domain if any if (field.domain is not None and field.domain != ""): fieldNameToDomainName[field.name] = field.domain dataPath = desc.path gdbPath = dataPath.split(".gdb")[0] gdbPath += ".gdb" arcpy.DomainToTable_management(gdbPath, field.domain, "in_memory/" + field.domain, CODE_FIELD_NAME, DESCRIPTION_FIELD_NAME) # print fieldNameList # restore this setting (set above) arcpy.env.overwriteOutput = previousOverwriteOutputSetting # Projected or geographic? xname = "lon" yname = "lat" isProjected = desc.spatialReference.type == "Projected" if (isProjected): xname = "x" yname = "y" wkid = desc.spatialReference.factoryCode ################Begin Export ########################## # Open a search cursor (if possible) try: rows = arcpy.SearchCursor(inputFC, "", "", "", orderBy) except: arcpy.AddError("Could not open Feature Class " + str(inputFC)) if (not ((orderBy == "") and not (orderBy is None))): arcpy.AddError("OrderBy Search Option: " + orderBy) raise Exception("Bad Feature Class Input") # Dictionary to map unique designation to ID unitDesignationToId = dict() featureFields = desc.fields ###################### Write XML file ######################### if not appendFile: # Ex: Next line writes: messageFile.write("<geomessages>\n") messageFile.write("<%s>\n" % MilitaryUtilities.getMessageRootTag()) rowCount = 0 # Iterate through the rows in the cursor for row in rows: shape = row.shape.getPart(0) arcpy.AddMessage("Processing row: " + str(rowCount)) ############################################## # Map Unique Names to same Unique IDs # IMPORTANT: this section tries to keep Unique Designations mapped to the # same Message Unique ID (so they will move in Message Processor), so... # WARNING: if you have repeated Unique Designations, # they are going to get mapped to the same Unique ID uniqueId = "{%s}" % str(uuid.uuid4()) uniqueDesignation = str( rowCount) # fallback value in case field does not exist try: uniqueDesignation = row.getValue( MilitaryUtilities.UniqueDesignationField) if ((uniqueDesignation is None) or (uniqueDesignation == "")): arcpy.AddWarning("Unique Designation is Empty") elif (DEBUG_GEOMETRY_CONVERSION or FORCE_UNIQUE_IDs): pass else: # Otherwise, see if we have seen this Designation before if (uniqueDesignation in unitDesignationToId): arcpy.AddMessage( "Creating update message for repeated Unique Designation: " + uniqueDesignation) uniqueId = unitDesignationToId[uniqueDesignation] else: unitDesignationToId[uniqueDesignation] = uniqueId except: arcpy.AddWarning( "Could not find Unique Designation field in row: " + str(rowCount)) ############################################## # work with "sidc" or "sic" try: SymbolIdCodeVal = row.getValue( MilitaryUtilities.SidcFieldChoice1) # "sic" except: try: SymbolIdCodeVal = row.getValue( MilitaryUtilities.SidcFieldChoice2) # "sidc" except: SymbolIdCodeVal = None # Note/Important: attributes need to be set in converter so needs declared before geometrytoControlPoints attributes = {} conversionNotes = None attributes[ DictionaryConstants.Tag_Wkid] = wkid # needed by conversion if (SymbolIdCodeVal is None) or (SymbolIdCodeVal == ""): SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType( shapeType) if not (DEBUG_GEOMETRY_CONVERSION): foundEmptySIDC = True msg = "SIDC is not set, using default: " + SymbolIdCodeVal arcpy.AddWarning(msg) # TODO: we may need to add an option to Disable the geometry conversion # *but* not to change the SIDC to the default one, if you don't want the SIDC to change # when "Disable Geometry Conversion" is checked, comment/uncomment thses lines to # set this to false/disable this behavior: # elif False : elif DEBUG_GEOMETRY_CONVERSION: print "Using Debug SIDC" conversionNotes = "Original SIDC: " + SymbolIdCodeVal uniqueDesignation = SymbolIdCodeVal # use this label for debugging SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType( shapeType) controlPointsString = MilitaryUtilities.parseGeometryToControlPoints( shape) requiresConversion = MilitaryUtilities.geoConverter.requiresConversion( SymbolIdCodeVal) if requiresConversion and not DEBUG_GEOMETRY_CONVERSION: msg = "SIC: " + SymbolIdCodeVal + " requires conversion/translation" print msg arcpy.AddMessage(msg) transformedPoints, conversionNotes = \ MilitaryUtilities.geoConverter.geometrytoControlPoints(SymbolIdCodeVal, controlPointsString, attributes) if (conversionNotes == DictionaryConstants.CONVERSION_IGNORE_SECOND_LINE): continue elif (transformedPoints is None): arcpy.AddWarning("Conversion FAILED for SIC: " + SymbolIdCodeVal + \ ", Notes: " + conversionNotes + " (using original points)") else: controlPointsString = transformedPoints # Write Output Message # Ex: Next line writes: ex. "\t<geomessage v=\"1.0\">\n" messageFile.write("\t<%s v=\"%s\">\n" % (MilitaryUtilities.getMessageTag(), \ MilitaryUtilities.getMessageVersion())) messageFile.write("\t\t<sic>%s</sic>\n" % SymbolIdCodeVal) # Try to get a message type if the field exists try: messageTypeVal = row.getValue( MilitaryUtilities.MessageTypeField) messageFile.write("\t\t<_type>%s</_type>\n" % messageTypeVal) except: # if not default to position_report messageFile.write("\t\t<_type>%s</_type>\n" % DictionaryConstants.DefaultMessageType) ##TODO: see if other actions are valid besides just "update" messageFile.write( "\t\t<_action>%s</_action>\n" % DictionaryConstants.DefaultMessageAction) # = update messageFile.write("\t\t<_id>%s</_id>\n" % uniqueId) messageFile.write("\t\t<_control_points>%s</_control_points>\n" % controlPointsString) if not ((conversionNotes is None) or (conversionNotes == "")): messageFile.write( "\t\t<ConversionNotes>%s</ConversionNotes>\n" % conversionNotes) # Note: written with attributes below: messageFile.write("\t\t<_wkid>%i</_wkid>\n" % wkid) if not ((uniqueDesignation is None) or (uniqueDesignation == "")): messageFile.write("\t\t<%s>%s</%s>\n" % (DictionaryConstants.Tag_UniqueDesignation, \ uniqueDesignation, DictionaryConstants.Tag_UniqueDesignation)) # Check on Military Geometries for Lines/Areas if (shapeType is "Point"): messageFile.write("\t\t<altitude_depth>%d</altitude_depth>\n" % shape.Z) rowCount = rowCount + 1 messageFile.write("\t\t<MessageCount>%s</MessageCount>\n" % str(rowCount)) for key in attributes: attrValAsString = str(attributes[key]) messageFile.write("\t\t<" + key + ">" + attrValAsString + "</" + key + ">\n") ###################Common Fields/Attributes##################### # Write out remaining table fields as Tag attributes for field in fieldNameList: try: # But don't repeat existing tags we've created if field in DictionaryConstants.MESSAGES_TAG_LIST: rowVal = None else: rowVal = row.getValue(field) except: print "Could not get row val for field" + field rowVal = None if (rowVal is not None) and (rowVal != ''): try: fieldValAsString = str(row.getValue(field)) messageFile.write("\t\t<" + field + ">" + fieldValAsString + "</" + field + ">\n") except: #fixed issue #19 fieldValAsString = row.getValue(field) decodedstring = fieldValAsString.encode( 'ascii', 'ignore') arcpy.AddMessage( "trying to fix unicode problem, changing " + fieldValAsString + " -> " + decodedstring) messageFile.write("\t\t<" + field + ">" + decodedstring + "</" + field + ">\n") ###################Common Fields/Attributes##################### # Ex: messageFile.write("\t</geomessage>\n") messageFile.write("\t</%s>\n" % MilitaryUtilities.getMessageTag()) # Ex: messageFile.write("</geomessages>") messageFile.write("</%s>\n" % MilitaryUtilities.getMessageRootTag()) arcpy.AddMessage("Rows Processed: " + str(rowCount)) if foundEmptySIDC: arcpy.AddWarning( "IMPORTANT: Some rows did not have SIDC set - you may need to run CalcSIDCField tool first." ) arcpy.AddMessage("Write/Append Message File Complete") except: print "Exception: " tb = traceback.format_exc() print tb arcpy.AddError("Exception") arcpy.AddError(tb)
def RunTests() : TestRotateAndScale() TestGeoConversionProblem() try: print("Starting Test: TestGeometryConverter") # load this library not in the local dir or pythonpath, so we can test it: # assumes it is run from the current dir & exists at this relative location sys.path.append('../../../toolboxes/scripts') import MilitaryUtilities standard = "2525" geometryConverter = MilitaryUtilities.getGeometryConverterStandard(standard) RunTests() print "Test Successful" except: # Get the traceback object tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] # Concatenate information together concerning the error into a message string pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1]) # Print Python error messages for use in Python / Python Window print pymsg + "\n"
def writeFeaturesFromMessageFile() : foundEmptyRuleId = False # used to detect if we can not set a RuleID for any rows # Get the input message file inputFileName = arcpy.GetParameterAsText(0) if (inputFileName == "") or (inputFileName is None): inputFileName = os.path.join(MilitaryUtilities.dataPath, r"/messages/Mil2525CMessages.xml") if not os.path.isfile(inputFileName) : arcpy.AddError("Bad Input File: " + inputFileName) return inputFile=open(inputFileName, "r") if (inputFile is None) : arcpy.AddError("Input file can't be opened, exiting") return # Get the output feature class outputFC = arcpy.GetParameter(1) if (outputFC == "") or (outputFC is None): outputFC = os.path.join(MilitaryUtilities.geoDatabasePath, r"/test_outputs.gdb/FriendlyOperations/FriendlyUnits") desc = arcpy.Describe(outputFC) if desc == None : arcpy.AddError("Can't open Output Dataset: " + str(outputFC)) return shapeType = desc.shapeType; # Get standard standard = arcpy.GetParameterAsText(2) # Message Type Field messageTypeField = arcpy.GetParameterAsText(3) arcpy.AddMessage("Running with Parameters:") arcpy.AddMessage("0 - input XML File: " + str(inputFileName)) arcpy.AddMessage("1 - output FC: " + str(outputFC)) arcpy.AddMessage("2 - symbology standard: " + str(standard)) arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField) if not ((messageTypeField == "") or (messageTypeField is None)) : if desc.Fields.contains(field) : MilitaryUtilities.MessageTypeField = messageTypeField else : arcpy.AddWarning("MessageTypeField does not exist in output: " + MessageTypeField + " , using default") print "Exporting message objects from: " + str(inputFileName) print "To Feature Class: " + str(outputFC) print "That match shape type: " + shapeType # initialize the standard MilitaryUtilities.getGeometryConverterStandard(standard) ruleFieldName = MilitaryUtilities.symbolDictionary.initializeRulesByMilitaryFeatures(outputFC) if (ruleFieldName == "") or (ruleFieldName is None) : arcpy.AddError("RuleFieldName not found, exiting") return # Projected or geographic? xname = "lon" yname = "lat" isProjected = desc.spatialReference.type == "Projected" if (isProjected): xname = "x" yname = "y" outputWkid = desc.spatialReference.factoryCode ################Begin Export ########################## featureFields = desc.fields # Iterate through the messages and check the shape WRITE_OUTPUT = True # debug switch when output not needed newRow = None newRows = None try : if WRITE_OUTPUT : newRows = arcpy.InsertCursor(outputFC) messageCount = 0 # for each message in the message file, get its attributes and copy to the output FeatureClass for sic, controlPoints, attributes in MessageIterator.MessageIterator(inputFileName) : print sic, controlPoints, attributes geoType = MilitaryUtilities.geoConverter.expectedGeometryType(sic) if not DictionaryConstants.isCorrectShapeTypeForFeature(geoType, shapeType) : skipMsg = "Skipping SIC: " + sic + " - does not match feature type" + shapeType arcpy.AddMessage(skipMsg) continue # Used for those SICs that map to 2 lines (ex. Task Screen/Guard/Cover) repeatForPairFeatures = True repeatCount = 0 while repeatForPairFeatures : outputPointList, conversionNotes = MilitaryUtilities.geoConverter.controlPointsToGeometry(sic, controlPoints, attributes) if outputPointList == None : msg = "Failed to Convert Points from Military to MilFeature format for SIDC: " + sic arcpy.AddError(msg) arcpy.AddError("Conversion Notes: " + conversionNotes) repeatForPairFeatures = False continue inputWkid = 0 if attributes.has_key(DictionaryConstants.Tag_Wkid) : inputWkid = int(attributes[DictionaryConstants.Tag_Wkid]) if outputWkid != inputWkid : msg = "ERROR: Input Message and Output Feature WKIDs do not match (InsertFeature will fail)" arcpy.AddError(msg) msg = "Output WKID = " + str(outputWkid) + " , Input WKID = " + str(inputWkid) arcpy.AddError(msg) ruleId, symbolName = MilitaryUtilities.symbolDictionary.symbolIdToRuleId(sic) if ruleId < 0 : foundEmptyRuleId = True # arcpy.AddWarning("WARNING: Could not map ruleId to SIDC: " + sic) # For those SIC that map to 2 lines (ex. Task Screen/Guard/Cover) # will need to clone/repeat the message here for Left/Right Upper/Lower pair repeatForPairFeatures = False geoConversion = MilitaryUtilities.symbolDictionary.symbolIdToGeometryConversionType(sic) if (geoConversion == DictionaryConstants.GCT_TWOLINE) or \ (geoConversion == DictionaryConstants.GCT_TWOLINE3OR4PT) : if repeatCount > 0 : repeatForPairFeatures = False # Only do once ## TODO: find better way to set rule Id for 2nd line (Left/Right) version # This is quite kludgy, and relies on the 2nd ruleid code being the 1st + 1 # and this may not always be the case ruleId = ruleId + 1 else : repeatForPairFeatures = True attributes[DictionaryConstants.Tag_TwoLinesNeeded] = "True" # don't let id get repeated, so append "_2" if attributes.has_key(DictionaryConstants.Tag_Id) : attributes[DictionaryConstants.Tag_Id] = attributes[DictionaryConstants.Tag_Id] + "_2" repeatCount = repeatCount + 1 arcpy.AddMessage("Adding feature #" + str(messageCount) + " with SIDC: " + sic) if WRITE_OUTPUT : try : shape = MilitaryUtilities.pointsToArcPyGeometry(outputPointList, shapeType) newRow = newRows.newRow() newRow.setValue(desc.shapeFieldName, shape) newRow.setValue(ruleFieldName, ruleId) # both "sic" and "sidc" used try : newRow.setValue("sic", sic) except : try : newRow.setValue("sidc", sic) except : arcpy.AddWarning("Failed to set SIDC field in output") # add any extra fields for field in featureFields : if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST) : lowerFieldName = field.name.lower() # we don't the case of the attribute so have to search for key in attributes.keys() : lowerKey = key.lower() if (lowerKey == lowerFieldName) : try : newRow.setValue(field.name, attributes[key]) except : print "Could not add: Field: " + field.name + ", Value: " + str(attributes[key]) newRows.insertRow(newRow) arcpy.AddMessage("Message successfully added: " + str(messageCount)) except : arcpy.AddError("ERROR: Exception while adding new feature (does Spatial Ref match?)") tb = traceback.format_exc() print tb else : print "WRITING OUTPUT:" print "SIC: " + sic + ", Name: " + symbolName print "Adding geometry to feature, with points: " for point in outputPointList : x = point.split(',')[0] y = point.split(',')[1] print "(", x, ",", y, ")" messageCount += 1 if messageCount == 0 : arcpy.AddWarning("No Messages Found in Input") if foundEmptyRuleId : arcpy.AddWarning("IMPORTANT: Some rows do not have Symbol RuleId set - you may need to run CalcRepRuleField tool.") except : tb = traceback.format_exc() arcpy.AddError("Exception:") arcpy.AddError(tb) finally : # Delete cursor and row objects to remove locks on the data if not newRow is None : del newRow if not newRows is None : del newRows
TestRotateAndScale() TestGeoConversionProblem() try: print("Starting Test: TestGeometryConverter") # load this library not in the local dir or pythonpath, so we can test it: # assumes it is run from the current dir & exists at this relative location sys.path.append('../../../toolboxes/scripts') import MilitaryUtilities standard = "2525" geometryConverter = MilitaryUtilities.getGeometryConverterStandard( standard) RunTests() print "Test Successful" except: # Get the traceback object tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] # Concatenate information together concerning the error into a message string pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str( sys.exc_info()[1]) # Print Python error messages for use in Python / Python Window