symcad.core.Coordinate
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 typing import List, Optional, Tuple, Union 19from sympy import Expr, Symbol 20from copy import deepcopy 21 22class Coordinate(object): 23 """Represents a set of XYZ Cartesian coordinates.""" 24 25 # Public attributes ---------------------------------------------------------------------------- 26 27 name: str 28 """Unique, identifying name of the `Coordinate` instance.""" 29 30 x: Union[float, Expr] 31 """X-axis coordinate in meters.""" 32 33 y: Union[float, Expr] 34 """Y-axis coordinate in meters.""" 35 36 z: Union[float, Expr] 37 """Z-axis coordinate in meters.""" 38 39 40 # Constructor ---------------------------------------------------------------------------------- 41 42 def __init__(self, identifier: str, **kwargs) -> None: 43 """Initializes a `Coordinate` instance, where `identifier` uniquely identifies the instance, 44 and `**kwargs` may contain the keywords `x`, `y`, or `z` to specify a concrete value 45 for each axis of the coordinate. If any of these keywords are missing, the corresponding 46 coordinate will be treated as a symbol. 47 """ 48 super().__init__() 49 self.name = identifier 50 self.x = kwargs.get('x', Symbol(identifier + '_x')) 51 self.y = kwargs.get('y', Symbol(identifier + '_y')) 52 self.z = kwargs.get('z', Symbol(identifier + '_z')) 53 54 55 # Built-in method implementations -------------------------------------------------------------- 56 57 def __repr__(self) -> str: 58 return 'x = {} m, y = {} m, z = {} m'.format(self.x, self.y, self.z) 59 60 def __eq__(self, other: Coordinate) -> bool: 61 return (self.x == other.x) and (self.y == other.y) and (self.z == other.z) 62 63 def __copy__(self): 64 copy = self.__class__.__new__(self.__class__) 65 copy.__dict__.update(self.__dict__) 66 return copy 67 68 def __deepcopy__(self, memo): 69 copy = self.__class__.__new__(self.__class__) 70 memo[id(self)] = copy 71 for key, val in self.__dict__.items(): 72 setattr(copy, key, deepcopy(val, memo)) 73 return copy 74 75 76 # Public methods ------------------------------------------------------------------------------- 77 78 def clone(self, concrete_values: Optional[List[Tuple[str, float]]] = None) -> Coordinate: 79 """Returns an exact clone of this `Coordinate` instance, optionally replacing any symbolic 80 parameters with their corresponding values as specified in the `concrete_values` list.""" 81 copy = deepcopy(self) 82 if concrete_values is not None: 83 if isinstance(copy.x, Expr): 84 copy.x = copy.x.subs(concrete_values) 85 if isinstance(copy.y, Expr): 86 copy.y = copy.y.subs(concrete_values) 87 if isinstance(copy.z, Expr): 88 copy.z = copy.z.subs(concrete_values) 89 return copy 90 91 92 def copy_from(self, other: Coordinate) -> Coordinate: 93 """Copies the coordinates from another `Coordinate` instance into this one. 94 95 The name of this instance will not be changed or overwritten. 96 97 Parameters 98 ---------- 99 other : `Coordinate` 100 A Coordinate object whose contents should be copied into this instance. 101 102 Returns 103 ------- 104 self : `Coordinate` 105 The Coordinate instance being manipulated. 106 """ 107 self.x = other.x 108 self.y = other.y 109 self.z = other.z 110 return self 111 112 113 def set(self, *, x: Union[float, Expr, None], 114 y: Union[float, Expr, None], 115 z: Union[float, Expr, None]) -> Coordinate: 116 """Sets the Cartesian coordinates to the specified values. 117 118 Parameters 119 ---------- 120 x : `Union[float, sympy.Expr, None]` 121 Desired x-axis coordinate in meters. If `None` is specified, the coordinate 122 will be treated as a symbol. 123 y : `Union[float, sympy.Expr, None]` 124 Desired y-axis coordinate in meters. If `None` is specified, the coordinate 125 will be treated as a symbol. 126 z : `Union[float, sympy.Expr, None]` 127 Desired z-axis coordinate in meters. If `None` is specified, the coordinate 128 will be treated as a symbol. 129 130 Returns 131 ------- 132 self : `Coordinate` 133 The Coordinate instance being manipulated. 134 """ 135 self.x = x if x is not None else Symbol(self.name + '_x') 136 self.y = y if y is not None else Symbol(self.name + '_y') 137 self.z = z if z is not None else Symbol(self.name + '_z') 138 return self 139 140 141 def clear(self) -> Coordinate: 142 """Clears all coordinates to `<0, 0, 0>`. 143 144 Returns 145 ------- 146 self : `Coordinate` 147 The Coordinate instance being manipulated. 148 """ 149 self.x = self.y = self.z = 0.0 150 return self 151 152 153 def as_tuple(self) -> Tuple[float, float, float]: 154 """Returns the current XYZ coordinates as a `tuple`.""" 155 return self.x, self.y, self.z
class
Coordinate:
23class Coordinate(object): 24 """Represents a set of XYZ Cartesian coordinates.""" 25 26 # Public attributes ---------------------------------------------------------------------------- 27 28 name: str 29 """Unique, identifying name of the `Coordinate` instance.""" 30 31 x: Union[float, Expr] 32 """X-axis coordinate in meters.""" 33 34 y: Union[float, Expr] 35 """Y-axis coordinate in meters.""" 36 37 z: Union[float, Expr] 38 """Z-axis coordinate in meters.""" 39 40 41 # Constructor ---------------------------------------------------------------------------------- 42 43 def __init__(self, identifier: str, **kwargs) -> None: 44 """Initializes a `Coordinate` instance, where `identifier` uniquely identifies the instance, 45 and `**kwargs` may contain the keywords `x`, `y`, or `z` to specify a concrete value 46 for each axis of the coordinate. If any of these keywords are missing, the corresponding 47 coordinate will be treated as a symbol. 48 """ 49 super().__init__() 50 self.name = identifier 51 self.x = kwargs.get('x', Symbol(identifier + '_x')) 52 self.y = kwargs.get('y', Symbol(identifier + '_y')) 53 self.z = kwargs.get('z', Symbol(identifier + '_z')) 54 55 56 # Built-in method implementations -------------------------------------------------------------- 57 58 def __repr__(self) -> str: 59 return 'x = {} m, y = {} m, z = {} m'.format(self.x, self.y, self.z) 60 61 def __eq__(self, other: Coordinate) -> bool: 62 return (self.x == other.x) and (self.y == other.y) and (self.z == other.z) 63 64 def __copy__(self): 65 copy = self.__class__.__new__(self.__class__) 66 copy.__dict__.update(self.__dict__) 67 return copy 68 69 def __deepcopy__(self, memo): 70 copy = self.__class__.__new__(self.__class__) 71 memo[id(self)] = copy 72 for key, val in self.__dict__.items(): 73 setattr(copy, key, deepcopy(val, memo)) 74 return copy 75 76 77 # Public methods ------------------------------------------------------------------------------- 78 79 def clone(self, concrete_values: Optional[List[Tuple[str, float]]] = None) -> Coordinate: 80 """Returns an exact clone of this `Coordinate` instance, optionally replacing any symbolic 81 parameters with their corresponding values as specified in the `concrete_values` list.""" 82 copy = deepcopy(self) 83 if concrete_values is not None: 84 if isinstance(copy.x, Expr): 85 copy.x = copy.x.subs(concrete_values) 86 if isinstance(copy.y, Expr): 87 copy.y = copy.y.subs(concrete_values) 88 if isinstance(copy.z, Expr): 89 copy.z = copy.z.subs(concrete_values) 90 return copy 91 92 93 def copy_from(self, other: Coordinate) -> Coordinate: 94 """Copies the coordinates from another `Coordinate` instance into this one. 95 96 The name of this instance will not be changed or overwritten. 97 98 Parameters 99 ---------- 100 other : `Coordinate` 101 A Coordinate object whose contents should be copied into this instance. 102 103 Returns 104 ------- 105 self : `Coordinate` 106 The Coordinate instance being manipulated. 107 """ 108 self.x = other.x 109 self.y = other.y 110 self.z = other.z 111 return self 112 113 114 def set(self, *, x: Union[float, Expr, None], 115 y: Union[float, Expr, None], 116 z: Union[float, Expr, None]) -> Coordinate: 117 """Sets the Cartesian coordinates to the specified values. 118 119 Parameters 120 ---------- 121 x : `Union[float, sympy.Expr, None]` 122 Desired x-axis coordinate in meters. If `None` is specified, the coordinate 123 will be treated as a symbol. 124 y : `Union[float, sympy.Expr, None]` 125 Desired y-axis coordinate in meters. If `None` is specified, the coordinate 126 will be treated as a symbol. 127 z : `Union[float, sympy.Expr, None]` 128 Desired z-axis coordinate in meters. If `None` is specified, the coordinate 129 will be treated as a symbol. 130 131 Returns 132 ------- 133 self : `Coordinate` 134 The Coordinate instance being manipulated. 135 """ 136 self.x = x if x is not None else Symbol(self.name + '_x') 137 self.y = y if y is not None else Symbol(self.name + '_y') 138 self.z = z if z is not None else Symbol(self.name + '_z') 139 return self 140 141 142 def clear(self) -> Coordinate: 143 """Clears all coordinates to `<0, 0, 0>`. 144 145 Returns 146 ------- 147 self : `Coordinate` 148 The Coordinate instance being manipulated. 149 """ 150 self.x = self.y = self.z = 0.0 151 return self 152 153 154 def as_tuple(self) -> Tuple[float, float, float]: 155 """Returns the current XYZ coordinates as a `tuple`.""" 156 return self.x, self.y, self.z
Represents a set of XYZ Cartesian coordinates.
Coordinate(identifier: str, **kwargs)
43 def __init__(self, identifier: str, **kwargs) -> None: 44 """Initializes a `Coordinate` instance, where `identifier` uniquely identifies the instance, 45 and `**kwargs` may contain the keywords `x`, `y`, or `z` to specify a concrete value 46 for each axis of the coordinate. If any of these keywords are missing, the corresponding 47 coordinate will be treated as a symbol. 48 """ 49 super().__init__() 50 self.name = identifier 51 self.x = kwargs.get('x', Symbol(identifier + '_x')) 52 self.y = kwargs.get('y', Symbol(identifier + '_y')) 53 self.z = kwargs.get('z', Symbol(identifier + '_z'))
Initializes a Coordinate instance, where identifier uniquely identifies the instance,
and **kwargs may contain the keywords x, y, or z to specify a concrete value
for each axis of the coordinate. If any of these keywords are missing, the corresponding
coordinate will be treated as a symbol.
79 def clone(self, concrete_values: Optional[List[Tuple[str, float]]] = None) -> Coordinate: 80 """Returns an exact clone of this `Coordinate` instance, optionally replacing any symbolic 81 parameters with their corresponding values as specified in the `concrete_values` list.""" 82 copy = deepcopy(self) 83 if concrete_values is not None: 84 if isinstance(copy.x, Expr): 85 copy.x = copy.x.subs(concrete_values) 86 if isinstance(copy.y, Expr): 87 copy.y = copy.y.subs(concrete_values) 88 if isinstance(copy.z, Expr): 89 copy.z = copy.z.subs(concrete_values) 90 return copy
Returns an exact clone of this Coordinate instance, optionally replacing any symbolic
parameters with their corresponding values as specified in the concrete_values list.
93 def copy_from(self, other: Coordinate) -> Coordinate: 94 """Copies the coordinates from another `Coordinate` instance into this one. 95 96 The name of this instance will not be changed or overwritten. 97 98 Parameters 99 ---------- 100 other : `Coordinate` 101 A Coordinate object whose contents should be copied into this instance. 102 103 Returns 104 ------- 105 self : `Coordinate` 106 The Coordinate instance being manipulated. 107 """ 108 self.x = other.x 109 self.y = other.y 110 self.z = other.z 111 return self
Copies the coordinates from another Coordinate instance into this one.
The name of this instance will not be changed or overwritten.
Parameters
- other (
Coordinate): A Coordinate object whose contents should be copied into this instance.
Returns
- self (
Coordinate): The Coordinate instance being manipulated.
def
set( self, *, x: Union[float, sympy.core.expr.Expr, NoneType], y: Union[float, sympy.core.expr.Expr, NoneType], z: Union[float, sympy.core.expr.Expr, NoneType]) -> Coordinate:
114 def set(self, *, x: Union[float, Expr, None], 115 y: Union[float, Expr, None], 116 z: Union[float, Expr, None]) -> Coordinate: 117 """Sets the Cartesian coordinates to the specified values. 118 119 Parameters 120 ---------- 121 x : `Union[float, sympy.Expr, None]` 122 Desired x-axis coordinate in meters. If `None` is specified, the coordinate 123 will be treated as a symbol. 124 y : `Union[float, sympy.Expr, None]` 125 Desired y-axis coordinate in meters. If `None` is specified, the coordinate 126 will be treated as a symbol. 127 z : `Union[float, sympy.Expr, None]` 128 Desired z-axis coordinate in meters. If `None` is specified, the coordinate 129 will be treated as a symbol. 130 131 Returns 132 ------- 133 self : `Coordinate` 134 The Coordinate instance being manipulated. 135 """ 136 self.x = x if x is not None else Symbol(self.name + '_x') 137 self.y = y if y is not None else Symbol(self.name + '_y') 138 self.z = z if z is not None else Symbol(self.name + '_z') 139 return self
Sets the Cartesian coordinates to the specified values.
Parameters
- x (
Union[float, sympy.Expr, None]): Desired x-axis coordinate in meters. IfNoneis specified, the coordinate will be treated as a symbol. - y (
Union[float, sympy.Expr, None]): Desired y-axis coordinate in meters. IfNoneis specified, the coordinate will be treated as a symbol. - z (
Union[float, sympy.Expr, None]): Desired z-axis coordinate in meters. IfNoneis specified, the coordinate will be treated as a symbol.
Returns
- self (
Coordinate): The Coordinate instance being manipulated.
142 def clear(self) -> Coordinate: 143 """Clears all coordinates to `<0, 0, 0>`. 144 145 Returns 146 ------- 147 self : `Coordinate` 148 The Coordinate instance being manipulated. 149 """ 150 self.x = self.y = self.z = 0.0 151 return self
Clears all coordinates to <0, 0, 0>.
Returns
- self (
Coordinate): The Coordinate instance being manipulated.