Merge branch 'blender-v4.0-release'
[blender-addons.git] / add_curve_extra_objects / add_surface_plane_cone.py
bloba76a097cf75e27066bbece1a8eb7db1168bc0029
1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "Surface: Plane / Cone/ Star / Wedge",
7 "description": "Create a NURBS surface plane",
8 "author": "Folkert de Vries",
9 "version": (1, 0, 2),
10 "blender": (2, 80, 0),
11 "location": "View3D > Add > Surface",
12 "warning": "",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
14 "category": "Add Mesh"
17 """
18 Info:
19 to add a surface star, plane or cone, go to add Menu > Surface > Star, Plane or Cone
20 next parameters like scale and u and v resolution can be adjusted in the toolshelf
22 have fun using this add-on
23 """
25 import bpy
26 from bpy.props import (
27 FloatProperty,
28 IntProperty,
30 from bpy.types import Operator
33 # generic class for inheritance
34 class MakeSurfaceHelpers:
35 # get input for size and resolution
36 size : FloatProperty(
37 name="Size",
38 description="Size of the object",
39 default=1.0,
40 min=0.01,
41 max=100.0,
42 unit="LENGTH",
44 res_u : IntProperty(
45 name="Resolution U",
46 description="Surface resolution in u direction",
47 default=1,
48 min=1,
49 max=500,
51 res_v : IntProperty(
52 name="Resolution V",
53 description="Surface resolution in v direction",
54 default=1,
55 min=1,
56 max=500,
59 @classmethod
60 def poll(cls, context):
61 return context.mode == 'OBJECT'
63 def draw(self, context):
64 layout = self.layout
65 layout.prop(self, "size")
67 col = layout.column(align=True)
68 col.prop(self, "res_u")
69 col.prop(self, "res_v")
72 class MakeSurfaceWedge(Operator, MakeSurfaceHelpers):
73 bl_idname = "object.add_surface_wedge"
74 bl_label = "Add Surface Wedge"
75 bl_description = "Construct a Surface Wedge"
76 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
78 def execute(self, context):
79 # variables
80 size = self.size
81 res_u = self.res_u
82 res_v = self.res_v
84 # add a surface Plane
85 bpy.ops.object.add_surface_plane()
86 # save some time, by getting instant access to those values
87 ao = context.active_object
88 point = ao.data.splines[0].points
90 # rotate 90 degrees on the z axis
91 ao.rotation_euler[0] = 0.0
92 ao.rotation_euler[1] = 0.0
93 ao.rotation_euler[2] = 1.570796
95 # go into edit mode and deselect
96 bpy.ops.object.mode_set(mode='EDIT')
97 bpy.ops.curve.select_all(action='DESELECT')
99 # select points 0 and 1, and extrudde them
100 # declaring ao and point again seems necessary...
101 ao = context.active_object
102 point = ao.data.splines[0].points
103 point[0].select = True
104 ao = context.active_object
105 point = ao.data.splines[0].points
106 point[1].select = True
107 bpy.ops.curve.extrude()
108 # bring extruded points up 1 bu on the z axis, and toggle
109 # cyclic in V direction
110 bpy.ops.transform.translate(value=(0, 0, 1), constraint_axis=(False, False, True))
111 bpy.ops.curve.cyclic_toggle(direction='CYCLIC_V')
113 # get points to the right coords.
114 point[0].co = (1.0, 0.0, 1.0, 1.0)
115 point[1].co = (-1.0, 0.0, 1.0, 1.0)
116 point[2].co = (1.0, -0.5, 0.0, 1.0)
117 point[3].co = (-1.0, -0.5, 0.0, 1.0)
118 point[4].co = (1.0, 0.5, 0.0, 1.0)
119 point[5].co = (-1.0, 0.5, 0.0, 1.0)
121 # go back to object mode
122 bpy.ops.object.mode_set(mode='OBJECT')
123 # get origin to geometry.
124 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
125 # change name
126 context.active_object.name = 'SurfaceWedge'
127 # get the wedge to the 3d cursor.
128 context.active_object.location = context.scene.cursor.location
129 bpy.ops.transform.resize(value=(size, size, size))
131 # adjust resolution in u and v direction
132 context.active_object.data.resolution_u = res_u
133 context.active_object.data.resolution_v = res_v
135 return{'FINISHED'}
138 class MakeSurfaceCone(Operator, MakeSurfaceHelpers):
139 bl_idname = "object.add_surface_cone"
140 bl_label = "Add Surface Cone"
141 bl_description = "Construct a Surface Cone"
142 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
144 def execute(self, context):
145 size = self.size
146 res_u = self.res_u
147 res_v = self.res_v
149 # add basemesh, a nurbs torus
150 bpy.ops.surface.primitive_nurbs_surface_torus_add(location=(0, 0, 0))
151 # get active object and active object name
153 ao = context.active_object
155 # go to edit mode
156 bpy.ops.object.mode_set(mode='EDIT')
157 # deselect all
158 bpy.ops.curve.select_all(action='DESELECT')
159 # too shorten a lot of lines
160 point = ao.data.splines[0].points
161 # get middle points
163 for i in range(0, 63):
164 if point[i].co.z == 0.0:
165 point[i].select = True
167 # select non-middle points and delete them
168 bpy.ops.curve.select_all(action='INVERT')
169 bpy.ops.curve.delete(type='VERT')
170 # declaring this again seems necessary...
171 point = ao.data.splines[0].points
172 # list of points to be in center, and 2 bu'' s higher
174 ToKeep = [1, 3, 5, 7, 9, 11, 13, 15, 17]
175 for i in range(0, len(ToKeep) - 1):
176 point[ToKeep[i]].select = True
178 bpy.ops.transform.resize(value=(0, 0, 0))
179 bpy.ops.curve.cyclic_toggle(direction='CYCLIC_U')
180 bpy.ops.transform.translate(value=(0, 0, 2))
182 # to make cone visible
183 bpy.ops.object.editmode_toggle()
184 bpy.ops.object.editmode_toggle()
185 # change name
186 context.active_object.name = 'SurfaceCone'
187 # go back to object mode
188 bpy.ops.object.editmode_toggle()
189 # bring object to cursor
190 bpy.ops.object.mode_set(mode='OBJECT')
191 context.active_object.location = context.scene.cursor.location
192 # adjust size
193 bpy.ops.transform.resize(value=(size, size, size))
195 # adjust resolution in u and v direction
196 context.active_object.data.resolution_u = res_u
197 context.active_object.data.resolution_v = res_v
199 return{'FINISHED'}
202 class MakeSurfaceStar(Operator, MakeSurfaceHelpers):
203 bl_idname = "object.add_surface_star"
204 bl_label = "Add Surface Star"
205 bl_description = "Construct a Surface Star"
206 bl_options = {'REGISTER', 'UNDO'}
208 def execute(self, context):
209 size = self.size
210 res_u = self.res_u
211 res_v = self.res_v
213 # add surface circle:
214 bpy.ops.surface.primitive_nurbs_surface_circle_add(location=(0, 0, 0))
215 # we got 8 points, we need 40 points.
216 # get active object
217 ao = context.active_object
218 # enter edtimode
219 bpy.ops.object.mode_set(mode='EDIT')
220 # deselect all
221 bpy.ops.curve.select_all(action='DESELECT')
222 # select point 0 and 1, and subdivide
223 point = ao.data.splines[0].points
225 point[0].select = True
226 point[1].select = True
227 bpy.ops.curve.subdivide()
228 bpy.ops.curve.select_all(action='DESELECT')
230 # select point 2 and 3, and subdivide
231 point[2].select = True
232 point[3].select = True
233 bpy.ops.curve.subdivide()
234 bpy.ops.curve.select_all(action='DESELECT')
236 ListOfCoords = [
237 (0.5, 0.0, 0.25, 1.0),
238 (0.80901700258255, 0.5877853035926819, 0.25, 1.0),
239 (0.1545085906982422, 0.4755282402038574, 0.25, 1.0),
240 (-0.30901703238487244, 0.9510565400123596, 0.25, 1.0),
241 (-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0),
242 (-1.0, 0.0, 0.25, 1.0),
243 (-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0),
244 (-0.30901703238487244, -0.9510565400123596, 0.25, 1.0),
245 (0.1545085906982422, -0.4755282402038574, 0.25, 1.0),
246 (0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0)
248 for i in range(0, 10):
249 context.active_object.data.splines[0].points[i].co = ListOfCoords[i]
251 # now select all, and subdivide till 40 points is reached:
252 bpy.ops.curve.select_all(action='SELECT')
253 bpy.ops.curve.subdivide()
254 bpy.ops.curve.subdivide()
255 bpy.ops.curve.subdivide()
257 # extrude the star
258 bpy.ops.curve.extrude(mode='TRANSLATION')
259 # bring extruded part up
260 bpy.ops.transform.translate(
261 value=(0, 0, 0.5),
262 constraint_axis=(False, False, True)
264 # flip normals
265 bpy.ops.curve.switch_direction()
266 # go back to object mode
267 bpy.ops.object.mode_set(mode='OBJECT')
268 # origin to geometry
269 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
270 # get object to 3d cursor
271 context.active_object.location = context.scene.cursor.location
272 # change name
273 ao.name = 'SurfaceStar'
274 # adjust size
275 bpy.ops.transform.resize(value=(size, size, size))
277 # adjust resolution in u and v direction
278 context.active_object.data.resolution_u = res_u
279 context.active_object.data.resolution_v = res_v
281 return{'FINISHED'}
284 class MakeSurfacePlane(Operator, MakeSurfaceHelpers):
285 bl_idname = "object.add_surface_plane"
286 bl_label = "Add Surface Plane"
287 bl_description = "Construct a Surface Plane"
288 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
290 def execute(self, context):
291 size = self.size
292 res_u = self.res_u
293 res_v = self.res_v
295 bpy.ops.surface.primitive_nurbs_surface_surface_add() # add the base mesh, a NURBS Surface
297 bpy.ops.transform.resize(
298 value=(1, 1, 0.0001),
299 constraint_axis=(False, False, True)
300 ) # make it flat
302 # added surface has 16 points
304 # deleting points to get plane shape
305 bpy.ops.object.mode_set(mode='EDIT')
306 bpy.ops.curve.select_all(action='DESELECT')
308 context.active_object.data.splines[0].points[0].select = True
309 context.active_object.data.splines[0].points[1].select = True
310 context.active_object.data.splines[0].points[2].select = True
311 context.active_object.data.splines[0].points[3].select = True
312 bpy.ops.curve.delete(type='VERT')
314 context.active_object.data.splines[0].points[8].select = True
315 context.active_object.data.splines[0].points[9].select = True
316 context.active_object.data.splines[0].points[10].select = True
317 context.active_object.data.splines[0].points[11].select = True
318 bpy.ops.curve.delete(type='VERT')
320 context.active_object.data.splines[0].points[0].select = True
321 context.active_object.data.splines[0].points[4].select = True
322 bpy.ops.curve.delete(type='VERT')
323 context.active_object.data.splines[0].points[2].select = True
324 context.active_object.data.splines[0].points[5].select = True
325 bpy.ops.curve.delete(type='VERT')
327 # assigning name
328 context.active_object.name = "SurfacePlane"
329 # select all
330 bpy.ops.curve.select_all(action='SELECT')
331 # bringing origin to center:
332 bpy.ops.object.mode_set(mode='OBJECT')
333 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
334 # transform scale
335 bpy.ops.object.transform_apply(location=False,rotation=False,scale=True)
337 # bring object to 3d cursor
338 bpy.ops.object.mode_set(mode='OBJECT')
339 context.active_object.location = context.scene.cursor.location
340 bpy.ops.transform.resize(value=(size, size, size))
342 # adjust resolution in u and v direction
343 context.active_object.data.resolution_u = res_u
344 context.active_object.data.resolution_v = res_v
346 return{'FINISHED'}
349 class SmoothXtimes(Operator):
350 bl_idname = "curve.smooth_x_times"
351 bl_label = "Smooth X Times"
352 #bl_space_type = "VIEW_3D"
353 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
355 # use of this class:
356 # lets you smooth till a thousand times. this is normally difficult, because
357 # you have to press w, click, press w, click etc.
359 # get values
360 times : IntProperty(
361 name="Smooth x Times",
362 min=1,
363 max=1000,
364 default=1,
365 description="Smooth amount"
368 @classmethod
369 def poll(cls, context):
370 return context.mode == 'EDIT_SURFACE'
372 def execute(self, context):
373 # smooth times
374 times = self.times
375 for i in range(1, times):
376 bpy.ops.curve.smooth()
378 return{'FINISHED'}
380 # Register
381 classes = [
382 #MakeSurfaceHelpers,
383 MakeSurfacePlane,
384 MakeSurfaceCone,
385 MakeSurfaceStar,
386 MakeSurfaceWedge,
387 SmoothXtimes
390 def register():
391 from bpy.utils import register_class
392 for cls in classes:
393 register_class(cls)
395 def unregister():
396 from bpy.utils import unregister_class
397 for cls in reversed(classes):
398 unregister_class(cls)
400 if __name__ == "__main__":
401 register()