# doqq7.sml # # ############################################################################## # global variables that need declaring ############################################################################## class TEXTSTYLE textstyle, labelstyle; class GRE_GROUP group, mapgroup, indexgroup; class GRE_LAYER_RASTER rastlayer; class GRE_LAYER_VECTOR vectlayer; class GRE_LAYER_MAPGRID gridlayer, neatlayer; class GRE_LAYER_TEXT textlayer; class GRE_LAYER layer; class RECT extents; # Extents of DOQQ in lat/lon # for step 0 class OBJECTINFO layoutObject; raster DOQQ; vector WetlandsVector; string layoutFileName$, layoutObjectName$; string doqqFileName$, doqqObjectName$, doqqObjectDesc$, templateDir$; numeric layoutObjectNumber, doqqObjectNumber; # for steps 1-3 class FILE inFile; string workDir$, name$, prffile$, currentDate$, inFile$, ccs755$; string newname$, oldname$, objname$; numeric numLines; # for step 4 class DATABASE db; class DBTABLEINFO table; numeric photodate, dftcont, dftbright, wantNeatLine, ntokens, contrast, brightness; string photodate$, quadname$, reqfilen$, direct$, a$, imgdate$, maptitle$; class XmSeparator sep; class XmForm br; # for step 5-10 class GRE_LAYOUT layout; class DBTABLEINFO tinfo; # for step 11 class Georef georef; numeric xmin, ymin, xmax, ymax; numeric halfsize, twosec, cx, cy; ############################################################################## # initialize global variables ############################################################################## # This is the map projection we will use everywhere class MAPPROJ projection; projection.System = "United States State Plane 1983"; projection.Zone = "Maryland"; # This is the projection used for clipping class MAPPROJ latlon; latlon.System = "Latitude / Longitude"; latlon.Datum = "North American 1983"; latlon.Ellipsoid = "GRS 1980"; #============================================================================= clear(); ############################################################################## # function to count number of lines in a text file ############################################################################## func CountLines(string fileName$) { class file f; numeric c; string line$; f = fopen(fileName$, "r"); c = 0; line$ = fgetline$(f); while (line$ != "" ) { c = c + 1; line$ = fgetline$(f); } fclose(f); return(c); } ############################################################################## # step 0: # Prompt for Input objects ############################################################################## layoutFileName$ = IniReadString("DOQQSML", "Layout"); layoutObject = SelectInputObject("D2DWIN", "Select the template layout", layoutFileName$); layoutFileName$ = layoutObject.Filename; layoutObjectName$ = layoutObject.Name; layoutObjectNumber = layoutObject.Number; IniWriteString("DOQQSML", "Layout", layoutFileName$); GetInputRaster(DOQQ); GetInputVector(WetlandsVector); doqqFileName$ = DOQQ.$INFO.Filename; doqqObjectName$ = DOQQ.$INFO.Name; doqqObjectDesc$ = DOQQ.$INFO.Desc; doqqObjectNumber = DOQQ.$INFO.Number; IniWriteString("DOQQSML", "DOQQRaster", doqqFileName$); templateDir$ = FileNameGetPath(layoutFileName$); ############################################################################## # step 1: # Prompt for the output *.prf file. Use the directory the user puts this # file into as the "workDir". Prevent it from being the same directory as # the template for sanity's sake. ############################################################################## # XXX The work directory name should be derived from the DOQQ raster # name, but The GetFile dialog won't default to a nonexistant # directory. workDir$ = IniReadString("DOQQSML", "WorkDir"); # PRF file has same name as DOQQ file, but change the "1" to a "5" # example: brand1sw.rvc -> brand5sw.prf name$ = FileNameGetName(doqqFileName$); if (NumberTokens(name$, "1") == 2) { name$ = GetToken(name$, "1", 1) + "5" + GetToken(name$, "1", 2); } prffile$ = workDir$ + "/" + name$ + ".prf"; prffile$ = GetOutputFileName(prffile$, "Select output print file. The layout and other\n" + "files will be placed in this directory as well.", "prf"); workDir$ = FileNameGetPath(prffile$); # Keep the user from puting the workDir in the same place as the # tempDir, as this would be bad. ("I'm a little fuzzy on this whole # good-bad thing.") while (workDir$ == templateDir$) { PopupMessage( "You can't create the new layout in the same directory as\n" + "the template layout. Please choose a different directory." ); prffile$ = GetOutputFileName(prffile$, "Select output print file. The layout and other\n" + "files will be placed in this directory as well.", "prf"); workDir$ = FileNameGetPath(prffile$); } IniWriteString("DOQQSML", "WorkDir", workDir$); ############################################################################## # step 3: # edit ccs755.txt - change date on last line to current date # Note we don't actually write out any file here. The text is just # held in a string variable and placed into the text layer directly. ############################################################################## # The format string (2nd parameter) to DateToString can contain the following # codes which it will replace with the information shown # # %a abbreviated weekday name # %A Full weekday name # %b abbreviated month name # %B Full month name # %d Day of the month ( 01 - 31 ) # %e Day of the month ( 1 - 32; single digits preceded by a space) # %m month number (01 - 12) # %y year within century (00-99) # %Y four digit year currentDate$ = DateToString(Date(), "%e %B %Y"); inFile$ = templateDir$ + "/ccs755.txt"; numLines = CountLines(inFile$); ccs755$ = ""; inFile = fopen(inFile$, "r"); numeric i; for i = 1 to (numLines - 1) { line$ = fgetline$(inFile); ccs755$ = ccs755$ + line$ + "\n"; } line$ = fgetline$(inFile); line$ = left$(line$, 6) + currentDate$; ccs755$ = ccs755$ + line$ + "\n"; fclose(inFile); ############################################################################## # step 4: # get date of photography from DOQQNAMEs metadata # change IMG_DATE.TXT to this date ############################################################################## db = OpenDatabase(templateDir$ + "/doqqmeta.rvc", "Database"); table = DatabaseGetTableInfo(db, "DOQQMETA"); photodate = 0; quadname$ = ""; name$ = FileNameGetName(doqqFileName$); for i = 1 to table.NumRecords { reqfilen$ = TableReadFieldStr(table, "REQFILEN", i); direct$ = TableReadFieldStr(table, "DIRECT", i); a$ = reqfilen$ + "1" + direct$; if (name$ == a$) { photodate = TableReadFieldNum(table, "PHOTODATE", i); quadname$ = TableReadFieldStr(table, "QUADNAME", i); dftcont = TableReadFieldNum(table, "CONTRAST", i); dftbright = TableReadFieldNum(table, "BRIGHTNESS", i); } } if (!photodate) { photodate$ = PopupString( 'The metadata for this DOQQ (' + name$ + ') is empty or missing. Please type the date of the photography as you wish it to appear on the map here (mm/dd/yy):'); } else { #photodate$ = DateToString(photodate, "%e %B %Y"); # 5 January 1996 photodate$ = DateToString(photodate, "%m/%d/%y"); # 01/05/96 } CloseRaster(DOQQ); imgdate$ = "Date of photography: " + photodate$ + "\n"; wantNeatLine = IniReadNumber("DOQQSML", "WantNeatLine", false); wantNeatLine = PopupYesNo("Do you want a neatline around the map image area?", wantNeatLine); IniWriteNumber("DOQQSML", "WantNeatLine", wantNeatLine); ############################################################################## # step 4b: # We got the title from the metadata too (assuming we found it) ############################################################################## if (quadname$ == "") { # Didn't find one in the metadata. Default to doqq object description maptitle$ = doqqObjectDesc$; } else { ntokens = NumberTokens(quadname$, " "); maptitle$ = GetToken(quadname$, " ", 1); for i = 2 to (ntokens - 1) { maptitle$ = maptitle$ + " " + GetToken(quadname$, " ", i); } # The last token will be the direction. Insert a comma after it. if (ntokens > 1) { maptitle$ = maptitle$ + ", " + GetToken(quadname$, " ", ntokens); } } contrast = 50; brightness = 100; if (dftcont) contrast = dftcont; if (dftbright) brightness = dftbright; ############################################################################## # step 4d: # Prompt for title, contrast and brightness values ############################################################################## class PromptStr promptTitle; class PromptNum promptCont, promptBright; class XmForm dlg; proc CB_Close() { maptitle$ = promptTitle.value; contrast = promptCont.value; brightness = promptBright.value; DialogClose(dlg); } dlg = CreateModalFormDialog("Settings"); promptTitle = CreatePromptStr(dlg, "Title:", 64, maptitle$); promptTitle.TopWidget = dlg; promptTitle.LeftWidget = dlg; promptTitle.RightWidget = dlg; promptCont = CreatePromptNum(dlg, "Contrast:", 4, 0, contrast, 0, 100); promptCont.TopWidget = promptTitle; promptCont.LeftWidget = dlg; promptBright = CreatePromptNum(dlg, "Brightness:", 4, 0, brightness, 0, 200); promptBright.TopWidget = promptTitle; promptBright.LeftWidget = promptCont; sep = CreateHorizontalSeparator(dlg); sep.TopWidget = promptBright; sep.LeftWidget = dlg; sep.RightWidget = dlg; br = CreateButtonRow(dlg, CreatePushButtonItem("ok", CB_Close)); br.TopWidget = sep; br.LeftWidget = dlg; br.RightWidget = dlg; br.BottomWidget = dlg; DialogWaitForClose(dlg); DestroyWidget(dlg); ############################################################################## # step 2: (moved) # copy DOQQNAME from MERLIN data servers (in /RASTERS/DOQQ) # Copy DNR Wetland vector from MERLIN data server (in VECTORS/DNRWET) # # Make sure they're not already there. We might want to prompt the # user and ask them if they want to do this. If the source is already on # a local harddrive or the network connection is reasonably fast, there's # no reason to copy them. But there's no way we can tell if this is the case. ############################################################################## if (PopupYesNo("Do you wish to copy the DOQQ raster and Wetlands\n vector to the work directory?", true)) { if (FileNameGetPath(doqqFileName$) != workDir$) { CloseRaster(DOQQ); newname$ = workDir$ + "/" + FileNameGetName(doqqFileName$) + ".rvc"; CopyFile(doqqFileName$, newname$); # Now need to reopen the object because we use that instead of the OpenRaster(DOQQ, doqqFileName$, doqqObjectName$); CloseRaster(DOQQ); } oldname$ = WetlandsVector.$INFO.Filename; objname$ = WetlandsVector.$INFO.Name; if (FileNameGetPath(oldname$) != workDir$) { newname$ = workDir$ + "/" + FileNameGetName(oldname$) + ".rvc"; CopyFile(oldname$, newname$); OpenVector(WetlandsVector, newname$, objname$); CloseVector(WetlandsVector); } } ############################################################################## # step 5: # Open LAYOUT.RVC/DOQQ_Wetland_v - change description to DOQQNAME ############################################################################## layout = LayoutCreate("layout", 1); LayoutRead(layout, layoutFileName$, layoutObjectName$); ############################################################################## # step 6: # Verify print settings ############################################################################## #layout.Hardcopy.Printer = "HP DesignJet 650C"; layout.Hardcopy.Printer = "HP DesignJet Series Color 300dpi"; layout.Hardcopy.MapScale = 8400; layout.Hardcopy.RasterDitherPattern = "Stucki"; layout.Hardcopy.VectorDitherPattern = "weave"; # Internal name of "vector" layout.Hardcopy.UseTempRast = true; layout.Hardcopy.FullPage = true; layout.Hardcopy.Paper = "E"; layout.Hardcopy.dpi = 300; layout.Hardcopy.Contrast = contrast; layout.Hardcopy.Brightness = brightness; IniWriteString("PRINTERS", "PortType", "file"); IniWriteString("PRINTERS", "PortName", prffile$); IniWriteString("PRINTERS", "PRFFile", prffile$); ############################################################################## # step 7: # Change the title ############################################################################## group = LayoutGetGroupByName(layout, "Title"); textlayer = group.FirstLayer; textstyle.Font = "times.ttf"; textstyle.Height = 1.25; # inches textstyle.LineSpace = .3228; # Inches textstyle.MapScale = layout.Hardcopy.MapScale; textstyle.UseLayoutScale = 1; textstyle.Foreground.Name = "black"; textstyle.Background.Name = "white"; textlayer.Text = maptitle$; textlayer.Style = textstyle; ############################################################################## # step 8: # Remove the DOQQ raster and wetlands vector # (Dont actually do this here. Well replace the objects in the # existing layers instead) # Instead, find the actual layers ############################################################################## mapgroup = LayoutGetGroupByName(layout, "Map Data"); layer = mapgroup.FirstLayer; while (layer) { if (layer.Type == "Raster") rastlayer = layer; if (layer.Type == "Vector") vectlayer = layer; if (layer.Type == "Map Grid") gridlayer = layer; layer = layer.NextLayer; } ############################################################################## # step 9: # Re add the new DOQQ ############################################################################## RasterLayerSetObject(rastlayer, DOQQ); rastlayer.NullCellsTransparent = false; ############################################################################## # step 10a: # Re add the new Wetlands vector. ############################################################################## VectorLayerSetObject(vectlayer, WetlandsVector); vectlayer.Point.Select.Mode = "None"; vectlayer.Node.Draw = false; vectlayer.StyleObject = OpenStyleObject(templateDir$ + "/styles.rvc", "STYLES"); ############################################################################## # step 10b: # Set the line styles ############################################################################## vectlayer.Line.Select.Mode = "ByAttribute"; vectlayer.Line.StyleMode = "ByAttribute"; vectlayer.DrawLinesFirst = false; # Don't draw lines before polygons tinfo = TableGetInfo(WetlandsVector.line.ClassStyle); tinfo.StyleObjName = ""; numeric num = NumRecords(WetlandsVector.line.ClassStyle); string cl$, l$; for i = 1 to num { cl$ = WetlandsVector.line.ClassStyle[@i].Class$; if (cl$ == "Unclassified") { WetlandsVector.line.ClassStyle[@i]._DrawFlag_ = 0; } else { WetlandsVector.line.ClassStyle[@i]._DrawFlag_ = 1; l$ = left$(cl$, 1); if (l$ == "E") { WetlandsVector.line.ClassStyle[@i]._StyleName_$ = "Estuarine_Lin"; WetlandsVector.line.ClassStyle[@i]._StyleIndex_ = 1; } else if (l$ == "P") { WetlandsVector.line.ClassStyle[@i]._StyleName_$ = "Palustrine_Lin"; WetlandsVector.line.ClassStyle[@i]._StyleIndex_ = 4; } else if (l$ == "R") { WetlandsVector.line.ClassStyle[@i]._StyleName_$ = "Riverine_Lin"; WetlandsVector.line.ClassStyle[@i]._StyleIndex_ = 2; } else { # Assume "break line" or "lead line" # Instructions say "or similar", but can't tell WetlandsVector.line.ClassStyle[@i]._StyleName_$ = "Break_Lead_Line"; WetlandsVector.line.ClassStyle[@i]._StyleIndex_ = 0; } } } ############################################################################## # step 10c: # Set the polygon styles ############################################################################## vectlayer.Poly.Select.Mode = "ByAttribute"; vectlayer.Poly.NoFill = false; # Don't disable polygon filling tinfo = TableGetInfo(WetlandsVector.poly.ClassStyle); tinfo.StyleObjName = ""; num = NumRecords(WetlandsVector.poly.ClassStyle); for i = 1 to num { WetlandsVector.poly.ClassStyle[@i]._DrawFlag_ = 1; WetlandsVector.poly.ClassStyle[@i]._StyleName_$ = "Wetland"; WetlandsVector.poly.ClassStyle[@i]._StyleIndex_ = 0; } ############################################################################## # step 10d: # Set the Label styles ############################################################################## vectlayer.Label.Draw = true; labelstyle.Font = "mallard.of"; labelstyle.Foreground.Name = "yellow"; labelstyle.Background.Name = "black"; labelstyle.Enhance = true; labelstyle.UseElemHeight = true; vectlayer.Label.NormalStyle = labelstyle; ############################################################################## # step 11: # Change group settings for the "Map Data" group ############################################################################## # Need the extents of the DOQQ raster layer in degrees georef = GeorefAlloc(); GeorefSetProjection(georef, latlon); GetObjectExtents(DOQQ, xmin, ymin, xmax, ymax, georef); GeorefFree(georef); # Set the ClipRegion to this rect + a 2 second buffer halfsize = (7.5 / 4) / 60; # Half the height of a quarter quad in degrees twosec = 2.0 / 3600; # Two seconds converted to degrees cx = (xmin + xmax) / 2; cy = (ymin + ymax) / 2; # Force center to fall on a the correct interval # Floor rounds to -infinity. cx = floor(cx / halfsize + .5) * halfsize; cy = floor(cy / halfsize + .5) * halfsize; extents.x1 = cx - halfsize - twosec; extents.x2 = cx + halfsize + twosec; extents.y1 = cy - halfsize - twosec; extents.y2 = cy + halfsize + twosec; # Need to set clip region to this rectangle mapgroup.ClipRegion.SetFromRect(extents); mapgroup.ClipRegion.Projection = latlon; mapgroup.Clip = true; mapgroup.X.AttachTo = "Margin"; mapgroup.X.AttachThis = "Left"; mapgroup.X.AttachRef = "Left"; mapgroup.X.Offset = .2; # Page inches mapgroup.Y.AttachTo = "Margin"; mapgroup.Y.AttachThis = "Center"; mapgroup.Y.AttachRef = "Center"; mapgroup.Y.Offset = -.5; # Page inches ############################################################################## # step 12: # Modify the mapgrid ############################################################################## if (gridlayer) LayerDestroy(gridlayer); gridlayer = GroupAddMapGridLayer(mapgroup, projection, 5000, 5000, "feet", latlon, extents); LayerRaise(vectlayer); # Move vector layer back on top gridlayer.Name = projection.System; gridlayer.CoordFormat = "Comma"; gridlayer.BorderRelative = false; # Starting At: Origin gridlayer.ShowBorder = false; gridlayer.LayoutScale = true; gridlayer.ShowCoordText2D = true; gridlayer.CoordLabelStyle = textstyle; gridlayer.CoordLabelStyle.Foreground.name = "black"; gridlayer.CoordLabelStyle.Height = .1; # Inches, approx 2.5 mm gridlayer.ShowGrid = true; gridlayer.GridStyle.Color.name = "white"; gridlayer.GridWidthUnits = "mm"; gridlayer.GridWidth = .5; # Border ticks are off. To offset text by a bit, turn them # on, but keep them white so they don't show up gridlayer.ShowBorderTicksExt = false; gridlayer.ShowBorderTicksExt = false; gridlayer.BorderTickWidthUnits = "mm"; gridlayer.BorderTickWidth = .5; gridlayer.BorderTickOutsideUnits = "mm"; gridlayer.BorderTickOutside = 2.0; gridlayer.BorderTickStyle.Color.name = "white"; ############################################################################## # step 13: # Modify the CCWS Text group ############################################################################## group = LayoutGetGroupByName(layout, "CCWS Text"); textlayer = group.FirstLayer; textstyle.Height = .315; # approx 8 mm textlayer.Style = textstyle; textlayer.Text = ccs755$; ############################################################################## # step 14: # Modify the Photo Date text layer ############################################################################## group = LayoutGetGroupByName(layout, "Photo Date"); textlayer = group.FirstLayer; textstyle.Height = .157; # approx 4 mm textlayer.Style = textstyle; textlayer.Text = imgdate$; ############################################################################## # step 16: (Changed the order here on purpose) # Use object editor to edit the neatline vector. Id change this to use # an SML layer to autogenerate a neatline. (This is an option Maryland # didnt have when they started this project) # # Heres an even easier way. Create a mapgrid but only show the border # The neatline will then be exactly on the quarter quad border. ############################################################################## # We had expanded the extents out by two seconds for clipping. Now put them # back to the actual quarter quad bounds. extents.x1 = extents.x1 + twosec; extents.x2 = extents.x2 - twosec; extents.y1 = extents.y1 + twosec; extents.y2 = extents.y2 - twosec; # Neatline was done with a vector. Delete it layer = GroupGetLayerByName(mapgroup, "NEATLINE / Neatline"); if (layer) LayerDestroy(layer); if (wantNeatLine) { neatlayer = GroupAddMapGridLayer(mapgroup, latlon, 1, 1, "degrees", latlon, extents); neatlayer.Name = "NEATLINE / Neatline"; neatlayer.ShowGrid = false; neatlayer.ShowCoordText2D = false; neatlayer.ShowBorderTicksExt = false; neatlayer.ShowBorderTicksInt = false; neatlayer.ShowBorder = true; neatlayer.LayoutScale = true; # XXX Change the color of the neatline in the main map here... neatlayer.BorderStyle.Color.name = "red"; # name from RGB.txt neatlayer.BorderWidthUnits = "mm"; neatlayer.BorderWidth = .5; } ############################################################################## # Step 16a: There's a neatline in the index map too. Same drill ############################################################################## indexgroup = LayoutGetGroupByName(layout, "Index Map"); # Neatline was done with a vector. Delete it layer = GroupGetLayerByName(indexgroup, "NEATLINE / Neatline"); if (layer) LayerDestroy(layer); neatlayer = GroupAddMapGridLayer(indexgroup, latlon, 1, 1, "degrees", latlon, extents); neatlayer.Name = "NEATLINE / Neatline"; neatlayer.ShowGrid = false; neatlayer.ShowCoordText2D = false; neatlayer.ShowBorderTicksExt = false; neatlayer.ShowBorderTicksInt = false; neatlayer.ShowBorder = true; neatlayer.LayoutScale = true; # XXX This is the color of the rectangle in the index map neatlayer.BorderStyle.Color.name = "red"; neatlayer.BorderWidthUnits = "mm"; neatlayer.BorderWidth = .5; neatlayer.SizeRelative = true; neatlayer.LayoutScale = false; neatlayer.MapScale = layout.MapScale / indexgroup.RelScale; ############################################################################## # step 15: (Changed the order here on purpose) # Save the layout ############################################################################## string newFileName$ = workDir$ + "/layout.rvc"; CopyFile(layoutFileName$, newFileName$); layoutFileName$ = newFileName$; DeleteObject(layoutFileName$, layoutObjectNumber); # Remove old layout LayoutWrite(layout, layoutFileName$, layoutObjectName$, doqqObjectDesc$); ############################################################################## # step 17: # View / Print to generate print file, then save and exit ############################################################################## numeric err = LayoutPageSetupDialog(layout); #define SML_DEFINE_SML_MDISP_FUNC_LIST if (!err && PopupYesNo("Do you want to print the layout now?", true)) { LayoutPrint(layout); } # If we don't destroy the layout, it will prevent view from being able to # exit. LayoutDestroy(layout); # # rvcmain 4.131 4618 # rvcdbase.c 4.273 1260 # qqobject.c 1.138 1196 # doqq.sml --- 165 # # Need better error if the database isn't found # # setting style object on vector layer seems to fail if it had no style # assigned to begin with. May be that if vector was originally set to # "From vector" it ignores the style object I set #