1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
23 "author": "Guillaume Bouchard (Guillaum)",
25 "blender": (2, 80, 0),
26 "location": "File > Import-Export > Stl",
27 "description": "Import-Export STL files",
29 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
30 "Scripts/Import-Export/STL",
31 "support": 'OFFICIAL',
32 "category": "Import-Export",
36 # @todo write the wiki page
39 Import-Export STL files (binary or ascii)
41 - Import automatically remove the doubles.
42 - Export can export with/without modifiers applied
47 - Does not handle endien
52 if "stl_utils" in locals():
53 importlib
.reload(stl_utils
)
54 if "blender_utils" in locals():
55 importlib
.reload(blender_utils
)
60 from bpy
.props
import (
67 from bpy_extras
.io_utils
import (
73 from bpy
.types
import (
75 OperatorFileListElement
,
79 @orientation_helper(axis_forward
='Y', axis_up
='Z')
80 class ImportSTL(Operator
, ImportHelper
):
81 """Load STL triangle mesh data"""
82 bl_idname
= "import_mesh.stl"
83 bl_label
= "Import STL"
88 filter_glob
: StringProperty(
92 files
: CollectionProperty(
94 type=OperatorFileListElement
,
96 directory
: StringProperty(
100 global_scale
: FloatProperty(
102 soft_min
=0.001, soft_max
=1000.0,
107 use_scene_unit
: BoolProperty(
109 description
="Apply current scene's unit (as defined by unit scale) to imported data",
113 use_facet_normal
: BoolProperty(
114 name
="Facet Normals",
115 description
="Use (import) facet normals (note that this will still give flat shading)",
119 def execute(self
, context
):
120 from . import stl_utils
121 from . import blender_utils
122 from mathutils
import Matrix
124 paths
= [os
.path
.join(self
.directory
, name
.name
)
125 for name
in self
.files
]
127 scene
= context
.scene
129 # Take into account scene's unit scale, so that 1 inch in Blender gives 1 inch elsewhere! See T42000.
130 global_scale
= self
.global_scale
131 if scene
.unit_settings
.system
!= 'NONE' and self
.use_scene_unit
:
132 global_scale
/= scene
.unit_settings
.scale_length
134 global_matrix
= axis_conversion(from_forward
=self
.axis_forward
,
135 from_up
=self
.axis_up
,
136 ).to_4x4() @ Matrix
.Scale(global_scale
, 4)
139 paths
.append(self
.filepath
)
141 if bpy
.ops
.object.mode_set
.poll():
142 bpy
.ops
.object.mode_set(mode
='OBJECT')
144 if bpy
.ops
.object.select_all
.poll():
145 bpy
.ops
.object.select_all(action
='DESELECT')
148 objName
= bpy
.path
.display_name(os
.path
.basename(path
))
149 tris
, tri_nors
, pts
= stl_utils
.read_stl(path
)
150 tri_nors
= tri_nors
if self
.use_facet_normal
else None
151 blender_utils
.create_and_link_mesh(objName
, tris
, tri_nors
, pts
, global_matrix
)
156 @orientation_helper(axis_forward
='Y', axis_up
='Z')
157 class ExportSTL(Operator
, ExportHelper
):
158 """Save STL triangle mesh data from the active object"""
159 bl_idname
= "export_mesh.stl"
160 bl_label
= "Export STL"
162 filename_ext
= ".stl"
163 filter_glob
: StringProperty(default
="*.stl", options
={'HIDDEN'})
165 use_selection
: BoolProperty(
166 name
="Selection Only",
167 description
="Export selected objects only",
170 global_scale
: FloatProperty(
172 min=0.01, max=1000.0,
176 use_scene_unit
: BoolProperty(
178 description
="Apply current scene's unit (as defined by unit scale) to exported data",
183 description
="Save the file in ASCII file format",
186 use_mesh_modifiers
: BoolProperty(
187 name
="Apply Modifiers",
188 description
="Apply the modifiers before saving",
191 batch_mode
: EnumProperty(
193 items
=(('OFF', "Off", "All data in one file"),
194 ('OBJECT', "Object", "Each object as a file"),
198 def check_extension(self
):
199 return self
.batch_mode
== 'OFF'
201 def execute(self
, context
):
202 from . import stl_utils
203 from . import blender_utils
205 from mathutils
import Matrix
206 keywords
= self
.as_keywords(ignore
=("axis_forward",
213 "use_mesh_modifiers",
217 scene
= context
.scene
218 if self
.use_selection
:
219 data_seq
= context
.selected_objects
221 data_seq
= scene
.objects
223 # Take into account scene's unit scale, so that 1 inch in Blender gives 1 inch elsewhere! See T42000.
224 global_scale
= self
.global_scale
225 if scene
.unit_settings
.system
!= 'NONE' and self
.use_scene_unit
:
226 global_scale
*= scene
.unit_settings
.scale_length
228 global_matrix
= axis_conversion(to_forward
=self
.axis_forward
,
230 ).to_4x4() @ Matrix
.Scale(global_scale
, 4)
232 if self
.batch_mode
== 'OFF':
233 faces
= itertools
.chain
.from_iterable(
234 blender_utils
.faces_from_mesh(ob
, global_matrix
, self
.use_mesh_modifiers
)
237 stl_utils
.write_stl(faces
=faces
, **keywords
)
238 elif self
.batch_mode
== 'OBJECT':
239 prefix
= os
.path
.splitext(self
.filepath
)[0]
240 keywords_temp
= keywords
.copy()
242 faces
= blender_utils
.faces_from_mesh(ob
, global_matrix
, self
.use_mesh_modifiers
)
243 keywords_temp
["filepath"] = prefix
+ bpy
.path
.clean_name(ob
.name
) + ".stl"
244 stl_utils
.write_stl(faces
=faces
, **keywords_temp
)
249 def menu_import(self
, context
):
250 self
.layout
.operator(ImportSTL
.bl_idname
, text
="Stl (.stl)")
253 def menu_export(self
, context
):
254 self
.layout
.operator(ExportSTL
.bl_idname
, text
="Stl (.stl)")
264 bpy
.utils
.register_class(cls
)
266 bpy
.types
.TOPBAR_MT_file_import
.append(menu_import
)
267 bpy
.types
.TOPBAR_MT_file_export
.append(menu_export
)
272 bpy
.utils
.unregister_class(cls
)
274 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_import
)
275 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_export
)
278 if __name__
== "__main__":