Some help from you blender wizards is needed

I have a task to create dials for nearly thousand clock designs with different shapes, something like this (the script generate mesh from .svg and places clock arrows by the coordinates in the middle) enter image description here

By creating 4 paths and then clamping dial objects to them I am able to move objects on coret axes but moving them by hand will take agesenter image description here

Guess I am looking for way to push dial objects inwards and stop them right before they touch the mesh. Remember that every object will have a different shape, so i cant use fixed numbers, I was thinking to use force field physics to push them inward, by magnetic force or something like that

Do you guys have some solutions or suggestions will appreciate any help, thank you?


3 Answers 3



Finally have managed to solve the problem by using Rigid Body Constraints and wind force physics to push dial objects inwards

enter image description here

  • 3
    $\begingroup$ Interesting solution, though there's a problem with № 4 there... $\endgroup$ Jul 9, 2021 at 13:33
  • $\begingroup$ Cool solution for an interesting project. $\endgroup$
    – PJM Design
    Jul 9, 2021 at 14:51
  • 5
    $\begingroup$ @MarkusvonBroady don't think the № 4 liked where it was headed. $\endgroup$
    – batFINGER
    Jul 9, 2021 at 21:27

Thought about using Shrinkwrap + instancing, but that can make the arrows squeeze through tiny holes and overlap with the mesh. So I used lemon's answer here:

Python in Blender 2.8 - testing if two objects overlap in the XY Plane?

import bpy
from mathutils.bvhtree import BVHTree

center_object = bpy.data.objects["S"]
initial_step = 0.01  # 1 cm initial step size
min_step = 0.0001  # accuracy
step_limit = 1000  # just in case to not hang, though you can always press CTRL+C in system console

def main():
    for o in bpy.data.objects:
        if o.name.startswith("Cone"):

def adjust_cone(cone):
    if not any(cone.location):
        print(f"{cone.name} is in the center")
        # can't figure direction
    while is_colliding(cone):
        # move away from center
        cone.location += cone.location.normalized()*.1
    current_step = initial_step
    for _ in range(step_limit):
        prev_loc = cone.location
        cone.location -= cone.location.normalized()*current_step
        if is_colliding(cone):
            cone.location = prev_loc
            current_step /= 2
            if current_step < min_step:

def is_colliding(cone):
    # Get the objects
    obj1 = cone
    obj2 = center_object
    # Get their world matrix
    mat1 = obj1.matrix_world
    mat2 = obj2.matrix_world
    # Get the geometry in world coordinates
    vert1 = [mat1 @ v.co for v in obj1.data.vertices] 
    poly1 = [p.vertices for p in obj1.data.polygons]
    vert2 = [mat2 @ v.co for v in obj2.data.vertices] 
    poly2 = [p.vertices for p in obj2.data.polygons]
    # Create the BVH trees
    bvh1 = BVHTree.FromPolygons(vert1, poly1)
    bvh2 = BVHTree.FromPolygons(vert2, poly2)
    # Test if overlap
    return bool(bvh1.overlap(bvh2))


The script is blatanly inefficient, but since it's a learning site I wanted to make the logic simple. Optimizing doesn't take a whole lot of effort, though: instead of moving the arrow object and updating the scene, just modify the coordinates of the vertices passed to the BVHTree as well as have a variable keeping the total tranlation, apply that to the object once in the end.


You can use object constraints for that. The "limit distance" object constraint does exactly this. It limits/sets the distance to outside/surface of the "target" object - which would be the clock in your case. With "distance" you can determine the...you guessed it - distance ;)

Like this:

enter image description here

  • $\begingroup$ Can you provide a blend file so I can check it out? $\endgroup$
    – Chris
    Jul 9, 2021 at 7:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .