' Name: View.AddGenerate ' File: gen2shp.ave ' ' Title: Import GENERATE format files ' ' Topics: GeoData ' ' Description: Reads a user specified ARC/INFO GENERATE format ' file and converts the data to the appropriate feature type ' (either Point, Line or Polygon) to be saved to a user specified ' shapefile, creates the theme and adds it to the active View. ' ' Various graphic types can be used as input. The input file ' format is the ARC/INFO GENERATE format with some extensions: ' ' For points (standard ARC/INFO GENERATE format): ' ID, X, Y ' ID, X, Y ' END ' ' For lines (standard ARC/INFO GENERATE format): ' ID ' X, Y ' X, Y ' END ' ID ' X, Y ' X, Y ' END ' END ' ' For polygons (standard ARC/INFO GENERATE format): ' ID, X, Y ' X, Y ' X, Y ' X, Y ' END ' ID, X, Y ' X, Y ' X, Y ' X, Y ' END ' END ' ' For unclosed polygons or to force the closure of lines (non-standard format): ' CLOSE ' ID ' X, Y ' X, Y ' X, Y ' END ' ID ' X, Y ' X, Y ' X, Y ' END ' END ' ' For rectangles (standard ARC/INFO GENERATE format): ' ID, BottomLeftX, BottomLeftY, TopRightX, TopRightY ' ID, BottomLeftX, BottomLeftY, TopRightX, TopRightY ' END ' ' For rectangles defined by a box (non-standard format): ' BOX ' ID, BottomLeftX, BottomLeftY, Width, Height ' ID, BottomLeftX, BottomLeftY, Width, Height ' END ' ' For circles (standard ARC/INFO GENERATE format): ' ID, CenterX, CenterY, Radius ' ID, CenterX, CenterY, Radius ' END ' ' For donuts (non-standard format): ' DONUT ' ID, CenterX, CenterY, InnerRadius, OuterRadius ' ID, CenterX, CenterY, InnerRadius, OuterRadius ' END ' ' ' Notes: ' 1. Full support of multi-part line and polygon shapes. ' 2. Unclosed polygons can automaticaly be closed by inserting ' the word CLOSE on the first line (record) of the input file. ' 3. Labelpoints for polygons are optional; if present they are ' ignored. ' 4. A file with polygons without labelpoints will be recognised ' as a line feature file. Use CLOSE to force the creation of ' polygons instead of lines. ' 5. Input files may 'loosely' follow the GENERATE format; ' besides semicolons and spaces, tabs can be used as delimiters ' and extra spaces are allowed. ' 6. This script should be associated with the Click property of ' a button on the View DocGUI. ' 7. The amount of checking for a valid input file once the ' feature type has been determined is minimal. ' ' Requires: A View must be the active document. ' ' Self: ' ' Returns: ' ' Author : Ron Wardenier ( warden@cistron.nl ) ' Version : 3.1 ' Date : August 26 1998 ' More info : http://warden.www.cistron.nl/geo/ ' ' Modified by Tim Thomas ' Sept 1, 2004 ' View should be the Active Document theView = av.GetActiveDoc ' Set output precision ' Prompt the user for a data file... ' Open an ASCII line file importFileFN = FileDialog.Show("*.*","Text File (*.*)","Add Theme from GENERATE format ASCII file") if (importFileFN = nil) then exit end importFile = LineFile.Make(importFileFN, #FILE_PERM_READ) ' Read the first record of the input file, replace tabs by a space and remove extra spaces buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim if ((importFile.IsAtEnd) or (buffer = nil)) then MsgBox.Error("Empty input file."+NL+"Halting conversion.", "") exit end NumRecs = importFile.GetSize Type = "" ' Check first record for a special graphic tag if(buffer = "CLOSE") then type = "PolygonClose" InfoMsg = "Save polygon(s) as Polygon feature shapefile (with automatic closure)" else if(buffer = "BOX") then type = "RectangleBox" InfoMsg = "Save rectangle(s) as Polygon feature shapefile" else if(buffer = "DONUT") then type = "Donut" InfoMsg = "Save donut(s) as Polygon feature shapefile" end end end if (Type <> "") then ' Special tag found ' Next check for a legal ID; so read the next record buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim inpTokens = buffer.AsTokens(" ,") if (inpTokens.Get(0).IsNumber.Not) then MsgBox.Error("ID must be numeric."+NL+"Halting conversion.", "Error") exit end else ' No special tag; auto determine type by input file format ' Next check for a legal ID; no need to read the next record inpTokens = buffer.AsTokens(" ,") if (inpTokens.Get(0).IsNumber.Not) then MsgBox.Error("ID must be numeric."+NL+"Halting conversion.", "Error") exit end inpTokens = buffer.AsTokens(" ,") if (inpTokens.Count = 1) then type = "Line" InfoMsg = "Save line(s) as Line feature shapefile" else if (inpTokens.Count = 5) then type = "Rectangle" InfoMsg = "Save rectangle(s) as Polygon feature shapefile" else if (inpTokens.Count = 4) then type = "Circle" InfoMsg = "Save circle(s) as Polygon feature shapefile" else if (inpTokens.Count = 3) then buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim inpTokens = buffer.AsTokens(" ,") if (inpTokens.Count = 3) then type = "Point" InfoMsg = "Save point(s) as Point feature shapefile" else if (inpTokens.Count = 2) then type = "Polygon" InfoMsg = "Save polygon(s) as Polygon feature shapefile" else MsgBox.Error("Unable to determine feature type in input file."+NL+"Halting conversion.", "Error") exit end end else if (inpTokens.Get(1) = "AUTO") then type = "Polygon" InfoMsg = "Save polygon(s) as Polygon feature shapefile" else MsgBox.Error("Unable to determine feature type in input file."+NL+"Halting conversion.", "Error") exit end end end end end end ' Input file is valid (so far anyway) and data type is known tempName = importFileFN.GetBaseName.AsTokens(".").Get(0) tempDir = importFileFN.ReturnDir.AsString defName = FN.Make(tempDir).MakeTmp(tempName, "shp") theShapeFN = FileDialog.Put(defName, "*.shp", InfoMsg) if (theShapeFN = nil) then ' If canceled by user then quit exit end av.ShowMsg("Importing " + importFileFN.GetBaseName + "...") av.ShowStopButton RecCnt = 1 ' Reset file pointer to the beginning of the input file importFile.SetPos(0) ' For performance sake make three separate loops for each shape type if (type = "Point") then ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Point) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theXField = Field.Make("X", #FIELD_FLOAT, 12, 2) theYField = Field.Make("Y", #FIELD_FLOAT, 12, 2) theFTab.AddFields({theIDField, theXField, theYField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") theXField = theFTab.FindField("X") theYField = theFTab.FindField("Y") ' Read next record, replace tabs by a space and remove extra spaces buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0).AsNumber theX = inpTokens.Get(1).AsNumber theY = inpTokens.Get(2).AsNumber thePoint = theX@theY theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, thePoint) theFTab.SetValue(theIDField, theRecord, ID) theFTab.SetValue(theXField, theRecord, theX) theFTab.SetValue(theYField, theRecord, theY) RecCnt = RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if ( proceed.Not ) then av.ClearStatus av.ShowMsg( "Stopped" ) exit end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim end end if (type = "Line") then ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Polyline) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theLengthField = Field.Make("Length", #FIELD_DECIMAL, 13, 3) theFTab.AddFields({theLengthField, theIDField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") theLengthField = theFTab.FindField("Length") pointList = List.Make theLineList = List.Make ' This is the loop which reads the file record-by-record. ' ' There's an outside loop, which reads the record header. The inside loop ' then reads the vertices for the polyline feature. buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(TRUE) ' Terminate outside loop at EOF or upon encountering a second "END" at the end of file if((importFile.IsAtEnd) or (buffer = "END")) then break end ' Every record read by the outside loop should be a record header record. ' It will contain information about the feature (here only the ID). inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0) theLineList = {} buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim RecCnt = RecCnt + 1 ' Now we're ready to loop through the vertices (this is the inside loop) newID=False while(newID=False) pointList = {} while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") thePoint = inpTokens.Get(0).AsNumber@inpTokens.Get(1).AsNumber pointList.Add(thePoint) buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim RecCnt = RecCnt + 1 end theLineList.add(pointList) buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim RecCnt= RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if (proceed.Not) then av.ClearStatus av.ShowMsg("Stopped") exit end inpTokens = buffer.AsTokens(" ,") if (inpTokens.Count = 1) then newID=True end end thePolyLine = PolyLine.Make(theLineList) theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, thePolyLine) theFTab.SetValue(theIDField, theRecord, ID) theFTab.SetValue(theLengthField, theRecord, thePolyLine.ReturnLength) end end if ((type = "Polygon") or (type = "PolygonClose")) then kt=0 ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Polygon) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theFTab.AddFields({theIDField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") pointList = List.Make thePolygonList = List.Make if (type = "PolygonClose") then ' Skip first record (which reads "CLOSE") buffer = importFile.ReadElt end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(TRUE) ' Terminate outside loop at EOF or upon encountering a second "END" at the end of file if((importFile.IsAtEnd) or (buffer = "END")) then break end inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0) thePolygonList = {} pointList = {} if (inpTokens.Count=3) then thePoint = inpTokens.Get(1).AsNumber@inpTokens.Get(2).AsNumber pointList.Add(thePoint) end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim RecCnt = RecCnt + 1 newID=False while(newID=False) while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") thePoint = inpTokens.Get(0).AsNumber@inpTokens.Get(1).AsNumber pointList.Add(thePoint) buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim RecCnt = RecCnt + 1 end thePolygonList.add(pointList) buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim if (buffer = "END") then break end RecCnt = RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if (proceed.Not) then av.ClearStatus av.ShowMsg("Stopped") exit end inpTokens = buffer.AsTokens(" ,") ' MsgBox.Info(((inpTokens.Count = 3) or (inpTokens.Count = 1)).AsString,"") ' MsgBox.Info((inpTokens.Get(0).AsNumber < -99999.1).AsString,"") ' MsgBox.Info(((inpTokens.Get(0).AsNumber > -99998.9) and (inpTokens.Get(0).AsNumber < -9999.1)).AsString,"") ' MsgBox.Info((inpTokens.Get(0).AsNumber > -9998.9).AsString,"") if ((((inpTokens.Count = 3) or (inpTokens.Count = 1)) and ((inpTokens.Get(0).AsNumber < -99999.1) or ((inpTokens.Get(0).AsNumber > -99998.9) and (inpTokens.Get(0).AsNumber < -9999.1)) or (inpTokens.Get(0).AsNumber > -9998.9))) or ((inpTokens.Count = 1) and (type = "PolygonClose")) or ((inpTokens.Count = 2) and (inpTokens.Get(1) = "AUTO"))) then newID=True pointList = {} ' MsgBox.Info("A","") elseif ((((inpTokens.Count = 3) or (inpTokens.Count = 1)) and (((inpTokens.Get(0).AsNumber > -99999.1) and (inpTokens.Get(0).AsNumber < -99998.9)) or ((inpTokens.Get(0).AsNumber > -9999.1)) and (inpTokens.Get(0).AsNumber < -9998.9)))) then pointList = {} thePoint = inpTokens.Get(1).AsNumber@inpTokens.Get(2).AsNumber pointList.Add(thePoint) buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim ' MsgBox.Info("B","") else ' MsgBox.Info("C","") pointList = {} end end thePolygon = Polygon.Make(thePolygonList) kt = kt + 1 theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, thePolygon) theFTab.SetValue(theIDField, theRecord, ID) end end if (type = "Rectangle") then ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Polygon) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theWidthField = Field.Make("Width", #FIELD_DECIMAL, 13, 3) theHeightField = Field.Make("Height", #FIELD_DECIMAL, 13, 3) theAreaField = Field.Make("Area", #FIELD_DECIMAL, 13, 3) theFTab.AddFields({theWidthField, theHeightField, theAreaField, theIDField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") theWidthField = theFTab.FindField("Width") theHeightField = theFTab.FindField("Height") theAreaField = theFTab.FindField("Area") buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0) theRectangle = Rect.MakeXY(inpTokens.Get(1).AsNumber, inpTokens.Get(2).AsNumber, inpTokens.Get(3).AsNumber, inpTokens.Get(4).AsNumber) theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, theRectangle.AsPolygon) theFTab.SetValue(theIDField, theRecord, ID) theFTab.SetValue(theWidthField, theRecord, theRectangle.GetWidth) theFTab.SetValue(theHeightField, theRecord, theRectangle.GetHeight) theFTab.SetValue(theAreaField, theRecord, theRectangle.ReturnArea) RecCnt = RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if ( proceed.Not ) then av.ClearStatus av.ShowMsg("Stopped") exit end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim end end if (type = "RectangleBox") then ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Polygon) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theWidthField = Field.Make("Width", #FIELD_DECIMAL, 13, 3) theHeightField = Field.Make("Height", #FIELD_DECIMAL, 13, 3) theAreaField = Field.Make("Area", #FIELD_DECIMAL, 13, 3) theFTab.AddFields({theWidthField, theHeightField, theAreaField, theIDField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") theWidthField = theFTab.FindField("Width") theHeightField = theFTab.FindField("Height") theAreaField = theFTab.FindField("Area") ' Skip first record (which reads "BOX") buffer = importFile.ReadElt buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0) theBLPoint = inpTokens.Get(1).AsNumber@inpTokens.Get(2).AsNumber theWidth = inpTokens.Get(3).AsNumber ' if there is no value for the height create a square if (inpTokens.Count = 4) then theHeight = theWidth else theHeight = inpTokens.Get(4).AsNumber end theTRPoint = theWidth@theHeight theRectangle = Rect.Make(theBLPoint, theTRPoint) theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, theRectangle.AsPolygon) theFTab.SetValue(theIDField, theRecord, ID) theFTab.SetValue(theWidthField, theRecord, theRectangle.GetWidth) theFTab.SetValue(theHeightField, theRecord, theRectangle.GetHeight) theFTab.SetValue(theAreaField, theRecord, theRectangle.ReturnArea) RecCnt = RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if ( proceed.Not ) then av.ClearStatus av.ShowMsg("Stopped") exit end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim end end if (type = "Circle") then ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Polygon) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theRadiusField = Field.Make("Radius", #FIELD_DECIMAL, 13, 3) theAreaField = Field.Make("Area", #FIELD_DECIMAL, 13, 3) theFTab.AddFields({theRadiusField, theAreaField, theIDField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") theRadiusField = theFTab.FindField("Radius") theAreaField = theFTab.FindField("Area") buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0) theCenter = inpTokens.Get(1).AsNumber@inpTokens.Get(2).AsNumber theRadius = inpTokens.Get(3).AsNumber theCircle = Circle.Make(theCenter, theRadius) theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, theCircle.AsPolygon) theFTab.SetValue(theIDField, theRecord, ID) theFTab.SetValue(theRadiusField, theRecord, theCircle.GetRadius) theFTab.SetValue(theAreaField, theRecord, theCircle.ReturnArea) RecCnt = RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if ( proceed.Not ) then av.ClearStatus av.ShowMsg("Stopped") exit end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim end end if (type = "Donut") then ' Create the FTab for the new shape file... theFTab = FTab.MakeNew(theShapeFN, Polygon) theIDField = Field.Make("ID", #FIELD_DECIMAL, 11, 0) theInnerRadiusField = Field.Make("InnerRadius", #FIELD_DECIMAL, 13, 3) theOuterRadiusField = Field.Make("OuterRadius", #FIELD_DECIMAL, 13, 3) theAreaField = Field.Make("Area", #FIELD_DECIMAL, 13, 3) theFTab.AddFields({theInnerRadiusField, theOuterRadiusField, theAreaField, theIDField}) theShapeField = theFTab.FindField("Shape") theIDField = theFTab.FindField("ID") theInnerRadiusField = theFTab.FindField("InnerRadius") theOuterRadiusField = theFTab.FindField("OuterRadius") theAreaField = theFTab.FindField("Area") ' Skip first record (which reads "DONUT") buffer = importFile.ReadElt buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim while(buffer <> "END") inpTokens = buffer.AsTokens(" ,") ID = inpTokens.Get(0) theCenter = inpTokens.Get(1).AsNumber@inpTokens.Get(2).AsNumber theInnerRadius = inpTokens.Get(3).AsNumber theOuterRadius = inpTokens.Get(4).AsNumber theOuterCircle = Circle.Make(theCenter, theOuterRadius) theInnerCircle = Circle.Make(theCenter, theInnerRadius) theDonut = theOuterCircle.ReturnDifference(theInnerCircle.AsPolygon) theRecord = theFTab.AddRecord theFTab.SetValue(theShapeField, theRecord, theDonut) theFTab.SetValue(theIDField, theRecord, ID) theFTab.SetValue(theInnerRadiusField, theRecord, theInnerRadius) theFTab.SetValue(theOuterRadiusField, theRecord, theOuterRadius) theFTab.SetValue(theAreaField, theRecord, theDonut.ReturnArea) RecCnt = RecCnt + 1 proceed = av.SetStatus((RecCnt / NumRecs) * 100) if ( proceed.Not ) then av.ClearStatus av.ShowMsg("Stopped") exit end buffer = importFile.ReadElt.Substitute(9.AsChar," ").Trim end end av.ClearStatus av.ClearMsg theFTab.Flush importFile.Close ' Create the new Theme NewThemeName = SrcName.Make(theShapeFN.AsString) NewTheme = Theme.Make(NewThemeName) ' Set the Theme name without the extension .shp NewTheme.SetName(theShapeFN.GetBaseName.AsTokens(".").Get(0)) ' Add it to the active View theView.AddTheme(NewTheme) ' Make sure the View is on top theView.GetWin.Activate ' Flag that the Project has been modified av.GetProject.SetModified(True) ' End of script View.AddGenerate