' Name: Projector! ' ' Headline: Allows user to project themes from one projection ' to another, using any projections ArcView supports. User must ' know the input and output projection and units. ' ' Self: ' ' Returns: ' ' Description: Projects active fthemes in current view to ' new shape files in any projection that ArcView supports, ' projecting into units of feet, meters or decimal degrees. ' The user must know the units (and projection) of the input ' theme(s), and will be asked for the output units and projection. ' ' If neither input or output projection is geographic, ' then the user must have 2x the amount of space of the original ' shape file, as this script writes a temporary shapefile in geographic ' coordinates, projects that to the output projection and ' deletes the temporary files (much faster than stepping through records). ' ' Attach this as the click script to a control in a View GUI. ' ' Topics: Conversion, Themes ' ' Search Keys: Project, projections, theme, units, convert ' ' Requires: Fthemes in a view with the map units set, and a ' knowledge of the projection of the themes. '=========================================================== 'check for shift key, if shift key is down pop up instructions 'explain script, pops up a message with 'info about how to use if (System.IsShiftKeyDown) then message = "To use the projection tool you must know the map units and projection"++ "of the datasets being projected. You will be prompted for the output units and projection."+nl+nl+ "Brief Instructions:"+nl+nl+ "1. Add some themes to the view."+nl+nl+ "2. Set the map units appropriately in the View Properties window."+nl+nl+ "3. Make the theme(s) you wish to project active."+nl+nl+ "4. Press this button. You will be prompted for certain information"++ "which may include the input projection, the output units and the"++ "output projection."+nl+nl+ "5. You will be asked if you want to recalculate area, perimeter and length fields."+nl+nl+ "WARNING - If the field to be recalculated is not large enough to hold the new "+ "(calculated) number, the value put in that field will be incorrect."+nl+nl+ "6. You will be asked if you want to add the projected theme(s) to a view."+nl+nl+ "7. You will be asked for output shapefile names for each theme to be projected."+nl msgbox.report(message,"Projector! Instructions") return nil end 'get the active document, which should be a view theView=av.GetActiveDoc if (theView.Is(View).Not) then MsgBox.Error("This script must be run from a view. Exiting","Error") return nil end 'Get the current source units and make sure they are not unknown sourceunits = av.getactivedoc.getdisplay.getunits if (sourceunits = #UNITS_LINEAR_UNKNOWN) then MsgBox.Error("View units must be set before projecting. Stopping.", "Error!") return nil end 'build a list of fthemes from the active theme list, we will project these thms=List.Make for each t in theView.GetActiveThemes if (t.Is(Ftheme)) then thms.Add(t) end end 'if no themes active let the user know and quit if (thms.Count = 0) then System.Beep MsgBox.Error("Please make at least one feature theme active!","Error") return nil end 'Get the projection of the view myprj=av.getactivedoc.getprojection 'Try to figure out if the source data is geographic ' If our Prj.AsString <> "" then we have a projection and we are ' geographic, or if our sourceunits are set to decimal degrees without ' a projection we are too inputgeographic =((myprj.AsString <> "") or ((sourceunits = #UNITS_LINEAR_DEGREES) and (myprj.AsString = ""))) 'If not, then let user pick input and output if (inputgeographic.Not) then Msgbox.Info("Please select the input projection"++ "in the next dialog box","Projector!") 'Pop up dialog box, to get input projection 'and check for cancel button (nil) inputPrj = ProjectionDialog.Show(theView,sourceunits) if (inputPrj.IsNull) then return nil end 'Pop up dialog box, to get output projection 'and check for cancel button (nil) else 'your input projection is geographic sourceunits = #UNITS_LINEAR_DEGREES end unitslist1 = {"meters","feet","decimal degrees","miles","kilometers","yards", "centimeters","inches","millimeters"} unitslist2 = {#UNITS_LINEAR_METERS, #UNITS_LINEAR_FEET, #UNITS_LINEAR_DEGREES, #UNITS_LINEAR_MILES, #UNITS_LINEAR_KILOMETERS, #UNITS_LINEAR_YARDS, #UNITS_LINEAR_CENTIMETERS, #UNITS_LINEAR_INCHES, #UNITS_LINEAR_MILLIMETERS} outputunits = MsgBox.ChoiceAsString(unitslist1, "Please pick output units","Projector!") if (outputunits = nil) then return nil else outunits = unitslist2.Get(unitslist1.FindByValue(outputunits)) end 'get the output projection, using the dialog box and check for cancel (nil) if (outputunits = "decimal degrees") then outputPrj = prj.MakeNull outputPrj.SetDescription("Geographic") outputgeographic = true else outputPrj = ProjectionDialog.Show(theView,outunits) end if (outputPrj = nil) then return nil end 'check to see if they are the same. If so, exit if ((inputgeographic.Not) and ((outputPrj = inputPrj) and (sourceunits = outunits))) then MsgBox.Error("Input projection same as output projection.","Error") return nil end 'check to see if output projection is geographic. If it is, we won't need 'to do as much work below outputgeographic = outputPrj.ReturnDescription.Contains("Geographic") 'if both input and output are geographic, quit here if (inputgeographic and outputgeographic) then MsgBox.Error("Both input and output are geographic. Stopping.","Error") return nil end 'check to see if we want to recalculate area, perimeter, length fields recalc = Msgbox.YesNo("Recalculate area, perimeter and length fields"++ "(if present) using"++outputunits+"?","Projector!",true) 'check to see if we want to put results into a view if (MsgBox.YesNo("Add projected shapefile(s) as theme(s) to a view?", "Projector!",true)) then 'make a list of views viewlist = List.Make for each d in av.GetProject.GetDocs if (d.Is(View)) then viewlist.Add(d) end end 'for each d 'provide a choice for a new view viewlist.Add("") AddToView = MsgBox.ListAsString(viewlist,"Add Theme to:", "Projector!") if (AddToView <> nil) then if (AddToView = "") then AddToView = View.Make AddToView.GetWin.Open end end else 'don't add to view AddtoView = nil end 'step through each active theme For each thm in thms 'get a filename for the new shapefile defname = Filename.GetCWD.MakeTmp("theme","shp") outputfile = FileDialog.Put(defname,"*.shp","Project "+thm.GetName) 'if Canceled, then skip this theme if (outputfile = nil) then continue end 'now export the ftab (selected records only), thmftab = thm.GetFtab shapetype = thmftab.FindField("Shape").GetType if (outputgeographic) then newFtab = thmFtab.ExportUnprojected(outputfile,inputPrj, thmFtab.GetSelection.Count >0) elseif (inputgeographic) then newFtab = thmFtab.ExportProjected(outputfile,outputPrj, thmFtab.GetSelection.Count > 0) else 'need to go to geographic, then to something else 'make a temporary shape file tempshape = Filename.GetCWD.MakeTmp("xxprj","shp") tempftab = thmFtab.ExportUnprojected(tempshape, inputPrj,thmFtab.GetSelection.Count >0) newFtab = tempFtab.ExportProjected(outputfile,outputPrj,false) 'now clean up tempftab.DeActivate tempftab = nil av.PurgeObjects tempshpname = tempshape.GetBaseName.AsTokens(".").Get(0) tempshpdir = tempshape.GetFullName.Clone.AsFilename tempshpdir.Stripfile filesToDelete = tempshpdir.Readfiles(tempshpname+".*") for each f in filesToDelete File.Delete(f) end end 'recalculate area, perim, length fields if asked to if (recalc) then 'find the fields we need to recalculate newareafield = newftab.Findfield("Area") newperimfield = newftab.Findfield("Perimeter") newlengthfield = newftab.Findfield("Length") newftab.SetEditable(True) if (shapetype = #FIELD_SHAPEPOLY) then if (newareafield <> nil) then newftab.Calculate("[Shape].ReturnArea",newareafield) end if (newperimfield <> nil) then newftab.Calculate("[Shape].ReturnLength",newperimfield) end elseif (shapetype = #FIELD_SHAPELINE) then if (newlengthfield <> nil) then newftab.Calculate("[Shape].ReturnLength",newlengthfield) end end newftab.SetEditable(false) end 'if recalc if (addtoView <> nil) then 'create a theme and add it to the specifiedView fthm = FTheme.Make(newFTab) AddToView.AddTheme(fthm) 'put this theme in the same order as it was in the original view newplace = AddtoView.GetThemes.Count AddToView.GetThemes.Shuffle(fthm,newplace) end end 'for each thm if (addtoView <> nil) then 'if view units aren't set, then set them if (AddtoView.GetDisplay.GetUnits = #UNITS_LINEAR_UNKNOWN) then AddtoView.GetDisplay.SetUnits(outunits) end 'bring the View to the front AddToView.InvalidateTOC(nil) AddToView.GetWin.Activate end