geoclide.quadrics module#
Quadric shapes.
This module implements the quadric shapes of geoclide. Each shape is placed with an object-to-world transformation and provides ray intersection tests, accepting a single ray or a set of rays, as well as the calculation of its total area.
Key Classes#
- Sphere
A full or partial sphere, optionally cut below zmin and above zmax and limited to a maximum azimuthal angle phi_max.
- Spheroid
An oblate or prolate spheroid, described by its equatorial (xy) and polar (z) radii.
- Disk
A full or partial disk, described by its radius, an optional inner radius (annulus), a z height and a maximum azimuthal angle phi_max.
- class geoclide.quadrics.Disk(radius: float, inner_radius: float = 0.0, phi_max: float = 360.0, z_height: float = 0.0, otw: Transform | None = None, wto: Transform | None = None)[source]#
Bases:
ShapeCreation of the class Disk
- Parameters:
- radiusfloat
The disk radius
- inner_radiusfloat, optional
The inner radius (case of annulus)
- phi_maxfloat, optional
The maximum phi value in degrees of the disk/annulus, where phi is between 0 and 360°
- z_heightfloat, optional
the disk height along the z axis
- otwTransform, optional
From object to world space or the transformation applied to the spheroid
- wtoTransform, optional
From world to object space or the in inverse transformation applied to the spheroid
Methods
area()compute the disk / annulus area
intersect(r[, ds_output])Test if a ray/set of rays intersects the disk
Test if a ray/set of rays intersects the disk
Test if a ray/set of rays intersects the disk
plot(**kwargs)Plot the disk
to_trianglemesh([reso])Convert the disk to a triangle mesh
Notes
Even if z_height is given, the origin for rotation transformation do not change. For exemple: z_height=5 then we apply a rotation of 90 degrees around the y axis, the disk we be rotated from (0.,0.,0.), meaning the disk we be moved from position (0.,0.,5.) to (5.,0.,0.).
- area() float[source]#
compute the disk / annulus area
Warning
the scale transformation is not considered for the area calculation!
- intersect(r: Ray, ds_output: bool = True) Dataset | tuple[source]#
Test if a ray/set of rays intersects the disk
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- ds_outputbool, optional
If True the output is a dataset, else -> a tuple with intersection information variables
- Returns:
- Dataset or tuple
Xarray dataset containing the intersection information if ds_output is True (see the get_intersect_dataset function of the shapes module for its variables), else a tuple ready to be an input for that same function
Examples
>>> import geoclide as gc >>> r1 = gc.Ray(gc.Point(1.2,0.,10.), gc.Vector(0.,0.,-1.)) >>> annulus = gc.Disk(radius=1.5, inner_radius=0.8) >>> # hit point is between the inner radius and radius >>> ds = annulus.intersect(r1) >>> ds['thit'].values array(10.) >>> ds['phit'].values # the intersection point array([1.2, 0. , 0. ])
- is_intersection(r: Ray) bool | ndarray[source]#
Test if a ray/set of rays intersects the disk
- Parameters:
- rRay
The ray(s) to use for the intersection test
- Returns:
- bool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
Examples
>>> import geoclide as gc >>> r1 = gc.Ray(gc.Point(1.2,0.,10.), gc.Vector(0.,0.,-1.)) >>> r2 = gc.Ray(gc.Point(0.2,0.,10.), gc.Vector(0.,0.,-1.)) >>> r3 = gc.Ray(gc.Point(1.6,0.,10.), gc.Vector(0.,0.,-1.)) >>> annulus = gc.Disk(radius=1.5, inner_radius=0.8) >>> # hit point is between the inner radius and radius >>> annulus.is_intersection(r1) True >>> # the ray passes through the annulus hole, no intersection >>> annulus.is_intersection(r2) False >>> # the ray passes outside, no intersection >>> annulus.is_intersection(r3) False
- is_intersection_t(r: Ray) tuple[float | ndarray | None, bool | ndarray][source]#
Test if a ray/set of rays intersects the disk
- Parameters:
- rRay
The ray(s) to use for the intersection test
- Returns:
- thitfloat or ndarray
The t ray variable(s) for its first intersection at the shape surface. In case of an ndarray, it is 1-D
- is_intersectionbool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
Examples
>>> import geoclide as gc >>> r1 = gc.Ray(gc.Point(1.2,0.,10.), gc.Vector(0.,0.,-1.)) >>> r2 = gc.Ray(gc.Point(0.2,0.,10.), gc.Vector(0.,0.,-1.)) >>> r3 = gc.Ray(gc.Point(1.6,0.,10.), gc.Vector(0.,0.,-1.)) >>> annulus = gc.Disk(radius=1.5, inner_radius=0.8) >>> # hit point is between the inner radius and radius >>> annulus.is_intersection_t(r1) (10.0, True) >>> # the ray passes through the annulus hole, no intersection >>> annulus.is_intersection_t(r2) (None, False) >>> # the ray passes outside, no intersection >>> annulus.is_intersection_t(r3) (None, False)
- plot(**kwargs)[source]#
Plot the disk
The disk is first converted to a triangle mesh then the TriangleMesh plot method is used
- Parameters:
- **kwargs
The keyword arguments are passed on to the TriangleMesh plot method
- to_trianglemesh(reso: int | None = None) TriangleMesh[source]#
Convert the disk to a triangle mesh
- Parameters:
- resoint, optional
The number of lines around the polar phi angle, minimum accepted value is 3
- Returns:
- TriangleMesh
The disk converted to a triangle mesh
- class geoclide.quadrics.Sphere(radius: float, z_min: float | None = None, z_max: float | None = None, phi_max: float = 360.0, otw: Transform | None = None, wto: Transform | None = None)[source]#
Bases:
ShapeCreation of the class Sphere
without transformation the sphere is centered at the origin
z0, z1 and phi_max are needed parameters for the creation of any partial sphere
- Parameters:
- radiusfloat
The radius of the sphere
- z_minfloat, optional
The minimum z value of the sphere where z0 is between [-radius, 0]
- z_maxfloat, optional
The maximum z value of the sphere where z1 is between [0, radius]
- phi_maxfloat, optional
The maximum phi value in degrees of the sphere, where phi is between 0 and 360°
- otwTransform, optional
From object to world space or the transformation applied to the sphere
- wtoTransform, optional
From world to object space or the in inverse transformation applied to the sphere
Methods
area()compute the sphere / partial sphere area
intersect(r[, ds_output])Test if a ray/set of rays intersects the sphere/partial sphere
Test if a ray/set of rays intersects the sphere / partial sphere
Test if a ray/set of rays intersects the sphere/partial sphere
plot(**kwargs)Plot the sphere
to_trianglemesh([reso_theta, reso_phi])Convert the sphere to a triangle mesh
- area() float[source]#
compute the sphere / partial sphere area
Warning
the scale transformation is not considered for the area calculation!
- intersect(r: Ray, ds_output: bool = True) Dataset | tuple[source]#
Test if a ray/set of rays intersects the sphere/partial sphere
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- ds_outputbool, optional
If True the output is a dataset, else -> a tuple with intersection information variables
- Returns:
- Dataset or tuple
Xarray dataset containing the intersection information if ds_output is True (see the get_intersect_dataset function of the shapes module for its variables), else a tuple ready to be an input for that same function
Examples
>>> import geoclide as gc >>> sph1 = gc.Sphere(radius=1.) # sphere of radius 1 >>> # partial sphere where portion above z=0.5 is removed >>> sph2 = gc.Sphere(radius=1., z_max=0.5) >>> r = gc.Ray(o=gc.Point(-2., 0., 0.8), d=gc.Vector(1.,0.,0.)) >>> ds = sph1.intersect(r) >>> ds['phit'].values # the intersection point array([-0.6, 0. , 0.8]) >>> # The surface normal at the intersection point >>> ds['nhit'].values array([-0.6, 0. , 0.8]) >>> # here no intersection since the sphere part above z=0.5 is >>> # removed >>> ds2 = sph2.intersect(r) >>> ds2['is_intersection'].values array(False)
- is_intersection(r: Ray) bool | ndarray[source]#
Test if a ray/set of rays intersects the sphere / partial sphere
- Parameters:
- rRay
The ray(s) to use for the intersection test
- Returns:
- bool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
Examples
>>> import geoclide as gc >>> sph1 = gc.Sphere(radius=1.) # sphere of radius 1 >>> # partial sphere where portion above z=0.5 is removed >>> sph2 = gc.Sphere(radius=1., z_max=0.5) >>> r = gc.Ray(o=gc.Point(-2., 0., 0.8), d=gc.Vector(1.,0.,0.)) >>> sph1.is_intersection(r) True >>> # here no intersection since the sphere part above z=0.5 is >>> # removed >>> sph2.is_intersection(r) False
- is_intersection_t(r: Ray) tuple[float | ndarray | None, bool | ndarray][source]#
Test if a ray/set of rays intersects the sphere/partial sphere
- Parameters:
- rRay
The ray(s) to use for the intersection test
- Returns:
- thitfloat or ndarray
The t ray variable(s) for its first intersection at the shape surface. In case of an ndarray, it is 1-D
- is_intersectionbool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
Examples
>>> import geoclide as gc >>> sph1 = gc.Sphere(radius=1.) # sphere of radius 1 >>> # partial sphere where portion above z=0.5 is removed >>> sph2 = gc.Sphere(radius=1., z_max=0.5) >>> r = gc.Ray(o=gc.Point(-2., 0., 0.8), d=gc.Vector(1.,0.,0.)) >>> sph1.is_intersection_t(r) (1.4000000000000004, True) >>> # here no intersection since the sphere part above z=0.5 is >>> # removed >>> sph2.is_intersection(r) False
- plot(**kwargs)[source]#
Plot the sphere
The sphere is first converted to a triangle mesh then the TriangleMesh plot method is used
- Parameters:
- **kwargs
The keyword arguments are passed on to the TriangleMesh plot method
- to_trianglemesh(reso_theta: int | None = None, reso_phi: int | None = None) TriangleMesh[source]#
Convert the sphere to a triangle mesh
- Parameters:
- reso_thetaint, optional
The number of lines around the polar theta angle, minimum accepted value is 3
- reso_phiint, optional
The number of lines around the azimuth phi angle, minimum accepted value is 3
- Returns:
- TriangleMesh
The sphere converted to a triangle mesh
- class geoclide.quadrics.Spheroid(radius_xy: float, radius_z: float, otw: Transform | None = None, wto: Transform | None = None)[source]#
Bases:
ShapeCreation of the class Spheroid
without transformation the spheroid is centered at the origin
spheroid equation: x/(alpha**2) + y/(alpha**2) + z/(gamma**2) = 1, where alpha = radius_xy and gamma = radius_z
prolate -> radius_z > radius_xy
oblate -> radius_z < radius_xy
- Parameters:
- radius_xyfloat
The equatorial radius of the spheroid
- radius_zfloat
The pole radius of the spheroid (distance from center to pole along z axis)
- otwTransform, optional
From object to world space or the transformation applied to the spheroid
- wtoTransform, optional
From world to object space or the in inverse transformation applied to the spheroid
Methods
area()compute the spheroid area
intersect(r[, ds_output])Test if a ray/set of rays intersects the spheroid
Test if a ray/set of rays intersects the spheroid
Test if a ray/set of rays intersects the spheroid
plot(**kwargs)Plot the spheroid
to_trianglemesh([reso_theta, reso_phi])Convert the spheroid to a triangle mesh
- area() float[source]#
compute the spheroid area
Warning
the scale transformation is not considered for the area calculation!
- intersect(r: Ray, ds_output: bool = True) Dataset | tuple[source]#
Test if a ray/set of rays intersects the spheroid
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- ds_outputbool, optional
If True the output is a dataset, else -> a tuple with intersection information variables
- Returns:
- Dataset or tuple
Xarray dataset containing the intersection information if ds_output is True (see the get_intersect_dataset function of the shapes module for its variables), else a tuple ready to be an input for that same function
Examples
>>> import geoclide as gc >>> oblate = gc.Spheroid(radius_xy=3., radius_z=1.5) >>> prolate = gc.Spheroid(radius_xy=1.5, radius_z=3.) >>> r1 = gc.Ray( ... o=gc.Point(2.5, 0., 10.), d=(gc.Vector(0., 0., -1.)) ... ) >>> r2 = gc.Ray( ... o=gc.Point(10., 0., 2.5), d=(gc.Vector(-1., 0., 0.)) ... ) >>> ds1 = oblate.intersect(r1) >>> ds1['phit'].values # the intersection point array([2.5 , 0. , 0.8291562]) >>> # The surface normal at the intersection point >>> ds1['nhit'].values array([ 0.60192927, -0. , 0.79854941]) >>> ds2 = prolate.intersect(r2) >>> ds2['phit'].values array([0.8291562, 0. , 2.5 ]) >>> ds2['nhit'].values array([ 0.79854941, -0. , 0.60192927])
- is_intersection(r: Ray) bool | ndarray[source]#
Test if a ray/set of rays intersects the spheroid
- Parameters:
- rRay
The ray(s) to use for the intersection test
- Returns:
- bool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
Examples
>>> import geoclide as gc >>> oblate = gc.Spheroid(radius_xy=3., radius_z=1.5) >>> prolate = gc.Spheroid(radius_xy=1.5, radius_z=3.) >>> r1 = gc.Ray( ... o=gc.Point(2.5, 0., 10.), d=(gc.Vector(0., 0., -1.)) ... ) >>> r2 = gc.Ray( ... o=gc.Point(10., 0., 2.5), d=(gc.Vector(-1., 0., 0.)) ... ) >>> oblate.is_intersection(r1) True >>> oblate.is_intersection(r2) False >>> prolate.is_intersection(r1) False >>> prolate.is_intersection(r2) True
- is_intersection_t(r: Ray) tuple[float | ndarray | None, bool | ndarray][source]#
Test if a ray/set of rays intersects the spheroid
- Parameters:
- rRay
The ray(s) to use for the intersection test
- Returns:
- thitfloat or ndarray
The t ray variable(s) for its first intersection at the shape surface. In case of an ndarray, it is 1-D
- is_intersectionbool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
Examples
>>> import geoclide as gc >>> oblate = gc.Spheroid(radius_xy=3., radius_z=1.5) >>> prolate = gc.Spheroid(radius_xy=1.5, radius_z=3.) >>> r1 = gc.Ray( ... o=gc.Point(2.5, 0., 10.), d=(gc.Vector(0., 0., -1.)) ... ) >>> r2 = gc.Ray( ... o=gc.Point(10., 0., 2.5), d=(gc.Vector(-1., 0., 0.)) ... ) >>> oblate.is_intersection_t(r1) (9.170843802411135, True) >>> oblate.is_intersection_t(r2) (None, False) >>> prolate.is_intersection_t(r1) (None, False) >>> prolate.is_intersection_t(r2) (9.170843802411135, True)
- plot(**kwargs)[source]#
Plot the spheroid
The spheroid is first converted to a triangle mesh then the TriangleMesh plot method is used
- Parameters:
- **kwargs
The keyword arguments are passed on to the TriangleMesh plot method
- to_trianglemesh(reso_theta: int | None = None, reso_phi: int | None = None) TriangleMesh[source]#
Convert the spheroid to a triangle mesh
- Parameters:
- reso_thetaint, optional
The number of lines around the polar theta angle, minimum accepted value is 3
- reso_phiint, optional
The number of lines around the azimuth phi angle, minimum accepted value is 3
- Returns:
- TriangleMesh
The spheroid converted to a triangle mesh