You People might have seen similar question everywhere, I have checked almost all of them but none of them satisfies my requirement. :(
What I am Trying to achieve: Trying to draw a Tube and Bend using circular Rings and them joining them to form a tube and bend.
What Would be the best / Robust way to Draw a Circle in 3D ? I have following parameters:
- Circle Center (global Coordinates)
- Radius
- Direction Vector V
( Point B (x,y,z) - Point A (x,y,z) )
Technique I already used:
- Choose Arbitrary Vector v1 e.g. [1,0,0]
- Cross Product to get a new othronormal vector
v2 = CROSS ( V , v1 ) - Draw Circle using v1 and v2
Please Check the attached Code below:
def circularpoints_v3(center, radius, normal, num_points=12):
# normal == direction Vector (V)
v1 =v2 = np.array([0. , 0., 0.]).astype(np.float64) #z
if True:
if abs(normal[0]) > abs(normal[2]):
b2 = np.array([-normal[1], normal[0], 0.0])
else:
b2 = np.array([0.0, -normal[2], normal[1]])
b2 /= np.linalg.norm(b2)
b1 = np.cross(b2, normal)
v1 = b2
v2 = b1
circle = []
angles = np.linspace(0, 2 * np.pi, num=num_points)
for angle in angles:
v1_Out = np.cos(angle) * v1
v2_Out = np.sin(angle) * v2
point = center + (radius * (v1_Out + v2_Out ))
circle.append(point)
Issues: It is working perfectly, but I have almost every possible combination of Direction Vector V.
As a result, I need an orthonormal basis for every V. BUT sometimes, the basis form does not equal the previous basis. As a result, the Circle starting and ending point Differ. This is what I don't want because this would create a TWIST when I join all points.




When you move from one tube segment to the next, you can apply an appropriate minimal 3D rotation to the circle basis in order to keep it pointing in the right direction without any twisting. If the previous segment direction vector is $U$ and the new one is $V$, then you want a rotation by angle $\cos^{-1}(U\cdot V)$ around axis $U\times V$. This also works for determining the initial rotation.
With the scipy Rotation module, it should be something like this: