Align faces script

Very beta, I started working on that yesterday night after midnight.
Surpisingly enough duh to the time, it works always for the location, and sometimes for rotation.

I’ll post the code if anyone wants to have a look, but don’t expect much from the code (criptic and uncommented, at least there’s some error handling).


import Blender
from vecf import *

print "
START
"

objL = Blender.Object.GetSelected()

if len(objL) < 2: raise Exception("Must select at least two object")

for obj in objL:
	if obj.data.block_type != "NMesh": raise Exception("Must select only Meshes")

for obj in objL:
	if len(obj.data.getSelectedFaces()) != 1: raise Exception("Must have only one face selected")

ObjVecL = []
for obj in objL:
	vec = [0,0,0]
	nor = [0,0,0]
	tot = 0
	for vert in obj.data.getSelectedFaces()[0]:
		vec = vecadd(vec, vert.co)
		nor = vecadd(nor, vert.no)
		tot += 1
	
	vec = vecmul(vec,1.0/tot)
	nor = vecmul(nor,1.0/tot)
	vnorm(nor)

	ObjVecL.append([obj, vec, mulmatvec4x3(obj.mat,vec),nor, mulmatvec3x3(obj.mat,nor)])

target = ObjVecL.pop(0)

for ObjVec in ObjVecL:
	obj = ObjVec[0]
	vec = ObjVec[1:3]
	nor = ObjVec[3:]
	
	finalloc = vecadd(vecadd(vec[1],proj(vecsub(target[2],vec[1]),target[4])), vecmul(target[4],veclen(vec[0])))
	obj.LocX = finalloc[0]
	obj.LocY = finalloc[1]
	obj.LocZ = finalloc[2]

	tmpvec = vecnorm(crossp(target[4],nor[1]))
	mat = [target[4],crossp(target[4],tmpvec),tmpvec]
	mat1 = transp3x3(mat)
	matrot = makeRotMtx("Z",acos(vdot(nor[1],target[4])) + pi)

	matini = obj.mat

	matini = mulmat(matini,mat,3)
	matini = mulmat(matini,matrot,3)
	matini = mulmat(matini,mat1,3)
	
	rot = mat2euler_rot(matini)
	obj.RotX = rot[0]
	obj.RotY = rot[1]
	obj.RotZ = rot[2]


Blender.Redraw()

using the vecf module, as always: http://clubinfo.bdeb.qc.ca/~theeth/vecf.py

there’s surely something wrong with the matricial operations, but I was too tired to fix it. Probably tomorrow or next week.

Martin

well, it seems that I’m stupid and used a transpose function instead of inverse :confused:

New version coming soon to a forum near you :wink:

Martin


import Blender
from vecf import *

def invert(mat):
	scale= mat[0][0]*mat[0][0] + mat[1][0]*mat[1][0] + mat[2][0]*mat[2][0]
	if(scale==0.0): return

	inverse = [[0,0,0],[0,0,0],[0,0,0]]
		
	scale= 1.0/scale
	
	inverse[0][0]= scale*mat[0][0]
	inverse[1][0]= scale*mat[0][1]
	inverse[2][0]= scale*mat[0][2]
	inverse[0][1]= scale*mat[1][0]
	inverse[1][1]= scale*mat[1][1]
	inverse[2][1]= scale*mat[1][2]
	inverse[0][2]= scale*mat[2][0]
	inverse[1][2]= scale*mat[2][1]
	inverse[2][2]= scale*mat[2][2]


	return inverse	


print "
START
"

objL = Blender.Object.GetSelected()

if len(objL) < 2: raise Exception("Must select at least two object")

for obj in objL:
	if obj.data.block_type != "NMesh": raise Exception("Must select only Meshes")

for obj in objL:
	if len(obj.data.getSelectedFaces()) != 1: raise Exception("Must have only one face selected")

ObjVecL = []
for obj in objL:
	vec = [0,0,0]
	nor = [0,0,0]
	tot = 0
	for vert in obj.data.getSelectedFaces()[0]:
		vec = vecadd(vec, vert.co)
		nor = vecadd(nor, vert.no)
		tot += 1
	
	vec = vecmul(vec,1.0/tot)
	nor = vecmul(nor,1.0/tot)
	vnorm(nor)

	ObjVecL.append([obj, vec, mulmatvec4x3(obj.mat,vec),nor, mulmatvec3x3(obj.mat,nor)])

target = ObjVecL.pop(0)

for ObjVec in ObjVecL:
	obj = ObjVec[0]
	vec = ObjVec[1:3]
	nor = ObjVec[3:]
	
	finalloc = vecadd(vecadd(vec[1],proj(vecsub(target[2],vec[1]),target[4])), vecmul(target[4],veclen(vec[0])))
	obj.LocX = finalloc[0]
	obj.LocY = finalloc[1]
	obj.LocZ = finalloc[2]

	tmpvec = vecnorm(crossp(target[4],nor[1]))
	mat = [target[4],crossp(target[4],tmpvec),tmpvec]
	mat1 = invert(mat)
	matrot = makeRotMtx("Z",acos(round(vdot(nor[1],target[4]),5)) + pi)

	matini = [obj.mat[0][:3],obj.mat[1][:3],obj.mat[2][:3]]

	print mat
	print matini

	matini = mulmat(matini,mat,3)
	matini = mulmat(matini,matrot,3)
	matini = mulmat(matini,mat1,3)
	
	rot = mat2euler_rot(matini)
	obj.RotX = rot[0]
	obj.RotY = rot[1]
	obj.RotZ = rot[2]


Blender.Window.QRedrawAll()

should work perfectly well now.

Martin

k, what’s this for? hehe.

yah, I guess I should have explained that first, right?!

It takes multiple objects and alligns them with the active object. It aligns based on the selected face (one face per object, in Face Select mode).

Good for placing objects on one another at odd angles.

Martin

Nice one, theeth. This is exactly what we need to align out objects. Many thanks sir. One question, how do I select the alignment face ? I get the exception ‘Must have only one face selected’ - I’ve tried selecting the vertices of the face I want in ‘edit’ mode and also selecting a face in face-select mode.

ah, I’ve nearly got it. I misunderstood how to set it up. One has to select faces of all objects in face-select mode, then select all the objects one wants aligned. Lovely method, by the way. however it doesn’t operate as expected - does it take object rotations, translations etc into account ?

It aligns the faces of the selected objects on the nearest point on the plane defined by the face of the active object. That way, you can align more than one object at once and they will not stack on top of one another.

Martin

It works like a beauty in 2d - if I add a few cubes in top view, select a face on each, select them all, it aligns them all with the selected face of the active object - perfect. But if I add cubes at various angles throughout space and do the same it doesn’t appear to align.
Still extremely usefull already though.

Is this like Osnap in AutoCad ?

don’t know

Martin

I was just wondering if I was using the script correctly, or if I am just trying to do something for which it was not intended.

  1. Default scene (Blender 2.27), Add a mesh cone (5 vertices) Tab out into object mode, enter face select mode [f], and select the face on the right side. Exit face select mode [f].

  2. Move the 3D cursor a bit to the right, and add a mesh cube. Go to object and face select mode. Select the left side face of the cube. Exit face select mode and shift select the cone.

  3. Run the script.

I was expecting the cube to be aligned so that it’s selected face was the same orientation as the cone’s selected face, which wasn’t what happened.

Did I make a mistake somewhere ? I thought that I could use this script to do something like align a handle object to a face on a pan or something similiar; is that possible?

Thanks for any help.

uhm… I thought I had that bug fixed, but it seems like it isn’t.
There didn’t seem to be much intousiasm for the script, so I kinda let it be.
I’ll try and fix that and probably add a GUI and some options next week.

Martin

It’s one of those things people don’t know they need until they use it. I think the way you solved this problem should become a standard feature of Blender. currently it definitely works in one plane but not with out-of-plane rotations.

in complement, there’s my script Realign axis script to align the axis only.

the adress in the script effort post.