Visual Basic Class ShapeIO and Spatial Functions version 2.0

Initial Author : Kenneth R. McVay
Date : December 24, 1998
email : rcreed@earthlink.net

Contributing Authors
	Roger Merritt
	Mark Gray

Copyright (c) 1998 by ShapeIO Project

This code was written with Visual Basic version 5.0.

This code is out there in the free world for all to use anyway you see fit. You may freely distribute this code with your own applications.  The only thing I ask is if you use it give this project credit in your documentation or about box.

This code is distributed as is and I cannot be held responsible for what you do with it or any damages caused by its use.

This code is ment to (1) Read and write ESRI Shape Files works great (2) Perform spatial operations on shapes much work is needed here.
This code only handles Point, Multipoint, Polygon, and Polyline shapetypes. The 3 dimensional type are not handled as of yet. This is mainly because I have not had any need for the 3D types to date. I fully intend to implement the 3D types ASAP and if anyone would like to beat me to it please feel free.

This class is a vast improvement over the previous version and no longer requires the user to declare variable of a given shape type. This version is object oriented. If you are going to use this code it would be helpful if you are familiar with the file format of a shapefile. You can find the documentation for the ESRI shapefile at 
www.esri.com

In the zip you should find a number of class modules and a VB project called projShape.vbp I advise that you open this project and look at the simple code that I have included to show you how to read and write a shapefile with these classes. The example program will allow you to specify a shapefile, x and y shift values and the output shapefile name. It will then add the shift values to the original shapefile and create the new shapefile.

The code does not provide any way to read the dbase files associated with a shapefile. I believe there was no need to provide code to handle dbf file because Visual Basic will almost do it automatically for you. All you need to remember is keep the records in the dbase file in the same order as the associated shapefile. If database access it new to you and your not sure how to get started then you can look in the VB books online for help and also in MSDN visual studio help. If you would like a good book on the subject of reading and writing database files then a good place to start is "Teach Yourself Database Programming with Visual Basic 5 in 21 days. Sams publishing". There are many other books on the subject that are equally good.

This code may still have errors. However, I have tested it with point, polygon, and polyline shapefiles and have noticed no errors. If you find one would you kindly send me a report on the error so that I may fix the problem my email in rcreed@earthlink.net . If you improve it send me a copy so I can use it.

I know there are 2000 some odd people who downloaded the older version. If that many people downloads this version and were to write one function to add to this code, it would be very good freeware product for all to use. So I am asking if you have programming experience in VB or you are just learning and would like to contribute to the code please do so. Version control may be a bit of a problem so if you create some new code just zip up the whole project and send it to me along with a note on the functions you created and there purpose. I will then list you as one of the contributing authors and post the new version of the code.

CFileName

A utility class which eases the usage of manipulating filenames. This class is a parameter of the CShapeFile Class and is what you pass into a CSHAPEFILE object to specify the shapefile to open or create.

Properties include

SetFileSpec - This should be called to initialize the filename object. It initially sets the drive:\path\name.ext of the object.
GetFileSpec - Returns the drive:\path\name.ext of the object
SetBaseName - Allows the base name to be changed
GetBaseName - Returns the base name of the filename
SetExtension - Allows the extension to be changed
GetExtension - Returns the extension

Example usage :
	Dim FileSpec as new C_FileName
	dim s as string
	FileSpec.SetFileSpec = “c:\temp\lakes.shp”
	s = FileSpec.GetBasename    ‘returns lakes
	s = FileSpec.GetExtension    ‘returns shp
	FileSpec.SetBaseName = “cities”
	FileSpec.SetExtension = “shx”

CShapeFile

This is the main class which allow one to either (1) open an existing shapefile or (2) create a new shapefile. Once an CSHAPEFILE object is created, one can add shapes to the file or read shapes from the file.

Public Sub SetFileSpec(FileSpec As C_FileName, status As OPENCREATE, Optional aShapeType As SHAPEFILETYPE)

Once an object of CSHAPEFILE is created the Property SetFileSpec must be set before one can get shapes from or add shapes to it. To initialize the CSHAPEFILE object for reading an existing shapefile one would call SetFileSpec such as

dim aShapeFile as new CSHAPEFILE
dim fileSpec as new C_FileName
fileSpec.SetFileSpec = “c:\temp\lakes.shp”
aShapeFile.SetFileSpec fileSpec, OPENIT

To create a new shape file one would use SetFileSpec such as
dim aShapeFile as new CSHAPEFILE
dim fileSpec as new C_FileName
fileSpec.SetFileSpec = “c:\temp\lakes.shp”
aShapeFile.SetFileSpec fileSpec, CREATEIT, typePolygon

The last optional parameter is mandatory when creating a shapefile and is set to the desired type of shapefile.

Public Property Get Count() As Long
Returns the number of shapes in the open shapefile.

Public Property Get GetShapeFileType() As SHAPEFILETYPE
Returns the type of shapefile that the object currently points to.

Public Sub Add(anObject As Object)
Allows one to add a new shape of the appropriate type to the open shapefile.

Public Function Item(ByVal index As Long) As Object
Returns the Shape associated with the record number index.

Interface IShape

This is a public interface to all shape types including CRect. It will provide polymorphism to all shape types so one can call interface functions with out knowing what the underlying shape type is. There are not many properties/functions/methods available in the interface at the moment however, I will be steadily adding them as time permits. It will ultimately contain a large number of functions that permit spatial query, shape type conversions, etc... e.g. PointInPolygon, Distance, length, area, clipping, merging, moving and so on. I have already implemented one such function Distance which is only so far been implemented for the CPoint.

Anyone and everyone is encouraged to add to this code and in the end we will have a very nice set of Spatial tools for visual basic that we will be able to enhance our ArcView projects with.

To add and interface function all you need to do is declare it in the IShape interface as public with no code and then implement the new function in each of the Shape type classes include CRect with the code for each. If you need any help or would like me to clarify something please feel free to email me.

Public Property Get Top() As Double
Returns the top coord of the shape extent.

Public Property Get Bottom() As Double
Returns the bottom coord of the shape extent.

Public Property Get Left() As Double
Returns the left coord of the shape extent.

Public Property Get Right() As Double
Returns the right coord of the shape extent.

Public Property Get IsNull() As Boolean
Returns either TRUE or FALSE. If the shape is null then it returns TRUE. If the shape if not null it returns FALSE.
When you read a shape from disk or go to do anything with a shape you should always check to see if the shape is null.

Public Property Let MakeNull(TrueORFalse as Boolean)
Allows one to set a shape to null or not.

Public Function Distance(aShape As Object) As Double
This is the first of the spatial functions I have added to the interface. Only CPoint.Distance(anotherShape) is valid at this time.
You can use it like the following

d = MyPoint.Distance(MyPoint)
d = MyPoint.Distance(MyMultiPoint)
d = MyPoint.Distance(MyPolyLine)
d = MyPoint.Distance(MyPolygon)

Class CPart

CPart objects can only accept objects of type CPoint

Public Property Get Count() As Long
Returns the number of CPoints in the part.

Public Sub Add(anObject As Object)
Allow the addition of  a new CPoint to the part

Public Function Item(ByVal index As Long) As Object
Returns a CPoint associated with the index number. 1>= index  <= number of CPoints in the part

Public Sub Remove(ByVal index As Long)
Removes an CPoint from the part associated with the index. 1>= index  <= number of CPoints in the part

Public Property Get Left() As Double
Returns the left coord for the CPart extent.

Public Property Get Right() As Double
Returns the right coord for the CPart extent.

Public Property Get Top() As Double
Returns the top coord for the CPart extent.

Public Property Get Bottom() As Double
Returns the bottom coord for the CPart extent.

The following four write properties allow one to independently set the extent of a part. There is not need to use them if you are happy with the minimum bounding Rectangle for the part. The minimum bounding rectangle is handled automatically.

Public Property Let Left(aValue As Double)
Set the left coord for the CPart extent.

Public Property Let Right(aValue As Double)
Set the right coord for the CPart extent.

Public Property Let Top(aValue As Double)
Set the top coord for the CPart extent.

Public Property Let Bottom(aValue As Double)
Set the bottom coord for the CPart extent.

Class CPoint

This class is used to hold basic XY Points.

Public Property Get X() As Double
Returns the X value of the point.

Public Property Let X(ByVal XValue As Double)
Sets the X value of the point.

Public Property Get Y() As Double
Gets the Y values of the point.

Public Property Let Y(ByVal YValue As Double)
Sets the Y value of the point.

Class CMultiPoint

This class is used for MultiPoint shapes and can accept only CPoint objects

Public Property Get Count() As Long
Returns the number of CPoints in the MultiPoint Shape.

Public Sub Add(ByVal aPoint As CPoint)
Allows the addition of a CPoint to the MultiPoint shape

Public Function Item(ByVal index As Long) As CPoint
Returns the CPoint from the MultiPoint shape associated with index.  1>= index  <= number of CPoints in the MultiPoint shape.

Public Sub Remove(ByVal index As Long)
Allows the removal of a CPoint from the MultiPoint shape. 1>= index  <= number of CPoints in the MultiPoint shape.

Class CPolyLine

This class is used for Polyline shapes and can accept only CPart objects

Public Property Get Count() As Long
Returns the number of CParts in the CPolyLine shape.

Public Sub Add(ByVal aPoint As CPoint)
Allows the addition of a CPart to the CPolyLine Shape

Public Function Item(ByVal index As Long) As CPoint
Returns the CPart from the CPolyLine shape associated with index.  1>= index  <= number of CParts in the CPolyLine shape.

Public Sub Remove(ByVal index As Long)
Allows the removal of a CPart from the CPolyLine shape. 1>= index  <= number of CParts in the CPolyLine shape.

Class CPolygon

This class is used for Polygon shapes and can accept only CPart objects

Public Property Get Count() As Long
Returns the number of CParts in the CPolygon shape.

Public Sub Add(ByVal aPoint As CPoint)
Allow the addition of a CPart to the CPolygon shape.

Public Function Item(ByVal index As Long) As CPoint
Returns the CPart from the CPolyLine shape associated with index. 1>= index  <= number of CParts in the CPolygon shape.

Public Sub Remove(ByVal index As Long)
Allows the removal of a CPart from the CPolyLine shape. 1>= index  <= number of CParts in the CPolygon shape.

Class CRect

Public Sub MakeEmpty()
Once a CRect object is created a call to MakeEmpty will initialize all coords of the CRect object to 0.

Public Sub Make(ByVal originPoint As CPoint, ByVal sizePoint As CPoint)
Once a CRect object is created a call to Make will initialize the upper left corner of the rect to originPoint and the lower right corner of the rect to sizePoint.

Public Sub MakeXY(ByVal x1 As Double, ByVal y1 As Double, ByVal x2 As Double, ByVal y2 As Double)
Once a CRect object is create a call to MakeXY will initialize the upper left corner of the rect to (x1,y1 ) and the lower right corner to (x2,y2).

These following four get properties are also available in the IShape interface
Property Get Top() As Double
Returns the top coord of the CRect object.

Public Property Get Bottom() As Double
Returns the bottom coord of the CRect object.

Public Property Get Left() As Double
Returns the Left coord of the CRect object.

Public Property Get Right() As Double
Returns the Right coord of the CRect object.

Public Property Let Top() As Double
Set the Top coord of the CRect object.

Public Property Let Bottom() As Double
Set the Bottom coord of the CRect object.

Public Property Let Left() As Double
Set the Left coord of the CRect object.

Public Property Let Right() As Double
Set the Right coord of the CRect object.