pfc-geometry 0.2.20__py3-none-any.whl → 0.2.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
geometry/__init__.py CHANGED
@@ -18,7 +18,8 @@ from .gps import GPS
18
18
  from .coordinate_frame import Coord
19
19
  from .transformation import Transformation
20
20
  from .mass import Mass
21
-
21
+ from .air import Air
22
+ from .angles import wrap_to_pi
22
23
 
23
24
  def Euler(*args, **kwargs) -> Quaternion:
24
25
  return Quaternion.from_euler(Point(*args, **kwargs))
geometry/air.py ADDED
@@ -0,0 +1,20 @@
1
+ from geometry.base import Base
2
+
3
+ R = 287.058
4
+ GAMMA = 1.4
5
+
6
+
7
+ def get_rho(pressure, temperature):
8
+ return pressure / (R * temperature)
9
+
10
+
11
+ class Air(Base):
12
+ cols = ["P", "T", "rho"]
13
+
14
+ @staticmethod
15
+ def iso_sea_level(length: int):
16
+ return Air(101325, 288.15, get_rho(101325, 288.15)).tile(length)
17
+
18
+ @staticmethod
19
+ def from_pt(pressure, temperature):
20
+ return Air(pressure, temperature, get_rho(pressure, temperature))
geometry/angles.py CHANGED
@@ -16,4 +16,9 @@ def difference(a, b):
16
16
  bd=np.abs(d3) < np.abs(d1)
17
17
  d1[bd] = d3[bd]
18
18
 
19
- return d1
19
+ return d1
20
+
21
+
22
+ def wrap_to_pi(angles: npt.NDArray) -> npt.NDArray:
23
+ """Wrap angles to the range [-pi, pi]."""
24
+ return (angles + np.pi) % (2 * np.pi) - np.pi
geometry/base.py CHANGED
@@ -265,9 +265,11 @@ class Base:
265
265
  if not pd.api.types.is_list_like(dt):
266
266
  dt = np.full(len(self), dt)
267
267
  self, dt = Base.length_check(self, dt)
268
- diff_method = np.gradient if method == "gradient" else np.diff
268
+ if method=="gradient":
269
+ data = np.gradient(self.data, axis=0) if len(self) >1 else np.zeros(self.data.shape)
270
+ else:
271
+ data = np.diff(self.data, axis=0)
269
272
 
270
- data = diff_method(self.data, axis=0)
271
273
  dt = dt if method == "gradient" else dt[:-1]
272
274
  return self.__class__(data / np.tile(dt, (len(self.__class__.cols), 1)).T)
273
275
 
@@ -88,7 +88,7 @@ class Coord(Base):
88
88
  def axes(self):
89
89
  return Point.concatenate([self.x_axis, self.y_axis, self.z_axis])
90
90
 
91
- def plot(self, fig=None, scale=1, label: str = None):
91
+ def plot(self, fig=None, scale=1, width=2, label: str = None):
92
92
  import plotly.graph_objects as go
93
93
  if fig is None:
94
94
  fig = go.Figure(layout=dict(scene=dict(aspectmode="data")))
@@ -105,6 +105,7 @@ class Coord(Base):
105
105
  mode="markers",
106
106
  name="Origin",
107
107
  marker=dict(size=5, color="black"),
108
+ showlegend=False
108
109
  )
109
110
  )
110
111
  colors = ["red", "green", "blue"]
@@ -116,7 +117,8 @@ class Coord(Base):
116
117
  z=[self.origin.z[0], (self.origin.z + axis.z * scale)[0]],
117
118
  mode="lines",
118
119
  name=f"{label or 'Axis'} {Point.cols[i]}",
119
- line=dict(width=2, color=colors.pop(0))
120
+ line=dict(width=width, color=colors.pop(0)),
121
+ showlegend=False
120
122
  )
121
123
  )
122
124
  return fig
geometry/point.py CHANGED
@@ -272,7 +272,7 @@ def angle_between(a: Point, b: Point) -> np.ndarray:
272
272
 
273
273
  @ppmeth
274
274
  def scalar_projection(a: Point, b: Point) -> Point:
275
- return a.cos_angle_between(b) * abs(a)
275
+ return cos_angle_between(a, b) * abs(a)
276
276
 
277
277
 
278
278
  @ppmeth
@@ -284,21 +284,28 @@ def vector_projection(a: Point, b: Point) -> Point:
284
284
  def vector_rejection(a: Point, b: Point) -> Point:
285
285
  return a - ((Point.dot(a, b)) / Point.dot(b, b)) * b
286
286
 
287
+ @ppmeth
288
+ def min_angle_between(p1: Point, p2: Point):
289
+ angle = angle_between(p1, p2) % np.pi
290
+ return np.minimum(angle, np.pi - angle)
287
291
 
288
292
  @ppmeth
289
293
  def is_parallel(a: Point, b: Point, tolerance=1e-6):
290
294
  return abs(a.cos_angle_between(b) - 1) < tolerance
291
295
 
296
+ @ppmeth
297
+ def is_anti_parallel(a: Point, b: Point, tolerance=1e-6):
298
+ return abs(a.cos_angle_between(-b) - 1) < tolerance
299
+
292
300
 
293
301
  @ppmeth
294
- def is_perpendicular(a: Point, b: Point, tolerance=1e-6):
295
- return abs(a.dot(b)) < tolerance
302
+ def is_either_parallel(a: Point, b: Point, tolerance=1e-6):
303
+ return min_angle_between(a, b) < tolerance
296
304
 
297
305
 
298
306
  @ppmeth
299
- def min_angle_between(p1: Point, p2: Point):
300
- angle = angle_between(p1, p2) % np.pi
301
- return np.minimum(angle, np.pi - angle)
307
+ def is_perpendicular(a: Point, b: Point, tolerance=1e-6):
308
+ return abs(a.dot(b)) < tolerance
302
309
 
303
310
 
304
311
  def vector_norm(point: Point):
geometry/time.py CHANGED
@@ -25,12 +25,12 @@ class Time(Base):
25
25
  return Time(t, dt)
26
26
 
27
27
  @staticmethod
28
- def uniform(duration: float, npoints: int | None, minpoints: int = 1) -> Time:
28
+ def uniform(duration: float, npoints: int | None, minpoints: int = 1, freq=25) -> Time:
29
29
  return Time.from_t(
30
30
  np.linspace(
31
31
  0,
32
32
  duration,
33
- npoints if npoints else max(int(np.ceil(duration * 25)), minpoints),
33
+ npoints if npoints else max(int(np.ceil(duration * freq)), minpoints),
34
34
  )
35
35
  )
36
36
 
@@ -9,6 +9,7 @@ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9
9
  You should have received a copy of the GNU General Public License along with
10
10
  this program. If not, see <http://www.gnu.org/licenses/>.
11
11
  """
12
+ from __future__ import annotations
12
13
  from geometry import Base, Point, Quaternion, P0, Q0, Coord
13
14
 
14
15
  import numpy as np
@@ -54,7 +55,7 @@ class Transformation(Base):
54
55
  raise AttributeError(name)
55
56
 
56
57
  @staticmethod
57
- def build(p:Point, q:Quaternion):
58
+ def build(p:Point, q:Quaternion) -> Transformation:
58
59
  if len(p) == len(q):
59
60
  return Transformation(np.concatenate([
60
61
  p.data,
geometry/utils.py CHANGED
@@ -86,6 +86,8 @@ def get_value(arr: npt.NDArray, index: Number):
86
86
 
87
87
  def apply_index_slice(index: npt.NDArray, value: slice | Number | npt.ArrayLike | None):
88
88
  if isinstance(value, slice):
89
+ if value.start is not None and value.stop is not None and value.start >= value.stop:
90
+ return np.array([], dtype=index.dtype)
89
91
  middle = pd.Index(index)[
90
92
  int(np.ceil(value.start)) if value.start is not None else None : int(
91
93
  np.ceil(value.stop)
@@ -93,9 +95,9 @@ def apply_index_slice(index: npt.NDArray, value: slice | Number | npt.ArrayLike
93
95
  if value.stop is not None
94
96
  else None
95
97
  ]
96
- if value.start is not None and middle[0] != value.start and value.start > index[0]:
98
+ if value.start is not None and (len(middle) == 0 or middle[0] != value.start) and value.start > index[0]:
97
99
  middle = np.concatenate([[get_value(index, value.start)], middle])
98
- if value.stop is not None and middle[-1] != value.stop and value.stop < index[-1]:
100
+ if value.stop is not None and (len(middle) == 0 or middle[-1] != value.stop) and value.stop < index[-1]:
99
101
  middle = np.concatenate([middle, [get_value(index, value.stop)]])
100
102
  return middle
101
103
  else:
@@ -1,10 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pfc-geometry
3
- Version: 0.2.20
3
+ Version: 0.2.22
4
4
  Summary: A library for working with 3D geometry.
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
7
- Requires-Dist: numpy-quaternion>=2024.0.7
8
7
  Requires-Dist: numpy>=2.1.3
9
8
  Requires-Dist: pandas>=2.2.3
10
9
  Requires-Dist: rowan>=1.3.2
@@ -0,0 +1,18 @@
1
+ geometry/__init__.py,sha256=YT9pVH7zbfi26MLehrcCjcBf39aiCeq8aMuTtB3hC8Y,1133
2
+ geometry/air.py,sha256=cmOoUiVYmCWccDAy_7u-bfOvkKnRW5gWUxcD8X-ukvM,443
3
+ geometry/angles.py,sha256=OxuYcjFGexuOputr_eo9xHXnGCc44H3o3S5GQPp1geY,630
4
+ geometry/base.py,sha256=uHnQpOhv3Y9bXzpIttOODKRVUxFIlRbxmg4EbMRQa_s,15037
5
+ geometry/checks.py,sha256=o8yMBAdU5Vy0EspBYaof4fPGgRSFZhRDhzBjRPsLd0M,375
6
+ geometry/coordinate_frame.py,sha256=FeQn7TBAnbik4Rv0ErDUCaY-W480trVYspH46uS1NXw,4442
7
+ geometry/gps.py,sha256=EsokABt40ZoltpAQfKrRc4kA-Lc2ScP_ltJNF7pvAWc,3654
8
+ geometry/mass.py,sha256=BUWBSITwpdRfpJR5-oJTd16BI7FLZt8rhxdzr0cx1HY,1675
9
+ geometry/point.py,sha256=zsF7LVvwdVPsH-17RTPDiE-FqDpo1BiaDn6DosOLuwo,8716
10
+ geometry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ geometry/quaternion.py,sha256=dZwpViiVPwHUhRk7DhOwNab3pLhIWXyHk3DVh9mukSk,12143
12
+ geometry/time.py,sha256=VQEklZtZkwMthMsrH5QT83V8e3n78S06fWjyEqLHYbk,2706
13
+ geometry/transformation.py,sha256=-FQ_55l3_MykSQQuEIJ3MqWS5MHKR0HNWWCKpEEgRT0,5592
14
+ geometry/utils.py,sha256=62MO2G6SzP63P_xRMb-wzGu9digyk-tSIBjpOypMRXE,3631
15
+ pfc_geometry-0.2.22.dist-info/METADATA,sha256=Jii_pLAE9vY-2-dbkOhZo8G3jmf7b3m58yAT1UQ4b_E,1587
16
+ pfc_geometry-0.2.22.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
17
+ pfc_geometry-0.2.22.dist-info/licenses/LICENSE,sha256=z72U6pv-bQgJ_Svr4uCXnMjemsp38aSerhHEdEAOMJ4,7632
18
+ pfc_geometry-0.2.22.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,17 +0,0 @@
1
- geometry/__init__.py,sha256=Qipz0oxyBg-C_-sFLVI8LKW9Yq8_keR-CbyuseAvTGg,1082
2
- geometry/angles.py,sha256=Gw4PXr2kQMvvKECsugmi5kNiqOnK8T3PZSo3IKUpxPY,480
3
- geometry/base.py,sha256=6bM4J7VGhstel6qu-C4xU39vU4dZ71S9FZMY9Y7xDZY,14966
4
- geometry/checks.py,sha256=o8yMBAdU5Vy0EspBYaof4fPGgRSFZhRDhzBjRPsLd0M,375
5
- geometry/coordinate_frame.py,sha256=6KzRu0sSPzmHj5vLIuX5Efi0OWdEF6gQtKPf63wsaRk,4358
6
- geometry/gps.py,sha256=EsokABt40ZoltpAQfKrRc4kA-Lc2ScP_ltJNF7pvAWc,3654
7
- geometry/mass.py,sha256=BUWBSITwpdRfpJR5-oJTd16BI7FLZt8rhxdzr0cx1HY,1675
8
- geometry/point.py,sha256=wjAau7PiTpoIHMMvDDexXq8PisE5RdAQqT7Ze3NTm6A,8477
9
- geometry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- geometry/quaternion.py,sha256=dZwpViiVPwHUhRk7DhOwNab3pLhIWXyHk3DVh9mukSk,12143
11
- geometry/time.py,sha256=VTfMHLxhcws8YESYvxxP8W_vSePvl4lwKRXHxFWhJeA,2695
12
- geometry/transformation.py,sha256=wnxoDN9-IeapVlrS_Da4hXyxtPCyoa_UcCsB8QVgxuo,5539
13
- geometry/utils.py,sha256=q7-aaxDzRDwl78-3XzdpcJuh5iL7I8lN5agk2WNWjSY,3443
14
- pfc_geometry-0.2.20.dist-info/METADATA,sha256=XXAr-l0CNGbvC2GTXtUj0os-mDRYN_3OK7LwAft9LoU,1629
15
- pfc_geometry-0.2.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- pfc_geometry-0.2.20.dist-info/licenses/LICENSE,sha256=z72U6pv-bQgJ_Svr4uCXnMjemsp38aSerhHEdEAOMJ4,7632
17
- pfc_geometry-0.2.20.dist-info/RECORD,,