Dear all,
I would like for a scientific sketch to draw a flexible tube, whose color at each point is defined by its curvature.
What I’ve done by now is to extract from the control points of a bezier (which the cylinder is supposed to follow) a list of coordinates. From these I obtained the curvature and transformed it into a rgb triplet. See code below:
import bpy
import os
import mathutils
import numpy as np
ob = bpy.context.object
currPath = os.path.splitext(bpy.data.filepath)[0]+".txt"
currPath2 = os.path.splitext(bpy.data.filepath)[0]+".dat"
file = open(currPath2, "w")
r1, g1, b1 = (1, 0.0, 0) #start color
r2, g2, b2 = (0, 0, 1) # end color
rmin = 0
rmax = 15
res = 25 #number of interpolation points between bezier control points
def radius(A, B, C):
AB = B - A
BC = C - B
AC = C - A
a = np.linalg.norm(AB)
b = np.linalg.norm(BC)
c = np.linalg.norm(AC)
R = (a * b * c) / np.sqrt(2.0 * a**2 * b**2 +
2.0 * b**2 * c**2 +
2.0 * c**2 * a**2 -
a**4 - b**4 - c**4)
print(a,b,c,R)
if np.isnan(R) == True:
R = rmax
return R
def color(r):
if r >= rmax:
x = 1
else:
x = r/rmax
red = 1*(r1+(r2-r1)*x)
green = 1*(g1+(g2-g1)*x)
blue = 1*(b1+(b2-b1)*x)
colo = [red, green, blue]
return colo
coord = [0, 0, 0]
for curves in bpy.data.curves:
print(curves)
for splines in curves.splines:
print(splines)
for x in range(len(splines.bezier_points)-1):
#file.write("p ")
points = []
handle_left = ob.matrix_world * splines.bezier_points[x].handle_left
co = ob.matrix_world * splines.bezier_points[x].co
handle_right = ob.matrix_world * splines.bezier_points[x].handle_right
knot1 = ob.matrix_world * splines.bezier_points[x].co
knot2 = ob.matrix_world * splines.bezier_points[x+1].co
handle1 = ob.matrix_world * splines.bezier_points[x].handle_right
handle2 = ob.matrix_world * splines.bezier_points[x+1].handle_left
_points = mathutils.geometry.interpolate_bezier(knot1, handle1, handle2, knot2,res)
points.extend(_points)
for i in range(res):
B = [points[i].x, points[i].y, points[i].z]
coord = np.vstack([coord,B])
for i in range(len(coord)-3):
r = radius(coord[i+1],coord[i+2],coord[i+3])
file.write("%.6f " % (coord[i+2,0]))
file.write("%.6f " % (coord[i+2,1]))
file.write("%.6f " % (coord[i+2,2]))
file.write("%.6f " % r)
file.write("%.6f " % (color(r)[0]))
file.write("%.6f " % (color(r)[1]))
file.write("%.6f " % (color(r)[2]))
file.write("
")
file.close()
This script gives me, from an existing bezier a file containing the coordinates, the radius of the circle, and the rgb values, e.g:
5.065349 -10.414362 3.538601 3.387952 0.774137 0.000000 0.225863
5.123960 -10.350035 3.540624 3.757772 0.749482 0.000000 0.250518
5.184170 -10.282537 3.544642 4.076589 0.728227 0.000000 0.271773
5.245684 -10.212162 3.550690 4.335423 0.710972 0.000000 0.289028
5.308205 -10.139201 3.558802 4.527534 0.698164 0.000000 0.301836
5.371437 -10.063947 3.569014 4.649650 0.690023 0.000000 0.309977
5.435085 -9.986691 3.581360 4.703592 0.686427 0.000000 0.313573
5.498853 -9.907725 3.595873 4.690361 0.687309 0.000000 0.312691
5.562445 -9.827343 3.612590 4.617634 0.692158 0.000000 0.307842
5.625564 -9.745835 3.631544 4.491288 0.700581 0.000000 0.299419
5.687915 -9.663495 3.652771 4.319911 0.712006 0.000000 0.287994
5.749203 -9.580614 3.676304 4.110457 0.725970 0.000000 0.274030
5.809130 -9.497484 3.702178 3.872958 0.741803 0.000000 0.258197
5.867402 -9.414398 3.730428 3.615350 0.758977 0.000000 0.241023
5.923721 -9.331647 3.761088 3.345135 0.776991 0.000000 0.223009
5.977793 -9.249524 3.794194 3.069495 0.795367 0.000000 0.204633
6.029322 -9.168321 3.829779 2.794968 0.813669 0.000000 0.186331
6.078011 -9.088329 3.867878 2.526923 0.831538 0.000000 0.168462
6.123564 -9.009842 3.908526 2.269837 0.848678 0.000000 0.151322
6.165687 -8.933150 3.951757 2.027585 0.864828 0.000000 0.135172
6.204082 -8.858547 3.997607 1.803645 0.879757 0.000000 0.120243
6.238453 -8.786325 4.046108 1.599834 0.893344 0.000000 0.106656
6.268507 -8.716774 4.097297 1.417716 0.905486 0.000000 0.094514
6.293944 -8.650188 4.151208 0.066995 0.995534 0.000000 0.004466
6.293944 -8.650187 4.151208 0.064222 0.995719 0.000000 0.004281
6.315726 -8.586108 4.207057 2.694352 0.820377 0.000000 0.179623
6.335208 -8.523769 4.263901 3.021274 0.798582 0.000000 0.201418
6.352695 -8.462994 4.321537 3.489663 0.767356 0.000000 0.232644
6.368489 -8.403605 4.379761 4.194625 0.720358 0.000000 0.279642
6.382892 -8.345426 4.438371 5.347994 0.643467 0.000000 0.356533
6.396208 -8.288280 4.497162 7.536376 0.497575 0.000000 0.502425
6.408740 -8.231993 4.555931 13.219034 0.118731 0.000000 0.881269
6.420790 -8.176385 4.614475 61.837961 0.000000 0.000000 1.000000
Following another thread in this forum, with the full solution given at
http://www.gibert.biz/download/3dscatterplotswithblender I made a step forward imported this list as a series of spheres with the color defined by the value of the last three columns, with the following result.
This is close to what I wanted, but there are many reasons why I would prefer to have a cylinder, following the original bezier and with a color profile determined by the curvature (red where it is highly curved, blue where it is straight).
My approach is probably unnecessarily lengthy. Do you have any suggestion, how to manage in my task? Unfortunately I am a beginner of Blender and not really advanced in python, but willing to learn.
Best greets,
Leonardo