Thursday, December 3, 2009

Load Raster Data to a Field

A raster field is a column that allow a user to store raster objects in them. Rasters can be any imagery, jpg, pngs, etc...

To load data into the field you need to do the following:


///
/// Loads a raster into a raster field
///

/// feature where photo will be stored
/// image to be stored in record
/// Row of data to get the feature to store the raster dataset
/// Name of Raster field to save image to
public void LoadRasterDatasetToRasterField( IFeatureClass featureClass,
IRasterDataset rasterDataset, int OID, string RasterField )
{
try
{

//Get workspace for editing
IDataset dataset = (IDataset)featureClass;
IWorkspaceEdit workspaceEdit = (IWorkspaceEdit)dataset.Workspace;
workspaceEdit.StartEditing( false );
workspaceEdit.StartEditOperation();
IFeature feature = featureClass.GetFeature( OID );

//Find raster field index
int iRasterField = feature.Fields.FindField( RasterField );

//Create raster value with input raster dataset
IRasterValue rasterValue = new RasterValueClass();
rasterValue.RasterDataset = rasterDataset;

//Set raster value to the raster field
feature.set_Value( iRasterField, rasterValue );
feature.Store();

//Stop editing and save edits
workspaceEdit.StopEditOperation();
workspaceEdit.StopEditing( true );
}
catch (Exception ex)
{

MessageBox.Show( ex.Message );
}
}


This function basically starts an edit session to put data into the column. That means the featureclass be able to be edited.

Enjoy,

(I haven't forgot about Part 2 of my previous post, I've just been busy)

Thursday, November 12, 2009

Generating Elevation Profile (Part 1)

Elevation Profiles are a nice was to see the topography over a given line. This can be used for planning things like roads, easiest routes of travel, etc...

In Part 1, I will discuss how to develop a Geoprocessing Script to publish to ArcGIS Server to get the elevation profile data. I will be using spatial analyst to extract and transform the data. Next I will take the values and write them to a csv, which will be returned to a user.

Let's get started:

1). Create a new model. Make sure spatial analyst is enabled.

2). Add Extract by Mask and Raster to Point tools from ArcToolbox

3). Create a feature set object and provide a polyline shapefile as the schema reference. Make the schema of the data as follows: OBJECTID, SHAPE, ELEVATION

Now that you have that, you model should look like this:

Now you need to create the script that will return a csv table to the user from your ArcGIS Server Service.



4). Create a new python file and call it GenerateCSV.py


5). Add the following Code:
# Import system modules
import arcgisscripting, os, sys


# Create the Geoprocessor object
gp = arcgisscripting.create()
gp.overwriteoutput = 1

InputPtFC = sys.argv[1]
pnt = gp.CreateObject("Point")
rows = gp.SearchCursor(InputPtFC)
filename = gp.scratchworkspace + os.sep + r"test.csv"

myfile = open(filename, 'w')
myfile.write("X,Y,ELEVATION" + "\n")
row = rows.next()
while row:
feat = row.shape
pnt = feat.GetPart()
myfile.write(str(pnt.x) + "," + str(pnt.y) + "," + str(row.getvalue("GRID_CODE")) + "\n")
row = rows.next()
myfile.close()
gp.Addmessage(filename + " Completed")
gp.setparameterastext(1, filename)


6). Save your file, open catalog -> add this script to your toolbox -> Input Parameters - Feature Class and Output Parameter - Table

7). Add the newly create script to your orginal model

8). Save the model

9). Publish to ArcGIS Server


The resulting model should look like this:





Enjoy

Wednesday, October 14, 2009

Long Running Scripts

Well, today I've hit a major road block, but I have a work around that should help many of you out there. Have you ever had a process that performs the same operation multiple times, but sometimes that operation fails. It's almost random. Take my situation, I have a clipping function that clips 100s of data sets, but it will randomly fail with a TopoEngine error. The help suggests that you check the geometries of your features, but it turns out, they are fine.

After much search, and questioning, I discovered that I need to delete the Geoprocessing object, then re-create it as such:


import arcgisscripting
from time import strftime
print str(strftime("%H:%M:%S"))
gp = arcgisscripting.create(9.3)
gp.overwriteoutput = True
print str(strftime("%H:%M:%S"))
del gp
print str(strftime("%H:%M:%S"))
gp = arcgisscripting.create(9.3)
gp.overwriteoutput = True
print str(strftime("%H:%M:%S"))


I did it twice, and measured the time. The first time you create the object, it will take the longest. On my machine, it takes 3 seconds to initialize, but after that, the process takes less than a second. Since the processes I am running already take 2-3 hours to complete a 1-2 minute increase is not too hard to live with.

I found that if I delete the geoprocessing object after I perform work on about 3 processes, I eliminate the error.

Enjoy

Monday, October 12, 2009

Listing Only Directories Using Python

Sometimes it's necessary to list directories, but when the os.listdir() method is called, the return list contains both folders and files. To fix this do the following:



dirs = [ name for name in os.listdir(--Directory--)) if os.path.isdir(os.path.join(str(--Directory--), name))]
for d in dirs:
d = str(d)
d = d.upper()
if d.find(".GDB") == -1:
outString = outString + str(d) + "; "



Methods like this are very helpful when you need to use tool validation. It allows you to quickly list all data in a directory, so users can select what they need.

You'll notice that the script has a find(). This is used because file geodatabases are essentially folders and therefore need to be excluded from the generated list.

Enjoy

Friday, September 25, 2009

Table to HTML table

Sometimes it's necessary to generate an html table for returned results. This tool basically takes any format that can support a search cursor, and generates an HTML file on your local disk. I was using this script in conjunction with some reporting tools to analyze AGS server logs.

Enjoy, and I hope it sparks some great GP ideas.



# ---------------------------------------------------------------------------
# TableToHtml.py
# ---------------------------------------------------------------------------

import sys, string, os, arcgisscripting
gp = arcgisscripting.create(9.3)

tablePath = gp.GetParameterAsText(0)
filePath = gp.GetParameterAsText(1)

outfile = open(filePath, "w")
fields = gp.ListFields(tablePath)

fieldNames = []
for field in fields:
if (field.type <> "Geometry" and field.type <> "BLOB"):
fieldNames.append(field.name)

outfile.write(" <table border=""1"">\n")

outfile.write(" <tbody><tr>\n")
for fieldName in fieldNames:
outfile.write(" <th>" + fieldName + "</th>\n")

outfile.write("</tr>\n")

cur = gp.SearchCursor(tablePath)
row = cur.Next()
while row:
outfile.write(" <tr>\n")
for fieldName in fieldNames:
outfile.write(" <td>" + str(row.getValue(fieldName)) + "</td>\n")

outfile.write("</tr>\n")

row = cur.Next()

del cur

outfile.write("</tbody></table>\n")

outfile.flush()
outfile.close()

Tuesday, September 22, 2009

ArcPad Tips and Thoughts

If anyone is developing for ArcPad 8.0, make sure you get service pack 1. This will correct a whole host of issues with the AXF files. Also, if you wish to connect to an AXF, here is an example:

dim objRSPS, pDS
Set objRSPS = Application.CreateAppObject("RecordSet")
Set pDS = Application.CreateAppObject("DataSource")
pDS.Open(pDSDataSource)
set objRSPS = pDS.OpenLayer("")
If objRSPS.RecordCount > 0 Then
objRSPS.MoveFirst
End If
...do other stuff...


So basically what is happening here, the objRSPS is creating a recordset object, then pDS is a data source object. pDS opens the data source via path name. objRSPS obtains the data set's records by referencing what layer you want from the axf database (axf is a compact sql server).

Note: the axf is picky, and it will tell you. If any domain values are invalid, it will catch it. So keep your databases clean if you are going to use this stuff.

Note 2: the shapefile is going away in arcpad, so get use to the AXF way of doing things.

Enjoy

Tuesday, September 15, 2009

Deprecation Plan for ArcGIS 9.3.1 and ArcGIS 9.4

The deprecation plans for ArcGIS 9.3.1 and ArcGIS 9.4 can be found here. It shows that VBA and VB6 are finally going away and there are OS support changes planned also. It's time for people to move on to new technologies, so start getting ready to transition now.

Friday, August 28, 2009

Important Links to Bookmark for Geoprocessing Tool Development

Here are some important links that I think any developer should have in there back pocket, if they are going to use, publish, or create GP tools.

This is about Feature and Record sets.

This is about the input and output types that are supported when publishing services.

Monday, August 24, 2009

Serialize Anything!

When you start with threading, especially in AGX 900 sdk, you are going to need to translate your objects into strings. To do this, just use the two functions below.



private byte[] getByteArrayWithObject( Object o )
{
/*

1) Create a new MemoryStream class with the CanWrite property set to true
(should be by default, using the default constructor).

2) Create a new instance of the BinaryFormatter class.

3) Pass the MemoryStream instance and your object to be serialized to the
Serialize method of the BinaryFormatter class.

4) Call the ToArray method on the MemoryStream class to get a byte array
with the serialized data.

*/


MemoryStream ms = new MemoryStream();
BinaryFormatter bf1 = new BinaryFormatter();
bf1.Serialize( ms, o );
return ms.ToArray();
}
private object getObjectWithByteArray( byte[] theByteArray )
{
MemoryStream ms = new MemoryStream( theByteArray );
BinaryFormatter bf1 = new BinaryFormatter();
ms.Position = 0;

return bf1.Deserialize( ms );
}



You can then translate your byte[] into a string using the built in Convert with .Net. Now you have values passed into the AGX BackGroundThread.

Enjoy

Monday, August 17, 2009

AGX 900 is released

ESRI has released AGX 900 with new ribbon technology. I am quite excited about this release except for one issue, which I'll get to later.

The AGX 900 SDK has been revamped. It is shiny and new, and now uses a flavor of background workers instead of the task and taskui classes. The use of background workers makes programming tasks very easy compared to the old way. Now here is the rub, though I love this product, it lack the capabilities to use published Geoprocessing tasks out of the box.

During beta testing of this product, I did not see many comments on if this point. I'm interested to see if AGX 900 will have an expansion pack to perform this.

Wednesday, July 15, 2009

List of All GeoProcessing Data Types

From the resource center of ESRI, comes a pdf that contains all the different type of GeoProcessing data types with correlating ArcObjects in it. This is very helpful, and any .NET GP developer should have it printed out and right next to them.

Enjoy

Thursday, July 9, 2009

2 GP Functions That Make Life Easier

Here are two functions that make life easier for custom GP development. The find parameter value by the parameter name, return parameter type IGPValue. The second method is get parameter by name, which returns IGPParameter3. Parameter value by name allows you to retrieve

Get Parameter By Name

public IGPParameter3 GetParameterByName( IArray paramvalues, string name )
{
IGPParameter3 gpParameter;
for (int i = 0; i < paramvalues.Count; i++)
{
gpParameter = (IGPParameter3)paramvalues.get_Element( i );
if (gpParameter.Name.Equals( name, StringComparison.OrdinalIgnoreCase ))
return gpParameter;
}
return null;
}


Get Parameter Value By Name

public IGPValue GetParameterValueByName( IArray paramvalues, string name )
{
IGPUtilities2 gpUtils = new GPUtilitiesClass();
IGPParameter3 gpParameter;

for (int i = 0; i < paramvalues.Count; i++)
{
gpParameter = (IGPParameter3)paramvalues.get_Element( i );
if (gpParameter.Name.ToUpper() == name.ToUpper())
return gpUtils.UnpackGPValue( gpParameter );
}
return null;
}

Wednesday, July 1, 2009

Creating a Feature Set via C#

A very powerful model builder feature is the create variable option. This will allow users to create almost any type of user input desire. The feature set variable is a very helpful variable when a user needs to interact with the map or recordset. The feature set allows users to draw points, polylines, or polygons on the fly. To do this in C#, you need to use the IGPRecordSetLayerClass(), but the process of making the interactive part work isn't that straight forward.

To get the interactive part of the Feature set to work, you must define the Schema with either a layer file or feature class in model builder. When you take a look at the ArcObject description of a parameter, you notice a pointer called Schema, but this isn't where you define the template data for a GPFeatureRecordSet, you define it in Value().


inputParameter.DataType = new GPFeatureRecordSetLayerTypeClass();
//
// create the GP Feature Recordset Layer Object
// from template data
//
IFeatureClass FC = (IFeatureClass)m_GPUtilities.OpenDatasetFromLocation( @"