Initial commit

This commit is contained in:
Robert Nasarek 2026-06-25 09:09:16 +02:00
commit a437c068c8
64 changed files with 561683 additions and 0 deletions

View file

@ -0,0 +1,756 @@
import re
import config
import markup3dmodule as m3dm
import polygon3dmodule as p3dm
import json
import numpy as np
import open3d as o3d
import open3d.core as o3c
import os
# Function to create triangles at each corner in 3D
def create_corner_triangles(box_points, triangle_size=1):
triangles = []
for i, point in enumerate(box_points):
x, y, z = point
if i == 0: # Bottom-left-front corner
triangles.append([[x, y, z], [x + triangle_size, y, z], [x, y + triangle_size, z]])
elif i == 1: # Bottom-right-front corner
triangles.append([[x, y, z], [x - triangle_size, y, z], [x, y + triangle_size, z]])
elif i == 2: # Top-left-front corner
triangles.append([[x, y, z], [x + triangle_size, y, z], [x, y - triangle_size, z]])
elif i == 3: # Bottom-left-back corner
triangles.append([[x, y, z], [x + triangle_size, y, z], [x, y + triangle_size, z]])
elif i == 4: # Top-right-back corner
triangles.append([[x, y, z], [x - triangle_size, y, z], [x, y - triangle_size, z]])
elif i == 5: # Top-left-back corner
triangles.append([[x, y, z], [x + triangle_size, y, z], [x, y - triangle_size, z]])
elif i == 6: # Bottom-right-back corner
triangles.append([[x, y, z], [x - triangle_size, y, z], [x, y + triangle_size, z]])
elif i == 7: # Top-right-front corner
triangles.append([[x, y, z], [x - triangle_size, y, z], [x, y - triangle_size, z]])
return triangles
def addTranslationParameters(e, i, trans_param):
# Convert lists to numpy arrays for easier manipulation
e = np.array(e)
# i = np.array(i)
i_translated = []
trans_param = np.array(trans_param)
# case distinction for empty translation parameters
if len(trans_param) > 0:
# Subtract the translation parameters from each point
if len(e) > 0:
e_translated = e - trans_param
elif len(e) == 0:
e_translated = np.asarray([])
# Iterate over all the different interior rings
if len(i) > 0:
for interior_ring in i:
interior_ring = np.asarray(interior_ring)
# Translate the interior ring
interior_ring_translated = interior_ring - trans_param
# Coollect the translated interior rings
i_translated.append(interior_ring_translated.tolist())
else:
i_translated = i
return e_translated.tolist(), i_translated
else:
return e.tolist(), i
def getBufferedBBoxPoints(b):
# Schritt 1: identifying all wallsurfaces and roof surfaces of the building
output = {}
specifyVersion()
# comprehensive list of semantic surfaces
semanticSurfaces = ['GroundSurface', 'WallSurface', 'RoofSurface', 'ClosureSurface', 'CeilingSurface', ]
for semanticSurface in semanticSurfaces:
output[semanticSurface] = []
data = []
for cl in output:
cls = []
for child in b.getiterator():
if child.tag == '{%s}%s' % (ns_bldg, cl):
cls.append(child)
for feature in cls:
for p in feature.findall('.//{%s}Polygon' % ns_gml):
e, i = m3dm.polydecomposer(p)
epoints = m3dm.GMLpoints(e[0])
# -- Clean recurring points, except the last one
last_ep = epoints[-1]
epoints_clean = list(remove_reccuring(epoints))
epoints_clean.append(last_ep)
for point in epoints_clean:
data.append(point)
# Schritt 2: Idetify the Bounding volume
# 2.1 creating an open3d pointcloud from all the idetified vertex points
pcd = o3d.t.geometry.PointCloud(o3c.Tensor(data, o3c.float32))
# 2.2 obtain the axis aligned boundign box of the point cloud
axis_aligned_bb = pcd.get_axis_aligned_bounding_box()
# Schritt 3: Construct small triangles that describe the boundign box sufficienly
box_points = axis_aligned_bb.get_box_points().numpy().tolist()
# Convert the list to a numpy array for easier manipulation
box_points = np.array(box_points)
# Calculate the min and max coordinates
min_x, min_y, min_z = np.min(box_points, axis=0)
max_x, max_y, max_z = np.max(box_points, axis=0)
# Add a 3m buffer
buffer = 3
min_x -= buffer
min_y -= buffer
min_z -= buffer
max_x += buffer
max_y += buffer
max_z += buffer
# Define the buffered bounding box points
buffered_box_points = np.array([
[min_x, min_y, min_z],
[max_x, min_y, min_z],
[min_x, max_y, min_z],
[min_x, min_y, max_z],
[max_x, max_y, max_z],
[min_x, max_y, max_z],
[max_x, min_y, max_z],
[max_x, max_y, min_z]
])
return buffered_box_points
def obtainSRSInfo(root):
specifyVersion()
# obtain the envelope object
envelopes = []
for envelope in root.getiterator('{%s}Envelope' % ns_gml):
envelopes.append(envelope)
# Extracting the srsName attribute from each Envelope
srs_names = [envelope.get('srsName') for envelope in envelopes]
srs_Dimensions = [envelope.get('srsDimension') for envelope in envelopes]
return srs_names, srs_Dimensions
# This function is used to create a corresponding json file defining the bbox of an object for each corresponding obj file
def writeBBOXJSON(b, overall_counter, path, b_counter, trans_param):
if len(trans_param) > 0:
translation_parameters = {
"d_x": str(trans_param[0]),
"d_y": str(trans_param[1]),
"d_z": str(trans_param[2])
}
else:
translation_parameters = {
"d_x": str(0),
"d_y": str(0),
"d_z": str(0)
}
buffered_box_points_global = getBufferedBBoxPoints(b)
# translate to the local coordinate system
buffered_box_points, _ = addTranslationParameters(buffered_box_points_global, [], trans_param=trans_param)
# From this set of points, obtain the minimum set that is necessary to describe the bounding box.
min_point = buffered_box_points[0]
max_point = buffered_box_points[4]
# Construct the json file path
json_file_path = str(path) + str(b_counter) + "_" + str(overall_counter) + "_bbox_" + ".json"
# Write the bbox to a designated json file
# Prüfen, ob die JSON-Datei existiert und laden
if os.path.exists(json_file_path):
with open(json_file_path, 'r') as json_file:
axis_aligned_bbox = json.load(json_file)
else:
axis_aligned_bbox = {}
# Neuen Identifier hinzufügen
axis_aligned_bbox["axis_aligned_bbox"] = {
"min_point": str(min_point),
"max_point": str(max_point),
"translation_parameters": translation_parameters
}
# Zuordnungen in JSON-Datei schreiben
with open(json_file_path, 'w') as json_file:
json.dump(axis_aligned_bbox, json_file, indent=4)
return 0
# This function is used to add information about the used spatial reference system to the json file
def addCRSToJSON(root, json_file_path):
specifyVersion()
# obtain the envelope object
envelopes = []
for envelope in root.getiterator('{%s}Envelope' % ns_gml):
envelopes.append(envelope)
if envelopes:
# Extracting the srsName attribute from each Envelope
srs_names = [envelope.get('srsName') for envelope in envelopes]
srs_Dimensions = [envelope.get('srsDimension') for envelope in envelopes]
elif not envelopes:
srs_names = "Unkown"
srs_Dimensions = "Unkown"
used_srs = srs_names[0]
# Prüfen, ob die JSON-Datei existiert und laden
if os.path.exists(json_file_path):
with open(json_file_path, 'r') as json_file:
crs_info = json.load(json_file)
else:
crs_info = {}
# Neuen Identifier hinzufügen
crs_info["CRS"] = {
"srsName": used_srs,
"srsDimensions": srs_Dimensions
}
# Zuordnungen in JSON-Datei schreiben
with open(json_file_path, 'w') as json_file:
json.dump(crs_info, json_file, indent=4)
return 0
def claculateCornerTriangles(b, trans_param):
buffered_box_points = getBufferedBBoxPoints(b)
# Translate the Bounding box into the local coordinate system
# buffered_box_points, _ = addTranslationParameters(buffered_box_points_global, [], trans_param=trans_param)
# Create triangles at the corners of the buffered bounding box
corner_triangles = create_corner_triangles(buffered_box_points)
# Convert the triangles to lists
corner_triangles = [np.array(triangle).tolist() for triangle in corner_triangles]
print("\nCorner Triangles:")
for i, triangle in enumerate(corner_triangles):
print(f"Triangle {i + 1}: {triangle}")
return corner_triangles
# diese funktion dient dazu ein JSON file zu schreiben um die meta informationen über die einzelnen objekte zuspeichern
def add_identifier_to_json(filename, tag, parentID, gmlID, json_file_path):
"""
Adds the identifier information for one .obj file to a JSON file.
Parameters:
- number (int): The number corresponding to the .obj file.
- tag (str): The tag corresponding to the .obj file.
- parentID (str): The parent ID corresponding to the .obj file.
- gmlID (str): The gml ID corresponding to the .obj file.
- json_file_path (str): Path to the JSON file where identifier information will be stored.
"""
# Prüfen, ob die JSON-Datei existiert und laden
if os.path.exists(json_file_path):
with open(json_file_path, 'r') as json_file:
identifiers = json.load(json_file)
else:
identifiers = {}
# Neuen Identifier hinzufügen
identifiers[filename] = {
'tag': tag,
'parentID': parentID,
'gmlID': gmlID
}
# Zuordnungen in JSON-Datei schreiben
with open(json_file_path, 'w') as json_file:
json.dump(identifiers, json_file, indent=4)
print(f"Zuordnung für {filename} wurde gespeichert.")
def perturb_points(points, perturbation_scale=1e-6):
"""
Perturb the points slightly to avoid degenerate cases.
Parameters:
points (list of tuple of floats): A list where each element is a tuple (x, y, z) representing a 3D point.
perturbation_scale (float): The maximum magnitude of the perturbation applied to each coordinate.
Returns:
list of list of floats: Perturbed list of points.
"""
points_array = np.array(points)
perturbation = np.random.uniform(-perturbation_scale, perturbation_scale, points_array.shape)
perturbed_points = points_array + perturbation
return perturbed_points.tolist()
def write_obj_file(surfaces, filename, tag, parentid, gmlid, counter, path, tr_1, translation_parameters):
for triangle in tr_1:
triangle_local, _ = addTranslationParameters(triangle, [], trans_param=translation_parameters)
surfaces.append(triangle_local)
with open(filename, 'w') as file:
vertex_index = 1
for triangle in surfaces:
for vertex in triangle:
file.write(f"v {vertex[0]} {vertex[1]} {vertex[2]}\n")
file.write(f"f {vertex_index} {vertex_index + 1} {vertex_index + 2}\n")
vertex_index += 3
add_identifier_to_json(filename, tag, parentid, gmlid, (path + "index.json"))
def remove_reccuring(list_vertices):
"""Removes recurring vertices, which messes up the triangulation.
Inspired by http://stackoverflow.com/a/1143432"""
# last_point = list_vertices[-1]
list_vertices_without_last = list_vertices[:-1]
found = set()
for item in list_vertices_without_last:
if str(item) not in found:
yield item
found.add(str(item))
def separate_string(s):
# Define the regex pattern
pattern = r'\{([^}]*)\}(.*)'
# Search for the pattern in the input string
match = re.search(pattern, s)
if match:
# Extract the parts
inside_braces = match.group(1)
outside_braces = match.group(2)
return inside_braces, outside_braces
else:
return None, None
def specifyVersion():
global ns_citygml
global ns_gml
global ns_bldg
global ns_xsi
global ns_xAL
global ns_xlink
global ns_dem
global ns_con
global ns_app
global ns_pcl
global ns_gen
global ns_gss
global ns_pfx0
global ns_gsr
global ns_tran
global ns_gmd
global ns_gts
global ns_veg
global ns_frn
global ns_tun
global ns_wtr
global nsmap
if config.getVersion() == 1:
# -- Name spaces for CityGML 2.0
ns_citygml = "http://www.opengis.net/citygml/1.0"
ns_gml = "http://www.opengis.net/gml"
ns_bldg = "http://www.opengis.net/citygml/building/1.0"
ns_tran = "http://www.opengis.net/citygml/transportation/1.0"
ns_veg = "http://www.opengis.net/citygml/vegetation/1.0"
ns_gen = "http://www.opengis.net/citygml/generics/1.0"
ns_xsi = "http://www.w3.org/2001/XMLSchema-instance"
ns_xAL = "urn:oasis:names:tc:ciq:xsdschema:xAL:1.0"
ns_xlink = "http://www.w3.org/1999/xlink"
ns_dem = "http://www.opengis.net/citygml/relief/1.0"
ns_frn = "http://www.opengis.net/citygml/cityfurniture/1.0"
ns_tun = "http://www.opengis.net/citygml/tunnel/1.0"
ns_wtr = "http://www.opengis.net/citygml/waterbody/1.0"
ns_brid = "http://www.opengis.net/citygml/bridge/1.0"
ns_app = "http://www.opengis.net/citygml/appearance/1.0"
if config.getVersion() == 2:
# -- Name spaces for CityGML 2.0
ns_citygml = "http://www.opengis.net/citygml/2.0"
ns_gml = "http://www.opengis.net/gml"
ns_bldg = "http://www.opengis.net/citygml/building/2.0"
ns_xsi = "http://www.w3.org/2001/XMLSchema-instance"
ns_xAL = "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"
ns_xlink = "http://www.w3.org/1999/xlink"
ns_dem = "http://www.opengis.net/citygml/relief/2.0"
elif config.getVersion() == 3:
# -- Name spaces for CityGML 3.0
ns_citygml = "http://www.opengis.net/citygml/3.0"
ns_con = "http://www.opengis.net/citygml/construction/3.0"
ns_xlink = "http://www.w3.org/1999/xlink"
ns_gml = "http://www.opengis.net/gml/3.2"
ns_bldg = "http://www.opengis.net/citygml/building/3.0"
ns_app = "http://www.opengis.net/citygml/appearance/3.0"
ns_pcl = "http://www.opengis.net/citygml/pointcloud/3.0"
ns_gen = "http://www.opengis.net/citygml/generics/3.0"
ns_gss = "http://www.isotc211.org/2005/gss"
ns_pfx0 = "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"
ns_gsr = "http://www.isotc211.org/2005/gsr"
ns_xsi = "http://www.w3.org/2001/XMLSchema-instance"
ns_tran = "http://www.opengis.net/citygml/transportation/3.0"
ns_gmd = "http://www.isotc211.org/2005/gmd"
ns_gts = "http://www.isotc211.org/2005/gts"
ns_veg = "http://www.opengis.net/citygml/vegetation/3.0"
ns_xAL = "urn:oasis:names:tc:ciq:xal:3"
ns_dem = "http://www.opengis.net/citygml/relief/3.0"
ns_frn = "http://www.opengis.net/citygml/cityfurniture/3.0"
ns_tun = "http://www.opengis.net/citygml/tunnel/3.0"
ns_wtr = "http://www.opengis.net/citygml/waterbody/3.0"
nsmap = {
None: ns_citygml,
'gml': ns_gml,
'bldg': ns_bldg,
'xsi': ns_xsi,
'xAL': ns_xAL,
'xlink': ns_xlink,
'dem': ns_dem
}
def compute_convex_hull(points):
"""
Computes the convex hull of a set of 3D points using Open3D, including triangulation of the hull's faces.
Parameters:
points (list of tuple of floats): A list where each element is a tuple (x, y, z) representing a 3D point.
Returns:
list: A list of faces, where each face is a list of vertex coordinates forming that face.
"""
# Convert the list of points to a NumPy array
points_array = np.array(points)
perturbed_points = perturb_points(points_array)
# Create an Open3D PointCloud object
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(perturbed_points)
# Compute the convex hull
hull, triangles = pcd.compute_convex_hull()
# Extract vertices and faces (triangles)
hull_vertices = np.asarray(hull.vertices)
hull_triangles = np.asarray(hull.triangles)
# Prepare the faces in the desired format
faces = []
for triangle in hull_triangles:
face = [list(hull_vertices[vertex]) for vertex in triangle]
faces.append(face)
return faces
def process_polygon(p, trans_param):
e = p[0]
i = p[1]
e_trans, i_trans = addTranslationParameters(e, i, trans_param=trans_param)
t = p3dm.triangulation(e_trans, i_trans)
# print(f"t: {t}")
return t
def process_polygons_parallel(polys, trans_param):
data = []
results = []
for poly in polys:
e, i = m3dm.polydecomposer(poly)
epoints = m3dm.GMLpoints(e[0])
# -- Clean recurring points, except the last one
last_ep = epoints[-1]
epoints_clean = list(remove_reccuring(epoints))
epoints_clean.append(last_ep)
# -- LinearRing(s) forming the interior
irings = []
for iring in i:
ipoints = m3dm.GMLpoints(iring)
# -- Clean them in the same manner as the exterior ring
last_ip = ipoints[-1]
ipoints_clean = list(remove_reccuring(ipoints))
ipoints_clean.append(last_ip)
irings.append(ipoints_clean)
if len(epoints_clean) > 4:
t = process_polygon([epoints_clean, irings], trans_param=trans_param)
results.append(t)
# data.append(poly_components)
if len(epoints_clean) == 4:
epoints_clean_translated, _ = addTranslationParameters(epoints_clean, [], trans_param=trans_param)
results.append([epoints_clean_translated])
# t = process_polygon(poly)
# results.append(t)
# cpu_cores = os.cpu_count()
# print(f'Number of available CPU cores (using os): {cpu_cores}')
# with ThreadPoolExecutor(max_workers=cpu_cores) as executor:
# # Submitting all tasks
# futures = [executor.submit(process_polygon, p) for p in data]
# # Collecting results
# for future in futures:
# result = future.result() # This will re-raise any exception caught during the execution of the task
# results.append(result)
return results
# this is an experimental method for parallelization
def processOpening(o, path, buildingid, overall_counter, tr_1, trans_param, b_counter):
for child in o.getiterator():
unique_identifier = child.xpath("@g:id", namespaces={'g': ns_gml})
if child.tag == '{%s}Window' % ns_bldg or child.tag == '{%s}Door' % ns_bldg:
polys = m3dm.polygonFinder(o)
t = process_polygons_parallel(polys, trans_param=trans_param)
triangles = []
for poly in t:
for tr in poly:
triangles.append(tr)
filename = path + str(b_counter) + "_" + str(overall_counter) + ".obj"
write_obj_file(triangles, filename, str(child.tag), buildingid, unique_identifier, overall_counter, path,
tr_1, trans_param)
def getAllExteriorPoints(polys):
data = []
for poly in polys:
e, i = m3dm.polydecomposer(poly)
epoints = m3dm.GMLpoints(e[0])
# -- Clean recurring points, except the last one
last_ep = epoints[-1]
epoints_clean = list(remove_reccuring(epoints))
epoints_clean.append(last_ep)
for point in epoints_clean:
data.append(point)
return data
def processWithApproximatedWindows(o, path, buildingid, overall_counter, tr_1, translation_parameters, b_counter):
for child in o.getiterator():
unique_identifier = child.xpath("@g:id", namespaces={'g': ns_gml})
if child.tag == '{%s}Window' % ns_bldg or child.tag == '{%s}Door' % ns_bldg:
polys = m3dm.polygonFinder(o)
exterior_points = getAllExteriorPoints(polys)
t_global = compute_convex_hull(exterior_points)
_, t = addTranslationParameters(e=[], i=t_global, trans_param=translation_parameters)
filename = path + str(b_counter) + "_" + str(overall_counter) + ".obj"
write_obj_file(t, filename, str(child.tag), buildingid, unique_identifier, overall_counter, path, tr_1,
translation_parameters=translation_parameters)
# This function is used to im port a bounding box that is associated to the corresponding building component
# It still has to be tested if it works
def importBoundingBox(pathToBoundingBoxFile, trans_param):
print("Hier")
keys = ["_xmin", "_xmax", "_ymin", "_ymax", "_zmin", "_zmax"]
values = {}
with open(pathToBoundingBoxFile, 'r') as file:
for _ in range(15):
line = file.readline()
for key in keys:
match = re.search(f'"{key}"\s*:\s*([-0-9.]+)', line)
if match:
values[key] = float(match.group(1))
if not all(k in values for k in keys):
raise ValueError("Missing bounding box values in the first 15 lines")
min_x, max_x = values["_xmin"], values["_xmax"]
min_y, max_y = values["_ymin"], values["_ymax"]
min_z, max_z = values["_zmin"], values["_zmax"]
print(f"min x: {min_x} min y: {min_y} , min z: {min_z}")
print(f"max x: {max_x} max y: {max_y} , max z: {max_z}")
box_points = np.array([
[min_x, min_y, min_z],
[max_x, min_y, min_z],
[min_x, max_y, min_z],
[min_x, min_y, max_z],
[max_x, max_y, max_z],
[min_x, max_y, max_z],
[max_x, min_y, max_z],
[max_x, max_y, min_z]
])
# Create triangles at the corners of the buffered bounding box
corner_triangles = create_corner_triangles(box_points)
# Convert the triangles to lists
corner_triangles = [np.array(triangle).tolist() for triangle in corner_triangles]
print("\nCorner Triangles:")
for i, triangle in enumerate(corner_triangles):
print(f"Triangle {i + 1}: {triangle}")
return corner_triangles
def separateComponents(b, path, APPROXIMATEWINDOWS, ADDBOUNDINGBOX, ADDBOUNDINGBOXJSON, TRANSLATEBUILDINGS,
IMPORTBOUNDINGBOX, b_counter):
if TRANSLATEBUILDINGS:
# Step 1: Obtain the axis oriented bounding box of the building
bounding_box_points = getBufferedBBoxPoints(b)
# Step 2 calculate the mean value of the points that the bbox points
translation_parameters = np.mean(bounding_box_points, axis=0)
if not TRANSLATEBUILDINGS: # todo: nocheinmal üerlegen ob man hier nicht vielleicht besser elif oder so nehmen sollte
translation_parameters = []
if IMPORTBOUNDINGBOX != None:
ADDBOUNDINGBOX = False # make sure that the bounding box is not calculated
# Option to include the small triangles to mark the buffered bounding box
if ADDBOUNDINGBOX:
tr_1 = claculateCornerTriangles(b, trans_param=translation_parameters)
elif not ADDBOUNDINGBOX:
tr_1 = []
global overall_counter
overall_counter = 0
output = {}
specifyVersion()
# comprehensive list of semantic surfaces
semanticSurfaces = ['GroundSurface', 'WallSurface', 'RoofSurface', 'ClosureSurface', 'CeilingSurface',
'InteriorWallSurface', 'FloorSurface', 'OuterCeilingSurface', 'OuterFloorSurface', 'Door',
"outerBuildingInstallation",
'Window', "BuildingInstallation", "BuildingConstructiveElement"]
for semanticSurface in semanticSurfaces:
output[semanticSurface] = []
# get the building id for the building
buildingid = b.xpath("@g:id", namespaces={'g': ns_gml})
# Handle the case when a building has no gml:id - This should however never occur...
if not buildingid:
buildingid = b_counter
# Todo: Muss noch implementiert werden
# Import the bounding box
if IMPORTBOUNDINGBOX != None:
pathToBoundingBoxFile = IMPORTBOUNDINGBOX + "/" + str(buildingid) + ".json"
tr_1 = importBoundingBox(pathToBoundingBoxFile=pathToBoundingBoxFile, trans_param=translation_parameters)
if config.getVersion() != 3:
openings = []
openingpolygons = []
for child in b.getiterator():
if child.tag == '{%s}opening' % ns_bldg:
openings.append(child)
for o in child.findall('.//{%s}Polygon' % ns_gml):
openingpolygons.append(o)
for o in openings:
# print("approximate windows: ", APPROXIMATEWINDOWS)
if APPROXIMATEWINDOWS:
processWithApproximatedWindows(o, path, buildingid, overall_counter, tr_1=tr_1,
translation_parameters=translation_parameters, b_counter=b_counter)
if not APPROXIMATEWINDOWS:
processOpening(o, path, buildingid, overall_counter, tr_1, trans_param=translation_parameters,
b_counter=b_counter)
if ADDBOUNDINGBOXJSON:
writeBBOXJSON(b, overall_counter=overall_counter, path=path, b_counter=b_counter,
trans_param=translation_parameters)
overall_counter += 1
if config.getVersion() == 3:
openingpolygons = []
print("Component separation for CityGML 3.0 is not implemented yet.")
# todo: muss noch implementiert werden
# -- Process other thematic boundaries
for cl in output:
cls = []
for child in b.getiterator():
if child.tag == '{%s}%s' % (ns_bldg, cl):
cls.append(child)
for feature in cls:
# -- If it is the first feature, print the object identifier
unique_identifier = feature.xpath("@g:id", namespaces={
'g': ns_gml})
if str(unique_identifier) != "[]" or str(unique_identifier) == "[]":
cleaned_filename = str(unique_identifier)
# -- This is not supposed to happen, but just to be sure...
if feature.tag == '{%s}Window' % ns_bldg or feature.tag == '{%s}Door' % ns_bldg:
continue
tag = feature.tag
_, cleaned_tag = separate_string(tag)
# -- Find all polygons in this semantic boundary hierarchy
poly_t = []
t_ges = []
number_of_polygons = len(feature.findall('.//{%s}Polygon' % ns_gml))
pcounter = 0
print(f"there are {number_of_polygons} polygons there!")
for p in feature.findall('.//{%s}Polygon' % ns_gml):
found_opening = False
for optest in openingpolygons:
if p == optest:
found_opening = True
break
# -- If there is an opening skip it
if found_opening:
pass
else:
# -- Decompose the polygon into exterior and interior
e, i = m3dm.polydecomposer(p)
# -- Points forming the exterior LinearRing
epoints = m3dm.GMLpoints(e[0])
# -- Clean recurring points, except the last one
last_ep = epoints[-1]
epoints_clean = list(remove_reccuring(epoints))
epoints_clean.append(last_ep)
# -- LinearRing(s) forming the interior
irings = []
for iring in i:
ipoints = m3dm.GMLpoints(iring)
# -- Clean them in the same manner as the exterior ring
last_ip = ipoints[-1]
ipoints_clean = list(remove_reccuring(ipoints))
ipoints_clean.append(last_ip)
irings.append(ipoints_clean)
# Applying the translation parameters
e_trans, i_trans = addTranslationParameters(e=epoints_clean, i=irings,
trans_param=translation_parameters)
try:
if len(epoints_clean) > 4:
t = p3dm.triangulation(e_trans, i_trans)
# print("Nur drei Punkte")
poly_t.append(t)
if len(epoints_clean) == 4:
t = e_trans[0:3]
poly_t.append([t])
if len(epoints_clean) < 3:
t = []
# print("Empty Surface!")
except:
t = []
for surfaces in poly_t:
t_ges = t_ges + surfaces
pcounter += 1
if pcounter % 100 == 0:
print(pcounter)
filename = path + str(b_counter) + "_" + str(overall_counter) + ".obj"
if ADDBOUNDINGBOXJSON:
writeBBOXJSON(b, overall_counter=overall_counter, path=path, b_counter=b_counter,
trans_param=translation_parameters)
write_obj_file(t_ges, filename, str(feature.tag), buildingid, cleaned_filename, overall_counter, path,
tr_1, translation_parameters=translation_parameters)
overall_counter += 1
print("Segmentation finished!")
return 0