7
$\begingroup$

I have two objects that I want to connect using a curved arrow whose thickness should be variable. The following picture illustrates my intention:

enter image description here

The grey boxes have to be imagined as cylinders. I assume that I would have to create some curve that is attached to the two objects and extrude the curve accordingly, but I can not figure out how to achieve this.

Thank you very much for your help!

$\endgroup$
  • 3
    $\begingroup$ I thought the intention was to have a scriptable solution? $\endgroup$ – zeffii Aug 9 '15 at 17:03
8
$\begingroup$

I think you're looking for a scripted solution which allows you to define two points and the direction of the Curve. Remember; the thickness and colour of such Curves can be animated at a later stage, and the Arrow or 'direction indicator' of the Curve is another matter.

The concept is each box you want to connect has an edge which will be a terminal for the Curve.

enter image description here

Exactly how you determine the length of these virtual guide lines is up to you, it could be some factor of the relative distance between the two terminals on the boxes -- really that's down to taste.

The script would create something like this, if you give it two terminal coordinates, and a direction for each.

enter image description here

If you look at the source of the TubeTool addon you'd get a fair idea of how to script it, but the core of the code is this snippet.

import bpy
from mathutils import Vector

def add_curve(medians, normals, curvename, amp=2):
    curvedata = bpy.data.curves.new(name=curvename, type='CURVE')
    curvedata.dimensions = '3D'

    obj = bpy.data.objects.new('Obj'+curvename, curvedata)
    obj.location = (0,0,0) #object origin
    bpy.context.scene.objects.link(obj)

    polyline = curvedata.splines.new('BEZIER')
    polyline.bezier_points.add(1)
    #   polyline.use_smooth = False

    # obj.data.fill_mode = 'FULL'
    # obj.data.bevel_depth = 0.1
    # obj.data.bevel_resolution = 4
    point = polyline.bezier_points[0]
    co = medians[0]

    point.co = co
    point.handle_left = co - (normals[0]*amp)
    point.handle_right = co + (normals[0]*amp)

    point = polyline.bezier_points[1]
    co = medians[1]
    point.co = co
    point.handle_right = co - (normals[1]*amp)
    point.handle_left = co + (normals[1]*amp)

    polyline.order_u = len(polyline.points)-1  

medians = [Vector((-2, 0, 0)), Vector((2,3,0))]
normals = [Vector((0, 2, 0)), Vector(( -2, 0, 0))]  
add_curve(medians, normals, "curvename", amp=1.2)  

And that gives (with the extras commented out, like thickness) this:

enter image description here

  • medians: Absolute coordinates, Vectors. (Location)
  • normals: Relative to the median they're associated with. (Direction, and Distance away from Location)
  • amp: 'push factor' for the control point. The amp parameter pushes the control points along the normals, effectively scaling the control points to be further away or closer to the terminal)
$\endgroup$
  • $\begingroup$ Thank you for your answer, I like this idea really much! I thought that I should first create all arrows and later script only the change in thickness, but your solution is much more elegant since I need quite many arrows. I experimented a bit with it already, and it works good! $\endgroup$ – mindm49907 Aug 10 '15 at 12:36
  • $\begingroup$ hopefully the additional link at the top of the post gives enough information to also script the arrow heads. I think once you make the one single function to add the arrow head + spline and keep track of the object names, you'll be able to easily move on to the materials and animation $\endgroup$ – zeffii Aug 10 '15 at 13:22
  • $\begingroup$ I actually think about using the tubes alone without the arrow heads since I feel it looks better this way, and the direction of the flow does never change so should be clear in either way. I can still add them if I get the feedback that it would be mandatory. $\endgroup$ – mindm49907 Aug 10 '15 at 13:47
6
$\begingroup$

I would do this with curves.

Create a curve that is going to be the tip of the arrow. In edit mode align the control points on the Y axis by selecting them and pressing S Y 0

exit edit mode and rotate the curve 90 degrees in the X axis. (R X 90)

Go back to edit mode and shape the tip of the arrow.

enter image description here

Create a new curve (repeat the steps to align it on the Y axis and rotate in X) and add a hook to the control point next to the tip. This will create an Empty that controls that end of the curve.

enter image description here

Add a hook to the other end of the curve. (sorry no picture)

Select the curve that will serve as the tip, Shift Select the empty and press Ctrl C to parent it the curve to the empty. Now the tip and the curve will move together.

enter image description here

Now give the curves some extrusion and bevel to make them renderable.

enter image description here

enter image description here

Now by moving and rotating the empties that control the curves you can have the arrow do whatever you want.

enter image description here

If you parent the empties to the objects you want to connect then moving the objects will make the arrow follow. See this answer

$\endgroup$
  • $\begingroup$ Thank you really much for your answer! But in my case, I think the scripted solution is more applicable. $\endgroup$ – mindm49907 Aug 10 '15 at 12:36
  • $\begingroup$ @mindm49907 no problem. Next time please make that explicit on the question :) $\endgroup$ – cegaton Aug 10 '15 at 15:35
  • $\begingroup$ I would have, but I did not know before since I'm completely new to Blender and am not aware about the different possibilities it brings, sorry about that! But I'm sure your detailed answer will help other people as well! Thank you for your efforts! $\endgroup$ – mindm49907 Aug 11 '15 at 6:33
4
$\begingroup$

There is an addon you can get, it's called "Tube Tool", this will make what you want for you very easy and give you much control over it. More information here: http://blenderaddonlist.blogspot.com/2015/05/addon-tube-tool.html?m=1

enter image description here

$\endgroup$
  • 1
    $\begingroup$ Thank you really much for your answer! But in my case, I think the scripted solution is more applicable. $\endgroup$ – mindm49907 Aug 10 '15 at 12:37
3
$\begingroup$

You simply can model those cubes and arrow.

  1. Creating base - rectangles. I switched to Top View by Numpad 7. Added 2 cubes, scaled them, selected the face pointing to me and used inset tool by I. I scaled new face so it to be roughly the same rectangle:

    curved-arrow_0_1

    I flipped normals of the boundary faces so them to create a knid of border (may be not the best way, depending on your scene you may rather use materials). I did the same with second cube.

  2. I added a curve and positioned it, extruded new points and rotated them to get that shaped arrow:

    curved_arrow_2

  3. I duplicated that curve, moved it by X and Y so it to be located roughly the same as the first. I made actual arrow and made curve cyclic.

    curved_arrow_3

  4. After that I switched it to 2D curve and made Fill option to Front.The result:

    enter image description here

There are a lot of ways to do that, it depends on animation needs. If you want to animate that curve's thickness then I think you might want to convert it to mesh and use Shape Keys.

$\endgroup$
  • $\begingroup$ Thank you really much for your answer! But in my case, I think the scripted solution is more applicable. $\endgroup$ – mindm49907 Aug 10 '15 at 12:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.