import ddg.datastructures.nets.net as net
import ddg.datastructures.nets.net_generators.quadrics as qng
import ddg.datastructures.nets.utils as nutils
import ddg.math.symmetric_matrices as sm
from ddg.datastructures.nets.utils import compose
[docs]def quadric_to_smooth_net(quadric, affine=True):
"""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=True)
Whether the resulting net should return affine or homogeneous
coordinates.
Returns
-------
SmoothNet, SmoothCurve, EmptyNet, PointNet or NetCollection
Resulting smooth net.
"""
sgn = quadric.signature(affine=True)
Q = quadric.normalize(affine=True)
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
s = nutils.homogenize(s)
# Final parametrization in the ambient space
s = compose(B, s)
if affine:
s = nutils.dehomogenize(s)
return s
_SGN_DICT = {
#########################
# Conics (?) in 0D space
#########################
sm.AffineSignature(1, 0): {
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [], "name": "EmptyQuadric"},
},
sm.AffineSignature(0, 0, 1): {
"net_fct": net.PointNet,
"net_args": {"value": [], "name": "OnePoint"},
},
#########################
# Conics (?) in 1D space
#########################
sm.AffineSignature(2, 0): {
# complex quadric
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0], "name": "ComplexQuadric"},
},
sm.AffineSignature(1, 1, last_entry=-1): {
# two points
"net_fct": qng.two_points
},
sm.AffineSignature(1, 0, 1, last_entry=0): {
# double point (?)
"net_fct": net.PointNet,
"net_args": {"value": [0.0], "name": "DoublePoint"},
},
sm.AffineSignature(1, 0, 1, last_entry=1): {
# point at infinity
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0], "name": "PointAtInfinity"},
},
sm.AffineSignature(0, 0, 2): {
# fully degenerate
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0], "name": "FullyDegenerateQuadric"},
},
sm.AffineSignature(1, 1, last_entry="parabolic"): {
# one point (and one at infinity)
"net_fct": net.PointNet,
"net_args": {"value": [0.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, 0.0], "name": "ComplexConic"},
},
sm.AffineSignature(2, 1, last_entry=-1): {
# ellipse
"net_fct": qng.circle
},
sm.AffineSignature(2, 1, last_entry=1): {
# hyperbola
"net_fct": qng.hyperbola
},
# once degenerate
sm.AffineSignature(2, 0, 1, last_entry=0): {
# single point (two intersecting complex lines)
"net_fct": net.PointNet,
"net_args": {"value": [0.0, 0.0], "name": "ConjugateLines"},
},
sm.AffineSignature(1, 1, 1, last_entry=-1): {
# pair of parallel lines
"net_fct": qng.linepair
},
sm.AffineSignature(1, 1, 1, last_entry=0): {
# pair of intersecting lines
"net_fct": qng.interline
},
sm.AffineSignature(2, 0, 1, last_entry=1): {
# empty (complex lines)
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0], "name": "ConjugateParallelLines"},
},
# twice degenerate
sm.AffineSignature(1, 0, 2, last_entry=0): {
# double line
"net_fct": qng.cline,
"net_args": {"name": "DoubleLine"},
},
sm.AffineSignature(1, 0, 2, last_entry=1): {
# empty (double line at infinity)
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0], "name": "DoubleLineInfty"},
},
# fully degenerate
sm.AffineSignature(0, 0, 3): {
# empty
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0], "name": "FullyDegenerateConic"},
},
# parabolic cases
# non-degenerate
sm.AffineSignature(2, 1, last_entry="parabolic"): {
# parabola
"net_fct": qng.parabola
},
# degenerate
sm.AffineSignature(1, 1, 1, last_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.0, 0.0], "name": "ComplexQuadric"},
},
sm.AffineSignature(3, 1, last_entry=-1): {
# sphere
"net_fct": qng.sphere
},
sm.AffineSignature(3, 1, last_entry=1): {
# two-sheeted hyperboloid
"net_fct": qng.hyperboloid_two_sheeted,
"net_args": {"axis": 2},
},
# one-sheeted hyperboloid
sm.AffineSignature(2, 2, last_entry=-1): {
"net_fct": qng.hyperboloid_one_sheeted,
"net_args": {"axis": 0},
},
# once degenerate
sm.AffineSignature(3, 0, 1, last_entry=0): {
# one point (complex cone with real vertex)
"net_fct": net.PointNet,
"net_args": {"value": [0.0, 0.0, 0.0], "name": "ComplexCone"},
},
sm.AffineSignature(2, 1, 1, last_entry=0): {
# cone
"net_fct": qng.cone
},
sm.AffineSignature(3, 0, 1, last_entry=1): {
# empty (complex cylinder with vertex at infinity)
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0, 0.0], "name": "ComplexCylinder"},
},
sm.AffineSignature(2, 1, 1, last_entry=1): {
# hyperbolic cylinder
"net_fct": qng.cylinder_hyperbolic,
"net_args": {"rot": True},
},
sm.AffineSignature(2, 1, 1, last_entry=-1): {
# elliptic cylinder
"net_fct": qng.cylinder_elliptic
},
# twice degenerate
sm.AffineSignature(2, 0, 2, last_entry=0): {
# one line (two complex conjugate planes)
"net_fct": qng.line,
"net_args": {"name": "ConjugatePlanes"},
},
sm.AffineSignature(1, 1, 2, last_entry=0): {
# two intersecting planes
"net_fct": qng.planes_intersecting,
"net_args": {"name": "Planes"},
},
sm.AffineSignature(2, 0, 2, last_entry=1): {
# empty (two complex conjugate planes intersecting at infinity)
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0, 0.0], "name": "ConjugateParallelPlanes"},
},
sm.AffineSignature(1, 1, 2, last_entry=1): {
# two parallel planes
"net_fct": qng.planes_parallel,
"net_args": {"name": "ParallelPlanes"},
},
# thrice degenerate
sm.AffineSignature(1, 0, 3, last_entry=0): {
# double plane
"net_fct": qng.plane,
"net_args": {"axis": 0, "name": "DoublePlane"},
},
sm.AffineSignature(1, 0, 3, last_entry=1): {
# empty (double plane at infinity)
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0, 0.0], "name": "DoublePlaneInfty"},
},
# fully degenerate
sm.AffineSignature(0, 0, 4): {
"net_fct": net.EmptyNet,
"net_args": {"coordinates": [0.0, 0.0, 0.0], "name": "FullyDegenerateQuadric"},
},
# parabolic cases
# non-degenerate
sm.AffineSignature(3, 1, last_entry="parabolic"): {
# elliptic paraboloid
"net_fct": qng.paraboloid_elliptic
},
sm.AffineSignature(2, 2, last_entry="parabolic"): {
# hyperbolic paraboloid
"net_fct": qng.paraboloid_hyperbolic
},
# once degenerate
sm.AffineSignature(2, 1, 1, last_entry="parabolic"): {
# parabolic cylinder
"net_fct": qng.cylinder_parabolic
},
# twice degenerate
sm.AffineSignature(1, 1, 2, last_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
|
+ ...
"""