# Using force field to move clamped objects (difficult task)

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)

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 ages

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?

UPD

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

• Interesting solution, though there's a problem with № 4 there... Jul 9, 2021 at 13:33
• Cool solution for an interesting project. Jul 9, 2021 at 14:51
• @MarkusvonBroady don't think the № 4 liked where it was headed. 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"):

if not any(cone.location):
print(f"{cone.name} is in the center")
# can't figure direction
return

while is_colliding(cone):
# move away from center
cone.location += cone.location.normalized()*.1
bpy.context.view_layer.update()

current_step = initial_step
for _ in range(step_limit):
prev_loc = cone.location
cone.location -= cone.location.normalized()*current_step
bpy.context.view_layer.update()
if is_colliding(cone):
cone.location = prev_loc
bpy.context.view_layer.update()
current_step /= 2
if current_step < min_step:
break

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))

main()


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:

• Can you provide a blend file so I can check it out? Jul 9, 2021 at 7:31