paper 1675 title geospatial calculation of scs runoff ... · requires that soil survey information...

48
Paper 1675 Title Geospatial Calculation of SCS Runoff Curve Numbers Author John M. Huddleston, PE, PhD Paper Abstract The calculation of runoff curve numbers (RCN) to estimate volumes of runoff after rainfall is now made possible with a web based geospatial interface. Using hydrography, hypsography, and USDA soils data stored in ArcSDE 8.3 using SQL Server, a user can digitize online and use a .NET program to create a weighted RCN. This complicated system based on C++ COM+, JSCRIPT, Visual Basic, C# Global Assembly Cache, and Java using Tomcat allows a user to calculate the RCN in minutes whereas it used to take months. Orthophoto Mosaics from a Terra Server guide the user and online contours allow for creating watershed boundaries. The composite RCN is based on the intersection of USDA soils SSURGOv2 and the user delineated fields within the watershed.

Upload: others

Post on 29-Mar-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

Paper 1675 Title

Geospatial Calculation of SCS Runoff Curve Numbers

Author

John M. Huddleston, PE, PhD

Paper Abstract

The calculation of runoff curve numbers (RCN) to estimate volumes of runoff after rainfall

is now made possible with a web based geospatial interface. Using hydrography,

hypsography, and USDA soils data stored in ArcSDE 8.3 using SQL Server, a user can

digitize online and use a .NET program to create a weighted RCN. This complicated

system based on C++ COM+, JSCRIPT, Visual Basic, C# Global Assembly Cache, and

Java using Tomcat allows a user to calculate the RCN in minutes whereas it used to take

months. Orthophoto Mosaics from a Terra Server guide the user and online contours

allow for creating watershed boundaries. The composite RCN is based on the intersection

of USDA soils SSURGOv2 and the user delineated fields within the watershed.

Page 2: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

TABLE OF CONTENTS CHAPTER 1

GENERAL INTRODUCTION

1.1 INTRODUCTION............................................................................................................ 1 1.2 DEFINITION OF THE PROBLEM................................................................................. 1 1.3 OBJECTIVE .................................................................................................................... 1 1.4 LAYOUT OF PAPER 1675............................................................................................. 1

CHAPTER 2 SCS RUNOFF CURVE NUMBER

2.1 RUNOFF EQUATIONS .................................................................................................. 2 2.2 CURVE NUMBER .......................................................................................................... 3 2.3 SOIL SURVEYS.............................................................................................................. 3

CHAPTER 3 DATABASES FOR CURVE NUMBER COMPUTATION

3.1 INTRODUCTION............................................................................................................ 3 3.2 RCN DATABASE ........................................................................................................... 3 3.3 SDM DATABASE........................................................................................................... 3 3.4 NED DATABASE ........................................................................................................... 4

CHAPTER 4 RCN PUBLISHING AND DATA ACCESS

4.1 INTRODUCTION............................................................................................................ 4 4.2 NAVIGATION WEB SERVICE ..................................................................................... 5 4.3 ORTHOPHOTO WEB SERVICE ................................................................................... 5 4.4 OMS RCN WEB SERVICE ............................................................................................ 6 4.5 RCN LIBRARY ............................................................................................................... 9 4.6 JAKARTA TOMCAT WEB SERVICE .......................................................................... 9

CHAPTER 5

CONCLUSION

5.1 BENEFITS ..................................................................................................................... 10 5.2 CONSTRAINTS ............................................................................................................ 10

CHAPTER 6 APPENDICES

6.1 SDEAPI LISTING ......................................................................................................... 10 6.2 SPATIALDATALIBRARY LISTING .......................................................................... 25

CHAPTER 7

REFERENCES..................................................................................................................... 44

i

Page 3: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1.0 GENERAL INTRODUCTION

1.1 INTRODUCTION

Surface runoff from a precipitation event is a function of the storm intensity and distribution as well as surface cover, soil, and watershed characteristics. The initial precipitation is captured in soil infiltration and surface depressions. Infiltration rate decreases over time during a rain event; consequently runoff rate increases over time during the rain event. A method developed by United States Department of Agriculture (USDA) Natural Resources Conservation Service (NRCS, formerly SCS) to estimate runoff, does not require estimating infiltration and surface storage separately. Everything is expressed as just one watershed characteristic called the Curve Number (CN). CN is related to how much precipitation becomes runoff. This is similar to (BUT NOT THE SAME AS) a percentage: totally impervious CN = 100, totally absorbent CN = 0. There are equations to estimate runoff from CN as presented in Chapter 2.

Three components of CN are land cover, soil type, and antecedent runoff condition. Land cover descriptions are grouped by cover type, treatment, and hydrologic condition. Soil types are classified by soil infiltration rate known as hydrologic groups. The four hydrologic groups are A, B, C, and D where class A has a high infiltration rate (like sandy soils) and class D has a low infiltration rate (like clay or a high water table.) Antecedent runoff conditions (ARC) are based upon previous rainfall amounts. ARC is broken into three categories: very dry, average moisture, and very wet.

1.2 DEFINITION OF THE PROBLEM

In practice a conservationist would create an “area-soil type-land cover” computation table by hand. First, the watershed sub-areas had to be delineated using the U. S. Geological Survey (USGS) 1:24,000 quadrangle maps. Using a tool such as a planimeter, the area of the

watershed sub-areas would be calculated. The sub-area boundaries would be transferred to the soils maps. Each different soil within the sub-area had to be planimetered. Each of these soils within the sub-area had to be identified with a land cover or multiple land covers. The differing scales of the maps make the process of determining the CN value time consuming.

1.3 OBJECTIVE

The process just described could take months for a large watershed study. In order to shorten the time frame for calculating the CN values, a geospatial interface was developed that accesses digital orthophoto data, digital line graphs for elevation contours, and digital soils data. The orthophoto imagery can be used to identify the land cover. The contour lines can be used to delineate the watershed and fields. The soils data is then accessed for the hydrologic soil group.

The objective of this work is to provide a tool that automates the CN value computation process to use online hydrography, hypsography and soils data. A .NET geospatial Internet web service application was created and will be described in Chapter 4.

1.4 LAYOUT OF PAPER 1675

Chapter 2 will present the theory behind the CN computation. Chapter 3 will discuss the available sources of data stored in Microsoft SQL Server Environmental Systems Research Institute (ESRI) Spatial Data Engine (SDE) databases. Chapter 4 will present the .NET solution including C++ COM+ components, C# global assembly cache components, and C# web application and service components. Chapter 5 is a listing of the source code. Chapter 6 is a compendium of references for this topic.

1

Page 4: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

2.0 SCS RUNOFF CURVE NUMBER

2.1 RUNOFF EQUATIONS

The United States Department of Agriculture Natural Resources Conservation Service (NRCS, formerly SCS) funded research in the early 1950s to determine the volume of runoff from small (< 10 acres) watersheds for a given precipitation event. Plotting volumes/area of runoff versus volumes/area of rainfall, the following empirical runoff equation was derived by Victor Mockus (13):

( ) 2P-IQ = ; I = 0.2S

P-I+S 1.1

Equation 1.1 is the SCS runoff equation where

Q = runoff in volume/area

P = precipitation in volume/area

S = maximum potential soil retention

I = initial abstraction

To find the retention parameter, S, the SCS curve number (CN) value was related to S

1000CN = S + 10

1.2

According to Mockus (13) the rainfall-runoff curves would plot at nearly equal intervals. (Figure 1.1)

Figure 1.1. Runoff Curves for Varying CN

2

Page 5: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

2.2 CURVE NUMBER

The CN value can be computed using the soil types and cover conditions of the watershed. Given that the CN value can be computed, the retention parameter, S, can be computed by re-arranging equation 1.2 as follows:

S = 1000CN

−10 1.3

The CN corresponding to a large number of soil types and cover conditions are available from NRCS in Technical Release 55 or the National Engineering Handbook, Section 4. (22,23) Consequently, application of the method requires that soil survey information be available for the watershed of interest. A soil survey provides the information needed to choose the CN value based on soil type, land use or cover type, treatment or management practice, and hydrologic condition.

2.3 SOIL SURVEYS

NRCS has prepared soil surveys for each county in the United States. NRCS provides generalized soil maps and detailed descriptions of the soil series and the soils capabilities and limitations for land use and management. The range of physical and chemical characteristics of each soil series is supported by both field and laboratory data recorded by NRCS. The NRCS Soil Surveys are prepared at scales ranging from 1:12,000 to 1: 63,360.

3.0 DATABASES FOR CURVE NUMBER COMPUTATION

3.1 INTRODUCTION

There are four separate databases used in the RCN calculator web application. The RCN tables used to store the users session data is both a tabular and ESRI Spatial Data Engine (SDE) write and read database. The Soil Data Mart (SDM) read only SDE database contains the NRCS soils polygon features and tabular SSURGO data. The National Elevation Data (NED) read only USDA SDE database contains digital line graph contour data obtained from the

U.S. Geological Survey (USGS) National Elevation Dataset. Both SDM and NED data are part of the USDA Geospatial Data Gateway.

3.2 RCN DATABASE

Three RCN SDE tables store the spatial data for the user selected watershed, land covers, and results. Four tabular RCN tables store the Session, Watershed, Field, and SoilData elements. A conceptual diagram of a user digitized area of three fields and multiple soils would appear as follows. (Figure 2.1)

Figure 2.1 Sample Watershed, Fields, and Soils

The Watershed area has three different soils, AcA, AbC and NuC. Soil AcA occurs in two different polygons. There are three different fields, Field A, Field B and Field C. There are 11 different soil/field polygon area's. Three of these area's 1, 3 and 5 are actually the same soil/field combination, but they are different physical polygons. There would be a total of 11 SoilData records, three Field records, one Watershed record, and one Session record.

3.3 SDM DATABASE

The SDM SDE database stores both the spatial and tabular data for the NRCS soils data. The map unit symbol (MUSYM) and map unit key (MUKEY) are contained within each polygon spatial data feature. Once the MUKEY is determined it is then used to access soils data from the other tables. In this case, the RCN

3

Page 6: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

calculator is interested in the hydrologic soils group (hydgrpdcd) from the map unit aggregate attribute (muaggatt) table. In addition, the SDM database has version identification and record locking capabilities. These are contained in other tables.

3.4 NED DATABASE

The U.S. Geological Survey (USGS) National Elevation Data (NED) spatial data themes consist of 7.5 minute Digital Elevation Model (DEM) data files, which are digital representations of cartographic information in a raster form. DEMs consist of a sampled array of elevations for a number of ground positions at regularly spaced intervals. The USGS produces these digital cartographic/geographic data files as part of the National Mapping Program. DEM data for 7.5 minute units correspond to the USGS 7.5 minute topographic quadrangle map series for all of the United States and its territories except Alaska. Each 7.5 minute DEM is based on 30- by 30-meter data spacing with the Universal Transverse Mercator UTM projection. Each 7.5 by 7.5 minute block provides the same coverage as the standard USGS 7.5 minute map series. Digital Raster Graphs (DRG) data themes are georeferenced rectified raster image of a scanned USGS topographic or planimetric map.

The USDA NRCS has loaded the NED SDE raster data and has developed routines to generate contours for loading as SDE polyline data using ARC workstation AML and the following GRID function

<arc coverage> = contour(focalsum(<NED grid>,weight,<kernelfile>,NODATA), INTERVAL,<interval in meters>,0.01)

The focalsum function smooths the peaks and valleys of contours, eliminating right angles that are cartographically poor. The 0.01 base offset smooths zigzag contours that are result from uniform integer grid values that occur along waterlines and flat areas. Five foot intervals are extracted from the 10 meter data source using

<interval in meters> = 1.524. This creates a large number of small closed contours. The process extracts features to a separate coverage, builds polygons, associates the arc contour interval with the polygon, writes the centroid out as a point, and deletes these arcs from contour layer. The 10 foot interval is extracted from the 30 M data source using <interval in meters> = 3.048.

4.0 RCN PUBLISHING AND DATA ACCESS

4.1 INTRODUCTION

The World Wide Web Consortium (W3C) has defined message formats and protocols to call and pass parameters to an XML page server. Most applications require query string parameters or specific form fields be filled in with appropriate values in order to generate the HTML or XML document. The W3C developed the Simple Object Access Protocol (SOAP) and related standards that extend XML so that computer programs can easily pass parameters to server applications, and then receive and understand the returned XML data document.

SOAP is augmented with an interface definition language (IDL) called Web Services Definition Language (WSDL). Each web service publishes its interface as an XML document that completely specifies the service’s request/response interface so that clients and client tools can automatically bind to the web service. SOAP provides the framework to enable two cooperating software programs to inter-operate and allows cooperation over the public Internet using vendor-neutral XML-based protocols.

Web service clients are computer programs that invoke the web service methods. Client programs accesses the web service just the same way they access any other object class. The tool reads the WSDL and translates the class definitions into the programmer’s language. The tools build the proxy and stub code required to communicate between the client and the remote web service. When a

4

Page 7: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

program invokes a published web service method, it is calling a method implemented that handles the SOAP/XML encoding/decoding and transmission to the remote web service. The runtime builds a SOAP request document, sends it to the remote web service via HTTP or native SOAP, waits for a response, decodes the returned SOAP/XML document, and formats the returned result in the binary format familiar to the program.

In summary, a web service allows a client application to access methods published as a remote public class via Internet protocols over a wide-area, typically public network. Because it is encoded as an XML document, data is easily exchanged between computing systems with incompatible architectures and incompatible data formats. WSDL completely describes the web service interface, and SOAP headers and documents completely describe the data types of parameters, returned data structures, and exceptions. The publisher simply implements a class with public methods and declares them to be a Web Method. A consumer references the published web service class as they would a local or system class and invokes the public methods. The programming environment uses the SOAP system to perform all the RPC and data encoding/decoding operations.

4.2.NAVIGATION SERVICE

NRCS in cooperation with Microsoft, Compaq, and ESRI put together a TerraServer to deliver large scale, enterprise data from USDA and other Federal data providers. The TerraService WSDL interface document is (http://terraservice.net/TerraService.asmx?wsdl)The initial display to the user contains a map of the United States using the USDA Lighthouse TerraServer. This navigational aid allows the user to zoom to their area of interest. The application uses ArcIMS and ArcSDE with a Microsoft SQL Server database. Using server-to-server communications, images are retrieved from Microsoft's TerraServer and merged with other map information. "ESRI's strength in

building cross-cutting technologies and working with solutions partners has paid off in this effort where ArcIMS is the mechanism whereby the merging of these various data sets takes place and is rendered into JPEG files for delivery to the end user through their Web browser," said John Steffenson, USDA account manager for ESRI. (10)

4.3.ORTHOPHOTO WEB SERVICE

In order to provide a background to the user to orient themselves within the area of concern a digital ortho-quadrangle image of the ground is displayed using a digital ortho-photography TerraService. The TerraService web service (http://terraserver-usa.com) provides a programmatic interface to the TerraServer database. TerraServer is a database repository of high resolution, ortho-rectified imagery that is logically represented as a “seamless mosaic of earth” at several scales (meters per pixel). The TerraService also provides a landmark service that returns place names and a list of all the places within a specified area. The mosaic is stored as sets of uniformly sized, JPEG or GIF compressed images called tiles. Each tile has a predictable resolution and location on the earth.

The TerraService methods enable consuming applications to query the TerraServer database of tiles by a number of different methods to determine the existence of tile data over some expanse of geographic territory. Data returned by tile query methods enable a calling application to determine the set of tiles required to build a complete image that covers the queried geographic area. The consuming RCN application calls TerraService’s GetImageArea() method to retrieve the image. The parameters “t=1&s=<scalefactor>&lon=<longitude>&lat=<latitude>&w=<width>&h=<height>” are passed to GetImageArea.ashx where items in angle brackets are supplied by the application. The parameter t is set to 1 for Digital Orthophoto Quadrangle (DOQ) imagery, s is set to 10 thru

5

Page 8: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

16 for resolution, lon is set to the center point’s longitude, lat is set to the center point’s latitude, w is set to the image width in pixels, and h is set to image height in pixels. TerraService replies with the ortho-image JPEG.

4.4 OMS RCN WEB SERVICE

In 1992 George Leavesley (11) initiated the Modular Modeling System (MMS) at the U.S. Geological Survey (USGS) in Denver. This X11 based system allows modules to be built such that multiple components can be added by a modeler, create a binary, and access data using the user selected modules for a runtime operation

In 1996 Olaf David, Institute of Geography Department Geoinformatics at the Friedrich-Schiller-University Jena started the development of the Object Modeling System (OMS), a java based object-oriented framework. In cooperation with the USGS and USDA Agricultural Research Service (ARS) the MMS concepts were advanced. (3,4) The USDA ARS brought Olaf David over to the U.S. to implement OMS for ARS applications in 2000.

NRCS supported this effort of ARS applications destined for NRCS use by providing support and funding beginning in 2000. While the original MMS and OMS designs were based as a standalone modeling system on the users desktop, NRCS initiated a web based system design to pioneer the OMS concepts. The system is .NET based with C++, C#, Java Script, and Visual Basic source code. A call to a Jakarta Tomcat Java web service performs the curve number computation. The database is Microsoft SQL Server. The geospatial data engine is ESRI’s SDE. This system is known as the OMS runoff curve number (OMS-RCN) calculator.

A logical design of the operation is shown in Figure 4.1. In the design, a user navigates to the area of concern, uses digitizing tools to identify watersheds and sub-areas and uses editing tools to identify information about the

user, the watershed, and the sub-areas, and submits a request for a report. Built into the services are VML data transfers, database storage, image display, and return to the user of the report in html format.

SDEREQ

Data Mart Matrix Page

+ Image

GML

Compute Weighted

RCN

NavigateLocate Area

DigitizeLand Use

and Watershed

Transform VMLinto

GML

Middle TierConstruct

SDE

SDEDB

ARC IMS

POSTPage

SDEOBJ

POINTLINE

POLYGON

AXLFile

Name

MicrosoftTerra

Server

SDEREQ

Image

Xml

Store Xml Report

XMLAcres

LUHSG

WRCN

Figure 4.1 Logical Design of OMS RCN

The major components within the OMS-RCN web application are: (Table 4.1)

Default.htm Java script file main web page for user digitization

Web.Config File controls the Id/Password and other .NET controls

Images Directory that holds the images for the Default.htm

Output Directory holding output Xml files from the rcn report

Bin Directory holding the OMS Web App.DLL

rcn-output.aspx

Visual Basic file containing the report generator

Table 4.1 Components of OMS RCN

Numerous C# files including Assembly, AttributeField, Global, Information, LonLat, are compiled into a DLL and provide a fast and efficient operation of the web application.

The major components within the OMS-RCN-Services web service are: (Table 4.2)

Services.asmx File main services page for web page access

Web.Config File with the Id/Password and other .NET controls

Bin Directory holds the OMS-RCN.DLL Table 4.2 Components of OMS RCN-Services

The Assembly, Global, and Services C# files are compiled into a DLL for fast operation of this

6

Page 9: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

web service. The OMS-RCN-Services web service provides the following methods:

• GetSoilsForFields: returns polygon data for the soils within the extent of the user digitized ortho image area

• GetfeaturesAsVml: returns the spatial extent for the hypsography, hydrography, and soils orthophoto images in terms of latitude and longitude.

The GetFeaturesAsVml web method is used to project the hypsography, hydrography, and soils geospatial data as a background. Initially, the Topologically Integrated Geographic Census Encoding and Referencing (TIGER) data was loaded. However, NRCS is now using TeleAtlas data. The GetSoilsFor Fields is used to project the user digitized area, create and update tabular and spatial records, and generate XML for the geographic data. Geography Markup Language 2.0 (GML) is used to describe the polygons and the XML was extended to contain the parameters to access the soils data mart.

The OMS-RCN web service is stateless. Each method call passes all the context information required by the method to form a complete result. Like the TerraService, all parameters and method results use simple data-types such as strings, integers, and floating point values.

The OMS-RCN is an HTML/JSCRIPT application that is over 150,000 bytes or nearly 6000 lines of code and the first time the application is loaded there will be a delay especially at slow internet line speeds (< 56K).

At startup time, that is when the OMS-RCN URL1 is put into the IE navigation bar, the main window opens to the Texas county of Medina. In addition, a second pop-up window appears requesting “User Information” (Figure 4.2). The information is for reporting purposes and is used by the OMS-RCN report. The

1 http://cougar.itc.nrcs.usda.gov/OMS-RCN/

RCN_User should be replaced by the name of the owner of the land or some similar designation to identify a person and/or property. The remaining four entry lines can be changed as appropriate.

Figure 4.2 Image of the User Information Pop-

Up Window

The OMS-RCN web application centers in on Medina, Texas (Figure 4.3) for which SSURGO soils and elevation contour data have been loaded in a local database for development. The user can “Zoom Out” and go to another location in the United States but the development environment only has Texas data loaded. Soils data for other areas of the U.S. are being loaded and will be completed by December, 2004.

Figure 4.3 – Image of the OMS-RCNWindow

7

Page 10: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

The OMS-RCN web application is automatically set for “Zoom In” operation. Click on any point in the image (or canvas) and the application will zoom in closer to the image. The zoom out and the pan operations are available as well. Once the user has zoomed down to a scale of 2, an orthophoto image of the area is projected. (Figure 4.4)

Figure 4.4 Ortho-photo Image of the OMS-

RCNWindow

At the first entry of the orthophoto image, the map scale is approximately 1 cm = 320 m or 1 inch = 2640 feet. The zoom in spyglass can be

used or now there are four additional tools between the spyglasses on the tool bar to quickly change the scale of the canvas. Information on the scale will be displayed for English and metric units as the mouse passes over the images. Each time the zoom is activated a new orthophoto image is returned from the TerraServer. A new SOAP packet is formed, sent to the TerraServer, Xml data received, and the new image rendered onto the canvas.

The user first digitizes the watershed(s) by clicking the DigitizeWatershed menu item.

Figure 4.5 Image of the Active Toolbar

Black letters indicate a tool is available for use. (Figure 4.5) Blue letters in a menu item indicate that those operations are unavailable and that more work has to be done. All the processing for the digitizing is local since the HTML/JSCRIPT code has been downloaded into the IE framework. As a result, this part of the processing is responsive.

Once the watershed has been digitized the DigitizeLandCover menu item will be enabled. The DigitizeLandCover allows the user to break up the watershed into mutually exclusive parts.

At the completion of the field delineation, the LandCoverInfo will be enabled. Using the LandCoverInfo tool a pop-up window will appear as each field is selected. (Figure 4.6) The logic of the entry follows the logic of the TR-552 manual. (23) Each field must contain an area type, cover type, treatment, and hydrologic condition.

Figure 4.6 Image of the Land Cover Window

When the last field land unit information has been completed the Submit button will become operational. Once the Submit button is pressed the RCN report will be generated by first collecting the information and then passing it as VML to the OMS-RCN-Services web service for retrieving the soils3 data. This web service in turn submits a request to a COM+ object (Section 4.5) that inserts the digitized data into 2 http://www.wcc.nrcs.usda.gov/hydro/hydro-tools-models-tr55.html 3 http://cougar.itc.nrcs.usda.gov/OMS-RCN-Services/Services.asmx

8

Page 11: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

an SQL Server database running the ESRI Spatial Data Engine (SDE). The digitized watershed and fields are intersected with the SSURGO soils data. The original window is modified to show the intersection and a new window is initiated that contains the report of the RCN analysis.

4.5 RCN LIBRARY

There are two major components within the rcn-library:

SpatialDataLibrary.DLL Global Assembly Cache DLL

SdeApi.DLL COM+ DLL

These components are added to the Windows system via the RegSvcs and GacUtil commands respectively. e.g.

RegSvcs SdeApi.dll

GacUtil /I SpatialDataLibrary.dll

The assembly Application name of the SdeApi namespace is SmartTech. This name appears in the COM+ window after the RegSvcs registration. The SpatialDataLibrary name appears in the Global Assembly Cache list after insertion with the GacUtil command.

There are six CSHARP source files used in the building of the SpatialDataLibrary.DLL. These are

AssemblyInfo.cs Controls the .NET assembly of the DLL for version and key

LonLatPt.cs Defines the LonLatPt struct

Projection.cs Defines the Projection class

SpatialData.cs Defines SpatialDataLibrary Namespace

SpatialToVml.cs Adds Vml methods to the SpatialDataLibrary Namespace

UtmPt.cs Defines the UtmPt struct

The Microsoft .NET environment is required to build the CSHARP components into the binary DLL.

There are five C++ source files used in the building of the SdeApi.DLL. These are

AssemblyInfo.cpp Controls the .NET assembly of the DLL for version and key

SdeApi.cpp Contains the main code for accessing the SDE database with SE calls

SdeException.cpp Defines the behavior for exceptions

Stdafx.cpp Includes the standard includes

Unmanaged.cpp Uses SE calls to get parts and points

The logic for access to the DLLs with OMS-RCN is as follows:

ASPX .NET WEB APP ASMX .NET SOAP SERVICE SpatialDataLibrary C# DLL SdeApi C++ DLL ESRI SDE C API SQL/SDE Database

4.6 JAKARTA TOMCAT WEB SERVICE

A TR55S.jws java web service is used to compute the runoff curve number. TR55S.jws is installed in the $TOMCAT/webapps/axis directory. The OMS-RCN-Services web service calls the TR55S.jws Java web service in order to determine the CN and calculate the weighted CN. This information is stored with the soils, area, land cover, and other attribute data in the tabular and spatial database. The TR55S WSDL interface document is published at http://cougar.itc.nrcs.usda.gov:8080/axis/TR55S.jws?wsdl .

Jakarta Tomcat is available from http://jakarta.apache.org and Axis is available from http://ws.apache.org/axis.

9

Page 12: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

5.0 CONCLUSION

5.1 BENEFITS

The OMS-RCN calculator has been developed to reduce the amount of time required to compute the weighted runoff curve number. It does so by automating the process of overlaying hypsography data over NRCS soil maps and in the process provides distinct soils polygons and soils data within user defined areas. This not only reduces the amount of time required to compute the weighted CN, it provides a consistent and repeatable procedure across the U.S. for the computation of CN values.

The combination of the Microsoft .NET COM+ and ESRI C API provide an efficient access to the NRCS soils data. These algorithms provide large areas of NRCS soils data within several seconds.

5.2 CONSTRAINTS

There are two user processes required for successful computation of the weighted RCN. The user must digitize the area under consideration. This is not a new requirement; the area would have had to be delineated on a topography map; however NRCS is working on developing automated procedures to define drainage boundaries given the national elevation data.

The user must enter the land cover for each sub-area that was defined. This also is not a new requirement. A detailed knowledge of the land is still required in order to assign the correct land cover. The ortho-photo image is helpful to delineate the land cover boundaries; however, users must assign the land cover to each sub-area.

6.0 APPENDICES

6.1 SDEAPI LISTING File: AssemblyInfo.cpp 1: #include "stdafx.h" 2: 3: using namespace System::Reflection; 4: using namespace System::Runtime::CompilerServices; 5: using namespace System::EnterpriseServices;

6: 7: [assembly:AssemblyTitleAttribute("")]; 8: [assembly:AssemblyDescriptionAttribute("")]; 9: [assembly:AssemblyConfigurationAttribute("")]; 10: [assembly:AssemblyCompanyAttribute("")]; 11: [assembly:AssemblyProductAttribute("")]; 12: [assembly:AssemblyCopyrightAttribute("")]; 13: [assembly:AssemblyTrademarkAttribute("")]; 14: [assembly:AssemblyCultureAttribute("")]; 15: [assembly:AssemblyVersionAttribute("1.0.*")]; 16: [assembly:AssemblyDelaySignAttribute(false)]; 17: [assembly:AssemblyKeyFileAttribute("sdeapikey.snk")]; 18: [assembly:AssemblyKeyNameAttribute("")]; 19: [assembly:ApplicationActivation(ActivationOption::Server)]; 20: [assembly:ApplicationName("SmartTech")]; End of File: AssemblyInfo.cpp File: SdeApi.cpp 1: // This is the main DLL file. 2: 3: #pragma once 4: #include "StdAfx.h" 5: #include "SdeApi.h" 6: 7: namespace SdeApi 8: { 9: Sde::Sde() { 10: um_connection = new UmConnection; 11: connected = false; 12: } 13: 14: Sde::~Sde() { 15: SE_connection_free(um_connection->ptr); 16: delete um_connection; 17: } 18: 19: bool Sde::CanBePooled() { 20: return true; 21: } 22: 23: void Sde::Disconnect() { 24: SE_connection_free(um_connection->ptr); 25: connected = false; 26: } 27: 28: int Sde::ConnectionState() { 29: if(um_connection == NULL) { 30: return -1; 31: } 32: 33: char serverName[SE_MAX_SERVER_LEN]; 34: 35: return SE_connection_get_server_name(um_connection->ptr, serverName); 36: } 37: 38: void Sde::Connect( 39: String * server, 40: String * instance, 41: String * database, 42: String * user, 43: String * password 44: ) 45: { 46: char * cserver; 47: char * cinstance; 48: char * cdatabase; 49: char * cuser; 50: char * cpassword; 51: 52: SE_ERROR errptr;

10

Page 13: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

53: 54: if(connected == true) { 55: return; 56: } 57: 58: try { 59: cserver = (char *)Marshal::StringToHGlobalAnsi(server).ToPointer(); 60: cinstance = (char *)Marshal::StringToHGlobalAnsi(instance).ToPointer(); 61: cdatabase = (char *)Marshal::StringToHGlobalAnsi(database).ToPointer(); 62: cuser = (char *)Marshal::StringToHGlobalAnsi(user).ToPointer(); 63: cpassword = (char *)Marshal::StringToHGlobalAnsi(password).ToPointer(); 64: 65: CE(SE_connection_create(cserver,cinstance, cdatabase, cuser, cpassword, &errptr, &um_connection->ptr)); 66: connected = true; 67: } catch (System::Exception * sysex) { 68: throw sysex; 69: } __finally { 70: Marshal::FreeHGlobal(cserver); 71: Marshal::FreeHGlobal(cinstance); 72: Marshal::FreeHGlobal(cdatabase); 73: Marshal::FreeHGlobal(cuser); 74: Marshal::FreeHGlobal(cpassword); 75: } 76: } 77: 78: UmShape * Sde::GeometryToShape(IGeometry * geometry, UmCoordref * um_coordref) 79: { 80: UmShape * um_shape; 81: switch(geometry->GetFeatureType()) { 82: case FeatureType::BoxType: 83: um_shape = BoxToShape(__try_cast<Box *>(geometry), um_coordref); 84: break; 85: 86: case FeatureType::PointType: 87: um_shape = PointToShape(__try_cast<Point *>(geometry), um_coordref); 88: break; 89: 90: case FeatureType::MultiPointType: 91: um_shape = MultiPointToShape(__try_cast<MultiPoint *>(geometry), um_coordref); 92: break; 93: 94: case FeatureType::LineStringType: 95: um_shape = LineStringToShape(__try_cast<LineString *>(geometry), um_coordref); 96: break; 97: 98: case FeatureType::MultiLineStringType: 99: um_shape = MultiLineStringToShape(__try_cast<MultiLineString *>(geometry), um_coordref); 100: break; 101: 102: case FeatureType::PolygonType: 103: um_shape = PolygonToShape(__try_cast<Polygon *>(geometry), um_coordref); 104: break; 105: 106: case FeatureType::MultiPolygonType: 107: um_shape = MultiPolygonToShape(__try_cast<MultiPolygon *>(geometry), um_coordref); 108: break;

109: 110: default: 111: break; 112: } 113: return um_shape; 114: } 115: 116: UmShape * Sde::BoxToShape(Box * box, UmCoordref * um_coordref) 117: { 118: SE_ENVELOPE se_box; 119: UmShape * um_shape = new UmShape; 120: 121: se_box.minx = box->Min->X; 122: se_box.miny = box->Min->Y; 123: se_box.maxx = box->Max->X; 124: se_box.maxy = box->Max->Y; 125: 126: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 127: CE(SE_shape_generate_rectangle(&se_box, um_shape->ptr)); 128: 129: return um_shape; 130: } 131: 132: UmShape * Sde::PointToShape(Point * point, UmCoordref * um_coordref) 133: { 134: SE_POINT __nogc * point_array; 135: UmShape * um_shape = new UmShape; 136: 137: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 138: 139: try 140: { 141: point_array = new SE_POINT[1]; 142: point_array[0].x = point->coord->X; 143: point_array[0].y = point->coord->Y; 144: 145: CE(SE_shape_generate_point(1, point_array, NULL, NULL, um_shape->ptr)); 146: } 147: __finally 148: { 149: delete[] point_array; 150: } 151: 152: return um_shape; 153: } 154: 155: UmShape * Sde::MultiPointToShape(MultiPoint * multiPoint, UmCoordref * um_coordref) 156: { 157: SE_POINT __nogc * point_array; 158: UmShape * um_shape = new UmShape; 159: int i, point_count; 160: 161: point_count = multiPoint->coordinates->Count; 162: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 163: 164: try 165: { 166: point_array = new SE_POINT[point_count]; 167: for(i = 0; i < point_count; i++) { 168: point_array[i].x = multiPoint->coordinates[i]->X; 169: point_array[i].y = multiPoint->coordinates[i]->Y; 170: } 171: 172: CE(SE_shape_generate_point(point_count, point_array, NULL, NULL, um_shape->ptr)); 173: }

11

Page 14: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

174: __finally 175: { 176: delete[] point_array; 177: } 178: 179: return um_shape; 180: } 181: 182: UmShape * Sde::LineStringToShape(LineString * lineString, UmCoordref * um_coordref) 183: { 184: SE_POINT __nogc * point_array; 185: int num_pts, i; 186: 187: UmShape * um_shape = new UmShape; 188: 189: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 190: num_pts = lineString->coordinates->Count; 191: try 192: { 193: point_array = new SE_POINT[num_pts]; 194: for(i = 0; i < num_pts; i++) { 195: point_array[i].x = lineString->coordinates[i]->X; 196: point_array[i].y = lineString->coordinates[i]->Y; 197: } 198: 199: CE(SE_shape_generate_line(num_pts, 1, NULL, point_array, NULL, NULL, um_shape->ptr)); 200: } 201: __finally 202: { 203: delete[] point_array; 204: } 205: 206: return um_shape; 207: } 208: 209: UmShape * Sde::MultiLineStringToShape(MultiLineString * multiLineString, UmCoordref * um_coordref) 210: { 211: UmShape * um_line; 212: UmShape * um_shape = new UmShape; 213: 214: int i, num_lines; 215: 216: num_lines = multiLineString->lineStrings->Count; 217: 218: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 219: 220: for(i = 0; i < num_lines; i++) { 221: try 222: { 223: um_line = LineStringToShape(multiLineString->lineStrings[i], um_coordref); 224: CE(SE_shape_add_part(um_line->ptr, um_shape->ptr)); 225: } 226: __finally 227: { 228: SE_shape_free(um_line->ptr); 229: delete um_line; 230: } 231: } 232: 233: return um_shape; 234: } 235: 236: UmShape * Sde::PolygonToShape(Polygon * polygon, UmCoordref * um_coordref) 237: { 238: SE_POINT __nogc * point_array;

239: SE_SDEPOINT __nogc * island_array; 240: int num_pts, inner_num_pts, i, j; 241: 242: LinearRing * outerBoundary = polygon->outerBoundary; 243: LinearRing * innerBoundaries[] = polygon->innerBoundaries; 244: LinearRing * innerBoundary; 245: 246: UmShape * um_shape = new UmShape; 247: 248: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 249: num_pts = outerBoundary->coordinates->Count; 250: 251: try 252: { 253: point_array = new SE_POINT[num_pts]; 254: for(i = 0; i < num_pts; i++) { 255: point_array[i].x = outerBoundary->coordinates[i]->X; 256: point_array[i].y = outerBoundary->coordinates[i]->Y; 257: } 258: 259: CE(SE_shape_generate_polygon(num_pts, 1, NULL, point_array, NULL, NULL, um_shape->ptr)); 260: 261: if(innerBoundaries != NULL) { 262: for(i = i; i < innerBoundaries->Count; i++) { 263: try { 264: innerBoundary = innerBoundaries[i]; 265: inner_num_pts = innerBoundary->coordinates->Count; 266: island_array = new SE_SDEPOINT[inner_num_pts]; 267: for(j = 0; j < inner_num_pts; j++) { 268: island_array[i].x = innerBoundary->coordinates[j]->X; 269: island_array[i].y = innerBoundary->coordinates[j]->Y; 270: island_array[i].z = 0; 271: island_array[i].m = 0; 272: } 273: CE(SE_shape_add_island(um_shape->ptr, island_array, inner_num_pts)); 274: } 275: __finally 276: { 277: delete[] island_array; 278: } 279: } 280: } 281: } 282: __finally 283: { 284: delete[] point_array; 285: } 286: return um_shape; 287: } 288: 289: UmShape * Sde::MultiPolygonToShape(MultiPolygon * multiPolygon, UmCoordref * um_coordref) 290: { 291: UmShape * um_poly; 292: UmShape * um_shape = new UmShape; 293: 294: int i, num_polys; 295: 296: num_polys = multiPolygon->polygons->Count; 297: 298: CE(SE_shape_create(um_coordref->ptr, &um_shape->ptr)); 299: 300: for(i = 0; i < num_polys; i++) { 301: try 302: { 303: um_poly = PolygonToShape(multiPolygon->polygons[i], um_coordref); 304: CE(SE_shape_add_part(um_poly->ptr, um_shape->ptr));

12

Page 15: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

305: } 306: __finally 307: { 308: SE_shape_free(um_poly->ptr); 309: delete um_poly; 310: } 311: } 312: 313: return um_shape; 314: } 315: 316: Coordinate * Sde::SubpartToCoordinates(UmShapeData * usd, int index)[] 317: { 318: Coordinate * coordinates[]; 319: int i, p, start, end; 320: 321: start = usd->subpart_offsets[index]; 322: end = usd->subpart_offsets[index+1]; 323: 324: coordinates = new Coordinate*[end - start]; 325: 326: for( 327: p = 0, i = start; 328: i < end; 329: p++, i++ 330: ) { 331: coordinates[p] = new Coordinate(usd->points[i].x, usd->points[i].y); 332: } 333: 334: return coordinates; 335: } 336: 337: IGeometry * Sde::ShapeToGeometry(UmShape * um_shape) { 338: LONG shapeType; 339: IGeometry * geometry; 340: 341: CE(SE_shape_get_type(um_shape->ptr, &shapeType)); 342: 343: switch(shapeType) { 344: case SG_POINT_SHAPE: 345: return PointToGeometry(um_shape); 346: break; 347: 348: case SG_LINE_SHAPE: 349: case SG_SIMPLE_LINE_SHAPE: 350: return LineStringToGeometry(um_shape); 351: break; 352: 353: case SG_AREA_SHAPE: 354: return PolygonToGeometry(um_shape); 355: break; 356: 357: case SG_MULTI_POINT_SHAPE: 358: return MultiPointToGeometry(um_shape); 359: break; 360: 361: case SG_MULTI_LINE_SHAPE: 362: case SG_MULTI_SIMPLE_LINE_SHAPE: 363: return MultiLineStringToGeometry(um_shape); 364: break; 365: 366: case SG_MULTI_AREA_SHAPE: 367: return MultiPolygonToGeometry(um_shape); 368: break; 369: 370: default: 371: break; 372: }

373: 374: return geometry; 375: } 376: 377: Point * Sde::PointToGeometry(UmShape * um_shape) 378: { 379: Point * point; 380: UmShapeData * usd; 381: 382: try 383: { 384: usd = new UmShapeData(um_shape); 385: if(usd->num_points > 0) { 386: point = new Point(usd->points[0].x, usd->points[0].y); 387: } else { 388: point = new Point(); 389: } 390: } 391: __finally 392: { 393: delete usd; 394: } 395: 396: return point; 397: } 398: 399: MultiPoint * Sde::MultiPointToGeometry(UmShape * um_shape) 400: { 401: MultiPoint * multiPoint; 402: UmShapeData * usd; 403: int i; 404: 405: try 406: { 407: usd = new UmShapeData(um_shape); 408: if(usd->num_points > 0) { 409: multiPoint = new MultiPoint(usd->num_points); 410: for(i = 0; i < usd->num_points; i++) { 411: multiPoint->coordinates[i] = new Coordinate(usd->points[i].x, usd->points[i].y); 412: } 413: 414: } else { 415: multiPoint = new MultiPoint(); 416: } 417: } 418: __finally 419: { 420: delete usd; 421: } 422: 423: return multiPoint; 424: } 425: 426: LineString * Sde::LineStringToGeometry(UmShape * um_shape) 427: { 428: LineString * lineString; 429: UmShapeData * usd; 430: int i; 431: 432: try 433: { 434: usd = new UmShapeData(um_shape); 435: if(usd->num_points > 0) { 436: lineString = new LineString(usd->num_points); 437: for(i = 0; i < usd->num_points; i++) { 438: lineString->coordinates[i] = new Coordinate(usd->points[i].x, usd->points[i].y); 439: } 440: } else {

13

Page 16: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

441: lineString = new LineString(); 442: } 443: } 444: __finally 445: { 446: delete usd; 447: } 448: 449: return lineString; 450: } 451: 452: MultiLineString * Sde::MultiLineStringToGeometry(UmShape * um_shape) 453: { 454: MultiLineString * multiLineString; 455: UmShapeData * usd; 456: int i; 457: 458: try 459: { 460: usd = new UmShapeData(um_shape); 461: if(usd->num_points > 0) { 462: multiLineString = new MultiLineString(usd->num_subparts); 463: for(i = 0; i < usd->num_subparts; i++) { 464: multiLineString->lineStrings[i] = new LineString(SubpartToCoordinates(usd, i)); 465: } 466: } else { 467: multiLineString = new MultiLineString(); 468: } 469: } 470: __finally 471: { 472: delete usd; 473: } 474: 475: return multiLineString; 476: } 477: 478: SpatialDataLibrary::Polygon * Sde::PolygonToGeometry(UmShape * um_shape) 479: { 480: SpatialDataLibrary::Polygon * polygon; 481: UmShapeData * usd; 482: int i; 483: 484: try 485: { 486: usd = new UmShapeData(um_shape); 487: if(usd->num_points > 0) { 488: polygon = new Polygon(); 489: polygon->outerBoundary = new LinearRing(SubpartToCoordinates(usd, 0)); 490: 491: if(usd->num_subparts > 1) { 492: polygon->innerBoundaries = new LinearRing*[usd->num_subparts - 1]; 493: for(i = 1; i < usd->num_subparts; i++) { 494: polygon->innerBoundaries[i-1] = new LinearRing(SubpartToCoordinates(usd, i)); 495: } 496: } 497: } else { 498: polygon = new Polygon(); 499: } 500: } 501: __finally 502: { 503: delete usd; 504: }

505: 506: return polygon; 507: } 508: 509: MultiPolygon * Sde::MultiPolygonToGeometry(UmShape * um_shape) 510: { 511: MultiPolygon * multiPolygon; 512: SpatialDataLibrary::Polygon * polygon; 513: UmShapeData * usd; 514: int i, j, p, start, end, subpart_count; 515: 516: try 517: { 518: usd = new UmShapeData(um_shape); 519: if(usd->num_points > 0) { 520: multiPolygon = new MultiPolygon(usd->num_parts); 521: for(i = 0; i < usd->num_parts; i++) { 522: polygon = new SpatialDataLibrary::Polygon(); 523: multiPolygon->polygons[i] = polygon; 524: start = usd->part_offsets[i]; 525: end = usd->part_offsets[i+1]; 526: subpart_count = end - start; 527: 528: if(subpart_count > 1) { 529: polygon->innerBoundaries = new LinearRing*[subpart_count - 1]; 530: } 531: 532: for( 533: p = 0, j = start; 534: j < end; 535: p++, j++ 536: ) { 537: if(p == 0) { 538: polygon->outerBoundary = new LinearRing( 539: SubpartToCoordinates(usd, j)); 540: } else { 541: polygon->innerBoundaries[p-1] = new LinearRing( 542: SubpartToCoordinates(usd, j)); 543: } 544: } 545: } 546: } else { 547: multiPolygon = new MultiPolygon(); 548: } 549: } 550: __finally 551: { 552: delete usd; 553: } 554: 555: return multiPolygon; 556: } 557: 558: FeatureSet * Sde::Query( 559: String * table[], 560: QueryColumn * column[], 561: String * where, 562: SpatialConstraint * constraint, 563: IGeometry * clip, 564: int coordrefid 565: ) { 566: FeatureSet * featureSet = new FeatureSet(); 567: ArrayList * tempFeatureList; 568: Feature * feature; 569: Feature * tempFeature; 570: LONG num_clip_shapes; 571: SE_SHAPE * se_clip_shapes; 572:

14

Page 17: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

573: int i, j; 574: char __nogc ** um_columns; 575: SE_SQL_CONSTRUCT * se_sqlconstruct; 576: 577: char * cspatialTable; 578: char * cspatialColumn; 579: 580: SE_LAYERINFO se_layerinfo; 581: SE_FILTER filter; 582: 583: SE_STREAM se_stream; 584: UmCoordref * um_coordref; 585: UmShape * um_shape; 586: UmShape * um_constraint; 587: 588: Box * box; 589: SE_ENVELOPE se_clipenvelope; 590: UmShape * um_clipshape; 591: UmShape * um_tempshape; 592: UmShape * um_projshape; 593: 594: SE_COORDREF se_projcoordref; 595: bool clipshape = false; 596: bool clipenvelope = false; 597: 598: int sdeColIdx; 599: 600: double dvalue; 601: long lvalue; 602: char __nogc * svalue; 603: SE_COLUMN_DEF column_def; 604: 605: int tableCount; 606: int columnCount; 607: 608: IEnumerator * enu; 609: 610: tableCount = table->Count; 611: columnCount = column->Count; 612: 613: try { 614: CE(SE_stream_create(um_connection->ptr, &se_stream)); 615: CE(SE_sql_construct_alloc(tableCount, &se_sqlconstruct)); 616: 617: um_shape = new UmShape; 618: um_tempshape = new UmShape; 619: 620: um_columns = new char*[columnCount]; 621: for(i = 0; i < columnCount; i++) { 622: um_columns[i] = (char *)Marshal::StringToHGlobalAnsi( 623: column[i]->ColumnName).ToPointer(); 624: } 625: 626: se_sqlconstruct->num_tables = tableCount; 627: for(i = 0; i < tableCount; i++) { 628: se_sqlconstruct->tables[i] = (char *)Marshal::StringToHGlobalAnsi( 629: table[i]).ToPointer(); 630: } 631: 632: if(where != NULL) { 633: se_sqlconstruct->where = (char *)Marshal::StringToHGlobalAnsi( 634: where).ToPointer(); 635: } 636: 637: CE(SE_stream_query( 638: se_stream, 639: columnCount, 640: (const char **)um_columns,

641: se_sqlconstruct 642: )); 643: 644: um_coordref = new UmCoordref; 645: 646: if(constraint != NULL) { 647: try { 648: cspatialTable = (char *)Marshal::StringToHGlobalAnsi( 649: constraint->Table).ToPointer(); 650: cspatialColumn = (char *)Marshal::StringToHGlobalAnsi( 651: constraint->Column).ToPointer(); 652: 653: CE(SE_layerinfo_create(NULL, &se_layerinfo)); 654: CE(SE_coordref_create(&um_coordref->ptr)); 655: CE(SE_layer_get_info( 656: um_connection->ptr, 657: cspatialTable, 658: cspatialColumn, 659: se_layerinfo 660: )); 661: CE(SE_layerinfo_get_coordref(se_layerinfo, um_coordref->ptr)); 662: 663: um_constraint = GeometryToShape(constraint->Constraint, um_coordref); 664: 665: strcpy(filter.table, cspatialTable); 666: strcpy(filter.column, cspatialColumn); 667: filter.filter_type = SE_SHAPE_FILTER; 668: filter.filter.shape = um_constraint->ptr; 669: filter.method = constraint->Method; 670: filter.truth = TRUE; 671: if(constraint->Truth == false) 672: filter.truth = FALSE; 673: 674: CE(SE_stream_set_spatial_constraints( 675: se_stream, 676: SE_SPATIAL_FIRST, 677: FALSE, 678: 1, 679: &filter 680: )); 681: } 682: __finally 683: { 684: if(um_constraint) { 685: SE_shape_free(um_constraint->ptr); 686: delete um_constraint; 687: } 688: } 689: } 690: 691: if(clip != NULL) { 692: if(clip->GetFeatureType() == BoxType) { 693: box = __try_cast<Box *>(clip); 694: se_clipenvelope.minx = box->Min->X; 695: se_clipenvelope.miny = box->Min->Y; 696: se_clipenvelope.maxx = box->Max->X; 697: se_clipenvelope.maxy = box->Max->Y; 698: } else { 699: um_clipshape = GeometryToShape(clip, um_coordref); 700: } 701: } 702: 703: if(coordrefid > 0) 704: { 705: CE(SE_coordref_create(&se_projcoordref)); 706: CE(SE_coordref_set_by_id(se_projcoordref, coordrefid)); 707: 708: }

15

Page 18: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

709: 710: featureSet->QueryStampStart(); 711: CE(SE_stream_execute(se_stream)); 712: 713: while(SE_stream_fetch(se_stream) == SE_SUCCESS) { 714: feature = new Feature(); 715: tempFeatureList = NULL; 716: for(i = 0; i < columnCount; i++) { 717: sdeColIdx = i + 1; 718: switch(column[i]->ColumnType) { 719: case DoubleQCType: 720: CE(SE_stream_get_double(se_stream, sdeColIdx, &dvalue)); 721: feature->attributes->Add( 722: column[i]->ColumnName->Clone(), 723: __box(dvalue)); 724: break; 725: 726: case IntegerQCType: 727: CE(SE_stream_get_integer(se_stream, sdeColIdx, &lvalue)); 728: feature->attributes->Add( 729: column[i]->ColumnName->Clone(), 730: __box(lvalue)); 731: break; 732: 733: case ShapeQCType: 734: try { 735: CE(SE_shape_create(NULL, &um_shape->ptr)); 736: CE(SE_stream_get_shape( 737: se_stream, 738: sdeColIdx, 739: um_shape->ptr 740: )); 741: 742: if(clip != NULL) { 743: if(clip->GetFeatureType() == BoxType) { 744: try { 745: CE(SE_shape_create(NULL, &um_tempshape->ptr)); 746: CE(SE_shape_clip( 747: um_shape->ptr, 748: &se_clipenvelope, 749: um_tempshape->ptr 750: )); 751: 752: if(coordrefid > 0) { 753: try { 754: um_projshape = new UmShape(); 755: CE(SE_shape_create(NULL, &um_projshape->ptr)); 756: CE(SE_shape_change_coordref( 757: um_tempshape->ptr, 758: se_projcoordref, 759: NULL, 760: um_projshape->ptr 761: )); 762: feature->geometry = ShapeToGeometry(um_projshape); 763: } catch (Exception * ignorebadshape) { 764: try { 765: feature->geometry = ShapeToGeometry(um_tempshape); 766: feature->AddAttribute( 767: new String("ProjectionError"), 768: new String("Nad83GcsToPcs")); 769: } catch(Exception * ignorebadshape2) { 770: feature->geometry = new NullShape(); 771: ignorebadshape2 = NULL; 772: } 773: ignorebadshape = NULL; 774: } __finally { 775: SE_shape_free(um_projshape->ptr); 776: delete um_projshape; 777: } 778: } else {

779: feature->geometry = ShapeToGeometry(um_tempshape); 780: } 781: 782: } __finally { 783: SE_shape_free(um_tempshape->ptr); 784: } 785: } else { 786: tempFeatureList = new ArrayList(); 787: try { 788: CE(SE_shape_intersect( 789: um_clipshape->ptr, 790: um_shape->ptr, 791: &num_clip_shapes, 792: &se_clip_shapes 793: )); 794: for(j = 0; j < num_clip_shapes; j++) { 795: if(coordrefid > 0) { 796: try { 797: CE(SE_shape_create(NULL, &um_tempshape->ptr)); 798: CE(SE_shape_change_coordref( 799: se_clip_shapes[j], 800: se_projcoordref, 801: NULL, 802: um_tempshape->ptr 803: )); 804: tempFeature = new Feature(); 805: tempFeature->geometry = ShapeToGeometry(um_tempshape); 806: tempFeatureList->Add(tempFeature); 807: 808: } __finally { 809: SE_shape_free(um_tempshape->ptr); 810: } 811: } else { 812: tempFeature = new Feature(); 813: um_tempshape->ptr = se_clip_shapes[j]; 814: tempFeature->geometry = ShapeToGeometry(um_tempshape); 815: tempFeatureList->Add(tempFeature); 816: } 817: } 818: } __finally { 819: SE_shape_free_array(num_clip_shapes, se_clip_shapes); 820: } 821: } 822: } else if(coordrefid > 0) { 823: try { 824: CE(SE_shape_create(NULL, &um_tempshape->ptr)); 825: CE(SE_shape_change_coordref( 826: um_shape->ptr, 827: se_projcoordref, 828: NULL, 829: um_tempshape->ptr 830: )); 831: feature->geometry = ShapeToGeometry(um_tempshape); 832: } __finally { 833: SE_shape_free(um_tempshape->ptr); 834: } 835: } else { 836: feature->geometry = ShapeToGeometry(um_shape); 837: } 838: } __finally { 839: try { 840: SE_shape_free(um_shape->ptr); 841: } catch(Exception * ignore) { 842: ignore = NULL; 843: } 844: } 845: 846: break;

16

Page 19: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

847: 848: case StringQCType: 849: try { 850: CE(SE_stream_describe_column(se_stream, sdeColIdx, &column_def)); 851: svalue = new char[column_def.size + 1]; 852: CE(SE_stream_get_string(se_stream, sdeColIdx, svalue)); 853: feature->attributes->Add( 854: column[i]->ColumnName->Clone(), 855: new String(svalue)); 856: } __finally { 857: try { 858: delete[] svalue; 859: } catch(Exception * ignore) { 860: ignore = NULL; 861: } 862: } 863: break; 864: 865: default: 866: break; 867: } 868: } 869: if(tempFeatureList == NULL) { 870: featureSet->AddFeature(feature); 871: } else { 872: enu = tempFeatureList->GetEnumerator(); 873: while(enu->MoveNext()) { 874: tempFeature = dynamic_cast<Feature*>(enu->get_Current()); 875: tempFeature->attributes = feature->attributes; 876: featureSet->AddFeature(tempFeature); 877: } 878: tempFeatureList = NULL; 879: } 880: } 881: 882: 883: } 884: __finally { 885: try { 886: SE_stream_free(se_stream); 887: } catch(Exception * ignore) { 888: ignore = NULL; 889: } 890: 891: try { 892: Marshal::FreeHGlobal(cspatialTable); 893: } catch(Exception * ignore) { 894: ignore = NULL; 895: } 896: 897: try { 898: Marshal::FreeHGlobal(cspatialColumn); 899: } catch(Exception * ignore) { 900: ignore = NULL; 901: } 902: 903: try { 904: SE_layerinfo_free(se_layerinfo); 905: } catch(Exception * ignore) { 906: ignore = NULL; 907: } 908: 909: try { 910: SE_shape_free(um_shape->ptr); 911: delete um_shape; 912: } catch(Exception * ignore) { 913: ignore = NULL; 914: } 915:

916: try { 917: SE_shape_free(um_tempshape->ptr); 918: delete um_tempshape; 919: } catch(Exception * ignore) { 920: ignore = NULL; 921: } 922: 923: if(clip != NULL && clip->GetFeatureType() != BoxType) { 924: try { 925: SE_shape_free(um_clipshape->ptr); 926: delete um_clipshape; 927: } catch(Exception * ignore) { 928: ignore = NULL; 929: } 930: } 931: 932: try { 933: if(coordrefid > 0) { 934: SE_coordref_free(se_projcoordref); 935: } 936: } catch(Exception * ignore) { 937: ignore = NULL; 938: } 939: 940: try { 941: for(i = 0; i < columnCount; i++) { 942: Marshal::FreeHGlobal(um_columns[i]); 943: } 944: delete [] um_columns; 945: } catch(Exception * ignore) { 946: ignore = NULL; 947: } 948: 949: try { 950: for(i = 0; i < se_sqlconstruct->num_tables; i++) { 951: Marshal::FreeHGlobal(se_sqlconstruct->tables[i]); 952: } 953: } catch(Exception * ignore) { 954: ignore = NULL; 955: } 956: 957: try { 958: if(se_sqlconstruct->where) { 959: Marshal::FreeHGlobal(se_sqlconstruct->where); 960: } 961: } catch(Exception * ignore) { 962: ignore = NULL; 963: } 964: 965: try { 966: SE_sql_construct_free(se_sqlconstruct); 967: } catch(Exception * ignore) { 968: ignore = NULL; 969: } 970: 971: try { 972: if(um_coordref) { 973: SE_coordref_free(um_coordref->ptr); 974: delete um_coordref; 975: } 976: } catch(Exception * ignore) { 977: ignore = NULL; 978: } 979: } 980: 981: featureSet->QueryStampEnd(); 982: return featureSet; 983: } 984: 985: FeatureSet * Sde::umQuery(

17

Page 20: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

986: String * table[], 987: QueryColumn * column[], 988: String * where, 989: SpatialConstraint * constraint, 990: IGeometry * clip, 991: UmCoordref * um_coordref, 992: int coordrefid 993: ) { 994: FeatureSet * featureSet = new FeatureSet(); 995: ArrayList * tempFeatureList; 996: Feature * feature; 997: Feature * tempFeature; 998: LONG num_clip_shapes; 999: SE_SHAPE * se_clip_shapes; 1000: 1001: int i, j; 1002: char __nogc ** um_columns; 1003: SE_SQL_CONSTRUCT * se_sqlconstruct; 1004: 1005: char * cspatialTable; 1006: char * cspatialColumn; 1007: 1008: SE_LAYERINFO se_layerinfo; 1009: SE_FILTER filter; 1010: 1011: SE_STREAM se_stream; 1012: UmShape * um_shape; 1013: UmShape * um_constraint; 1014: 1015: Box * box; 1016: SE_ENVELOPE se_clipenvelope; 1017: UmShape * um_clipshape; 1018: UmShape * um_tempshape; 1019: UmShape * um_projshape; 1020: 1021: SE_COORDREF se_projcoordref; 1022: bool clipshape = false; 1023: bool clipenvelope = false; 1024: 1025: int sdeColIdx; 1026: 1027: double dvalue; 1028: long lvalue; 1029: char __nogc * svalue; 1030: SE_COLUMN_DEF column_def; 1031: 1032: int tableCount; 1033: int columnCount; 1034: 1035: IEnumerator * enu; 1036: 1037: tableCount = table->Count; 1038: columnCount = column->Count; 1039: 1040: try { 1041: CE(SE_stream_create(um_connection->ptr, &se_stream)); 1042: CE(SE_sql_construct_alloc(tableCount, &se_sqlconstruct)); 1043: 1044: um_shape = new UmShape; 1045: um_tempshape = new UmShape; 1046: 1047: um_columns = new char*[columnCount]; 1048: for(i = 0; i < columnCount; i++) { 1049: um_columns[i] = (char *)Marshal::StringToHGlobalAnsi( 1050: column[i]->ColumnName).ToPointer(); 1051: } 1052: 1053: se_sqlconstruct->num_tables = tableCount; 1054: for(i = 0; i < tableCount; i++) {

1055: se_sqlconstruct->tables[i] = (char *)Marshal::StringToHGlobalAnsi( 1056: table[i]).ToPointer(); 1057: } 1058: 1059: if(where != NULL) { 1060: se_sqlconstruct->where = (char *)Marshal::StringToHGlobalAnsi( 1061: where).ToPointer(); 1062: } 1063: 1064: CE(SE_stream_query( 1065: se_stream, 1066: columnCount, 1067: (const char **)um_columns, 1068: se_sqlconstruct 1069: )); 1070: 1071: if(constraint != NULL) { 1072: try { 1073: cspatialTable = (char *)Marshal::StringToHGlobalAnsi( 1074: constraint->Table).ToPointer(); 1075: cspatialColumn = (char *)Marshal::StringToHGlobalAnsi( 1076: constraint->Column).ToPointer(); 1077: 1078: CE(SE_layerinfo_create(NULL, &se_layerinfo)); 1079: CE(SE_layer_get_info( 1080: um_connection->ptr, 1081: cspatialTable, 1082: cspatialColumn, 1083: se_layerinfo 1084: )); 1085: CE(SE_layerinfo_get_coordref(se_layerinfo, um_coordref->ptr)); 1086: 1087: um_constraint = GeometryToShape(constraint->Constraint, um_coordref); 1088: 1089: strcpy(filter.table, cspatialTable); 1090: strcpy(filter.column, cspatialColumn); 1091: filter.filter_type = SE_SHAPE_FILTER; 1092: filter.filter.shape = um_constraint->ptr; 1093: filter.method = constraint->Method; 1094: filter.truth = TRUE; 1095: if(constraint->Truth == false) 1096: filter.truth = FALSE; 1097: 1098: CE(SE_stream_set_spatial_constraints( 1099: se_stream, 1100: SE_SPATIAL_FIRST, 1101: FALSE, 1102: 1, 1103: &filter 1104: )); 1105: } 1106: __finally 1107: { 1108: if(um_constraint) { 1109: SE_shape_free(um_constraint->ptr); 1110: delete um_constraint; 1111: } 1112: } 1113: } 1114: 1115: if(clip != NULL) { 1116: if(clip->GetFeatureType() == BoxType) { 1117: box = __try_cast<Box *>(clip); 1118: se_clipenvelope.minx = box->Min->X; 1119: se_clipenvelope.miny = box->Min->Y; 1120: se_clipenvelope.maxx = box->Max->X;

18

Page 21: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1121: se_clipenvelope.maxy = box->Max->Y; 1122: } else { 1123: um_clipshape = GeometryToShape(clip, um_coordref); 1124: } 1125: } 1126: 1127: if(coordrefid > 0) 1128: { 1129: CE(SE_coordref_create(&se_projcoordref)); 1130: CE(SE_coordref_set_by_id(se_projcoordref, coordrefid)); 1131: } 1132: 1133: featureSet->QueryStampStart(); 1134: CE(SE_stream_execute(se_stream)); 1135: 1136: while(SE_stream_fetch(se_stream) == SE_SUCCESS) { 1137: feature = new Feature(); 1138: tempFeatureList = NULL; 1139: for(i = 0; i < columnCount; i++) { 1140: sdeColIdx = i + 1; 1141: switch(column[i]->ColumnType) { 1142: case DoubleQCType: 1143: CE(SE_stream_get_double(se_stream, sdeColIdx, &dvalue)); 1144: feature->attributes->Add( 1145: column[i]->ColumnName->Clone(), 1146: __box(dvalue)); 1147: break; 1148: 1149: case IntegerQCType: 1150: CE(SE_stream_get_integer(se_stream, sdeColIdx, &lvalue)); 1151: feature->attributes->Add( 1152: column[i]->ColumnName->Clone(), 1153: __box(lvalue)); 1154: break; 1155: 1156: case ShapeQCType: 1157: try { 1158: CE(SE_shape_create(NULL, &um_shape->ptr)); 1159: CE(SE_stream_get_shape( 1160: se_stream, 1161: sdeColIdx, 1162: um_shape->ptr 1163: )); 1164: 1165: if(clip != NULL) { 1166: if(clip->GetFeatureType() == BoxType) { 1167: try { 1168: CE(SE_shape_create(NULL, &um_tempshape->ptr)); 1169: CE(SE_shape_clip( 1170: um_shape->ptr, 1171: &se_clipenvelope, 1172: um_tempshape->ptr 1173: )); 1174: 1175: if(coordrefid > 0) { 1176: try { 1177: um_projshape = new UmShape(); 1178: CE(SE_shape_create(NULL, &um_projshape->ptr)); 1179: CE(SE_shape_change_coordref( 1180: um_tempshape->ptr, 1181: se_projcoordref, 1182: NULL, 1183: um_projshape->ptr 1184: )); 1185: feature->geometry = ShapeToGeometry(um_projshape); 1186: } catch (Exception * ignorebadshape) { 1187: try { 1188: feature->geometry = ShapeToGeometry(um_tempshape); 1189: feature->AddAttribute( 1190: new String("ProjectionError"),

1191: new String("Nad83GcsToPcs")); 1192: } catch(Exception * ignorebadshape2) { 1193: feature->geometry = new NullShape(); 1194: ignorebadshape2 = NULL; 1195: } 1196: ignorebadshape = NULL; 1197: } __finally { 1198: SE_shape_free(um_projshape->ptr); 1199: delete um_projshape; 1200: } 1201: } else { 1202: feature->geometry = ShapeToGeometry(um_tempshape); 1203: } 1204: 1205: } __finally { 1206: SE_shape_free(um_tempshape->ptr); 1207: } 1208: } else { 1209: tempFeatureList = new ArrayList(); 1210: try { 1211: CE(SE_shape_intersect( 1212: um_clipshape->ptr, 1213: um_shape->ptr, 1214: &num_clip_shapes, 1215: &se_clip_shapes 1216: )); 1217: for(j = 0; j < num_clip_shapes; j++) { 1218: if(coordrefid > 0) { 1219: try { 1220: CE(SE_shape_create(NULL, &um_tempshape->ptr)); 1221: CE(SE_shape_change_coordref( 1222: se_clip_shapes[j], 1223: se_projcoordref, 1224: NULL, 1225: um_tempshape->ptr 1226: )); 1227: tempFeature = new Feature(); 1228: tempFeature->geometry = ShapeToGeometry(um_tempshape); 1229: tempFeatureList->Add(tempFeature); 1230: 1231: } __finally { 1232: SE_shape_free(um_tempshape->ptr); 1233: } 1234: } else { 1235: tempFeature = new Feature(); 1236: um_tempshape->ptr = se_clip_shapes[j]; 1237: tempFeature->geometry = ShapeToGeometry(um_tempshape); 1238: tempFeatureList->Add(tempFeature); 1239: } 1240: } 1241: } __finally { 1242: SE_shape_free_array(num_clip_shapes, se_clip_shapes); 1243: } 1244: } 1245: } else if(coordrefid > 0) { 1246: try { 1247: CE(SE_shape_create(NULL, &um_tempshape->ptr)); 1248: CE(SE_shape_change_coordref( 1249: um_shape->ptr, 1250: se_projcoordref, 1251: NULL, 1252: um_tempshape->ptr 1253: )); 1254: feature->geometry = ShapeToGeometry(um_tempshape); 1255: } __finally { 1256: SE_shape_free(um_tempshape->ptr); 1257: } 1258: } else {

19

Page 22: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1259: feature->geometry = ShapeToGeometry(um_shape); 1260: } 1261: } __finally { 1262: try { 1263: SE_shape_free(um_shape->ptr); 1264: } catch(Exception * ignore) { 1265: ignore = NULL; 1266: } 1267: } 1268: 1269: break; 1270: 1271: case StringQCType: 1272: try { 1273: CE(SE_stream_describe_column(se_stream, sdeColIdx, &column_def)); 1274: svalue = new char[column_def.size + 1]; 1275: CE(SE_stream_get_string(se_stream, sdeColIdx, svalue)); 1276: feature->attributes->Add( 1277: column[i]->ColumnName->Clone(), 1278: new String(svalue)); 1279: } __finally { 1280: try { 1281: delete[] svalue; 1282: } catch(Exception * ignore) { 1283: ignore = NULL; 1284: } 1285: } 1286: break; 1287: 1288: default: 1289: break; 1290: } 1291: } 1292: if(tempFeatureList == NULL) { 1293: featureSet->AddFeature(feature); 1294: } else { 1295: enu = tempFeatureList->GetEnumerator(); 1296: while(enu->MoveNext()) { 1297: tempFeature = dynamic_cast<Feature*>(enu->get_Current()); 1298: tempFeature->attributes = feature->attributes; 1299: featureSet->AddFeature(tempFeature); 1300: } 1301: tempFeatureList = NULL; 1302: } 1303: } 1304: 1305: 1306: } 1307: __finally { 1308: try { 1309: SE_stream_free(se_stream); 1310: } catch(Exception * ignore) { 1311: ignore = NULL; 1312: } 1313: 1314: try { 1315: Marshal::FreeHGlobal(cspatialTable); 1316: } catch(Exception * ignore) { 1317: ignore = NULL; 1318: } 1319: 1320: try { 1321: Marshal::FreeHGlobal(cspatialColumn); 1322: } catch(Exception * ignore) { 1323: ignore = NULL; 1324: } 1325: 1326: try { 1327: SE_layerinfo_free(se_layerinfo);

1328: } catch(Exception * ignore) { 1329: ignore = NULL; 1330: } 1331: 1332: try { 1333: SE_shape_free(um_shape->ptr); 1334: delete um_shape; 1335: } catch(Exception * ignore) { 1336: ignore = NULL; 1337: } 1338: 1339: try { 1340: SE_shape_free(um_tempshape->ptr); 1341: delete um_tempshape; 1342: } catch(Exception * ignore) { 1343: ignore = NULL; 1344: } 1345: 1346: if(clip != NULL && clip->GetFeatureType() != BoxType) { 1347: try { 1348: SE_shape_free(um_clipshape->ptr); 1349: delete um_clipshape; 1350: } catch(Exception * ignore) { 1351: ignore = NULL; 1352: } 1353: } 1354: 1355: try { 1356: if(coordrefid > 0) { 1357: SE_coordref_free(se_projcoordref); 1358: } 1359: } catch(Exception * ignore) { 1360: ignore = NULL; 1361: } 1362: 1363: try { 1364: for(i = 0; i < columnCount; i++) { 1365: Marshal::FreeHGlobal(um_columns[i]); 1366: } 1367: delete [] um_columns; 1368: } catch(Exception * ignore) { 1369: ignore = NULL; 1370: } 1371: 1372: try { 1373: for(i = 0; i < se_sqlconstruct->num_tables; i++) { 1374: Marshal::FreeHGlobal(se_sqlconstruct->tables[i]); 1375: } 1376: } catch(Exception * ignore) { 1377: ignore = NULL; 1378: } 1379: 1380: try { 1381: if(se_sqlconstruct->where) { 1382: Marshal::FreeHGlobal(se_sqlconstruct->where); 1383: } 1384: } catch(Exception * ignore) { 1385: ignore = NULL; 1386: } 1387: 1388: try { 1389: SE_sql_construct_free(se_sqlconstruct); 1390: } catch(Exception * ignore) { 1391: ignore = NULL; 1392: } 1393: 1394: } 1395: 1396: featureSet->QueryStampEnd(); 1397: return featureSet;

20

Page 23: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1398: } 1399: 1400: FeatureSet * Sde::Intersect(IGeometry * A, IGeometry * B, int coordrefid) { 1401: FeatureSet * featureSet = new FeatureSet(); 1402: 1403: int i; 1404: 1405: UmShape * um_shapeA; 1406: UmShape * um_shapeB; 1407: UmShape * um_tempshape; 1408: UmCoordref * um_coordref; 1409: 1410: LONG num_ret_shapes; 1411: SE_SHAPE * se_ret_shapes; 1412: 1413: try { 1414: um_shapeA = new UmShape(); 1415: um_shapeB = new UmShape(); 1416: um_tempshape = new UmShape(); 1417: um_coordref = new UmCoordref(); 1418: 1419: CE(SE_coordref_create(&um_coordref->ptr)); 1420: CE(SE_coordref_set_by_id(um_coordref->ptr, coordrefid)); 1421: 1422: um_shapeA = GeometryToShape(A, um_coordref); 1423: um_shapeB = GeometryToShape(B, um_coordref); 1424: 1425: CE(SE_shape_intersect( 1426: um_shapeA->ptr, 1427: um_shapeB->ptr, 1428: &num_ret_shapes, 1429: &se_ret_shapes 1430: )); 1431: 1432: for(i = 0; i < num_ret_shapes; i++) { 1433: um_tempshape->ptr = se_ret_shapes[i]; 1434: featureSet->AddFeature(new Feature(ShapeToGeometry(um_tempshape))); 1435: } 1436: } __finally { 1437: SE_shape_free_array(num_ret_shapes, se_ret_shapes); 1438: SE_shape_free(um_shapeA->ptr); 1439: SE_shape_free(um_shapeB->ptr); 1440: SE_shape_free(um_tempshape->ptr); 1441: SE_coordref_free(um_coordref->ptr); 1442: 1443: try {delete um_shapeA;} catch(Exception * ignore) {ignore = NULL;} 1444: try {delete um_shapeB;} catch(Exception * ignore) {ignore = NULL;} 1445: try {delete um_tempshape;} catch(Exception * ignore) {ignore = NULL;} 1446: try {delete um_coordref;} catch(Exception * ignore) {ignore = NULL;} 1447: } 1448: return featureSet; 1449: } 1450: 1451: FeatureSet * Sde::Intersect(IGeometry * A, IGeometry * B, String * layerref, String * spatialcolumn) { 1452: FeatureSet * featureSet = new FeatureSet(); 1453: 1454: int i; 1455: 1456: UmShape * um_shapeA; 1457: UmShape * um_shapeB; 1458: UmShape * um_tempshape; 1459: UmCoordref * um_coordref; 1460:

1461: SE_LAYERINFO se_layerinfo; 1462: LONG num_ret_shapes; 1463: SE_SHAPE * se_ret_shapes; 1464: 1465: char * clayerref; 1466: char * cspatialcolumn; 1467: 1468: try { 1469: clayerref = (char *)Marshal::StringToHGlobalAnsi(layerref).ToPointer(); 1470: cspatialcolumn = (char *)Marshal::StringToHGlobalAnsi(spatialcolumn).ToPointer(); 1471: 1472: um_shapeA = new UmShape(); 1473: um_shapeB = new UmShape(); 1474: um_tempshape = new UmShape(); 1475: um_coordref = new UmCoordref(); 1476: 1477: CE(SE_layerinfo_create(NULL, &se_layerinfo)); 1478: CE(SE_coordref_create(&um_coordref->ptr)); 1479: CE(SE_layer_get_info( 1480: um_connection->ptr, 1481: clayerref, 1482: cspatialcolumn, 1483: se_layerinfo 1484: )); 1485: CE(SE_layerinfo_get_coordref(se_layerinfo, um_coordref->ptr)); 1486: 1487: um_shapeA = GeometryToShape(A, um_coordref); 1488: um_shapeB = GeometryToShape(B, um_coordref); 1489: 1490: CE(SE_shape_intersect( 1491: um_shapeA->ptr, 1492: um_shapeB->ptr, 1493: &num_ret_shapes, 1494: &se_ret_shapes 1495: )); 1496: 1497: for(i = 0; i < num_ret_shapes; i++) { 1498: um_tempshape->ptr = se_ret_shapes[i]; 1499: featureSet->AddFeature(new Feature(ShapeToGeometry(um_tempshape))); 1500: } 1501: } __finally { 1502: Marshal::FreeHGlobal(clayerref); 1503: Marshal::FreeHGlobal(cspatialcolumn); 1504: 1505: SE_shape_free_array(num_ret_shapes, se_ret_shapes); 1506: SE_shape_free(um_shapeA->ptr); 1507: SE_shape_free(um_shapeB->ptr); 1508: SE_shape_free(um_tempshape->ptr); 1509: SE_coordref_free(um_coordref->ptr); 1510: SE_layerinfo_free(se_layerinfo); 1511: 1512: try {delete um_shapeA;} catch(Exception * ignore) {ignore = NULL;} 1513: try {delete um_shapeB;} catch(Exception * ignore) {ignore = NULL;} 1514: try {delete um_tempshape;} catch(Exception * ignore) {ignore = NULL;} 1515: try {delete um_coordref;} catch(Exception * ignore) {ignore = NULL;} 1516: } 1517: return featureSet; 1518: } 1519: 1520: void Sde::Insert(String * table, String * spatialColumn, Feature * shape) 1521: {

21

Page 24: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1522: SE_LAYERINFO se_layerinfo; 1523: UmStream * um_stream; 1524: UmShape * um_shape; 1525: UmCoordref * um_coordref; 1526: 1527: char __nogc ** um_columns; 1528: char __nogc * um_spatial_column; 1529: char __nogc * um_table; 1530: 1531: char __nogc * um_value; 1532: double um_dvalue; 1533: 1534: int i, columnCount; 1535: Object * key; 1536: Object * value; 1537: Hashtable * Attributes; 1538: 1539: System::TypeCode valuetc; 1540: 1541: DictionaryEntry * entry; 1542: IDictionaryEnumerator * iden; 1543: 1544: try 1545: { 1546: um_stream = new UmStream; 1547: um_coordref = new UmCoordref; 1548: 1549: Attributes = shape->attributes; 1550: columnCount = Attributes->Count + 1; 1551: 1552: CE(SE_stream_create(um_connection->ptr, &um_stream->ptr)); 1553: CE(SE_layerinfo_create(NULL, &se_layerinfo)); 1554: CE(SE_coordref_create(&um_coordref->ptr)); 1555: 1556: um_columns = new char*[columnCount]; 1557: um_spatial_column = (char *)Marshal::StringToHGlobalAnsi(spatialColumn).ToPointer(); 1558: um_table = (char *)Marshal::StringToHGlobalAnsi(table).ToPointer(); 1559: 1560: um_columns[0] = (char *)Marshal::StringToHGlobalAnsi(spatialColumn).ToPointer(); 1561: for( 1562: i = 1, iden = Attributes->GetEnumerator(); 1563: iden->MoveNext(); 1564: i++ 1565: ) { 1566: entry = dynamic_cast<DictionaryEntry*>(iden->Current); 1567: key = entry->get_Key(); 1568: um_columns[i] = (char *)Marshal::StringToHGlobalAnsi(entry->Key->ToString()).ToPointer(); 1569: } 1570: 1571: CE(SE_layer_get_info(um_connection->ptr, um_table, um_spatial_column, se_layerinfo)); 1572: CE(SE_layerinfo_get_coordref(se_layerinfo, um_coordref->ptr)); 1573: um_shape = GeometryToShape(shape->geometry, um_coordref); 1574: 1575: CE(SE_stream_insert_table(um_stream->ptr, um_table, columnCount, (const char **)um_columns)); 1576: 1577: CE(SE_stream_set_shape(um_stream->ptr, 1, um_shape->ptr)); 1578: for( 1579: i = 2, iden = Attributes->GetEnumerator(); 1580: iden->MoveNext(); 1581: i++ 1582: ) {

1583: entry = dynamic_cast<DictionaryEntry*>(iden->Current); 1584: value = entry->Value; 1585: if(value) { 1586: valuetc = Type::GetTypeCode(value->GetType()); 1587: switch(valuetc) { 1588: case System::TypeCode::Double: 1589: um_dvalue = *dynamic_cast<__box double*>(value); 1590: CE(SE_stream_set_double(um_stream->ptr, i, &um_dvalue)); 1591: break; 1592: 1593: case System::TypeCode::String: 1594: try { 1595: um_value = (char *)Marshal::StringToHGlobalAnsi(value->ToString()).ToPointer(); 1596: CE(SE_stream_set_string(um_stream->ptr, i, um_value)); 1597: } __finally { 1598: Marshal::FreeHGlobal(um_value); 1599: } 1600: break; 1601: 1602: default: 1603: throw new System::Exception("Cannot handle type for an object. Supported types are double and string."); 1604: break; 1605: } 1606: } 1607: } 1608: 1609: CE(SE_stream_execute(um_stream->ptr)); 1610: i=0; 1611: } 1612: __finally 1613: { 1614: if(um_stream) { 1615: if(um_stream->ptr) { 1616: SE_stream_free(um_stream->ptr); 1617: um_stream->ptr = NULL; 1618: } 1619: delete um_stream; 1620: um_stream = NULL; 1621: } 1622: 1623: if(um_shape) { 1624: if(um_shape->ptr) { 1625: SE_shape_free(um_shape->ptr); 1626: } 1627: delete um_shape; 1628: } 1629: 1630: if(um_coordref) { 1631: if(um_coordref->ptr) { 1632: SE_coordref_free(um_coordref->ptr); 1633: } 1634: delete um_coordref; 1635: } 1636: 1637: if(se_layerinfo) { 1638: SE_layerinfo_free(se_layerinfo); 1639: } 1640: 1641: if(um_columns) { 1642: for(i = 0; i < columnCount; i++) { 1643: try { 1644: Marshal::FreeHGlobal(um_columns[i]); 1645: } __finally { 1646: // do nothing 1647: } 1648: } 1649: delete[] um_columns;

22

Page 25: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1650: } 1651: 1652: if(um_spatial_column) { 1653: Marshal::FreeHGlobal(um_spatial_column); 1654: } 1655: 1656: if(um_table) { 1657: Marshal::FreeHGlobal(um_table); 1658: } 1659: } 1660: } 1661: 1662: 1663: 1664: void Sde::Delete(String * table, String * where) 1665: { 1666: char __nogc * um_table; 1667: char __nogc * um_where; 1668: 1669: UmStream * um_stream; 1670: 1671: try 1672: { 1673: um_stream = new UmStream; 1674: CE(SE_stream_create(um_connection->ptr, &um_stream->ptr)); 1675: 1676: um_table = (char *)Marshal::StringToHGlobalAnsi(table).ToPointer(); 1677: um_where = (char *)Marshal::StringToHGlobalAnsi(where).ToPointer(); 1678: 1679: CE(SE_stream_delete_from_table(um_stream->ptr, um_table, um_where)); 1680: } 1681: __finally { 1682: if(um_stream) { 1683: if(um_stream->ptr) { 1684: SE_stream_free(um_stream->ptr); 1685: um_stream->ptr = NULL; 1686: } 1687: delete um_stream; 1688: um_stream = NULL; 1689: } 1690: 1691: if(um_table) { 1692: Marshal::FreeHGlobal(um_table); 1693: } 1694: 1695: if(um_where) { 1696: Marshal::FreeHGlobal(um_where); 1697: } 1698: } 1699: } 1700: } End of File: SdeApi.cpp File: SdeApi.h 1: // SdeApi.h 2: 3: #pragma once 4: #include "StdAfx.h" 5: #include "SdeException.h" 6: #include "Unmanaged.h" 7: 8: using namespace System; 9: using namespace System::Text; 10: using namespace System::Collections; 11: using namespace System::Runtime::InteropServices; 12: using namespace System::EnterpriseServices; 13: using namespace SpatialDataLibrary;

14: 15: namespace SdeApi 16: { 17: [ObjectPooling(true, 5, 20)] 18: public __gc class Sde : public ServicedComponent 19: { 20: public: 21: Sde(); 22: ~Sde(); 23: 24: bool CanBePooled(); 25: 26: void Connect( 27: String * server, 28: String * instance, 29: String * database, 30: String * user, 31: String * password); 32: 33: void Disconnect(); 34: 35: FeatureSet * Query( 36: String * table[], 37: QueryColumn * column[], 38: String * where, 39: SpatialConstraint * constraint, 40: IGeometry * clip, 41: int coordrefid 42: ); 43: 44: FeatureSet * umQuery( 45: String * table[], 46: QueryColumn * column[], 47: String * where, 48: SpatialConstraint * constraint, 49: IGeometry * clip, 50: UmCoordref * um_coordref, 51: int coordrefid 52: ); 53: 54: FeatureSet * Intersect(IGeometry * A, IGeometry * B, int coordrefid); 55: FeatureSet * Intersect(IGeometry * A, IGeometry * B, String * layerref, String * spatialcolumn); 56: 57: void Insert(String * table, String * spatialColumn, Feature * shape); 58: void Delete(String * table, String * where); 59: 60: protected: 61: int ConnectionState(); 62: 63: UmShape * GeometryToShape(IGeometry * geometry, UmCoordref * um_coordref); 64: UmShape * BoxToShape(Box * box, UmCoordref * um_coordref); 65: UmShape * PointToShape(Point * point, UmCoordref * um_coordref); 66: UmShape * MultiPointToShape(MultiPoint * multiPoint, UmCoordref * um_coordref); 67: UmShape * LineStringToShape(LineString * lineString, UmCoordref * um_coordref); 68: UmShape * MultiLineStringToShape(MultiLineString * multiLineString, UmCoordref * um_coordref); 69: UmShape * PolygonToShape(Polygon * polygon, UmCoordref * um_coordref); 70: UmShape * MultiPolygonToShape(MultiPolygon * multiPolygon, UmCoordref * um_coordref); 71:

23

Page 26: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

72: Coordinate * SubpartToCoordinates(UmShapeData * usd, int index)[]; 73: 74: IGeometry * ShapeToGeometry(UmShape * um_shape); 75: Point * PointToGeometry(UmShape * um_shape); 76: MultiPoint * MultiPointToGeometry(UmShape * um_shape); 77: LineString * LineStringToGeometry(UmShape * um_shape); 78: MultiLineString * MultiLineStringToGeometry(UmShape * um_shape); 79: SpatialDataLibrary::Polygon * PolygonToGeometry(UmShape * um_shape); 80: MultiPolygon * MultiPolygonToGeometry(UmShape * um_shape); 81: 82: 83: Hashtable * columnHash; 84: 85: bool connected; 86: 87: UmConnection * um_connection; 88: }; 89: } End of File: SdeApi.h File: SdeException.cpp 1: #include "StdAfx.h" 2: 3: #include "SdeException.h" 4: #include <stdlib.h> 5: 6: void ThrowSDEException(int rc) { 7: static char error_string[SE_MAX_MESSAGE_LENGTH ]; 8: char buffer[10]; 9: char message[SE_MAX_MESSAGE_LENGTH + 22]; 10: 11: error_string[0] = '\0'; 12: SE_error_get_string (rc, error_string); 13: 14: strcpy(message, "SDE Error "); 15: strcat(message, _itoa(rc, buffer, 10)); 16: strcat(message, ": "); 17: strcat(message, error_string); 18: 19: throw new Exception(new String(message)); 20: } 21: 22: String * GetSDEError(int rc) { 23: String * err; 24: 25: static char error_string[SE_MAX_MESSAGE_LENGTH ]; 26: char buffer[10]; 27: char message[SE_MAX_MESSAGE_LENGTH + 22]; 28: 29: error_string[0] = '\0'; 30: SE_error_get_string (rc, error_string); 31: 32: strcpy(message, "SDE Error "); 33: strcat(message, _itoa(rc, buffer, 10)); 34: strcat(message, ": "); 35: strcat(message, error_string); 36: 37: err = new String(message); 38: return err; 39: } 40: End of File: SdeException.cpp File: SdeException.h 1: #pragma once 2: 3: #include "StdAfx.h" 4:

5: using namespace System; 6: using namespace System::Text; 7: using namespace System::Collections; 8: using namespace System::Runtime::InteropServices; 9: 10: #define CE(fn) {int rc = fn; if(((rc) != SE_SUCCESS) && ((rc) != SE_FINISHED)) throw new Exception(GetSDEError(rc));} 11: 12: void ThrowSDEException(int rc); 13: String * GetSDEError(int rc); End of File: SdeException.h File: Stdafx.cpp 1: // stdafx.cpp : source file that includes just the standard includes 2: // SdeApi.pch will be the pre-compiled header 3: // stdafx.obj will contain the pre-compiled type information 4: 5: #include "stdafx.h" End of File: Stdafx.cpp File: Stdafx.h 1: // stdafx.h : include file for standard system include files, 2: // or project specific include files that are used frequently, 3: // but are changed infrequently 4: 5: #pragma once 6: 7: #using <mscorlib.dll> 8: #using <System.EnterpriseServices.dll> 9: #using <..\..\OMSSpatialDataLibrary\bin\Debug\SpatialDataLibrary.dll> 10: 11: #include <sdetype.h> 12: #include <sdeerno.h> 13: #include <pef.h> 14: #include <string.h> 15: 16: End of File: Stdafx.h File: Unmanaged.cpp 1: #include "StdAfx.h" 2: 3: #include "Unmanaged.h" 4: #include "SdeException.h" 5: #include <stdlib.h> 6: 7: namespace SdeApi 8: { 9: UmShapeData::UmShapeData(UmShape * um_shape) 10: { 11: CE(SE_shape_get_num_points(um_shape->ptr, 0, 0, &num_points)); 12: 13: try { 14: if(num_points > 0) { 15: CE(SE_shape_get_num_parts(um_shape->ptr, &num_parts, &num_subparts)); 16: 17: part_offsets = new LONG[num_parts + 1]; 18: subpart_offsets = new LONG[num_subparts + 1]; 19: points = new SE_POINT[num_points]; 20: 21: CE(SE_shape_get_all_points(um_shape->ptr, SE_DEFAULT_ROTATION, part_offsets, 22: subpart_offsets, points, NULL, NULL)); 23: 24: part_offsets[num_parts] = num_subparts; 25: subpart_offsets[num_subparts] = num_points; 26: } 27: } catch(Exception * ignore) { 28: try { 29: delete[] part_offsets;

24

Page 27: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

30: } catch(Exception * ignore2) {ignore2 = NULL;} 31: 32: try { 33: delete[] subpart_offsets; 34: } catch(Exception * ignore2) {ignore2 = NULL;} 35: 36: try { 37: delete[] points; 38: } catch(Exception * ignore2) {ignore2 = NULL;} 39: ignore = NULL; 40: num_points = 0; 41: } 42: } 43: 44: UmShapeData::~UmShapeData() 45: { 46: if(num_points > 0) { 47: try { 48: delete[] part_offsets; 49: } catch(Exception * ignore) {ignore = NULL;} 50: 51: try { 52: delete[] subpart_offsets; 53: } catch(Exception * ignore) {ignore = NULL;} 54: 55: try { 56: delete[] points; 57: } catch(Exception * ignore) {ignore = NULL;} 58: } 59: } 60: }End of File: Unmanaged.cpp File: Unmanaged.h 1: #pragma once 2: 3: namespace SdeApi 4: { 5: __nogc struct UmConnection { 6: public: 7: SE_CONNECTION ptr; 8: }; 9: 10: __nogc struct UmStream { 11: public: 12: SE_STREAM ptr; 13: }; 14: 15: __nogc struct UmCoordref { 16: public: 17: UmCoordref() {ptr = NULL;} 18: SE_COORDREF ptr; 19: }; 20: 21: __nogc struct UmShape { 22: public: 23: UmShape() {ptr = NULL;} 24: SE_SHAPE ptr; 25: }; 26: 27: __nogc class UmShapeData { 28: public: 29: LONG num_parts; 30: LONG num_subparts; 31: LONG num_points; 32: LONG __nogc * part_offsets; 33: LONG __nogc * subpart_offsets; 34: SE_POINT __nogc * points; 35: 36: UmShapeData(UmShape * um_shape); 37: ~UmShapeData(); 38: };

39: } End of File: Unmanaged.h

6.2 SPATIALDATALIBRARY LISTING File: AssemblyInfo.cs 1: using System.Reflection; 2: using System.Runtime.CompilerServices; 3: 4: [assembly: AssemblyTitle("")] 5: [assembly: AssemblyDescription("")] 6: [assembly: AssemblyConfiguration("")] 7: [assembly: AssemblyCompany("")] 8: [assembly: AssemblyProduct("")] 9: [assembly: AssemblyCopyright("")] 10: [assembly: AssemblyTrademark("")] 11: [assembly: AssemblyCulture("")] 12: [assembly: AssemblyVersion("1.0.*")] 13: [assembly: AssemblyDelaySign(false)] 14: [assembly: AssemblyKeyFile("..\\..\\SpatialDataLibrary.snk")] 15: [assembly: AssemblyKeyName("")] End of File: AssemblyInfo.cs File: LonLatPt.cs 1: // LonLatPt.cs 2: // 3: 4: 5: using System; 6: 7: /// <summary> 8: /// Geographic reference point 9: /// </summary> 10: public struct LonLatPt { 11: 12: public Double Lon; 13: public Double Lat; 14: } End of File: LonLatPt.cs File: Projection.cs 1: using System; 2: using System.Diagnostics; 3: 4: public class Projection { 5: private Projection() { /* No instances allowed */ } 6: 7: public static int LonToZone(double lon) 8: { 9: return((int) ((lon + 180) / 6 + 1)); 10: } 11: 12: private static Int32 LonLatPtToZone(LonLatPt lonlat) { 13: return((Int32) ((lonlat.Lon + 180) / 6 + 1)); 14: } 15: private static Double e0fn(Double x) { 16: return(1.0 - 0.25 * x * (1.0 + x / 16.0 * (3.0 + 1.25 * x))); 17: } 18: private static Double e1fn(Double x) { 19: return(0.375 * x * (1.0 + 0.25 * x * (1.0 + 0.46875 * x))); 20: } 21: private static Double e2fn(Double x) { 22: return(0.05859375 * x * x * (1.0 + 0.75 * x)); 23: } 24: private static Double e3fn(Double x) { 25: return(x * x * x * (35.0 / 3072.0)); 26: } 27: private static Double mlfn(Double e0, Double e1, Double e2, Double e3, Double phi) { 28: return(e0 * phi - e1 * Math.Sin(2.0 * phi) + e2 * Math.Sin(4.0 * phi) - e3 * Math.Sin(6.0 * phi));

25

Page 28: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

29: } 30: 31: private static Double AdjustLon(Double x) { 32: if (Math.Abs(x) <= Math.PI) { 33: return x; 34: } 35: x = x - Math.Sign(x) * (int) ( x / ( 2 * Math.PI ) ) * 2 * Math.PI; 36: if ( x > Math.PI ) { 37: x -= 2 * Math.PI; 38: } 39: return x; 40: } 41: 42: public static UtmPt LonLatPtToUtmNad83Pt(LonLatPt lonlat, Int32 zone) { 43: Double rMajor = 6378137.0; 44: Double rMinor = 6356752.3142450; 45: Double scaleFactor = .9996; 46: Double degreesToRadians = 1.745329251994328e-2; 47: Double factor = degreesToRadians; 48: Double latOrigin = 0; 49: Double lonCenter = ((6 * Math.Abs(zone)) - 183) * degreesToRadians; 50: Debug.WriteLine("lonCenter = " + lonCenter); 51: Double falseEasting = 500000; 52: Double falseNorthing = (zone < 0) ? 10000000 : 0; 53: Debug.WriteLine(String.Format("rMajor = {0}\n rMinor = {1}\n scaleFactor = {2}\n degreesToRadians = {3}\n latOrigin = {4}\n lonCenter = {5}\n falseEasting = {6}\n falseNorthing = {7}", 54: new Object[] {rMajor, rMinor, scaleFactor, degreesToRadians, latOrigin, lonCenter, falseEasting, falseNorthing})); 55: 56: Double temp = rMinor / rMajor; 57: Debug.WriteLine("temp = " + temp); 58: 59: Double es = 1 - (temp * temp); 60: Double e = Math.Sqrt(es); 61: Double e0 = e0fn(es); 62: Double e1 = e1fn(es); 63: Double e2 = e2fn(es); 64: Double e3 = e3fn(es); 65: Double ml0 = rMajor * mlfn(e0, e1, e2, e3, latOrigin); 66: Double esp = es / (1 - es); 67: Double ind = (es < .0001) ? 1: 0; 68: Debug.WriteLine(String.Format("es = {0}\n e = {1}\n e0 = {2}\n e1 = {3}\n e2 = {4}\n e3 = {5}\n ml0 = {6}\n esp = {7}\n ind = {8}", 69: new Object[] {es, e, e0, e1, e2, e3, ml0, esp, ind})); 70: Debug.WriteLine(""); 71: 72: Double longitude = lonlat.Lon * factor; 73: Double latitude = lonlat.Lat * factor; 74: Double deltaLon = AdjustLon(longitude - lonCenter); 75: Double sinPhi = Math.Sin(latitude); 76: Double cosPhi = Math.Cos(latitude); 77: Double al = cosPhi * deltaLon; 78: Double als = al * al; 79: Double c = esp * cosPhi * cosPhi; 80: Double tq = Math.Tan(latitude); 81: Double t = tq * tq; 82: Double con = 1.0 - es * sinPhi * sinPhi; 83: Double n = rMajor / Math.Sqrt(con); 84: Double ml = rMajor * mlfn(e0, e1, e2, e3, latitude); 85: Debug.WriteLine(String.Format("logitude = {0}\n latitude = {1}\n delaLon = {2}\n sinPhi = {3}\n cosPhi = {4}\n al = {5}\n als = {6}\n c = {7}\n tq = {8}\n t = {9}\n con = {10}\n n = {11}\n ml = {12}", 86: new Object[]{longitude, latitude, deltaLon, sinPhi, cosPhi, al, als, c, tq, t, con, n, ml})); 87: 88: UtmPt utmpt; 89: utmpt.X = scaleFactor * n * al * (1.0 + als / 6.0 *

90: (1.0 - t + c + als / 20.0 * (5.0 - 18.0 * t + (t * t) + 72.0 * c - 58.0 * esp))) + falseEasting; 91: 92: utmpt.Y = scaleFactor * (ml - ml0 + n * tq * (als * (0.5 + als / 24.0 * 93: (5.0 - t + 9.0 * c + 4.0 * (c * c) + als / 30.0 * 94: (61.0 - 58.0 * t + (t * t) + 600.0 * c - 330.0 * esp))))) + falseNorthing; 95: utmpt.Zone = zone; 96: return(utmpt); 97: } 98: 99: 100: public static UtmPt LonLatPtToUtmNad83Pt(LonLatPt lonlat) { 101: Int32 zone = LonLatPtToZone(lonlat); 102: return(LonLatPtToUtmNad83Pt(lonlat, zone)); 103: } 104: 105: public static LonLatPt UtmNad83PtToLonLatPt(UtmPt utmpt) { 106: Double rMajor = 6378137.0; 107: Double rMinor = 6356752.3142450; 108: Double latOrigin = 0; 109: Double degreesToRadians = 1.745329251994328e-2; 110: Double factor = 57.29577951308231; 111: Double lonCenter = ((6 * Math.Abs(utmpt.Zone)) - 183) * degreesToRadians; 112: Double falseEasting = 500000; 113: Double falseNorthing = (utmpt.Zone < 0) ? 10000000 : 0; 114: Double scaleFactor = .9996; 115: Double temp = rMinor / rMajor; 116: Debug.WriteLine("temp = " + temp); 117: 118: Double es = 1 - (temp * temp); 119: Double e = Math.Sqrt(es); 120: Double e0 = e0fn(es); 121: Double e1 = e1fn(es); 122: Double e2 = e2fn(es); 123: Double e3 = e3fn(es); 124: Double ml0 = rMajor * mlfn(e0, e1, e2, e3, latOrigin); 125: Double esp = es / (1 - es); 126: Double ind = (es < .0001) ? 1: 0; 127: Debug.WriteLine(String.Format("es = {0}\n e = {1}\n e0 = {2}\n e1 = {3}\n e2 = {4}\n e3 = {5}\n ml0 = {6}\n esp = {7}\n ind = {8}", 128: new Object[] {es, e, e0, e1, e2, e3, ml0, esp, ind})); 129: Debug.WriteLine(""); 130: Int32 maxIterations = 6; 131: utmpt.X -= falseEasting; 132: utmpt.Y -= falseNorthing; 133: Double con = (ml0 + utmpt.Y / scaleFactor) / rMajor; 134: Double phi = con; 135: for (int i = 0; ; i++) { 136: Double delta_phi = ((con + e1 * Math.Sin(2.0 * phi) - e2 * Math.Sin(4.0 * phi) + e3 * Math.Sin(6.0 * phi)) 137: / e0) - phi; 138: phi += delta_phi; 139: if (Math.Abs(delta_phi) <= 1.0e-10) break; 140: if (i >= maxIterations) { 141: throw new Exception("Latitude failed to converge"); 142: } 143: } 144: LonLatPt lonlat = new LonLatPt(); 145: if (Math.Abs(phi) < (Math.PI / 2)) { 146: Double sinPhi = Math.Sin(phi); 147: Double cosPhi = Math.Cos(phi); 148: Double tanPhi = Math.Tan(phi); 149: Double c = esp * (cosPhi * cosPhi); 150: Double cs = (c * c); 151: Double t = (tanPhi * tanPhi); 152: Double ts = (t * t); 153: con = 1.0 - es * (sinPhi * sinPhi);

26

Page 29: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

154: Double n = rMajor / Math.Sqrt(con); 155: Double r = n * (1.0 - es) / con; 156: Double d = utmpt.X / (n * scaleFactor); 157: Double ds = (d * d); 158: lonlat.Lat = phi - (n * tanPhi * ds / r) * (0.5 - ds / 24.0 * (5.0 + 3.0 * t + 159: 10.0 * c - 4.0 * cs - 9.0 * esp - ds / 30.0 * (61.0 + 90.0 * t + 160: 298.0 * c + 45.0 * ts - 252.0 * esp - 3.0 * cs))); 161: 162: lonlat.Lon = AdjustLon(lonCenter + (d * (1.0 - ds / 6.0 * (1.0 + 2.0 * t + 163: c - ds / 20.0 * (5.0 - 2.0 * c + 28.0 * t - 3.0 * cs + 8.0 * esp + 164: 24.0 * ts))) / cosPhi)); 165: } else { 166: lonlat.Lat = (Math.PI / 2) * Math.Sign(utmpt.Y); 167: lonlat.Lon = lonCenter; 168: } 169: lonlat.Lon *= factor; 170: lonlat.Lat *= factor; 171: return(lonlat); 172: } 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: public static UtmPt LonLatPtToUtmNad27Pt(LonLatPt lonlat, Int32 zone) { 191: Double rMajor = 6378137.0; 192: Double rMinor = 6356752.3142450; 193: Double scaleFactor = .9996; 194: Double degreesToRadians = 1.745329251994328e-2; 195: Double factor = degreesToRadians; 196: Double latOrigin = 0; 197: Double lonCenter = ((6 * Math.Abs(zone)) - 183) * degreesToRadians; 198: Debug.WriteLine("lonCenter = " + lonCenter); 199: Double falseEasting = 500000; 200: Double falseNorthing = (zone < 0) ? 10000000 : 0; 201: Debug.WriteLine(String.Format("rMajor = {0}\n rMinor = {1}\n scaleFactor = {2}\n degreesToRadians = {3}\n latOrigin = {4}\n lonCenter = {5}\n falseEasting = {6}\n falseNorthing = {7}", 202: new Object[] {rMajor, rMinor, scaleFactor, degreesToRadians, latOrigin, lonCenter, falseEasting, falseNorthing})); 203: 204: Double temp = rMinor / rMajor; 205: Debug.WriteLine("temp = " + temp); 206: 207: Double es = 1 - (temp * temp); 208: Double e = Math.Sqrt(es); 209: Double e0 = e0fn(es); 210: Double e1 = e1fn(es); 211: Double e2 = e2fn(es); 212: Double e3 = e3fn(es); 213: Double ml0 = rMajor * mlfn(e0, e1, e2, e3, latOrigin); 214: Double esp = es / (1 - es); 215: Double ind = (es < .0001) ? 1: 0;

216: Debug.WriteLine(String.Format("es = {0}\n e = {1}\n e0 = {2}\n e1 = {3}\n e2 = {4}\n e3 = {5}\n ml0 = {6}\n esp = {7}\n ind = {8}", 217: new Object[] {es, e, e0, e1, e2, e3, ml0, esp, ind})); 218: Debug.WriteLine(""); 219: 220: Double longitude = lonlat.Lon * factor; 221: Double latitude = lonlat.Lat * factor; 222: Double deltaLon = AdjustLon(longitude - lonCenter); 223: Double sinPhi = Math.Sin(latitude); 224: Double cosPhi = Math.Cos(latitude); 225: Double al = cosPhi * deltaLon; 226: Double als = al * al; 227: Double c = esp * cosPhi * cosPhi; 228: Double tq = Math.Tan(latitude); 229: Double t = tq * tq; 230: Double con = 1.0 - es * sinPhi * sinPhi; 231: Double n = rMajor / Math.Sqrt(con); 232: Double ml = rMajor * mlfn(e0, e1, e2, e3, latitude); 233: Debug.WriteLine(String.Format("logitude = {0}\n latitude = {1}\n delaLon = {2}\n sinPhi = {3}\n cosPhi = {4}\n al = {5}\n als = {6}\n c = {7}\n tq = {8}\n t = {9}\n con = {10}\n n = {11}\n ml = {12}", 234: new Object[]{longitude, latitude, deltaLon, sinPhi, cosPhi, al, als, c, tq, t, con, n, ml})); 235: 236: UtmPt utmpt; 237: utmpt.X = scaleFactor * n * al * (1.0 + als / 6.0 * 238: (1.0 - t + c + als / 20.0 * (5.0 - 18.0 * t + (t * t) + 72.0 * c - 58.0 * esp))) + falseEasting; 239: 240: utmpt.Y = scaleFactor * (ml - ml0 + n * tq * (als * (0.5 + als / 24.0 * 241: (5.0 - t + 9.0 * c + 4.0 * (c * c) + als / 30.0 * 242: (61.0 - 58.0 * t + (t * t) + 600.0 * c - 330.0 * esp))))) + falseNorthing; 243: utmpt.Zone = zone; 244: return(utmpt); 245: } 246: 247: public static UtmPt LonLatPtToUtmNad27Pt(LonLatPt lonlat) { 248: Int32 zone = LonLatPtToZone(lonlat); 249: return(LonLatPtToUtmNad27Pt(lonlat, zone)); 250: } 251: } End of File: Projection.cs File: SpatialData.cs 1: using System; 2: using System.Collections; 3: using System.Text; 4: using System.Xml; 5: using System.Xml.XPath; 6: 7: 8: namespace SpatialDataLibrary 9: { 10: public class Nad83Utilities 11: { 12: private Nad83Utilities() {} 13: 14: public static int ZoneToCoordRefId(int zone) 15: { 16: return 26900 + zone; 17: } 18: } 19: public class Nad27Utilities 20: { 21: private Nad27Utilities() {} 22: 23: public static int ZoneToCoordRefId(int zone) 24: {

27

Page 30: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

25: return 26700 + zone; 26: } 27: } 28: 29: public interface IGeometry 30: { 31: FeatureType GetFeatureType(); 32: Box GetExtent(); 33: 34: void Nad83PcsToGcs(int zone); 35: void Nad83GcsToPcs(int zone); 36: } 37: 38: public enum QueryMethod 39: { 40: EnvelopeOverlap = 0, /* ENVELOPES OVERLAP */ 41: EnvelopeOverlapByGrid = 1, /* ENVELOPES OVERLAP */ 42: CommonPoint = 2, /* COMMON POINT */ 43: LineCross = 3, /* LINE CROSS */ 44: CommonEdge = 4, /* COMMON EDGE/LINE */ 45: CommonPointOrLineCross = 5, /* COMMON POINT OR LINE CROSS */ 46: EdgeTouchOrAreaIntersect = 6, /* EDGE TOUCH OR AREA INTERSECT */ 47: AreaOrInteriorIntersect = 7, /* AREA INTERSECT or INTERIOR INTERSECT*/ 48: AreaOrInteriorIntersectAndNoEdgeTouch = 8, /* AREA or INTERIOR INTERSECT AND NO EDGE TOUCH */ 49: PrimaryInSecondary = 9, /* PRIMARY CONTAINED IN SECONDARY */ 50: SecondaryInPrimary = 10, /* SECONDARY CONTAINED IN PRIMARY */ 51: PrimaryContainedAndNoEdgeTouch = 11, /* PRIM CONTAINED AND NO EDGE TOUCH */ 52: SecondaryContainedAndNoEdgeTouch = 12, /* SEC CONTAINED AND NO EDGE TOUCH */ 53: FirstPointInPrimaryInSecond = 13, /* FIRST POINT IN PRIMARY IN SEC */ 54: Identical = 15 /* IDENTICAL */ 55: } 56: 57: public enum FeatureType 58: { 59: NullType, 60: BoxType, 61: PointType, 62: MultiPointType, 63: LineStringType, 64: MultiLineStringType, 65: LinearRingType, 66: PolygonType, 67: MultiPolygonType 68: } 69: 70: public enum RingDirection 71: { 72: CouterClockwise, 73: Clockwise 74: } 75: 76: public enum FeatureExtents 77: { 78: GetNoExtents, 79: GetDefaultExtents, 80: GetAllExtents 81: } 82: 83: public enum QueryColumnType 84: { 85: DoubleQCType,

86: IntegerQCType, 87: ShapeQCType, 88: StringQCType, 89: ExtentQCType 90: } 91: 92: [Serializable] 93: public class QueryColumn 94: { 95: public string ColumnName; 96: public QueryColumnType ColumnType; 97: 98: public QueryColumn() 99: { 100: } 101: 102: public QueryColumn(string columnName, QueryColumnType columnType) 103: { 104: ColumnName = columnName; 105: ColumnType = columnType; 106: } 107: } 108: 109: [Serializable] 110: public class Coordinate 111: { 112: public double X; 113: public double Y; 114: 115: public Coordinate(string coord) 116: { 117: string[] point; 118: 119: try 120: { 121: point = coord.Split(new char[]{','}); 122: X = double.Parse(point[0]); 123: Y = double.Parse(point[1]); 124: } 125: catch(Exception e) 126: { 127: X = 0; 128: Y = 0; 129: throw e; 130: } 131: } 132: 133: public Coordinate(double x, double y) 134: { 135: X = x; 136: Y = y; 137: } 138: 139: public Coordinate() 140: { 141: X = 0; 142: Y = 0; 143: } 144: 145: public override string ToString() 146: { 147: return X + "," + Y; 148: } 149: 150: public Coordinate(Coordinate coordinate) 151: { 152: X = coordinate.X; 153: Y = coordinate.Y; 154: }

28

Page 31: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

155: 156: public static Coordinate[] ParsePoints(string delimitedPoints) 157: { 158: Coordinate[] coordinates; 159: string[] coords; 160: string[] point; 161: int i; 162: 163: coords = delimitedPoints.Trim().Split(new char[]{' '}); 164: coordinates = new Coordinate[coords.Length]; 165: for(i = 0; i < coords.Length; i++) 166: { 167: point = coords[i].Split(new char[]{','}); 168: coordinates[i] = new Coordinate(double.Parse(point[0]), double.Parse(point[1])); 169: } 170: 171: return coordinates; 172: } 173: 174: public static string ToString(Coordinate[] coordinates) 175: { 176: StringBuilder coordString = new StringBuilder(); 177: 178: if(coordinates == null) return ""; 179: 180: foreach(Coordinate p in coordinates) 181: { 182: if(coordString.Length > 0) 183: coordString.Append(" "); 184: coordString.Append(p.ToString()); 185: } 186: 187: return coordString.ToString(); 188: } 189: 190: public void Nad83PcsToGcs(int zone) 191: { 192: UtmPt u; 193: LonLatPt l; 194: 195: u.X = X; 196: u.Y = Y; 197: u.Zone = zone; 198: l = Projection.UtmNad83PtToLonLatPt(u); 199: X = l.Lon; 200: Y = l.Lat; 201: } 202: 203: public void Nad83GcsToPcs(int zone, bool round) 204: { 205: UtmPt u; 206: LonLatPt l; 207: 208: l.Lon = X; 209: l.Lat = Y; 210: u = Projection.LonLatPtToUtmNad83Pt(l, zone); 211: if(round) 212: { 213: X = Math.Round(u.X); 214: Y = Math.Round(u.Y); 215: } 216: else 217: { 218: X = u.X; 219: Y = u.Y; 220: } 221: } 222: 223: public void Nad83GcsToPcs(int zone)

224: { 225: Nad83GcsToPcs(zone, true); 226: } 227: } 228: [Serializable] 229: public class NullShape : IGeometry 230: { 231: public Coordinate coord; 232: 233: public NullShape() 234: { 235: } 236: 237: public FeatureType GetFeatureType() 238: { 239: return FeatureType.NullType; 240: } 241: 242: public Box GetExtent() 243: { 244: return new Box(0,0,0,0); 245: } 246: 247: public void Nad83PcsToGcs(int zone) 248: { 249: } 250: 251: public void Nad83GcsToPcs(int zone) 252: { 253: } 254: } 255: 256: [Serializable] 257: public class Box : IGeometry 258: { 259: public Coordinate Min; 260: public Coordinate Max; 261: 262: public Box() 263: { 264: Min = new Coordinate(0, 0); 265: Max = new Coordinate(0, 0); 266: } 267: 268: public Box(double minx, double miny, double maxx, double maxy) 269: { 270: Min = new Coordinate(minx, miny); 271: Max = new Coordinate(maxx, maxy); 272: } 273: 274: public Box(Coordinate min, Coordinate max) 275: { 276: Min = min; 277: Max = max; 278: } 279: 280: public Box(Box box) 281: { 282: Min = new Coordinate(box.Min); 283: Max = new Coordinate(box.Max); 284: } 285: 286: public bool Contains(Box box) 287: { 288: if((Min.X <= box.Min.X) && (Min.Y <= box.Min.Y)) 289: { 290: if((Max.X >= box.Max.X) && (Max.Y >= box.Max.Y)) 291: { 292: return true;

29

Page 32: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

293: } 294: } 295: return false; 296: } 297: 298: public FeatureType GetFeatureType() 299: { 300: return FeatureType.BoxType; 301: } 302: 303: public Box GetExtent() 304: { 305: return new Box(this); 306: } 307: 308: public void Nad83PcsToGcs(int zone) 309: { 310: Min.Nad83PcsToGcs(zone); 311: Max.Nad83PcsToGcs(zone); 312: } 313: 314: public void Nad83GcsToPcs(int zone) 315: { 316: Min.Nad83GcsToPcs(zone); 317: Max.Nad83GcsToPcs(zone); 318: } 319: } 320: 321: [Serializable] 322: public class Point : IGeometry 323: { 324: public Coordinate coord; 325: 326: public Point() 327: { 328: coord = new Coordinate(); 329: } 330: 331: public Point(double x, double y) 332: { 333: coord = new Coordinate(x, y); 334: } 335: 336: public Point(string scoord) 337: { 338: coord = new Coordinate(scoord); 339: } 340: 341: public FeatureType GetFeatureType() 342: { 343: return FeatureType.PointType; 344: } 345: 346: public Box GetExtent() 347: { 348: return new Box(new Coordinate(coord), new Coordinate(coord)); 349: } 350: 351: public void Nad83PcsToGcs(int zone) 352: { 353: coord.Nad83PcsToGcs(zone); 354: } 355: 356: public void Nad83GcsToPcs(int zone) 357: { 358: coord.Nad83GcsToPcs(zone); 359: } 360: } 361: 362: [Serializable]

363: public class MultiPoint : IGeometry 364: { 365: public Coordinate[] coordinates; 366: 367: public MultiPoint() 368: { 369: coordinates = null; 370: } 371: 372: public MultiPoint(int coordcount) 373: { 374: coordinates = new Coordinate[coordcount]; 375: } 376: 377: public MultiPoint(Coordinate[] coordinates) 378: { 379: this.coordinates = coordinates; 380: } 381: 382: public MultiPoint(string delimitedPoints) 383: { 384: coordinates = Coordinate.ParsePoints(delimitedPoints); 385: } 386: 387: public FeatureType GetFeatureType() 388: { 389: return FeatureType.MultiPointType; 390: } 391: 392: public Box GetExtent() 393: { 394: Coordinate min = null, max = null; 395: 396: if(coordinates == null) return null; 397: 398: foreach(Coordinate coord in coordinates) 399: { 400: if(min == null) 401: { 402: min = coord; 403: max = coord; 404: } 405: else 406: { 407: if((coord.X < min.X) && (coord.Y < min.Y)) 408: min = coord; 409: 410: if((coord.X > max.X) && (coord.Y > max.Y)) 411: max = coord; 412: } 413: } 414: 415: if(min == null) return null; 416: 417: return new Box(new Coordinate(min), new Coordinate(max)); 418: } 419: 420: public void Nad83PcsToGcs(int zone) 421: { 422: foreach(Coordinate coord in coordinates) 423: { 424: coord.Nad83PcsToGcs(zone); 425: } 426: } 427: 428: public void Nad83GcsToPcs(int zone) 429: { 430: foreach(Coordinate coord in coordinates) 431: { 432: coord.Nad83GcsToPcs(zone);

30

Page 33: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

433: } 434: } 435: } 436: 437: [Serializable] 438: public class LineString : IGeometry 439: { 440: public Coordinate[] coordinates; 441: 442: public LineString() 443: { 444: coordinates = null; 445: } 446: 447: public LineString(int coordCount) 448: { 449: coordinates = new Coordinate[coordCount]; 450: } 451: 452: public LineString(Coordinate[] coords) 453: { 454: coordinates = coords; 455: } 456: 457: public LineString(string delimitedPoints) 458: { 459: coordinates = Coordinate.ParsePoints(delimitedPoints); 460: } 461: 462: public FeatureType GetFeatureType() 463: { 464: return FeatureType.LineStringType; 465: } 466: 467: public Box GetExtent() 468: { 469: Coordinate min = null, max = null; 470: 471: if(coordinates == null) return null; 472: 473: foreach(Coordinate coord in coordinates) 474: { 475: if(min == null) 476: { 477: min = coord; 478: max = coord; 479: } 480: else 481: { 482: if((coord.X < min.X) && (coord.Y < min.Y)) 483: min = coord; 484: 485: if((coord.X > max.X) && (coord.Y > max.Y)) 486: max = coord; 487: } 488: } 489: 490: if(min == null) return null; 491: 492: return new Box(new Coordinate(min), new Coordinate(max)); 493: } 494: 495: public void Nad83PcsToGcs(int zone) 496: { 497: foreach(Coordinate coord in coordinates) 498: { 499: coord.Nad83PcsToGcs(zone); 500: } 501: } 502:

503: public void Nad83GcsToPcs(int zone) 504: { 505: foreach(Coordinate coord in coordinates) 506: { 507: coord.Nad83GcsToPcs(zone); 508: } 509: } 510: } 511: 512: [Serializable] 513: public class MultiLineString : IGeometry 514: { 515: public LineString[] lineStrings; 516: 517: public MultiLineString() 518: { 519: lineStrings = null; 520: } 521: 522: public MultiLineString(LineString lineString) 523: { 524: lineStrings = new LineString[1]; 525: lineStrings[0] = lineString; 526: } 527: 528: public MultiLineString(int lineStringCount) 529: { 530: lineStrings = new LineString[lineStringCount]; 531: } 532: 533: public MultiLineString(LineString[] lineStrings) 534: { 535: this.lineStrings = lineStrings; 536: } 537: 538: public FeatureType GetFeatureType() 539: { 540: return FeatureType.MultiLineStringType; 541: } 542: 543: public Box GetExtent() 544: { 545: Coordinate min = null, max = null; 546: 547: if(lineStrings == null) return null; 548: 549: foreach(LineString lineString in lineStrings) 550: { 551: if(lineString.coordinates != null) 552: { 553: foreach(Coordinate coord in lineString.coordinates) 554: { 555: if(min == null) 556: { 557: min = coord; 558: max = coord; 559: } 560: else 561: { 562: if((coord.X < min.X) && (coord.Y < min.Y)) 563: min = coord; 564: 565: if((coord.X > max.X) && (coord.Y > max.Y)) 566: max = coord; 567: } 568: } 569: } 570: } 571: 572: if(min == null) return null;

31

Page 34: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

573: 574: return new Box(new Coordinate(min), new Coordinate(max)); 575: } 576: 577: public void Nad83PcsToGcs(int zone) 578: { 579: foreach(LineString lineString in lineStrings) 580: { 581: lineString.Nad83PcsToGcs(zone); 582: } 583: } 584: 585: public void Nad83GcsToPcs(int zone) 586: { 587: foreach(LineString lineString in lineStrings) 588: { 589: lineString.Nad83GcsToPcs(zone); 590: } 591: } 592: } 593: 594: [Serializable] 595: public class LinearRing : IGeometry 596: { 597: public Coordinate[] coordinates; 598: private double area = 0; 599: 600: public LinearRing() 601: { 602: coordinates = null; 603: } 604: 605: public LinearRing(int coordCount) 606: { 607: coordinates = new Coordinate[coordCount]; 608: } 609: 610: public LinearRing(Coordinate[] coords) 611: { 612: coordinates = coords; 613: } 614: 615: public LinearRing(string delimitedPoints) 616: { 617: coordinates = Coordinate.ParsePoints(delimitedPoints); 618: } 619: 620: public LinearRing(double minx, double miny, double maxx, double maxy) 621: { 622: coordinates = new Coordinate[5]; 623: 624: coordinates[0] = new Coordinate(minx, miny); 625: coordinates[1] = new Coordinate(minx, maxy); 626: coordinates[2] = new Coordinate(maxx, maxy); 627: coordinates[3] = new Coordinate(maxx, miny); 628: coordinates[4] = new Coordinate(minx, miny); 629: } 630: 631: public double CalcAreaAndCentroid(Coordinate centroidResult) 632: { 633: double A = 0, Cx = 0, Cy = 0, pXq; 634: Coordinate p = null; 635: 636: foreach(Coordinate q in coordinates) 637: { 638: if(p == null) 639: { 640: p = q; 641: }

642: else 643: { 644: pXq = p.X * q.Y - q.X * p.Y; 645: A += pXq; 646: if(centroidResult != null) 647: { 648: Cx += pXq * (p.X + q.X); 649: Cy += pXq * (p.Y + q.Y); 650: } 651: p = q; 652: } 653: } 654: A /= 2; 655: if(centroidResult != null) 656: { 657: centroidResult.X = Cx/(6*A); 658: centroidResult.Y = Cy/(6*A); 659: } 660: area = A; 661: return A; 662: } 663: 664: public RingDirection Direction() 665: { 666: if(area == 0) 667: { 668: CalcAreaAndCentroid(null); 669: } 670: 671: if(area > 0) 672: { 673: return RingDirection.CouterClockwise; 674: } 675: else 676: { 677: return RingDirection.Clockwise; 678: } 679: } 680: 681: public FeatureType GetFeatureType() 682: { 683: return FeatureType.LinearRingType; 684: } 685: 686: public Box GetExtent() 687: { 688: Coordinate min = null, max = null; 689: 690: if(coordinates == null) return null; 691: 692: foreach(Coordinate coord in coordinates) 693: { 694: if(min == null) 695: { 696: min = coord; 697: max = coord; 698: } 699: else 700: { 701: if((coord.X < min.X) && (coord.Y < min.Y)) 702: min = coord; 703: 704: if((coord.X > max.X) && (coord.Y > max.Y)) 705: max = coord; 706: } 707: } 708: 709: if(min == null) return null; 710: 711: return new Box(new Coordinate(min), new Coordinate(max));

32

Page 35: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

712: } 713: 714: public void Nad83PcsToGcs(int zone) 715: { 716: foreach(Coordinate coord in coordinates) 717: { 718: coord.Nad83PcsToGcs(zone); 719: } 720: } 721: 722: public void Nad83GcsToPcs(int zone) 723: { 724: foreach(Coordinate coord in coordinates) 725: { 726: coord.Nad83GcsToPcs(zone); 727: } 728: } 729: } 730: 731: [Serializable] 732: public class Polygon : IGeometry 733: { 734: public LinearRing outerBoundary = null; 735: public LinearRing[] innerBoundaries = null; 736: 737: public Polygon() 738: { 739: 740: } 741: 742: public Polygon(LinearRing outerBoundary) 743: { 744: this.outerBoundary = outerBoundary; 745: } 746: 747: public Polygon(int innerBoundaryCount) 748: { 749: innerBoundaries = new LinearRing[innerBoundaryCount]; 750: } 751: 752: public Polygon(LinearRing outerBoundary, int innerBoundaryCount) 753: { 754: this.outerBoundary = outerBoundary; 755: innerBoundaries = new LinearRing[innerBoundaryCount]; 756: } 757: 758: public Polygon(LinearRing outerBoundary, LinearRing[] innerBoundaries) 759: { 760: this.outerBoundary = outerBoundary; 761: this.innerBoundaries = innerBoundaries; 762: } 763: 764: public FeatureType GetFeatureType() 765: { 766: return FeatureType.PolygonType; 767: } 768: 769: public Box GetExtent() 770: { 771: return outerBoundary.GetExtent(); 772: } 773: 774: public double CalcArea() 775: { 776: double area = 0; 777: 778: if(outerBoundary != null) 779: {

780: area += outerBoundary.CalcAreaAndCentroid(null); 781: } 782: 783: if(innerBoundaries != null) 784: { 785: foreach(LinearRing boundary in innerBoundaries) 786: { 787: area += boundary.CalcAreaAndCentroid(null); 788: } 789: } 790: return area; 791: } 792: 793: public void Nad83PcsToGcs(int zone) 794: { 795: if(outerBoundary != null) 796: { 797: outerBoundary.Nad83PcsToGcs(zone); 798: } 799: if(innerBoundaries != null) 800: { 801: foreach(LinearRing ib in innerBoundaries) 802: { 803: ib.Nad83PcsToGcs(zone); 804: } 805: } 806: } 807: 808: public void Nad83GcsToPcs(int zone) 809: { 810: if(outerBoundary != null) 811: { 812: outerBoundary.Nad83GcsToPcs(zone); 813: } 814: if(innerBoundaries != null) 815: { 816: foreach(LinearRing ib in innerBoundaries) 817: { 818: ib.Nad83GcsToPcs(zone); 819: } 820: } 821: } 822: } 823: 824: [Serializable] 825: public class MultiPolygon : IGeometry 826: { 827: public Polygon[] polygons = null; 828: 829: public MultiPolygon() 830: { 831: } 832: 833: public MultiPolygon(Polygon polygon) 834: { 835: polygons = new Polygon[1]; 836: polygons[0] = polygon; 837: } 838: 839: public MultiPolygon(int polygonCount) 840: { 841: polygons = new Polygon[polygonCount]; 842: } 843: 844: public MultiPolygon(Polygon[] polygons) 845: { 846: this.polygons = polygons; 847: } 848: 849: public double CalcArea()

33

Page 36: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

850: { 851: double area = 0; 852: 853: if(polygons != null) 854: { 855: foreach(Polygon p in polygons) 856: { 857: area += p.CalcArea(); 858: } 859: } 860: return area; 861: } 862: 863: public FeatureType GetFeatureType() 864: { 865: return FeatureType.MultiPolygonType; 866: } 867: 868: public Box GetExtent() 869: { 870: Coordinate min = null, max = null; 871: LinearRing outerBoundary; 872: 873: if(polygons == null) return null; 874: 875: foreach(Polygon polygon in polygons) 876: { 877: outerBoundary = polygon.outerBoundary; 878: if(outerBoundary != null) 879: { 880: if(outerBoundary.coordinates != null) 881: { 882: foreach(Coordinate coord in outerBoundary.coordinates) 883: { 884: if(min == null) 885: { 886: min = coord; 887: max = coord; 888: } 889: else 890: { 891: if((coord.X < min.X) && (coord.Y < min.Y)) 892: min = coord; 893: 894: if((coord.X > max.X) && (coord.Y > max.Y)) 895: max = coord; 896: } 897: } 898: } 899: } 900: } 901: 902: if(min == null) return null; 903: 904: return new Box(new Coordinate(min), new Coordinate(max)); 905: } 906: 907: public void Nad83PcsToGcs(int zone) 908: { 909: foreach(Polygon poly in polygons) 910: { 911: poly.Nad83PcsToGcs(zone); 912: } 913: } 914: 915: public void Nad83GcsToPcs(int zone) 916: { 917: foreach(Polygon poly in polygons) 918: { 919: poly.Nad83GcsToPcs(zone);

920: } 921: } 922: } 923: 924: [Serializable] 925: public class Feature 926: { 927: public Hashtable attributes; 928: public IGeometry geometry; 929: public bool GetExtent = false; 930: 931: public Feature() 932: { 933: attributes = new Hashtable(); 934: } 935: 936: public Feature(IGeometry geometry) 937: { 938: attributes = new Hashtable(); 939: this.geometry = geometry; 940: } 941: 942: public void AddAttribute(String key, Object attribute) 943: { 944: attributes[key] = attribute; 945: } 946: } 947: 948: [Serializable] 949: public class FeatureSet 950: { 951: public ArrayList features; 952: public Hashtable attributes; 953: public string coordinateSystem = ""; 954: 955: public long startQueryTicks = 0; 956: public long endQueryTicks = 0; 957: 958: public void QueryStampStart() 959: { 960: startQueryTicks = DateTime.Now.Ticks; 961: } 962: 963: public void QueryStampEnd() 964: { 965: endQueryTicks = DateTime.Now.Ticks; 966: } 967: 968: public FeatureSet() 969: { 970: features = new ArrayList(); 971: attributes = new Hashtable(); 972: } 973: 974: public FeatureSet(int featureCount) 975: { 976: features = new ArrayList(featureCount); 977: attributes = new Hashtable(); 978: } 979: 980: public FeatureSet(ArrayList features) 981: { 982: this.features = features; 983: attributes = new Hashtable(); 984: } 985: 986: public FeatureSet(Hashtable attributes) 987: { 988: features = new ArrayList(); 989: this.attributes = attributes;

34

Page 37: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

990: } 991: 992: public FeatureSet(ArrayList features, Hashtable attributes) 993: { 994: this.features = features; 995: this.attributes = attributes; 996: } 997: 998: public void AddFeature(Feature feature) 999: { 1000: features.Add(feature); 1001: } 1002: 1003: public void AddAttribute(String key, Object attribute) 1004: { 1005: attributes[key] = attribute; 1006: } 1007: } 1008: 1009: [Serializable] 1010: public class SpatialConstraint 1011: { 1012: public String Table; 1013: public String Column; 1014: public IGeometry Constraint; 1015: public QueryMethod Method; 1016: public bool Truth; 1017: 1018: public SpatialConstraint() 1019: { 1020: } 1021: 1022: public SpatialConstraint(String table, String column, IGeometry constraint, QueryMethod method, bool truth) 1023: { 1024: Table = table; 1025: Column = column; 1026: Constraint = constraint; 1027: Method = method; 1028: Truth = truth; 1029: } 1030: } 1031: 1032: public class XmlGeometry 1033: { 1034: public const string OpenGisGMLUrl = "http://www.opengis.net/gml"; 1035: 1036: private static void CreateAttribute(XmlDocument gml, XmlNode element, string attName, string attValue) 1037: { 1038: XmlAttribute gmlAttribute; 1039: 1040: gmlAttribute = gml.CreateAttribute(attName); 1041: gmlAttribute.Value = attValue; 1042: 1043: element.Attributes.Append(gmlAttribute); 1044: } 1045: 1046: public static XmlNode NullToGml(XmlDocument gml, NullShape g) 1047: { 1048: XmlElement gmlNull; 1049: 1050: gmlNull = gml.CreateElement("gml", "NullShape", OpenGisGMLUrl); 1051: 1052: return gmlNull; 1053: } 1054:

1055: public static XmlNode BoxToGml(XmlDocument gml, Box g) 1056: { 1057: XmlElement gmlBox; 1058: XmlElement gmlCoords; 1059: 1060: gmlBox = gml.CreateElement("gml", "Box", OpenGisGMLUrl); 1061: gmlCoords = gml.CreateElement("gml", "coordinates", OpenGisGMLUrl); 1062: gmlCoords.InnerText = g.Min.ToString() + " " + g.Max.ToString(); 1063: gmlBox.AppendChild(gmlCoords); 1064: 1065: return gmlBox; 1066: } 1067: 1068: public static XmlNode PointToGml(XmlDocument gml, Point g) 1069: { 1070: XmlElement gmlPoint; 1071: XmlElement gmlCoords; 1072: 1073: gmlPoint = gml.CreateElement("gml", "Point", OpenGisGMLUrl); 1074: gmlCoords = gml.CreateElement("gml", "coordinates", OpenGisGMLUrl); 1075: gmlCoords.InnerText = g.coord.ToString(); 1076: gmlPoint.AppendChild(gmlCoords); 1077: 1078: return gmlPoint; 1079: } 1080: 1081: public static XmlNode MultiPointToGml(XmlDocument gml, MultiPoint g) 1082: { 1083: XmlElement gmlMultiPoint; 1084: XmlElement gmlCoords; 1085: 1086: gmlMultiPoint = gml.CreateElement("gml", "MultiPoint", OpenGisGMLUrl); 1087: 1088: gmlCoords = gml.CreateElement("gml", "coordinates", OpenGisGMLUrl); 1089: gmlCoords.InnerText = Coordinate.ToString(g.coordinates); 1090: gmlMultiPoint.AppendChild(gmlCoords); 1091: 1092: return gmlMultiPoint; 1093: } 1094: 1095: public static XmlNode LineStringToGml(XmlDocument gml, LineString g) 1096: { 1097: XmlElement gmlLineString; 1098: XmlElement gmlCoords; 1099: 1100: gmlLineString = gml.CreateElement("gml", "LineString", OpenGisGMLUrl); 1101: 1102: gmlCoords = gml.CreateElement("gml", "coordinates", OpenGisGMLUrl); 1103: gmlCoords.InnerText = Coordinate.ToString(g.coordinates); 1104: gmlLineString.AppendChild(gmlCoords); 1105: 1106: return gmlLineString; 1107: } 1108: 1109: public static XmlNode MultiLineStringToGml(XmlDocument gml, MultiLineString g) 1110: { 1111: XmlElement gmlLineString; 1112:

35

Page 38: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1113: gmlLineString = gml.CreateElement("gml", "MultiLineString", OpenGisGMLUrl); 1114: 1115: if(g.lineStrings != null) 1116: { 1117: foreach(LineString lineString in g.lineStrings) 1118: gmlLineString.AppendChild(LineStringToGml(gml, lineString)); 1119: } 1120: 1121: return gmlLineString; 1122: } 1123: 1124: public static XmlNode LinearRingToGml(XmlDocument gml, LinearRing g) 1125: { 1126: XmlElement gmlLinearRing; 1127: XmlElement gmlCoords; 1128: 1129: gmlLinearRing = gml.CreateElement("gml", "LinearRing", OpenGisGMLUrl); 1130: 1131: gmlCoords = gml.CreateElement("gml", "coordinates", OpenGisGMLUrl); 1132: gmlCoords.InnerText = Coordinate.ToString(g.coordinates); 1133: gmlLinearRing.AppendChild(gmlCoords); 1134: 1135: return gmlLinearRing; 1136: } 1137: 1138: public static XmlNode PolygonToGml(XmlDocument gml, Polygon g) 1139: { 1140: XmlElement gmlPolygon; 1141: XmlElement gmlBoundary; 1142: 1143: gmlPolygon = gml.CreateElement("gml", "Polygon", OpenGisGMLUrl); 1144: 1145: if(g.outerBoundary != null) 1146: { 1147: gmlBoundary = gml.CreateElement("gml", "outerBoundaryIs", OpenGisGMLUrl); 1148: gmlBoundary.AppendChild(LinearRingToGml(gml, g.outerBoundary)); 1149: gmlPolygon.AppendChild(gmlBoundary); 1150: } 1151: 1152: if(g.innerBoundaries != null) 1153: { 1154: foreach(LinearRing ib in g.innerBoundaries) 1155: { 1156: gmlBoundary = gml.CreateElement("gml", "innerBoundaryIs", OpenGisGMLUrl); 1157: gmlBoundary.AppendChild(LinearRingToGml(gml, ib)); 1158: gmlPolygon.AppendChild(gmlBoundary); 1159: } 1160: } 1161: 1162: return gmlPolygon; 1163: } 1164: 1165: public static XmlNode MultiPolygonToGml(XmlDocument gml, MultiPolygon g) 1166: { 1167: XmlElement gmlMultiPolygon; 1168: 1169: gmlMultiPolygon = gml.CreateElement("gml", "MultiPolygon", OpenGisGMLUrl); 1170:

1171: if(g.polygons != null) 1172: { 1173: foreach(Polygon polygon in g.polygons) 1174: gmlMultiPolygon.AppendChild(PolygonToGml(gml, polygon)); 1175: } 1176: 1177: return gmlMultiPolygon; 1178: } 1179: 1180: public static XmlNode GeometryToGml(XmlDocument gml, IGeometry g) 1181: { 1182: XmlNode xnd = null; 1183: switch(g.GetFeatureType()) 1184: { 1185: case FeatureType.NullType: 1186: xnd = NullToGml(gml, (NullShape)g); 1187: break; 1188: 1189: case FeatureType.BoxType: 1190: xnd = BoxToGml(gml, (Box)g); 1191: break; 1192: 1193: case FeatureType.PointType: 1194: xnd = PointToGml(gml, (Point)g); 1195: break; 1196: 1197: case FeatureType.MultiPointType: 1198: xnd = MultiPointToGml(gml, (MultiPoint)g); 1199: break; 1200: 1201: case FeatureType.LineStringType: 1202: xnd = LineStringToGml(gml, (LineString)g); 1203: break; 1204: 1205: case FeatureType.MultiLineStringType: 1206: xnd = MultiLineStringToGml(gml, (MultiLineString)g); 1207: break; 1208: 1209: case FeatureType.LinearRingType: 1210: xnd = LinearRingToGml(gml, (LinearRing)g); 1211: break; 1212: 1213: case FeatureType.PolygonType: 1214: xnd = PolygonToGml(gml, (Polygon)g); 1215: break; 1216: 1217: case FeatureType.MultiPolygonType: 1218: xnd = MultiPolygonToGml(gml, (MultiPolygon)g); 1219: break; 1220: 1221: default: 1222: break; 1223: } 1224: return xnd; 1225: } 1226: 1227: public static XmlNode GeometryExtentToGml(XmlDocument gml, IGeometry g) 1228: { 1229: return BoxToGml(gml, (Box)(g.GetExtent())); 1230: } 1231: 1232: public static XmlNode FeatureToGml(XmlDocument gml, Feature f, FeatureExtents getExtents) 1233: { 1234: XmlElement gmlSpatialFeature, gmlSpatialInfo, gmlBoundedBy; 1235: XmlAttribute gmlAttribute;

36

Page 39: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1236: 1237: gmlSpatialFeature = gml.CreateElement("Feature"); 1238: gmlAttribute = gml.CreateAttribute("featuretype"); 1239: gmlAttribute.Value = f.geometry.GetFeatureType().ToString(); 1240: gmlSpatialFeature.Attributes.Append(gmlAttribute); 1241: 1242: if(f.attributes.Count > 0) 1243: { 1244: gmlSpatialInfo = gml.CreateElement("Attributes"); 1245: foreach(string attribute in f.attributes.Keys) 1246: { 1247: gmlAttribute = gml.CreateAttribute(attribute); 1248: gmlAttribute.Value = f.attributes[attribute].ToString(); 1249: gmlSpatialInfo.Attributes.Append(gmlAttribute); 1250: } 1251: gmlSpatialFeature.AppendChild(gmlSpatialInfo); 1252: } 1253: 1254: if(f.geometry != null) 1255: gmlSpatialFeature.AppendChild(GeometryToGml(gml, f.geometry)); 1256: 1257: if(getExtents == FeatureExtents.GetAllExtents) 1258: { 1259: gmlBoundedBy = gml.CreateElement("gml", "boundedBy", OpenGisGMLUrl); 1260: gmlBoundedBy.AppendChild(GeometryExtentToGml(gml, f.geometry)); 1261: gmlSpatialFeature.AppendChild(gmlBoundedBy); 1262: } 1263: 1264: if(getExtents == FeatureExtents.GetDefaultExtents) 1265: { 1266: if(f.GetExtent == true) 1267: { 1268: gmlBoundedBy = gml.CreateElement("gml", "boundedBy", OpenGisGMLUrl); 1269: gmlBoundedBy.AppendChild(GeometryExtentToGml(gml, f.geometry)); 1270: gmlSpatialFeature.AppendChild(gmlBoundedBy); 1271: } 1272: } 1273: 1274: return gmlSpatialFeature; 1275: } 1276: 1277: public static XmlDocument FeatureSetToGml(FeatureSet fs, FeatureExtents GetExtents) 1278: { 1279: XmlDocument gml; 1280: XmlElement gmlSpatialInfo; 1281: XmlElement gmlGenerationTime, gmlQueryTime; 1282: long start, end, length; 1283: DateTime dtTime; 1284: TimeSpan tsTime; 1285: TimeSpan queryTime; 1286: 1287: start = DateTime.Now.Ticks; 1288: dtTime = new DateTime(start); 1289: 1290: gml = new XmlDocument(); 1291: gml.LoadXml("<FeatureSet xmlns:gml=\"http://www.opengis.net/gml\"/>"); 1292: 1293: gmlGenerationTime = gml.CreateElement("XmlGenerationTime"); 1294: CreateAttribute(gml, gmlGenerationTime, "start", dtTime.ToLongTimeString()); 1295: 1296: if(fs.startQueryTicks > 0)

1297: { 1298: queryTime = new TimeSpan(fs.endQueryTicks - fs.startQueryTicks); 1299: gmlQueryTime = gml.CreateElement("QueryTime"); 1300: CreateAttribute(gml, gmlQueryTime, "length", queryTime.ToString()); 1301: gml.FirstChild.AppendChild(gmlQueryTime); 1302: } 1303: gml.FirstChild.AppendChild(gmlGenerationTime); 1304: 1305: if(fs.coordinateSystem.Length > 0) 1306: { 1307: gmlSpatialInfo = gml.CreateElement("CoordinateSystem"); 1308: gmlSpatialInfo.InnerText = fs.coordinateSystem; 1309: gml.FirstChild.AppendChild(gmlSpatialInfo); 1310: } 1311: 1312: if(fs.attributes.Count > 0) 1313: { 1314: gmlSpatialInfo = gml.CreateElement("Attributes"); 1315: foreach(string satt in fs.attributes.Keys) 1316: { 1317: CreateAttribute(gml, gmlSpatialInfo, satt, fs.attributes[satt].ToString()); 1318: } 1319: gml.FirstChild.AppendChild(gmlSpatialInfo); 1320: } 1321: 1322: foreach(Feature feature in fs.features) 1323: { 1324: gml.FirstChild.AppendChild(FeatureToGml(gml, feature, GetExtents)); 1325: } 1326: 1327: end = DateTime.Now.Ticks; 1328: CreateAttribute(gml, gmlGenerationTime, "end", dtTime.ToLongTimeString()); 1329: 1330: length = end - start; 1331: tsTime = new TimeSpan(end - start); 1332: CreateAttribute(gml, gmlGenerationTime, "length", tsTime.ToString()); 1333: 1334: return gml; 1335: } 1336: 1337: 1338: public static XmlDocument FeatureSetToGml(FeatureSet fs) 1339: { 1340: return FeatureSetToGml(fs, FeatureExtents.GetDefaultExtents); 1341: } 1342: 1343: 1344: 1345: 1346: 1347: public static MultiPolygon GmlToMultiPolygon(XPathNavigator navgml) 1348: { 1349: MultiPolygon g = new MultiPolygon(); 1350: 1351: XPathNodeIterator xiter; 1352: int i; 1353: 1354: xiter = navgml.SelectChildren("Polygon", OpenGisGMLUrl); 1355: if(xiter.Count > 0) 1356: { 1357: g.polygons = new Polygon[xiter.Count]; 1358: i = 0; 1359: while(xiter.MoveNext())

37

Page 40: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1360: { 1361: g.polygons[i] = GmlToPolygon(xiter.Current.Clone()); 1362: i++; 1363: } 1364: } 1365: 1366: return g; 1367: } 1368: 1369: public static Polygon GmlToPolygon(XPathNavigator navgml) 1370: { 1371: Polygon g = new Polygon(); 1372: 1373: XPathNodeIterator xiter; 1374: XPathNodeIterator xiterinnerbound; 1375: int i; 1376: 1377: xiter = navgml.SelectChildren("outerBoundaryIs", OpenGisGMLUrl); 1378: if(xiter.MoveNext()) 1379: { 1380: xiter = xiter.Current.SelectChildren("LinearRing", OpenGisGMLUrl); 1381: if(xiter.MoveNext()) 1382: { 1383: xiter = xiter.Current.SelectChildren("coordinates", OpenGisGMLUrl); 1384: if(xiter.MoveNext()) 1385: { 1386: g.outerBoundary = new LinearRing(xiter.Current.Value); 1387: } 1388: } 1389: } 1390: 1391: xiter = navgml.SelectChildren("innerBoundaryIs", OpenGisGMLUrl); 1392: if(xiter.Count > 0) 1393: { 1394: g.innerBoundaries = new LinearRing[xiter.Count]; 1395: i = 0; 1396: while(xiter.MoveNext()) 1397: { 1398: xiterinnerbound = xiter.Current.SelectChildren("LinearRing", OpenGisGMLUrl); 1399: if(xiterinnerbound.MoveNext()) 1400: { 1401: xiterinnerbound = xiterinnerbound.Current.SelectChildren("coordinates", OpenGisGMLUrl); 1402: if(xiterinnerbound.MoveNext()) 1403: { 1404: g.innerBoundaries[i] = new LinearRing(xiter.Current.Value); 1405: i++; 1406: } 1407: } 1408: } 1409: } 1410: 1411: return g; 1412: } 1413: 1414: public static MultiLineString GmlToMultiLineString(XPathNavigator navgml) 1415: { 1416: MultiLineString g = new MultiLineString(); 1417: 1418: XPathNodeIterator xiter; 1419: int i; 1420: 1421: xiter = navgml.SelectChildren("LineString", OpenGisGMLUrl);

1422: if(xiter.Count > 0) 1423: { 1424: g.lineStrings = new LineString[xiter.Count]; 1425: i = 0; 1426: while(xiter.MoveNext()) 1427: { 1428: g.lineStrings[i] = GmlToLineString(xiter.Current.Clone()); 1429: i++; 1430: } 1431: } 1432: 1433: return g; 1434: } 1435: 1436: public static LineString GmlToLineString(XPathNavigator navgml) 1437: { 1438: LineString g = new LineString(); 1439: 1440: XPathNodeIterator xiter; 1441: 1442: xiter = navgml.SelectChildren("coordinates", OpenGisGMLUrl); 1443: if(xiter.MoveNext()) 1444: { 1445: g.coordinates = Coordinate.ParsePoints(xiter.Current.Value); 1446: } 1447: 1448: return g; 1449: } 1450: 1451: public static MultiPoint GmlToMultiPoint(XPathNavigator navgml) 1452: { 1453: MultiPoint g = new MultiPoint(); 1454: 1455: XPathNodeIterator xiter; 1456: 1457: xiter = navgml.SelectChildren("coordinates", OpenGisGMLUrl); 1458: if(xiter.MoveNext()) 1459: { 1460: g.coordinates = Coordinate.ParsePoints(xiter.Current.Value); 1461: } 1462: 1463: return g; 1464: } 1465: 1466: public static Point GmlToPoint(XPathNavigator navgml) 1467: { 1468: Point g = new Point(); 1469: 1470: XPathNodeIterator xiter; 1471: 1472: xiter = navgml.SelectChildren("coordinates", OpenGisGMLUrl); 1473: if(xiter.MoveNext()) 1474: { 1475: g.coord = new Coordinate(xiter.Current.Value); 1476: } 1477: 1478: return g; 1479: } 1480: 1481: public static Feature GmlToFeature(XPathNavigator navgml) 1482: { 1483: Feature f = new Feature(); 1484: 1485: XPathNodeIterator xiter; 1486: XPathNavigator xattnav;

38

Page 41: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

1487: string featuretype; 1488: 1489: f.attributes = new Hashtable(); 1490: 1491: featuretype = navgml.GetAttribute("featuretype", ""); 1492: 1493: xiter = navgml.Select("Attributes"); 1494: if(xiter.Count > 0) 1495: { 1496: xiter.MoveNext(); 1497: xattnav = xiter.Current.Clone(); 1498: if(xattnav.MoveToFirstAttribute()) 1499: { 1500: f.attributes.Add(xattnav.Name, xattnav.Value); 1501: while(xattnav.MoveToNextAttribute()) 1502: { 1503: f.attributes.Add(xattnav.Name, xattnav.Value); 1504: } 1505: } 1506: } 1507: 1508: switch(featuretype) 1509: { 1510: case "MultiPolygonType": 1511: xiter = navgml.SelectChildren("MultiPolygon", OpenGisGMLUrl); 1512: if(xiter.MoveNext()) 1513: { 1514: f.geometry = GmlToMultiPolygon(xiter.Current); 1515: } 1516: break; 1517: 1518: case "PolygonType": 1519: xiter = navgml.SelectChildren("Polygon", OpenGisGMLUrl); 1520: if(xiter.MoveNext()) 1521: { 1522: f.geometry = GmlToPolygon(xiter.Current); 1523: } 1524: break; 1525: 1526: case "MultiLineStringType" : 1527: xiter = navgml.SelectChildren("MultiLineString", OpenGisGMLUrl); 1528: if(xiter.MoveNext()) 1529: { 1530: f.geometry = GmlToMultiLineString(xiter.Current); 1531: } 1532: break; 1533: 1534: case "LineStringType" : 1535: xiter = navgml.SelectChildren("LineString", OpenGisGMLUrl); 1536: if(xiter.MoveNext()) 1537: { 1538: f.geometry = GmlToLineString(xiter.Current); 1539: } 1540: break; 1541: 1542: case "MultiPointType" : 1543: xiter = navgml.SelectChildren("MultiPoint", OpenGisGMLUrl); 1544: if(xiter.MoveNext()) 1545: { 1546: f.geometry = GmlToMultiPoint(xiter.Current); 1547: } 1548: break; 1549: 1550: case "PointType" : 1551: xiter = navgml.SelectChildren("Point", OpenGisGMLUrl); 1552: if(xiter.MoveNext())

1553: { 1554: f.geometry = GmlToPoint(xiter.Current); 1555: } 1556: break; 1557: 1558: default: 1559: break; 1560: } 1561: return f; 1562: } 1563: 1564: public static FeatureSet GmlToFeatureSet(XmlDocument gmldoc) 1565: { 1566: FeatureSet fs = new FeatureSet(); 1567: 1568: XmlNodeReader xr = new XmlNodeReader(gmldoc); 1569: XPathDocument xpath = new XPathDocument(xr); 1570: XPathNavigator xnav, xattnav; 1571: 1572: XPathNodeIterator xiter; 1573: 1574: int i; 1575: 1576: fs.attributes = new Hashtable(); 1577: 1578: xnav = xpath.CreateNavigator(); 1579: xiter = xnav.Select("/FeatureSet/Attributes"); 1580: if(xiter.Count > 0) 1581: { 1582: xiter.MoveNext(); 1583: xattnav = xiter.Current.Clone(); 1584: if(xattnav.MoveToFirstAttribute()) 1585: { 1586: fs.attributes.Add(xattnav.Name, xattnav.Value); 1587: while(xattnav.MoveToNextAttribute()) 1588: { 1589: fs.attributes.Add(xattnav.Name, xattnav.Value); 1590: } 1591: } 1592: } 1593: xiter = xnav.Select("FeatureSet/Feature"); 1594: 1595: fs.features = new ArrayList(xiter.Count); 1596: 1597: i = 0; 1598: while(xiter.MoveNext()) 1599: { 1600: fs.features.Add(GmlToFeature(xiter.Current.Clone())); 1601: i++; 1602: } 1603: 1604: return fs; 1605: } 1606: } 1607: } End of File: SpatialData.cs File: SpatialToVml.cs 1: using System; 2: using System.Collections; 3: using System.Text; 4: using System.Xml; 5: using System.Xml.XPath; 6: 7: namespace SpatialDataLibrary 8: { 9: /// <summary> 10: /// Summary description for SpatialToVml. 11: /// </summary> 12: public class SpatialToVml

39

Page 42: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

13: { 14: public const string MicrosoftVMLUrl = "urn:schemas-microsoft-com:vml"; 15: 16: public string idprefix; 17: public string className; 18: 19: public string strokecolor; 20: public string strokeweight; 21: public string fillcolor; 22: public string opacity; 23: 24: public bool strokeok; 25: public bool fillok; 26: 27: public Hashtable groupattributes; 28: public Hashtable shapeattributes; 29: 30: public int MinRandColor; 31: public int MaxRandColor; 32: 33: private Random rnd; 34: private long shapeId; 35: 36: private int pointRadius, mpp; 37: 38: public string HashColorAttribute = ""; 39: 40: public SpatialToVml( 41: string IdPrefix, 42: string ClassName, 43: string StrokeColor, 44: string StrokeWeight, 45: string FillColor, 46: string Opacity, 47: bool StrokeOk, 48: bool FillOk, 49: int RandColorSeed 50: ) { 51: idprefix = IdPrefix; 52: className = ClassName; 53: strokecolor = StrokeColor; 54: strokeweight = StrokeWeight; 55: fillcolor = FillColor; 56: opacity = Opacity; 57: strokeok = StrokeOk; 58: fillok = FillOk; 59: 60: groupattributes = new Hashtable(); 61: shapeattributes = new Hashtable(); 62: 63: MinRandColor = 100; 64: MaxRandColor = 255; 65: 66: if(RandColorSeed == 0) 67: { 68: rnd = new Random(); 69: } 70: else 71: { 72: rnd = new Random(RandColorSeed); 73: } 74: 75: shapeId = 0; 76: 77: pointRadius = 20; 78: mpp = 0; 79: } 80:

81: private void CreateAttribute(XmlDocument vml, XmlNode element, string attName, string attValue) 82: { 83: XmlAttribute vmlAttribute; 84: 85: vmlAttribute = vml.CreateAttribute(attName); 86: vmlAttribute.Value = attValue; 87: 88: element.Attributes.Append(vmlAttribute); 89: } 90: 91: private string HashColor(string s) 92: { 93: string color = "#"; 94: int colorcomp, i; 95: Random rnd; 96: 97: rnd = new Random(s.GetHashCode()); 98: 99: for(i = 0; i < 3; i++) 100: { 101: colorcomp = rnd.Next(MinRandColor, MaxRandColor); 102: color += colorcomp.ToString("X"); 103: } 104: 105: return color; 106: } 107: 108: private string RandomColor() 109: { 110: string color = "#"; 111: int colorcomp, i; 112: 113: for(i = 0; i < 3; i++) 114: { 115: colorcomp = rnd.Next(MinRandColor, MaxRandColor); 116: color += colorcomp.ToString("X"); 117: } 118: 119: return color; 120: } 121: 122: public string CoordinateToVmlArc(Coordinate coord) 123: { 124: int x, y, size; 125: 126: x = (int)Math.Round(coord.X); 127: y = (int)Math.Round(coord.Y); 128: 129: if(mpp > 0) 130: { 131: size = mpp * pointRadius; 132: } 133: else 134: { 135: size = pointRadius; 136: } 137: 138: return "ar " + (x - size) + "," + (y - size) + "," + (x + size) + "," + (y + size) + 139: ",0,0,0,0 "; 140: } 141: 142: public string CoordinatesToVmlArcs(Coordinate[] coords) 143: { 144: string spath = ""; 145: 146: foreach(Coordinate coord in coords) 147: { 148: spath += CoordinateToVmlArc(coord);

40

Page 43: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

149: } 150: 151: return spath; 152: } 153: 154: public string PointToVml(Point p) 155: { 156: return CoordinateToVmlArc(p.coord); 157: } 158: 159: public string MultiPointToVml(MultiPoint mp) 160: { 161: return CoordinatesToVmlArcs(mp.coordinates); 162: } 163: 164: public string LineStringToVml(LineString g) 165: { 166: int 167: i, ix, iy; 168: 169: string spath = ""; 170: 171: for(i = 0; i < g.coordinates.Length; i++) 172: { 173: ix = (int)Math.Round(g.coordinates[i].X); 174: iy = (int)Math.Round(g.coordinates[i].Y); 175: if(spath == "") 176: { 177: spath = "m " + ix + "," + iy + " l "; 178: } 179: else 180: { 181: spath += ix + "," + iy + " "; 182: } 183: } 184: 185: return spath; 186: } 187: 188: public string MultiLineStringToVml(MultiLineString g) 189: { 190: string path = ""; 191: 192: if(g.lineStrings != null) 193: { 194: foreach(LineString ls in g.lineStrings) 195: { 196: path += LineStringToVml(ls); 197: } 198: } 199: 200: return path; 201: } 202: 203: public string LinearRingToVml(LinearRing g) 204: { 205: int 206: i, ix, iy; 207: 208: string spath = ""; 209: 210: for(i = 0; i < g.coordinates.Length; i++) 211: { 212: ix = (int)Math.Round(g.coordinates[i].X); 213: iy = (int)Math.Round(g.coordinates[i].Y); 214: if(spath == "") 215: { 216: spath = "m " + ix + "," + iy + " l "; 217: } 218: else

219: { 220: spath += ix + "," + iy + " "; 221: } 222: } 223: 224: spath += "x "; 225: 226: return spath; 227: } 228: 229: public string PolygonToVml(Polygon g) 230: { 231: string path = ""; 232: 233: if(g.outerBoundary != null) 234: { 235: path += LinearRingToVml(g.outerBoundary); 236: } 237: 238: if(g.innerBoundaries != null) 239: { 240: foreach(LinearRing ib in g.innerBoundaries) 241: { 242: path += LinearRingToVml(ib); 243: } 244: } 245: 246: return path; 247: } 248: 249: public string MultiPolygonToVml(MultiPolygon g) 250: { 251: string path = ""; 252: 253: if(g.polygons != null) 254: { 255: foreach(Polygon p in g.polygons) 256: { 257: path += PolygonToVml(p); 258: } 259: } 260: 261: return path; 262: } 263: 264: public void SetStrokeAndFill(XmlDocument vml, XmlNode vmlElement, XmlNode vmlParent, Feature f) 265: { 266: XmlElement vmlFill = null; 267: 268: if(strokeok) 269: { 270: CreateAttribute(vml, vmlElement, "strokeok", "true"); 271: CreateAttribute(vml, vmlParent, "strokeweight", strokeweight); 272: if(strokecolor == "random") 273: { 274: CreateAttribute(vml, vmlParent, "strokecolor", RandomColor()); 275: } 276: else if(strokecolor == "hash") 277: { 278: CreateAttribute(vml, vmlParent, "strokecolor", 279: HashColor(f.attributes[HashColorAttribute].ToString())); 280: } 281: else 282: { 283: CreateAttribute(vml, vmlParent, "strokecolor", strokecolor); 284: } 285: } 286: else

41

Page 44: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

287: { 288: CreateAttribute(vml, vmlElement, "strokeok", "false"); 289: } 290: 291: if(fillok) 292: { 293: CreateAttribute(vml, vmlElement, "fillok", "true"); 294: vmlFill = vml.CreateElement("v", "fill", MicrosoftVMLUrl); 295: vmlParent.AppendChild(vmlFill); 296: 297: CreateAttribute(vml, vmlFill, "opacity", opacity); 298: if(fillcolor == "random") 299: { 300: CreateAttribute(vml, vmlFill, "color", RandomColor()); 301: } 302: else if(fillcolor == "hash") 303: { 304: CreateAttribute(vml, vmlFill, "color", 305: HashColor(f.attributes[HashColorAttribute].ToString())); 306: } 307: else 308: { 309: CreateAttribute(vml, vmlFill, "color", fillcolor); 310: } 311: } 312: else 313: { 314: CreateAttribute(vml, vmlElement, "fillok", "false"); 315: } 316: } 317: 318: public void GeometryToVml(XmlDocument vml, XmlNode vmlParent, Feature f) 319: { 320: XmlElement vmlElement = null; 321: 322: IGeometry g = f.geometry; 323: 324: switch(g.GetFeatureType()) 325: { 326: case FeatureType.PointType: 327: case FeatureType.MultiPointType: 328: case FeatureType.LineStringType: 329: case FeatureType.MultiLineStringType: 330: case FeatureType.LinearRingType: 331: case FeatureType.PolygonType: 332: case FeatureType.MultiPolygonType: 333: vmlElement = vml.CreateElement("v", "path", MicrosoftVMLUrl); 334: vmlParent.AppendChild(vmlElement); 335: SetStrokeAndFill(vml, vmlElement, vmlParent, f); 336: break; 337: 338: default: 339: return; 340: } 341: 342: switch(g.GetFeatureType()) 343: { 344: case FeatureType.PointType: 345: CreateAttribute(vml, vmlElement, "v", PointToVml((Point)g)); 346: break; 347: 348: case FeatureType.MultiPointType: 349: CreateAttribute(vml, vmlElement, "v", MultiPointToVml((MultiPoint)g)); 350: break; 351: 352: case FeatureType.LineStringType:

353: CreateAttribute(vml, vmlElement, "v", LineStringToVml((LineString)g) + "e"); 354: break; 355: 356: case FeatureType.MultiLineStringType: 357: CreateAttribute(vml, vmlElement, "v", MultiLineStringToVml((MultiLineString)g) + "e"); 358: break; 359: 360: case FeatureType.LinearRingType: 361: CreateAttribute(vml, vmlElement, "v", LinearRingToVml((LinearRing)g) + "e"); 362: break; 363: 364: case FeatureType.PolygonType: 365: CreateAttribute(vml, vmlElement, "v", PolygonToVml((Polygon)g) + "e"); 366: break; 367: 368: case FeatureType.MultiPolygonType: 369: CreateAttribute(vml, vmlElement, "v", MultiPolygonToVml((MultiPolygon)g) + "e"); 370: break; 371: 372: default: 373: break; 374: } 375: } 376: 377: public void FeatureToVml(XmlDocument vml, XmlNode vmlParent, Feature f) 378: { 379: XmlElement vmlShape; 380: XmlAttribute vmlAttribute; 381: 382: vmlShape = vml.CreateElement("v", "shape", MicrosoftVMLUrl); 383: vmlParent.AppendChild(vmlShape); 384: 385: CreateAttribute(vml, vmlShape, "id", idprefix + shapeId); 386: CreateAttribute(vml, vmlShape, "class", className); 387: 388: foreach(string sa in shapeattributes.Keys) 389: { 390: vmlAttribute = vml.CreateAttribute(sa); 391: vmlAttribute.Value = shapeattributes[sa].ToString(); 392: vmlShape.Attributes.Append(vmlAttribute); 393: } 394: 395: if(f.geometry != null) 396: GeometryToVml(vml, vmlShape, f); 397: } 398: 399: public XmlDocument FeatureSetToVml(FeatureSet fs, int mpp, int pointRadius) 400: { 401: this.pointRadius = pointRadius; 402: this.mpp = mpp; 403: 404: return FeatureSetToVml(fs); 405: } 406: 407: public XmlDocument FeatureSetToVml(FeatureSet fs, int mpp) 408: { 409: this.mpp = mpp; 410: 411: return FeatureSetToVml(fs); 412: } 413: 414: public XmlDocument FeatureSetToVml(FeatureSet fs)

42

Page 45: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

415: { 476: shapeId++; 416: XmlDocument vml; 477: foreach(string attribute in feature.attributes.Keys) 417: XmlElement vmlGroup, vmlSpatialInfo, vmlFeatureAttributes, vmlAttribute;

478: { 479: CreateAttribute(vml, vmlAttribute, attribute, feature.attributes[attribute].ToString()); 418: XmlElement vmlGenerationTime, vmlQueryTime;

419: long start, end, length; 480: } 420: DateTime dtTime; 481: vmlFeatureAttributes.AppendChild(vmlAttribute); 421: TimeSpan tsTime; 482: } 422: TimeSpan queryTime; 483: } 423: 484: 424: start = DateTime.Now.Ticks; 485: end = DateTime.Now.Ticks; 425: dtTime = new DateTime(start); 486: CreateAttribute(vml, vmlGenerationTime, "end",

dtTime.ToLongTimeString()); 426: 427: vml = new XmlDocument(); 487: 428: vml.LoadXml("<FeatureSet xmlns:v=\"" + MicrosoftVMLUrl + "\"/>");

488: length = end - start; 489: tsTime = new TimeSpan(end - start);

429: 490: CreateAttribute(vml, vmlGenerationTime, "length", tsTime.ToString()); 430: vmlGenerationTime =

vml.CreateElement("XmlGenerationTime"); 491: 431: CreateAttribute(vml, vmlGenerationTime, "start", dtTime.ToLongTimeString());

492: return vml; 493: }

432: 494: } 433: if(fs.startQueryTicks > 0) 495: } 434: { End of File: SpatialToVml.cs 435: queryTime = new TimeSpan(fs.endQueryTicks - fs.startQueryTicks);

File: UtmPt.cs 1: // UtmPt.cs

436: vmlQueryTime = vml.CreateElement("QueryTime"); 2: // 437: CreateAttribute(vml, vmlQueryTime, "length", queryTime.ToString());

3: 4: using System;

438: vml.FirstChild.AppendChild(vmlQueryTime); 5: 439: } 6: /// <summary> 440: vml.FirstChild.AppendChild(vmlGenerationTime); 7: /// Universal Transverse Mercator Point 441: 8: /// </summary> 442: if(fs.coordinateSystem.Length > 0) 9: public struct UtmPt { 443: { 10: 444: vmlSpatialInfo = vml.CreateElement("CoordinateSystem"); 11: public int Zone; 445: vmlSpatialInfo.InnerText = fs.coordinateSystem; 12: public double X; 446: vml.FirstChild.AppendChild(vmlSpatialInfo); 13: public double Y; 447: } 14: } 448: End of File: UtmPt.cs 449: if(fs.attributes.Count > 0)

450: { 451: vmlSpatialInfo = vml.CreateElement("Attributes");

452: foreach(string satt in fs.attributes.Keys) 453: { 454: CreateAttribute(vml, vmlSpatialInfo, satt, fs.attributes[satt].ToString()); 455: } 456: vml.FirstChild.AppendChild(vmlSpatialInfo); 457: } 458: 459: vmlGroup = vml.CreateElement("v", "group", MicrosoftVMLUrl); 460: vml.FirstChild.AppendChild(vmlGroup); 461: vmlFeatureAttributes = vml.CreateElement("FeatureAttributes"); 462: vml.FirstChild.AppendChild(vmlFeatureAttributes); 463: 464: foreach(string att in groupattributes.Keys) 465: { 466: CreateAttribute(vml, vmlGroup, att, groupattributes[att].ToString()); 467: } 468: 469: foreach(Feature feature in fs.features) 470: { 471: FeatureToVml(vml, vmlGroup, feature); 472: if(feature.attributes.Count > 0) 473: { 474: vmlAttribute = vml.CreateElement("Attribute"); 475: CreateAttribute(vml, vmlAttribute, "id", idprefix + shapeId);

43

Page 46: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

6.0 REFERENCES

1. Agricultural Research Service Water Data Center. 1995. ARS Water Data: ARS/Access CD. USDA-ARS Hydrology Lab, Beltsville, Maryland. Agricultural Research Service Water Data Center. http://www.hydrolab.arsusda.gov/arswater.html.

2. Burford, J.B. and J.M. Clark. 1976. Hydrologic data for experimental agricultural watersheds in the United States, 1968. U.S. Department of Agriculture Miscellaneous Publication No. 1330, 542pp.

3. David, O., S.L. Markstrom, K. W. Rojas, L.R. Ahuja, and I.W. Schneider 2002. The Object Modeling System, Agricultural System Models in Field Research and technology Transfer, L.R. Ahuja, L. Ma, and T.A. Howell (Eds), Lewis Publishers, New York, 317-330.

4. David, O., L.R. Ahuja, and J.C. Ascough, 2004. Developing Natural Resource Models Using the Object Modeling System: Feasibility and Challenges, IEMSS Osnabrueck.

5. Hawkins, R. H. 1979. Runoff curve numbers from partial area watersheds. Proc. American Society of Civil Engineering. 105(IR4).

6. Hawkins, R.H. 1993. Asymptotic determination of runoff curve numbers from data. Journal of Irrigation and Drainage Engineering. 119(2):334-345.

7. Hjelmfelt, A.T. 1980. Empirical investigation of curve number technique. Journal of the Hydraulics Division. ASCE, 106 (HY9):1471-1476.

8. Hjelmfelt, A.T. 1980. Curve Number Procedure as an Infiltration Method. Journal of the Hydrology Division. ASCE, 106 (HY6):1107-1111.

9. Hjelmfelt, A.T., Woodward, D.E., Conaway, G., Plummer, A., Quan, Q.D., Van Mullen, J., Hawkins, R.H., Rietz, D., Sept. 2001. Curve Numbers, Recent Developments. Proc. 29th Congress of the Intl. Assoc. for Hydraulic Research. Beijing, China.

10. Langlois, G., Oct. 4, 2001, USDA picks GIS standard, http://www.fcw.com/fcw/articles/2001/1001/web-gis-10-04-01.asp, FCW.COM

11. Leavesley, G.H., Restrepo, P., Stannard, L.G., and Dixon, M., 1992, The modular hydrologic modeling system - MHMS: AWRA 18th Annual Conference and Symposium, Managing water resources during global change, Reno, Nevada, November 1-5, 1992, p. 263-264.

12. Leavesley, G.H., Restrepo, P.J., Markstrom, S.L., Dixon, M., Stannard, L.G., 1996, The Modular Modeling System (MMS): User's Manual, U.S. Geological Survey Open-File Report 96-151, 175 p.

13. Mockus, Victor. 1964. Letter from Victor Mockus to Orrin Ferris, March 5, U.S. Department of Agriculture, Soil Conservation Service, Latham, MD.

14. Musgrave, G. W. 1955 “How much rain enters the soil,” Water Yearbook of Agriculture, U.S. Department of Agriculture, Washington, D.C. pp. 151-159

15. Nielson, R. D. and A. T. Hjelmfelt. 1998 Hydrologic soil-group assignment. IN Water Resource Engineering 98, Am. Soc. Civil Engrs., Abt, Young-Pezeshk, Watson(eds), v2pp1297-1302

16. Pankey, J.M. and R.H. Hawkins. 1981. Stormflow as a function of watershed impervious area. Proceedings Arizona Section Amer. Water Resources Association, and Hydrology Section Arizona-Nevada Academy of Sciences. Tucson, Arizona.

17. Soil Survey Staff. 1993. National Soil Survey Handbook. USDA-SCS, Soil Survey Division. U.S. Gov. Printing Office, Washington, D.C. Section 618

18. Rietz, P.D. and R.H. Hawkins. 2000. Effects of land use on runoff curve numbers. Watershed Management 2000. Am. Soc. Civil Engineers (CD ROM).

19. Smith, R.E., 1997. Comment on "Runoff Curve Number: Has it reached maturity?" by V.M. Ponce and R.H. Hawkins, Journal of Hydrologic Engineering, ASCE, 2(3):145-147.

20. Smith, R. E., and R. J. Montgomery, 1980. Discussion of "Runoff curve numbers from partial area watersheds". Journal of Irrigation and Drainage Division, ASCE 106(IR4):379-381.

44

Page 47: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

21. Smith, Roger E. and Kenneth G. Eggert, 1978. Discussion of "Infiltration formula based on SCS curve number", by Gert Aron, Arthur C. Miller, Jr., and David F. Lakotos, of the Irrigation and Drainage Division, Proc. ASCE 104(IR4): 462-464.

22. U.S. Department of Agriculture, Soil Conservation Service. 1993. National Engineering Handbook, Section 4, Hydrology (NEH-4).

23. U.S. Department of Agriculture, Soil Conservation Service. 1986. “Urban Hydrology for Small Watersheds”, Technical Release 55 (TR-55).

45

Page 48: Paper 1675 Title Geospatial Calculation of SCS Runoff ... · requires that soil survey information be available for the watershed of interest. A soil survey provides the information

About Your Paper

2004 International ESRI Conference Paper 1675

Status: Accepted

Water Modeling

Wednesday August 11, 2004 - 1:30 PM

Room 25-A

Contact Information

John M. Huddleston, PE, PhD

USDA NRCS

2150A Centre Avenue

Fort Collins, CO 80526 USA

970-295-5485

[email protected]

46