-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9a658d2
Showing
1 changed file
with
85 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import bpy | ||
import math | ||
from mathutils import Vector | ||
from functools import reduce | ||
|
||
bl_info = { | ||
"name": "Align by faces", | ||
"author": "Tom Rethaller", | ||
"version": (0,2,2), | ||
"blender": (2, 65, 0), | ||
"description": "Align two objects by their active faces", | ||
"warning": "", | ||
"category": "3D View"} | ||
|
||
def get_ortho(a,b,c): | ||
if c != 0.0 and -a != b: | ||
return [-b-c, a,a] | ||
else: | ||
return [c,c,-a-b] | ||
|
||
def clamp(v,min,max): | ||
if v < min: | ||
return min | ||
if v > max: | ||
return max | ||
return v | ||
|
||
def align_faces(from_obj, to_obj): | ||
fpolys = from_obj.data.polygons | ||
tpolys = to_obj.data.polygons | ||
fpoly = fpolys[fpolys.active] | ||
tpoly = tpolys[tpolys.active] | ||
|
||
to_obj.rotation_mode = 'QUATERNION' | ||
tnorm = to_obj.rotation_quaternion * tpoly.normal | ||
|
||
fnorm = fpoly.normal | ||
axis = fnorm.cross(tnorm) | ||
dot = fnorm.normalized().dot(tnorm.normalized()) | ||
dot = clamp(dot, -1.0, 1.0) | ||
|
||
# Parallel faces need a new rotation vactor | ||
if axis.length < 1.0e-8: | ||
axis = Vector(get_ortho(fnorm.x, fnorm.y, fnorm.z)) | ||
|
||
from_obj.rotation_mode = 'AXIS_ANGLE' | ||
from_obj.rotation_axis_angle = [math.acos(dot) + math.pi, axis[0],axis[1],axis[2]] | ||
bpy.context.scene.update() | ||
|
||
# Move from_obj so that faces match | ||
fvertices = [from_obj.data.vertices[i].co for i in fpoly.vertices] | ||
tvertices = [to_obj.data.vertices[i].co for i in tpoly.vertices] | ||
|
||
fbary = from_obj.matrix_world * (reduce(Vector.__add__, fvertices) / len(fvertices)) | ||
tbary = to_obj.matrix_world * (reduce(Vector.__add__, tvertices) / len(tvertices)) | ||
|
||
from_obj.location = tbary - (fbary - from_obj.location) | ||
|
||
|
||
class OBJECT_OT_AlignByFaces(bpy.types.Operator): | ||
bl_label = "Align by faces" | ||
bl_description= "Align two objects by their active faces" | ||
bl_idname = "object.align_by_faces" | ||
|
||
@classmethod | ||
def poll(cls, context): | ||
if not len(context.selected_objects) is 2: | ||
return False | ||
for obj in context.selected_objects: | ||
if obj.type != 'MESH': | ||
return False | ||
return True | ||
|
||
def execute(self, context): | ||
objs_to_move = [o for o in context.selected_objects if o != context.active_object] | ||
for o in objs_to_move: | ||
align_faces(o, context.active_object) | ||
return {'FINISHED'} | ||
|
||
def register(): | ||
bpy.utils.register_module(__name__) | ||
|
||
def unregister(): | ||
bpy.utils.unregister_module(__name__) | ||
|