import ddg.datastructures.nets.net as net
import ddg.datastructures.nets.utils as nutils
import ddg.math.symmetric_matrices as sm
import ddg.datastructures.nets.net_generators.quadrics as qng
[docs]def quadric_to_smooth_net(quadric, affine=False, affine_component=-1):
"""Convert a quadric to a smooth net.
Currently supported are all quadrics contained in lines, planes or 3D
subspaces.
Parameters
----------
quadric : Quadric
affine : bool (default=False)
Whether the resulting net should return affine or homogeneous
coordinates.
affine_component : int (default=-1)
Used to determine parametrization and optionally dehomogenize. This is
one of the rare cases where this has an effect even if affine=False.
Returns
-------
SmoothNet, SmoothCurve, EmptyNet, PointNet or NetCollection
Resulting smooth net.
"""
sgn = quadric.signature(affine=True, affine_component=affine_component)
Q = quadric.normalize(affine=True, affine_component=affine_component)
B = Q.subspace.matrix
net_fct = _SGN_DICT[sgn].get('net_fct')
net_args = _SGN_DICT[sgn].get('net_args', {})
if net_fct is None:
raise KeyError(f"Unknown signature: {repr(sgn)}")
s = net_fct(**net_args)
# Parametrization in B - coordinates
nutils.homogenize(s)
# Final parametrization in the ambient space
s.transform(B)
if affine:
nutils.dehomogenize(s, affine_component=affine_component)
return s
_SGN_DICT = {
#########################
# Conics (?) in 0D space
#########################
sm.AffineSignature(2, 0): {
# complex quadric
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0.], 'name': 'ComplexQuadric'}
},
sm.AffineSignature(1, 1, affine_component_entry=-1): {
# two points
'net_fct': qng.two_points
},
sm.AffineSignature(1, 0, 1, affine_component_entry=0): {
# double point (?)
'net_fct': net.PointNet,
'net_args': {'value': [0.], 'name': 'DoublePoint'}
},
sm.AffineSignature(1, 0, 1, affine_component_entry=1): {
# point at infinity
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0.], 'name': 'PointAtInfinity'}
},
sm.AffineSignature(0, 0, 2): {
# fully degenerate
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0.], 'name': 'FullyDegenerateQuadric'}
},
sm.AffineSignature(1, 1, affine_component_entry='parabolic'): {
# one point (and one at infinity)
'net_fct': net.PointNet,
'net_args': {'value': [0.], 'name': 'OnePoint'}
},
#####################
# Conics in 2D space
#####################
# non-parabolic cases
# non-degenerate
sm.AffineSignature(3, 0): {
# complex conic
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0.], 'name': 'ComplexConic'}
},
sm.AffineSignature(2, 1, affine_component_entry=-1): {
# ellipse
'net_fct': qng.circle
},
sm.AffineSignature(2, 1, affine_component_entry=1): {
# hyperbola
'net_fct': qng.hyperbola
},
# once degenerate
sm.AffineSignature(2, 0, 1, affine_component_entry=0): {
# single point (two intersecting complex lines)
'net_fct': net.PointNet,
'net_args': {'value': [0., 0.], 'name': 'ConjugateLines'}
},
sm.AffineSignature(1, 1, 1, affine_component_entry=-1): {
# pair of parallel lines
'net_fct': qng.linepair
},
sm.AffineSignature(1, 1, 1, affine_component_entry=0): {
# pair of intersecting lines
'net_fct': qng.interline
},
sm.AffineSignature(2, 0, 1, affine_component_entry=1): {
# empty (complex lines)
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0.], 'name': 'ConjugateParallelLines'}
},
# twice degenerate
sm.AffineSignature(1, 0, 2, affine_component_entry=0): {
# double line
'net_fct': qng.cline,
'net_args': {'name': 'DoubleLine'}
},
sm.AffineSignature(1, 0, 2, affine_component_entry=1): {
# empty (double line at infinity)
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0.], 'name': 'DoubleLineInfty'}
},
# fully degenerate
sm.AffineSignature(0, 0, 3): {
# empty
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0.], 'name': 'FullyDegenerateConic'}
},
# parabolic cases
# non-degenerate
sm.AffineSignature(2, 1, affine_component_entry='parabolic'): {
# parabola
'net_fct': qng.parabola
},
# degenerate
sm.AffineSignature(1, 1, 1, affine_component_entry='parabolic'): {
# one line (and one at infinity)
'net_fct': qng.cline,
'net_args': {'rot': True, 'name': 'OneLine'}
},
#######################
# Quadrics in 3D space
#######################
# non-parabolic cases
# non-degenerate
sm.AffineSignature(4, 0): {
# complex quadric
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0., 0.], 'name': 'ComplexQuadric'}
},
sm.AffineSignature(3, 1, affine_component_entry=-1): {
# sphere
'net_fct': qng.sphere
},
sm.AffineSignature(3, 1, affine_component_entry=1): {
# two-sheeted hyperboloid
'net_fct': qng.hyperboloid_two_sheeted,
'net_args': {'axis': 2}
},
# one-sheeted hyperboloid
sm.AffineSignature(2, 2, affine_component_entry=-1): {
'net_fct': qng.hyperboloid_one_sheeted,
'net_args': {'axis': 0}
},
# once degenerate
sm.AffineSignature(3, 0, 1, affine_component_entry=0): {
# one point (complex cone with real vertex)
'net_fct': net.PointNet,
'net_args': {'value': [0., 0., 0.], 'name': 'ComplexCone'}
},
sm.AffineSignature(2, 1, 1, affine_component_entry=0): {
# cone
'net_fct': qng.cone
},
sm.AffineSignature(3, 0, 1, affine_component_entry=1): {
# empty (complex cylinder with vertex at infinity)
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0., 0.], 'name': 'ComplexCylinder'}
},
sm.AffineSignature(2, 1, 1, affine_component_entry=1): {
# hyperbolic cylinder
'net_fct': qng.cylinder_hyperbolic,
'net_args': {'rot': True}
},
sm.AffineSignature(2, 1, 1, affine_component_entry=-1): {
# elliptic cylinder
'net_fct': qng.cylinder_elliptic
},
# twice degenerate
sm.AffineSignature(2, 0, 2, affine_component_entry=0): {
# one line (two complex conjugate planes)
'net_fct': qng.line,
'net_args': {'name': 'ConjugatePlanes'}
},
sm.AffineSignature(1, 1, 2, affine_component_entry=0): {
# two intersecting planes
'net_fct': qng.planes_intersecting,
'net_args': {'name': 'Planes'}
},
sm.AffineSignature(2, 0, 2, affine_component_entry=1): {
# empty (two complex conjugate planes intersecting at infinity)
'net_fct': net.EmptyNet,
'net_args': {
'coordinates': [0., 0., 0.],
'name': 'ConjugateParallelPlanes'
}
},
sm.AffineSignature(1, 1, 2, affine_component_entry=1): {
# two parallel planes
'net_fct': qng.planes_parallel,
'net_args': {'name': 'ParallelPlanes'}
},
# thrice degenerate
sm.AffineSignature(1, 0, 3, affine_component_entry=0): {
# double plane
'net_fct': qng.plane,
'net_args': {'axis': 0, 'name': 'DoublePlane'}
},
sm.AffineSignature(1, 0, 3, affine_component_entry=1): {
# empty (double plane at infinity)
'net_fct': net.EmptyNet,
'net_args': {'coordinates': [0., 0., 0.], 'name': 'DoublePlaneInfty'}
},
# fully degenerate
sm.AffineSignature(0, 0, 4): {
'net_fct': net.EmptyNet,
'net_args': {
'coordinates': [0., 0., 0.],
'name': 'FullyDegenerateQuadric'
}
},
# parabolic cases
# non-degenerate
sm.AffineSignature(3, 1, affine_component_entry='parabolic'): {
# elliptic paraboloid
'net_fct': qng.paraboloid_elliptic
},
sm.AffineSignature(2, 2, affine_component_entry='parabolic'): {
# hyperbolic paraboloid
'net_fct': qng.paraboloid_hyperbolic
},
# once degenerate
sm.AffineSignature(2, 1, 1, affine_component_entry='parabolic'): {
# parabolic cylinder
'net_fct': qng.cylinder_parabolic
},
# twice degenerate
sm.AffineSignature(1, 1, 2, affine_component_entry='parabolic'): {
# one plane (second plane at infinity)
'net_fct': qng.plane,
'net_args': {'axis': 2, 'name': 'OnePlane'}
}
}
"""
Dictionary mapping signature to parametrization of corresponding quadric in
normal form. It has the following structure::
+ ...
|
+--+ AffineSignature -> dict
| |
| +--+ 'net_fct' -> function that returns net
| |
| +--+ 'net_args' -> Optional dict of kwargs to be passed to net_fct
|
+ ...
It is assumed that affine_component of the signature is -1.
"""