Skip to content

Instantly share code, notes, and snippets.

@batFINGER
Last active January 2, 2021 11:10
Show Gist options
  • Save batFINGER/0aff253f586a4431a0e13695c7b8cf77 to your computer and use it in GitHub Desktop.
Save batFINGER/0aff253f586a4431a0e13695c7b8cf77 to your computer and use it in GitHub Desktop.
Spaces Spherical, Torus, Cylindrical
bl_info = {
"name": "Math Surface Shape",
"author": "batFINGER",
"version": (1, 0),
"blender": (2, 78, 0), # and most prior
"location": "View3D > Add > Mesh > New Object",
"description": "Adds a new Mesh Object",
"warning": "",
"wiki_url": "",
"category": "Add Mesh",
}
import bpy
from bpy.types import Operator, PropertyGroup
from bpy.props import (FloatVectorProperty,
IntProperty,
FloatProperty,
EnumProperty,
PointerProperty,
StringProperty,
)
from bpy.utils import register_class
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
import bmesh
from math import * #TODO (quick fix for mapping)
class TorusCoordsPoint:
@property
def xyz(self):
theta = self.theta
zi = self.zi
R = self.R
r = self.r
a = (R + r * cos(theta))
x = a * cos(zi)
y = a * sin(zi)
z = r * sin(theta)
return Vector((x,y,z))
def __init__(self, R, r, theta, zi):
self.theta = theta
self.zi = zi
self.R = R
self.r = r
#self.xyz = self.point(theta, zi)
def __repr__(self):
return "TorusCoord(%.4f, %.4f)" % (self.theta, self.zi)
class TorusCoords:
item = ('TOROIDAL', "Toroidal", "Use Torus Space")
def draw(self, layout, context):
#print(self, layout, context)
layout.label("TORUS")
layout.prop(self, "R")
layout.prop(self, "r")
layout.prop(self, "minor_segments")
layout.prop(self, "major_segments")
@property
def space(self):
return TorusCoords(self.R, self.r, self.major_segments, self.minor_segments)
props = {"R":FloatProperty(name="Major Radius", default=1.0, min=0.0),
"r":FloatProperty(name="Minor Radius", default=0.25, min=0.1),
"major_segments":IntProperty(name="Major Segments", default=48, min=3),
"minor_segments":IntProperty(name="Minor Segments", default=12, min=3),
"draw": draw,
"space": space}
def point(self, theta, zi):
return TorusCoordsPoint(self.R, self.r, theta, zi)
def points_rings(self):
rings = []
zi_range = radians(360) # TODO
theta_range = radians(360)
for r in range(self.major_segments + 1):
zi = r * zi_range / self.major_segments
ring = [self.point(i * theta_range / self.minor_segments, zi) for i in range(self.minor_segments)]
#ring.append(ring[0])
rings.append(ring)
return rings
def __init__(self, R, r, major_segments, minor_segments):
self.R = R
self.r = r
self.minor_segments = minor_segments
self.major_segments = major_segments
class SphericalCoordsPoint:
@property
def xyz(self):
theta = self.theta
zi = self.zi
x = cos(theta) * sin(zi)
y = sin(theta) * sin(zi)
z = cos(zi)
R = self.R
return R * Vector((x,y,z))
def __init__(self, R, theta, zi):
self.R = R
self.theta = theta
self.zi = zi
#self.xyz = self.point(theta, zi)
def __repr__(self):
return "SphericalCoord(%.4f, %.4f)" % (degrees(self.theta),
degrees(self.zi))
class SphericalCoords:
def draw(self, layout, context):
#print(self, layout, context)
layout.label("Spherical")
layout.prop(self, "R")
layout.prop(self, "rings")
layout.prop(self, "segments")
@property
def space(self):
return SphericalCoords(self.R, self.rings, self.segments)
def point(self, theta, zi):
return SphericalCoordsPoint(self.R, theta, zi)
def points_rings(self):
rings = []
zi_range = radians(180) # TODO
theta_range = radians(360)
for r in range(self.rings + 1):
zi = r * zi_range / self.rings
ring = [self.point(i * theta_range / self.segments, zi) for i in range(self.segments)]
#ring.append(ring[0])
rings.append(ring)
return rings
item = ('SPHERICAL', "Spherical", "Add Spherical Space")
props = {"R":FloatProperty(name="Radius", default=1.0, min=0.1),
"segments":IntProperty(name="Segments", default=32, min=3),
"rings":IntProperty(name="Rings", default=16, min=3),
"draw":draw,
"space":space}
def __init__(self, R, rings, segments):
self.R = R
self.rings = rings
self.segments = segments
class OBJECT_OT_add_object_using_space():
"""Create a new Mesh Object"""
bl_idname = "mesh.add_object_from_space"
bl_label = "Space Mapping"
bl_options = {'REGISTER', 'UNDO'}
bl_description = "Add Object using Spherical / Toroidal space"
fx = StringProperty(default="x")
fy = StringProperty(default="y")
fz = StringProperty(default="z")
def draw(self, context):
layout = self.layout
layout.label("SPACE")
layout.prop(self, "space")
space = getattr(self, self.space.lower(), None)
print(space)
space.draw(layout, context)
layout.label("MAPPING")
layout.prop(self, "fx")
layout.prop(self, "fy")
layout.prop(self, "fz")
col = layout.column()
col.prop(self, "scale")
col.prop(self, "location")
col.prop(self, "view_align")
rcol = layout.column()
rcol.enabled = not self.view_align
rcol.prop(self, "rotation")
#space.draw()
def add_object(self, context, name):
print(self, vars(self), self.bl_rna)
scale_x = self.scale.x
scale_y = self.scale.y
bm = bmesh.new()
# TODO come up with a nicer way to do this.
space = getattr(self, self.space.lower(), None)
if not space:
print("Something horrible happened")
return {'CANCELLED'}
rings = space.space.points_rings()
def map(p):
x, y, z = p.xyz
_x = self.scale.x * eval(self.fx)
_y = self.scale.y * eval(self.fy)
_z = self.scale.z * eval(self.fz)
return Vector((_x, _y, _z))
verts0 = [bm.verts.new(map(p)) for p in rings[0]]
verts0.append(verts0[0])
for ring in range(1, len(rings)):
verts1 = [bm.verts.new(map(p)) for p in rings[ring]]
verts1.append(verts1[0]) # make a ring
faces = [
bm.faces.new((
verts0[i], verts1[i],
verts1[i+1], verts0[i+1]
))
for i in range(len(verts0) - 1)
]
verts0 = verts1
mesh = bpy.data.meshes.new(name)
bm.to_mesh(mesh)
object_data_add(context, mesh, operator=self)
bm.free()
def __init__(self): # TODO
print("INIT")
def execute(self, context):
self.add_object(context, self.space)
return {'FINISHED'}
def make_op(spaces):
items = []
propdic = {}
for space in spaces:
enum, name, desc = space.item
items.append(space.item)
# make a pointer from the enum.lower()
gp = type("%sGroup" % enum, (PropertyGroup,), space.props)
register_class(gp)
propdic[enum.lower()] = PointerProperty(type=gp)
propdic["space"] = EnumProperty(
items=items,
name="space",
default='SPHERICAL',
description="Use space",
)
propdic["scale"] = FloatVectorProperty(
name="scale",
default=(1.0, 1.0, 1.0),
subtype='TRANSLATION',
description="scaling",
)
return type("OBJECT_OT_add_object_using_space", (OBJECT_OT_add_object_using_space, Operator, AddObjectHelper,), propdic)
# Registration
def add_object_button(self, context):
self.layout.operator(
"mesh.add_object_from_space",
text="Maths / Space Equations",
icon='PLUGIN')
# This allows you to right click on a button and link to the manual
def add_object_manual_map():
url_manual_prefix = "http://wiki.blender.org/index.php/Doc:2.6/Manual/"
url_manual_mapping = (
("bpy.ops.mesh.add_object", "Modeling/Objects"),
)
return url_manual_prefix, url_manual_mapping
object_space_op = None
def register():
object_space_op = make_op([SphericalCoords, TorusCoords])
register_class(object_space_op)
#bpy.utils.register_manual_map(add_object_manual_map)
bpy.types.INFO_MT_mesh_add.append(add_object_button)
def unregister():
if object_space_op:
bpy.utils.unregister_class(object_space_op)
#bpy.utils.unregister_manual_map(add_object_manual_map)
bpy.types.INFO_MT_mesh_add.remove(add_object_button)
if __name__ == "__main__":
register()
@batFINGER
Copy link
Author

batFINGER commented Sep 28, 2016

screenshot from 2016-09-30 03 07 26

battorus

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment