Programming‎ > ‎

ESRI

I have to scream: ESRI ArcObject software is the worst commercial software I've ever used.  Examples are amazing: the geospatial cache directory pathname must be less than DOS! limit.   The raster name must be less than 10 characters.   Creating raster images gets slower every iteration.  It won't release the lock until your application finishes.   The raster index file (.sbn) timestamp must be equal or later than the shapefile (.shp) timestamp.  I'm currently using Release 10.0 Sp3.   Now Release 10.1.

Anyway, I have to use ESRI ArcObjects to do for my work and thus here is the tip. 

Updated 8/15/2012

Index


What is the wkid for WebMercator?

WKID for WGS84 is 4326. WKID for WebMercator is 102100 or 3857. Here is the list of WKIDs http://resources.esri.com/help/9.3/arcgisserver/apis/rest/pcs.html

Index


Why does ESRI read altitude wrong for TIFF image?

We are using TIFF file for terrain data to get the altitude. We found that when compared with Global Mapper, ESRI sometimes read a ridiculous altitutde value (Global Mapper -0.918 vs. ESRI 64803.075). We looked at the TIFF image in ArcMap 10.1 and we found that the location has the value of 0xFFFF (this was a 16 bit TIFF image). Now you remind yourself of signed and unsigned representation of 16 bit number. Signed representation uses 2's complement and thus 0xFFFF = 65535 is actually -1. It turned out that the neighbors had the value of 0 and it is reasonable to assume that the altitude must be -1 but not 65535. Further more, the ESRI recognized the value of 0x8001 as the no data pixel. In order to fix this problem you have to set the pixel type to signed short when you read the TIFF 16 bit image as the altitude by hand. Here is the routine.

  
  Type factoryType = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory");  
  IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);  
  IWorkspace workspace = workspaceFactory.OpenFromFile(inputDirectory, 0);  
  IRasterWorkspace rasterWorkspace = (IRasterWorkspace)workspace;  
  IRasterDataset inputRasterDataset = rasterWorkspace.OpenRasterDataset(inputDatasetName);  
  IRaster inputRaster =((RasterDataset2)inputRasterDataset).CreateFullRaster();  
  IRasterProps inputRasterProps = (IRasterProps)inputRaster;  
  inputRasterProps.PixelType = rstPixelType.PT_SHORT;  
  IRasterSurface inputRasterSurface = new RasterSurfaceClass();  
  inputRaster.ResampleMethod = rstResamplingTypes.RSP_BilinearInterpolation;  
  inputRasterSurface.PutRaster(inputRaster, 0);  
  IFunctionalSurface inputSurface = (IFunctionalSurface) inputRasterSurface;  
  double? alt = inputSurface.get_Z(lon, lat):
  

Index


Why does my unit test for ESRI ArcObject fail?

It turns out that MSTest runs each test method on a separate thread (the thread is STA). I created unit test for ESRI ArcObject and not all the tests pass but if I run failed tests individually, they pass. This had been bothering me a long time. Finally I had to figure out the issue.I set to run two tests (the first one succeeds and the second one fails). I found that the exception was Runtime Callable Wrapper (RCW) was no longer associated with the COM object at GeoProcessor. I have access to RedGate Reflector and thus I disassemble ESRI.ArcGIS.Geoprocessor to find out. It turned out that at the license acquisition, it stores a static ESRI version variable using COM. When run GeoProcessor once and then another test which is in a different thread, this variable is released by COM and thus it throws exception when GeoProcessor runs in next test. Because when one thread finishes and nobody is using it, then COM object is released. ESRI should not store the version using COM object. Now I know the reason. RedGate told me the static variable to be initialized and how it is initialized: if the variable is null, then it will initialize. I can fix this problem by setting this variable null. Here is the method using Reflection:

  
  static private void ResetGISVersion()  
  {    
    Type t = typeof(ESRI.ArcGIS.RuntimeManager);    
	FieldInfo f = t.GetField("s_arcGISVersion", BindingFlags.NonPublic | BindingFlags.Static);    
	f.SetValue(null, null);  // first = object, second = value   
  }
  

If you call this routine before you call GeoProcessor ArcObject, you won't have issues with Unit Test anymore.

Index


Why my console application crashes?

I had a working function which uses ESRI and inside a GUI application. When I created a console application, it crashed. I pulled my hair for why. I realizedthat ESRI is a collection of COM components. Their COM components are all STA. Thus the solution is to have a [STATHread] attribute:


  [STAThread]     
  static int Main() 
  or      
  Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
  

Index


Where are the ESRI license file?

I had a weird issue with license and even the software uninstall won't remove the information. Here are the location.


  Windows 7:  
  c:\ProgramData\FLEXnet\ARCGIS*_tsf.dataWindows XP:  
  c:\Documents and Settings\All Users\Application Data\FLEXnet\ARCGIS*_tsf.data
  

Index


How can I convert NAD27 Raster to NAD83 using ArcObjects?

It took a while to get the following routine done. There are more than one way to convert NAD27 to NAD83. Important point is that the earth model changed (DATUM changed:NAD27 which uses Clark_1866 ellipsoid vs. NAD83 uses GRS80. (seehttp://en.wikipedia.org/wiki/North_American_Datum). The following way won't change the extent (ll and ur). ProjectFast changes the extent.  The popular terrain file format DEM (3 arc second) which covers the US is in NAD27.   The difference between NAD27 and NAD83 varies but near Sanfrancisco it is of the order of 100 m.

   
  public static ISpatialReference GetNad83Ref()   
  {     
    SpatialReferenceEnvironment spatialRefFactory = new SpatialReferenceEnvironment();     
	IGeographicCoordinateSystem gcs =        
	  spatialRefFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_NAD1983);     
	ISpatialReference latLonSpatRef = gcs as ISpatialReference;     
	latLonSpatRef.SetFalseOriginAndUnits(-180, -90, 1000000);     
	latLonSpatRef.SetZDomain(0.0, 100000.0);     
	ILinearUnitEdit linearUnitEdit = new LinearUnit() as ILinearUnitEdit;
	object name = "Meter";     
	object alias = "Meter";     
	object abbreviation = "M";     
	object remarks = "Meter is the linear unit";     
	object metersPerUnit = 1;     
	linearUnitEdit.Define(ref name, ref alias, ref abbreviation, ref remarks, ref metersPerUnit);     
	latLonSpatRef.ZCoordinateUnit = linearUnitEdit as ILinearUnit;     
	return latLonSpatRef;   
  }   
  
  public IRaster ConvertFromNad27ToNad83(IRasterDataset rasterDataset, IWorkspace workspace)   
  {     
    // create a new raster     
	IRaster raster = ((IRasterDataset2)rasterDataset).CreateFullRaster();     
	IRasterProps rasterProps = (IRasterProps)raster;     
	string spatRefName = rasterProps.SpatialReference.Name;     
	// spatial reference change to NAD83     
	rasterProps.SpatialReference = GetNad83Ref();     
	// specify geotransformation for DATUM change (NAD27 to NAD83)     
	ISpatialReferenceFactory2 srFactory = new SpatialReferenceEnvironment()
  	   as ISpatialReferenceFactory2;     
	esriSRGeoTransformation2Type geoTrans = 
	   esriSRGeoTransformation2Type.esriSRGeoTransformation_NAD_1927_TO_NAD_1983_NADCON;     
	IGeoTransformation geoTransformation = 
	               (IGeoTransformation)srFactory.CreateGeoTransformation((int)geoTrans);
	// Add to the geotransfomration operation set     
	IGeoTransformationOperationSet opSet = new GeoTransformationOperationSet();     
	opSet.Set(esriTransformDirection.esriTransformForward, geoTransformation);     
	opSet.Set(esriTransformDirection.esriTransformReverse, geoTransformation);     
	// set geotransformation on raster     
	IRaster2 raster2 = (IRaster2)raster;     
	raster2.GeoTransformations = opSet;     
	// set Resampling Method for transform     
	raster.ResampleMethod = rstResamplingTypes.RSP_BilinearInterpolation;     
	// trasform is applied when you save     
	ISaveAs saveas = (ISaveAs)raster;     
	// we need new tmpFile every cache so that ESRI won't cause exception     
	string tmpFile = System.IO.Path.GetRandomFileName();     
	// contains . and thus replace it.        
	tmpFile = tmpFile.Replace('.', 'z');     
	// ESRI Raster name must be less than 10 chars.     
	// The end result may not be as random as we want, but ...     
	tmpFile = tmpFile.Substring(0, 10);     
	// save it in memory "MEM"     
	IDataset outRasterDS = saveas.SaveAs(tmpFile, workspace, "MEM");     
	Marshal.ReleaseComObject(outRasterDS);     
	return raster;   
  }
  

Index