Newer
Older
# SPDX-License-Identifier: GPL-2.0-or-later
"name": "Surface: Plane / Cone/ Star / Wedge",
"description": "Create a NURBS surface plane",
"author": "Folkert de Vries",
"version": (1, 0, 2),
"blender": (2, 80, 0),
"location": "View3D > Add > Surface",
"warning": "",
"doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
"category": "Add Mesh"
}
"""
Info:
to add a surface star, plane or cone, go to add Menu > Surface > Star, Plane or Cone
next parameters like scale and u and v resolution can be adjusted in the toolshelf
have fun using this add-on
"""
import bpy
from bpy.props import (
FloatProperty,
IntProperty,
)
from bpy.types import Operator
# generic class for inheritance
class MakeSurfaceHelpers:
# get input for size and resolution
name="Size",
description="Size of the object",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH",
)
name="Resolution U",
description="Surface resolution in u direction",
default=1,
min=1,
max=500,
)
name="Resolution V",
description="Surface resolution in v direction",
default=1,
min=1,
max=500,
)
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def draw(self, context):
layout = self.layout
layout.prop(self, "size")
col = layout.column(align=True)
col.prop(self, "res_u")
col.prop(self, "res_v")
class MakeSurfaceWedge(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_wedge"
bl_label = "Add Surface Wedge"
bl_description = "Construct a Surface Wedge"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
def execute(self, context):
# variables
size = self.size
res_u = self.res_u
res_v = self.res_v
# add a surface Plane
bpy.ops.object.add_surface_plane()
# save some time, by getting instant access to those values
ao = context.active_object
point = ao.data.splines[0].points
# rotate 90 degrees on the z axis
ao.rotation_euler[0] = 0.0
ao.rotation_euler[1] = 0.0
ao.rotation_euler[2] = 1.570796
# go into edit mode and deselect
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.curve.select_all(action='DESELECT')
# select points 0 and 1, and extrudde them
# declaring ao and point again seems necessary...
ao = context.active_object
point = ao.data.splines[0].points
point[0].select = True
ao = context.active_object
point = ao.data.splines[0].points
point[1].select = True
bpy.ops.curve.extrude()
# bring extruded points up 1 bu on the z axis, and toggle
# cyclic in V direction
bpy.ops.transform.translate(value=(0, 0, 1), constraint_axis=(False, False, True))
bpy.ops.curve.cyclic_toggle(direction='CYCLIC_V')
# get points to the right coords.
point[0].co = (1.0, 0.0, 1.0, 1.0)
point[1].co = (-1.0, 0.0, 1.0, 1.0)
point[2].co = (1.0, -0.5, 0.0, 1.0)
point[3].co = (-1.0, -0.5, 0.0, 1.0)
point[4].co = (1.0, 0.5, 0.0, 1.0)
point[5].co = (-1.0, 0.5, 0.0, 1.0)
# go back to object mode
bpy.ops.object.mode_set(mode='OBJECT')
# get origin to geometry.
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# change name
context.active_object.name = 'SurfaceWedge'
# get the wedge to the 3d cursor.
context.active_object.location = context.scene.cursor.location
bpy.ops.transform.resize(value=(size, size, size))
# adjust resolution in u and v direction
context.active_object.data.resolution_u = res_u
context.active_object.data.resolution_v = res_v
return{'FINISHED'}
class MakeSurfaceCone(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_cone"
bl_label = "Add Surface Cone"
bl_description = "Construct a Surface Cone"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
def execute(self, context):
size = self.size
res_u = self.res_u
res_v = self.res_v
# add basemesh, a nurbs torus
bpy.ops.surface.primitive_nurbs_surface_torus_add(location=(0, 0, 0))
# get active object and active object name
ao = context.active_object
# go to edit mode
bpy.ops.object.mode_set(mode='EDIT')
# deselect all
bpy.ops.curve.select_all(action='DESELECT')
# too shorten a lot of lines
point = ao.data.splines[0].points
# get middle points
for i in range(0, 63):
if point[i].co.z == 0.0:
point[i].select = True
# select non-middle points and delete them
bpy.ops.curve.select_all(action='INVERT')
bpy.ops.curve.delete(type='VERT')
# declaring this again seems necessary...
point = ao.data.splines[0].points
# list of points to be in center, and 2 bu'' s higher
ToKeep = [1, 3, 5, 7, 9, 11, 13, 15, 17]
for i in range(0, len(ToKeep) - 1):
point[ToKeep[i]].select = True
bpy.ops.transform.resize(value=(0, 0, 0))
bpy.ops.curve.cyclic_toggle(direction='CYCLIC_U')
bpy.ops.transform.translate(value=(0, 0, 2))
# to make cone visible
bpy.ops.object.editmode_toggle()
bpy.ops.object.editmode_toggle()
# change name
context.active_object.name = 'SurfaceCone'
# go back to object mode
bpy.ops.object.editmode_toggle()
# bring object to cursor
bpy.ops.object.mode_set(mode='OBJECT')
context.active_object.location = context.scene.cursor.location
# adjust size
bpy.ops.transform.resize(value=(size, size, size))
# adjust resolution in u and v direction
context.active_object.data.resolution_u = res_u
context.active_object.data.resolution_v = res_v
return{'FINISHED'}
class MakeSurfaceStar(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_star"
bl_label = "Add Surface Star"
bl_description = "Construct a Surface Star"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
size = self.size
res_u = self.res_u
res_v = self.res_v
# add surface circle:
bpy.ops.surface.primitive_nurbs_surface_circle_add(location=(0, 0, 0))
# we got 8 points, we need 40 points.
# get active object
ao = context.active_object
# enter edtimode
bpy.ops.object.mode_set(mode='EDIT')
# deselect all
bpy.ops.curve.select_all(action='DESELECT')
# select point 0 and 1, and subdivide
point = ao.data.splines[0].points
point[0].select = True
point[1].select = True
bpy.ops.curve.subdivide()
bpy.ops.curve.select_all(action='DESELECT')
# select point 2 and 3, and subdivide
point[2].select = True
point[3].select = True
bpy.ops.curve.subdivide()
bpy.ops.curve.select_all(action='DESELECT')
ListOfCoords = [
(0.5, 0.0, 0.25, 1.0),
(0.80901700258255, 0.5877853035926819, 0.25, 1.0),
(0.1545085906982422, 0.4755282402038574, 0.25, 1.0),
(-0.30901703238487244, 0.9510565400123596, 0.25, 1.0),
(-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0),
(-1.0, 0.0, 0.25, 1.0),
(-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0),
(-0.30901703238487244, -0.9510565400123596, 0.25, 1.0),
(0.1545085906982422, -0.4755282402038574, 0.25, 1.0),
(0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0)
]
for i in range(0, 10):
context.active_object.data.splines[0].points[i].co = ListOfCoords[i]
# now select all, and subdivide till 40 points is reached:
bpy.ops.curve.select_all(action='SELECT')
bpy.ops.curve.subdivide()
bpy.ops.curve.subdivide()
bpy.ops.curve.subdivide()
# extrude the star
bpy.ops.curve.extrude(mode='TRANSLATION')
# bring extruded part up
bpy.ops.transform.translate(
value=(0, 0, 0.5),
constraint_axis=(False, False, True)
)
# flip normals
bpy.ops.curve.switch_direction()
# go back to object mode
bpy.ops.object.mode_set(mode='OBJECT')
# origin to geometry
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# get object to 3d cursor
context.active_object.location = context.scene.cursor.location
# change name
ao.name = 'SurfaceStar'
# adjust size
bpy.ops.transform.resize(value=(size, size, size))
# adjust resolution in u and v direction
context.active_object.data.resolution_u = res_u
context.active_object.data.resolution_v = res_v
return{'FINISHED'}
class MakeSurfacePlane(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_plane"
bl_label = "Add Surface Plane"
bl_description = "Construct a Surface Plane"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
def execute(self, context):
size = self.size
res_u = self.res_u
res_v = self.res_v
bpy.ops.surface.primitive_nurbs_surface_surface_add() # add the base mesh, a NURBS Surface
bpy.ops.transform.resize(
value=(1, 1, 0.0001),
constraint_axis=(False, False, True)
) # make it flat
# added surface has 16 points
# deleting points to get plane shape
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.curve.select_all(action='DESELECT')
context.active_object.data.splines[0].points[0].select = True
context.active_object.data.splines[0].points[1].select = True
context.active_object.data.splines[0].points[2].select = True
context.active_object.data.splines[0].points[3].select = True
bpy.ops.curve.delete(type='VERT')
context.active_object.data.splines[0].points[8].select = True
context.active_object.data.splines[0].points[9].select = True
context.active_object.data.splines[0].points[10].select = True
context.active_object.data.splines[0].points[11].select = True
bpy.ops.curve.delete(type='VERT')
context.active_object.data.splines[0].points[0].select = True
context.active_object.data.splines[0].points[4].select = True
bpy.ops.curve.delete(type='VERT')
context.active_object.data.splines[0].points[2].select = True
context.active_object.data.splines[0].points[5].select = True
bpy.ops.curve.delete(type='VERT')
# assigning name
context.active_object.name = "SurfacePlane"
# select all
bpy.ops.curve.select_all(action='SELECT')
# bringing origin to center:
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# transform scale
bpy.ops.object.transform_apply(location=False,rotation=False,scale=True)
# bring object to 3d cursor
bpy.ops.object.mode_set(mode='OBJECT')
context.active_object.location = context.scene.cursor.location
bpy.ops.transform.resize(value=(size, size, size))
# adjust resolution in u and v direction
context.active_object.data.resolution_u = res_u
context.active_object.data.resolution_v = res_v
return{'FINISHED'}
class SmoothXtimes(Operator):
bl_idname = "curve.smooth_x_times"
bl_label = "Smooth X Times"
#bl_space_type = "VIEW_3D"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
# use of this class:
# lets you smooth till a thousand times. this is normally difficult, because
# you have to press w, click, press w, click etc.
# get values
name="Smooth x Times",
min=1,
max=1000,
default=1,
description="Smooth amount"
)
@classmethod
def poll(cls, context):
return context.mode == 'EDIT_SURFACE'
def execute(self, context):
times = self.times
for i in range(1, times):
bpy.ops.curve.smooth()
# Register
classes = [
#MakeSurfaceHelpers,
MakeSurfacePlane,
MakeSurfaceCone,
MakeSurfaceStar,
MakeSurfaceWedge,
SmoothXtimes
]
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
if __name__ == "__main__":
register()