Source code for ddg.conversion.nets.geometry.subspaces

import numpy as np
from ddg.datastructures.nets.net import (SmoothNet, SmoothCurve, PointNet,
                                         EmptyNet)
import ddg.datastructures.nets.utils as nutils


[docs]def subspace_to_smooth_net(subspace, affine=False, convex=False, affine_component=-1): """Convert a subspace to a smooth net. Parameters ---------- subspace : ddg.geometry.subspaces.Subspace affine : bool (default=False) Whether the resulting smooth net should return homogeneous or affine coordinates. Note that this works by parametrizing using one of the two parametrizations explained below and then dehomogenizing, so if the parametrization produces points at infinity, you will get errors. convex : bool (default=False) Which parametrization to use. Let k=subspace.dimension and let the ai be the parameters given to the resulting net. ``convex=False`` takes k+1 parameters and gives :: a0 * v0 + ... + ak * vk where v0,...,vk are the k+1 homogeneous coordinate vectors spanning the subspace given in ``subspace.points``. ``convex=True`` can only be used if the subspace is not at infinity. It takes k parameters and gives:: ((1 - a1 * u1[i] - ... - ak * uk[i]) / u0[i]) * u0 + a1 * u1 + ... + ak * uk where `i` is `affine_component`. The basis u0,...,uk is just the given basis ``subspace.points``, but permuted: The first vector not at infinity is moved to the first position. Note that this can also be written as:: u0 / u0[i] + a1 * (u1 - (u1[i] / u0[i]) * u0) + ... + ak * (uk - (uk[i] / u0[i]) * u0) If `subspace` is a point, this parameter has no effect. The returned net will just be a PointNet with the homogeneous or affine coordinates. affine_component : int (default=-1) Used to dehomogenize. Returns ------- SmoothNet, SmoothCurve, PointNet or EmptyNet Raises ------ ValueError If `convex` is True and subspace is at infinity. """ # Empty space if subspace.dimension == -1: # subspace.matrix is empty with shape (k+1, 0) return EmptyNet(subspace.matrix) # Point # This is an exception to the convex=False parametrization. Strictly # speaking, a converted Point should be returned as a smooth curve, but I # feel this is more useful. elif subspace.dimension == 0: if affine: return PointNet(subspace.affine_point(affine_component)) else: return PointNet(subspace.point) if convex: if subspace.at_infinity(affine_component): raise ValueError("To use the 'convex' parametrization, the " "subspace can not be at infinity.") i = affine_component mask = np.full(subspace.dimension + 1, True) # Search for a point not at infinity to use as center for idx, u0 in enumerate(subspace.points): if not np.isclose(u0[i], 0, atol=subspace.atol, rtol=subspace.rtol): mask[idx] = False break def f(*coeffs): a0 = (1 - np.dot(coeffs, subspace.matrix[i, mask])) / u0[i] return a0 * u0 + subspace.matrix[:, mask] @ coeffs if subspace.dimension == 1: net = SmoothCurve(f, [-np.inf, np.inf]) else: net = SmoothNet(f, [[-np.inf, np.inf]] * subspace.dimension) else: def f(*coeffs): if all([c == 0 for c in coeffs]): raise ValueError("Zero vector is not a valid homogeneous " "coordinate vector.") return subspace.matrix @ coeffs net = SmoothNet(f, [[-np.inf, np.inf]] * (subspace.dimension + 1)) if affine: nutils.dehomogenize(net, affine_component=affine_component) return net