Source code for fabex.utilities.internal_utils
from math import (
cos,
sqrt,
)
import numpy as np
from .numba_utils import jit
@jit(nopython=True, parallel=True, fastmath=True, cache=True)
[docs]
def _internal_x_y_distance_to(ourpoints, theirpoints, cutoff):
v1 = ourpoints[0]
v2 = theirpoints[0]
minDistSq = (v1[0] - v2[0]) ** 2 + (v1[1] - v2[1]) ** 2
cutoffSq = cutoff**2
for v1 in ourpoints:
for v2 in theirpoints:
distSq = (v1[0] - v2[0]) ** 2 + (v1[1] - v2[1]) ** 2
if distSq < cutoffSq:
return sqrt(distSq)
minDistSq = min(distSq, minDistSq)
return sqrt(minDistSq)
# don't make this @jit parallel, because it sometimes gets called with small N
# and the overhead of threading is too much.
@jit(nopython=True, fastmath=True, cache=True)
[docs]
def _optimize_internal(points, keep_points, e, protect_vertical, protect_vertical_limit):
# inlined so that numba can optimize it nicely
def _mag_sq(v1):
return v1[0] ** 2 + v1[1] ** 2 + v1[2] ** 2
def _dot_pr(v1, v2):
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
def _applyVerticalLimit(v1, v2, cos_limit):
"""Test Path Segment on Verticality Threshold, for Protect_vertical Option"""
z = abs(v1[2] - v2[2])
if z > 0:
# don't use this vector because dot product of 0,0,1 is trivially just v2[2]
# vec_up = np.array([0, 0, 1])
vec_diff = v1 - v2
vec_diff2 = v2 - v1
vec_diff_mag = np.sqrt(_mag_sq(vec_diff))
# dot product = cos(angle) * mag1 * mag2
cos1_times_mag = vec_diff[2]
cos2_times_mag = vec_diff2[2]
if cos1_times_mag > cos_limit * vec_diff_mag:
# vertical, moving down
v1[0] = v2[0]
v1[1] = v2[1]
elif cos2_times_mag > cos_limit * vec_diff_mag:
# vertical, moving up
v2[0] = v1[0]
v2[1] = v1[1]
cos_limit = cos(protect_vertical_limit)
prev_i = 0
for i in range(1, points.shape[0] - 1):
v1 = points[prev_i]
v2 = points[i + 1]
vmiddle = points[i]
line_direction = v2 - v1
line_length = sqrt(_mag_sq(line_direction))
if line_length == 0:
# don't keep duplicate points
keep_points[i] = False
continue
# normalize line direction
line_direction *= 1.0 / line_length # N in formula below
# X = A + tN (line formula) Distance to point P
# A = v1, N = line_direction, P = vmiddle
# distance = || (P - A) - ((P-A).N)N ||
point_offset = vmiddle - v1
distance_sq = _mag_sq(
point_offset - (line_direction * _dot_pr(point_offset, line_direction))
)
# compare on squared distance to save a sqrt
if distance_sq < e * e:
keep_points[i] = False
else:
keep_points[i] = True
if protect_vertical:
_applyVerticalLimit(points[prev_i], points[i], cos_limit)
prev_i = i