symcad.parts.generic.Cone
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, Min, Max, sqrt 21from . import GenericShape 22import math 23 24class Cone(GenericShape): 25 """Model representing a generic parameteric cone. 26 27 By default, the cone is oriented such that its base is perpendicular to the z-axis: 28 29  30 31 The `geometry` of this shape includes the following parameters: 32 33 - `bottom_radius`: Radius (in `m`) of the base of the Cone (must be larger than `top_radius`) 34 - `top_radius`: Radius (in `m`) of the truncated Cone tip (may be `0` to create a full Cone) 35 - `height`: Height (in `m`) of the Cone from base to tip 36 37 If a non-truncated cone is desired, the `top_radius` parameter may be set to `0`. 38 39 Note that the above dimensions should be interpreted as if the Cone is unrotated. In other 40 words, any shape rotation takes place *after* the Cone 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 generic parametric cone 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, 'bottom_radius', Symbol(self.name + '_bottom_radius')) 57 setattr(self.geometry, 'top_radius', Symbol(self.name + '_top_radius')) 58 setattr(self.geometry, 'height', Symbol(self.name + '_height')) 59 60 61 # CAD generation function ---------------------------------------------------------------------- 62 63 @staticmethod 64 def __create_cad__(params: Dict[str, float], _fully_displace: bool) -> Part.Solid: 65 """Scripted CAD generation method for a `Cone`.""" 66 bottom_radius_mm = 1000.0 * params['bottom_radius'] 67 top_radius_mm = 1000.0 * params['top_radius'] 68 height_mm = 1000.0 * params['height'] 69 return Part.makeCone(bottom_radius_mm, top_radius_mm, height_mm) 70 71 72 # Geometry setter ------------------------------------------------------------------------------ 73 74 def set_geometry(self, *, bottom_radius_m: Union[float, None], 75 top_radius_m: Union[float, None], 76 height_m: Union[float, None]) -> Cone: 77 """Sets the physical geometry of the current `Cone` object. 78 79 See the `Cone` class documentation for a description of each geometric parameter. 80 """ 81 self.geometry.set(bottom_radius=bottom_radius_m, 82 top_radius=top_radius_m, 83 height=height_m) 84 return self 85 86 def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]: 87 parameter_bounds = { 88 'bottom_radius': (0.0, 2.0), 89 'top_radius': (0.0, 2.0), 90 'height': (0.0, 2.0) 91 } 92 return parameter_bounds.get(parameter, (0.0, 0.0)) 93 94 95 # Geometric properties ------------------------------------------------------------------------- 96 97 @property 98 def material_volume(self) -> Union[float, Expr]: 99 return self.displaced_volume 100 101 @property 102 def displaced_volume(self) -> Union[float, Expr]: 103 return (math.pi * self.geometry.height / 3.0) * \ 104 (self.geometry.bottom_radius**2 + self.geometry.top_radius**2 + 105 self.geometry.bottom_radius * self.geometry.top_radius) 106 107 @property 108 def surface_area(self) -> Union[float, Expr]: 109 return (math.pi * (self.geometry.bottom_radius**2 + self.geometry.top_radius**2)) + \ 110 (math.pi * (self.geometry.bottom_radius + self.geometry.top_radius) * 111 sqrt(self.geometry.height**2 + 112 (self.geometry.bottom_radius - self.geometry.top_radius)**2)) 113 114 @property 115 def unoriented_center_of_gravity(self) -> Tuple[Union[float, Expr], 116 Union[float, Expr], 117 Union[float, Expr]]: 118 return (self.geometry.bottom_radius, 119 self.geometry.bottom_radius, 120 (self.geometry.height * (self.geometry.bottom_radius**2 121 + (2.0 * self.geometry.bottom_radius * self.geometry.top_radius) 122 + (3.0 * self.geometry.top_radius**2))) / 123 (4.0 * (self.geometry.bottom_radius**2 124 + (self.geometry.bottom_radius * self.geometry.top_radius) 125 + self.geometry.top_radius**2))) 126 127 @property 128 def unoriented_center_of_buoyancy(self) -> Tuple[Union[float, Expr], 129 Union[float, Expr], 130 Union[float, Expr]]: 131 return self.unoriented_center_of_gravity 132 133 @property 134 def unoriented_length(self) -> Union[float, Expr]: 135 return 2.0 * self.geometry.bottom_radius 136 137 @property 138 def unoriented_width(self) -> Union[float, Expr]: 139 return self.unoriented_length 140 141 @property 142 def unoriented_height(self) -> Union[float, Expr]: 143 return self.geometry.height 144 145 @property 146 def oriented_length(self) -> Union[float, Expr]: 147 min_x, max_x = 1000000000000.0, -1000000000000.0 148 R = self.orientation.get_rotation_matrix_row(0) 149 for i in range(0, 360, 30): 150 deg_radians = math.radians(i) 151 point = (self.geometry.bottom_radius * math.cos(deg_radians), self.geometry.bottom_radius * math.sin(deg_radians), 0.0) 152 x = sum([R[i] * point[i] for i in range(3)]) 153 min_x = Min(min_x, x) 154 max_x = Max(max_x, x) 155 point = (self.geometry.top_radius * math.cos(deg_radians), self.geometry.top_radius * math.sin(deg_radians), self.geometry.height) 156 x = sum([R[i] * point[i] for i in range(3)]) 157 min_x = Min(min_x, x) 158 max_x = Max(max_x, x) 159 return max_x - min_x 160 161 @property 162 def oriented_width(self) -> Union[float, Expr]: 163 min_x, max_x = 1000000000000.0, -1000000000000.0 164 R = self.orientation.get_rotation_matrix_row(1) 165 for i in range(0, 360, 20): 166 deg_radians = math.radians(i) 167 point = (self.geometry.bottom_radius * math.cos(deg_radians), self.geometry.bottom_radius * math.sin(deg_radians), 0.0) 168 x = sum([R[i] * point[i] for i in range(3)]) 169 min_x = Min(min_x, x) 170 max_x = Max(max_x, x) 171 point = (self.geometry.top_radius * math.cos(deg_radians), self.geometry.top_radius * math.sin(deg_radians), self.geometry.height) 172 x = sum([R[i] * point[i] for i in range(3)]) 173 min_x = Min(min_x, x) 174 max_x = Max(max_x, x) 175 return max_x - min_x 176 177 @property 178 def oriented_height(self) -> Union[float, Expr]: 179 min_x, max_x = 1000000000000.0, -1000000000000.0 180 R = self.orientation.get_rotation_matrix_row(2) 181 for i in range(0, 360, 20): 182 deg_radians = math.radians(i) 183 point = (self.geometry.bottom_radius * math.cos(deg_radians), self.geometry.bottom_radius * math.sin(deg_radians), 0.0) 184 x = sum([R[i] * point[i] for i in range(3)]) 185 min_x = Min(min_x, x) 186 max_x = Max(max_x, x) 187 point = (self.geometry.top_radius * math.cos(deg_radians), self.geometry.top_radius * math.sin(deg_radians), self.geometry.height) 188 x = sum([R[i] * point[i] for i in range(3)]) 189 min_x = Min(min_x, x) 190 max_x = Max(max_x, x) 191 return max_x - min_x
25class Cone(GenericShape): 26 """Model representing a generic parameteric cone. 27 28 By default, the cone is oriented such that its base is perpendicular to the z-axis: 29 30  31 32 The `geometry` of this shape includes the following parameters: 33 34 - `bottom_radius`: Radius (in `m`) of the base of the Cone (must be larger than `top_radius`) 35 - `top_radius`: Radius (in `m`) of the truncated Cone tip (may be `0` to create a full Cone) 36 - `height`: Height (in `m`) of the Cone from base to tip 37 38 If a non-truncated cone is desired, the `top_radius` parameter may be set to `0`. 39 40 Note that the above dimensions should be interpreted as if the Cone is unrotated. In other 41 words, any shape rotation takes place *after* the Cone 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 generic parametric cone 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, 'bottom_radius', Symbol(self.name + '_bottom_radius')) 58 setattr(self.geometry, 'top_radius', Symbol(self.name + '_top_radius')) 59 setattr(self.geometry, 'height', Symbol(self.name + '_height')) 60 61 62 # CAD generation function ---------------------------------------------------------------------- 63 64 @staticmethod 65 def __create_cad__(params: Dict[str, float], _fully_displace: bool) -> Part.Solid: 66 """Scripted CAD generation method for a `Cone`.""" 67 bottom_radius_mm = 1000.0 * params['bottom_radius'] 68 top_radius_mm = 1000.0 * params['top_radius'] 69 height_mm = 1000.0 * params['height'] 70 return Part.makeCone(bottom_radius_mm, top_radius_mm, height_mm) 71 72 73 # Geometry setter ------------------------------------------------------------------------------ 74 75 def set_geometry(self, *, bottom_radius_m: Union[float, None], 76 top_radius_m: Union[float, None], 77 height_m: Union[float, None]) -> Cone: 78 """Sets the physical geometry of the current `Cone` object. 79 80 See the `Cone` class documentation for a description of each geometric parameter. 81 """ 82 self.geometry.set(bottom_radius=bottom_radius_m, 83 top_radius=top_radius_m, 84 height=height_m) 85 return self 86 87 def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]: 88 parameter_bounds = { 89 'bottom_radius': (0.0, 2.0), 90 'top_radius': (0.0, 2.0), 91 'height': (0.0, 2.0) 92 } 93 return parameter_bounds.get(parameter, (0.0, 0.0)) 94 95 96 # Geometric properties ------------------------------------------------------------------------- 97 98 @property 99 def material_volume(self) -> Union[float, Expr]: 100 return self.displaced_volume 101 102 @property 103 def displaced_volume(self) -> Union[float, Expr]: 104 return (math.pi * self.geometry.height / 3.0) * \ 105 (self.geometry.bottom_radius**2 + self.geometry.top_radius**2 + 106 self.geometry.bottom_radius * self.geometry.top_radius) 107 108 @property 109 def surface_area(self) -> Union[float, Expr]: 110 return (math.pi * (self.geometry.bottom_radius**2 + self.geometry.top_radius**2)) + \ 111 (math.pi * (self.geometry.bottom_radius + self.geometry.top_radius) * 112 sqrt(self.geometry.height**2 + 113 (self.geometry.bottom_radius - self.geometry.top_radius)**2)) 114 115 @property 116 def unoriented_center_of_gravity(self) -> Tuple[Union[float, Expr], 117 Union[float, Expr], 118 Union[float, Expr]]: 119 return (self.geometry.bottom_radius, 120 self.geometry.bottom_radius, 121 (self.geometry.height * (self.geometry.bottom_radius**2 122 + (2.0 * self.geometry.bottom_radius * self.geometry.top_radius) 123 + (3.0 * self.geometry.top_radius**2))) / 124 (4.0 * (self.geometry.bottom_radius**2 125 + (self.geometry.bottom_radius * self.geometry.top_radius) 126 + self.geometry.top_radius**2))) 127 128 @property 129 def unoriented_center_of_buoyancy(self) -> Tuple[Union[float, Expr], 130 Union[float, Expr], 131 Union[float, Expr]]: 132 return self.unoriented_center_of_gravity 133 134 @property 135 def unoriented_length(self) -> Union[float, Expr]: 136 return 2.0 * self.geometry.bottom_radius 137 138 @property 139 def unoriented_width(self) -> Union[float, Expr]: 140 return self.unoriented_length 141 142 @property 143 def unoriented_height(self) -> Union[float, Expr]: 144 return self.geometry.height 145 146 @property 147 def oriented_length(self) -> Union[float, Expr]: 148 min_x, max_x = 1000000000000.0, -1000000000000.0 149 R = self.orientation.get_rotation_matrix_row(0) 150 for i in range(0, 360, 30): 151 deg_radians = math.radians(i) 152 point = (self.geometry.bottom_radius * math.cos(deg_radians), self.geometry.bottom_radius * math.sin(deg_radians), 0.0) 153 x = sum([R[i] * point[i] for i in range(3)]) 154 min_x = Min(min_x, x) 155 max_x = Max(max_x, x) 156 point = (self.geometry.top_radius * math.cos(deg_radians), self.geometry.top_radius * math.sin(deg_radians), self.geometry.height) 157 x = sum([R[i] * point[i] for i in range(3)]) 158 min_x = Min(min_x, x) 159 max_x = Max(max_x, x) 160 return max_x - min_x 161 162 @property 163 def oriented_width(self) -> Union[float, Expr]: 164 min_x, max_x = 1000000000000.0, -1000000000000.0 165 R = self.orientation.get_rotation_matrix_row(1) 166 for i in range(0, 360, 20): 167 deg_radians = math.radians(i) 168 point = (self.geometry.bottom_radius * math.cos(deg_radians), self.geometry.bottom_radius * math.sin(deg_radians), 0.0) 169 x = sum([R[i] * point[i] for i in range(3)]) 170 min_x = Min(min_x, x) 171 max_x = Max(max_x, x) 172 point = (self.geometry.top_radius * math.cos(deg_radians), self.geometry.top_radius * math.sin(deg_radians), self.geometry.height) 173 x = sum([R[i] * point[i] for i in range(3)]) 174 min_x = Min(min_x, x) 175 max_x = Max(max_x, x) 176 return max_x - min_x 177 178 @property 179 def oriented_height(self) -> Union[float, Expr]: 180 min_x, max_x = 1000000000000.0, -1000000000000.0 181 R = self.orientation.get_rotation_matrix_row(2) 182 for i in range(0, 360, 20): 183 deg_radians = math.radians(i) 184 point = (self.geometry.bottom_radius * math.cos(deg_radians), self.geometry.bottom_radius * math.sin(deg_radians), 0.0) 185 x = sum([R[i] * point[i] for i in range(3)]) 186 min_x = Min(min_x, x) 187 max_x = Max(max_x, x) 188 point = (self.geometry.top_radius * math.cos(deg_radians), self.geometry.top_radius * math.sin(deg_radians), self.geometry.height) 189 x = sum([R[i] * point[i] for i in range(3)]) 190 min_x = Min(min_x, x) 191 max_x = Max(max_x, x) 192 return max_x - min_x
Model representing a generic parameteric cone.
By default, the cone is oriented such that its base is perpendicular to the z-axis:

The geometry of this shape includes the following parameters:
bottom_radius: Radius (inm) of the base of the Cone (must be larger thantop_radius)top_radius: Radius (inm) of the truncated Cone tip (may be0to create a full Cone)height: Height (inm) of the Cone from base to tip
If a non-truncated cone is desired, the top_radius parameter may be set to 0.
Note that the above dimensions should be interpreted as if the Cone is unrotated. In other words, any shape rotation takes place after the Cone dimensions have been specified.
46 def __init__(self, identifier: str, material_density_kg_m3: Optional[float] = 1.0) -> None: 47 """Initializes a generic parametric cone 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, 'bottom_radius', Symbol(self.name + '_bottom_radius')) 58 setattr(self.geometry, 'top_radius', Symbol(self.name + '_top_radius')) 59 setattr(self.geometry, 'height', Symbol(self.name + '_height'))
Initializes a generic parametric cone object.
Parameters
- identifier (
str): Unique identifying name for the object. - material_density_kg_m3 (
float, optional, default=1.0): Uniform material density inkg/m^3to be used in mass property calculations.
75 def set_geometry(self, *, bottom_radius_m: Union[float, None], 76 top_radius_m: Union[float, None], 77 height_m: Union[float, None]) -> Cone: 78 """Sets the physical geometry of the current `Cone` object. 79 80 See the `Cone` class documentation for a description of each geometric parameter. 81 """ 82 self.geometry.set(bottom_radius=bottom_radius_m, 83 top_radius=top_radius_m, 84 height=height_m) 85 return self
87 def get_geometric_parameter_bounds(self, parameter: str) -> Tuple[float, float]: 88 parameter_bounds = { 89 'bottom_radius': (0.0, 2.0), 90 'top_radius': (0.0, 2.0), 91 'height': (0.0, 2.0) 92 } 93 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 geometricparameter.
Material volume (in m^3) of the SymPart (read-only).
Displaced volume (in m^3) of the SymPart (read-only).
Surface/wetted area (in m^2) of the SymPart (read-only).
Center of gravity (in m) of the unoriented SymPart (read-only).
Center of buoyancy (in m) of the unoriented SymPart (read-only).
X-axis length (in m) of the bounding box of the unoriented SymPart (read-only).
Y-axis width (in m) of the bounding box of the unoriented SymPart (read-only).
Z-axis height (in m) of the bounding box of the unoriented SymPart (read-only).
X-axis length (in m) of the bounding box of the oriented SymPart (read-only).
Y-axis length (in m) of the bounding box of the oriented SymPart (read-only).
Z-axis length (in m) of the bounding box of the oriented SymPart (read-only).
Inherited Members
- symcad.core.SymPart.SymPart
- name
- geometry
- attachment_points
- attachments
- connection_ports
- connections
- static_origin
- static_placement
- orientation
- material_density
- current_states
- is_exposed
- clone
- set_placement
- set_orientation
- set_state
- set_unexposed
- set_material_density
- add_attachment_point
- add_connection_port
- attach
- connect
- get_cad_physical_properties
- export
- get_valid_states
- mass
- oriented_center_of_gravity
- oriented_center_of_buoyancy