Today, I am posting a piece I wrote a while ago and had been putting off, after some refinement. I ask for your understanding; it has been difficult to concentrate on writing lately.
The reason I created this script was because I saw a close junior of mine manually zooming in and out of hundreds of parcels in CAD, capturing each one for a report. I thought he might not survive long if he kept working like that. I made this to solve the problem for him the next time he faced a similar task.
As shown in the image above, you can divide the cadastral map by parcel into separate layers and then perform the following operations. (Global Mapper users will likely find this basic.)
I will cover how to separate the layers in a future post.
I originally planned to introduce integration with external languages after the lectures had progressed a bit more, but for now, just take a look at it to see that this kind of functionality is possible.
How to Use
- The satellite image layer (raster layer) at the bottom must be at the very top of the layer list. Turn off all other raster layers.
- Each parcel must be separated into its own layer. The layer description should be in English.
- Turn off all vector layers related to the parcels.
- Go to the File menu -> Open Script Editor, paste the code below, and save it with an appropriate name.
- Project folders and paths must all be in English.
- You can change the image save path on line 35.
- The image aspect ratio can be adjusted on line 9. It is currently set to 16:9.
- The horizontal pixel width is set on line 70. The vertical pixels are automatically determined to maintain the 16:9 ratio.
- Click the Run Script button to execute.
- Once you click Run Script, JPG images will be created in the specified path.
#/usr/bin/env python
# coding=utf8
import globalmapper as gm
import os
zoom_out_factor = 1.5
aspect_ratio = 16/9
layers_are_loaded = gm.GetLoadedLayerList()
if not layers_are_loaded:
print("No layers are currently open, so nothing was exported.")
else:
arr_ptr, arr_size = layers_are_loaded
all_layers = gm.GM_LayerHandle_array_frompointer(arr_ptr)
raster_layers = []
vector_layers = []
for layer in gm.carray_to_list(all_layers, arr_size):
layer_info = gm.GetLayerInfo(layer)
if layer_info.mHasVectorData:
vector_layers.append(layer)
elif layer_info.mHasRasterData:
raster_layers.append(layer)
if len(vector_layers) == 0:
print("No vector layers were found, so nothing was exported.")
elif len(raster_layers) == 0:
print("No raster layers were found to use as background.")
else:
# Set your export path here
output_directory = os.path.expanduser("F:\\2024-08-26_export\\result\\")
print("Exporting files to {}".format(output_directory))
gm.SetLayerEnabled(raster_layers[0], True)
for layer in vector_layers:
layer_info = gm.GetLayerInfo(layer)
try:
# Character encoding handling
if layer_info.mCodePage == 949:
layer_name = layer_info.mDescription.encode('raw_unicode_escape').decode('cp949')
elif layer_info.mCodePage == 0:
layer_name = layer_info.mDescription.encode("latin1").decode("cp1252")
else:
layer_name = layer_info.mDescription
except UnicodeDecodeError:
layer_name = layer_info.mDescription
name_wo_ext = layer_name[:layer_name.index(".")] if "." in layer_name else layer_name
name_wo_ext = name_wo_ext.replace(" ", "_")
name_wo_ext = "".join(c for c in name_wo_ext if c.isalnum() or c in "_-")
# Calculating bounding box and aspect ratio
width_meters = layer_info.mGlobalRect.mMaxX - layer_info.mGlobalRect.mMinX
height_meters = layer_info.mGlobalRect.mMaxY - layer_info.mGlobalRect.mMinY
dim_ratio = width_meters / height_meters
center_x = (layer_info.mGlobalRect.mMaxX + layer_info.mGlobalRect.mMinX) / 2
center_y = (layer_info.mGlobalRect.mMaxY + layer_info.mGlobalRect.mMinY) / 2
if dim_ratio > aspect_ratio:
new_width = width_meters * zoom_out_factor
new_height = new_width / aspect_ratio
else:
new_height = height_meters * zoom_out_factor
new_width = new_height * aspect_ratio
new_min_x = center_x - new_width / 2
new_max_x = center_x + new_width / 2
new_min_y = center_y - new_height / 2
new_max_y = center_y + new_height / 2
export_rect = gm.GM_Rectangle_t(new_min_x, new_min_y, new_max_x, new_max_y)
gm.SetLayerEnabled(layer, True)
output_filename = os.path.join(output_directory, "{}.jpg".format(name_wo_ext))
HD_WIDTH = 800
HD_HEIGHT = int(HD_WIDTH / aspect_ratio)
error_code = gm.ExportRaster(output_filename, gm.GM_Export_JPG, 0x0, export_rect, HD_WIDTH, HD_HEIGHT, gm.GM_ExportFlags_AddAlpha)
if error_code == gm.GM_Error_None:
print("Exported {} to {}".format(layer_name, output_filename))
else:
print("Error exporting {}: {}".format(layer_name, gm.strerror(error_code)))
gm.SetLayerEnabled(layer, False)
gm.SetLayerEnabled(raster_layers[0], False)
I tinkered with lines 47–54 while trying to handle character conversion, but eventually left it as is. It works fine for English, so you can use it without issues. I was going to fix it but felt a bit too lazy.
I tested it with 500 parcels, and the export finished in less than 20 seconds. It’s incredibly satisfying.
As a side note, when using Python scripts in Global Mapper, you should handle everything in English. The path where the workspace is saved, the workspace name itself, and even the comments should ideally be in English for best compatibility.
That's all for today...