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