mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 10:41:20 -08:00
Added docs for 3mf/stl mesher
This commit is contained in:
parent
dcf71b6fef
commit
a058b45ca2
3 changed files with 182 additions and 103 deletions
|
|
@ -34,6 +34,7 @@ __all__ = [
|
||||||
"Keep",
|
"Keep",
|
||||||
"Kind",
|
"Kind",
|
||||||
"LengthMode",
|
"LengthMode",
|
||||||
|
"MeshType",
|
||||||
"Mode",
|
"Mode",
|
||||||
"PositionMode",
|
"PositionMode",
|
||||||
"Select",
|
"Select",
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,18 @@ class LengthMode(Enum):
|
||||||
return f"<{self.__class__.__name__}.{self.name}>"
|
return f"<{self.__class__.__name__}.{self.name}>"
|
||||||
|
|
||||||
|
|
||||||
|
class MeshType(Enum):
|
||||||
|
"""3MF mesh types typically for 3D printing"""
|
||||||
|
|
||||||
|
OTHER = auto()
|
||||||
|
MODEL = auto()
|
||||||
|
SUPPORT = auto()
|
||||||
|
SOLIDSUPPORT = auto()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<{self.__class__.__name__}.{self.name}>"
|
||||||
|
|
||||||
|
|
||||||
class PositionMode(Enum):
|
class PositionMode(Enum):
|
||||||
"""Position along curve mode"""
|
"""Position along curve mode"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,90 +1,83 @@
|
||||||
# pylint: skip-file
|
|
||||||
"""++
|
|
||||||
|
|
||||||
Copyright (C) 2019 3MF Consortium (Original Author)
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
2. 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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
This file has been generated by the Automatic Component Toolkit (ACT) version 1.6.0-develop.
|
|
||||||
|
|
||||||
Abstract: This is an autogenerated Python application that demonstrates the
|
|
||||||
usage of the Python bindings of the 3MF Library
|
|
||||||
|
|
||||||
Interface version: 2.2.0
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
"""
|
build123d exporter/import for 3MF and STL
|
||||||
Creating a 3MF object involves constructing a valid 3D model conforming to
|
|
||||||
the 3MF specification. The resource hierarchy represents the various
|
|
||||||
components that make up a 3MF object. The main components required to create
|
|
||||||
a 3MF object are:
|
|
||||||
|
|
||||||
Wrapper: The wrapper is the highest-level component representing the
|
name: mesher.py
|
||||||
entire 3MF model. It serves as a container for all other resources and
|
by: Gumyr
|
||||||
provides access to the complete 3D model. The wrapper is the starting point
|
date: Aug 9th 2023
|
||||||
for creating and managing the 3MF model.
|
|
||||||
|
|
||||||
Model: The model is a core component that contains the geometric and
|
desc:
|
||||||
non-geometric resources of the 3D object. It represents the actual 3D
|
This module provides the Mesher class that implements exporting and importing
|
||||||
content, including geometry, materials, colors, textures, and other model
|
both 3MF and STL mesh files. It uses the 3MF Consortium's Lib3MF library
|
||||||
information.
|
(see https://github.com/3MFConsortium/lib3mf).
|
||||||
|
|
||||||
Resources: Within the model, various resources are used to define
|
Creating a 3MF object involves constructing a valid 3D model conforming to
|
||||||
different aspects of the 3D object. Some essential resources are:
|
the 3MF specification. The resource hierarchy represents the various
|
||||||
|
components that make up a 3MF object. The main components required to create
|
||||||
|
a 3MF object are:
|
||||||
|
|
||||||
a. Mesh: The mesh resource defines the geometry of the 3D object. It
|
Wrapper: The wrapper is the highest-level component representing the
|
||||||
contains a collection of vertices, triangles, and other geometric
|
entire 3MF model. It serves as a container for all other resources and
|
||||||
information that describes the shape.
|
provides access to the complete 3D model. The wrapper is the starting point
|
||||||
|
for creating and managing the 3MF model.
|
||||||
|
|
||||||
b. Components: Components allow you to define complex structures by
|
Model: The model is a core component that contains the geometric and
|
||||||
combining multiple meshes together. They are useful for hierarchical
|
non-geometric resources of the 3D object. It represents the actual 3D
|
||||||
assemblies and instances.
|
content, including geometry, materials, colors, textures, and other model
|
||||||
|
information.
|
||||||
|
|
||||||
c. Materials: Materials define the appearance properties of the
|
Resources: Within the model, various resources are used to define
|
||||||
surfaces, such as color, texture, or surface finish.
|
different aspects of the 3D object. Some essential resources are:
|
||||||
|
|
||||||
d. Textures: Textures are images applied to the surfaces of the 3D
|
a. Mesh: The mesh resource defines the geometry of the 3D object. It
|
||||||
object to add detail and realism.
|
contains a collection of vertices, triangles, and other geometric
|
||||||
|
information that describes the shape.
|
||||||
|
|
||||||
e. Colors: Colors represent color information used in the 3D model,
|
b. Components: Components allow you to define complex structures by
|
||||||
which can be applied to vertices or faces.
|
combining multiple meshes together. They are useful for hierarchical
|
||||||
|
assemblies and instances.
|
||||||
|
|
||||||
Build Items: Build items are the instances of resources used in the 3D
|
c. Materials: Materials define the appearance properties of the
|
||||||
model. They specify the usage of resources within the model. For example, a
|
surfaces, such as color, texture, or surface finish.
|
||||||
build item can refer to a specific mesh, material, and transformation to
|
|
||||||
represent an instance of an object.
|
|
||||||
|
|
||||||
Metadata: Metadata provides additional information about the model, such
|
d. Textures: Textures are images applied to the surfaces of the 3D
|
||||||
as author, creation date, and custom properties.
|
object to add detail and realism.
|
||||||
|
|
||||||
Attachments: Attachments can include additional files or data associated
|
e. Colors: Colors represent color information used in the 3D model,
|
||||||
with the 3MF object, such as texture images or other external resources.
|
which can be applied to vertices or faces.
|
||||||
|
|
||||||
|
Build Items: Build items are the instances of resources used in the 3D
|
||||||
|
model. They specify the usage of resources within the model. For example, a
|
||||||
|
build item can refer to a specific mesh, material, and transformation to
|
||||||
|
represent an instance of an object.
|
||||||
|
|
||||||
|
Metadata: Metadata provides additional information about the model, such
|
||||||
|
as author, creation date, and custom properties.
|
||||||
|
|
||||||
|
Attachments: Attachments can include additional files or data associated
|
||||||
|
with the 3MF object, such as texture images or other external resources.
|
||||||
|
|
||||||
|
When creating a 3MF object, you typically start with the wrapper and then
|
||||||
|
create or import the necessary resources, such as meshes, materials, and
|
||||||
|
textures, to define the 3D content. You then organize the model using build
|
||||||
|
items, specifying how the resources are used in the scene. Additionally, you
|
||||||
|
can add metadata and attachments as needed to complete the 3MF object.
|
||||||
|
|
||||||
|
license:
|
||||||
|
|
||||||
|
Copyright 2023 Gumyr
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
When creating a 3MF object, you typically start with the wrapper and then
|
|
||||||
create or import the necessary resources, such as meshes, materials, and
|
|
||||||
textures, to define the 3D content. You then organize the model using build
|
|
||||||
items, specifying how the resources are used in the scene. Additionally, you
|
|
||||||
can add metadata and attachments as needed to complete the 3MF object.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -96,8 +89,9 @@ import uuid
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Iterable, Union
|
from typing import Iterable, Union
|
||||||
|
|
||||||
from build123d import *
|
from build123d.build_enums import MeshType, Unit
|
||||||
from build123d import Shape, downcast
|
from build123d.geometry import Color, Vector
|
||||||
|
from build123d.topology import downcast, Compound, Shape, Shell, Solid
|
||||||
from OCP.BRep import BRep_Tool
|
from OCP.BRep import BRep_Tool
|
||||||
from OCP.BRepBuilderAPI import (
|
from OCP.BRepBuilderAPI import (
|
||||||
BRepBuilderAPI_MakeFace,
|
BRepBuilderAPI_MakeFace,
|
||||||
|
|
@ -114,7 +108,16 @@ from py_lib3mf import Lib3MF
|
||||||
from ocp_vscode import *
|
from ocp_vscode import *
|
||||||
|
|
||||||
|
|
||||||
class Mesh3MF:
|
class Mesher:
|
||||||
|
"""Mesher
|
||||||
|
|
||||||
|
Tool for exporting and import meshed objects stored in 3MF or STL files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unit (Unit, optional): model units. Defaults to Unit.MM.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Translate b3d Units to Lib3MF ModelUnits
|
||||||
map_b3d_to_3mf_unit = {
|
map_b3d_to_3mf_unit = {
|
||||||
Unit.MC: Lib3MF.ModelUnit.MicroMeter,
|
Unit.MC: Lib3MF.ModelUnit.MicroMeter,
|
||||||
Unit.MM: Lib3MF.ModelUnit.MilliMeter,
|
Unit.MM: Lib3MF.ModelUnit.MilliMeter,
|
||||||
|
|
@ -123,37 +126,51 @@ class Mesh3MF:
|
||||||
Unit.FT: Lib3MF.ModelUnit.Foot,
|
Unit.FT: Lib3MF.ModelUnit.Foot,
|
||||||
Unit.M: Lib3MF.ModelUnit.Meter,
|
Unit.M: Lib3MF.ModelUnit.Meter,
|
||||||
}
|
}
|
||||||
|
# Translate Lib3MF ModelUnits to b3d Units
|
||||||
map_3mf_to_b3d_unit = {v: k for k, v in map_b3d_to_3mf_unit.items()}
|
map_3mf_to_b3d_unit = {v: k for k, v in map_b3d_to_3mf_unit.items()}
|
||||||
|
|
||||||
|
# Translate b3d MeshTypes to 3MF ObjectType
|
||||||
|
map_b3d_mesh_type_3mf = {
|
||||||
|
MeshType.OTHER: Lib3MF.ObjectType.Other,
|
||||||
|
MeshType.MODEL: Lib3MF.ObjectType.Model,
|
||||||
|
MeshType.SUPPORT: Lib3MF.ObjectType.Support,
|
||||||
|
MeshType.SOLIDSUPPORT: Lib3MF.ObjectType.SolidSupport,
|
||||||
|
}
|
||||||
|
# Translate 3MF ObjectType to b3d MeshTypess
|
||||||
|
map_3mf_to_b3d_mesh_type = {v: k for k, v in map_b3d_mesh_type_3mf.items()}
|
||||||
|
|
||||||
def __init__(self, unit: Unit = Unit.MM):
|
def __init__(self, unit: Unit = Unit.MM):
|
||||||
self.unit = unit
|
self.unit = unit
|
||||||
self.tessellations = None
|
|
||||||
libpath = os.path.dirname(Lib3MF.__file__)
|
libpath = os.path.dirname(Lib3MF.__file__)
|
||||||
self.wrapper = Lib3MF.Wrapper(os.path.join(libpath, "lib3mf"))
|
self.wrapper = Lib3MF.Wrapper(os.path.join(libpath, "lib3mf"))
|
||||||
self.model = self.wrapper.CreateModel()
|
self.model = self.wrapper.CreateModel()
|
||||||
self.model.SetUnit(Mesh3MF.map_b3d_to_3mf_unit[unit])
|
self.model.SetUnit(Mesher.map_b3d_to_3mf_unit[unit])
|
||||||
self.meshes: list[Lib3MF.MeshObject] = []
|
self.meshes: list[Lib3MF.MeshObject] = []
|
||||||
# self.mesh.MultiPropertyLayer
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model_unit(self) -> Unit:
|
def model_unit(self) -> Unit:
|
||||||
|
"""Unit used in the model"""
|
||||||
return self.unit
|
return self.unit
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def triangle_counts(self) -> list[int]:
|
def triangle_counts(self) -> list[int]:
|
||||||
|
"""Number of triangles in each of the model's meshes"""
|
||||||
return [m.GetTriangleCount() for m in self.meshes]
|
return [m.GetTriangleCount() for m in self.meshes]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vertex_counts(self) -> list[int]:
|
def vertex_counts(self) -> list[int]:
|
||||||
|
"""Number of vertices in each of the models's meshes"""
|
||||||
return [m.GetVertexCount() for m in self.meshes]
|
return [m.GetVertexCount() for m in self.meshes]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mesh_count(self) -> int:
|
def mesh_count(self) -> int:
|
||||||
|
"""Number of meshes in the model"""
|
||||||
mesh_iterator: Lib3MF.MeshObjectIterator = self.model.GetMeshObjects()
|
mesh_iterator: Lib3MF.MeshObjectIterator = self.model.GetMeshObjects()
|
||||||
return mesh_iterator.Count()
|
return mesh_iterator.Count()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def library_version(self) -> str:
|
def library_version(self) -> str:
|
||||||
|
"""3MF Consortium Lib#MF version"""
|
||||||
major, minor, micro = self.wrapper.GetLibraryVersion()
|
major, minor, micro = self.wrapper.GetLibraryVersion()
|
||||||
return f"{major}.{minor}.{micro}"
|
return f"{major}.{minor}.{micro}"
|
||||||
|
|
||||||
|
|
@ -165,6 +182,17 @@ class Mesh3MF:
|
||||||
metadata_type: str,
|
metadata_type: str,
|
||||||
must_preserve: bool,
|
must_preserve: bool,
|
||||||
):
|
):
|
||||||
|
"""add_meta_data
|
||||||
|
|
||||||
|
Add meta data to the models
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name_space (str): categorizer of different metadata entries
|
||||||
|
name (str): metadata label
|
||||||
|
value (str): metadata content
|
||||||
|
metadata_type (str): metadata trype
|
||||||
|
must_preserve (bool): metadata must not be removed if unused
|
||||||
|
"""
|
||||||
# Get an existing meta data group if there is one
|
# Get an existing meta data group if there is one
|
||||||
mdg = self.model.GetMetaDataGroup()
|
mdg = self.model.GetMetaDataGroup()
|
||||||
if mdg is None:
|
if mdg is None:
|
||||||
|
|
@ -176,6 +204,9 @@ class Mesh3MF:
|
||||||
mdg.AddMetaData(name_space, name, value, metadata_type, must_preserve)
|
mdg.AddMetaData(name_space, name, value, metadata_type, must_preserve)
|
||||||
|
|
||||||
def add_code_to_metadata(self):
|
def add_code_to_metadata(self):
|
||||||
|
"""Add the code calling this method to the 3MF metadata with the custom
|
||||||
|
name space `build123d`, name equal to the base file name and the type
|
||||||
|
as `python`"""
|
||||||
caller_file = sys._getframe().f_back.f_code.co_filename
|
caller_file = sys._getframe().f_back.f_code.co_filename
|
||||||
code_file = open(caller_file, "r") # open code file in read mode
|
code_file = open(caller_file, "r") # open code file in read mode
|
||||||
source_code = code_file.read() # read whole file to a string
|
source_code = code_file.read() # read whole file to a string
|
||||||
|
|
@ -190,6 +221,7 @@ class Mesh3MF:
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_meta_data(self) -> list[str]:
|
def get_meta_data(self) -> list[str]:
|
||||||
|
"""Retrieve all of the metadata"""
|
||||||
meta_data_group = self.model.GetMetaDataGroup()
|
meta_data_group = self.model.GetMetaDataGroup()
|
||||||
meta_data_contents = []
|
meta_data_contents = []
|
||||||
for i in range(meta_data_group.GetMetaDataCount()):
|
for i in range(meta_data_group.GetMetaDataCount()):
|
||||||
|
|
@ -201,6 +233,7 @@ class Mesh3MF:
|
||||||
return meta_data_contents
|
return meta_data_contents
|
||||||
|
|
||||||
def get_meta_data_by_key(self, name_space: str, name: str) -> list[str]:
|
def get_meta_data_by_key(self, name_space: str, name: str) -> list[str]:
|
||||||
|
"""Retrive the metadata value and type for the provided name space and name"""
|
||||||
meta_data_group = self.model.GetMetaDataGroup()
|
meta_data_group = self.model.GetMetaDataGroup()
|
||||||
meta_data_contents = []
|
meta_data_contents = []
|
||||||
meta_data = meta_data_group.GetMetaDataByKey(name_space, name)
|
meta_data = meta_data_group.GetMetaDataByKey(name_space, name)
|
||||||
|
|
@ -208,25 +241,45 @@ class Mesh3MF:
|
||||||
meta_data_contents.append(f"Value: {meta_data.GetValue()}")
|
meta_data_contents.append(f"Value: {meta_data.GetValue()}")
|
||||||
return meta_data_contents
|
return meta_data_contents
|
||||||
|
|
||||||
def get_mesh_properties(self, mesh: Lib3MF.MeshObject) -> str:
|
def get_mesh_properties(self) -> list[str]:
|
||||||
newline = "\n"
|
"""Retrieve the properties from all the meshes"""
|
||||||
properties = f"Name: {mesh.GetName()}{newline}"
|
properties = []
|
||||||
properties += f"Part Number: {mesh.GetPartNumber()}{newline}"
|
for mesh in self.meshes:
|
||||||
properties += f"Type: {Lib3MF.ObjectType(mesh.GetType()).name}{newline}"
|
properties += f"Name: {mesh.GetName()}"
|
||||||
uuid_valid, uuid_value = mesh.GetUUID()
|
properties += f"Part Number: {mesh.GetPartNumber()}"
|
||||||
if uuid_valid:
|
properties += f"Type: {Mesher.map_3mf_to_b3d_mesh_type[Lib3MF.ObjectType(mesh.GetType())].name}"
|
||||||
properties += f"UUID: {uuid_value}s{newline}"
|
uuid_valid, uuid_value = mesh.GetUUID()
|
||||||
|
if uuid_valid:
|
||||||
|
properties += f"UUID: {uuid_value}"
|
||||||
|
|
||||||
def add_shape(
|
def add_shape(
|
||||||
self,
|
self,
|
||||||
shape: Union[Shape, Iterable[Shape]],
|
shape: Union[Shape, Iterable[Shape]],
|
||||||
linear_deflection: float = 0.5,
|
linear_deflection: float = 0.5,
|
||||||
angular_deflection: float = 0.5,
|
angular_deflection: float = 0.5,
|
||||||
object_type: Lib3MF.ObjectType = Lib3MF.ObjectType.Model,
|
mesh_type: MeshType = MeshType.MODEL,
|
||||||
part_number: str = None,
|
part_number: str = None,
|
||||||
uuid: uuid = None,
|
uuid: uuid = None,
|
||||||
):
|
):
|
||||||
def is_facet_forward(
|
"""add_shape
|
||||||
|
|
||||||
|
Add a shape to the 3MF/STL file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
shape (Union[Shape, Iterable[Shape]]): build123d object
|
||||||
|
linear_deflection (float, optional): mesh control for edges. Defaults to 0.5.
|
||||||
|
angular_deflection (float, optional): mesh control for non-planar surfaces. Defaults to 0.5.
|
||||||
|
mesh_type (MeshType, optional): 3D printing use of mesh. Defaults to MeshType.MODEL.
|
||||||
|
part_number (str, optional): part #. Defaults to None.
|
||||||
|
uuid (uuid, optional): uuid from uuid package. Defaults to None.
|
||||||
|
|
||||||
|
Rasises:
|
||||||
|
RuntimeError: 3mf mesh is invalid
|
||||||
|
Warning: Degenerate shape skipped
|
||||||
|
Warning: 3mf mesh is not manifold
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _is_facet_forward(
|
||||||
points: tuple[gp_Pnt, gp_Pnt, gp_Pnt], shape_center: Vector
|
points: tuple[gp_Pnt, gp_Pnt, gp_Pnt], shape_center: Vector
|
||||||
) -> bool:
|
) -> bool:
|
||||||
# Create the facet
|
# Create the facet
|
||||||
|
|
@ -299,7 +352,7 @@ class Mesh3MF:
|
||||||
mesh_3mf: Lib3MF.MeshObject = self.model.AddMeshObject()
|
mesh_3mf: Lib3MF.MeshObject = self.model.AddMeshObject()
|
||||||
|
|
||||||
# Add the meta data
|
# Add the meta data
|
||||||
mesh_3mf.SetType(object_type)
|
mesh_3mf.SetType(Mesher.map_b3d_mesh_type_3mf[mesh_type])
|
||||||
if shape.label:
|
if shape.label:
|
||||||
mesh_3mf.SetName(shape.label)
|
mesh_3mf.SetName(shape.label)
|
||||||
if part_number:
|
if part_number:
|
||||||
|
|
@ -329,7 +382,7 @@ class Mesh3MF:
|
||||||
)
|
)
|
||||||
order = (
|
order = (
|
||||||
[0, 2, 1]
|
[0, 2, 1]
|
||||||
if not is_facet_forward(triangle_points, shape_center)
|
if not _is_facet_forward(triangle_points, shape_center)
|
||||||
else [0, 1, 2]
|
else [0, 1, 2]
|
||||||
)
|
)
|
||||||
# order = [2, 1, 0] # Creates an invalid mesh
|
# order = [2, 1, 0] # Creates an invalid mesh
|
||||||
|
|
@ -377,7 +430,8 @@ class Mesh3MF:
|
||||||
components = self.model.AddComponentsObject()
|
components = self.model.AddComponentsObject()
|
||||||
components.AddComponent(mesh_3mf, self.wrapper.GetIdentityTransform())
|
components.AddComponent(mesh_3mf, self.wrapper.GetIdentityTransform())
|
||||||
|
|
||||||
def get_shape(self, mesh_3mf: Lib3MF.MeshObject) -> Union[Shell, Solid]:
|
def _get_shape(self, mesh_3mf: Lib3MF.MeshObject) -> Shape:
|
||||||
|
"""Build build123d object from lib3mf mesh"""
|
||||||
# Extract all the vertices
|
# Extract all the vertices
|
||||||
gp_pnts = [gp_Pnt(*p.Coordinates[0:3]) for p in mesh_3mf.GetVertices()]
|
gp_pnts = [gp_Pnt(*p.Coordinates[0:3]) for p in mesh_3mf.GetVertices()]
|
||||||
|
|
||||||
|
|
@ -406,13 +460,24 @@ class Mesh3MF:
|
||||||
|
|
||||||
return shape_obj
|
return shape_obj
|
||||||
|
|
||||||
def read(self, file_name: str) -> list[Union[Shell, Solid]]:
|
def read(self, file_name: str) -> list[Shape]:
|
||||||
|
"""read
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_name (str): file path
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: Unknown file format - must be 3mf or stl
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[Shape]: build123d shapes extracted from mesh file
|
||||||
|
"""
|
||||||
input_file_format = file_name.split(".")[-1].lower()
|
input_file_format = file_name.split(".")[-1].lower()
|
||||||
if input_file_format not in ["3mf", "stl"]:
|
if input_file_format not in ["3mf", "stl"]:
|
||||||
raise ValueError(f"Unknown file format {input_file_format}")
|
raise ValueError(f"Unknown file format {input_file_format}")
|
||||||
reader = self.model.QueryReader(input_file_format)
|
reader = self.model.QueryReader(input_file_format)
|
||||||
reader.ReadFromFile(file_name)
|
reader.ReadFromFile(file_name)
|
||||||
self.unit = Mesh3MF.map_3mf_to_b3d_unit[self.model.GetUnit()]
|
self.unit = Mesher.map_3mf_to_b3d_unit[self.model.GetUnit()]
|
||||||
|
|
||||||
# Extract 3MF meshes and translate to OCP meshes
|
# Extract 3MF meshes and translate to OCP meshes
|
||||||
mesh_iterator: Lib3MF.MeshObjectIterator = self.model.GetMeshObjects()
|
mesh_iterator: Lib3MF.MeshObjectIterator = self.model.GetMeshObjects()
|
||||||
|
|
@ -422,7 +487,7 @@ class Mesh3MF:
|
||||||
self.meshes.append(mesh_iterator.GetCurrentMeshObject())
|
self.meshes.append(mesh_iterator.GetCurrentMeshObject())
|
||||||
shapes = []
|
shapes = []
|
||||||
for mesh in self.meshes:
|
for mesh in self.meshes:
|
||||||
shape = self.get_shape(mesh)
|
shape = self._get_shape(mesh)
|
||||||
shape.label = mesh.GetName()
|
shape.label = mesh.GetName()
|
||||||
triangle_properties = mesh.GetAllTriangleProperties()
|
triangle_properties = mesh.GetAllTriangleProperties()
|
||||||
color_indices = []
|
color_indices = []
|
||||||
|
|
@ -445,14 +510,15 @@ class Mesh3MF:
|
||||||
|
|
||||||
return shapes
|
return shapes
|
||||||
|
|
||||||
def _get_meshes(self):
|
|
||||||
mesh_iterator: Lib3MF.MeshObjectIterator = self.model.GetMeshObjects()
|
|
||||||
self.meshes: list[Lib3MF.MeshObject]
|
|
||||||
for _i in range(mesh_iterator.Count()):
|
|
||||||
mesh_iterator.MoveNext()
|
|
||||||
self.meshes.append(mesh_iterator.GetCurrentMeshObject())
|
|
||||||
|
|
||||||
def write(self, file_name: str):
|
def write(self, file_name: str):
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_name (str): file path
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: Unknown file format - must be 3mf or stl
|
||||||
|
"""
|
||||||
output_file_format = file_name.split(".")[-1].lower()
|
output_file_format = file_name.split(".")[-1].lower()
|
||||||
if output_file_format not in ["3mf", "stl"]:
|
if output_file_format not in ["3mf", "stl"]:
|
||||||
raise ValueError(f"Unknown file format {output_file_format}")
|
raise ValueError(f"Unknown file format {output_file_format}")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue