Surface Analysis Samples¶
Surface analysis involves examining terrain data to extract geographic information, such as slope, aspect, and elevation. Using digital elevation models (DEMs), watersheds, viewshed maps, contour lines, and elevation grids can be generated. These tools can help better understand landscape characteristics and assess the environmental impact of enironmental changes like natural disasters.
Create Elevation Layer¶
Note
Before running this sample, configure these variables:
export_dir
: the directory for resulting files to be exported to
A more complex sample script, showing a common workflow using Global Mapper Pro’s lidar tools: loading lidar data, creating an elevation layer from it, and exporting it to an elevation grid file. This sample grabs any loaded lidar layers, classifies the noise and ground points, and creates a class filter to only allow the use of ground points. An elevation grid is then generated, scaled to the size of the layer’s GlobalRect. Similar dimensions are then used to determine the export bounds for the newly created elevation grid. Finally the elevation grid is exported to a directory specified by ‘resource_dir.’
# Resolution of the output dataset in meters
pixel_resolution = 1.0
lidar_layers = []
# Load all LiDAR layers found into a list
for i in range(num_layers):
info = gm.GetLayerInfo(all_layers[i])
if info.mEnabled and info.mTypeName == "LIDAR_LAS":
lidar_layers.append(all_layers[i])
# If there's no lidar layers, no need to run the rest of the script
if len(lidar_layers):
# Classify noise points
print("Classifying noise...")
noise_setup = gm.GM_ClassifyNoiseSetup_t()
# Only check unclassified points for noise
noise_setup.mFlags += gm.GM_ClassifyNoise_UnclassifiedOnly
# Detect any points that resemble noisy lidar returns and reclassify them (best practice to do this first)
err_LidarClassifyNoise = gm.LidarClassifyNoise(
lidar_layers, noise_setup, 0
)
# Classify the ground points
print("Classifying ground...")
# Default settings work well for ground classification
err_LidarClassifyGround = gm.LidarClassifyGround(
lidar_layers, gm.GM_ClassifyGroundSetup_t(), 0
)
# Create the class filter to only use ground points
print("Applying class filter...")
# Save the current settings so they can be restored afterward
err_GetLidarClassFilter, prev_filter = gm.GetLidarClassFilter()
# New filter object with all classes disabled
err_LidarClassFilter_Init, class_filter = gm.LidarClassFilter_Init(False)
# Enable ground points to pass through the filter
err_LidarClassFilter_SetClassEnabled, mask = gm.LidarClassFilter_SetClassEnabled(
class_filter, gm.GM_LidarClass_Ground, True
)
# Apply new filter: only ground points will be used in lidar operations now
err_SetLidarClassFilter1 = gm.SetLidarClassFilter(class_filter)
# Get the dimensions of the layer in meters in case it isn't already
bounds = gm.GetLayerInfo(lidar_layers[0]).mGlobalRect
# Get the total width and height of the data in meters
err_CalcDistance1, width = gm.CalcDistance(
bounds.mMaxX, bounds.mMaxY, bounds.mMinX, bounds.mMaxY, 0
)
err_CalcDistance2, height = gm.CalcDistance(
bounds.mMaxX, bounds.mMaxY, bounds.mMaxX, bounds.mMinY, 0
)
groundcrs_width = (abs(bounds.mMaxX - bounds.mMinX) / width / pixel_resolution)
groundcrs_height = (abs(bounds.mMaxY - bounds.mMinY) / height / pixel_resolution)
# Create elevation grid layer from ground points at the approximate resolution
print("Generating elevation grid...")
grid_setup = gm.GM_GridGenSetup_t()
grid_setup.mXRes = groundcrs_width
grid_setup.mYRes = groundcrs_height
grid_setup.mGridAlg = gm.GM_GridAlg_BinAverage
# This value is high enough to fill gaps in most lidar data
grid_setup.mTightnessMult = 32
# Define how the gaps are filled
gap_fill = gm.GM_FillGapsParams_t()
gap_fill.mGapAlg = gm.GM_GapFillAlg_IDW
# Needs to be the same as grid_setup.mGridAlg
gap_fill.mGridAlg = gm.GM_GridAlg_BinAverage
grid_setup.mGapFillSetup = gap_fill
err_GenerateElevationGrid, grid_layer, tin_layer = gm.GenerateElevationGrid(lidar_layers, grid_setup)
# We don't need the TIN layer
err_CloseLayer = gm.CloseLayer(tin_layer)
# Reset the lidar class filter to previous settings
err_SetLidarClassFilter2 = gm.SetLidarClassFilter(prev_filter)
# Get the dimensions of grid layer in meters to use as the export size
bounds = gm.GetLayerInfo(grid_layer).mGlobalRect
err_CalcDistance3, grid_width = gm.CalcDistance(
bounds.mMaxX, bounds.mMaxY, bounds.mMinX, bounds.mMaxY, 0
)
err_CalcDistance4, grid_height = gm.CalcDistance(
bounds.mMaxX, bounds.mMaxY, bounds.mMaxX, bounds.mMinY, 0
)
# We are using the pixel_resolution variable for spacing
# A higher pixel_resolution value means a bigger pixels, and therefore a smaller file
pixel_width = round(grid_width / pixel_resolution)
pixel_height = round(grid_height / pixel_resolution)
# Export the new elevation data
print("Exporting elevation grid layer...")
err_ExportElevation = gm.ExportElevation(
export_dir + "ExampleDem.dem",
gm.GM_Export_DEM,
grid_layer,
bounds,
pixel_width,
pixel_height,
0,
gm.GM_ElevUnit_Centimeters,
)
else:
print("There are no lidar layers open.")
Elevation Grids from Multiple Lidar Files¶
Note
Before running this sample, configure these variables:
import_dir
: the directory containing sample dataexport_dir
: the directory for resulting files to be exported to
A sample that iterates through multiple lidar files, generates elevation grids for each one, determines the appropriate dimensions for the exported image, then exports the elevation grid as a JPEG. This demonstrates how multiple files in a directory can be easily accessed and modified.
# Retrieve all lidar files in the directory
filenames = []
for f in dir_files:
file = f.lower()
if file.endswith(".las") or file.endswith(".laz"):
filenames.append(file)
# Modify the display options
vert_display_opts = gm.GM_VerticalDisplayOptions_t()
vert_display_opts.mSize = 50
vert_display_opts.mShaderName = "Atlas Shader"
err_SetVerticalDisplayOptions = gm.SetVerticalDisplayOptions(vert_display_opts)
# Loop through all the lidar layers
for file in filenames:
err_LoadLayerList, arr_ptr, arr_size = gm.LoadLayerList(
import_dir + file, gm.GM_LoadFlags_UseDefaultLoadOpts
)
layers_arr = gm.GM_LayerHandle_array_frompointer(arr_ptr)
# Generate an elevation grid with all the loaded layers
grid_setup = gm.GM_GridGenSetup_t()
grid_setup.mGridAlg = gm.GM_GridAlg_BinAverage
grid_setup.mElevUnits = gm.GM_ElevUnit_Meters
err_GenerateElevationGrid2, grid_layer = gm.GenerateElevationGrid2(
[layers_arr[0]], grid_setup
)
# Get the right dimensions for the image
bounds = gm.GetLayerInfo(grid_layer).mGlobalRect
ratio = abs(bounds.mMaxX - bounds.mMinX) / abs(bounds.mMaxY - bounds.mMinY)
width = 1920
height = width * (1 / ratio)
# Make sure the exported layers are at least HD
if height < 1080:
height = 1080
width = height * ratio
width = int(width)
height = int(height)
# Export the raster image, maintaining file names
export_name = file.split('.')
err_ExportRaster = gm.ExportRaster(
export_dir + export_name[0] + "_elevation_grid.jpg",
gm.GM_Export_JPG,
grid_layer,
None,
width,
height,
0x0,
)
err_CloseLayer1 = gm.CloseLayer(layers_arr[0])
err_CloseLayer2 = gm.CloseLayer(grid_layer)
Contour maps from Multiple USGS DEMs¶
Note
Before running this sample, configure these variables:
import_dir
: the directory containing sample dataDXF_dir
: the directory for DXF files to be exported toSHP_dir
: the directory for SHP files to be exported to
This script generates a vector contour map based on elevation data and exports the contours into multiple vector formats. All of the data is retrieved from a provided directory, filtering only the desired extensions. The DEMs are then loaded and contour lines are generated at intervals of 50ft. The resulting contours are then exported as DXFs and shapefiles.
# Retrieve all files in the directory with the desired extension(s)
filenames = []
for f in dir_files:
file = f.lower()
if (
file.endswith(".dem")
or file.endswith(".stds")
or file.endswith(".tar")
or file.endswith(".gz")
):
filenames.append(file)
# Loop over and load in all the found files
for filename in filenames:
err_LoadLayerList, arr_ptr, arr_size = gm.LoadLayerList(
import_dir + filename, gm.GM_LoadFlags_UseDefaultLoadOpts
)
layer_arr = gm.GM_LayerHandle_array_frompointer(arr_ptr)
layer = layer_arr[0]
# Generate the contour lines at intervals of 50 feet
contour_params = gm.GM_ContourParams_t()
contour_params.mIntervalInFeet = 50
contour_params.mShowProgress = False
err_GenerateContours, contour_layer = gm.GenerateContours(layer, contour_params)
# Export the generate contours file to this path
filename_wo_ext = filename[: filename.index(".")]
err_ExportVector1 = gm.ExportVector(
DXF_dir + filename_wo_ext + "_contours.dxf",
gm.GM_Export_DXF,
contour_layer,
None,
gm.GM_VectorExportFlags_HideProgress + gm.GM_VectorExportFlags_GenPRJFile,
0x0,
)
err_ExportVector2 = gm.ExportVector(
SHP_dir + filename_wo_ext + "_contours.shp",
gm.GM_Export_Shapefile,
contour_layer,
None,
gm.GM_VectorExportFlags_HideProgress
+ gm.GM_VectorExportFlags_GenPRJFile
+ gm.GM_VectorExportFlags_ExportLines
+ gm.GM_VectorExportFlags_Export3D,
0x0,
)
# Close the layers after we're done with them
err_CloseLayer1 = gm.CloseLayer(layer)
err_CloseLayer2 = gm.CloseLayer(contour_layer)
Generating a Viewshed and Watershed¶
Note
Before running this sample, configure these variables:
export_dir
: the directory for resulting files to be exported to
A script that generates a viewshed centered on a specified (X,Y) coordinate and creates a watershed based on the provided GMG file. It calculates key watershed attributes, such as drainage area size, inflow, and outflow values. The resulting viewshed, stream network, and drainage areas are then exported to the specified export directory.
# Generate a viewshed at a specific coordinate-location
center_point = gm.GM_Point_t(435986.9, 4893585.6)
viewshed_opts = gm.GM_ViewShedParams_t()
viewshed_opts.mAtmosphericCorr = 1.33333
viewshed_opts.mCenterPoint = center_point
viewshed_opts.mColor = gm.toRGB(255, 255, 255)
viewshed_opts.mDesc = "Viewshed Analysis"
viewshed_opts.mGenCoveragePolys = True
viewshed_opts.mRadius = 3000
viewshed_opts.mTransmitterHeight = 0
viewshed_opts.mReceiverHeight = 2
err_CalcViewShed, viewshed_handle = gm.CalcViewShed(layers_list[0], viewshed_opts)
# Generate a watershed
watershed_param = gm.GM_WatershedParams_t()
watershed_param.mFlags = gm.GM_Watershed_CreateAreas
watershed_param.mFlags += gm.GM_Watershed_KeepZeroAtZero
watershed_param.mFlags += gm.GM_Watershed_SmoothStreams
watershed_param.mDesc = "DRAINAGE NETWORK"
watershed_param.mMaxDepressionDepth = 12
watershed_param.mStreamThreshold = 10000
watershed_param.mBounds = gm.GetLayerInfo(layers_list[0]).mGlobalRect
watershed_layer = [layers_list[0]]
err_GenerateWatershed, stream_layer, drainage_area_layer = gm.GenerateWatershed(
watershed_layer, watershed_param
)
# Gather watershed data
watershed_data = []
i = 0
stream_feature = gm.GetLineFeature(stream_layer, i)
while stream_feature:
# Get the STREAM_ID, IN_FLOW, OUT_FLOW, and DRAIN_AREA
attr_array = gm.GM_AttrValue_array_frompointer(
stream_feature.mFeatureInfo.mAttrList
)
attribute_values = gm.carray_to_list(
attr_array, stream_feature.mFeatureInfo.mNumAttrs
)
# Create a dictionary to hold the stream data
stream_data = {
attribute_values[0].mName: attribute_values[0].mVal,
attribute_values[1].mName: attribute_values[1].mVal,
attribute_values[2].mName: attribute_values[2].mVal,
attribute_values[3].mName: attribute_values[3].mVal,
}
watershed_data.append(stream_data)
# Frees deep copies from memory
# Without this step the script causes the program to freeze
gm.FreeLineFeature(stream_feature)
i += 1
stream_feature = gm.GetLineFeature(stream_layer, i)
# Display watershed data
for data in watershed_data:
print("STREAM_ID", data["STREAM_ID"] + ":")
print(" IN_FLOW:", data["IN_FLOW"])
print(" OUT_FLOW:", data["OUT_FLOW"])
print(" DRAIN_AREA:", data["DRAIN_AREA"])
print("-" * 30)
# Export all created layers
err_ExportVector1 = gm.ExportVector(
export_dir + "view_shed.kmz",
gm.GM_Export_KML,
viewshed_handle,
None,
gm.GM_ExportFlags_HideProgress,
gm.NULL,
)
err_ExportVector2 = gm.ExportVector(
export_dir + "streams.shp",
gm.GM_Export_Shapefile,
stream_layer,
None,
gm.GM_ExportFlags_HideProgress
+ gm.GM_ExportFlags_GenPRJFile
+ gm.GM_ExportFlags_GenWorldFile,
gm.NULL,
)
err_ExportVector3 = gm.ExportVector(
export_dir + "drainage_areas.shp",
gm.GM_Export_Shapefile,
drainage_area_layer,
None,
gm.GM_ExportFlags_HideProgress
+ gm.GM_ExportFlags_GenPRJFile
+ gm.GM_ExportFlags_GenWorldFile,
gm.NULL,
)
err_CloseLayer1 = gm.CloseLayer(viewshed_handle)
err_CloseLayer2 = gm.CloseLayer(stream_layer)
err_CloseLayer3 = gm.CloseLayer(drainage_area_layer)