(scroll down for embedded source code and more remarks about its runtime context)
When it comes to XYZ coordinates and 3D graphics, what tool might we use? The answer is pretty obvious: Blender of course.
But then do you have the Personal Workspace (PWS) you need, equipped with the necessary hardware? Perhaps you're not interested enough to want a dedicated workspace all your own and that's OK. A friend might let you test drive from time to time. Check it out. Try (test the waters) before you buy (dive in).
One theme we might take up within Blender, are the internal and external furnishings of this space to learn Blender, among other topics. What does your School of Tomorrow look like, inside (concave) and from without (convex)?
Blender is free open source so don't take this as a sales pitch in the conventional sense. I'm not selling Blender. I am selling using Quadrays inside of Blender, why not?
The code below is about four arrows, or rays, of equal length, pointing from a common origin, the center of a regular tetrahedron. These rays are labeled (1,0,0,0) (0,1,0,0) (0,0,1,0) (0,0,0,1) and may be called Quadrays, quad meaning four, and there are four of them. Check Wikipedia for more details.
We use Quadrays quite a bit at the School of Tomorrow, because twelve additive combinations of two of one, and one of two others, none of one last, give the 12 directions to neighboring ball centers, imagining twelve equi-diameter balls around a nucleus.
In fact, our regular tetrahedron is one of those connecting any four inter-tangent balls in such a packing, which, as it expands on out (12, 42, 92, 162...) begets the CCP or Cubic Close Packing, also known as the FCC or Face Centered Cubic Packing.
You may be wondering what a cube has to do with it, and we'll get to that in the course of our studies.
import bpy
from qrays import Qvector
from itertools import permutations
g = permutations((2,1,1,0))
ORIGIN_IVM = Qvector((0,0,0,0))
# set comprehension in list comprehension
SPOKES_IVM = [Qvector(v) for v in {p for p in g}]
ORIGIN_XYZ = ORIGIN_IVM.xyz().xyz # (0,0,0)
c6xty_ball = bpy.ops.mesh.primitive_ico_sphere_add
c6xty_ball(radius=0.5, enter_editmode=False, location=ORIGIN_XYZ)
bpy.ops.object.shade_smooth()
for qv in SPOKES_IVM:
xyz = qv.xyz().xyz
c6xty_ball(radius=0.5, enter_editmode=False, location=xyz)
bpy.ops.object.shade_smooth()
In the Youtube below, I rant about the "Concentric Hierarchy" which "my generation did not deign to share". If you're not sure what I'm talking about, you must be new to the School of Tomorrow, as it's what's at the core of the Bucky stuff, as the source of the domes and his thinking in general (see Synergetics: The Invention Behind the Inventions).
Who am I? Some autobio.
Given the context (namespace) of this School, of course a primary use of Blender is to bring forward the work of previous decades, which focused on VRML, X3D, Vpython, POV-Ray as strategies for rendering the 3D graphics.
In particular, I'm continuing recent work on the Flextegrity Lattice here at the School of Tomorrow.
Blender is the most capable tool yet, and you might wonder why I've been slow to bake it into this curriculum.
As students, you get to be the next faculty, meaning take what you've learned from others and value add, perform the alchemy of synergy to advance and enchance our curriculum of tomorrow.
from IPython.display import YouTubeVideo
YouTubeVideo("w9OU6B-qvjA")
YouTubeVideo("D1nw1PH4wjs") # no sound
YouTubeVideo("lrr4InSMX2E") # no sound
YouTubeVideo("rHzf3Dku_cE")
YouTubeVideo("hfYgCwC_4iE")
My immediate application has been to continue the work with POV-Ray (ray tracer) and Rhino (CAD). Blender has the best Python integration of anything I've yet used. I've not had occasion to use the ESRI product line up close, even if I got to lead a training for some of its people that time.
My Python framework developed around making animated GIFs about Flextegrity, part of our School's literature, may now be adapted for use within Blender.
The code above uses the techniques I share in Generating the FCC.
Looking ahead, I see using pandas and sqlite3 from inside Blender why not? The work we do around databases and polyhedrons will pay off inside this capable "3D" environment (using the namespace of 3D XYZ, versus the 4D of the IVM namespace).
YouTubeVideo("axyCPw6GAzI") # "dimension" in Synergetics
The code below results in an exception raised, no surprise there, as we're not inside Blender. You'll be able to fire up Blender's scripting window and run it from there, provided you have access to the Quadray Coordinates dependency (qrays.py
).
If you run this script, don't forget to change the path to wherever you decide to put your qrays.py, available here at the school repo.
You'll notice though, that these mesh icosaspheres have no materiality nor texture. The whole business of treating surfaces with invented textures and materials comprises a huge piece of what Blender is all about, especially its procedural node system. I link to a good teacher of Blender's procedural nodes below.
import bpy
import sys
sys.path.append("C:\\Users\\Kirby\\School_of_Tomorrow")
from qrays import Qvector
from functools import partial
from itertools import permutations
g = permutations((2,1,1,0))
ORIGIN_IVM = Qvector((0,0,0,0))
# set comprehension in list comprehension
SPOKES_IVM = [Qvector(v) for v in {p for p in g}]
nucleus = tuple([ORIGIN_IVM])
def next_layer(curr_layer, prev_layer):
"""
generates a next layer of FCC spheres by trying 12-around-1
for each in the current layer (curr_layer) but without keeping
any duplicates i.e. discarding redundant sphere centers.
"""
next_layer = set()
for qv in curr_layer:
for bv in SPOKES_IVM:
v_sum = qv + bv
if (not v_sum in curr_layer
and not v_sum in prev_layer):
next_layer.add(v_sum)
return sorted(list(next_layer))
nl = next_layer(nucleus, nucleus) # 1-freq
nnl = next_layer(nl, nucleus) # 2-freq
nnnl = next_layer(nnl, nl) # 3-freq
nnnnl= next_layer(nnnl, nnl) # 4-freq
def get_xyz(qvectors):
xyz_vectors = []
for qv in qvectors:
xyz_vectors.append(qv.xyz())
return xyz_vectors
# c6xty_ball = bpy.ops.mesh.primitive_ico_sphere_add
c6xty_ball = partial(bpy.ops.mesh.primitive_ico_sphere_add, subdivisions=1, radius=0.5, enter_editmode=False)
for ball in get_xyz(nl):
c6xty_ball(location=ball.xyz)
for ball in get_xyz(nnl):
c6xty_ball(location=ball.xyz)
for ball in get_xyz(nnnl):
c6xty_ball(location=ball.xyz)
for ball in get_xyz(nnnnl):
c6xty_ball(location=ball.xyz)
YouTubeVideo("O3gLBhC353Y")
YouTubeVideo("qJEWOTZnFeg")
YouTubeVideo("WSQFt1Nruns")