### ===================================================================================================================
### viia_find_min_max_z
### ===================================================================================================================
# Copyright ©2026 Haskoning Nederland B.V.
# For use by VIIA
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
import math
from typing import List
# References for functions and classes in the haskoning_datafusr_py_base package
from haskoning_datafusr_py_base.math import unit_vector, greater, smaller
### ===================================================================================================================
### 2. Function to find the minimum and maximum z-coordinates of the intersections
### ===================================================================================================================
[docs]def viia_find_min_max_z(plane_points: List[List[float]], point: List[float]):
"""
This function returns the intersections of a vertical line through a vertical plane. The plane (wall) may be angled
in x- and y- direction. The shape of the plane is free to chose, as long as it is vertical.
Input:
- plane_points (list with lists of 3 floats): The sorted points of a given plane. Coordinates in x-, y- and z-
directionm e.g. [[0,1,2],[2,3,4],[3,6,4], etc.
- point (list with 3 floats): The coordinates (x,y,z) of the requested point where vertical section is made.
The z-coordinate is not used. For example: [0.1, 0.3, 2.3]
Output:
The z-coordinates of intersections are returned as list. Should always be an even number.
For example:
>>> viia_find_min_max_z([[0.0, 0.0, -0.175], [0.0, 0.0, 2.325], [0.0, 5.0, 4.325], [0.0, 5.0, 1.825]], [0, 5])
Returns the list: [[4.325], [1.8250000000000002]]
"""
# The first found vector in x- and y- directions from the first point of the plane, determines the direction of the
# line in x- and y- projection of the plane. If the second point is vertically above the first point, the next point
# will be evaluated, etc.
for i in range(1, len(plane_points)):
deltaX0 = plane_points[i][0] - plane_points[i - 1][0]
deltaY0 = plane_points[i][1] - plane_points[i - 1][1]
r = math.sqrt(deltaX0*deltaX0 + deltaY0*deltaY0)
if r != 0:
break
# Following the contour of the plane, the delta-functions are saved in a list
z_functions = []
for i in range(0, len(plane_points)):
if i == len(plane_points)-1:
deltaX = plane_points[0][0] - plane_points[i][0]
deltaY = plane_points[0][1] - plane_points[i][1]
deltaZ = plane_points[0][2] - plane_points[i][2]
else:
deltaX = plane_points[i + 1][0] - plane_points[i][0]
deltaY = plane_points[i + 1][1] - plane_points[i][1]
deltaZ = plane_points[i + 1][2] - plane_points[i][2]
if deltaX0 == 0:
z_functions.append([deltaY/deltaY0 * r, deltaZ])
else:
z_functions.append([deltaX/deltaX0 * r, deltaZ])
### ADDED BY ROB, CHECK WORKING ###
# Check if z-functions contains consecutive functions with the same direction
# Add these up, otherwise one intersection can be found twice, when it is exactly at the point where two functions
# coincide
# Initiate counter to count number of merged functions
merge_counter = 0
for i in range(len(z_functions)):
if i-merge_counter == len(z_functions) - 1:
# Compute unit vectors of consecutive functions
uv1 = unit_vector(a=z_functions[i-merge_counter])
uv2 = unit_vector(a=z_functions[0])
# If equal, functions can be merged
if uv1 == uv2:
# Add both functions up in z_function
z_function = []
z_function.append(z_functions[i-merge_counter][0] + z_functions[0][0])
z_function.append(z_functions[i-merge_counter][1] + z_functions[0][1])
# Replace first function
z_functions[i-merge_counter] = z_function
# Delete second function
del z_functions[0]
# Update counter
merge_counter += 1
else:
uv1 = unit_vector(a=z_functions[i-merge_counter])
uv2 = unit_vector(a=z_functions[i-merge_counter+1])
if uv1 == uv2:
z_function = []
z_function.append(z_functions[i-merge_counter][0] + z_functions[i-merge_counter+1][0])
z_function.append(z_functions[i-merge_counter][1] + z_functions[i-merge_counter+1][1])
z_functions[i-merge_counter] = z_function
del z_functions[i-merge_counter+1]
merge_counter += 1
### ADDED BY ROB, CHECK WORKING ###
# Determine the requested coordinate on the line of the projection of the wall in x- and y-direction.
# This direction is called r in this function.
deltaX = point[0] - plane_points[0][0]
deltaY = point[1] - plane_points[0][1]
if deltaX0 == 0:
rc = deltaY/deltaY0 * r
else:
rc = deltaX/deltaX0 * r
# Following the contour of the plane, it is checked if the r-coordinate is defined in the delta-functions.
Intersections = []
r = 0
z = plane_points[0][2]
for i in range(len(z_functions)):
if smaller(a=r, b=rc) and smaller(a=rc, b=r + z_functions[i][0]):
if z_functions[i][0] != 0:
zc = z + z_functions[i][1]*(rc - r)/z_functions[i][0]
Intersections.append(zc)
if greater(a=r, b=rc) and greater(a=rc, b=r + z_functions[i][0]):
if z_functions[i][0] != 0:
zc = z + z_functions[i][1]*(r - rc)/-z_functions[i][0]
Intersections.append(zc)
r = r + z_functions[i][0]
z = z + z_functions[i][1]
# The intersections are returned as list (should be even number)
return Intersections
### ===================================================================================================================
### 3. End of script
### ===================================================================================================================