symcad.parts.composite.YFormAirfoils

  1#!/usr/bin/env python3
  2# Copyright (C) 2022, Will Hedgecock
  3#
  4# This program is free software: you can redistribute it and/or modify
  5# it under the terms of the GNU General Public License as published by
  6# the Free Software Foundation, either version 3 of the License, or
  7# (at your option) any later version.
  8#
  9# This program is distributed in the hope that it will be useful,
 10# but WITHOUT ANY WARRANTY; without even the implied warranty of
 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12# GNU General Public License for more details.
 13#
 14# You should have received a copy of the GNU General Public License
 15# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16
 17from __future__ import annotations
 18from PyFreeCAD.FreeCAD import FreeCAD, Part
 19from typing import Dict, Optional, Tuple, Union
 20from sympy import Expr, Symbol, sqrt, sin, cos
 21from . import CompositeShape
 22import math
 23
 24class YFormAirfoils(CompositeShape):
 25   """Model representing a set of Y-form parameteric airfoils.
 26
 27   By default, the airfoils are oriented in the following configuration:
 28
 29   ![YFormAirfoils](https://symbench.github.io/SymCAD/images/YFormAirfoils.png)
 30
 31   The `geometry` of this shape includes the following parameters:
 32
 33   - `max_thickness`: Maximum thickness (in `% of length`) of each airfoil
 34   - `chord_length`: Length (in `m`) of the chord of each airfoil
 35   - `span`: Width (in `m`) of each airfoil
 36   - `separation_radius`: Radius (in `m`) of separation between each airfoil
 37   - `curvature_tilt`: Amount of tilt (in `deg`) of each airfoil
 38
 39   Note that the above dimensions should be interpreted as if the airfoils are unrotated. In other
 40   words, any shape rotation takes place *after* the airfoil dimensions have been specified.
 41   """
 42
 43   # Constructor ----------------------------------------------------------------------------------
 44
 45   def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None:
 46      """Initializes a Y-form parametric airfoil object.
 47
 48      Parameters
 49      ----------
 50      identifier : `str`
 51         Unique identifying name for the object.
 52      material_density_kg_m3 : `float`, optional, default=1.0
 53         Uniform material density in `kg/m^3` to be used in mass property calculations.
 54      """
 55      super().__init__(identifier, self.__create_cad__, None, material_density_kg_m3)
 56      setattr(self.geometry, 'max_thickness', Symbol(self.name + '_max_thickness'))
 57      setattr(self.geometry, 'chord_length', Symbol(self.name + '_chord_length'))
 58      setattr(self.geometry, 'span', Symbol(self.name + '_span'))
 59      setattr(self.geometry, 'separation_radius', Symbol(self.name + '_separation_radius'))
 60      setattr(self.geometry, 'curvature_tilt', Symbol(self.name + '_curvature_tilt'))
 61
 62
 63   # CAD generation function ----------------------------------------------------------------------
 64
 65   @staticmethod
 66   def z_val(x: float, max_thickness: float, chord_length: float) -> float:
 67      return 5.0 * max_thickness * chord_length * (
 68         (0.2969 * x**0.5) - (0.1260 * x) - (0.3516 * x**2) + (0.2843 * x**3) - (0.1036 * x**4))
 69
 70   @staticmethod
 71   def __create_cad__(params: Dict[str, float], _fully_displace: bool) -> Part.Solid:
 72      """Scripted CAD generation method for `YFormAirfoils`."""
 73      doc = FreeCAD.newDocument('Temp')
 74      max_thickness_percent = params['max_thickness']
 75      chord_length_mm = 1000.0 * params['chord_length']
 76      span_mm = 1000.0 * params['span']
 77      separation_radius_mm = 1000.0 * params['separation_radius']
 78      curvature_tilt = params['curvature_tilt']
 79      x, points_upper, points_lower = 0.0, [], []
 80      while x <= 1.009:
 81         points_upper.append(FreeCAD.Vector(x * chord_length_mm,
 82                                            YFormAirfoils.z_val(x, max_thickness_percent,
 83                                                                   chord_length_mm)))
 84         points_lower.append(FreeCAD.Vector(x * chord_length_mm,
 85                                            -YFormAirfoils.z_val(x, max_thickness_percent,
 86                                                                    chord_length_mm)))
 87         x += 0.01
 88      bodies = []
 89      for i in range(3):
 90         body = doc.addObject('PartDesign::Body','Airfoil' + str(i))
 91         sketch = doc.addObject('Sketcher::SketchObject', 'Sketch' + str(i))
 92         sketch.Support = doc.XZ_Plane
 93         sketch.MapMode = 'FlatFace'
 94         body.addObject(sketch)
 95         sketch.addGeometry(Part.BSplineCurve(points_upper, None, None,
 96                                              False, 3, None, False), False)
 97         sketch.addGeometry(Part.BSplineCurve(points_lower, None, None,
 98                                              False, 3, None, False), False)
 99         pad = doc.addObject('PartDesign::Pad', 'Pad' + str(i))
100         body.addObject(pad)
101         pad.Length = int(span_mm)
102         pad.Profile = sketch
103         y_offset = sin(math.pi / 3.0) * separation_radius_mm
104         z_offset = cos(math.pi / 3.0) * separation_radius_mm
105         placement_vector = \
106            FreeCAD.Vector(0, y_offset if i == 1 else (-y_offset if i == 2 else 0),
107                              -z_offset if i == 1 or i == 2 else separation_radius_mm)
108         body.Placement = FreeCAD.Placement(placement_vector,
109                          FreeCAD.Rotation(-curvature_tilt if i == 1 else
110                                           (curvature_tilt if i == 2 else 0),
111                                           curvature_tilt if i == 0 else 0, -90.0 - (i * 120.0)))
112         bodies.append(body)
113      fusion = doc.addObject('Part::MultiFuse', 'Fusion')
114      fusion.Shapes = bodies
115      doc.recompute()
116      airfoils = fusion.Shape
117      FreeCAD.closeDocument(doc.Name)
118      return airfoils
119
120
121   # Geometry setter ------------------------------------------------------------------------------
122
123   def set_geometry(self, *, max_thickness_percent: Union[float, None],
124                             chord_length_m: Union[float, None],
125                             span_m: Union[float, None],
126                             separation_radius_m: Union[float, None],
127                             curvature_tilt_deg: Union[float, None]) -> YFormAirfoils:
128      """Sets the physical geometry of the current `YFormAirfoils` object.
129
130      See the `YFormAirfoils` class documentation for a description of each geometric
131      parameter.
132      """
133      self.geometry.set(max_thickness=max_thickness_percent,
134                        chord_length=chord_length_m,
135                        span=span_m,
136                        separation_radius=separation_radius_m,
137                        curvature_tilt=curvature_tilt_deg)
138      return self
139
140   def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
141      parameter_bounds = {
142         'max_thickness': (0.01, 0.90),
143         'chord_length': (0.1, 2.0),
144         'span': (0.0, 2.0),
145         'separation_radius': (0.0, 1.5),
146         'curvature_tilt': (0.0, 45.0)
147      }
148      return parameter_bounds.get(parameter, (0.0, 0.0))
149
150
151   # Geometric properties -------------------------------------------------------------------------
152
153   @property
154   def material_volume(self) -> Union[float, Expr]:
155      return self.displaced_volume
156
157   @property
158   def displaced_volume(self) -> Union[float, Expr]:
159      x, points_upper = 0.0, []
160      while x <= 1.009:
161         points_upper.append((x * self.geometry.chord_length,
162                              YFormAirfoils.z_val(x, self.geometry.max_thickness,
163                                                     self.geometry.chord_length)))
164         x += 0.01
165      area = 0.0
166      for i in range(1, len(points_upper) - 1):
167         area += points_upper[i][1]
168      area = points_upper[0][1] + (2.0 * area) + points_upper[len(points_upper)-1][1]
169      h = (points_upper[len(points_upper)-1][0] - points_upper[0][0]) / (len(points_upper) - 1)
170      return 3.0 * h * area * self.geometry.span
171
172   @property
173   def surface_area(self) -> Union[float, Expr]:
174      x, points_upper = 0.0, []
175      while x <= 1.009:
176         points_upper.append((x * self.geometry.chord_length,
177                              YFormAirfoils.z_val(x, self.geometry.max_thickness,
178                                                     self.geometry.chord_length)))
179         x += 0.01
180      area = 0.0
181      for i in range(1, len(points_upper)):
182         x_diff = (points_upper[i][0] - points_upper[i-1][0])
183         y_diff = (points_upper[i][1] - points_upper[i-1][1])
184         area += sqrt(x_diff**2 + y_diff**2)
185      area = (2.0 * area) * self.geometry.span
186      return 3.0 * area
187
188   @property
189   def unoriented_center_of_gravity(self) -> Tuple[Union[float, Expr],
190                                                   Union[float, Expr],
191                                                   Union[float, Expr]]:
192      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
193      sine = sin(self.geometry.curvature_tilt * math.pi / 180.0)
194      return ((0.41 * cosine * self.geometry.chord_length) + (0.5 * sine * self.geometry.span),
195              0.5 * self.unoriented_width,
196              self.unoriented_height / 3.0)
197
198   @property
199   def unoriented_center_of_buoyancy(self) -> Tuple[Union[float, Expr],
200                                                    Union[float, Expr],
201                                                    Union[float, Expr]]:
202      return self.unoriented_center_of_gravity
203
204   @property
205   def unoriented_length(self) -> Union[float, Expr]:
206      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
207      sine = sin(self.geometry.curvature_tilt * math.pi / 180.0)
208      return (cosine * self.geometry.chord_length) + (sine * self.geometry.span)
209
210   @property
211   def unoriented_width(self) -> Union[float, Expr]:
212      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
213      y_offset = sin(math.pi / 3.0) * self.geometry.separation_radius
214      y_width = cos(math.pi / 6.0) * (cosine * self.geometry.span)
215      return 2.0 * (y_offset + y_width)
216
217   @property
218   def unoriented_height(self) -> Union[float, Expr]:
219      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
220      z_offset = cos(math.pi / 3.0) * self.geometry.separation_radius
221      z_width = sin(math.pi / 6.0) * (cosine * self.geometry.span)
222      return z_offset + z_width + self.geometry.separation_radius + self.geometry.span
223
224   @property
225   def oriented_length(self) -> Union[float, Expr]:
226      # TODO: Implement this
227      return 0
228
229   @property
230   def oriented_width(self) -> Union[float, Expr]:
231      # TODO: Implement this
232      return 0
233
234   @property
235   def oriented_height(self) -> Union[float, Expr]:
236      # TODO: Implement this
237      return 0
class YFormAirfoils(symcad.parts.composite.CompositeShape):
 25class YFormAirfoils(CompositeShape):
 26   """Model representing a set of Y-form parameteric airfoils.
 27
 28   By default, the airfoils are oriented in the following configuration:
 29
 30   ![YFormAirfoils](https://symbench.github.io/SymCAD/images/YFormAirfoils.png)
 31
 32   The `geometry` of this shape includes the following parameters:
 33
 34   - `max_thickness`: Maximum thickness (in `% of length`) of each airfoil
 35   - `chord_length`: Length (in `m`) of the chord of each airfoil
 36   - `span`: Width (in `m`) of each airfoil
 37   - `separation_radius`: Radius (in `m`) of separation between each airfoil
 38   - `curvature_tilt`: Amount of tilt (in `deg`) of each airfoil
 39
 40   Note that the above dimensions should be interpreted as if the airfoils are unrotated. In other
 41   words, any shape rotation takes place *after* the airfoil dimensions have been specified.
 42   """
 43
 44   # Constructor ----------------------------------------------------------------------------------
 45
 46   def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None:
 47      """Initializes a Y-form parametric airfoil object.
 48
 49      Parameters
 50      ----------
 51      identifier : `str`
 52         Unique identifying name for the object.
 53      material_density_kg_m3 : `float`, optional, default=1.0
 54         Uniform material density in `kg/m^3` to be used in mass property calculations.
 55      """
 56      super().__init__(identifier, self.__create_cad__, None, material_density_kg_m3)
 57      setattr(self.geometry, 'max_thickness', Symbol(self.name + '_max_thickness'))
 58      setattr(self.geometry, 'chord_length', Symbol(self.name + '_chord_length'))
 59      setattr(self.geometry, 'span', Symbol(self.name + '_span'))
 60      setattr(self.geometry, 'separation_radius', Symbol(self.name + '_separation_radius'))
 61      setattr(self.geometry, 'curvature_tilt', Symbol(self.name + '_curvature_tilt'))
 62
 63
 64   # CAD generation function ----------------------------------------------------------------------
 65
 66   @staticmethod
 67   def z_val(x: float, max_thickness: float, chord_length: float) -> float:
 68      return 5.0 * max_thickness * chord_length * (
 69         (0.2969 * x**0.5) - (0.1260 * x) - (0.3516 * x**2) + (0.2843 * x**3) - (0.1036 * x**4))
 70
 71   @staticmethod
 72   def __create_cad__(params: Dict[str, float], _fully_displace: bool) -> Part.Solid:
 73      """Scripted CAD generation method for `YFormAirfoils`."""
 74      doc = FreeCAD.newDocument('Temp')
 75      max_thickness_percent = params['max_thickness']
 76      chord_length_mm = 1000.0 * params['chord_length']
 77      span_mm = 1000.0 * params['span']
 78      separation_radius_mm = 1000.0 * params['separation_radius']
 79      curvature_tilt = params['curvature_tilt']
 80      x, points_upper, points_lower = 0.0, [], []
 81      while x <= 1.009:
 82         points_upper.append(FreeCAD.Vector(x * chord_length_mm,
 83                                            YFormAirfoils.z_val(x, max_thickness_percent,
 84                                                                   chord_length_mm)))
 85         points_lower.append(FreeCAD.Vector(x * chord_length_mm,
 86                                            -YFormAirfoils.z_val(x, max_thickness_percent,
 87                                                                    chord_length_mm)))
 88         x += 0.01
 89      bodies = []
 90      for i in range(3):
 91         body = doc.addObject('PartDesign::Body','Airfoil' + str(i))
 92         sketch = doc.addObject('Sketcher::SketchObject', 'Sketch' + str(i))
 93         sketch.Support = doc.XZ_Plane
 94         sketch.MapMode = 'FlatFace'
 95         body.addObject(sketch)
 96         sketch.addGeometry(Part.BSplineCurve(points_upper, None, None,
 97                                              False, 3, None, False), False)
 98         sketch.addGeometry(Part.BSplineCurve(points_lower, None, None,
 99                                              False, 3, None, False), False)
100         pad = doc.addObject('PartDesign::Pad', 'Pad' + str(i))
101         body.addObject(pad)
102         pad.Length = int(span_mm)
103         pad.Profile = sketch
104         y_offset = sin(math.pi / 3.0) * separation_radius_mm
105         z_offset = cos(math.pi / 3.0) * separation_radius_mm
106         placement_vector = \
107            FreeCAD.Vector(0, y_offset if i == 1 else (-y_offset if i == 2 else 0),
108                              -z_offset if i == 1 or i == 2 else separation_radius_mm)
109         body.Placement = FreeCAD.Placement(placement_vector,
110                          FreeCAD.Rotation(-curvature_tilt if i == 1 else
111                                           (curvature_tilt if i == 2 else 0),
112                                           curvature_tilt if i == 0 else 0, -90.0 - (i * 120.0)))
113         bodies.append(body)
114      fusion = doc.addObject('Part::MultiFuse', 'Fusion')
115      fusion.Shapes = bodies
116      doc.recompute()
117      airfoils = fusion.Shape
118      FreeCAD.closeDocument(doc.Name)
119      return airfoils
120
121
122   # Geometry setter ------------------------------------------------------------------------------
123
124   def set_geometry(self, *, max_thickness_percent: Union[float, None],
125                             chord_length_m: Union[float, None],
126                             span_m: Union[float, None],
127                             separation_radius_m: Union[float, None],
128                             curvature_tilt_deg: Union[float, None]) -> YFormAirfoils:
129      """Sets the physical geometry of the current `YFormAirfoils` object.
130
131      See the `YFormAirfoils` class documentation for a description of each geometric
132      parameter.
133      """
134      self.geometry.set(max_thickness=max_thickness_percent,
135                        chord_length=chord_length_m,
136                        span=span_m,
137                        separation_radius=separation_radius_m,
138                        curvature_tilt=curvature_tilt_deg)
139      return self
140
141   def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
142      parameter_bounds = {
143         'max_thickness': (0.01, 0.90),
144         'chord_length': (0.1, 2.0),
145         'span': (0.0, 2.0),
146         'separation_radius': (0.0, 1.5),
147         'curvature_tilt': (0.0, 45.0)
148      }
149      return parameter_bounds.get(parameter, (0.0, 0.0))
150
151
152   # Geometric properties -------------------------------------------------------------------------
153
154   @property
155   def material_volume(self) -> Union[float, Expr]:
156      return self.displaced_volume
157
158   @property
159   def displaced_volume(self) -> Union[float, Expr]:
160      x, points_upper = 0.0, []
161      while x <= 1.009:
162         points_upper.append((x * self.geometry.chord_length,
163                              YFormAirfoils.z_val(x, self.geometry.max_thickness,
164                                                     self.geometry.chord_length)))
165         x += 0.01
166      area = 0.0
167      for i in range(1, len(points_upper) - 1):
168         area += points_upper[i][1]
169      area = points_upper[0][1] + (2.0 * area) + points_upper[len(points_upper)-1][1]
170      h = (points_upper[len(points_upper)-1][0] - points_upper[0][0]) / (len(points_upper) - 1)
171      return 3.0 * h * area * self.geometry.span
172
173   @property
174   def surface_area(self) -> Union[float, Expr]:
175      x, points_upper = 0.0, []
176      while x <= 1.009:
177         points_upper.append((x * self.geometry.chord_length,
178                              YFormAirfoils.z_val(x, self.geometry.max_thickness,
179                                                     self.geometry.chord_length)))
180         x += 0.01
181      area = 0.0
182      for i in range(1, len(points_upper)):
183         x_diff = (points_upper[i][0] - points_upper[i-1][0])
184         y_diff = (points_upper[i][1] - points_upper[i-1][1])
185         area += sqrt(x_diff**2 + y_diff**2)
186      area = (2.0 * area) * self.geometry.span
187      return 3.0 * area
188
189   @property
190   def unoriented_center_of_gravity(self) -> Tuple[Union[float, Expr],
191                                                   Union[float, Expr],
192                                                   Union[float, Expr]]:
193      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
194      sine = sin(self.geometry.curvature_tilt * math.pi / 180.0)
195      return ((0.41 * cosine * self.geometry.chord_length) + (0.5 * sine * self.geometry.span),
196              0.5 * self.unoriented_width,
197              self.unoriented_height / 3.0)
198
199   @property
200   def unoriented_center_of_buoyancy(self) -> Tuple[Union[float, Expr],
201                                                    Union[float, Expr],
202                                                    Union[float, Expr]]:
203      return self.unoriented_center_of_gravity
204
205   @property
206   def unoriented_length(self) -> Union[float, Expr]:
207      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
208      sine = sin(self.geometry.curvature_tilt * math.pi / 180.0)
209      return (cosine * self.geometry.chord_length) + (sine * self.geometry.span)
210
211   @property
212   def unoriented_width(self) -> Union[float, Expr]:
213      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
214      y_offset = sin(math.pi / 3.0) * self.geometry.separation_radius
215      y_width = cos(math.pi / 6.0) * (cosine * self.geometry.span)
216      return 2.0 * (y_offset + y_width)
217
218   @property
219   def unoriented_height(self) -> Union[float, Expr]:
220      cosine = cos(self.geometry.curvature_tilt * math.pi / 180.0)
221      z_offset = cos(math.pi / 3.0) * self.geometry.separation_radius
222      z_width = sin(math.pi / 6.0) * (cosine * self.geometry.span)
223      return z_offset + z_width + self.geometry.separation_radius + self.geometry.span
224
225   @property
226   def oriented_length(self) -> Union[float, Expr]:
227      # TODO: Implement this
228      return 0
229
230   @property
231   def oriented_width(self) -> Union[float, Expr]:
232      # TODO: Implement this
233      return 0
234
235   @property
236   def oriented_height(self) -> Union[float, Expr]:
237      # TODO: Implement this
238      return 0

Model representing a set of Y-form parameteric airfoils.

By default, the airfoils are oriented in the following configuration:

YFormAirfoils

The geometry of this shape includes the following parameters:

  • max_thickness: Maximum thickness (in % of length) of each airfoil
  • chord_length: Length (in m) of the chord of each airfoil
  • span: Width (in m) of each airfoil
  • separation_radius: Radius (in m) of separation between each airfoil
  • curvature_tilt: Amount of tilt (in deg) of each airfoil

Note that the above dimensions should be interpreted as if the airfoils are unrotated. In other words, any shape rotation takes place after the airfoil dimensions have been specified.

YFormAirfoils(identifier: str, material_density_kg_m3: Optional[float] = 1.0)
46   def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None:
47      """Initializes a Y-form parametric airfoil object.
48
49      Parameters
50      ----------
51      identifier : `str`
52         Unique identifying name for the object.
53      material_density_kg_m3 : `float`, optional, default=1.0
54         Uniform material density in `kg/m^3` to be used in mass property calculations.
55      """
56      super().__init__(identifier, self.__create_cad__, None, material_density_kg_m3)
57      setattr(self.geometry, 'max_thickness', Symbol(self.name + '_max_thickness'))
58      setattr(self.geometry, 'chord_length', Symbol(self.name + '_chord_length'))
59      setattr(self.geometry, 'span', Symbol(self.name + '_span'))
60      setattr(self.geometry, 'separation_radius', Symbol(self.name + '_separation_radius'))
61      setattr(self.geometry, 'curvature_tilt', Symbol(self.name + '_curvature_tilt'))

Initializes a Y-form parametric airfoil object.

Parameters
  • identifier (str): Unique identifying name for the object.
  • material_density_kg_m3 (float, optional, default=1.0): Uniform material density in kg/m^3 to be used in mass property calculations.
@staticmethod
def z_val(x: float, max_thickness: float, chord_length: float) -> float:
66   @staticmethod
67   def z_val(x: float, max_thickness: float, chord_length: float) -> float:
68      return 5.0 * max_thickness * chord_length * (
69         (0.2969 * x**0.5) - (0.1260 * x) - (0.3516 * x**2) + (0.2843 * x**3) - (0.1036 * x**4))
def set_geometry( self, *, max_thickness_percent: Optional[float], chord_length_m: Optional[float], span_m: Optional[float], separation_radius_m: Optional[float], curvature_tilt_deg: Optional[float]) -> YFormAirfoils:
124   def set_geometry(self, *, max_thickness_percent: Union[float, None],
125                             chord_length_m: Union[float, None],
126                             span_m: Union[float, None],
127                             separation_radius_m: Union[float, None],
128                             curvature_tilt_deg: Union[float, None]) -> YFormAirfoils:
129      """Sets the physical geometry of the current `YFormAirfoils` object.
130
131      See the `YFormAirfoils` class documentation for a description of each geometric
132      parameter.
133      """
134      self.geometry.set(max_thickness=max_thickness_percent,
135                        chord_length=chord_length_m,
136                        span=span_m,
137                        separation_radius=separation_radius_m,
138                        curvature_tilt=curvature_tilt_deg)
139      return self

Sets the physical geometry of the current YFormAirfoils object.

See the YFormAirfoils class documentation for a description of each geometric parameter.

def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
141   def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
142      parameter_bounds = {
143         'max_thickness': (0.01, 0.90),
144         'chord_length': (0.1, 2.0),
145         'span': (0.0, 2.0),
146         'separation_radius': (0.0, 1.5),
147         'curvature_tilt': (0.0, 45.0)
148      }
149      return parameter_bounds.get(parameter, (0.0, 0.0))

Abstract method that must be overridden by a concrete SymPart class to return the minimum and maximum expected bounds for a given geometric parameter.

Parameters
  • parameter (str): Name of the geometric parameter for which to return the minimum and maximum bounds.
Returns
  • Tuple[float, float]: Minimum and maximum bounds for the specified geometric parameter.
material_volume: Union[float, sympy.core.expr.Expr]

Material volume (in m^3) of the SymPart (read-only).

displaced_volume: Union[float, sympy.core.expr.Expr]

Displaced volume (in m^3) of the SymPart (read-only).

surface_area: Union[float, sympy.core.expr.Expr]

Surface/wetted area (in m^2) of the SymPart (read-only).

unoriented_center_of_gravity: Tuple[Union[float, sympy.core.expr.Expr], Union[float, sympy.core.expr.Expr], Union[float, sympy.core.expr.Expr]]

Center of gravity (in m) of the unoriented SymPart (read-only).

unoriented_center_of_buoyancy: Tuple[Union[float, sympy.core.expr.Expr], Union[float, sympy.core.expr.Expr], Union[float, sympy.core.expr.Expr]]

Center of buoyancy (in m) of the unoriented SymPart (read-only).

unoriented_length: Union[float, sympy.core.expr.Expr]

X-axis length (in m) of the bounding box of the unoriented SymPart (read-only).

unoriented_width: Union[float, sympy.core.expr.Expr]

Y-axis width (in m) of the bounding box of the unoriented SymPart (read-only).

unoriented_height: Union[float, sympy.core.expr.Expr]

Z-axis height (in m) of the bounding box of the unoriented SymPart (read-only).

oriented_length: Union[float, sympy.core.expr.Expr]

X-axis length (in m) of the bounding box of the oriented SymPart (read-only).

oriented_width: Union[float, sympy.core.expr.Expr]

Y-axis length (in m) of the bounding box of the oriented SymPart (read-only).

oriented_height: Union[float, sympy.core.expr.Expr]

Z-axis length (in m) of the bounding box of the oriented SymPart (read-only).