symcad.parts.endcaps.FlangedFlatPlate

  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 Part
 19from typing import Dict, Optional, Tuple, Union
 20from sympy import Expr, Symbol
 21from . import EndcapShape
 22import math
 23
 24class FlangedFlatPlate(EndcapShape):
 25   """Model representing a hollow, parametric, flat-plated endcap with flanged corners.
 26
 27   By default, the endcap is oriented such that its base is perpendicular to the z-axis:
 28
 29   ![FlangedFlatPlate](https://symbench.github.io/SymCAD/images/FlangedFlatPlate.png)
 30
 31   The `geometry` of this shape includes the following parameters:
 32
 33   - `radius`: Radius (in `m`) of the base of the FlangedFlatPlate
 34   - `thickness`: Thickness (in `m`) of the shell of the FlangedFlatPlate
 35
 36   Note that the above dimensions should be interpreted as if the FlangedFlatPlate is unrotated.
 37   In other words, any shape rotation takes place *after* the FlangedFlatPlate dimensions have been
 38   specified.
 39   """
 40
 41   # Constructor ----------------------------------------------------------------------------------
 42
 43   def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None:
 44      """Initializes a hollow, parametric, flat-plated endcap object with flanged corners.
 45
 46      Parameters
 47      ----------
 48      identifier : `str`
 49         Unique identifying name for the object.
 50      material_density_kg_m3 : `float`, optional, default=1.0
 51         Uniform material density in `kg/m^3` to be used in mass property calculations.
 52      """
 53      super().__init__(identifier, self.__create_cad__, None, material_density_kg_m3)
 54      setattr(self.geometry, 'radius', Symbol(self.name + '_radius'))
 55      setattr(self.geometry, 'thickness', Symbol(self.name + '_thickness'))
 56
 57
 58   # CAD generation function ----------------------------------------------------------------------
 59
 60   @staticmethod
 61   def __create_cad__(params: Dict[str, float], _fully_displace: bool) -> Part.Solid:
 62      """Scripted CAD generation method for a `FlangedFlatPlate`."""
 63      thickness_mm = 1000.0 * params['thickness']
 64      radius_mm = 1000.0 * params['radius']
 65      flat_plate = Part.makeCylinder(radius_mm, thickness_mm)
 66      return flat_plate.makeFillet(thickness_mm - 0.001, flat_plate.Edges[0:1])
 67
 68
 69   # Geometry setter ------------------------------------------------------------------------------
 70
 71   def set_geometry(self, *, radius_m: Union[float, None],
 72                             thickness_m: Union[float, None]) -> FlangedFlatPlate:
 73      """Sets the physical geometry of the current `FlangedFlatPlate` object.
 74
 75      See the `FlangedFlatPlate` class documentation for a description of each geometric parameter.
 76      """
 77      self.geometry.set(radius=radius_m, thickness=thickness_m)
 78      return self
 79
 80   def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
 81      parameter_bounds = {
 82         'radius': (0.0, 2.0),
 83         'thickness': (0.0, 0.1)
 84      }
 85      return parameter_bounds.get(parameter, (0.0, 0.0))
 86
 87
 88   # Geometric properties -------------------------------------------------------------------------
 89
 90   @property
 91   def material_volume(self) -> Union[float, Expr]:
 92      return self.displaced_volume
 93
 94   @property
 95   def displaced_volume(self) -> Union[float, Expr]:
 96      cylinder_radius = self.geometry.radius - self.geometry.thickness
 97      return (math.pi * cylinder_radius**2 * self.geometry.thickness) + \
 98             (0.25 * math.pi * self.geometry.thickness**2) * \
 99             (2.0 * math.pi * (cylinder_radius + self.geometry.thickness))
100
101   @property
102   def surface_area(self) -> Union[float, Expr]:
103      cylinder_radius = self.geometry.radius - self.geometry.thickness
104      return (math.pi * cylinder_radius**2) + \
105             (2.0 * math.pi * (cylinder_radius + self.geometry.thickness)) * \
106             (2.0 * math.pi * self.geometry.thickness) * 0.25
107
108   @property
109   def unoriented_center_of_gravity(self) -> Tuple[Union[float, Expr],
110                                                   Union[float, Expr],
111                                                   Union[float, Expr]]:
112      return self.geometry.radius, self.geometry.radius, 0.5 * self.geometry.thickness
113
114   @property
115   def unoriented_center_of_buoyancy(self) -> Tuple[Union[float, Expr],
116                                                    Union[float, Expr],
117                                                    Union[float, Expr]]:
118      return self.unoriented_center_of_gravity
119
120   @property
121   def unoriented_length(self) -> Union[float, Expr]:
122      return 2.0 * self.geometry.radius
123
124   @property
125   def unoriented_width(self) -> Union[float, Expr]:
126      return self.unoriented_length
127
128   @property
129   def unoriented_height(self) -> Union[float, Expr]:
130      return self.geometry.thickness
131
132   @property
133   def oriented_length(self) -> Union[float, Expr]:
134      # TODO: Implement this
135      return 0
136
137   @property
138   def oriented_width(self) -> Union[float, Expr]:
139      # TODO: Implement this
140      return 0
141
142   @property
143   def oriented_height(self) -> Union[float, Expr]:
144      # TODO: Implement this
145      return 0
class FlangedFlatPlate(symcad.parts.endcaps.EndcapShape):
 25class FlangedFlatPlate(EndcapShape):
 26   """Model representing a hollow, parametric, flat-plated endcap with flanged corners.
 27
 28   By default, the endcap is oriented such that its base is perpendicular to the z-axis:
 29
 30   ![FlangedFlatPlate](https://symbench.github.io/SymCAD/images/FlangedFlatPlate.png)
 31
 32   The `geometry` of this shape includes the following parameters:
 33
 34   - `radius`: Radius (in `m`) of the base of the FlangedFlatPlate
 35   - `thickness`: Thickness (in `m`) of the shell of the FlangedFlatPlate
 36
 37   Note that the above dimensions should be interpreted as if the FlangedFlatPlate is unrotated.
 38   In other words, any shape rotation takes place *after* the FlangedFlatPlate dimensions have been
 39   specified.
 40   """
 41
 42   # Constructor ----------------------------------------------------------------------------------
 43
 44   def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None:
 45      """Initializes a hollow, parametric, flat-plated endcap object with flanged corners.
 46
 47      Parameters
 48      ----------
 49      identifier : `str`
 50         Unique identifying name for the object.
 51      material_density_kg_m3 : `float`, optional, default=1.0
 52         Uniform material density in `kg/m^3` to be used in mass property calculations.
 53      """
 54      super().__init__(identifier, self.__create_cad__, None, material_density_kg_m3)
 55      setattr(self.geometry, 'radius', Symbol(self.name + '_radius'))
 56      setattr(self.geometry, 'thickness', Symbol(self.name + '_thickness'))
 57
 58
 59   # CAD generation function ----------------------------------------------------------------------
 60
 61   @staticmethod
 62   def __create_cad__(params: Dict[str, float], _fully_displace: bool) -> Part.Solid:
 63      """Scripted CAD generation method for a `FlangedFlatPlate`."""
 64      thickness_mm = 1000.0 * params['thickness']
 65      radius_mm = 1000.0 * params['radius']
 66      flat_plate = Part.makeCylinder(radius_mm, thickness_mm)
 67      return flat_plate.makeFillet(thickness_mm - 0.001, flat_plate.Edges[0:1])
 68
 69
 70   # Geometry setter ------------------------------------------------------------------------------
 71
 72   def set_geometry(self, *, radius_m: Union[float, None],
 73                             thickness_m: Union[float, None]) -> FlangedFlatPlate:
 74      """Sets the physical geometry of the current `FlangedFlatPlate` object.
 75
 76      See the `FlangedFlatPlate` class documentation for a description of each geometric parameter.
 77      """
 78      self.geometry.set(radius=radius_m, thickness=thickness_m)
 79      return self
 80
 81   def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
 82      parameter_bounds = {
 83         'radius': (0.0, 2.0),
 84         'thickness': (0.0, 0.1)
 85      }
 86      return parameter_bounds.get(parameter, (0.0, 0.0))
 87
 88
 89   # Geometric properties -------------------------------------------------------------------------
 90
 91   @property
 92   def material_volume(self) -> Union[float, Expr]:
 93      return self.displaced_volume
 94
 95   @property
 96   def displaced_volume(self) -> Union[float, Expr]:
 97      cylinder_radius = self.geometry.radius - self.geometry.thickness
 98      return (math.pi * cylinder_radius**2 * self.geometry.thickness) + \
 99             (0.25 * math.pi * self.geometry.thickness**2) * \
100             (2.0 * math.pi * (cylinder_radius + self.geometry.thickness))
101
102   @property
103   def surface_area(self) -> Union[float, Expr]:
104      cylinder_radius = self.geometry.radius - self.geometry.thickness
105      return (math.pi * cylinder_radius**2) + \
106             (2.0 * math.pi * (cylinder_radius + self.geometry.thickness)) * \
107             (2.0 * math.pi * self.geometry.thickness) * 0.25
108
109   @property
110   def unoriented_center_of_gravity(self) -> Tuple[Union[float, Expr],
111                                                   Union[float, Expr],
112                                                   Union[float, Expr]]:
113      return self.geometry.radius, self.geometry.radius, 0.5 * self.geometry.thickness
114
115   @property
116   def unoriented_center_of_buoyancy(self) -> Tuple[Union[float, Expr],
117                                                    Union[float, Expr],
118                                                    Union[float, Expr]]:
119      return self.unoriented_center_of_gravity
120
121   @property
122   def unoriented_length(self) -> Union[float, Expr]:
123      return 2.0 * self.geometry.radius
124
125   @property
126   def unoriented_width(self) -> Union[float, Expr]:
127      return self.unoriented_length
128
129   @property
130   def unoriented_height(self) -> Union[float, Expr]:
131      return self.geometry.thickness
132
133   @property
134   def oriented_length(self) -> Union[float, Expr]:
135      # TODO: Implement this
136      return 0
137
138   @property
139   def oriented_width(self) -> Union[float, Expr]:
140      # TODO: Implement this
141      return 0
142
143   @property
144   def oriented_height(self) -> Union[float, Expr]:
145      # TODO: Implement this
146      return 0

Model representing a hollow, parametric, flat-plated endcap with flanged corners.

By default, the endcap is oriented such that its base is perpendicular to the z-axis:

FlangedFlatPlate

The geometry of this shape includes the following parameters:

  • radius: Radius (in m) of the base of the FlangedFlatPlate
  • thickness: Thickness (in m) of the shell of the FlangedFlatPlate

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

FlangedFlatPlate(identifier: str, material_density_kg_m3: Optional[float] = 1.0)
44   def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None:
45      """Initializes a hollow, parametric, flat-plated endcap object with flanged corners.
46
47      Parameters
48      ----------
49      identifier : `str`
50         Unique identifying name for the object.
51      material_density_kg_m3 : `float`, optional, default=1.0
52         Uniform material density in `kg/m^3` to be used in mass property calculations.
53      """
54      super().__init__(identifier, self.__create_cad__, None, material_density_kg_m3)
55      setattr(self.geometry, 'radius', Symbol(self.name + '_radius'))
56      setattr(self.geometry, 'thickness', Symbol(self.name + '_thickness'))

Initializes a hollow, parametric, flat-plated endcap object with flanged corners.

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.
def set_geometry( self, *, radius_m: Optional[float], thickness_m: Optional[float]) -> FlangedFlatPlate:
72   def set_geometry(self, *, radius_m: Union[float, None],
73                             thickness_m: Union[float, None]) -> FlangedFlatPlate:
74      """Sets the physical geometry of the current `FlangedFlatPlate` object.
75
76      See the `FlangedFlatPlate` class documentation for a description of each geometric parameter.
77      """
78      self.geometry.set(radius=radius_m, thickness=thickness_m)
79      return self

Sets the physical geometry of the current FlangedFlatPlate object.

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

def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
81   def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]:
82      parameter_bounds = {
83         'radius': (0.0, 2.0),
84         'thickness': (0.0, 0.1)
85      }
86      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).