Geoclide package#
Geoclide#
A python package for geometric calculations in the three-dimensional Euclidean space.
- Provides
Basic geometric objects: vectors, points, normals, rays and bounding boxes
Geometric transformations: translations, scales and rotations
Ray intersection tests with shapes: spheres, spheroids, disks, triangles and triangle meshes
How to use the documentation#
Documentation is available in two forms: docstrings provided with the code, and a standalone reference guide, available from the geoclide homepage.
Code snippets are indicated by three greater-than signs:
>>> import geoclide as gc
>>> v = gc.Vector(0., 0., 1.)
Use the built-in help function to view a function’s
docstring:
>>> help(gc.calc_intersection)
- class geoclide.BBox(p1: Point | None = None, p2: Point | None = None)[source]#
Bases:
objectBounding Box
- Parameters:
- p1Point, optional
Frist point(s) to use to create the bounding box(es)
- p2Point, optional
Second point(s) to use to create the bounding box(es)
Methods
common_face(b[, fill_value])Get the face index/indices which is/are common with one of the face(s) of bounding box(es) b2
Get a list of boolean checking which vertices (self) are common to the bounding box(es) b
intersect(...)Test if a ray/rays intersect(s) the bounding box(es)
is_inside(p)Test if point(s) p is/are included in the bounding box(es)
is_intersection(r[, diag_calc])Test if a ray/rays intersect(s) the bounding box(es)
union(b)Union with a point/set of points or a bounding box/set of bounding boxes
Examples
>>> import geoclide as gc >>> p1 = gc.Point(0., 0., 0.) >>> p2 = gc.Point(1., 1., 1.) >>> b1 = gc.BBox(p1, p2) >>> b1 pmin=Point(0.0, 0.0, 0.0), pmax=Point(1.0, 1.0, 1.0)
- common_face(b: BBox, fill_value: int | float | None = None) int | float | ndarray | None[source]#
Get the face index/indices which is/are common with one of the face(s) of bounding box(es) b2
The convention of index from face 0 to 5, for +X,-X,+Y,-Y,+Z,-Z:
|F2| |+Y| |F1|F4|F0|F5| where -> |-X|+Z|+X|-Z| |F3| |-Y|
- Parameters:
- bBBox
The secondary bounding box(es)
- fill_valueinteger, optional
In case there is no common face(s) returns fill_value
- Returns:
- int or ndarray
Returns the index/indices of the common face(s) or fill_value. In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> b1 = gc.BBox(gc.Point(0., 0., 0.), gc.Point(1., 1., 1.)) >>> b2 = gc.BBox(gc.Point(1., 0., 0.), gc.Point(2., 1., 1.)) >>> gc.get_common_face(b1, b2) 0 >>> gc.get_common_face(b2, b1) 1
- common_vertices(b: BBox) ndarray[source]#
Get a list of boolean checking which vertices (self) are common to the bounding box(es) b
- Parameters:
- bBBox
The secondary bounding box(es)
- Returns:
- ndarray
Returns an array of boolean values indicating if the bounding box(es) vertices are common to the secondary b bounding box(es) vertices
Examples
>>> import geoclide as gc >>> b0 = gc.BBox(gc.Point(0., 0., 0.), gc.Point(1., 1., 1.)) >>> b1 = gc.BBox(gc.Point(1., 0., 0.), gc.Point(2., 1., 1.)) >>> b0.common_vertices(b1) array([False, True, True, False, False, True, True, False]) >>> b1.common_vertices(b0) array([ True, False, False, True, True, False, False, True])
- intersect(r: Ray, diag_calc: bool = False, *, ds_output: Literal[True] = True) Dataset[source]#
- intersect(r: Ray, diag_calc: bool = False, *, ds_output: Literal[False]) tuple[float | ndarray, float | ndarray, bool | ndarray]
- intersect(r: Ray, diag_calc: bool = False, *, ds_output: bool) Dataset | tuple
Test if a ray/rays intersect(s) the bounding box(es)
There are 3 possibilities:
no intersection
only 1 intersection (case of ray located initially inside the BBox)
2 intersections
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- diag_calcbool, optional
Perform diagonal calculations in case of multiple bounding boxes and rays, the output is a 1-D array instead of a 2-D array where out[i] is calculated using r(i) and bbox(i). The same size for the BBox and Ray objects is required.
- ds_outputbool, optional
If True the output is a dataset, else returns a tuple with intersection information variables
- Returns:
- Dataset or tuple
Xarray dataset containing the intersection information if ds_output is True (see the get_bbox_intersect_dataset function for its variables), else a tuple. Form of the tuple:
- t0None or float or ndarray
-> The t ray variable of the first intersection. In case of only 1 intersection it represents nothing. An ndarray is 1-D, or 2-D for a set of rays and a set of bounding boxes.
- t1None or float or ndarray
-> The t ray variable of the second intersection. In case of only 1 intersection, t1 becomes the t ray variable of the first intersection. An ndarray is 1-D, or 2-D for a set of rays and a set of bounding boxes.
- is_intersectionbool or ndarray
-> If there is at least 1 intersection return True, else False. An ndarray is an ndarray of booleans, 1-D, or 2-D for a set of rays and a set of bounding boxes.
Examples
>>> import geoclide as gc >>> p1 = gc.Point(0., 0., 0.) >>> p2 = gc.Point(1., 1., 1.) >>> b1 = gc.BBox(p1, p2) >>> b1 pmin=Point(0.0, 0.0, 0.0), pmax=Point(1.0, 1.0, 1.0) >>> p3 = gc.Point(0.5, 0.5, 0.1) >>> v1 = gc.Vector(0., 0., 1.) >>> r1 = gc.Ray(p3, v1) >>> r1 r(t) = (0.5, 0.5, 0.1) + t*(0.0, 0.0, 1.0) with t ∈ [0,inf[ >>> t0, t1, is_intersection = b1.intersect(r1, ds_output=False) >>> t0, t1, is_intersection (0.0, np.float64(0.9000000000000006), True) >>> r1(t1) Point(0.5, 0.5, 1.0000000000000007)
- is_inside(p: Point) bool | ndarray[source]#
Test if point(s) p is/are included in the bounding box(es)
- is_intersection(r: Ray, diag_calc: bool = False) bool | ndarray[source]#
Test if a ray/rays intersect(s) the bounding box(es)
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- diag_calcbool
Perform diagonal calculations in case of multiple bounding boxes and rays, the output is a 1-D array instead of a 2-D array where out[i] is calculated using r(i) and bbox(i). The same size for the BBox and Ray objects is required.
- Returns:
- bool or ndarray
If there is at least 1 intersection returns True, else False. In case of an ndarray, it is an ndarray of booleans, 1-D, or 2-D for a set of rays and a set of bounding boxes.
Examples
>>> import geoclide as gc >>> p1 = gc.Point(0., 0., 0.) >>> p2 = gc.Point(1., 1., 1.) >>> b1 = gc.BBox(p1, p2) >>> b1 pmin=Point(0.0, 0.0, 0.0), pmax=Point(1.0, 1.0, 1.0) >>> p3 = gc.Point(0.5, 0.5, 0.1) >>> v1 = gc.Vector(0., 0., 1.) >>> r1 = gc.Ray(p3, v1) >>> r1 r(t) = (0.5, 0.5, 0.1) + t*(0.0, 0.0, 1.0) with t ∈ [0,inf[ >>> b1.is_intersection(r1) True
- union(b: Point | BBox) BBox[source]#
Union with a point/set of points or a bounding box/set of bounding boxes
- Parameters:
- bPoint or BBox
The point(s) or bounding box(es) to use for the union
- Returns:
- BBox
The new bounding box(es) after the union
Examples
>>> import geoclide as gc >>> p1 = gc.Point(0., 0., 0.) >>> p2 = gc.Point(1., 1., 1.) >>> p3 = gc.Point(1., 1., 3.) >>> b1 = gc.BBox(p1, p2) >>> b1 pmin=Point(0.0, 0.0, 0.0), pmax=Point(1.0, 1.0, 1.0) >>> b2 = b1.union(p3) >>> b2 pmin=Point(0.0, 0.0, 0.0), pmax=Point(1.0, 1.0, 3.0)
- class geoclide.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.Normal(x: float | ndarray | Vector | Point | Normal | None = None, y: float | ndarray | None = None, z: float | ndarray | None = None, copy: bool = False)[source]#
Bases:
object- Parameters:
- xfloat or ndarray or Point or Vector or Normal, optional
The x component(s) of the normal (see notes)
- yfloat or ndarray, optional
The y component(s) of the normal. In case of an ndarray, it must be 1-D
- zfloat or ndarray, optional
The z component(s) of the normal. In case of an ndarray, it must be 1-D
- copybool, optional
If True the given ndarrays are copied, else they are used as they are (see notes)
Methods
length
length_squared
to_numpy
Notes
if the parameter x is a 1-D ndarray of size 3 and y and z are None, the values of x, y and z will be equal to respectively x[0], x[1], and x[2]
if the parameter x is a 2-D ndarray of shape (n,3) and y and z are None, the values of x, y and z will be equal to respectively x[:,0], x[:,1], and x[:,2]
if the parameter x is a Point, Vector or Normal, it will circumvent the y and z parameters and take the components of the Point/Vector/Normal for x, y and z values
the x, y and z ndarrays given as parameters are not copied, modifying them afterwards modifies the normal. Use copy=True to get a normal with its own components
Examples
>>> import geoclide as gc >>> n1 = gc.Normal(0.,0.,1.) >>> n1 Normal(0.0, 0.0, 1.0)
- fmt = '.8f'#
- class geoclide.Point(x: float | ndarray | Vector | Point | Normal | None = None, y: float | ndarray | None = None, z: float | ndarray | None = None, copy: bool = False)[source]#
Bases:
object- Parameters:
- xfloat or ndarray or Point or Vector or Normal, optional
The x component(s) of the point (see notes)
- yfloat or ndarray, optional
The y component(s) of the point. In case of an ndarray, it must be 1-D
- zfloat or ndarray, optional
The z component(s) of the point. In case of an ndarray, it must be 1-D
- copybool, optional
If True the given ndarrays are copied, else they are used as they are (see notes)
Methods
to_numpy
Notes
if the parameter x is a 1-D ndarray of size 3 and y and z are None, the values of x, y and z will be equal to respectively x[0], x[1], and x[2]
if the parameter x is a 2-D ndarray of shape (n,3) and y and z are None, the values of x, y and z will be equal to respectively x[:,0], x[:,1], and x[:,2]
if the parameter x is a Point, Vector or Normal, it will circumvent the y and z parameters and take the components of the Point/Vector/Normal for x, y and z values
the x, y and z ndarrays given as parameters are not copied, modifying them afterwards modifies the point. Use copy=True to get a point with its own components
Examples
>>> import geoclide as gc >>> p1 = gc.Point(0.,0.,1.) >>> p1 Point(0.0, 0.0, 1.0)
- fmt = '.8f'#
- class geoclide.Ray(o: Point | Ray, d: Vector | None = None, mint: float = 0, maxt: float = inf)[source]#
Bases:
objectDefinition of ray:
r(t) = o + t*d, where:
o is/are the origin point(s) of the ray(s)
d is/are the direction(s) of the ray(s)
t belongs to stricly positive real numbers
- Parameters:
- oPoint or Ray
Origin point(s) of the ray(s). If the o parameter is a Ray -> circumvent all the parameters by the ray attributs
- dVector
Direction(s) of the ray(s)
- mintfloat, optional
The minimum t value
- maxtfloat, optional
The maximum t value
Methods
__call__(t)Solve ray(s) equation(s)
Examples
>>> import geoclide as gc >>> o = gc.Point(0., 50., 2.) >>> d = gc.Vector(0.,0.,1.) >>> r = gc.Ray(o, d, mint=20, maxt=100) >>> r r(t) = (0.0, 50.0, 2.0) + t*(0.0, 0.0, 1.0) with t ∈ [20,100[
- __call__(t: float | ndarray) Point[source]#
Solve ray(s) equation(s)
- Parameters:
- tfloat or ndarray
The t rays(s) values(s). The value(s) must lie between mint and maxt. In case of an ndarray, it must be 1-D
- Returns:
- Point
The result(s) of the equation r(t) = o + t*d
Examples
>>> import geoclide as gc >>> o = gc.Point(0., 0., 0.) >>> d = gc.Vector(1., 0., 0.) >>> r = gc.Ray(o, d) >>> t = 10. >>> r(t) Point(10.0, 0.0, 0.0)
- class geoclide.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.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
- class geoclide.Transform(m: Transform | ndarray | None = None, m_inv: ndarray | None = None)[source]#
Bases:
objectRepresents 3D geometric transformation(s) using a 4x4 matrix or ntx4x4 matrix, where nt is the number of transformations
It allows translation, rotation and scalling. It can be applied to vectors, points, normals and rays
- Parameters:
- mTransform or ndarray, optional
The matrix of the transformation(s), of shape (4, 4) or (nt, 4, 4) for a set of nt transformations
- m_invTransform or ndarray, optional
The inverse matrix of the transformation(s), of shape (4, 4) or (nt, 4, 4) for a set of nt transformations
Methods
__call__(...)Apply the transformations
inverse()Inverse the transformation(s) matrix
rotate(angle, axis[, diag_calc])Update the self transformation(s) by adding a rotate transformation(s)
rotate_x(angle)Update the self transformation(s) by adding a rotate_x transformation(s)
rotate_y(angle)Update the self transformation(s) by adding a rotate_y transformation(s)
rotate_z(angle)Update the self transformation(s) by adding a rotate_z transformation(s)
scale(v)Update the self transformation(s) by adding a scale transformation(s)
translate(v)Update the self transformation(s) by adding a translate transformation(s)
is_identity
Examples
>>> import geoclide as gc >>> t1 = gc.Transform() >>> t1 m= array( [[1. 0. 0. 0.] [0. 1. 0. 0.] [0. 0. 1. 0.] [0. 0. 0. 1.]] ) m_inv= array( [[1. 0. 0. 0.] [0. 1. 0. 0.] [0. 0. 1. 0.] [0. 0. 0. 1.]] )
- __call__(c: Vector, diag_calc: bool = False, flatten: bool = False) Vector[source]#
- __call__(c: Point, diag_calc: bool = False, flatten: bool = False) Point
- __call__(c: Normal, diag_calc: bool = False, flatten: bool = False) Normal
- __call__(c: Ray, diag_calc: bool = False, flatten: bool = False) Ray
- __call__(c: BBox, diag_calc: bool = False, flatten: bool = False) BBox
Apply the transformations
- Parameters:
- cVector or Point or Normal or Ray or BBox
The vector(s)/point(s)/normal(s)/ray(s)/bounding box(es) to which the transformation is applied
- diag_calcbool, optional
Perform diagonal calculations between c(i) and tranformation(i). The number of transformations must be equal to the number of vectors/points/ …
- Returns:
- Vector or Point or Normal or Ray or BBox or ndarray
The vector(s)/point(s)/normal(s)/ray(s)/bounding box(es) after the application of the transformation(s). In case of several transformations, it returns a 1-D ndarray of dtype equals to the c parameter type, but if flatten is True returns directly an object of same type as the c parameter.
Examples
>>> import geoclide as gc >>> t = gc.get_translate_tf(gc.Vector(5., 5., 5.)) >>> p = gc.Point(0., 0., 0.) >>> t[p] Point(5.0, 5.0, 5.0)
- inverse() Transform[source]#
Inverse the transformation(s) matrix
- Parameters:
- tTransform
The transformation(s) to be inversed
- Returns:
- Transform
The inversed transformation(s)
- rotate(angle: float | ndarray, axis: Vector | Normal, diag_calc: bool = False) Transform[source]#
Update the self transformation(s) by adding a rotate transformation(s)
Warning
The angle parameter can be a 1-D array only if axis parameter is a Vector/Normal with scalar x, y, z components, or if the parameter diag_calc=True
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s). In case of an ndarray, it must be 1-D
- axisVector or Normal
The rotation(s) is/are performed around the vector(s)/normal(s) axis/axes
- diag_calcbool, optional
Perform diagonal calculations in case angle is a 1-D ndarray and axis is a Vector/Normal with 1-D ndarray x, y, z components. Use angle(i) with axis(i) to calculate transformation(i)
- Returns:
- Transform
The product of the self transformation(s) and the rotate transformation(s) matrices
- rotate_x(angle: float | ndarray) Transform[source]#
Update the self transformation(s) by adding a rotate_x transformation(s)
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s) around the x axis. In case of an ndarray, it must be 1-D
- Returns:
- Transform
The product of the self transformation(s) and the rotate_x transformation(s) matrices
- rotate_y(angle: float | ndarray) Transform[source]#
Update the self transformation(s) by adding a rotate_y transformation(s)
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s) around the y axis. In case of an ndarray, it must be 1-D
- Returns:
- Transform
The product of the self transformation(s) and the rotate_y transformation(s) matrices
- rotate_z(angle: float | ndarray) Transform[source]#
Update the self transformation(s) by adding a rotate_z transformation(s)
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s) around the Z axis. In case of an ndarray, it must be 1-D
- Returns:
- Transform
The product of the initial transformation(s) and the rotate_z transformation(s) matrices
- scale(v: Vector) Transform[source]#
Update the self transformation(s) by adding a scale transformation(s)
- Parameters:
- vVector
The vector(s) used for scale transformation(s)
- Returns:
- Transform
The product of the self transformation(s) and the scale transformation(s) matrices
- translate(v: Vector) Transform[source]#
Update the self transformation(s) by adding a translate transformation(s)
- Parameters:
- vVector
The vector(s) used for the transformation(s)
- Returns:
- Transform
The product of the self transformation(s) and the translate transformation(s)
Examples
>>> import geoclide as gc >>> t = Transform() >>> t = t.translate(gc.Vector(5.,0.,0.)) >>> t m= array( [[1. 0. 0. 5.] [0. 1. 0. 0.] [0. 0. 1. 0.] [0. 0. 0. 1.]] ) m_inv= array( [[ 1. 0. 0. -5.] [ 0. 1. 0. 0.] [ 0. 0. 1. 0.] [ 0. 0. 0. 1.]] )
- class geoclide.Triangle(p0: Point | None = None, p1: Point | None = None, p2: Point | None = None, otw: Transform | None = None, wto: Transform | None = None, p0t: Point | None = None, p1t: Point | None = None, p2t: Point | None = None)[source]#
Bases:
ShapeCreation of the class Triangle
- Parameters:
- p0Point
The first point(s) of the triangle(s)
- p1Point
The second point(s) of the triangle(s)
- p2Point
The the third point(s) of the triangle(s)
- otwTransform, optional
From object to world space or the transformation applied to the triangle
- wtoTransform, optional
From world to object space or the in inverse transformation applied to the triangle
- p0tPoint, optional
If given circumvent the automatically computed p0t (p0 after applying transformation)
- p1tPoint, optional
If given circumvent the automatically computed p1t (p1 after applying transformation)
- p2tPoint, optional
If given circumvent the automatically computed p2t (p2 after applying transformation)
Methods
area()compute the area of the triangle
intersect(...)Test if a ray/set of rays intersect with the triangle(s) and return intersection information
intersect_v2(...)intersect_v3(...)is_intersection(r[, method, diag_calc])Test if a ray/set of rays intersect with the triangle(s)
is_intersection_t(r[, method, diag_calc])Test if a ray/set of rays intersect with the triangle(s)
is_intersection_v2(r[, diag_calc])is_intersection_v2_t(r[, diag_calc])is_intersection_v3(r, diag_calc)is_intersection_v3_t(r[, diag_calc])- area() float | ndarray[source]#
compute the area of the triangle
Warning
the scale transformation is not considered for the area calculation!
- intersect(r: Ray, method: str = 'v3', diag_calc: bool = False, *, ds_output: Literal[True] = True) Dataset[source]#
- intersect(r: Ray, method: str = 'v3', diag_calc: bool = False, *, ds_output: Literal[False]) tuple
- intersect(r: Ray, method: str = 'v3', diag_calc: bool = False, *, ds_output: bool) Dataset | tuple
Test if a ray/set of rays intersect with the triangle(s) and return intersection information
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- methodstr, optional
Two choices -> ‘v2’ (use mainly pbrt v2 intersection test method) or ‘v3’ (pbrt v3)
- diag_calcbool, optional
Perform diagonal calculations in case Triangle and Ray have ndarray point components, meaning the output is a 1-D array instead of a 2-D array where out[i] is calculated using r(i) and triangle(i). The same size for the Triangle and the Ray is required.
- ds_outputbool, optional
If True the output is a dataset, else return 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. Form of the tuple:
- shape_namestr
-> The shape class name
- rRay
-> The ray(s) used for the intersection test
- tNone or float or ndarray
-> The t ray variable(s) for its first intersection at the shape surface. An ndarray is 1-D, or 2-D for a set of rays and a set of triangles.
- is_intersectionbool or ndarray
-> If there is an intersection return True, else False. An ndarray is an ndarray of booleans, 1-D, or 2-D for a set of rays and a set of triangles.
- uNone or float or ndarray
-> The u coordinate(s) of the parametric representation. An ndarray is 1-D, or 2-D for a set of rays and a set of triangles.
- vNone or float or ndarray
-> The v coordinate(s) of the parametric representation. An ndarray is 1-D, or 2-D for a set of rays and a set of triangles.
- dpduNone or ndarray
-> The surface partial derivative(s) of phit with respect to u. An ndarray is 1-D, or 2-D in case of a set of rays and/or a set of triangles.
- dpdvNone or ndarray
-> The surface partial derivative(s) of phit with respect to v. An ndarray is 1-D, or 2-D in case of a set of rays and/or a set of triangles.
- diag_calcbool
-> This indicates whether a diagonal calculation has been performed
Notes
By default the ‘v3’ method is used since there are more robustness tests. But the ‘v2’ method is at least twice faster than ‘v3’.
- is_intersection(r: Ray, method: str = 'v3', diag_calc: bool = False) bool | ndarray[source]#
Test if a ray/set of rays intersect with the triangle(s)
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- methodstr, optional
Two choices -> ‘v2’ (use mainly pbrt v2 intersection test method) or ‘v3’ (pbrt v3)
- diag_calcbool, optional
Perform diagonal calculations in case Triangle and Ray have ndarray point components, meaning the output is a 1-D array instead of a 2-D array where out[i] is calculated using r(i) and triangle(i). The same size for the Triangle and the Ray is required.
- Returns:
- bool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is an ndarray of booleans, 1-D, or 2-D for a set of rays and a set of triangles
- is_intersection_t(r: Ray, method: str = 'v3', diag_calc: bool = False) tuple[float | ndarray | None, bool | ndarray][source]#
Test if a ray/set of rays intersect with the triangle(s)
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- methodstr, optional
Two choices -> ‘v2’ (use mainly pbrt v2 intersection test method) or ‘v3’ (pbrt v3)
- diag_calcbool, optional
Perform diagonal calculations in case Triangle and Ray have ndarray point components, meaning the output is a 1-D array instead of a 2-D array where out[i] is calculated using r(i) and triangle(i). The same size for the Triangle and the Ray is required.
- Returns:
- thitNone or float or ndarray
The t ray variable(s) for its first intersection at the shape surface. In case of an ndarray, it is 1-D, or 2-D for a set of rays and a set of triangles
- is_intersectionbool or ndarray
If there is an intersection -> True, else False. In case of an ndarray, it is an ndarray of booleans, 1-D, or 2-D for a set of rays and a set of triangles
- class geoclide.TriangleMesh(vertices: ndarray, faces: ndarray, otw: Transform | None = None, wto: Transform | None = None)[source]#
Bases:
ShapeCreation of the class TriangleMesh
- Parameters:
- verticesndarray
The vertices xyz coordinates. It is a 2d ndarray of size (nvertices, 3) where the first element is the coordinate of first vertex and so on
- facesndarray
The vertices indices of triangles, a 2d ndarray of shape (ntriangles, 3). The 3 first indices are the vertices (p0, p1 and p3) indices of the first triangle and so on
- otwTransform, optional
From object to world space or the transformation applied to the triangle mesh
- wtoTransform, optional
From world to object space or the in inverse transformation applied to the triangle mesh
Methods
apply_tf(t)Apply transformation to the triangle mesh
area()compute the area of the triangle mesh
intersect(...)Test if a ray/set of rays intersect with the triangle mesh and return intersection information
is_intersection(r[, method, diag_calc, use_loop])Test if a ray/set of rays intersect with the triangle mesh
is_intersection_t(r[, method, diag_calc, ...])Test if a ray/set of rays intersect with the triangle mesh
plot([source, savefig_name])Plot the triangle mesh
to_dataset([name])Create an xarray dataset where the triangle mesh information are stored
write(path, **kwargs)Save the mesh
- apply_tf(t: Transform) None[source]#
Apply transformation to the triangle mesh
- Parameters:
- tTranform
The transfomation matrix to apply
- area() float[source]#
compute the area of the triangle mesh
Warning
the scale transformation is not considered for the area calculation!
- intersect(r: Ray, method: str = 'v3', diag_calc: bool = False, *, ds_output: Literal[True] = True, use_loop: bool = False) Dataset[source]#
- intersect(r: Ray, method: str = 'v3', diag_calc: bool = False, *, ds_output: Literal[False], use_loop: bool = False) tuple
- intersect(r: Ray, method: str = 'v3', diag_calc: bool = False, *, ds_output: bool, use_loop: bool = False) Dataset | tuple
Test if a ray/set of rays intersect with the triangle mesh and return intersection information
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- methodstr, optional
Two choices -> ‘v2’ (use mainly pbrt v2 triangle intersection test method) or ‘v3’ (pbrt v3)
- diag_calcbool, optional
Perform diagonal calculations between r(i) and triangle(i). The number of triangles must be equal to the number of rays
- use_loopbool, optional
If True -> scalar calculations over a loop (instead of using numpy). It can be useful for debugging
- ds_outputbool, optional
If True the output is a dataset, else return 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. Form of the tuple:
- shape_namestr
-> The shape class name
- rRay
-> The ray(s) used for the intersection test
- tNone or float or ndarray
-> The t ray variable(s) for its first intersection at the shape surface. An ndarray is 1-D.
- is_intersectionbool or ndarray
-> If there is an intersection return True, else False. An ndarray is a 1-D ndarray of booleans.
- uNone or float or ndarray
-> The u coordinate(s) of the parametric representation. An ndarray is 1-D.
- vNone or float or ndarray
-> The v coordinate(s) of the parametric representation. An ndarray is 1-D.
- dpduNone or ndarray
-> The surface partial derivative(s) of phit with respect to u. An ndarray is 1-D, or 2-D for a set of rays.
- dpdvNone or ndarray
-> The surface partial derivative(s) of phit with respect to v. An ndarray is 1-D, or 2-D for a set of rays.
- diag_calcbool
-> This indicates whether a diagonal calculation has been performed
- is_intersection(r: Ray, method: str = 'v3', diag_calc: bool = False, use_loop: bool = False) bool | ndarray[source]#
Test if a ray/set of rays intersect with the triangle mesh
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- methodstr, optional
Two choices -> ‘v2’ (use mainly pbrt v2 triangle intersection test method) or ‘v3’ (pbrt v3)
- diag_calcbool, optional
Perform diagonal calculations between r(i) and triangle(i). The number of triangles must be equal to the number of rays
- use_loopbool, optional
If True -> scalar calculations over a loop (instead of using numpy). It can be useful for debugging
- 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
- is_intersection_t(r: Ray, method: str = 'v3', diag_calc: bool = False, use_loop: bool = False) tuple[float | ndarray | None, bool | ndarray][source]#
Test if a ray/set of rays intersect with the triangle mesh
- Parameters:
- rRay
The ray(s) to use for the intersection test(s)
- methodstr, optional
Two choices -> ‘v2’ (use mainly pbrt v2 triangle intersection test method) or ‘v3’ (pbrt v3)
- diag_calcbool, optional
Perform diagonal calculations between r(i) and triangle(i). The number of triangles must be equal to the number of rays
- use_loopbool, optional
If True -> scalar calculations over a loop (instead of using numpy). It can be useful for debugging
- Returns:
- thitNone or float 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
Notes
If use_loop = True, is_intersection_t can be significantly more consuming than is_intersection. Because it does not stop at the first intersection, but it finalize the complete loop to return the thit corresponding to the nearest triangle.
- plot(source: str | None = None, savefig_name: str | None = None, **kwargs)[source]#
Plot the triangle mesh
- Parameters:
- sourcestr
The package used for the plot, only 2 option -> ‘matplotlib’ or ‘trimesh’. If source = None, use matplolib for mesh with ntriangle < 5000, else use trimesh
- savefig_namestr, optional
If savefig_name is given, the figure is saved with the given name (only if source=’matplotlib)
- **kwargs
All other keyword arguments are passed on to matplotlib plot_trisurf function. For example: alpha, color, shade, … If source = ‘trimesh’ then the keyword arguments passed on to show Trimesh method
Examples
>>> import geoclide as gc >>> prolate = gc.Spheroid(radius_xy=1.5, radius_z=3.) >>> msh = prolate.to_trianglemesh() >>> msh.plot(color='green', edgecolor='k')
- to_dataset(name: str = 'none') Dataset[source]#
Create an xarray dataset where the triangle mesh information are stored
- Parameters:
- namestr, optional
The name of the triangle mesh to be stored
- Returns:
- Dataset
Xarray dataset containing the triangle mesh information.
Key variables included:
obj_names: The name(s) of the mesh(es)
vertices: The vertices xyz coordinates [nobj, nvertices, xyz]
faces: For each triangle, the indices of its vertices p0, p1 and p2 [nobj, ntriangles, p0p1p2]
- class geoclide.Vector(x: float | ndarray | Vector | Point | Normal | None = None, y: float | ndarray | None = None, z: float | ndarray | None = None, copy: bool = False)[source]#
Bases:
object- Parameters:
- xfloat or ndarray or Point or Vector or Normal, optional
The x component(s) of the vector (see notes)
- yfloat or ndarray, optional
The y component(s) of the vector. In case of an ndarray, it must be 1-D
- zfloat or ndarray, optional
The z component(s) of the vector. In case of an ndarray, it must be 1-D
- copybool, optional
If True the given ndarrays are copied, else they are used as they are (see notes)
Methods
length
length_squared
to_numpy
Notes
if the parameter x is a 1-D ndarray of size 3 and y and z are None, the values of x, y and z will be equal to respectively x[0], x[1], and x[2]
if the parameter x is a 2-D ndarray of shape (n,3) and y and z are None, the values of x, y and z will be equal to respectively x[:,0], x[:,1], and x[:,2]
if the parameter x is a Point, Vector or Normal, it will circumvent the y and z parameters and take the components of the Point/Vector/Normal for x, y and z values
the x, y and z ndarrays given as parameters are not copied, modifying them afterwards modifies the vector. Use copy=True to get a vector with its own components
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(0.,0.,1.) >>> v1 Vector(0.0, 0.0, 1.0)
- fmt = '.8f'#
- geoclide.ang2vec(theta: float | ndarray, phi: float | ndarray, vec_view: str = 'zenith', diag_calc: bool = False) Vector[source]#
Convert a direction/directions described by 2 angles/set of 2 angles into a direction/directions described by a vector/vectors
direct orthogonal coordinate system where z is pointing upwards
- Parameters:
- thetafloat or ndarray
The polar angle(s) in degrees, starting at z+ in the zx plane and going in the trigonometric direction around the y axis. In case of an ndarray, it must be 1-D
- phifloat or ndarray
The azimuthal angle(s) in degrees, starting at x+ in the xy plane and going in the trigonometric direction around the z axis. In case of an ndarray, it must be 1-D
- vec_viewstr, optional
Two choices (concerning initial direction at theta=phi=0): ‘zenith’ (i.e. pointing above) or ‘nadir’ (i.e. pointing below)
- diag_calcbool, optional
Perform diagonal calculations, v(i) is calculated using theta(i) and phi(i)
- Returns:
- Vector
The direction(s) described by a vector
Notes
In case both theta and phi are 1-D ndarrays, the vectors are ordered in phi-major order
Examples
>>> import geoclide as gc >>> th = 30. >>> ph = 0. >>> v1 = gc.ang2vec(theta=th, phi=ph, vec_view='zenith') >>> v1 Vector(0.49999999999999994, 0.0, 0.8660254037844387) >>> v2 = gc.ang2vec(theta=th, phi=ph, vec_view='nadir') >>> v2 Vector(-0.49999999999999994, 0.0, -0.8660254037844387)
- geoclide.calc_intersection(shape: BBox | Sphere | Spheroid | Disk | Triangle | TriangleMesh, r: Ray, **kwargs) Dataset[source]#
Performs intersection test between a shape and a ray and returns dataset
- Parameters:
- shapeBBox, Sphere, Spheroid, Disk, Triangle or TriangleMesh
The shape used for the intersection(s)
- rRay
The ray(s) used for the intersection(s)
- **kwargs
The keyword arguments are passed on to intersect method. The ds_output parameter is forced here to always be True.
- Returns:
- Dataset
Xarray dataset containing the intersection information.
Key variables included:
o: The origin(s) of the ray(s) [xyz]
d: The direction(s) of the ray(s) [xyz]
mint: The mint attribute of the ray(s)
maxt: The maxt attribute of the ray(s)
is_intersection: If there is an intersection -> True, else False
thit: The t ray variable(s) of the intersection point(s)
phit: The intersection point(s) [xyz]
nhit: The surface normal(s) at the intersection point(s) [xyz] (not for a BBox)
u, v, dpdu, dpdv: The parametric coordinates and surface partial derivatives (not for a BBox)
the shape attributes (e.g. radius, z_min, z_max and phi_max for a sphere, or pmin and pmax for a bounding box)
wto_m, wto_m_inv, otw_m, otw_m_inv: The transformation matrices of the shape (not for a BBox)
Examples
>>> import geoclide as gc >>> sphere = gc.Sphere(radius=1.) # sphere of radius 1 >>> bbox = gc.BBox(p1=gc.Point(0., 0., 0.), p2=gc.Point(1.,1.,1.)) >>> ray = gc.Ray(o=gc.Point(-2., 0., 0.8), d=gc.Vector(1.,0.,0.)) >>> ds_sphere = gc.calc_intersection(sphere, ray) >>> ds_sphere['thit'].values array(1.4) >>> ds_sphere['phit'].values array([-0.6, 0. , 0.8]) >>> ds_bbox = gc.calc_intersection(bbox, ray) >>> ds_bbox['thit'].values array(2.) >>> ds_bbox['phit'].values array([0. , 0. , 0.8])
- geoclide.clamp(val: float, val_min: float, val_max: float) float[source]#
Clamps val into the range [val_min, val_max]
- Parameters:
- valfloat
The scalar to be clamped
- val_minfloat
The minimum value
- val_maxfloat
The maximum value
- Returns:
- float
The result of the clamp
Examples
>>> import geoclide as gc >>> gc.clamp(4, val_min=5, val_max=11) 5
- geoclide.coordinate_system(v1: Vector, method: str = 'm2') tuple[Vector, Vector][source]#
Create orthogonal coordinate system(s) from a vector/set of vectors
- Parameters:
- v1Vector
The base vector(s) used to create the orthogonal coordinate system(s)
- methodstr, optional
Default is ‘m2’ (method from pbrt v4), other choice is ‘m1’ (pbrt v2 and v3)
- Returns:
- v2Vector
The second vector(s) of the orthogonal coordinate system(s)
- v3Vector
The third vector(s) of the orthogonal coordinate system(s)
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(0., 0., 1.) >>> gc.coordinate_system(v1) (Vector(1.0, -0.0, -0.0), Vector(-0.0, 1.0, -0.0))
- geoclide.cross(a: Vector | Normal, b: Vector | Normal) Vector[source]#
The cross product
Warning
The cross product of 2 normals is not allowed
Definition of the cross product:
\((a × b) = ((a.y*b.z)-(a.z*b.y))x̂ + ((a.z*b.x)-(a.x*b.z))ŷ + ((a.x*b.y)-(a.y*b.x))\)
\((a × b) = ||a||*||b||*sin(θ)\)
where x̂, ŷ and ẑ are the unitary vectors respectively in axes x, y and z
- Parameters:
- aVector or Normal
The first vector(s) or normal(s) used for the cross product
- bVector or Normal
The second vector(s) or normal(s) used for the cross product
- Returns:
- Vector
The result(s) of the cross product
Examples
>>> import geoclide as gc >>> a = gc.Vector(0.,0.,1.) >>> b = gc.Vector(1.,0.,0.) >>> gc.cross(a,b) Vector(0.0, 1.0, 0.0)
- geoclide.distance(p1: Point, p2: Point) float | ndarray[source]#
Compute the distance(s) between 2 points/set of points
- Parameters:
- p1Point
The first point(s)
- p2Point
The second point(s)
- Returns:
- float or ndarray
The distance(s) between the 2 points/set of points. In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> p1 = gc.Point(0., 0., 0.) >>> p2 = gc.Point(0., 0., 10.) >>> gc.distance(p1,p2) 10.0 >>> p1 = gc.Point(1., 2., 1.9) >>> p2 = gc.Point(5., 15., 3.) >>> gc.distance(p1,p2) 13.64587849865299
- geoclide.dot(a: Vector | Normal, b: Vector | Normal) float | ndarray[source]#
The dot/scalar product
Definition of the dot product:
\((a . b) = a.x*b.x + a.y*b.y + a.z*b.z\)
\((a . b) = ||a|| * ||b|| * cos(θ)\)
- Parameters:
- aVector or Normal
The first vector(s) or normal(s) used for the dot product
- bVector or Normal
The second vector(s) or normal(s) used for the dot product
- Returns:
- float or ndarray
The result(s) of the dot product i.e. sum of products. In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> a = gc.Vector(0., 0., 1.) >>> b = gc.Vector(math.sqrt(2.)/2., 0., math.sqrt(2.)/2.) >>> gc.dot(a,b) 0.7071067811865476
- geoclide.face_forward(a: Vector | Normal, b: Vector | Normal) Vector | Normal[source]#
Flip the vector(s)/normal(s) a if the vector(s)/normal(s) b is/are in the opposite direction(s)
It can be useful to flip a surface normal so that it lies in the same hemisphere as a given vector.
- Parameters:
- aVector or Normal
The vector(s) or normal(s) to potentially flip
- bVector or Normal
The base vector(s) or normal(s) used for the flip
- Returns:
- Vector or Normal
The potentially flipped vector(s) or normal(s)
Examples
>>> import geoclide as gc >>> n1 = gc.Normal(1., 0., 0.) >>> v1 = gc.Vector(-1., 0., 0.) >>> gc.face_forward(v1, n1) Vector(1.0, -0.0, -0.0)
- geoclide.get_common_face(b1: BBox, b2: BBox, fill_value: int | float | None = None) int | float | ndarray | None[source]#
Get the face index/indices of the bounding box(es) b1 which is/are common to the bounding box(es) b2
The convention of index from face 0 to 5, for +X,-X,+Y,-Y,+Z,-Z:
|F2| |+Y| |F1|F4|F0|F5| where -> |-X|+Z|+X|-Z| |F3| |-Y|
- Parameters:
- b1BBox
The principal bounding box(es)
- b2BBox
The secondary bounding box(es)
- fill_valueinteger, optional
In case there is no common face(s) returns fill_value
- Returns:
- int or ndarray
Returns the index/indices of the common face(s) or fill_value. In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> b1 = gc.BBox(gc.Point(0., 0., 0.), gc.Point(1., 1., 1.)) >>> b2 = gc.BBox(gc.Point(1., 0., 0.), gc.Point(2., 1., 1.)) >>> gc.get_common_face(b1, b2) 0 >>> gc.get_common_face(b2, b1) 1
- geoclide.get_common_vertices(b1: BBox, b2: BBox) ndarray[source]#
Check which vertices of bounding box(es) b1 are common to the vectices of bounding box(es) b2
- Parameters:
- b1BBox
The principal bounding box(es)
- b2BBox
The secondary bounding box(es)
- Returns:
- ndarray
Returns an array of boolean values indicating whether the principal bounding box(es) b1 vertices are common to the secondary bounding box(es) b2 vertices. It is 1-D, or 2-D in case of a set of bounding boxes.
Examples
>>> import geoclide as gc >>> b1 = gc.BBox(gc.Point(0., 0., 0.), gc.Point(1., 1., 1.)) >>> b2 = gc.BBox(gc.Point(1., 0., 0.), gc.Point(2., 1., 1.)) >>> gc.get_common_vertices(b1, b2) array([False, True, True, False, False, True, True, False]) >>> gc.get_common_vertices(b2, b1) array([ True, False, False, True, True, False, False, True])
- geoclide.get_inverse_tf(t: Transform) Transform[source]#
Get the inverse transformation(s)
- Parameters:
- tTransform
The transformation(s) to be inversed
- Returns:
- Transform
The inversed transformation(s)
- geoclide.get_rotate_tf(angle: float | ndarray, axis: Vector | Normal, diag_calc: bool = False) Transform[source]#
Get the rotate transformation(s) around a given axis/axes
Warning
The angle parameter can be a 1-D array only if axis parameter is a Vector/Normal with scalar x, y, z components, or if the parameter diag_calc=True
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s). In case of an ndarray, it must be 1-D
- axisVector or Normal
The rotation(s) is/are performed around the vector(s)/normal(s) axis/axes
- diag_calcbool, optional
Perform diagonal calculations in case angle is a 1-D ndarray and axis is a Vector/Normal with 1-D ndarray x, y, z components. Use angle(i) with axis(i) to calculate transformation(i)
- Returns:
- Transform
The rotate transformation(s)
- geoclide.get_rotate_x_tf(angle: float | ndarray) Transform[source]#
Get the rotate_x transformation(s)
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s) around the x axis. In case of an ndarray, it must be 1-D
- Returns:
- Transform
The rotate_x transformation(s)
- geoclide.get_rotate_y_tf(angle: float | ndarray) Transform[source]#
Get the rotate_y transformation(s)
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s) around the y axis. In case of an ndarray, it must be 1-D
- Returns:
- Transform
The rotate_y transformation(s)
- geoclide.get_rotate_z_tf(angle: float | ndarray) Transform[source]#
Get the rotate_z transformation(s)
- Parameters:
- anglefloat or ndarray
The angle(s) in degrees for the rotation(s) around the Z axis. In case of an ndarray, it must be 1-D
- Returns:
- Transform
The rotate_z transformation(s)
- geoclide.get_scale_tf(v: Vector) Transform[source]#
Get the scale transformation(s)
- Parameters:
- vVector
The vector(s) used for scale transformation(s)
- Returns:
- Transform
The scale transformation(s)
- geoclide.get_translate_tf(v: Vector) Transform[source]#
Get the translate transformation(s)
- Parameters:
- vVector
The vector(s) used for the translate transformation(s)
- Returns:
- Transform
The translate transformation(s)
Examples
>>> import geoclide as gc >>> t = gc.get_translate_tf(gc.Vector(5.,0.,0.)) >>> t m= array( [[1. 0. 0. 5.] [0. 1. 0. 0.] [0. 0. 1. 0.] [0. 0. 0. 1.]] ) m_inv= array( [[ 1. 0. 0. -5.] [ 0. 1. 0. -0.] [ 0. 0. 1. -0.] [ 0. 0. 0. 1.]] )
- geoclide.normalize(v: Vector) Vector[source]#
- geoclide.normalize(v: Normal) Normal
Normalize a vector/normal or a set of vectors/normals
- Parameters:
- vVector or Normal
The vector(s) or normal(s) to be normalized
- Returns:
- Vector or Normal
The normalized vector(s)/normal(s)
Examples
>>> import geoclide as gc >>> v = gc.Vector(1.,0.,1.) >>> gc.normalize(v) Vector(0.7071067811865475, 0.0, 0.7071067811865475)
- geoclide.permute(a: Vector | Point | Normal, ix: int | ndarray | list | None = None, iy: int | ndarray | list | None = None, iz: int | ndarray | list | None = None) Vector | Point | Normal[source]#
Permutes the vector(s)/point(s)/normal(s) x, y, z values according to the given indices
- Parameters:
- aVector or Point or Normal
The vector(s), point(s) or normal(s) used for permutation
- ixint or np.ndarray or list, optional
The index/indices of the value(s) we want to keep as a remplacement for the x component(s)
- iyint or np.ndarray or list, optional
The index/indices of the value(s) we want to keep as a remplacement for the y component(s)
- izint or np.ndarray or list, optional
The index/indices of the value(s) we want to keep as a remplacement for the z component(s)
- Returns:
- Vector or Point or Normal
The vector(s)/point(s)/normal(s) after the permute operation
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(2., 3., 1.) >>> gc.permute(v1, 1, 0, 2) Vector(3.0, 2.0, 1.0) >>> import numpy as np >>> p_set = np.array( ... [[0.,0.,3.], [1.,0.,0.], [-0.5,0.,0.], [0.,-3.,0.]] ... ) >>> p_set = gc.Point(p_set) >>> gc.permute(p_set, [2,0,0,1], 1, 2).to_numpy() array([[ 3. , 0. , 3. ], [ 1. , 0. , 0. ], [-0.5, 0. , 0. ], [-3. , -3. , 0. ]])
- geoclide.quadratic(a: ndarray, b: ndarray, c: ndarray) tuple[ndarray, ndarray, ndarray][source]#
- geoclide.quadratic(a: float, b: float, c: float) tuple[bool, float | None, float | None]
Resolve the quadratic polynomial: ax**2 + bx + c
where x is the quadratic polynomial variable and a, b and c the coefficients
- Parameters:
- afloat or ndarray
The first coefficient(s) of the quadratic polynomial. In case of an ndarray, it must be 1-D
- bfloat or ndarray
The second coefficient(s) of the quadratic polynomial. In case of an ndarray, it must be 1-D
- cfloat or ndarray
The third coefficient(s) of the quadratic polynomial. In case of an ndarray, it must be 1-D
- Returns:
- bbool or ndarray
If the quadratic can be solved return True, else False. In case of an ndarray, it is a 1-D ndarray of booleans
- x0float or None or ndarray
The first solution(s). In case of an ndarray, it is 1-D
- x1float or None or ndarray
The second solution(s). In case of an ndarray, it is 1-D
Notes
If There are 2 solutions x0 < x1. And if there is only one solution x0 = x1.
Examples
>>> import geoclide as gc >>> a = 2 >>> b = -5 >>> c = 0 >>> gc.quadratic(a, b, c) (True, 0.0, 2.5)
- geoclide.read_trianglemesh(path: str, **kwargs) TriangleMesh[source]#
Open mesh file
if gcnc format use xarray, else use trimesh
- Parameters:
- pathstr
The xarray filename_or_obj or trimesh file_obj parameter
- **kwargs
The keyword arguments are passed on to xarray open_dataset or trimesh load_mesh method
- Returns:
- TriangleMesh
The triangle mesh
Notes
A file describing several objects, as a glb file or an obj file with several groups, is read as a single triangle mesh gathering all of them.
- geoclide.vabs(a: Vector | Point | Normal) Vector | Point | Normal[source]#
Calculate the absolute value(s) of each component of the vector(s)/point(s)/normal(s)
- Parameters:
- aVector or Point or Normal
The vector(s)/point(s)/normal(s) used
- Returns:
- Vector or Point or Normal or ndarray
The vector(s)/point(s)/normal(s) with absolute values. In case of an ndarray, it is 1-D
- geoclide.vargmax(a: Vector | Point | Normal) int | ndarray[source]#
Get the index/indices of the vector(s)/point(s)/normal(s) components with the largest value(s)
- Parameters:
- aVector or Point or Normal
The vector(s)/point(s)/normal(s) used
- Returns:
- int or ndarray
The index/indices of the largest vector(s)/point(s)/normal(s) value(s). In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(2.,3.,1.) >>> gc.vargmax(v1) 1
- geoclide.vargmin(a: Vector | Point | Normal) int | ndarray[source]#
Get the index/indices of the vector(s)/point(s)/normal(s) components with the smallest value(s)
- Parameters:
- aVector or Point or Normal
The vector(s)/point(s)/normal(s) used
- Returns:
- int or ndarray
The index/indices of the smallest vector(s)/point(s)/normal(s) value(s). In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(2.,3.,1.) >>> gc.vargmin(v1) 2
- geoclide.vec2ang(v: Vector, vec_view: str = 'zenith', acc: float = 1e-06) tuple[float | ndarray, float | ndarray][source]#
Convert a direction/directions described by a vector/vectors into a direction/directions described by 2 angles/set of 2 angles
direct orthogonal coordinate system where z is pointing upwards
- Parameters:
- vVector
The direction(s) described by a vector
- vec_viewstr, optional
Two choices (concerning initial direction at theta=phi=0): ‘zenith’ (i.e. pointing above) or ‘nadir’ (i.e. pointing below)
- accfloat, optional
The tolerance for numerical errors. Default is 1e-6.
- Returns:
- thetafloat or ndarray
The polar angle(s) in degrees, starting at z+ in the zx plane and going in the trigonometric direction around the y axis. In case of an ndarray, it is 1-D
- phifloat or ndarray
The azimuthal angle(s) in degrees, starting at x+ in the xy plane and going in the trigonometric direction around the z axis. In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> th = 30. >>> ph = 0. >>> v1 = gc.ang2vec(theta=th, phi=ph, vec_view='zenith') >>> v1 Vector(0.49999999999999994, 0.0, 0.8660254037844387) >>> theta, phi = gc.vec2ang(v1, vec_view='zenith') >>> theta, phi (29.999999999999993, 0.0) >>> v2 = gc.ang2vec(theta=th, phi=ph, vec_view='nadir') >>> v2 Vector(-0.49999999999999994, 0.0, -0.8660254037844387) >>> theta, phi = gc.vec2ang(v2, vec_view='nadir') >>> theta, phi (29.999999999999993, 0.0)
- geoclide.vmax(a: Vector | Point | Normal) float | ndarray[source]#
Get the largest components value(s) of the vector(s)/point(s)/normal(s)
- Parameters:
- aVector or Point or Normal
The vector(s)/point(s)/normal(s) used
- Returns:
- float or ndarray
The largest vector(s)/point(s)/normal(s) value(s). In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(2.,3.,1.) >>> gc.vmax(v1) 3.0
- geoclide.vmin(a: Vector | Point | Normal) float | ndarray[source]#
Get the smallest components value(s) of the vector(s)/point(s)/normal(s)
- Parameters:
- aVector or Point or Normal
The vector(s)/point(s)/normal(s) used
- Returns:
- float or ndarray
The smallest vector(s)/point(s)/normal(s) value(s). In case of an ndarray, it is 1-D
Examples
>>> import geoclide as gc >>> v1 = gc.Vector(2.,3.,1.) >>> gc.vmin(v1) 1.0
Modules#
- geoclide.basic module
- geoclide.mathope module
- geoclide.vecope module
- geoclide.transform module
- geoclide.quadrics module
- geoclide.trianglemesh module
- geoclide.intersection module
- geoclide.shapes module
- geoclide.advancedvecope module