Skip to content

npxpy.resources.Mesh

Bases: Resource

A class to represent a mesh resource with attributes such as translation, rotation, scale, etc.

Attributes:

Name Type Description
translation List[float]

Translation values [x, y, z].

rotation List[float]

Rotation values [psi, theta, phi].

scale List[float]

Scale values [x, y, z].

enhance_mesh bool

Whether to enhance the mesh.

simplify_mesh bool

Whether to simplify the mesh.

target_ratio float

Target ratio for mesh simplification.

Source code in npxpy/resources.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
class Mesh(Resource):
    """
    A class to represent a mesh resource with attributes such as translation, rotation, scale, etc.

    Attributes:
        translation (List[float]): Translation values [x, y, z].
        rotation (List[float]): Rotation values [psi, theta, phi].
        scale (List[float]): Scale values [x, y, z].
        enhance_mesh (bool): Whether to enhance the mesh.
        simplify_mesh (bool): Whether to simplify the mesh.
        target_ratio (float): Target ratio for mesh simplification.
    """

    def __init__(
        self,
        file_path: str,
        name: str = "mesh",
        translation: List[float] = [0, 0, 0],
        auto_center: bool = False,
        rotation: List[float] = [0.0, 0.0, 0.0],
        scale: List[float] = [1.0, 1.0, 1.0],
        enhance_mesh: bool = True,
        simplify_mesh: bool = False,
        target_ratio: float = 100.0,
    ):
        """
        Initialize the mesh resource with the specified parameters.

        Parameters:
            file_path (str): Path where the mesh is stored (original file location).
            name (str, optional): Name of the mesh resource. Defaults to 'mesh'.
            translation (List[float], optional): Translation values [x, y, z]. Defaults to [0, 0, 0].
            auto_center (bool, optional): Whether to auto-center the mesh. Defaults to False.
            rotation (List[float], optional): Rotation values [psi, theta, phi]. Defaults to [0.0, 0.0, 0.0].
            scale (List[float], optional): Scale values [x, y, z]. Defaults to [1.0, 1.0, 1.0].
            enhance_mesh (bool, optional): Whether to enhance the mesh. Defaults to True.
            simplify_mesh (bool, optional): Whether to simplify the mesh. Defaults to False.
            target_ratio (float, optional): Target ratio for mesh simplification. Defaults to 100.0.
        """
        super().__init__(
            resource_type="mesh_file", name=name, file_path=file_path
        )

        # Set attributes with validation
        self.translation = translation
        self.auto_center = auto_center
        self.rotation = rotation
        self.scale = scale
        self.enhance_mesh = enhance_mesh
        self.simplify_mesh = simplify_mesh
        self.target_ratio = target_ratio
        self.original_triangle_count = self._get_triangle_count(file_path)

        # Load the mesh data
        self.mesh_data = stl_mesh.Mesh.from_file(file_path)

        # Apply auto-centering if enabled
        if self.auto_center:
            self._auto_center()

    @property
    def translation(self):
        return self._translation

    @translation.setter
    def translation(self, value: List[Any]):
        if len(value) != 3:
            raise ValueError(
                "Translation must have exactly 3 elements [x, y, z]"
            )
        try:
            self._translation = [float(v) for v in value]
        except ValueError:
            raise ValueError("Translation elements must be numeric values.")

    @property
    def rotation(self):
        return self._rotation

    @rotation.setter
    def rotation(self, value: List[Any]):
        if len(value) != 3:
            raise ValueError(
                "Rotation must have exactly 3 elements [psi, theta, phi]"
            )
        try:
            self._rotation = [float(v) for v in value]
        except ValueError:
            raise ValueError("Rotation elements must be numeric values.")

    @property
    def scale(self):
        return self._scale

    @scale.setter
    def scale(self, value: List[Any]):
        if len(value) != 3:
            raise ValueError("Scale must have exactly 3 elements [x, y, z]")
        try:
            self._scale = [float(v) for v in value]
        except ValueError:
            raise ValueError("Scale elements must be numeric values.")

    @property
    def target_ratio(self):
        return self._target_ratio

    @target_ratio.setter
    def target_ratio(self, value: Any):
        try:
            value = float(value)
        except ValueError:
            raise ValueError("Target ratio must be a numeric value.")
        if not (0 <= value <= 100):
            raise ValueError("Target ratio must be between 0 and 100")
        self._target_ratio = value

    def _auto_center(self):
        """
        Auto-center the mesh by translating it so the bounding box center aligns with the origin
        in the x and y axes, and the lowest z coordinate is set to 0.
        """
        all_vertices = self.mesh_data.vectors.reshape(-1, 3)

        # Calculate the min and max coordinates for bounding box
        min_coords = all_vertices.min(axis=0)
        max_coords = all_vertices.max(axis=0)

        # Center x and y by calculating the bounding box center
        bounding_box_center = (min_coords + max_coords) / 2.0
        bounding_box_center[2] = min_coords[2]  # For z, use the lowest point

        # Calculate the translation
        translation = -bounding_box_center
        translation[2] = -min_coords[
            2
        ]  # Translate only enough to set the lowest z to 0

        # Apply the translation to the mesh
        self.mesh_data.translate(translation)

        # Update translation property to reflect the applied translation
        self.translation = [
            t + c for t, c in zip(self.translation, translation)
        ]

    def _get_triangle_count(self, path: str) -> int:
        """
        Get the number of triangles in the mesh.

        Parameters:
            path (str): Path to the mesh file.

        Returns:
            int: Number of triangles in the mesh.

        Raises:
            FileNotFoundError: If the mesh file does not exist.
            Exception: If there is an error reading the STL file.
        """
        if not os.path.isfile(path):
            raise FileNotFoundError(f"Mesh file not found: {path}")

        try:
            mesh_data = stl_mesh.Mesh.from_file(path)
            return len(mesh_data.vectors)
        except Exception as e:
            raise Exception(f"Error reading STL file: {e}")

    def to_dict(self) -> Dict[str, Any]:
        """
        Converts the current state of the object into a dictionary representation.

        Returns:
            dict: Dictionary representation of the current state of the object.
        """
        resource_dict = super().to_dict()
        resource_dict.update(
            {
                "translation": self.translation,
                "auto_center": self.auto_center,
                "rotation": self.rotation,
                "scale": self.scale,
                "enhance_mesh": self.enhance_mesh,
                "simplify_mesh": self.simplify_mesh,
                "target_ratio": self.target_ratio,
                "properties": {
                    "original_triangle_count": self.original_triangle_count
                },
            }
        )
        return resource_dict

__init__(file_path, name='mesh', translation=[0, 0, 0], auto_center=False, rotation=[0.0, 0.0, 0.0], scale=[1.0, 1.0, 1.0], enhance_mesh=True, simplify_mesh=False, target_ratio=100.0)

Initialize the mesh resource with the specified parameters.

Parameters:

Name Type Description Default
file_path str

Path where the mesh is stored (original file location).

required
name str

Name of the mesh resource. Defaults to 'mesh'.

'mesh'
translation List[float]

Translation values [x, y, z]. Defaults to [0, 0, 0].

[0, 0, 0]
auto_center bool

Whether to auto-center the mesh. Defaults to False.

False
rotation List[float]

Rotation values [psi, theta, phi]. Defaults to [0.0, 0.0, 0.0].

[0.0, 0.0, 0.0]
scale List[float]

Scale values [x, y, z]. Defaults to [1.0, 1.0, 1.0].

[1.0, 1.0, 1.0]
enhance_mesh bool

Whether to enhance the mesh. Defaults to True.

True
simplify_mesh bool

Whether to simplify the mesh. Defaults to False.

False
target_ratio float

Target ratio for mesh simplification. Defaults to 100.0.

100.0
Source code in npxpy/resources.py
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
def __init__(
    self,
    file_path: str,
    name: str = "mesh",
    translation: List[float] = [0, 0, 0],
    auto_center: bool = False,
    rotation: List[float] = [0.0, 0.0, 0.0],
    scale: List[float] = [1.0, 1.0, 1.0],
    enhance_mesh: bool = True,
    simplify_mesh: bool = False,
    target_ratio: float = 100.0,
):
    """
    Initialize the mesh resource with the specified parameters.

    Parameters:
        file_path (str): Path where the mesh is stored (original file location).
        name (str, optional): Name of the mesh resource. Defaults to 'mesh'.
        translation (List[float], optional): Translation values [x, y, z]. Defaults to [0, 0, 0].
        auto_center (bool, optional): Whether to auto-center the mesh. Defaults to False.
        rotation (List[float], optional): Rotation values [psi, theta, phi]. Defaults to [0.0, 0.0, 0.0].
        scale (List[float], optional): Scale values [x, y, z]. Defaults to [1.0, 1.0, 1.0].
        enhance_mesh (bool, optional): Whether to enhance the mesh. Defaults to True.
        simplify_mesh (bool, optional): Whether to simplify the mesh. Defaults to False.
        target_ratio (float, optional): Target ratio for mesh simplification. Defaults to 100.0.
    """
    super().__init__(
        resource_type="mesh_file", name=name, file_path=file_path
    )

    # Set attributes with validation
    self.translation = translation
    self.auto_center = auto_center
    self.rotation = rotation
    self.scale = scale
    self.enhance_mesh = enhance_mesh
    self.simplify_mesh = simplify_mesh
    self.target_ratio = target_ratio
    self.original_triangle_count = self._get_triangle_count(file_path)

    # Load the mesh data
    self.mesh_data = stl_mesh.Mesh.from_file(file_path)

    # Apply auto-centering if enabled
    if self.auto_center:
        self._auto_center()

to_dict()

Converts the current state of the object into a dictionary representation.

Returns:

Name Type Description
dict Dict[str, Any]

Dictionary representation of the current state of the object.

Source code in npxpy/resources.py
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
def to_dict(self) -> Dict[str, Any]:
    """
    Converts the current state of the object into a dictionary representation.

    Returns:
        dict: Dictionary representation of the current state of the object.
    """
    resource_dict = super().to_dict()
    resource_dict.update(
        {
            "translation": self.translation,
            "auto_center": self.auto_center,
            "rotation": self.rotation,
            "scale": self.scale,
            "enhance_mesh": self.enhance_mesh,
            "simplify_mesh": self.simplify_mesh,
            "target_ratio": self.target_ratio,
            "properties": {
                "original_triangle_count": self.original_triangle_count
            },
        }
    )
    return resource_dict