From f8112285306cc117f67b0af4b8174fb005d725f8 Mon Sep 17 00:00:00 2001 From: Luis Camero Date: Tue, 4 Feb 2025 15:47:09 -0500 Subject: [PATCH 1/2] Add Material common type --- clearpath_config/common/types/material.py | 98 +++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 clearpath_config/common/types/material.py diff --git a/clearpath_config/common/types/material.py b/clearpath_config/common/types/material.py new file mode 100644 index 0000000..9776932 --- /dev/null +++ b/clearpath_config/common/types/material.py @@ -0,0 +1,98 @@ +# Software License Agreement (BSD) +# +# @author Luis Camero +# @copyright (c) 2025, Clearpath Robotics, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Clearpath Robotics nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +from typing import List + +from clearpath_config.common.types.package_path import PackagePath + + +class Material(): + NAME = 'name' + COLOR = 'color' + TEXTURE = 'texture' + + def __init__( + self, + name: str = None, + color: List = None, + texture: PackagePath | dict = None, + ) -> None: + self.name = name + self.color = color + self.texture = texture + + def from_dict(self, d: dict) -> None: + if self.NAME in d: + self.name = d[self.NAME] + if self.COLOR in d: + self.color = d[self.COLOR] + if self.TEXTURE in d: + self.texture in d[self.TEXTURE] + + def to_dict(self) -> dict: + return { + self.NAME: self.name, + self.COLOR: self.color, + self.TEXTURE: self.texture + } + + @property + def name(self) -> str: + return self._name + + @name.setter + def name(self, name: str) -> None: + self._name = name + + @property + def color(self) -> List: + return self._color + + @color.setter + def color(self, color: List) -> None: + if color: + assert isinstance(color, List), ( + f'Material color must be a list of floats.' + f'Received {color}') + assert len(color) == 4, ( + f'Material color must be a list of 4 floats, representing RGBA.' + f'Received list of length {len(color)}') + self._color = color + + @property + def texture(self) -> PackagePath: + return self._texture + + @texture.setter + def texture(self, texture: PackagePath | dict): + if texture: + if isinstance(texture, PackagePath): + self._texture = texture + if isinstance(texture, dict): + self._texture = PackagePath() + self._texture.from_dict(dict) + self._texture = None From 2d2c9c9208241758fe04be6eeab1357064d87b81 Mon Sep 17 00:00:00 2001 From: Luis Camero Date: Tue, 4 Feb 2025 15:47:28 -0500 Subject: [PATCH 2/2] Add material to links --- clearpath_config/links/types/link.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/clearpath_config/links/types/link.py b/clearpath_config/links/types/link.py index 2b77ffc..a3ba77e 100644 --- a/clearpath_config/links/types/link.py +++ b/clearpath_config/links/types/link.py @@ -26,6 +26,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from clearpath_config.common.types.accessory import Accessory +from clearpath_config.common.types.material import Material from typing import List @@ -58,6 +59,7 @@ class BaseLink(Accessory): LINK_TYPE = "base" OFFSET_XYZ = [0.0, 0.0, 0.0] OFFSET_RPY = [0.0, 0.0, 0.0] + MATERIAL = {'name': 'clearpath_dark_grey'} def __init__( self, @@ -66,13 +68,15 @@ def __init__( xyz: List[float] = Accessory.XYZ, rpy: List[float] = Accessory.RPY, offset_xyz: List[float] = OFFSET_XYZ, - offset_rpy: List[float] = OFFSET_RPY + offset_rpy: List[float] = OFFSET_RPY, + material: Material | dict = MATERIAL ) -> None: super().__init__(name, parent, xyz, rpy) self.offset_xyz: List[float] = BaseLink.OFFSET_XYZ self.set_offset_xyz(offset_xyz) self.offset_rpy: List[float] = BaseLink.OFFSET_RPY self.set_offset_rpy(offset_rpy) + self.material = material def to_dict(self) -> dict: d = {} @@ -80,6 +84,7 @@ def to_dict(self) -> dict: d['parent'] = self.get_parent() d['xyz'] = self.get_xyz() d['rpy'] = self.get_rpy() + d['material'] = self.material.to_dict() return d def from_dict(self, d: dict) -> None: @@ -91,6 +96,8 @@ def from_dict(self, d: dict) -> None: self.set_xyz(d['xyz']) if 'rpy' in d: self.set_rpy(d['rpy']) + if 'material' in d: + self.material = d['material'] @classmethod def get_link_type(cls) -> str: @@ -112,3 +119,15 @@ def set_offset_rpy(self, rpy: List[float]) -> None: "Offset RPY must be a list of exactly three float values" ) self.offset_rpy = rpy + + @property + def material(self) -> Material: + return self._material + + @material.setter + def material(self, material: Material | dict) -> None: + if isinstance(material, Material): + self._material = material + if isinstance(material, dict): + self._material = Material() + self._material.from_dict(material)