Skip to content

Instantly share code, notes, and snippets.

@dinizime
Created March 19, 2025 18:41
Show Gist options
  • Select an option

  • Save dinizime/20b9d0add1793bce7464661c9e3775bf to your computer and use it in GitHub Desktop.

Select an option

Save dinizime/20b9d0add1793bce7464661c9e3775bf to your computer and use it in GitHub Desktop.
Converte camada poligono do qgis para kmz com label
from qgis.core import QgsProject, QgsGeometry, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsWkbTypes, QgsPointXY
import os
import zipfile
import xml.dom.minidom as minidom
import random
import math
def create_kmz_with_labels(layer_name, label_field, output_kmz_path,
line_color='ff4aaf4d', line_width=4,
label_color='ff00ff00', label_scale=1.5,
min_lod_pixels=100,
char_width_factor=0): # Fator de largura do caractere em coordenadas
"""
Cria um arquivo KMZ com polígonos e labels centralizados com controle de zoom
Parâmetros:
layer_name (str): Nome da camada no QGIS
label_field (str): Nome do campo a ser usado como label
output_kmz_path (str): Caminho completo para o arquivo KMZ de saída
line_color (str): Cor da linha no formato ABGR (hexadecimal)
line_width (int): Espessura da linha do polígono
label_color (str): Cor do texto no formato ABGR (hexadecimal)
label_scale (float): Tamanho do texto (1.0 = tamanho normal)
min_lod_pixels (int): Nível de zoom mínimo para o texto aparecer
char_width_factor (float): Fator para estimar a largura de um caractere em coordenadas geográficas
"""
# Obter a camada pelo nome
layer = None
for lyr in QgsProject.instance().mapLayers().values():
if lyr.name() == layer_name:
layer = lyr
break
if not layer:
print(f"Camada '{layer_name}' não encontrada!")
return
# Verificar se o campo existe
field_index = layer.fields().indexFromName(label_field)
if field_index == -1:
print(f"Campo '{label_field}' não encontrado na camada!")
return
# Criar o documento KML
doc = minidom.getDOMImplementation().createDocument(None, "kml", None)
kml = doc.documentElement
kml.setAttribute("xmlns", "http://www.opengis.net/kml/2.2")
document = doc.createElement("Document")
kml.appendChild(document)
# Criar estilos
# Estilo para polígonos
polygon_style_id = f"polyStyle_{random.randint(1000, 9999)}"
polygon_style = doc.createElement("Style")
polygon_style.setAttribute("id", polygon_style_id)
line_style = doc.createElement("LineStyle")
color_element = doc.createElement("color")
color_element.appendChild(doc.createTextNode(line_color))
line_style.appendChild(color_element)
width_element = doc.createElement("width")
width_element.appendChild(doc.createTextNode(str(line_width)))
line_style.appendChild(width_element)
polygon_style.appendChild(line_style)
poly_style = doc.createElement("PolyStyle")
fill_color = doc.createElement("color")
fill_color.appendChild(doc.createTextNode("00ffffff")) # Transparente
poly_style.appendChild(fill_color)
fill_element = doc.createElement("fill")
fill_element.appendChild(doc.createTextNode("1"))
poly_style.appendChild(fill_element)
outline_element = doc.createElement("outline")
outline_element.appendChild(doc.createTextNode("1"))
poly_style.appendChild(outline_element)
polygon_style.appendChild(poly_style)
document.appendChild(polygon_style)
# Estilo para labels
label_style_id = f"labelStyle_{random.randint(1000, 9999)}"
label_style = doc.createElement("Style")
label_style.setAttribute("id", label_style_id)
icon_style = doc.createElement("IconStyle")
icon_scale = doc.createElement("scale")
icon_scale.appendChild(doc.createTextNode("0")) # Esconde o ícone
icon_style.appendChild(icon_scale)
label_style.appendChild(icon_style)
label_style_element = doc.createElement("LabelStyle")
label_color_element = doc.createElement("color")
label_color_element.appendChild(doc.createTextNode(label_color))
label_style_element.appendChild(label_color_element)
label_scale_element = doc.createElement("scale")
label_scale_element.appendChild(doc.createTextNode(str(label_scale)))
label_style_element.appendChild(label_scale_element)
label_style.appendChild(label_style_element)
document.appendChild(label_style)
# Transformação para coordenadas geográficas (se necessário)
src_crs = layer.crs()
dest_crs = QgsCoordinateReferenceSystem("EPSG:4326") # WGS 84
transform = QgsCoordinateTransform(src_crs, dest_crs, QgsProject.instance())
# Processar cada feição
for feature in layer.getFeatures():
# Obter o valor do campo para o label
label_value = str(feature[label_field])
# Obter a geometria e transformar para WGS 84
geom = feature.geometry()
geom.transform(transform)
# Calcular o centroide exato do polígono
centroid = geom.centroid().asPoint()
# Criar placemark para o polígono
poly_placemark = doc.createElement("Placemark")
# Adicionar nome como atributo ao polígono
poly_name = doc.createElement("name")
poly_name.appendChild(doc.createTextNode(label_value))
poly_placemark.appendChild(poly_name)
# Adicionar descrição com o valor do atributo
poly_description = doc.createElement("description")
poly_description.appendChild(doc.createTextNode(''))
poly_placemark.appendChild(poly_description)
style_url = doc.createElement("styleUrl")
style_url.appendChild(doc.createTextNode(f"#{polygon_style_id}"))
poly_placemark.appendChild(style_url)
# Converter geometria para KML
polygon_element = create_polygon_element(doc, geom)
poly_placemark.appendChild(polygon_element)
document.appendChild(poly_placemark)
# Calcular deslocamento para centralizar o texto
# Estimamos a largura do texto com base no número de caracteres
# e aplicamos um deslocamento para a esquerda
text_width = len(label_value) * char_width_factor * label_scale
# O deslocamento é aplicado na direção oeste-leste (longitude)
# Deslocamos para a esquerda metade da largura estimada
offset_x = -text_width / 2
# Calculamos o novo ponto deslocado
adjusted_x = centroid.x() + offset_x
# Criar placemark para o label com controle de zoom
label_placemark = doc.createElement("Placemark")
label_name = doc.createElement("name")
label_name.appendChild(doc.createTextNode(label_value))
label_placemark.appendChild(label_name)
label_style_url = doc.createElement("styleUrl")
label_style_url.appendChild(doc.createTextNode(f"#{label_style_id}"))
label_placemark.appendChild(label_style_url)
# Adicionar controle de zoom para o label
region = doc.createElement("Region")
lat_lon_alt_box = doc.createElement("LatLonAltBox")
# Obter o envelope da geometria para o controle de região
bbox = geom.boundingBox()
north = doc.createElement("north")
north.appendChild(doc.createTextNode(str(bbox.yMaximum())))
lat_lon_alt_box.appendChild(north)
south = doc.createElement("south")
south.appendChild(doc.createTextNode(str(bbox.yMinimum())))
lat_lon_alt_box.appendChild(south)
east = doc.createElement("east")
east.appendChild(doc.createTextNode(str(bbox.xMaximum())))
lat_lon_alt_box.appendChild(east)
west = doc.createElement("west")
west.appendChild(doc.createTextNode(str(bbox.xMinimum())))
lat_lon_alt_box.appendChild(west)
region.appendChild(lat_lon_alt_box)
lod = doc.createElement("Lod")
min_lod = doc.createElement("minLodPixels")
min_lod.appendChild(doc.createTextNode(str(min_lod_pixels)))
lod.appendChild(min_lod)
max_lod = doc.createElement("maxLodPixels")
max_lod.appendChild(doc.createTextNode("-1")) # Sem limite
lod.appendChild(max_lod)
region.appendChild(lod)
label_placemark.appendChild(region)
# Adicionar ponto no centroide ajustado
point = doc.createElement("Point")
coords = doc.createElement("coordinates")
coords.appendChild(doc.createTextNode(f"{adjusted_x},{centroid.y()},0"))
point.appendChild(coords)
label_placemark.appendChild(point)
document.appendChild(label_placemark)
# Salvar o KML temporário
kml_temp_path = output_kmz_path.replace(".kmz", ".kml")
with open(kml_temp_path, "w", encoding="utf-8") as f:
f.write(doc.toprettyxml(indent=" "))
# Criar o arquivo KMZ (KML comprimido)
with zipfile.ZipFile(output_kmz_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
zipf.write(kml_temp_path, os.path.basename(kml_temp_path))
# Remover o KML temporário
os.remove(kml_temp_path)
print(f"Arquivo KMZ criado com sucesso: {output_kmz_path}")
def create_polygon_element(doc, geometry):
"""
Cria o elemento Polygon do KML a partir de uma geometria QgsGeometry
"""
# Usar o tipo correto de QgsWkbTypes para verificar o tipo de geometria
geom_type = QgsWkbTypes.geometryType(geometry.wkbType())
if geom_type == QgsWkbTypes.PolygonGeometry:
# Verificar se é um único polígono ou multipolígono
if geometry.isMultipart():
# Para multipolígonos
multi_geom = doc.createElement("MultiGeometry")
multi_polygon = geometry.asMultiPolygon()
for polygon in multi_polygon:
poly = doc.createElement("Polygon")
outer_boundary = doc.createElement("outerBoundaryIs")
linear_ring = doc.createElement("LinearRing")
coords = doc.createElement("coordinates")
coord_str = " ".join([f"{point.x()},{point.y()},0" for point in polygon[0]])
coords.appendChild(doc.createTextNode(coord_str))
linear_ring.appendChild(coords)
outer_boundary.appendChild(linear_ring)
poly.appendChild(outer_boundary)
# Adicionar buracos, se houver
for i in range(1, len(polygon)):
inner_boundary = doc.createElement("innerBoundaryIs")
inner_ring = doc.createElement("LinearRing")
inner_coords = doc.createElement("coordinates")
inner_coord_str = " ".join([f"{point.x()},{point.y()},0" for point in polygon[i]])
inner_coords.appendChild(doc.createTextNode(inner_coord_str))
inner_ring.appendChild(inner_coords)
inner_boundary.appendChild(inner_ring)
poly.appendChild(inner_boundary)
multi_geom.appendChild(poly)
return multi_geom
else:
# Para polígonos simples
poly = doc.createElement("Polygon")
outer_boundary = doc.createElement("outerBoundaryIs")
linear_ring = doc.createElement("LinearRing")
coords = doc.createElement("coordinates")
polygon = geometry.asPolygon()
if polygon:
coord_str = " ".join([f"{point.x()},{point.y()},0" for point in polygon[0]])
coords.appendChild(doc.createTextNode(coord_str))
linear_ring.appendChild(coords)
outer_boundary.appendChild(linear_ring)
poly.appendChild(outer_boundary)
# Adicionar buracos, se houver
for i in range(1, len(polygon)):
inner_boundary = doc.createElement("innerBoundaryIs")
inner_ring = doc.createElement("LinearRing")
inner_coords = doc.createElement("coordinates")
inner_coord_str = " ".join([f"{point.x()},{point.y()},0" for point in polygon[i]])
inner_coords.appendChild(doc.createTextNode(inner_coord_str))
inner_ring.appendChild(inner_coords)
inner_boundary.appendChild(inner_ring)
poly.appendChild(inner_boundary)
return poly
# Fallback para outros tipos ou geometrias não suportadas
return doc.createElement("Polygon")
create_kmz_with_labels(
layer_name="grade_25k",
label_field="mi",
output_kmz_path= "C:/25k.kmz",
line_color="ff4aaf4d", # Verde (ABGR)
line_width=4,
label_color="ff4aaf4d", # Verde (ABGR)
label_scale=2,
min_lod_pixels=200,
char_width_factor=0
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment