Utility Infrastructure Mapping and Application Migration from Avenue to VBA


Ken Brown,G.I.S. Coordinator
Brij M. Garg, P.E., DEE, Utilities & Engineering Director
City of Coconut Creek, Florida

This paper presents the technical tips and methods for the effective mapping of municipal utility infrastructure. Additionally, the specifics of using ArcInfo-based VBA for application development are addressed. Experienced users will benefit from exposure to the detailed methodology presented regarding the creation of a seamless utility as-built mosaic in workstation ArcInfo and subsequent feature mapping in the personal geodatabase data model. Graphical User Interface design is addressed both conceptually and technically, with specific attention paid to the conversion of existing Avenue code to VBA equivalent. Extensive code examples are provided in parallel: utilizing both VBA and Avenue language formats.




Introduction

The following paper is targeted towards experienced ArcInfo users by presenting the technical tips and methods that address several specific issues related to the application of G.I.S. in a local government setting. In addition to the presentation of specific methodologies, this paper strives to demonstrate the feasibility of a local government entity achieving a relatively sophisticated level of G.I.S. development, without investing a small fortune in sub-contracting specialized consultants. As with any decision involved in the implementation of a G.I.S., there are both benefits and costs that result.

The benefits of performing the methods described herein, in-house, are numerous and include the following: a.) Absence of costly "Needs Assessments" due to gradual, progressive system development/ growth, b.) ease of debugging in the case of system errors due to intimate familiarity with data and custom applications, c.) ease of adaptation to future changes in database/dataset structure, d.) ease of future application customizations, and e.) dramatically increased familiarity of staff personnel with each individual land parcel and the mappable infrastructure features. Furthermore, the creation of custom applications in-house, results in user interfaces which are completely tailored to the particular organization's needs and therefore, contain no "canned" modules and/or methods.

The costs associated with these in-house methods involve the amount of time required for the gradual, progressive development/growth of the evolving G.I.S. functionality. It is felt that a reasonable amount of time for in-house G.I.S. staff to develop and implement a fully functional system (infrastructure mapping and GUI development/deployment) is approximately 3 to 4 years. A specialized consultant, on the other hand, could likely achieve an equivalent level of development (or more) in 6-12 months, depending on the extent of their existing "custom" applications.

As with any course of action that is characterized by both costs and benefits, valid arguments can be made for both sides. None-the-less, the difference between out-sourcing G.I.S. development and performing the methods of this paper, in-house, can easily be well over a million dollars in expense plus subsequent annual mantenance fees. While this process is much slower than sub-contracting everything, it is felt that the benefits described above are nearly immeasurable.



Methods

The City of Coconut Creek, Florida, has taken the initiative to perform an in-house conversion of all Utility infrastructure from mylar drawings to digital spatial data in a fully functional Geographic Information System (G.I.S.). This includes the initial phase of thoroughly inventorying and cataloging all archived record drawings, followed by the scanning of each document. Esri's ArcInfo (version 8.0.2 and 8.1) was subsequently implemented in order to rotate, scale, transform, and clip each digital image via a georeferencing procedure. Once this was accomplished, this same software product was used to map all pertinent line and point information into a personal geodatabase in the state-plane coordinate system.

Additionally, the City of Coconut Creek has accomplished the customized in-house application development required in order for the newly created G.I.S. data to be readily accessible to network users. This Graphical User Interface (GUI) was initially developed and implemented in ArcView 3.1 using the Avenue programming language. Subsequently, this GUI application was re-created in ArcInfo 8.0.2/8.1 using the Esri version of Visual Basic [ArcInfo-based Visual Basic for Applications (VBA)].

Digitization of Hard Copy Record Drawings

The City of Coconut Creek is estimated to have over 3300 record as-built drawings archived in two large mylar storage cabinets. Of these drawings, the City's G.I.S. section has currently scanned approximately 80% of the aforementioned record drawings using a large format (24"x36") monochrome (B/W) scanner possessing a single camera. The resulting images were created with a 500 dpi resolution and saved using a TIFF image format with LZW compression. In all, 2,640 files have been scanned and arranged into 444 folders. The top level of this directory structure is governed by a rectangular grid system defined by a Section-Township-Range (S-T-R) method. Each Townhip-Range is comprised of 36 Sections, with each Section being approximately one square mile in area. The origin of this grid system is located in Tallahassee, Florida. Township divisions increment in a North-South orientation and Range divisions increment in an East-West direction. The City of Coconut Creek, for example, is approximately centered on Sections 19 and 20 of Township 48 South, Range 42 East. In all, the top level of the Coconut Creek scanned file archive directory structure is comprised of 17 unique S-T-R folders. Under each Section's folder resides a list of subdirectories which correspond the current list of recorded plats (or in some cases, re-plats) within that Section. In the case of plats than span Sectional boundaries, a weighted-method is used in order to determine the dominant Section by percentage area. The scanned as-builts were then placed in the dominant Section's directory with text files (Readme.txt) containing directory locational information being placed in the adjacent Section subdirectories. All scanned plat mylars reside at this Plat-name level in the directory structure. Rarely, the County Property Appraiser folio number of a particular plat has been replaced with that of a County site plan, and in such a case, the site plan name would be used to represent the property. At the tertiary subdirectory level, all folders correspond to either county site plan names or community development names (see Figure 1).


Figure 1. Example scanned archive directory structure and standardized file naming conventions

Seamless Utility As-Built Moasic Creation

The ArcInfo Workstation environment has been primarily utilized for the creation of the Utility as-built mosaic. More specifically, the REGISTER and RECTIFY commands have been used in order to georeference a portion of the approximate 2000 as-built sheets pertaining to the Coconut Creek Utility service area (note: excludes scanned as-built sheets such as details, cross-sections, cover sheets, etc.). Prior to the actual registration, each water, sewer, or drainage as-built image was imported into Corel PhotoPaint. The images were then re-sampled to 300 dpi for saving as an uncompressed TIFF. This step was required since the City has not licensed LZW Compression in ArcInfo and file size would otherwise be unmanageable. The irregular mask tool was then used in Corel PhotoPaint to copy the appropriate regions of the re-sampled image and thereby eliminate unwanted information. Depending on the content of the particular as-built, upon saving, the newly re-sample and clipped as-built image was placed into one of the following file directories: ..\ScannedFiles\CompositeAsBuilts\Water, ..\W&S, ..\Sewer, or ..\Drainage.

Next, the image was brought into ArcInfo Workstation for registration. The registration process requires the use of existing coverage data in order to georeference the raster imagery. In the case of the City of Coconut Creek project, a high horizontal positional accuracy basemap was used as the coverage data. This survey-grade parcel basemap was created for the city by the Broward County Property appraiser's office in their effort to create a 440 square mile county basemap. Real-time kinematic GPS (sub-centimeter accuracy) was implemented in the course of this mapping project in order to establish a network of county-wide control points. The resulting parcel basemap utilized in this Coconut Creek project is estimated to have a horizontal error of less than 6 inches at any given location.

REGISTER is an ARC command that initiates an interactive multi-window display allowing the user to georeference an image using existing coverage data. REGISTER utilizes user-defined links to apply an affine transformation (1st order, linear equation) to calculate the amount of scaling, rotation, and translation required to align the image to map coordinates. As such, the scale and rotation of the image being georeferenced must not vary across the image. A minimum of three user-defined links, or control points, are required for the georeferencing process. In most cases, the registration of as-built sheets in the City of Coconut Creek project made use of three control points, preferentially along three edges/corners of the image. Goodness-of-fit was determined visually by locking the transformed image and the coverage data linework in the overlay window of the REGISTER environment. In the case of poor registration (> 3 ft of offset), the process was repeated with up to four user-defined control points. When using more than three links with REGISTER, error can be evaluated by the least squares solution report provided by ArcInfo. In the case of the City of Coconut Creek project, goodness-of-fit remained to be determined visually even in the case of four links. Once the registration was acceptable (i.e., overlay showing a line/image offset of less than 3 ft), the registration process was completed by saving the transformation to a world file (*.tfw). The registration process was subsequently followed by rectification of the original image based on the information saved to the world file. RECTIFY is the ArcInfo command that applies the saved transformation permanently to the image, creating a new georeferenced image which is correctly rotated, scaled, and transformed to map coordinates.

Utility Feature Mapping in the Personal GeoDatabase

Utility feature mapping was performed in the Desktop environment of ArcInfo 8.0.2/8.1. The choice was made to create a personal GeoDatabase (pGDB) in order to utilize the advanced mapping abilities available in ArcMap. Geodatabase design, including feature class properties, is summarized in Table 1. As can be seen, multiple default values were automatically assigned to the attribute tables of each newly created feature of a given feature class. Furthermore, no attribute validation rules were created for the defined subtypes (i.e., no attribute domains, connectivity rules, nor relationship rules). Once all the feature classes and their properties of the pGDB were created, a separate ArcMap document (*.mxd) was created for each of the three utility layers: water, sewer, and drainage. At the top level of each document's legend, all corresponding feature data layers were positioned in the order: point, line, polygon. Below these data sets, high resolution black and white aerial photography was position and displayed with a 35% transparency. Each georeferenced as-built image was then brought into the respective ArcMap document and positioned at the bottom level of the legend; ordered amongst themselves so as to achieve maximum visibility of each image when displayed in the mosaic. In this way, the aerial photography is transparent enough to see through; allowing the user to simultaneously view the G.I.S. data layers, aerial photographs, and scanned as-builts drawings.


Table 1. Summary of the personal Geodatabase feature classes created for the mapping of utility infrastructure in the City of Coconut Creek. Additionally shown are the defined subtypes and the automatically assigned default attribute values.

The digitization of the individual map features was subsequently performed by tracing the line work and point features indicated on the georeferenced digital as-builts. The digitization of new features in Desktop ArcInfo is characterized by the new feature being displayed with the correct symbology the instant they are created. Additionally, the transparent aerial photography can be displayed over the georeferenced as-built mosaic to further aid the digitization process. As each point/line feature is created, any modification to the default attribute assignments is performed. For instance, if a water line is created, the default attribute assigned to the TYPE field is 8" D.I.P.. If this main is delineated as a 6" main on the georeferenced as-built image, the value can be modified immediately in the "attributes window" initiated from the Editor Toolbar. In the Coconut Creek project, it was decided to digitize point symbols in a specific order so as to achieve the desired feature visibility. Point symbols created in a pGDB are layered in the display according to the order in which they are digitized. Therefore, it was necessary to determine the most effective order of digitization so as to achieve the optimal visibility of this projects point symbology (see Figure 2 for symbols). For example, tees were digitized first, followed by gate valves (or hydrant valves), followed by reducers, then hydrants. This order was primarily implemented due to visibility, but may also indicate the importance of the various features.


Figure 2. Current mapping symbology for point features within the Coconut Creek personal GeoDatabase

The dynamic snap environment provides for a rapid means for not only changing the current snap feature, but also for switching between feature datasets. Additionally, an entire hierarchical array of active snap features can be simultaneously invoked. In the case of sewer linework, gravity mains were created by snapping the endpoints of each arc to the previously created sewer manholes. Sewer laterals were subsequently snapped to the arcs of the newly digitized gravity mains. In this way, gravity mains are not broken into line segments by the connecting laterals (as in reality), and are continuous from manhole to manhole. None-the-less, sewer laterals are snapped to the gravity mains exact edge location. In the case of the water system, distribution mains were digitized first, with snapping to watermain end-points (nodes). Transmission main arcs were broken at the as-built locations of all water structures (tees, gate valves, reducers, etc.). Digitizing the mains first allowed the City to take full advantage of the draw parallel, perpendicular, and specified angle options available in the Desktop environment. Subsequently, water point features were snapped to watermain nodes, with water service lines being snapped to arc edges of the mains to achieve the same connectivity as described for the sewer system.

Graphical User Interface Migration from Avenue to VBA

The fundamentals required for the migration from Arc Avenue to VBA for ArcInfo were found in the Esri publication: ArcObjects Developer's Guide. This is one of the numerous manuals that were provided by Esri with ArcInfo 8.0.2 (see also: ArcGIS Disk #3: Digital Books and Sample Maps – "DigitalBooks\ArcObjects\GettingStartedIn VB" and ..\ExploringArcObjects"). While none of these publications provide any code conversion examples (from Avenue to VBA), it does provide simple (and complex) VBA examples that provide insight into the syntax and structure of coding in the new development environment. Such beginning examples are essential due to the fact that ArcGIS 8.1 is built upon a compiled language source code, making the textural examination of system scripts impossible. Furthermore, some of the examples within this Developer's Guide publication demonstrate how VBA code can be used to execute the built-in commands of existing menus, buttons, and tools. Additional characteristics of the VBA environment include the required use of sub-routines, modules, and functions; as well as the need for variable declaration [defining the variable type (i.e., myVar As Integer, String, etc.) or establishing variable class inheritance (pVar As ICollection)]. Sub-routines and functions replace the need for the numerous Avenue script files, and variable declaration is no longer simply implied by the DocGui Interface being implemented (i.e., View, Layout, Table, etc.). In ArcInfo 8.1, VBA contains the largest COM-based object model ever created in any application. It follows that the object model is also the most intricate and extensive. Variable declaration is clearly the most difficult part of coding in VBA for ArcGIS.

Of primary significance in the GUI migration process, is the existence/development of programmatic flow charts. As Shown in Appendix II and IV, a programmatic flow chart has been created by the City of Coconut Creek for the current GUI development; using both Avenue and VBA. Re-development of GUI functionality has been accomplished by emulating the function of each routine, one at a time, in a top-down order. By having the flow chart on-hand, each routine can be individually examined by isolating all associated Avenue scripts and dialogs. Once this is done, each dialog can then be graphically re-created in the VBA development environment, with the code being attached to form events so as to emulate the original Avenue functionality. The one exception to this was in the case of the LOCATION routine of the "ParcelSearch" form. In this case, it was necessary for the application to zoom to the selected city zone (by user click), followed immediately by zooming to the selected zone. The initial attempt involved the execution of the built-in tool "Query_SelectFeatures", followed by "Query_ZoomToSelected". This cannot work since the multi-threaded nature of VBA in ArcInfo 8.1 causes the zoom-in command to run simultaneously with the select feature command. In this case, an active-X dynamic link library (*.dll) was created in order to build a custom select-zoom tool. This method requires the use of VB 6.0 to create a stand-alone project to which the ArcID module has been imported. Instead of this VB project being then compiled into a standard *.exe file, it is compiled into a *.dll which can then be added as a resource to the VBA project. A step-by-step example of this technique is outlined below:


In this way, the mouse-down event is assigned to select a polygon by the user's mouse-click, while the mouse-up event is assigned to zoom to the selected polygon upon the release of the mouse button.

Similar to the multi-threaded problem described above, the use of calls to subroutines or user-defined functions, can result in code running in parallel when it is intended to run sequentially. In these cases, where there is no issue of waiting for a tool to receive input from the user, the use of the "DoEvents" statement is sufficient in order to yield execution so that the operating system can process other events simultaneously (see Appendix VI).



Discussion

The objective of this section is to discuss the author's evaluations as to the applicability, appropriateness, and relevance of the G.I.S.-related work performed by the City of Coconut Creek. Of greatest importance is to convey to the reader, a sense of what worked well, what didn't, and what we would have done differently had we the opportunity to start over. Insight into the reasoning behind the methodology employed is likely to be as important and the methodology itself.

Considerations in the Digitization of Hard Copy Record Drawings

It is of utmost importance for the organization beginning a full-scale scanning process, to first thoroughly inventory all property parcels within its legal boundaries (see Appendix I). The essence of the scanned image directory structure lies in the fact that the directory path for a parcel's digital as-builts is dynamically concatenated by the GUI, as the system is queried by the user (see code example #3 in Appendices III and VI). If the digital archive is poorly constructed, or inaccurately populated, the end-result will be that the corresponding record drawings will become inaccessible. In other words, the ultimate directory location of a particular file will determine whether it will be found by subsequent GUI applications. Furthermore, the file naming convention adopted will determine the archive's usefulness to the actual end-users. With regard to the physical portion of the scanning process, the City of Coconut Creek has been implemented a system using a large format (24"x36") monochrome (B/W) scanner with a single camera. Future improvements shall include the move to a two camera digital scanner for greater speed of scanning. Further changes will be a reduction of the scanned image resolution (300 dpi), so as to eliminate the need for LZW compression. A scanned file resolution of 500 dpi is excessive, even for large scale plotting.

As-Built Mosaic Creation

With regard to the As-Built mosaic creation process, the REGISTER and RECTIFY commands have been used in ArcInfo Workstation due to the absence of a georeferencing capability in the Desktop environment of ArcInfo 8.0.2. REGISTER is an ARC command utilizes user-defined links to apply an affine transformation to calculate the amount of scaling, rotation, and translation required to align the image to map coordinates. This affine transformation does not rubber sheet the image! Rotation, translation, and scaling are applied uniformly across the entire image. Hence, it follows that in order for the registration process to be successful, the basemap coverage data should possesses a relatively high degree of horizontal positional accuracy (preferably survey-grade mapping), in order to fit with the "to-scale" engineering as-built images. It is important to note that this very same methodology can be adapted to work in the georeferencing functionality provided in the Desktop environment of the newly released ArcInfo 8.1. Additionally, georeferencing in 8.1 allows the rectification of a scanned image to existing rectified aeial photography. This may be a powerful capability for organizations that have invested in high positional accuracy ortho-rectified aerial photography, as opposed to a survey-grade parcel basemap (as in the case of the City of Coconut Creek). It should be noted, however, that if ArcInfo 8.1 is used, the non-linear second/third order equations are not recommended. Rubber sheeting record drawings should not be adopted as a methodology where horizontal accuracy is of primary concern.

With regard to the Workstation methodology, REGISTER calculates the fit based upon the assumption that all links are of equal quality. Therefore, if four or more links are used, link 3 may show a high error in the least-squares report. Using the above assumption, deleting link 3 should result in a better overall registration. In reality, link 3 could be a high quality link whose offset distance is being influenced by other low-quality links. Hence, visual inspection of the goodness-of-fit (graphically examining the amount of offset between the image and coverage) was determined to be of utmost importance in the City of Coconut Creek project. Of course, increasing the number of links will dilute the deleterious effect of the creation of a low quality link. A much better choice is to rely on the 3-link method to immediately flag the presence of a erroneous link; allowing for the transformation to be re-set, and performed again to attain the necessary goodness-of fit by visual inspection.

Justification of Utility Feature Mapping in the Personal GeoDatabase

Feature mapping was chosen to be performed in the ArcInfo Desktop environment over Workstation ArcInfo for several factors. First and foremost, the advanced feature symbology allowed for visually distinguishable thematic map elements while digitizing each feature. This symbology includes all of the standardized Engineering/AutoCAD symbols, previously only available in Arc FM. No longer was it necessary to list attribute values during the digitization process, in order to confirm that a feature had been assigned properly. Secondly, the automatic population of attribute items with default values provided a means for rapid, consistent, and accurate database development. Desktop ArcInfo additionally posses many AutoCAD-like digitizing tools (i.e., draw perpendicular, parallel, circular arcs, etc.) that dramatically aided the digitization process. Furthermore, the dynamic snap environment was extensive and rapidly convertible between features classes (point, node, edge, etc.) and datasets (parcel basemap, watermains, water structures, etc.). The advanced raster display of the Desktop environment additionally allowed for the incorporation of a 35% transparent, high-resolution aerial photo overlay. This allowed the aerial photography to be simultaneously used in conjunction with the georeferenced as-built imagery mosaic.

Making the Migration from Avenue to VBA

Unlike the Arc Avenue environment, the system code of existing buttons, tools, and menu commands is not available for direct use by the programmer. While the buttons, tools, and menu commands are accessible by executing their function, the system code is compiled and can not be viewed in order to learn how to write in the VBA programming environment. This represents a dramatic departure from the common method of learning Avenue. An even greater departure from Arc Avenue, is the need for variable declaration in VBA. This will probably be the single greatest hurdle that an ex-Avenue programmer will face in the migration process. In Avenue, variable declaration was implicitly defined by the use of objects belonging to a particular DocGui Interface (i.e., View, Layout, Table, etc.). Similarly, object references in ArcGIS 8.1 inherit a specific set of methods depending on the type of interface implemented. An interface in VBA consists of a group of methods and properties. If one interface inherits from another, then all of the methods and properties in the parent are directly available in the inheriting object. When one considers the enormity of the COM-based object model of ArcGIS and the resulting multi-level arrays of available interfaces, variable declaration in VBA can be an over-whelming task. An example of the significance of variable declaration and the subtleties of implementing the correct interface is shown in the example below.


In both parts of this example, sample code for zooming the view extent to the bounds of a given feature data layer is examined. On the left, the code example shows a functional sub-routine that zooms the ArcMap view window to the map extent of the first layer in the map's legend. On the right, the non-functional correlate has substituted the variable pMap for pActiveView. This may appear to be a valid substitution since the object reference to pMap had been previously assigned to the variable, pActiveView. The reason that this substitution does not work is due to the fact that by implementing the IActiveView interface via the Set statement, the methods, Extent and Refresh, are possible with regard to the visible view window display.

Admittedly, it is extremely difficult to gain proficiency with the intricacies of implementing the various interfaces available for the manipulation of ArcMap objects in VBA. It follows that for some, there is validity in continuing the use of Avenue-based applications in ArcView 3.x. Nevertheless, Arc Avenue and Visual Basic are both object oriented programming languages (object.request), and hence, the migration process is somewhat facilitated. Furthermore, the extensive Arc Objects library provides a tremendous array of ArcGIS functionality via application specific Visual Basic (VBA for ArcInfo). Ex-Avenue programmers will quickly realize the compactness of attaching code to form events, rather than creating dozens of individual Avenue scripts. Additionally, VBA forms possess a much higher degree of customizability than that of the dialogs that could be created via the ArcView Dialog Designer. It is clearly evident as to why existing Avenue script can not be, and will never be able to be, simply ported over to VBA.



Conclusions

The intent of this paper, from its inception, has been to serve as a reference guide for entities wishing to achieve a fully functional G.I.S.; designed and implemented in-house. Governmental agencies have been conceived as the ideal target audience due to the significant time investment required for such a program's progressive development. It is further hoped that through the inclusion of multiple detailed appendices, experienced users will have the tools necessary to customize ArcGIS to an appreciable extent; making the complete migration to the new coding environment. Clearly, Esri has developed ArcGIS with the primary goal of making their software readily expandable and customizable. There is a tremendous potential for growth in G.I.S. functionality, and fortunately for this author, the City of Coconut Creek has been extremely progressive minded and has encouraged its in-house development. The City is currently 2 years into its G.I.S. commitment and estimated to be 2 years away from possessing a cutting edge, enterprise-wide geographic information system.


Appendices

Appendix I : Example from the Existing Documented Inventory of All Property Parcels within the Legal Boundaries of the City of Coconut Creek

Appendix II : Programmatic Flowchart Representing GUI Development in Avenue

Appendix III : Avenue Code Examples

Appendix IV : Programmatic Flowchart Representing GUI Development in VBA

Appendix V : Example Illustration Showing the On-Screen Usage of the VBA GUI

Appendix VI : VBA Correlate to Appendix III Code Examples



Appendix I: Example from the Existing Documented Inventory of All Property Parcels within the Legal Boundaries of the City of Coconut Creek



NOTE: To obtain a high-quality image, please e-mail your request to Kbrown@creekgov.net






Appendix II: Programmatic Flowchart Representing GUI Development in Avenue


NOTE: To obtain a high-quality image, please e-mail your request to Kbrown@creekgov.net




Appendix III: Avenue Code Examples





If (_CityComm <> nil) then
ControlList = _CityComm.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_CityComm.Close
End
'Run the script which executes the "update script" of the specified dialogs
Av.Run("GUI.Update",nil)
'Initialize global variables
_ParcelAnnoList = {}
_WaterAnnoList = {}
_SewerAnnoList = {}
_DrnAnnoList = {}
_ThemeList = {}
_myView = av.GetProject.FindDoc("Data Layers")
I=0
'Populate lists corresponding to theme categories
For Each t in _myView.GetThemes
If (I<7) Then _ParcelAnnoList.Add(t)
'ElseIf (I<10) Then _WaterAnnoList.Add(t)
'ElseIf (I<12) Then _SewerAnnoList.Add(t)
'ElseIf (I<14) Then _DrnAnnoList.Add(t)

End
I=I+1
I=I+1>End
'If this is the intial running of GUI.Set, set the value of the globals corresponding to theme definitions
If (_AnnoTheme = nil) Then
_AnnoTheme = _myView.GetThemes.Get(7)
_MajRoadTheme = _myView.GetThemes.Get(8)
_StreetTheme = _myView.GetThemes.Get(9)
_PSZoneTheme = _myView.GetThemes.Get(10)
_PSSubZoneTheme = _myView.GetThemes.Get(11)
_PlatTheme = _myView.GetThemes.Get(12)
_PlatBndTheme = _myView.GetThemes.Get(13)
_DrnStructTheme = _myView.GetThemes.Get(14)
_PumpStatTheme = _myView.GetThemes.Get(15)
_WaterStructTheme = _myView.GetThemes.Get(16)
_WaterTheme = _myView.GetThemes.Get(17)
_SewerStructTheme = _myView.GetThemes.Get(18)
_SewerTheme = _myView.GetThemes.Get(19)
_DrnTheme = _myView.GetThemes.Get(20)
_LakeTheme = _myView.GetThemes.Get(21)
_BldgTheme = _myView.GetThemes.Get(22)
_PaveTheme = _myView.GetThemes.Get(23)
_ROWTheme = _myView.GetThemes.Get(24)
_BasemapTheme = _myView.GetThemes.Get(25)
_CitiesTheme = _myView.GetThemes.Get(26)
_PropTheme = _myView.GetThemes.Get(27)
_CityLUTheme = _myView.GetThemes.Get(28)
_LUTheme = _myView.GetThemes.Get(29)
_FloodTheme = _myView.GetThemes.Get(33)
_theDisplay = _myView.GetDisplay

'Set globals corresponding to major dialogs
_HelpBox = av.FindDialog("Help1")
_HelpString = _HelpBox.FindByName("HelpString")
_PrintHelpBox = av.FindDialog("PrintHelper")
_HelpStringP = _PrintHelpBox.FindByName("HelpStringP")
_Results = av.FindDialog("Results2")
_Tools = Av.FindDialog("Tools")
_LegendEd = Av.FindDialog("LegendEd")
_Identify = AV.FindDialog("Identify")
_OwnerSearch = AV.FindDialog("OwnerSearch")
End
_CheckList = {}
_RadioList = {}

'Batch populate the globals corresponding to the legend dialog elements (check boxes and radio buttons)
For each i in 0..12
Item1 = "Theme"+i.AsString
If (i<8) Then _CheckList.Add(_LegendEd.FindByName(Item1)) End
Item2 = Item1+"Radio"
_RadioList.Add(_LegendEd.FindByName(Item2))
End
_Plot = av.FindDialog("Plot2")
_PrintConfirm = av.FindDialog("PrintConfirm")

'Define lists by which to batch assign theme visibility of activeness
_ThemeList = {_WaterStructTheme,_WaterTheme,_SewerStructTheme,
_SewerTheme,_DrnTheme,_DrnStructTheme,_BasemapTheme,
_PropTheme,_LakeTheme,_BldgTheme,_PaveTheme,_ROWTheme}
_DevServThemeList = {_PlatBndTheme,_BasemapTheme,_PropTheme,_LakeTheme,
_BldgTheme,_PaveTheme,_ROWTheme}

'Define globals corresponding to all tables and their fields
If (_theFTab = nil) Then
_theFTab = _PlatTheme.GetFTab
_LUFTab = _LUTheme.GetFTab
_ZFTab = _PSZoneTheme.GetFTab
_FloodTab = _FloodTheme.GetFTab
_Zone = _FloodTab.FindField("Zone")
_Elev = _FloodTab.FindField("Elevation")
_ZType = _FloodTab.FindField("Type")
_SubZTab = _PSSubZoneTheme.GetFTab
MapRoomTable = av.GetProject.FindDoc("PlansRoomList")
_MapRoomVTab = MapRoomTable.GetVTab
BCPATable = av.GetProject.FindDoc("Attributes of ParcelBasemap")
_BCPAVTab = BCPATable.GetVTab
_PlatField = _theFTab.FindField("ParcelName")
_BCPAType = _theFTab.FindField("Type")
_PriorName = _theFTab.FindField("Alias")
_BookPg = _theFTab.FindField("PbPg")
_FolioNo = _theFTab.FindField("Folio#")
_LUCode = _LUFTab.FindField("LU")
_PlatName = _MapRoomVTab.FindField("PLAT NAME")
_ProjName = _MapRoomVTab.FindField("PROJECT NAME")
_BinNo = _MapRoomVTab.FindField("BIN NO#")
_Type = _MapRoomVTab.FindField("TYPE")
_ParcelBasemapID = _BCPAVTab.FindField("ParcelBasemap#")
End

'Define and initialize all selection bitmaps
_Bitmap1 = _ZFTab.GetSelection
_Bitmap2 = _theFTab.GetSelection
_Bitmap3 = _SubZTab.GetSelection
_BCPABitmap = _BCPAVTab.GetSelection
_Bitmap1.ClearAll
_Bitmap2.ClearAll
_Bitmap3.ClearAll
_BCPABitmap.ClearAll

'Get rid of any residual graphics
GraphicSet2 = _PlatTheme.GetGraphics
Graphicset2.SetVisible(FALSE)
GraphicSet2.Empty

'Zoom to the region slightly larger than the extent of the Public Safety Zones polygons
_theDisplay.SetExtent((_PSZoneTheme.ReturnExtent).Scale(1.1))
mlj = 0
for each i in _ThemeList
_ThemeList.Get(mlj).SetVisible(FALSE)
mlj = mlj+1
end
_AnnoTheme.SetVisible(TRUE)
_PSZoneTheme.SetVisible(TRUE)
_PlatTheme.SetActive(TRUE)
_myView.Invalidate
_myView.GetWin.Open
Exists = av.GetProject.FindDoc("FTable")
If (Exists <> nil) then
av.GetProject.RemoveDoc(Exists)
End
FTable = Table.Make(_theFTab)
FTable.SetName("FTable")

'Initialize orientation globals which are used for creating layouts and switching between landscape and portrait
_Orientation1 = "Landscape"
_Orientation2 = "Landscape"
_Dept = "None"

'Prevent the program from promting the user to save the project
AV.GetProject.SetModified(FALSE)







Av.Run("GUI.Update",nil)
'The following code is for the Development Services option initialization
_Bitmap1.ClearAll
_Bitmap2 = _theFTab.GetSelection
_Bitmap2.ClearAll
_theFTab.Refresh
GraphicSet1 = _PlatTheme.GetGraphics
GraphicSet2 = _PSZoneTheme.GetGraphics
GraphicSet1.SetVisible(FALSE)
GraphicSet2.SetVisible(FALSE)
GraphicSet1.Empty
GraphicSet2.Empty
ThemeList = _myView.GetThemes
for each t in ThemeList
t.SetVisible(FALSE)
t.Setactive(FALSE)
end
If (_g <> nil) then
_g.Select
_myView.GetGraphics.ClearSelected
End
_theDisplay.SetExtent((_PSZoneTheme.ReturnExtent).Scale(1.1))
_AnnoTheme.SetVisible(TRUE)
_PSZoneTheme.SetVisible(TRUE)
_PlatTheme.SetActive(TRUE)
_myView.Invalidate
_myView.GetWin.Open
If (_SearchType = nil) Then
_SearchType = av.FindDialog("Search")
_SearchType2 = av.FindDialog("Search2")
_SearchLab = _SearchType.FindByName("SearchLab")
_SearchLab2 = _SearchType2.FindByName("SearchLab")
_PlatChoice = av.FindDialog("PlatChoice")
_PlatSearchList = _PlatChoice.FindByName("PlatSearchList")
_HelpBox2 = av.FindDialog("Help2")
_HelpString2 = _HelpBox2.FindByName("HelpString2")
_ProjList = _Results.FindByName("ProjList")
_ProjLabel = _Results.FindByName("ProjLabel")
_BinList = _Results.FindByName("BinList")
_BinLabel = _Results.FindByName("BinLabel")
_PBLine = _Results.FindByName("PBLine")
_PLine = _Results.FindByName("PLine")
_FolioLine = _Results.FindByName("FolioLine")
_PlotSize = _Plot.FindByName("PlotSize")
_ATTList = _Identify.FindByName("ATTList")
_LastName = _OwnerSearch.FindByName("LastNameInputLine")
_FirstName = _OwnerSearch.FindByName("FirstNameInputLine")
_ResultsButton1 = _Results.FindByName("ViewAsBuilts")
_ResultsButton2 = _Results.FindByName("GenPrint")
_ResultsButton3 = _Results.FindByName("GenPlot")
End
_SearchLab.SetLabel("Please specify the method by which"+NL+
"to select the disired Plat/Parcel:")
_SearchLab2.SetLabel("Please specify the method by which"+NL+
"to select the disired Plat/Parcel:")
_PlotCount = 0



Av.Run("GUI.Update",nil)
_ListMe = {}
myValueminus = ""

'Examine each record of the city parcels coverage and add each unique record to a list
For each REC in _theFTab
myValue = _theFTab.ReturnValue(_PlatField,REC)
If (REC > 1) then myValueminus = _theFTab.ReturnValue(_PlatField,REC-1) End
If (myValue <> nil) then
If (myValue <> "") then
If (myValue <> myValueMinus) then
_ListMe.Add(myValue)
End
End
End
End

'Remove duplicate records, populate the dialog's scrolling listbox, and sort the records prior to display
_ListMe.RemoveDuplicates
_PlatSearchList.DefineFromList(_ListMe)
_PlatSearchList.SortAscending(FALSE)
ControlList = _SearchType.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_SearchType.Close
_SearchType2.Close
ControlList = _PlatChoice.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_PlatChoice.Open




Av.Run("GUI.Update",nil)
ControlList = _HelpBox2.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_HelpBox2.Close

'Initialize variables
_myList = {}
_herList = {}
PBList = {}
_ZoneLabels = {}
If ((av.GetSymbolWin.GetPanel = #SYMBOLWIN_PANEL_COLOR).not) then
av.GetSymbolWin.SetPanel(#SYMBOLWIN_PANEL_FONT)
End
ControlList = _PlatChoice.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_PlatChoice.Close

'Get the users choice from the Platname selection List Box
it = _PlatSearchList.GetSelection For each x in it
'Set the global variable to flag if the parcelname contains "plat" so as to avoid "plat plat" later when creating dialog title
_Suffix = x.AsString.Contains("PLAT")
'Format and concatenate query string
theText = x.Quote
BeginString = "([ParcelName] = "
EndString = ")"
theQuery = (BeginString+theText+EndString)
_theFTab.Query(theQuery.AsString,_Bitmap2,#VTAB_SELTYPE_NEW)
_theFTab.UpdateSelection
_AnnoTheme.SetVisible(FALSE)

'Zoom to the region slightly larger than that of the selected polygon
r = _PlatTheme.GetSelectedExtent
_theDisplay.ZoomToRect(r.Scale(1.1))

'Turn off all the themes in the legend
TheList = _myView.GetThemes
For each t in TheList
t.SetVisible(FALSE)
End

'If the user got here via the Development Services button choice, display & set activeness of all appropriate themes
If (_Dept = "DevServ") Then
MINE = _DevServThemeList
AList = _MyView.GetActiveThemes
i=0
For each a in AList
AList.Get(i).SetActive(FALSE)
i=i+1
End
MINE.Get(1).SetActive(TRUE)
Else
MINE = _ThemeList
End
For each mlj in MINE
mlj.SetVisible(TRUE)
End
_StreetTheme.SetVisible(FALSE)
_PlatBndTheme.SetVisible(TRUE)
_PSZoneTheme.SetVisible(FALSE)
_PlotCount = 0
_Loop = 0

'Return values of particular fields from the selected record for population of "Results" Dialog elements
For each ENTRY in _MapRoomVTab
Proji = _MapRoomVTab.ReturnValue(_ProjName,ENTRY)
Plati = _MapRoomVTab.ReturnValue(_PlatName,ENTRY)
Bini = _MapRoomVTab.ReturnValue(_BinNo,ENTRY)

'If the parcelname record (x) is found as an entry in the "MapRoom" table, then add the project names and bin numbers to the lists
If (x = Plati) then
_myList.Add(Proji)
_herList.Add(Bini)
_Loop = _Loop+1
End
End

'If there were no matches in the "maproom" table, populate the projects scrolling list box with a default message
If (_myList.Count = 0) then
ProjError = "There is no match for the selected Plat name!"
BinError = "None"
_myList.Add(ProjError)
_herList.Add(BinError)
End

'Match the selected the selected record to the source table and retrieve that records values for all targeted attribute fields
For each REC in _theFTab
Projx = _theFTab.ReturnValue(_PlatField,REC)
If (x = Projx) then
_FNo = _theFTab.returnValue(_FolioNo,REC)
_PN = _theFTab.returnValue(_PriorName,REC)
_Type = _theFTab.returnValue(_BCPAType,REC)
PbPg = _theFTab.ReturnValue(_BookPg,REC).AsString
_PBList = PbPg.AsTokens(".")
End
End
_ProjList.DefineFromList(_myList)
_BinList.DefineFromList(_herList)
_FolioLine.SetText(_FNo)

'Only populate the Plat Book & Page if the selected record was indeed a recorded plat
If (_Type <> "RECORDED PLAT") then
_PBLine.SetText("N/A")
_PLine.Settext("N/A")
Else
_PBLine.SetText(_PBList.Get(0))
_PLine.Settext(_PBList.Get(1))
END
If (_Type = "RECORDED PLAT") then _Type = "PLAT" end

'Trim the word "Plat" from the parcelname if part of the parcelname. This avoids "Plat Plat" when concatenating the "Results" dialog title
_PolyPlat = x
If (_Suffix = TRUE) then
TrimMe = _PolyPlat.Trim
theCount = TrimMe.Count
_PolyPlatNew = TrimMe.Left(theCount-4)
Else
_PolyPlatNew = _PolyPlat
End

'Concatenate the "Results" dialog title depending on the classification of the selected polygon (i.e., Plat, Roadway, Site Plan, etc.)
If (_PN <> _PolyPlat) Then
_Results.SetTitle("You have chosen the"++_PolyPlatNew++_Type++"("+_PN+")")
ElseIf (_Type = "ROADWAY") Then
_Results.SetTitle("You have chosen "++_PolyplatNew)
Else
_Results.SetTitle("You have chosen the"++_PolyPlatNew++_Type)
End
End

'Select each Public Safety Zone and get the extent as a Rectangle and store each in a list
ExtentsList = {}
For each i in 0..5
_Bitmap1 = _ZFTab.GetSelection
Zone = i+1
Beginning = "([Zone] = "
theEnd = ")"
theQuery = Beginning+Zone.AsString+theEnd
_ZFTab.Query(theQuery.AsString,_Bitmap1,#VTAB_SELTYPE_NEW)
ExtentsList.Add(_PSZoneTheme.GetSelectedExtent)
End

'Use the previously determined selected Plat extent (r) to find Rect in the list of PSZone Rects that intersect. ' Pass this Zone index to the SELECT script
step = 1
For each i in ExtentsList
If (i.intersects(r)) then
_RefZone = step
End
step = step+1
End
_Flag = "LimitedResults"
_Results.Open
_Tools.Open

'Do not show the legend if the user got here via the Development Services button
If (_Dept = "DevServ") Then
MINE = _DevServThemeList
AList = _MyView.GetActiveThemes
i=0
For each a in AList
AList.Get(i).SetActive(FALSE)
i=i+1
End
MINE.Get(1).SetActive(TRUE)
Else

'Prior to showing the legend editor dialog set the initial values for all check box elelments
For each MonaLisa in 0..7
If (MonaLisa=3) Then _CheckList.Get(MonaLisa).SetSelected(FALSE)
ElseIf (MonaLisa=5) Then _CheckList.Get(MonaLisa).SetSelected(FALSE)
Else _CheckList.Get(MonaLisa).SetSelected(TRUE)
End
End
_LegendEd.Open
Av.Run("GUI.ThemeActivate",nil)
End
Av.Run("GUI.ThemeSelect",nil)






Av.Run("GUI.Update",nil)
'If the checkbox is checked, uncheck it when the user clicks it…otherwise, check the unchecked box
_CheckList.Get(0).SetSelected(_CheckList.Get(0).IsSelected.NOT)
Av.Run("GUI.ThemeSelect",nil)




Av.Run("GUI.Update",nil)
_ParcelAnnoList.Get(1).SetVisible(TRUE)
_ThemeList.Get(14).SetVisible(TRUE)

'Set layer visibility depending on the users selection in the Legend Editor dialog
If (_CheckList.Get(0).IsSelected) then _PlatBndTheme.SetVisible(TRUE)
Else _PlatBndTheme.SetVisible(FALSE)
End
If (_CheckList.Get(1).IsSelected) then
_ThemeList.Get(0).SetVisible(TRUE)
_ThemeList.Get(2).SetVisible(TRUE)
_ThemeList.Get(3).SetVisible(TRUE)
_ThemeList.Get(4).SetVisible(TRUE)
For Each Babe in _WaterAnnoList
Babe.SetVisible(TRUE)
End
Else
_ThemeList.Get(0).SetVisible(FALSE)
_ThemeList.Get(2).SetVisible(FALSE)
_ThemeList.Get(3).SetVisible(FALSE)
_ThemeList.Get(4).SetVisible(FALSE)
For Each Babe in _WaterAnnoList
Babe.SetVisible(FALSE)
End
End
If (_CheckList.Get(2).IsSelected) then
_ThemeList.Get(1).SetVisible(TRUE)
_ThemeList.Get(5).SetVisible(TRUE)
_ThemeList.Get(6).SetVisible(TRUE)
For each Babe in _SewerAnnoList
Babe.SetVisible(TRUE)
End
Else
_ThemeList.Get(1).SetVisible(FALSE)
_ThemeList.Get(5).SetVisible(FALSE)
_ThemeList.Get(6).SetVisible(FALSE)
For each Babe in _SewerAnnoList
Babe.SetVisible(FALSE)
End
End
If (_CheckList.Get(3).IsSelected) then
_ThemeList.Get(7).SetVisible(TRUE)
_ThemeList.Get(8).SetVisible(TRUE)
For each Item in _DrnAnnoList
Item.SetVisible(TRUE)
End
Else
_ThemeList.Get(7).SetVisible(FALSE)
_ThemeList.Get(8).SetVisible(FALSE)
For each Item in _DrnAnnoList
Item.SetVisible(FALSE)
End
End
If (_CheckList.Get(4).IsSelected) then
_ThemeList.Get(9).SetVisible(TRUE)
_ThemeList.Get(10).SetVisible(TRUE)
Else
_ThemeList.Get(9).SetVisible(FALSE)
_ThemeList.Get(10).SetVisible(FALSE)
End
If (_CheckList.Get(5).IsSelected) then
For each Item in _ParcelAnnoList
Item.SetVisible(TRUE)
End
Else
For each Item in 0..6
If (Item<>1) Then _ParcelAnnoList.Get(Item).SetVisible(FALSE) End
End
End
If (_CheckList.Get(6).IsSelected) then _ThemeList.Get(12).SetVisible(TRUE)
Else _ThemeList.Get(12).SetVisible(FALSE)
End
If (_CheckList.Get(7).IsSelected) then _ThemeList.Get(13).SetVisible(TRUE)
Else _ThemeList.Get(13).SetVisible(FALSE)
End

'Redraw the View frame
_theDisplay.Invalidate(TRUE)



'Get the user's choice of either Portrait or Landscape
_Orientation2 = _PlotSize.GetSelection)
'If the user did not change the current orientation (default set to "landscape" is GUI.Set.ave), clean-up and close the dialog
If (_Orientation1 = _Orientation2) then
ControlList = _Plot.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_Plot.Close
d = _PlotLayout)

'System code for print task
If (0 <= Printer.The.Edit({d.GetName})) then
av.ShowMsg("Printing "+d.GetName+"...")
av.UseWaitCursor
System.RefreshWindows
d.Print
av.ShowMsg("")
End
Else)

'If the user did change the current orientation, change the current layout, redraw, and prompt for printing again
_Orientation1 = _Orientation2
Av.Run("GUI.PlotLS&P",nil)
End




Av.Run("GUI.Update",nil)
'Concatenate Layout title string
If (_PN <> "") Then
TitleData = _Polyplat++_Type++"("+_PN+")"
Else
TitleData = _Polyplat++_Type
End
If (_Orientation1 = _Orientation2) then
If (_Orientation2 = "Landscape") then)

'If there is a Layout already created for landscape orientation, delete it so a new one can be created with the same name
Exists = av.GetProject.FindDoc("Data Layers (LS)")
If (Exists <> nil) then
av.GetProject.RemoveDoc(Exists)
End)

'Select existing Layout Template for landscape orientation and use it to create a new Layout
_PlotLayout = Layout.Make
_PlotLayout.Setname("Data Layers (LS)")
PlotList = TemplateMgr.GetTemplates
Temp = PlotList.get(5)
_PlotLayout.UseTemplate(Temp)
_NewView = av.GetProject.FindDoc("Data Layers (LS)")
NewDisplay = _NewView.GetDisplay)

'Set the graphic containing the dynamically concatenated title to the specified location on the Layout window
GT1 = GraphicText.Make(TitleData,749@760.5)
_PlotSize.DefineFromList({"Landscape","Profile"})
Else
Exists = av.GetProject.FindDoc("Data Layers (Profile)")
If (Exists <> nil) then
av.GetProject.RemoveDoc(Exists)
End
_PlotLayout = Layout.Make
_PlotLayout.Setname("Data Layers (Profile)")
PlotList = TemplateMgr.GetTemplates
Temp = PlotList.get(6)
_PlotLayout.UseTemplate(Temp)
_NewView = av.GetProject.FindDoc("Data Layers (Profile)")
NewDisplay = _NewView.GetDisplay
GT1 = GraphicText.Make(TitleData,748.5@765.0)
_PlotSize.DefineFromList({"Profile","Landscape"})
End)

'Draw the new layout in a window with the specified screen position and window size
tList = _PlotLayout.GetGraphics
tList.AddName(GT1)
tList.Draw
tList.Invalidate
theViewFrame = tList.FindByName("ViewFrame1")
theViewFrame.SetView(_myView,FALSE)
_NewView.GetWin.Resize(575,400)
_NewView.GetWin.MoveTo(235,46)
_NewView.GetWin.Open
tList.Draw
_Plot.Open
Else
If (_NewView <> nil) then
_NewView.GetWin.Close
End
End)




Av.Run("GUI.Update",nil)
MINE = {}
ControlList = _SearchType.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_SearchType.Close
_SearchType2.Close

'Open the default ArcView "locate address" dialog box
p = LocateDialog.Show(_StreetTheme)
If (p <> NIL) Then
If (p.IsNull) Then
MsgBox.Info("Cannot locate address.", "Locate")
Else
TheList = _myView.GetThemes
For each t in TheList
t.SetVisible(FALSE)
End

'Set theme visibility differently for Engineering and development services
If (_Dept = "DevServ") Then
MINE = _DevServThemeList
AList = _MyView.GetActiveThemes
i=0
For each a in AList
AList.Get(i).SetActive(FALSE)
i=i+1
End
MINE.Get(1).SetActive(TRUE)
Else
MINE = _ThemeList
End
For each mlj in MINE
mlj.SetVisible(TRUE)
End
_StreetTheme.SetVisible(FALSE)

'Utilize the default ArcView address matching capability
UserInput = LocateDialog.GetLastAddress
Address = _BCPAVTab.FindField("Address_li")
Beginning = "([Address_li] = "
QuotedInput = UserInput.Quote
Ending = ")"
Query = (Beginning+QuotedInput+Ending)

'Create a new query based on concatenated query string
BoolVal = _BCPAVTab.Query(Query,_BCPABitMap,#VTAB_SELTYPE_NEW)
_BCPAVtab.UpdateSelection
r = Rect.MakeEmpty
If (_BasemapTheme.CanSelect) Then
r = r.UnionWith(_BasemapTheme.GetSelectedExtent)
End

'If the record is not found in the parcelbasemap (City has only 20% of the city mapped in county parcel basemap) then
' zoom in to the graphic, otherwise zoom to the selected parcelbasemap polygon

If (_BCPAVTab.GetNumSelRecords = 0) Then
proj = _myView.GetProjection
_p = p.ReturnProjected(proj)
_g = GraphicShape.Make(_p)
_myView.GetGraphics.Add(_g)
ext = _theDisplay.ReturnExtent
r = _g.GetBounds
_theDisplay.ZoomToRect(r.Scale(1.5))
If (not(_p.IsContainedIn(_theDisplay.ReturnExtent))) Then
_theDisplay.PanTo(_p)
return nil
End
ElseIf ( r.ReturnSize = (0@0) ) Then
_MyView.GetDisplay.PanTo(r.ReturnOrigin)
Else
proj = _myView.GetProjection
_p = p.ReturnProjected(proj)
_MyView.GetDisplay.SetExtent(r.Scale(15.1))
End

'Set global flags to pass on info regarding how user got to other parts of the GUI and how to display or not display related dialogs
_Method = "ADDRESS"
_Flag = "LimitedResults"
_WaterLevel = "Not Flooded"
av.run("GUI.Results",nil)
End
End




Av.Run("GUI.Update",nil)
'Clean-up dialogs and set the text of labels and button captions if the Flood Zone button had been selected by the user
If (_WaterLevel <> "Flooded") Then
ControlList = _HelpBox2.FindByClass(Control)
For Each C in ControlList
C.SetObjectTag(nil)
End
_HelpBox2.Close
Else
_ProjLabel.SetLabel("Flood Zone Query Results")
_BinLabel.SetLabel("Elevation Certificates:")
_ResultsButton1.SetLabel("Flood Control History")
_ResultsButton1.SetClick("GUI.Flood1")
_ResultsButton2.SetLabel("Emergency Management")
_ResultsButton2.SetClick("GUI.Flood2")
_ResultsButton3.SetLabel("SFWMD Geographic Features")
_ResultsButton3.SetClick("GUI.Flood3")
End
_myList = {}
_herList = {}
_RecNoList2 = {}
PBList = {}
Zone = ""
Elev = 0
ZType = ""
found = FALSE
If (_Method = "LOCATION") Then
_p = _theDisplay.ReturnUserPoint
End
If (_PlatTheme.CanFindByPoint) Then
keys = _PlatTheme.FindByPoint(_p)
If (Keys.Count = 0) Then
_MyList.Add("No Plat Found...")
_HerList.Add("")
If (_WaterLevel = "Flooded") Then
_myList = {}
locks = _FloodTheme.FindByPoint(_p)
For Each lock in locks
Zone = _FloodTab.ReturnValue(_Zone,lock)
Elev = _FloodTab.ReturnValue(_Elev,lock)
ZType = _FloodTab.ReturnValue(_ZType,lock)
End
If (Zone = "") Then
MsgBox.Info("Please re-try using the city zone ""CK""","ERROR!")
Else
_myList.Add("Flood Zone:"++Zone)
If (Elev = 0) Then _myList.Add("Elevation: N/A")
Else _myList.Add("Elevation:"++Elev.AsString)
End
_myList.Add("Flood Zone Type:"++ZType)
End
End
_Results.SetTitle("The chosen address does not fall within a recorded plat boundary")
_FolioLine.SetText("")
_PBLine.SetText("")
_PLine.Settext("")
_ProjList.DefineFromList(_myList)
_BinList.DefineFromList(_herList)
_Results.Open
End
For each key in keys
_Polyplat = _theFTab.ReturnValue(_PlatField,key)
PbPg = _theFTab.returnValue(_BookPg,key).AsString
_PBList = PbPg.AsTokens(".")
_FNo = _theFTab.returnValue(_FolioNo,key)
_PN = _theFTab.returnValue(_PriorName,key)
_Type = _theFTab.returnValue(_BCPAType,key)
_Loop = 0
for each ENTRY in _MapRoomVTab
Proji = _MapRoomVTab.ReturnValue(_ProjName,ENTRY)
Plati = _MapRoomVTab.ReturnValue(_PlatName,ENTRY)
Bini = _MapRoomVTab.ReturnValue(_BinNo,ENTRY)

'MsgBox.Report(_Polyplat+NL+Plati,"")
if (_Polyplat = Plati) then
_myList.Add(Proji)
_herList.Add(Bini)
_Loop = _Loop+1
end
end
If (_myList.Count = 0) then
ProjError = "There are no listed projects! Double click to zoom-in..."
BinError = "None"
_myList.Add(ProjError)
_herList.Add(BinError)
end
If (_WaterLevel = "Flooded") Then
_myList = {}
_herList = {}
locks = _FloodTheme.FindByPoint(_p)
For Each lock in locks
Zone = _FloodTab.ReturnValue(_Zone,lock)
Elev = _FloodTab.ReturnValue(_Elev,lock)
ZType = _FloodTab.ReturnValue(_ZType,lock)
End
_myList.Add("Flood Zone:"++Zone)
If (Elev = 0) Then _myList.Add("Elevation: N/A")
Else _myList.Add("Elevation:"++Elev.AsString)
End
_myList.Add("Flood Zone Type:"++ZType)
For Each droplet in _ElevationCertVTab
Flood1 = _ElevationCertVTab.ReturnValue(_FloodedPlat,droplet)
Flood2 = _ElevationCertVTab.ReturnValue(_FloodedAddress,droplet)
If (_PolyPlat = Flood1) Then
_herList.Add(Flood2.AsString)
_RecNoList2.Add(droplet.AsString)
End
End
End
_ProjList.DefineFromList(_myList)
_BinList.DefineFromList(_herList)
_FolioLine.SetText(_FNo)
If (_Type <> "RECORDED PLAT") then
_PBLine.SetText("N/A")
_PLine.Settext("N/A")
Else
_PBLine.SetText(_PBList.Get(0))
_PLine.Settext(_PBList.Get(1))
End
_Suffix = _PolyPLat.Contains("PLAT")
If (_Suffix = TRUE) then
TrimMe = _PolyPlat.Trim
theCount = TrimMe.Count
_PolyPlatNew = TrimMe.Left(theCount-4)
Else
_PolyPlatNew = _PolyPlat
End
If (_Type = "RECORDED PLAT") Then _Type = "PLAT" End
If (_PN <> _PolyPlat) Then
_Results.SetTitle("You have chosen the"++_PolyplatNew++_Type++"("+_PN+")")
ElseIf (_Type = "ROADWAY") Then
_Results.SetTitle("You have chosen "++_PolyplatNew)
Else
_Results.SetTitle("You have chosen the"++_PolyplatNew++_Type)
End
_Results.Open
If (_Dept = "DevServ") Then
MINE = _DevServThemeList
AList = _MyView.GetActiveThemes
i=0
For each a in AList
AList.Get(i).SetActive(FALSE)
i=i+1
End
MINE.Get(1).SetActive(TRUE)
Else
For each MonaLisa in 0..7
If (MonaLisa=3) Then _CheckList.Get(MonaLisa).SetSelected(FALSE)
ElseIf (MonaLisa=5) Then _CheckList.Get(MonaLisa).SetSelected(FALSE)
Else _CheckList.Get(MonaLisa).SetSelected(TRUE)
End
End
End
End
End
If (not found) then
System.Beep
end
If (_Method = "ADDRESS") Then
If (_Dept <> "DevServ") Then
_LegendEd.Open
AV.Run("GUI.ThemeSelect",Nil)
End
_Tools.Open
End
If (_Method = "LOCATION") Then
_Tools.Open
End





Appendix IV: Programmatic Flowchart Representing GUI Development in VBA


NOTE: To obtain a high-quality image, please e-mail your request to Kbrown@creekgov.net




Appendix V: Example Illustration Showing the On-Screen Usage of the VBA GUI



NOTE: To obtain a high-quality image, please e-mail your request to Kbrown@creekgov.net




Appendix VI: VBA Correlate to Appendix III Code Examples






Option Explicit
'By declaring these varaibles as Public at the module level, they will be available in all scripts within this document
Public pApp As IApplication
Public pMxApp As IMxApplication
Public pDoc As IMxDocument
Public pMap As IMap
Public pActiveView As IActiveView
Public pPageLayout As IPageLayout
Public pPage As IPage
Public pPageSetUp As IPageSetupDialog
Public pItem As ICommandItem
Public m_pEditor As IEditor
Public pPolygon As IPolygon
Public pPoint As IPoint
Public pEnv As IEnvelope
Public pFeat As IFeature
Public pFeatClass As IFeatureClass
Public pFeatLyrZone As IGeoFeatureLayer, pFeatLyrParcel As IGeoFeatureLayer, _
pFeatLyrWaterStr As IGeoFeatureLayer, pFeatLyrSewerStr As IGeoFeatureLayer, _
pFeatLyrDrainStr As IGeoFeatureLayer, pFeatLyrWater As IGeoFeatureLayer, _
pFeatLyrSewer As IGeoFeatureLayer, pFeatLyrDrain As IGeoFeatureLayer, _
pFeatLyrBuild As IGeoFeatureLayer, pFeatLyrBasemap As IGeoFeatureLayer, _
pFeatLyrEmptyParcel As IGeoFeatureLayer, pFeatLyr1SID As ILayer, _
pFeatLyr2SID As ILayer, pFeatLyrStreetCL As IGeoFeatureLayer, _
pFeatLyrWaterNstr As IGeoFeatureLayer, pFeatLyrWaterSstr As IGeoFeatureLayer
Public pTable As ITable
Public pTableSort As ITableSort
Public pTrackCancel As EsriCore.ITrackCancel
Public pSortedCursor As ICursor
Public pRowBuff As IRowBuffer
Public pQFilt As IQueryFilter
Public pCursor As ICursor
Public pRow As IRow
Public pFeatCursor As IFeatureCursor
Public pFeatSel As IFeatureSelection
Public pEnumFeat As IEnumFeature
Public pGxDialog As IGxDialog
Public pGxObjEnum As IEnumGxObject
Public pFile As IGxObject
Public pSpatialFilter As ISpatialFilter
Public pFillSymbol As ISimpleFillSymbol
Public pSym As ISymbol
Public pFeatConvert As IFeatureDataConverter
Public pGraphicsContainer As IGraphicsContainer

'Required reference to a system DLL (Windows NT and 2000) in order to retrieve user's log-on name
Public Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Long) As Long
____________________________________________________________________________________________________________________________________________________________________________
Sub RunGUI()

'RunGUI is the VBA Macro that initiates the execution of the GUI. Set the object reference to the property that returns each data layer in the legend
Set pDoc = ThisDocument
Set pApp = Application
Set pFeatLyrZone = pDoc.FocusMap.Layer(0)
Set pFeatLyrParcel = pDoc.FocusMap.Layer(1)
Set pFeatLyrWaterStr = pDoc.FocusMap.Layer(2)
Set pFeatLyrSewerStr = pDoc.FocusMap.Layer(3)
Set pFeatLyrDrainStr = pDoc.FocusMap.Layer(4)
Set pFeatLyrWater = pDoc.FocusMap.Layer(5)
Set pFeatLyrSewer = pDoc.FocusMap.Layer(6)
Set pFeatLyrDrain = pDoc.FocusMap.Layer(7)
Set pFeatLyrBuild = pDoc.FocusMap.Layer(8)
Set pFeatLyrBasemap = pDoc.FocusMap.Layer(9)
Set pFeatLyrEmptyParcel = pDoc.FocusMap.Layer(10)
Set pFeatLyr1SID = pDoc.FocusMap.Layer(11)
Set pFeatLyr2SID = pDoc.FocusMap.Layer(12)
Set pFeatLyrStreetCL = pDoc.FocusMap.Layer(13)
Set pFeatLyrWaterNstr = pDoc.FocusMap.Layer(14)
Set pFeatLyrWaterSstr = pDoc.FocusMap.Layer(15)
pFeatLyrZone.Visible = True
pFeatLyrParcel.Visible = False
pFeatLyrWaterStr.Visible = False
pFeatLyrSewerStr.Visible = False
pFeatLyrDrainStr.Visible = False
pFeatLyrWater.Visible = False
pFeatLyrSewer.Visible = False
pFeatLyrDrain.Visible = False
pFeatLyrBuild.Visible = False
pFeatLyrBasemap.Visible = False
pFeatLyrEmptyParcel.Visible = False
pFeatLyr1SID.Visible = False
pFeatLyr2SID.Visible = False
pFeatLyrStreetCL.Visible = False

'Assures that the View window is shown in the display (as oppossed to a layout window)
Set pItem = pApp.Document.CommandBars.Find(ArcID.View_Geographic)
pItem.Execute
Set pMap = pDoc.FocusMap
Set pActiveView = pMap

'AreaOfInterest property returns the spatial-referenced extent of the first layer in the legend
pActiveView.Extent = pMap.Layer(0).AreaOfInterest
pActiveView.Refresh

'Set the text for the text that appears when the user briefly holds the mouse pointer over a control without clicking
UandEMenu.InfrastructureButton.ControlTipText = "View Water, Sewer, Paving, Grading, and Drainage Info"
UandEMenu.FloodZonesButton.ControlTipText = "Obtain Floodzone Info for a Specific Address"
UandEMenu.ArcPadUploadButton.ControlTipText = "Upload Mobile GIS Data by Authorized Users"
Results.AsBuilts.ControlTipText = "View As-Builts for the Selected Parcel"
Results.PrintMap.ControlTipText = "Print the Current Map Display Exactly as Shown"
LegendEditor.ParcelBndLayer.ControlTipText = "Toggle All Parcel Boundaries ON/OFF"
LegendEditor.WaterLayers.ControlTipText = "Toggle All Water Features ON/OFF"
LegendEditor.SewerLayers.ControlTipText = "Toggle All Sewer Features ON/OFF"
LegendEditor.DrainLayers.ControlTipText = "Toggle All Drainage Features ON/OFF"
LegendEditor.APLayers.ControlTipText = "Toggle All Aerial Photography ON/OFF"
Tools.ZoomWindow.ControlTipText = "Zoom to Window"
Tools.PanNW.ControlTipText = "Pan the Current Map NW"
Tools.PanN.ControlTipText = "Pan the Current Map N"
Tools.PanNE.ControlTipText = "Pan the Current Map NE"
Tools.ZoomIn.ControlTipText = "Zoom In"
Tools.MeasureMe.ControlTipText = "Measure Tool"
Tools.PanW.ControlTipText = "Pan the Current Map W"
Tools.ZoomFullExtent.ControlTipText = "Zoom to Full Extent"
Tools.PanE.ControlTipText = "Pan the Current Map E"
Tools.ZoomOut.ControlTipText = "Zoom Out"
Tools.Information.ControlTipText = "Attribute Retieval Tool"
Tools.PanSW.ControlTipText = "Pan the Current Map SW"
Tools.PanS.ControlTipText = "Pan the Current Map S"
Tools.PanSE.ControlTipText = "Pan the Current Map SE"
Tools.ZoomPrevious.ControlTipText = "Zoom to Previous Extent"

'Display the main menu form
MainMenu.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Public Function UpdateScale(ScaleValue As Double)

'Declare function as Public so as to make it available to all of the GUI's sub-routines
Dim TheScale As Double
Dim TheScaleStr As String
Dim ScaleArray As Variant

'Obtain the current View map scale of the View and return this Public function's value to the calling sub-routine
TheScale = pDoc.ActiveView.FocusMap.MapScale
TheScaleStr = Str(TheScale)

'Split the real number into 2 parts: before decimal and after decimal
ScaleArray = Split(TheScaleStr, ".")
'Extract the number before the decimal point to get the approximate value for the ratio (1:?)
ScaleValue = ScaleArray(0)
End Function
____________________________________________________________________________________________________________________________________________________________________________
Public Function GetBounds(Xmin As Double, Xmax As Double, Ymin As Double, Ymax As Double)

'Get the current View extent and return the coordinates of this rectangle to the calling sub-routine
Set pEnv = pDoc.ActiveView.Extent
Xmin = pEnv.Xmin
Xmax = pEnv.Xmax
Ymin = pEnv.Ymin
Ymax = pEnv.Ymax
End Function
____________________________________________________________________________________________________________________________________________________________________________
Public Sub FormOpener()
LegendEditor.ParcelBndLayer.Value = 1
LegendEditor.WaterLayers.Value = 1
LegendEditor.SewerLayers.Value = 1
LegendEditor.DrainLayers.Value = 0
LegendEditor.APLayers.Value = 0

'Set layer visibility to agree with initial LegendEditor settings
pFeatLyrZone.Visible = False
pFeatLyrParcel.Visible = False
pFeatLyrWaterStr.Visible = True
pFeatLyrSewerStr.Visible = True
pFeatLyrDrainStr.Visible = False
pFeatLyrWater.Visible = True
pFeatLyrSewer.Visible = True
pFeatLyrDrain.Visible = False
pFeatLyrBuild.Visible = True
pFeatLyrBasemap.Visible = True
pFeatLyrEmptyParcel.Visible = True
pFeatLyrStreetCL.Visible = False

'Position & open all forms
UandEMenu.Move 0, 0
LegendEditor.Move 0, 252
LegendEditor.Show
Results.Move 146.25, 0
Results.Show
Tools.Move 640.5, 0
Tools.Show
End Sub




Private Sub AddressButton_Click()
ParcelSearch.Hide

'Populate the default text for the 2 textboxes of the AddressQuery form
AddressQuery.StreetBox.Text = "4800 W Copans Rd"
AddressQuery.ZoneBox.Text = "CK"
AddressQuery.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub LocationButton_Click()
Dim Start As Double

'Close the Search form and call the routine to animate the bubble image while the form waits for the user
ParcelSearch.Hide
Call Bubbles("GO")
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Public Sub ParcelNameButton_Click()
Dim i As Long
Dim FieldIndex As Long
Dim ParcelCollection As New Collection

'Get the index of the fields we are interested in (parcelname)
Set pFeatClass = pFeatLyrParcel.FeatureClass
Set pTable = pFeatClass
FieldIndex = pTable.FindField("PARCELNAME")

'Sort the Table based on THE field
Set pTableSort = New TableSort
Set pTrackCancel = New EsriCore.CancelTracker
Set pTableSort.Table = pTable
pTableSort.Fields = "PARCELNAME"
pTableSort.Ascending("PARCELNAME") = True
pTableSort.Sort pTrackCancel

'Set cursor to increment through the sorted table, one row at a time
Set pSortedCursor = pTableSort.Rows
Set pRowBuff = pSortedCursor.NextRow

'Loop through the table and create a collection of values for the THE field
Do While Not pRowBuff Is Nothing
ParcelCollection.Add pRowBuff.Value(FieldIndex)
Set pRowBuff = pSortedCursor.NextRow
Loop
ParcelSelect.ParcelListBox.Clear

'Populate the listbox with the collection of sorted values while removing duplicate values (result is a sorted list of unique values)
For i = 1 To ParcelCollection.Count
If i = 1 Then
ParcelSelect.ParcelListBox.AddItem (ParcelCollection.Item(i))
ElseIf ParcelCollection.Item(i) <> ParcelCollection.Item(i - 1) Then
ParcelSelect.ParcelListBox.AddItem (ParcelCollection.Item(i))
End If
Next

'Searching by feature is MUCH slower and this code does NOT sort FieldIndex = pFeatClass.FindField("PARCELNAME")
'For i = 1 To pFeatClass.FeatureCount(Nothing)
' Set pFeat = pFeatClass.GetFeature(i)
'Next i

ParcelSearch.Hide
ParcelSelect.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Public Sub Bubbles(Command As String)
Dim Start As Double
Dim FormInt As Integer

'Use a timer derived from the system clock to count seconds
Start = 0
Start = Timer

'Method for for yielding execution so that the operating system can process other events
'(i.e. returns control to Sub "Location Button_Click to execute request "ParcelSearch.Hide" & "ParcelSelect.Show")

FormInt = DoEvents
GuideBot1.Show

'Ensure that the increment is only evaluated in whole seconds by using integer equivalants
'Difference between the current time as an integer and the start time as an integer

Diff = Int(Timer) - Int(Start)
Do While Command <> "STOP"

'Gives focus to Sub "GuideBot1.OKButton_Click to stop the animation by executing the request "GuideBot1.Hide")
FormInt = DoEvents
If (Diff > 4) Then
Diff = Int(Diff - 4)
End If

'Concatenat the file path and file name depending on the integer time interval
If (Diff = 0) Then
File = ("G:\Gis\ArcInfo\VB-VBA\Images\bubble" & Format(Diff + 1) & ".gif")
GuideBot1.BubbleImage.Picture = LoadPicture(File)
GuideBot1.Repaint
ElseIf (Diff = 1) Then
File = ("G:\Gis\ArcInfo\VB-VBA\Images\bubble" & Format(Diff + 1) & ".gif")
GuideBot1.BubbleImage.Picture = LoadPicture(File)
GuideBot1.Repaint
ElseIf (Diff = 2) Then
File = ("G:\Gis\ArcInfo\VB-VBA\Images\bubble" & Format(Diff + 1) & ".gif")
GuideBot1.BubbleImage.Picture = LoadPicture(File)
GuideBot1.Repaint
ElseIf (Diff = 3) Then
File = ("G:\Gis\ArcInfo\VB-VBA\Images\bubble" & Format(Diff + 1) & ".gif")
GuideBot1.BubbleImage.Picture = LoadPicture(File)
GuideBot1.Repaint
ElseIf (Diff = 4) Then
File = ("G:\Gis\ArcInfo\VB-VBA\Images\bubble1.gif")
GuideBot1.BubbleImage.Picture = LoadPicture(File)
GuideBot1.Repaint
End If
Diff = Int(Timer) - Int(Start)

'Only animate the bubble image for up to 9 seconds...if the user hasn't responded, he/she is probably dead
If (Diff = 9) Then
Command = "STOP"
End If
Loop
End Sub







'Declare the variable used locally, that is returned from an external function
Dim ScaleValue As Double
____________________________________________________________________________________________________________________________________________________________________________
Private Sub ParcelListBox_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim pEnv As IEnvelope
Dim TheString As String
Dim pFIDs As IEnumIDs
Dim CompositeCollection As New Collection
Dim ParcelType As String
Dim Alias As String
Dim ParcelName As String

'Close the Select form and clear any residual selected records
ParcelSelect.Hide
Set pItem = pApp.Document.CommandBars.Find(ArcID.Query_ClearSelection())
pItem.Execute

'Concatenate new query string using the user's selection from the parcelname scrolling listbox
Set pQFilt = New QueryFilter
pQFilt.WhereClause = "PARCELNAME = " + "'" + ParcelListBox.Text + "'"

'Set the Parcel layer as the FeatureSelection and the use the Query Filter object to select the feature(s), making it part of ArcMap's feature selection
Set pFeatSel = pFeatLyrParcel
pFeatSel.SelectFeatures pQFilt, EsriSelectionResultNew, False
pDoc.ActiveView.Refresh

'Zoom to the extent of the selected record and change the current tool to the Identify Feature Tool
Set pItem = pApp.Document.CommandBars.Find(ArcID.Query_ZoomToSelected()
pItem.Execute

Set pItem = pApp.Document.CommandBars.Find(ArcID.Query_Identify())
pItem.Execute
Set pMap = pDoc.FocusMap
Results.ResultsList.Clear

'Loop through each of the selected features and retieve the values
Set pEnumFeat = pMap.FeatureSelection
Set pFeat = pEnumFeat.Next
ParcelName = pFeat.Value(pFeat.Fields.FindField("PARCELNAME"))
ParcelType = pFeat.Value(pFeat.Fields.FindField("TYPE"))
Alias = pFeat.Value(pFeat.Fields.FindField("ALIAS"))
Set pFeat = pEnumFeat.Next

'Conditionally concatenate the text to be shown in the ResultsList textbox of the Results form
If ParcelType = "ROADWAY" Then
CompositeCollection.Add ("You have chosen " + ParcelName)
ElseIf ParcelType = "RECORDED PLAT" Then
ParcelName = Replace(ParcelName, "PLAT", "")
CompositeCollection.Add ("You have chosen the " + ParcelName + " PLAT")
Else
Alias = Replace(Alias, "PLAT", "")
CompositeCollection.Add ("You have chosen the " + ParcelName + " " + ParcelType + " (" + Alias + " PLAT" + ")")
End If
Results.ResultsList.AddItem (CompositeCollection.Item(1))

'Get the scale of the View AFTER zooming to the selected parcel and update the ScaleBox Textbox
Call UpdateScale(ScaleValue)
Results.ScaleBox.Text = ScaleValue

'Set all layer visibility and position & open all required forms Set the LegendEditor checkboxes to be selected (prior to opening) if the layers are going to be visible
Call FormOpener
End Sub




Private Sub APLayers_Click()
'If the user checks the checkbox (Value = -1 = checkbox is selected)...
If LegendEditor.APLayers.Value = -1 Then
pFeatLyr1SID.Visible = True
pFeatLyr2SID.Visible = True
pDoc.ActiveView.Refresh
'If the user unchecks the checkbox (Value = 0)...
Else
pFeatLyr1SID.Visible = False
pFeatLyr2SID.Visible = True
pDoc.ActiveView.Refresh
End If
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub DrainLayers_Click()
If LegendEditor.DrainLayers.Value = -1 Then
pFeatLyrDrainStr.Visible = True
pFeatLyrDrain.Visible = True
pDoc.ActiveView.Refresh
Else
pFeatLyrDrainStr.Visible = False
pFeatLyrDrain.Visible = False
pDoc.ActiveView.Refresh
End If
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub ParcelBndLayer_Click()
If LegendEditor.ParcelBndLayer.Value = -1 Then
pFeatLyrEmptyParcel.Visible = True
pDoc.ActiveView.Refresh
Else
pFeatLyrEmptyParcel.Visible = False
pDoc.ActiveView.Refresh
End If
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub SewerLayers_Click()
If LegendEditor.SewerLayers.Value = -1 Then
pFeatLyrSewerStr.Visible = True
pFeatLyrSewer.Visible = True
pDoc.ActiveView.Refresh
Else
pFeatLyrSewerStr.Visible = False
pFeatLyrSewer.Visible = False
pDoc.ActiveView.Refresh
End If
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub ViewDrainageStructs_Click()
DrainageStructs.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub ViewSewerStructs_Click()
SewerStructs.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub ViewWaterStructs_Click()
WaterStructs.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub WaterLayers_Click()
If LegendEditor.WaterLayers.Value = -1 Then
pFeatLyrWaterStr.Visible = True
pFeatLyrWater.Visible = True
pDoc.ActiveView.Refresh
Else
pFeatLyrWaterStr.Visible = False
pFeatLyrWater.Visible = False
pDoc.ActiveView.Refresh
End If
End Sub



Private Sub PrintButton_Click()
'Print the layout as per the user's input in the previously displayed page set-up dialog
Set pItem = pApp.Document.CommandBars.Find(ArcID.File_Print)
pItem.Execute

'Close the Print button form
PrintMe.Hide
End Sub




'Declare the variable used locally, that is returned from an external function
Dim ScaleValue As Double
____________________________________________________________________________________________________________________________________________________________________________
Private Sub OKButton_Click()
Dim theStreet As String
Dim theZone As String

'Get the user's input from the 2 textboxes
theStreet = StreetBox.Text
theZone = ZoneBox.Text
AddressQuery.Hide

'Pass the values representing the user's input the internal function which performs the address matching routine
Call GetAddress(theStreet, theZone)
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Function GetAddress(theStreet As String, theZone As String)
Dim i As Long
Dim pLM As ILocatorManager
Dim pLW As ILocatorWorkspace
Dim pLocator As ILocator
Dim pAddressCandidates As IAddressCandidates
Dim pAddressPropertySet As IPropertySet
Dim pCandidatePropertySet As IPropertySet
Dim pArray As IArray
Dim pFields As IFields
Dim ShapeFieldName As String
Dim pGeometry As IGeometry
Dim pDocDefaultSymbols As IDocumentDefaultSymbols
Dim pElement As IElement
Dim pGraphicsContainer As IGraphicsContainer
Dim pMarkerElement As IMarkerElement
Dim pArea As IArea
Set pLM = New LocatorManager

' Get the path to the directory where the locater is found
Set pLW = pLM.GetLocatorWorkspaceFromPath("Z:\")
' Retrieve a Locator (also known as a Geocoding Service: in this case an ArcView 3.x shape file)
Set pLocator = pLW.GetLocator("streets2.mxs")
' MsgBox pLocator.Description
Set pAddressCandidates = pLocator
' get the candidate fields for the geocoding service
Set pFields = pAddressCandidates.CandidateFields
For i = 0 To (pFields.FieldCount - 1)
If pFields.Field(i).Type = EsriFieldTypeGeometry Then
ShapeFieldName = pFields.Field(i).name
End If
Next i

' get candidates for an address
Set pAddressPropertySet = New PropertySet
With pAddressPropertySet
.SetProperty "Street", theStreet
.SetProperty "Zone", theZone
End With

' Use the address referenced by pAddressPropertySet to create an array of address matches
Set pArray = pAddressCandidates.FindAddressCandidates(pAddressPropertySet)
'Select the best match candidate (listed first in the array of matches)
Set pCandidatePropertySet = pArray.Element(0)
Set pGeometry = pCandidatePropertySet.GetProperty(ShapeFieldName)

'If Not pGeometry.IsEmpty Then
' MsgBox ShapeFieldName
'End If

Set pDocDefaultSymbols = pDoc
Set pMarkerElement = New EsriCore.MarkerElement

'The following line doesn't work...but it should
'Set pMarkerElement.Symbol = pDocDefaultSymbols.MarkerSymbol

Set pElement = pMarkerElement
pElement.Geometry = pGeometry
Set pGraphicsContainer = pActiveView.GraphicsContainer
pGraphicsContainer.AddElement pElement, 0

'pActiveView.PartialRefresh EsriViewGraphics, Nothing, pActiveView.Extent
'Zoom to graphic

Set pEnv = pGeometry.Envelope.Envelope
Set pArea = pEnv
Set pEnv = pActiveView.Extent

'Zoom the current display and then pan the center of the display to the graphic location
pEnv.Expand 0.05, 0.05, True
pEnv.CenterAt pArea.Centroid
pActiveView.Extent = pEnv

'Set all layer visibility and position & open all required forms. Set the LegendEditor checkboxes to be selected (prior to opening) if the layers are going to be visible
Call FormOpener
'Show linework of Geocoding Service
pFeatLyrStreetCL.Visible = True
pActiveView.Refresh

'Select a city parcels polygon featureby point graphic location
Set pMap = pDoc.FocusMap
Set pPoint = pArea.Centroid
pMap.SelectByShape pPoint, Nothing, False
Results.ResultsList.Clear

'Loop through each of the selected features and retieve the values
Set pEnumFeat = pMap.FeatureSelection
Set pFeat = pEnumFeat.Next
ParcelName = pFeat.Value(pFeat.Fields.FindField("PARCELNAME"))
ParcelType = pFeat.Value(pFeat.Fields.FindField("TYPE"))
Alias = pFeat.Value(pFeat.Fields.FindField("ALIAS"))
Set pFeat = pEnumFeat.Next

'Conditionally concatenate the text to be shown in the ResultsList textbox of the Results form
If ParcelType = "ROADWAY" Then
CompositeCollection.Add ("You have chosen " + ParcelName)
ElseIf ParcelType = "RECORDED PLAT" Then
ParcelName = Replace(ParcelName, "PLAT", "")
CompositeCollection.Add ("You have chosen the " + ParcelName + " PLAT")
Else
Alias = Replace(Alias, "PLAT", "")
CompositeCollection.Add ("You have chosen the " + ParcelName + " " + ParcelType + " (" + Alias + " PLAT" + ")")
End If
Results.ResultsList.AddItem (CompositeCollection.Item(1))

'Update the new View extent in the scale textbox of the Results form
Call UpdateScale(ScaleValue)
Results.ScaleBox.Text = ScaleValue
Set pItem = pApp.Document.CommandBars.Find(ArcID.Query_ClearSelection())
pItem.Execute
End Function




Private Sub AsBuilts_Click()
Dim FolioArray
Dim ParcelType As String
Dim Alias As String
Dim ParcelName As String
Dim FileBrowser As Boolean
If PrintMe.Visible = True Then
PrintMe.Hide
End If
'Ensure that the current display window shows a View (as opposed to a Layout)
Set pItem = pApp.Document.CommandBars.Find(ArcID.View_Geographic)
pItem.Execute
'Get the still selected parcel chosen by the user and obtain the values of the particular fields
Set pMap = pDoc.FocusMap
Set pEnumFeat = pMap.FeatureSelection
Set pFeat = pEnumFeat.Next
CommonDir = "Z:\ScannedFiles\"
FolioStr = pFeat.Value(pFeat.Fields.FindField("FOLIO_"))
ParcelName = pFeat.Value(pFeat.Fields.FindField("PARCELNAME"))
ParcelType = pFeat.Value(pFeat.Fields.FindField("TYPE"))
Alias = pFeat.Value(pFeat.Fields.FindField("ALIAS"))
'Concatenate the path in which to find the scanned as-builts associated with the selected parcel
If FolioStr <> "" Then
FolioArray = Split(FolioStr, "-")
theStr = "S" & Right(FolioArray(0), 2) & "4" & Left(FolioArray(0), 1) & "4" & Mid(FolioArray(0), 2, 1)
End If
'Strip-out any characters that may interfere with "theStr" being a valid pathname
ParcelDirStr = Replace(ParcelName, " ", "")
AliasDirStr = Replace(Alias, " ", "")
ParcelDirStr = Replace(ParcelDirStr, """", "")
AliasDirStr = Replace(AliasDirStr, """", "")
ParcelDirStr = Replace(ParcelDirStr, "/", ",")
AliasDirStr = Replace(AliasDirStr, "/", "")
ParcelDirStr = Replace(ParcelDirStr, "'", "")
AliasDirStr = Replace(AliasDirStr, "'", "")
ParcelDirStr = Replace(ParcelDirStr, ".", "")
AliasDirStr = Replace(AliasDirStr, ".", "")
'Conditionally complete the scanned file directory path depending on whether the parcel is a plat, site-plan, or roadway
If ParcelName = Alias Then
MainDir = CommonDir & theStr & "\" & ParcelDirStr
If ParcelType = "ROADWAY" Then
MainDir = CommonDir & "RoadwayProjects\" & ParcelDirStr
End If
Else
MainDir = CommonDir & theStr & "\" & AliasDirStr & "\" & ParcelDirStr
End If
'Implement the file browser dialog that is contained within the ArcCatalog object model
Set FS = CreateObject("Scripting.FileSystemObject")
If FS.FolderExists(MainDir) Then
Set pGxDialog = New GxDialog
'pGxDialog.AllowMultiSelect = False
pGxDialog.StartingLocation = MainDir
pGxDialog.Title = "Please Select an Existing Drawing to View..."
pGxDialog.ButtonCaption = "ViewMe!"
'pGxObjEnum will contain all files selected by the user
FileBrowser = pGxDialog.DoModalOpen(0, pGxObjEnum)
Set pFile = pGxObjEnum.Next
'pGxObj.BaseName 'Returns the filename If a selection has been successfully made by the user, split the file name at the "." and examine the file extension
If FileBrowser = True Then
FileExtArray = Split(pFile.name, ".")
FileExt = FileExtArray(1)
FileStr = pFile.FullName 'Returns the full pathname
'View the selected file with the default NT image viewer program if it is a TIFF file, use Wordpad if it is a TXT file
If FileExt = "tif" Then
OpenMe = "C:\Program Files\Windows NT\Accessories\ImageVue\Wangimg.exe" & " " & FileStr
ElseIf FileExt = "txt" Then
OpenMe = "C:\Program Files\Windows NT\Accessories\WordPad.exe" & " " & FileStr
End If
'Open the viewing program in a maximized state
Shell OpenMe, vbMaximizedFocus
Else: End If
Else
Text = MainDir & " does NOT exist!"
MsgBox (Text)
End If
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub FeatureQueryButton_Click()
If PrintMe.Visible = True Then
PrintMe.Hide
End If
Set pItem = pApp.Document.CommandBars.Find(ArcID.View_Geographic)
pItem.Execute
'Initialize the form elements to contain no text
FeatureQuery.HydrantBox.Text = ""
FeatureQuery.LSBox.Text = ""
FeatureQuery.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub PrintMap_Click()
'Open the page set-up dialog in order to get the user's desired printer, page size, and orientation PRIOR to creating the layout
Set pItem = pApp.Document.CommandBars.Find(ArcID.PageLayout_PageSetUp)
pItem.Execute
'Switch the current display to be a Layout
Set pItem = pApp.Document.CommandBars.Find(ArcID.View_LayoutView)
pItem.Execute
'Provide a form by which the user can send the print job
PrintMe.Show
End Sub
____________________________________________________________________________________________________________________________________________________________________________
Private Sub ScaleBox_AfterUpdate()
If PrintMe.Visible = True Then
PrintMe.Hide
End If
Set pItem = pApp.Document.CommandBars.Find(ArcID.View_Geographic)
pItem.Execute
'When the user changes the numerical value of the scalebox, redraw the View at the user-defined scale
NewScale = Results.ScaleBox.Text
pDoc.ActiveView.FocusMap.MapScale = NewScale
pDoc.ActiveView.Refresh
End Sub

Ken E. Brown
G.I.S. Coordinator
City of Coconut Creek
4800 W. Copans Road
Coconut Creek, FL, 33063
Kbrown@creekgov.net
(954) 956-1461
(954) 956-1424 (Fax)

Brij M. Garg, P.E., DEE
Utilities & Engineering Director
City of Coconut Creek