navaltoolbox 0.1.0__cp39-cp39-win_amd64.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.
navaltoolbox/__init__.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright (C) 2026 Antoine ANCEAU
|
|
2
|
+
#
|
|
3
|
+
# This file is part of navaltoolbox.
|
|
4
|
+
#
|
|
5
|
+
# navaltoolbox is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
NavalToolbox - High-performance naval architecture library.
|
|
20
|
+
|
|
21
|
+
This library provides tools for hydrostatics, stability analysis,
|
|
22
|
+
and tank management in naval architecture applications.
|
|
23
|
+
|
|
24
|
+
Classes:
|
|
25
|
+
Hull: A hull geometry loaded from an STL file.
|
|
26
|
+
Vessel: A vessel containing hulls, tanks, and silhouettes.
|
|
27
|
+
Silhouette: A 2D profile for wind heeling calculations.
|
|
28
|
+
Tank: A tank with fluid management capabilities.
|
|
29
|
+
HydrostaticsCalculator: Calculator for hydrostatic properties.
|
|
30
|
+
StabilityCalculator: Calculator for stability curves (GZ).
|
|
31
|
+
DownfloodingOpening: Openings for downflooding analysis.
|
|
32
|
+
OpeningType: Types of downflooding openings.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
>>> from navaltoolbox import Hull, Vessel, HydrostaticsCalculator
|
|
36
|
+
>>> hull = Hull("ship.stl")
|
|
37
|
+
>>> vessel = Vessel(hull)
|
|
38
|
+
>>> calc = HydrostaticsCalculator(vessel)
|
|
39
|
+
>>> state = calc.calculate_at_draft(5.0)
|
|
40
|
+
>>> print(f"Displacement: {state.displacement:.0f} kg")
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Re-export all types from the native module
|
|
44
|
+
from .navaltoolbox import (
|
|
45
|
+
Hull,
|
|
46
|
+
Vessel,
|
|
47
|
+
Silhouette,
|
|
48
|
+
OpeningType,
|
|
49
|
+
DownfloodingOpening,
|
|
50
|
+
HydrostaticState,
|
|
51
|
+
HydrostaticsCalculator,
|
|
52
|
+
StabilityPoint,
|
|
53
|
+
StabilityCurve,
|
|
54
|
+
StabilityCalculator,
|
|
55
|
+
Tank,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
__all__ = [
|
|
59
|
+
"Hull",
|
|
60
|
+
"Vessel",
|
|
61
|
+
"Silhouette",
|
|
62
|
+
"OpeningType",
|
|
63
|
+
"DownfloodingOpening",
|
|
64
|
+
"HydrostaticState",
|
|
65
|
+
"HydrostaticsCalculator",
|
|
66
|
+
"StabilityPoint",
|
|
67
|
+
"StabilityCurve",
|
|
68
|
+
"StabilityCalculator",
|
|
69
|
+
"Tank",
|
|
70
|
+
]
|
|
Binary file
|
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
# Copyright (C) 2026 Antoine ANCEAU
|
|
2
|
+
#
|
|
3
|
+
# This file is part of navaltoolbox.
|
|
4
|
+
#
|
|
5
|
+
# navaltoolbox is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
Type stubs for navaltoolbox - High-performance naval architecture library.
|
|
20
|
+
|
|
21
|
+
This module provides type hints for IDE autocompletion and static type checking.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from typing import List, Tuple
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"Hull",
|
|
28
|
+
"Vessel",
|
|
29
|
+
"Silhouette",
|
|
30
|
+
"OpeningType",
|
|
31
|
+
"DownfloodingOpening",
|
|
32
|
+
"HydrostaticState",
|
|
33
|
+
"HydrostaticsCalculator",
|
|
34
|
+
"StabilityPoint",
|
|
35
|
+
"StabilityCurve",
|
|
36
|
+
"StabilityCalculator",
|
|
37
|
+
"Tank",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Hull:
|
|
42
|
+
"""A hull geometry loaded from an STL file.
|
|
43
|
+
|
|
44
|
+
The Hull class represents a 3D mesh geometry that can be used for
|
|
45
|
+
hydrostatic and stability calculations. It supports loading from STL files,
|
|
46
|
+
transformations, and export operations.
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
>>> hull = Hull("path/to/hull.stl")
|
|
50
|
+
>>> print(hull.num_triangles())
|
|
51
|
+
>>> hull.scale(0.001) # Convert from mm to meters
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, file_path: str) -> None:
|
|
55
|
+
"""Load a hull from an STL file.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
file_path: Path to the STL file (ASCII or binary format).
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
IOError: If the file cannot be read or parsed.
|
|
62
|
+
"""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
def get_bounds(self) -> Tuple[float, float, float, float, float, float]:
|
|
66
|
+
"""Returns the bounding box of the hull.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A tuple (xmin, xmax, ymin, ymax, zmin, zmax) in meters.
|
|
70
|
+
"""
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
def num_triangles(self) -> int:
|
|
74
|
+
"""Returns the number of triangles in the mesh."""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
def num_vertices(self) -> int:
|
|
78
|
+
"""Returns the number of vertices in the mesh."""
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
def transform(
|
|
82
|
+
self,
|
|
83
|
+
translation: Tuple[float, float, float],
|
|
84
|
+
rotation: Tuple[float, float, float],
|
|
85
|
+
pivot: Tuple[float, float, float],
|
|
86
|
+
) -> None:
|
|
87
|
+
"""Applies a transformation to the hull.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
translation: Translation vector (dx, dy, dz) in meters.
|
|
91
|
+
rotation: Rotation angles (roll, pitch, yaw) in degrees.
|
|
92
|
+
pivot: Pivot point (x, y, z) for rotation.
|
|
93
|
+
"""
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
def scale(self, factor: float) -> None:
|
|
97
|
+
"""Scales the hull uniformly.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
factor: Scale factor (e.g., 0.001 to convert mm to m).
|
|
101
|
+
"""
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
def scale_xyz(self, sx: float, sy: float, sz: float) -> None:
|
|
105
|
+
"""Scales the hull non-uniformly along each axis.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
sx: Scale factor along X axis.
|
|
109
|
+
sy: Scale factor along Y axis.
|
|
110
|
+
sz: Scale factor along Z axis.
|
|
111
|
+
"""
|
|
112
|
+
...
|
|
113
|
+
|
|
114
|
+
def export_stl(self, file_path: str) -> None:
|
|
115
|
+
"""Exports the hull to an STL file.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
file_path: Output path for the STL file.
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
IOError: If the file cannot be written.
|
|
122
|
+
"""
|
|
123
|
+
...
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class Vessel:
|
|
127
|
+
"""A vessel containing one or more hulls, tanks, and silhouettes.
|
|
128
|
+
|
|
129
|
+
The Vessel class is the main container for naval architecture calculations.
|
|
130
|
+
It can hold multiple hulls (for multihull vessels), tanks for loading
|
|
131
|
+
conditions, and silhouettes for wind heeling calculations.
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
>>> hull = Hull("hull.stl")
|
|
135
|
+
>>> vessel = Vessel(hull)
|
|
136
|
+
>>> print(f"LBP: {vessel.lbp:.2f} m")
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def __init__(self, hull: Hull) -> None:
|
|
140
|
+
"""Create a vessel from a hull.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
hull: The main hull geometry.
|
|
144
|
+
"""
|
|
145
|
+
...
|
|
146
|
+
|
|
147
|
+
def get_bounds(self) -> Tuple[float, float, float, float, float, float]:
|
|
148
|
+
"""Returns the bounding box of all hulls.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
A tuple (xmin, xmax, ymin, ymax, zmin, zmax) in meters.
|
|
152
|
+
"""
|
|
153
|
+
...
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def ap(self) -> float:
|
|
157
|
+
"""Returns the Aft Perpendicular position (X coordinate)."""
|
|
158
|
+
...
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def fp(self) -> float:
|
|
162
|
+
"""Returns the Forward Perpendicular position (X coordinate)."""
|
|
163
|
+
...
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def lbp(self) -> float:
|
|
167
|
+
"""Returns the Length Between Perpendiculars in meters."""
|
|
168
|
+
...
|
|
169
|
+
|
|
170
|
+
def num_hulls(self) -> int:
|
|
171
|
+
"""Returns the number of hulls."""
|
|
172
|
+
...
|
|
173
|
+
|
|
174
|
+
def num_tanks(self) -> int:
|
|
175
|
+
"""Returns the number of tanks."""
|
|
176
|
+
...
|
|
177
|
+
|
|
178
|
+
def add_tank(self, tank: "Tank") -> None:
|
|
179
|
+
"""Add a tank to the vessel.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
tank: The tank to add.
|
|
183
|
+
"""
|
|
184
|
+
...
|
|
185
|
+
|
|
186
|
+
def get_total_tanks_mass(self) -> float:
|
|
187
|
+
"""Returns the total tanks mass in kg."""
|
|
188
|
+
...
|
|
189
|
+
|
|
190
|
+
def get_tanks_center_of_gravity(self) -> Tuple[float, float, float]:
|
|
191
|
+
"""Returns the tanks center of gravity [x, y, z] in meters."""
|
|
192
|
+
...
|
|
193
|
+
|
|
194
|
+
def add_silhouette(self, silhouette: "Silhouette") -> None:
|
|
195
|
+
"""Add a silhouette profile to the vessel.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
silhouette: The silhouette to add.
|
|
199
|
+
"""
|
|
200
|
+
...
|
|
201
|
+
|
|
202
|
+
def num_silhouettes(self) -> int:
|
|
203
|
+
"""Returns the number of silhouettes."""
|
|
204
|
+
...
|
|
205
|
+
|
|
206
|
+
def has_silhouettes(self) -> bool:
|
|
207
|
+
"""Returns true if there are any silhouettes."""
|
|
208
|
+
...
|
|
209
|
+
|
|
210
|
+
def clear_silhouettes(self) -> None:
|
|
211
|
+
"""Removes all silhouettes."""
|
|
212
|
+
...
|
|
213
|
+
|
|
214
|
+
def get_total_emerged_area(self, waterline_z: float) -> float:
|
|
215
|
+
"""Returns the total emerged area from all silhouettes.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
waterline_z: Waterline height in meters.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
Emerged lateral area in m².
|
|
222
|
+
"""
|
|
223
|
+
...
|
|
224
|
+
|
|
225
|
+
def get_combined_emerged_centroid(self, waterline_z: float) -> Tuple[float, float]:
|
|
226
|
+
"""Returns the combined emerged centroid [x, z].
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
waterline_z: Waterline height in meters.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Centroid coordinates (x, z) in meters.
|
|
233
|
+
"""
|
|
234
|
+
...
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class Silhouette:
|
|
238
|
+
"""A 2D silhouette profile in the X-Z plane for wind heeling calculations.
|
|
239
|
+
|
|
240
|
+
Silhouettes represent the lateral projected area of a vessel's superstructure,
|
|
241
|
+
used for calculating wind heeling moments in stability analysis.
|
|
242
|
+
|
|
243
|
+
Example:
|
|
244
|
+
>>> silhouette = Silhouette("superstructure.dxf")
|
|
245
|
+
>>> print(f"Lateral area: {silhouette.get_area():.2f} m²")
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
def __init__(self, file_path: str) -> None:
|
|
249
|
+
"""Load a silhouette from a DXF file.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
file_path: Path to the DXF file.
|
|
253
|
+
|
|
254
|
+
Raises:
|
|
255
|
+
IOError: If the file cannot be read or parsed.
|
|
256
|
+
"""
|
|
257
|
+
...
|
|
258
|
+
|
|
259
|
+
@staticmethod
|
|
260
|
+
def from_vtk(file_path: str) -> "Silhouette":
|
|
261
|
+
"""Load a silhouette from a VTK file (.vtk or .vtp polyline).
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
file_path: Path to the VTK file.
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
A new Silhouette instance.
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
IOError: If the file cannot be read or parsed.
|
|
271
|
+
"""
|
|
272
|
+
...
|
|
273
|
+
|
|
274
|
+
@staticmethod
|
|
275
|
+
def from_points(points: List[Tuple[float, float]], name: str) -> "Silhouette":
|
|
276
|
+
"""Create a silhouette from a list of points.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
points: List of (x, z) coordinates defining the contour.
|
|
280
|
+
name: Name identifier for the silhouette.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
A new Silhouette instance.
|
|
284
|
+
"""
|
|
285
|
+
...
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
def name(self) -> str:
|
|
289
|
+
"""Returns the silhouette name."""
|
|
290
|
+
...
|
|
291
|
+
|
|
292
|
+
def num_points(self) -> int:
|
|
293
|
+
"""Returns the number of points in the contour."""
|
|
294
|
+
...
|
|
295
|
+
|
|
296
|
+
def is_closed(self) -> bool:
|
|
297
|
+
"""Returns true if the contour is closed."""
|
|
298
|
+
...
|
|
299
|
+
|
|
300
|
+
def get_points(self) -> List[Tuple[float, float, float]]:
|
|
301
|
+
"""Returns the points as a list of tuples [(x, y, z), ...]."""
|
|
302
|
+
...
|
|
303
|
+
|
|
304
|
+
def get_area(self) -> float:
|
|
305
|
+
"""Returns the total lateral area in m²."""
|
|
306
|
+
...
|
|
307
|
+
|
|
308
|
+
def get_centroid(self) -> Tuple[float, float]:
|
|
309
|
+
"""Returns the centroid [x, z] in meters."""
|
|
310
|
+
...
|
|
311
|
+
|
|
312
|
+
def get_bounds(self) -> Tuple[float, float, float, float]:
|
|
313
|
+
"""Returns the bounding box (x_min, x_max, z_min, z_max)."""
|
|
314
|
+
...
|
|
315
|
+
|
|
316
|
+
def get_emerged_area(self, waterline_z: float) -> float:
|
|
317
|
+
"""Returns the emerged area above waterline in m².
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
waterline_z: Waterline height in meters.
|
|
321
|
+
"""
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
def get_emerged_centroid(self, waterline_z: float) -> Tuple[float, float]:
|
|
325
|
+
"""Returns the centroid of emerged area [x, z].
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
waterline_z: Waterline height in meters.
|
|
329
|
+
"""
|
|
330
|
+
...
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class OpeningType:
|
|
334
|
+
"""Type of opening that can cause downflooding.
|
|
335
|
+
|
|
336
|
+
Use the static methods to create specific opening types:
|
|
337
|
+
- OpeningType.vent()
|
|
338
|
+
- OpeningType.air_pipe()
|
|
339
|
+
- OpeningType.hatch()
|
|
340
|
+
- OpeningType.door()
|
|
341
|
+
- OpeningType.window()
|
|
342
|
+
- OpeningType.other("custom_name")
|
|
343
|
+
"""
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def vent() -> "OpeningType":
|
|
347
|
+
"""Creates a vent opening type."""
|
|
348
|
+
...
|
|
349
|
+
|
|
350
|
+
@staticmethod
|
|
351
|
+
def air_pipe() -> "OpeningType":
|
|
352
|
+
"""Creates an air pipe opening type."""
|
|
353
|
+
...
|
|
354
|
+
|
|
355
|
+
@staticmethod
|
|
356
|
+
def hatch() -> "OpeningType":
|
|
357
|
+
"""Creates a hatch opening type."""
|
|
358
|
+
...
|
|
359
|
+
|
|
360
|
+
@staticmethod
|
|
361
|
+
def door() -> "OpeningType":
|
|
362
|
+
"""Creates a door opening type."""
|
|
363
|
+
...
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def window() -> "OpeningType":
|
|
367
|
+
"""Creates a window opening type."""
|
|
368
|
+
...
|
|
369
|
+
|
|
370
|
+
@staticmethod
|
|
371
|
+
def other(name: str) -> "OpeningType":
|
|
372
|
+
"""Creates a custom opening type.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
name: Custom name for the opening type.
|
|
376
|
+
"""
|
|
377
|
+
...
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class DownfloodingOpening:
|
|
381
|
+
"""A downflooding opening point or contour.
|
|
382
|
+
|
|
383
|
+
Downflooding openings represent locations where water can enter the vessel
|
|
384
|
+
when heeled or trimmed. They are used in IMO intact stability calculations
|
|
385
|
+
to determine flooding angles.
|
|
386
|
+
|
|
387
|
+
Example:
|
|
388
|
+
>>> opening = DownfloodingOpening.from_point(
|
|
389
|
+
... "engine_vent", (50.0, 2.5, 8.0), OpeningType.vent()
|
|
390
|
+
... )
|
|
391
|
+
>>> if opening.is_submerged(heel=30.0, trim=0.0, pivot=(50, 0, 5), waterline_z=3.0):
|
|
392
|
+
... print("Opening flooded!")
|
|
393
|
+
"""
|
|
394
|
+
|
|
395
|
+
@staticmethod
|
|
396
|
+
def from_point(
|
|
397
|
+
name: str,
|
|
398
|
+
position: Tuple[float, float, float],
|
|
399
|
+
opening_type: OpeningType,
|
|
400
|
+
) -> "DownfloodingOpening":
|
|
401
|
+
"""Create a downflooding opening from a single point.
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
name: Identifier for the opening.
|
|
405
|
+
position: Position (x, y, z) in meters.
|
|
406
|
+
opening_type: Type of opening.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
A new DownfloodingOpening instance.
|
|
410
|
+
"""
|
|
411
|
+
...
|
|
412
|
+
|
|
413
|
+
@staticmethod
|
|
414
|
+
def from_contour(
|
|
415
|
+
name: str,
|
|
416
|
+
points: List[Tuple[float, float, float]],
|
|
417
|
+
opening_type: OpeningType,
|
|
418
|
+
) -> "DownfloodingOpening":
|
|
419
|
+
"""Create a downflooding opening from a contour (polyline).
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
name: Identifier for the opening.
|
|
423
|
+
points: List of (x, y, z) coordinates defining the contour.
|
|
424
|
+
opening_type: Type of opening.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
A new DownfloodingOpening instance.
|
|
428
|
+
"""
|
|
429
|
+
...
|
|
430
|
+
|
|
431
|
+
@property
|
|
432
|
+
def name(self) -> str:
|
|
433
|
+
"""Returns the opening name."""
|
|
434
|
+
...
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def is_active(self) -> bool:
|
|
438
|
+
"""Check if opening is active (considered in calculations)."""
|
|
439
|
+
...
|
|
440
|
+
|
|
441
|
+
def set_active(self, active: bool) -> None:
|
|
442
|
+
"""Set opening active state.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
active: True to include in calculations, False to ignore.
|
|
446
|
+
"""
|
|
447
|
+
...
|
|
448
|
+
|
|
449
|
+
def num_points(self) -> int:
|
|
450
|
+
"""Get number of points defining the opening."""
|
|
451
|
+
...
|
|
452
|
+
|
|
453
|
+
def get_points(self) -> List[Tuple[float, float, float]]:
|
|
454
|
+
"""Get all points as [(x, y, z), ...]."""
|
|
455
|
+
...
|
|
456
|
+
|
|
457
|
+
def is_submerged(
|
|
458
|
+
self,
|
|
459
|
+
heel: float,
|
|
460
|
+
trim: float,
|
|
461
|
+
pivot: Tuple[float, float, float],
|
|
462
|
+
waterline_z: float,
|
|
463
|
+
) -> bool:
|
|
464
|
+
"""Check if the opening is submerged at given heel/trim/draft.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
heel: Heel angle in degrees (positive = starboard down).
|
|
468
|
+
trim: Trim angle in degrees (positive = stern down).
|
|
469
|
+
pivot: Rotation pivot point (x, y, z) in meters.
|
|
470
|
+
waterline_z: Waterline height in meters.
|
|
471
|
+
|
|
472
|
+
Returns:
|
|
473
|
+
True if any point of the opening is below the waterline.
|
|
474
|
+
"""
|
|
475
|
+
...
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
class HydrostaticState:
|
|
479
|
+
"""Result of hydrostatic calculations.
|
|
480
|
+
|
|
481
|
+
Contains the hydrostatic properties at a specific floating condition.
|
|
482
|
+
|
|
483
|
+
Attributes:
|
|
484
|
+
draft: Draft at midship in meters.
|
|
485
|
+
trim: Trim angle in degrees.
|
|
486
|
+
heel: Heel angle in degrees.
|
|
487
|
+
volume: Submerged volume in m³.
|
|
488
|
+
displacement: Displacement mass in kg.
|
|
489
|
+
lcb: Longitudinal center of buoyancy (X) in meters.
|
|
490
|
+
tcb: Transverse center of buoyancy (Y) in meters.
|
|
491
|
+
vcb: Vertical center of buoyancy (Z) in meters.
|
|
492
|
+
"""
|
|
493
|
+
|
|
494
|
+
draft: float
|
|
495
|
+
trim: float
|
|
496
|
+
heel: float
|
|
497
|
+
volume: float
|
|
498
|
+
displacement: float
|
|
499
|
+
lcb: float
|
|
500
|
+
tcb: float
|
|
501
|
+
vcb: float
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
class HydrostaticsCalculator:
|
|
505
|
+
"""Calculator for hydrostatic properties.
|
|
506
|
+
|
|
507
|
+
Performs hydrostatic calculations on a vessel, including volume,
|
|
508
|
+
center of buoyancy, and draft finding.
|
|
509
|
+
|
|
510
|
+
Example:
|
|
511
|
+
>>> hull = Hull("hull.stl")
|
|
512
|
+
>>> vessel = Vessel(hull)
|
|
513
|
+
>>> calc = HydrostaticsCalculator(vessel, water_density=1025.0)
|
|
514
|
+
>>> state = calc.calculate_at_draft(draft=5.0)
|
|
515
|
+
>>> print(f"Displacement: {state.displacement:.0f} kg")
|
|
516
|
+
"""
|
|
517
|
+
|
|
518
|
+
def __init__(self, vessel: Vessel, water_density: float = 1025.0) -> None:
|
|
519
|
+
"""Create a hydrostatics calculator for a vessel.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
vessel: The vessel to analyze.
|
|
523
|
+
water_density: Water density in kg/m³ (default: seawater 1025).
|
|
524
|
+
"""
|
|
525
|
+
...
|
|
526
|
+
|
|
527
|
+
def calculate_at_draft(
|
|
528
|
+
self,
|
|
529
|
+
draft: float,
|
|
530
|
+
trim: float = 0.0,
|
|
531
|
+
heel: float = 0.0,
|
|
532
|
+
vcg: float = 0.0,
|
|
533
|
+
) -> HydrostaticState:
|
|
534
|
+
"""Calculate hydrostatics at a given draft, trim, and heel.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
draft: Draft at midship in meters.
|
|
538
|
+
trim: Trim angle in degrees (default: 0).
|
|
539
|
+
heel: Heel angle in degrees (default: 0).
|
|
540
|
+
vcg: Vertical center of gravity in meters (default: 0).
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
HydrostaticState with calculated properties.
|
|
544
|
+
|
|
545
|
+
Raises:
|
|
546
|
+
ValueError: If no submerged volume at this draft.
|
|
547
|
+
"""
|
|
548
|
+
...
|
|
549
|
+
|
|
550
|
+
def find_draft_for_displacement(self, displacement_mass: float) -> float:
|
|
551
|
+
"""Find the draft for a given displacement mass.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
displacement_mass: Target displacement in kg.
|
|
555
|
+
|
|
556
|
+
Returns:
|
|
557
|
+
Draft in meters that achieves the target displacement.
|
|
558
|
+
|
|
559
|
+
Raises:
|
|
560
|
+
ValueError: If the displacement cannot be achieved.
|
|
561
|
+
"""
|
|
562
|
+
...
|
|
563
|
+
|
|
564
|
+
@property
|
|
565
|
+
def water_density(self) -> float:
|
|
566
|
+
"""Returns the water density in kg/m³."""
|
|
567
|
+
...
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
class StabilityPoint:
|
|
571
|
+
"""A point on a stability curve.
|
|
572
|
+
|
|
573
|
+
Represents the stability properties at a specific heel angle.
|
|
574
|
+
|
|
575
|
+
Attributes:
|
|
576
|
+
heel: Heel angle in degrees.
|
|
577
|
+
draft: Draft at this heel angle in meters.
|
|
578
|
+
trim: Trim angle at this heel in degrees.
|
|
579
|
+
gz: Righting arm (GZ) in meters.
|
|
580
|
+
is_flooding: True if any downflooding opening is submerged.
|
|
581
|
+
flooded_openings: List of names of submerged openings.
|
|
582
|
+
"""
|
|
583
|
+
|
|
584
|
+
heel: float
|
|
585
|
+
draft: float
|
|
586
|
+
trim: float
|
|
587
|
+
gz: float
|
|
588
|
+
is_flooding: bool
|
|
589
|
+
flooded_openings: List[str]
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
class StabilityCurve:
|
|
593
|
+
"""A complete GZ stability curve.
|
|
594
|
+
|
|
595
|
+
Contains the full righting arm curve for a specific loading condition.
|
|
596
|
+
|
|
597
|
+
Example:
|
|
598
|
+
>>> curve = calc.calculate_gz_curve(
|
|
599
|
+
... displacement_mass=10000,
|
|
600
|
+
... cog=(50.0, 0.0, 5.0),
|
|
601
|
+
... heels=[0, 10, 20, 30, 40, 50, 60]
|
|
602
|
+
... )
|
|
603
|
+
>>> for heel, gz in zip(curve.heels(), curve.values()):
|
|
604
|
+
... print(f"Heel: {heel}°, GZ: {gz:.3f} m")
|
|
605
|
+
"""
|
|
606
|
+
|
|
607
|
+
@property
|
|
608
|
+
def displacement(self) -> float:
|
|
609
|
+
"""Returns the displacement in kg."""
|
|
610
|
+
...
|
|
611
|
+
|
|
612
|
+
def heels(self) -> List[float]:
|
|
613
|
+
"""Returns the heel angles in degrees."""
|
|
614
|
+
...
|
|
615
|
+
|
|
616
|
+
def values(self) -> List[float]:
|
|
617
|
+
"""Returns the GZ values in meters."""
|
|
618
|
+
...
|
|
619
|
+
|
|
620
|
+
def points(self) -> List[Tuple[float, float, float, float]]:
|
|
621
|
+
"""Returns the points as a list of tuples (heel, draft, trim, gz)."""
|
|
622
|
+
...
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class StabilityCalculator:
|
|
626
|
+
"""Calculator for stability curves (GZ).
|
|
627
|
+
|
|
628
|
+
Performs intact stability calculations, generating GZ curves for
|
|
629
|
+
specified loading conditions.
|
|
630
|
+
|
|
631
|
+
Example:
|
|
632
|
+
>>> hull = Hull("hull.stl")
|
|
633
|
+
>>> vessel = Vessel(hull)
|
|
634
|
+
>>> calc = StabilityCalculator(vessel, water_density=1025.0)
|
|
635
|
+
>>> curve = calc.calculate_gz_curve(
|
|
636
|
+
... displacement_mass=50000,
|
|
637
|
+
... cog=(45.0, 0.0, 6.5),
|
|
638
|
+
... heels=list(range(0, 91, 5))
|
|
639
|
+
... )
|
|
640
|
+
"""
|
|
641
|
+
|
|
642
|
+
def __init__(self, vessel: Vessel, water_density: float = 1025.0) -> None:
|
|
643
|
+
"""Create a stability calculator for a vessel.
|
|
644
|
+
|
|
645
|
+
Args:
|
|
646
|
+
vessel: The vessel to analyze.
|
|
647
|
+
water_density: Water density in kg/m³ (default: seawater 1025).
|
|
648
|
+
"""
|
|
649
|
+
...
|
|
650
|
+
|
|
651
|
+
def calculate_gz_curve(
|
|
652
|
+
self,
|
|
653
|
+
displacement_mass: float,
|
|
654
|
+
cog: Tuple[float, float, float],
|
|
655
|
+
heels: List[float],
|
|
656
|
+
) -> StabilityCurve:
|
|
657
|
+
"""Calculate the GZ curve for a given loading condition.
|
|
658
|
+
|
|
659
|
+
Args:
|
|
660
|
+
displacement_mass: Displacement in kg.
|
|
661
|
+
cog: Center of gravity (x, y, z) in meters.
|
|
662
|
+
heels: List of heel angles in degrees to calculate.
|
|
663
|
+
|
|
664
|
+
Returns:
|
|
665
|
+
StabilityCurve with GZ values at each heel angle.
|
|
666
|
+
"""
|
|
667
|
+
...
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
class Tank:
|
|
671
|
+
"""A tank with fluid management capabilities.
|
|
672
|
+
|
|
673
|
+
Represents a fluid tank on a vessel, with support for fill level
|
|
674
|
+
management and free surface effect calculations.
|
|
675
|
+
|
|
676
|
+
Example:
|
|
677
|
+
>>> tank = Tank.from_box(
|
|
678
|
+
... name="FO_1P",
|
|
679
|
+
... x_min=20.0, x_max=25.0,
|
|
680
|
+
... y_min=-5.0, y_max=0.0,
|
|
681
|
+
... z_min=0.0, z_max=3.0,
|
|
682
|
+
... fluid_density=850.0 # Fuel oil
|
|
683
|
+
... )
|
|
684
|
+
>>> tank.fill_percent = 80.0
|
|
685
|
+
>>> print(f"Mass: {tank.fluid_mass:.0f} kg")
|
|
686
|
+
"""
|
|
687
|
+
|
|
688
|
+
@staticmethod
|
|
689
|
+
def from_box(
|
|
690
|
+
name: str,
|
|
691
|
+
x_min: float,
|
|
692
|
+
x_max: float,
|
|
693
|
+
y_min: float,
|
|
694
|
+
y_max: float,
|
|
695
|
+
z_min: float,
|
|
696
|
+
z_max: float,
|
|
697
|
+
fluid_density: float,
|
|
698
|
+
) -> "Tank":
|
|
699
|
+
"""Create a box-shaped tank.
|
|
700
|
+
|
|
701
|
+
Args:
|
|
702
|
+
name: Tank identifier (e.g., "FO_1P", "FW_2S").
|
|
703
|
+
x_min: Minimum X coordinate in meters.
|
|
704
|
+
x_max: Maximum X coordinate in meters.
|
|
705
|
+
y_min: Minimum Y coordinate in meters (negative = port).
|
|
706
|
+
y_max: Maximum Y coordinate in meters (positive = starboard).
|
|
707
|
+
z_min: Minimum Z coordinate in meters (bottom).
|
|
708
|
+
z_max: Maximum Z coordinate in meters (top).
|
|
709
|
+
fluid_density: Fluid density in kg/m³.
|
|
710
|
+
|
|
711
|
+
Returns:
|
|
712
|
+
A new Tank instance.
|
|
713
|
+
"""
|
|
714
|
+
...
|
|
715
|
+
|
|
716
|
+
@property
|
|
717
|
+
def name(self) -> str:
|
|
718
|
+
"""Returns the tank name."""
|
|
719
|
+
...
|
|
720
|
+
|
|
721
|
+
@property
|
|
722
|
+
def total_volume(self) -> float:
|
|
723
|
+
"""Returns the total volume in m³."""
|
|
724
|
+
...
|
|
725
|
+
|
|
726
|
+
@property
|
|
727
|
+
def fill_level(self) -> float:
|
|
728
|
+
"""Returns the fill level as a fraction (0-1)."""
|
|
729
|
+
...
|
|
730
|
+
|
|
731
|
+
@fill_level.setter
|
|
732
|
+
def fill_level(self, level: float) -> None:
|
|
733
|
+
"""Sets the fill level as a fraction (0-1)."""
|
|
734
|
+
...
|
|
735
|
+
|
|
736
|
+
@property
|
|
737
|
+
def fill_percent(self) -> float:
|
|
738
|
+
"""Returns the fill level as a percentage (0-100)."""
|
|
739
|
+
...
|
|
740
|
+
|
|
741
|
+
@fill_percent.setter
|
|
742
|
+
def fill_percent(self, percent: float) -> None:
|
|
743
|
+
"""Sets the fill level as a percentage (0-100)."""
|
|
744
|
+
...
|
|
745
|
+
|
|
746
|
+
@property
|
|
747
|
+
def fill_volume(self) -> float:
|
|
748
|
+
"""Returns the filled volume in m³."""
|
|
749
|
+
...
|
|
750
|
+
|
|
751
|
+
@property
|
|
752
|
+
def fluid_mass(self) -> float:
|
|
753
|
+
"""Returns the fluid mass in kg."""
|
|
754
|
+
...
|
|
755
|
+
|
|
756
|
+
@property
|
|
757
|
+
def center_of_gravity(self) -> Tuple[float, float, float]:
|
|
758
|
+
"""Returns the center of gravity [x, y, z] in meters."""
|
|
759
|
+
...
|
|
760
|
+
|
|
761
|
+
@property
|
|
762
|
+
def free_surface_moment_t(self) -> float:
|
|
763
|
+
"""Returns the transverse free surface moment in m⁴."""
|
|
764
|
+
...
|
|
765
|
+
|
|
766
|
+
@property
|
|
767
|
+
def free_surface_moment_l(self) -> float:
|
|
768
|
+
"""Returns the longitudinal free surface moment in m⁴."""
|
|
769
|
+
...
|
navaltoolbox/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: navaltoolbox
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Science/Research
|
|
6
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Rust
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering
|
|
15
|
+
Summary: High-performance naval architecture library for hydrostatics, stability, and tank calculations
|
|
16
|
+
Home-Page: https://github.com/NavalToolbox/navaltoolbox-lib
|
|
17
|
+
Author: Antoine ANCEAU
|
|
18
|
+
License: AGPL-3.0-or-later
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Project-URL: Repository, https://github.com/NavalToolbox/navaltoolbox-lib
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
navaltoolbox\__init__.py,sha256=MPmxS-zhpOmPqW2W2B-ELfUdp5SEI4GoY7R0sBSrVxk,2286
|
|
2
|
+
navaltoolbox\navaltoolbox.cp39-win_amd64.pyd,sha256=i5nDqGe_fqvdw8u5T-SXGBxwHd5Z0UpEy2ASdu9qxqE,3393024
|
|
3
|
+
navaltoolbox\navaltoolbox.pyi,sha256=nDB0QomQCnwjSO9aA5CurG5zmO8yyNqmNxihbnyY5yY,22696
|
|
4
|
+
navaltoolbox\py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
navaltoolbox-0.1.0.dist-info\METADATA,sha256=odwRz6g62D1jLGaV-732leV7rB8nUHPEzaEKdQ8GCfw,943
|
|
6
|
+
navaltoolbox-0.1.0.dist-info\WHEEL,sha256=H5klTgXu3iVXpFbMzUkXja9m3gL244ExCR0k1sRMImo,95
|
|
7
|
+
navaltoolbox-0.1.0.dist-info\RECORD,,
|