Extensions: lock the repositories before overwriting their manifests
[blender-addons-contrib.git] / io_vector / __init__.py
blob09a3abce43d0df7856f30f73fb03f7bc8b1ff546
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 #####
19 bl_info = {
20 "name": "Adobe Illustrator / PDF / SVG",
21 "author": "Howard Trickey",
22 "version": (1, 3),
23 "blender": (2, 80, 0),
24 "location": "File > Import-Export > Vector files (.ai, .pdf, .svg)",
25 "description": "Import Adobe Illustrator, PDF, and SVG",
26 "warning": "",
27 "doc_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Import-Export/AI_PDF_SVG",
29 "category": "Import-Export"}
31 if "bpy" in locals():
32 import importlib
34 importlib.reload(geom)
35 importlib.reload(model)
36 importlib.reload(vecfile)
37 importlib.reload(import_vecfile)
38 importlib.reload(offset)
39 importlib.reload(pdf)
40 importlib.reload(svg)
41 importlib.reload(triquad)
42 importlib.reload(art2polyarea)
43 else:
44 from . import (
45 geom,
46 model,
47 vecfile,
48 import_vecfile,
49 offset,
50 pdf,
51 svg,
52 triquad,
53 art2polyarea,
56 import math
57 import bpy
58 import bpy_extras.io_utils
59 from bpy.props import (BoolProperty,
60 EnumProperty,
61 FloatProperty,
62 IntProperty,
63 StringProperty
65 from bpy_extras.io_utils import ImportHelper
68 class VectorImporter(bpy.types.Operator, ImportHelper):
69 """Load an AI or PDF or SVG file"""
70 bl_idname = "import_vec.aipdfsvg"
71 bl_label = "Import AI/PDF/SVG"
72 bl_options = {"UNDO"}
74 filter_glob : StringProperty(default="*.ai;*.pdf;*.svg", options={"HIDDEN"})
75 smoothness : IntProperty(name="Smoothness",
76 description="How closely to approximate curves",
77 default=1,
78 min=0,
79 max=100)
80 scale : FloatProperty(name="Scale",
81 description="Scale longer bounding box side to this size",
82 default=4.0,
83 min=0.1,
84 max=100.0,
85 unit="LENGTH")
86 subdiv_kind : EnumProperty(name="Subdivision Method",
87 description="Method for approximating curves with lines",
88 items=[ \
89 ('UNIFORM', "Uniform",
90 "All curves bisected 'smoothness' times"),
91 ('ADAPTIVE', "Adaptive",
92 "Curves subdivided until flat enough, as" \
93 " determined by 'smoothness'"),
94 ('EVEN', "Even",
95 "Curves subdivided until segments have a common length," \
96 " determined by 'smoothness'"),
98 default='ADAPTIVE')
99 filled_only : BoolProperty(name="Filled paths only",
100 description="Only import filled paths",
101 default=True)
102 ignore_white : BoolProperty(name="Ignore white-filled",
103 description="Do not import white-filled paths",
104 default=True)
105 combine_paths : BoolProperty(name="Combine paths",
106 description="Use all paths when looking for holes",
107 default=False)
108 use_colors : BoolProperty(name="Use colors",
109 description="Use colors from vector file as materials",
110 default=False)
111 extrude_depth : FloatProperty(name="Extrude depth",
112 description="Depth of extrusion, if > 0",
113 default=0.0,
114 min=0.0,
115 max=100.0,
116 unit='LENGTH')
117 bevel_amount : FloatProperty(name="Bevel amount",
118 description="Amount of inward bevel, if > 0",
119 default=0.0,
120 min=0.0,
121 max=1000.0,
122 unit='LENGTH')
123 bevel_pitch : FloatProperty(name="Bevel pitch",
124 description="Angle of bevel from horizontal",
125 default=45 * math.pi / 180.0,
126 min=0.0,
127 max=89.0 * math.pi / 180.0,
128 unit='ROTATION')
129 cap_back : BoolProperty(name="Cap back",
130 description="Cap the back if extruding",
131 default=False)
132 true_scale : BoolProperty(name="True Scale",
133 description="Use true scale, with 1 meter = 1 blender unit",
134 default=False)
135 # some info display properties
136 num_verts : IntProperty(name="Number of vertices",
137 default=0)
138 num_faces : IntProperty(name="Number of faces",
139 default=0)
141 def draw(self, context):
142 layout = self.layout
143 box = layout.box()
144 box.label(text="Import Options")
145 box.prop(self, "smoothness")
146 box.prop(self, "scale")
147 box.prop(self, "true_scale")
148 box.prop(self, "subdiv_kind")
149 box.prop(self, "filled_only")
150 box.prop(self, "ignore_white")
151 box.prop(self, "combine_paths")
152 box.prop(self, "use_colors")
153 box.prop(self, "extrude_depth")
154 box.prop(self, "bevel_amount")
155 box.prop(self, "bevel_pitch")
156 box.prop(self, "cap_back")
157 if self.num_verts > 0:
158 layout.label(text="Ve:" + str(self.num_verts) + \
159 " | Fa:" + str(self.num_faces))
161 def action(self, context):
162 #convert the filename to an object name
163 if not self.filepath:
164 return
165 objname = self.filepath.split("\\")[-1].split("/")[-1]
166 if objname.find(".") > 0:
167 objname = objname.split(".")[0]
168 options = import_vecfile.ImportOptions()
169 if self.true_scale:
170 options.scaled_side_target = 0.0
171 else:
172 options.scaled_side_target = self.scale
173 options.quadrangulate = True
174 options.extrude_depth = self.extrude_depth
175 options.bevel_amount = self.bevel_amount
176 options.bevel_pitch = self.bevel_pitch
177 options.cap_back = self.cap_back
178 options.convert_options.subdiv_kind = self.subdiv_kind
179 options.convert_options.smoothness = self.smoothness
180 options.convert_options.filled_only = self.filled_only
181 options.convert_options.ignore_white = self.ignore_white
182 options.convert_options.combine_paths = self.combine_paths
183 (mdl, msg) = import_vecfile.ReadVecFileToModel(self.filepath, options)
184 if msg:
185 self.report({'ERROR'},
186 "Problem reading file " + self.filepath + ": " + msg)
187 return {'FINISHED'}
188 verts = mdl.points.pos
189 if self.true_scale:
190 # assume model units are 90 dpi, if svg file
191 # else 72 dpi
192 # convert to meters (1 inch = 0.0254 meters)
193 if self.filepath[-4:] in (".svg", ".SVG"):
194 s = 0.0254 / 90.0
195 print("svg s=", s)
196 else:
197 s = 0.0254 / 72.0
198 verts = [(s * v[0], s * v[1], s * v[2]) for v in verts]
199 faces = [f for f in mdl.faces if 3 <= len(f) <= 4]
200 mesh = bpy.data.meshes.new(objname)
201 mesh.from_pydata(verts, [], faces)
202 if self.use_colors:
203 add_colors(mesh, mdl.face_data)
204 mesh.update()
205 self.num_verts = len(verts)
206 self.num_faces = len(faces)
207 obj = bpy.data.objects.new(objname, mesh)
208 context.scene.collection.objects.link(obj)
209 bpy.ops.object.select_all(action='DESELECT')
210 obj.select_set(True)
211 context.view_layer.objects.active = obj
213 def execute(self, context):
214 self.action(context)
215 return {'FINISHED'}
218 def add_colors(mesh, colors):
219 # assume colors are parallel to faces in mesh
220 if len(colors) < len(mesh.polygons):
221 return
223 # use rgbtoindex to keep track of colors already
224 # seen and map them to indices into mesh.materials
225 rgbtoindex = {}
226 matnameprefix = "VImat." + mesh.name + "."
227 for i, c in enumerate(colors):
228 print("color for face", i)
229 if c not in rgbtoindex:
230 matname = matnameprefix + str(len(bpy.data.materials))
231 mat = bpy.data.materials.new(matname)
232 mat.diffuse_color = c
233 mesh.materials.append(mat)
234 cindex = len(mesh.materials) - 1
235 rgbtoindex[c] = cindex
236 else:
237 cindex = rgbtoindex[c]
238 mesh.polygons[i].material_index = cindex
241 def menu_import(self, context):
242 self.layout.operator(VectorImporter.bl_idname,
243 text="Vector files (.ai, .pdf, .svg)")
246 def register():
247 bpy.utils.register_class(VectorImporter)
249 bpy.types.TOPBAR_MT_file_import.append(menu_import)
252 def unregister():
253 bpy.utils.unregister_class(VectorImporter)
255 bpy.types.TOPBAR_MT_file_import.remove(menu_import)
258 if __name__ == "__main__":
259 register()