Select to view content in your preferred language

How to solve type mismatches in object attributes that prevent a FileGDB export

266
0
05-23-2024 12:01 AM
JonasObertuefer
Esri Contributor
3 0 266

In CityEngine the type of an object attribute’s value does not have to be the same across multiple shapes, but this is a requirement for Esri’s FileGDB format. If such a type mismatch is present in your scene, the export to FileGDB will fail with the following message:

JonasObertuefer_0-1716390408972.png

The batch export completed but at least one error occurred. See export logfile for detailed error information.

If you inspect the details of the entry in the Log (Window -> Log -> Select entry -> Context Menu -> Event Details) you can find a line similar to the one below at the top of the Exception Stack Trace:

java.lang.IllegalArgumentException: esriFieldTypeDouble

The reason for this is that CityEngine checks the type of the value and sets it accordingly when adding object attributes to a shape. A typical example are house numbers: A number with the value 12 will be of type float but one with 12a will be of type string. This is very common for shapes imported from Get Map Data / OSM.

 

Solution: Don’t export object attributes

The simple workaround is to not export the object attributes in the first place by unchecking the “Export object attributes” option under General Settings in the FileGDB export.

JonasObertuefer_1-1716390534023.png

 

Solution: Align object attributes type using python

If object attributes are required for further processing, you need to make sure that the value of all attributes with the same name are of the same type before exporting. This can be achieved using python scripting:

 

'''
@version: 1.0
@author: Esri R&D Center Zurich
'''

from scripting import *


# get a CityEngine instance
ce = CE()

def findTypeMismatches(objects):
    allAttributes = {}
    mismatchAttributes = []
    
    print("object attributes type mismatch:")
    for object in objects:
        attributes = ce.getAttributeList(object)
        for attr in attributes:
            if not attr.startswith('/'):  # only check object attributes
                attrType = type(ce.getAttribute(object, attr))  
                if attr not in allAttributes:
                    allAttributes[attr] = [attrType,ce.getOID(object)]
                else:
                    if allAttributes[attr][0] != 0:
                        if allAttributes[attr][0] != attrType:
                            mismatchAttributes.append(attr)
                            print("Attribute " + attr +
                                  " is of " + str(attrType) + 
                                  " in OID: " + ce.getOID(object) + 
                                  " ref is of " + str(allAttributes[attr][0]) + 
                                  " in OID: " + allAttributes[attr][1])
                            allAttributes[attr][0] = 0
    
    return mismatchAttributes

@noUIupdate
def resolveTypeMismatch(mismatches, objects):
    # object attributes needed by ESRI.lib rules as type float
    exceptionAttributes = ["building__levels", "roof__height", 
                           "roof__direction", "building__levels__underground", 
                           "building__min_level", "min_heigh", "width", "lanes"]
    
    for object in objects:
        attributes = ce.getAttributeList(object)
        for attr in attributes:
            if attr in mismatches:
                attrValue = ce.getAttribute(object, attr)
                if attr in exceptionAttributes:
                    if not isinstance(attrValue, float):
                        ce.deleteAttribute(object, attr) 
                        print("Deleting " + attr + 
                              " of type " + str(type(attrValue)) +
                              " in OID: " + ce.getOID(object))
                else:
                    if not isinstance(attrValue, str):
                        newValue = str(attrValue)
                        ce.setAttribute(object, attr, newValue)
                        print("Updating " + attr + 
                              " from " + str(type(attrValue)) + 
                              " to <type 'str'> in OID: " + ce.getOID(object))
                         
    print("Done!")
    
def main():
    #objects = ce.getObjectsFrom(ce.scene)
    objects = ce.getObjectsFrom(ce.selection)
    
    mismatches = findTypeMismatches(objects)
    resolveTypeMismatch(mismatches,objects)
    
if __name__ == '__main__':
    main()

 

The script is divided into two parts:

  1. Find the attributes which have a type mismatch.
  2. Resolve the mismatches:
    • If an attribute which is required by the ESRI.lib OSM building / street rules of type float is of type string it gets removed from the shape, because the expected result from a string to float conversion can be unclear.
    • All other attributes which have a mismatch are converted to type string.