[Bf-committers] An Offering of Over 70 New Object Level Functions

Robert Tiess bf-committers@blender.org
Thu, 04 Mar 2004 01:19:13 -0500


This is a multi-part message in MIME format.
--------------030207090104060305040607
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Attached: spacecpatch.txt, alignmenucode.txt

After three weeks of working on this, I am ready to offer it up
to the Masters of the Blender Universe:

16 new main functions with more options yet for a combined total
of over 70 new functions quickly accessible from one simple menu.

Some of you from Elysiun might recall my object alignment Python
script:  http://www.elysiun.com/forum/viewtopic.php?t=18443
This was enthusiastically received by the Blender community and
seemed to reassure me this was something not only I but other
Blender users could benefit from having.

I wanted to advance ideas from that script and offer more
powerful capabilities yet within Blender, something that also
incorporated Blender's axial constraints and transformations,
for example.  The goal throughout this effort was to provide a
new set of capable functions at the object level to complement
Blender's current powerful array of mesh editing options.

The enclosed code establishes a new Align/Alter Object menu
by pressing CTRL SHIFT L.  A small patch for space.c is
included to make this possible.  A screenshot of the main menu
appears at
http://webusers.warwick.net/~u1019306/myblenderimages/alignmenuscreenshot.jpg 


Everything is neatly contained in one function, the code for
which can simply be added at the end of editobject.c with a
simple function prototype perhaps added at the top of the file.
I have included the function in a separate text file to eliminate
any possible cvs diff mixups concerning other areas in that
file I had been working on/experimenting with at my end.

I use Blender constantly, and I find that the ability to align
and alter multiple objects at once based on criteria such as
size, location, and rotation open new modeling possibilities
while increasing a modeller's productivity potential in having
increased control and flexibility over elements in a scene,
be it for a static render or for animation, where multiple
object maintenance and modification can add numerous
modeling hours to such a project.

Alignments and alterations occur according to the last
object selected -- the Active Object (OBACT as it's
commonly referred to in the source).  These functions
work best with meshes I find, but they have been used
on other objects (e.g. lamps, NURBS, metaballs).

Almost every function here offers axial contraints based
on the global axis and/or the local object axis.  Some
also make use of existing transformation functions as
well, allowing for interactive, constraint based alterations
of objects, including alterations around the median point,
3d cursor, and individual object centers if any of those
rotation types were selected.

There are some particularly interesting functions here
for different modeling applications.  For example, there
are the Move Closer and Further functions that move
selected objects nearer or further away from the active
object - either along the LocX, Y, Z or all axes (LocXYZ).
There's also the Line Up/Stack Objects function that
allows you to stack/line up in any axial direction selected
objects before/behind/above/below/right/left of the
active object.   This function, like many others here, has
an additional intereactive element as well -- in this case
a Distance Factor slider.

Modeling scenarios that might benefit from increased
randomness options could benefit from related functions
in the Align/Alter Object menu.  One user at Elysiun
indicated numerous hours were spent creating an
asteroid field.  With the upcoming Fractal Noise function
(submitted earlier) and the new Randomize Size, Rotation,
and Location functions proposed here, such a thing could
have been easily established in minutes instead of hours.

There are many other potential uses for each function
offered here, but in any event, I am grateful to have
my code considered.  I thank you for this incredible
opportunity to contribute to a community that has been
a true source of joy and excitement since I discovered
Blender last year.

Robert

(RobertT on Elysiun.com)
rjtiess@warwick.net





--------------030207090104060305040607
Content-Type: text/plain;
 name="alignmenucode.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="alignmenucode.txt"

MODIFICATIONS TO editobject.c:
======================================================

1 of 2:  Add at top of editobject.c (after void mirrormenu(void);):

	void align_objects_menu(void);

======================================================
2 of 2: Function appended to the end of editobject.c:


void align_objects_menu(void){
	Base *base;
	Object *ob, *theActiveObject;
	Mesh *me;
	MVert *mvert;
	float min[3], max[3], amin[3], amax[3], distanceDifference[3];
	int a, lineupDirection=1, includeActiveObject=0;
	short randFactor = 1, randDiv = 2;
	short alignObjectMenu, alignMode, userValueSelected, userAmountSpecified;

	theActiveObject = OBACT;
	if (theActiveObject == 0) return;
	if (G.obedit) return;

	if (theActiveObject->type == OB_MESH) {
		INIT_MINMAX(amin, amax);
		me = get_mesh(theActiveObject);
		mvert = me->mvert;
		for(a=0; a<me->totvert; a++, mvert++) {
			DO_MINMAX(mvert->co, amin, amax);
		}
	}
	if (theActiveObject->type == OB_LAMP) {
		amin[0] = amin[1] = amin[2] = 1;
		amax[0] = amax[1] = amax[2] = 1;
	}
	else {
		amin[0] = amin[1] = amin[2] = 1;
		amax[0] = amax[1] = amax[2] = 5;
	}

	alignObjectMenu = pupmenu("Align/Alter Object(s) %t|Align Location of Object(s) to Active Object %x1|Align Rotation of Object(s)  to Active Object %x2|Align Size of Object(s) to Active Object %x3|%l|Randomize Location of Object(s) %x4|Randomize Size of Object(s) %x5|Randomize Rotation of Object(s) %x6|%l|Move Object(s) to Grid Center %x7|%l|Reset Size of Object(s) to 1 %x8|Reduce Size of Object(s) %x9|Enlarge Object(s) %x10|%l|Freely Resize Object(s) %x11|Rotate Object(s) along... %x12|Reset Rotation of Object(s) %x13|%l|Line Up/Stack Objects by Active Object %x14|Move Object(s) Closer to Active Object %x15|Move Object(s) Further from Active Object %x16|");
	if (alignObjectMenu == -1) return;

	switch(alignObjectMenu) {

		case 1:

			alignMode = pupmenu("Align Location of Object(s) to Active Object %t|By LocX %x1|By LocY %x2|By LocZ %x3|By LocXYZ %x4|");
			if (alignMode == -1) return;
			break;

		case 2:

			alignMode = pupmenu("Align Rotation of Object(s) to Active Object%t|By RotX %x9|By RotY %x10|By RotZ %x11|By RotXYZ %x12|");
			if (alignMode == -1) return;
			break;

		case 3:

			alignMode = pupmenu("Align Size of Object(s) to Active Object%t|SizeX %x5|SizeY %x6|SizeZ %x7|SizeXYZ %x8|");
			if (alignMode == -1) return;
			break;

		case 4:

			alignMode = pupmenu("Randomize Location of Object(s)%t|LocX %x13|LocY %x14|LocZ %x15|LocXYZ %x16|");
			if (alignMode == -1) return;
			includeActiveObject = 1;
			break;

		case 5:


			alignMode = pupmenu("Randomize Size of Object(s)%t|SizeX %x17|SizeY %x18|SizeZ %x19|SizeXYZ %x20|");
			if (alignMode == -1) return;
			includeActiveObject = 1;
			break;

		case 6:

			alignMode = pupmenu("Randomize Rotation of Object(s)%t|RotX %x21|RotY %x22|RotZ %x23|RotXYZ %x24|");
			includeActiveObject = 1;
			break;

		case 7:

			alignMode = 25; /* Set LocXYZ=0 */  
			userValueSelected = pupmenu("Move Object(s) to Grid Center %t|LocX %x1|LocY %x2|LocZ %x3|LocXYZ %x4|");
			if (userValueSelected == -1) return;
			includeActiveObject = 1;
			break;

		case 8:

			alignMode = 26; /* Set SizeXYZ=1 */  
			userValueSelected = pupmenu("Reset Size of Object(s) to 1%t|SizeX=1 %x1|SizeY=1 %x2|SizeZ=1 %x3|SizeXYZ=1 %x4|");
			if (userValueSelected == -1) return;
			includeActiveObject = 1;
			break;

		case 9:

			alignMode = 27; /* Reduce Size X/Y/Z */  
			userValueSelected = pupmenu("Reduce Size of Object(s)%t|SizeX %x1|SizeY %x2|SizeZ %x3|SizeXYZ %x4|Free Resize SizeX %x5|Free Resize SizeY %x6|Free Resize SizeZ %x7|Free Resize SizeXYZ %x8|");
			if (userValueSelected == -1) return;
			userAmountSpecified = 2;
			if (button(&userAmountSpecified,2,10,"Percent ")==0) return;
			includeActiveObject = 1;
			break;

		case 10:

			alignMode = 28; /* Enlarge Size X/Y/Z */  
			userValueSelected = pupmenu("Enlarge Object(s)%t|SizeX %x1|SizeY %x2|SizeZ %x3|SizeXYZ %x4|");
			if (userValueSelected == -1) return;
			userAmountSpecified = 2;
			if (button(&userAmountSpecified,2,10,"Percent ")==0) return;
			includeActiveObject = 1;
			break;

		case 11:

			alignMode = 29; /* Freely Resize Size X/Y/Z */  
			userValueSelected = pupmenu("Freely Resize Object(s)%t|SizeX %x1|SizeY %x2|SizeZ %x3|Local SizeX %x4|Local SizeY %x5|Local SizeZ %x6|SizeXYZ %x7|");
			if (userValueSelected == -1) return;
			includeActiveObject = 1;
			break;

		case 12:

			alignMode = 30; /* Rotate Object(s)... */  
			userValueSelected = pupmenu("Rotate Object(s)... %t|Along RotX %x1|Along RotY %x2|Along RotZ %x3|Along Local RotX %x4|Along Local RotX %x5|Along Local RotY %x6|");
			if (userValueSelected == -1) return;
			includeActiveObject = 1;
			break;

		case 13:

			alignMode = 31; /* Reset Rotation of Selected Object(s)*/  
			userValueSelected = pupmenu("Reset Rotation of Object(s)%t|Reset RotX to 0 %x1|Reset RotY to 0 %x2|Reset RotZ to 0 %x3|Reset RotXYZ to 0 %x4|");
			if (userValueSelected == -1) return;
			includeActiveObject = 1;
			break;

		case 14:

			alignMode = 32; /* Line Up / Stack Objects */  
			userValueSelected = pupmenu("Line Up/Stack Objects by Active Object's %t|LocX %x1|-LocX %x2|LocY %x3|-LocY %x4|LocZ %x5|-LocZ %x6|LocXYZ %x7|");
			if (userValueSelected == -1) return;
			userAmountSpecified = 1;
			if (button(&userAmountSpecified,1,10,"Distance ")==0) return;
			if (userValueSelected == 2 || userValueSelected == 4 || userValueSelected == 6) {  
				lineupDirection = -1;
			}
			break;

		case 15:

			alignMode = 33 ; /* Move Objects Closer to Active Object */
			userValueSelected = pupmenu("Move Object(s) Closer to Active Object%t|By LocX %x1|By LocY %x2|By LocZ %x3|By LocXYZ %x4|");
			if (userValueSelected == -1) return;
			userAmountSpecified = 1;
			if (button(&userAmountSpecified,1,10,"Closer ")==0) return;
			break;

		case 16:

			alignMode = 34 ; /* Move Objects Further away from Active Object */
			userValueSelected = pupmenu("Move Object(s) Further from Active Object%t|By LocX %x1|By LocY %x2|By LocZ %x3|By LocXYZ %x4|");
			if (userValueSelected == -1) return;
			userAmountSpecified = 1;
			if (button(&userAmountSpecified,1,10,"Further ")==0) return;
			break;

	}

	if (alignMode>12 && alignMode<25) {
		if (button(&randFactor,1,50,"Amount ")==0) {
			return;
		}
		randFactor /= randDiv;
		BLI_srand(BLI_rand());
	}

	base = FIRSTBASE;
	while(base) {
		if TESTBASE(base) {
			if (base->flag & SELECT && (base!=BASACT || includeActiveObject==1)) {
				ob = base->object;

				switch(alignMode) {
					case 1:
						/* Align LocX */
						ob->loc[0] = theActiveObject->loc[0];
						break;

					case 2:
						/* Align LocY */
						ob->loc[1] = theActiveObject->loc[1];
						break;

					case 3:
						/* Align LocZ */
						ob->loc[2] = theActiveObject->loc[2];
						break;

					case 4:
						/* Align LocXYZ */
						ob->loc[0] = theActiveObject->loc[0];
						ob->loc[1] = theActiveObject->loc[1];
						ob->loc[2] = theActiveObject->loc[2];
						break;

					case 5:
						/* Align SizeX */
						ob->size[0] = theActiveObject->size[0];
						break;

					case 6:
						/* Align SizeY */
						ob->size[1] = theActiveObject->size[1];
						break;

					case 7:
						/* Align SizeZ */
						ob->size[2] = theActiveObject->size[2];
						break;

					case 8:
						/* Align SizeXYZ */
						ob->size[0] = theActiveObject->size[0];
						ob->size[1] = theActiveObject->size[1];
						ob->size[2] = theActiveObject->size[2];
						break;

					case 9:
						/* Align RotX */
						ob->rot[0] = theActiveObject->rot[0];
						break;

					case 10:
						/* Align RotY */
						ob->rot[1] = theActiveObject->rot[1];
						break;

					case 11:
						/* Align RotZ */
						ob->rot[2] = theActiveObject->rot[2];
						break;

					case 12:
						/* Align RotXYZ */
						ob->rot[0] = theActiveObject->rot[0];
						ob->rot[1] = theActiveObject->rot[1];
						ob->rot[2] = theActiveObject->rot[2];
						break;

					case 13:
						/* Rand LocX */
						ob->loc[0] = BLI_frand()*randFactor;
						if (BLI_frand()*10<5) ob->loc[0] *= 1;
						break;

					case 14:
						/* Rand LocY */
						ob->loc[1] = BLI_frand()*randFactor;
						if (BLI_frand()*10<5) ob->loc[0] *= 1;
						break;

					case 15:
						/* Rand LocZ */
						ob->loc[2] = BLI_frand()*randFactor;
						if (BLI_frand()*10<5) ob->loc[0] *= 1;
						break;

					case 16:
						/* Rand LocXYZ */
						ob->loc[0] = BLI_frand()*randFactor;
						ob->loc[1] = BLI_frand()*randFactor;
						ob->loc[2] = BLI_frand()*randFactor;
						if (BLI_frand()*10<5) ob->loc[0] *= 1;
						if (BLI_frand()*10<5) ob->loc[1] *= 1;
						if (BLI_frand()*10<5) ob->loc[2] *= 1;
						break;

					case 17:
						/* Rand SizeX */
						ob->size[0] = .2+BLI_frand()*randFactor;
						break;

					case 18:
						/* Rand SizeY */
						ob->size[1] = .2+BLI_frand()*randFactor;
						break;

					case	19:
						/* Rand SizeZ */
						ob->size[2] = .2+BLI_frand()*randFactor;
						break;

					case 20:
						/* Rand SizeXYZ */
						ob->size[0] = .2+BLI_frand()*randFactor;
						ob->size[1] = .2+BLI_frand()*randFactor;
						ob->size[2] = .2+BLI_frand()*randFactor;
						break;

					case 21:
						/* Rand RotX */
						ob->rot[0] = BLI_frand()*randFactor;
						break;

					case 22:
						/* Rand RotY */
						ob->rot[1] = BLI_frand()*randFactor;
						break;

					case 23:
						/* Rand RotZ */
						ob->rot[2] = BLI_frand()*randFactor;
						break;

					case 24:
						/* Rand RotXYZ */
						ob->rot[0] = BLI_frand()*randFactor;
						ob->rot[1] = BLI_frand()*randFactor;
						ob->rot[2] = BLI_frand()*randFactor;
						break;

					case 25:
						/* Set LocXYZ=0 */

						switch (userValueSelected) {

							case 1:
								ob->loc[0] = 0;
								break;

							case 2:
								ob->loc[1] = 0;
								break;

							case 3:
								ob->loc[2] = 0;
								break;

							case 4:
								ob->loc[0] = 0;
								ob->loc[1] = 0;
								ob->loc[2] = 0;
								break;
						}
						break;

					case 26:
						/* Reset Object Size X/Y/Z/XYZ */

						switch (userValueSelected) {

							case 1:
								ob->size[0] = 1;
								break;

							case 2:
								ob->size[1] = 1;
								break;

							case 3:
								ob->size[2] = 1;
								break;

							case 4:
								ob->size[0] = 1;
								ob->size[1] = 1;
								ob->size[2] = 1;
								break;
						}
						break;

					case 27:
						/* Reduce SizeXYZ by x% */

						switch (userValueSelected) {

							case 1:
								ob->size[0] /= userAmountSpecified;
								break;

							case 2:
								ob->size[1] /= userAmountSpecified;
								break;

							case 3:
								ob->size[2] /= userAmountSpecified;
								break;

							case 4:
								ob->size[0] /= userAmountSpecified;
								ob->size[1] /= userAmountSpecified;
								ob->size[2] /= userAmountSpecified;
								break;
						}
						break;

					case 28:
						/* Enlarge SizeXYZ by x% */

						switch (userValueSelected) {

							case 1:
								ob->size[0] *= userAmountSpecified;
								break;

							case 2:
								ob->size[1] *= userAmountSpecified;
								break;

							case 3:
								ob->size[2] *= userAmountSpecified;
								break;

							case 4:
								ob->size[0] *= userAmountSpecified;
								ob->size[1] *= userAmountSpecified;
								ob->size[2] *= userAmountSpecified;
								break;
						}
						break;

					case 29:
						/* Freely Resize Object */

						switch (userValueSelected) {

							case 1:
								transform('s'*'x');
								return;

							case 2:
								transform('s'*'y');
								return;

							case 3:
								transform('s'*'z');
								return;

							case 4:
								transform('s'*'X');
								return;

							case 5:
								transform('s'*'Y');
								return;

							case 6:
								transform('s'*'Z');
								return;

							case 7:
								transform('s');
								return;
						}
						break;

					case 30:
						/* Rotate by (case 1-4) or Reset Rot to 0 (case 5-8) */

						switch (userValueSelected) {
							case 1:
								transform('r'*'X');
								return;

							case 2:
								transform('r'*'Y');
								return;

							case 3:
								transform('r'*'Z');
								return;

							case 4:

								transform('r'*'x');
								return;

							case 5:

								transform('r'*'y');
								return;

							case 6:

								transform('r'*'z');
								return;
						}
						break;


					case 31:
						/* Reset Rotations */

						switch (userValueSelected) {

							case 1:
								ob->rot[0] = 0;
								break;

							case 2:
								ob->rot[1] = 0;
								break;

							case 3:
								ob->rot[2] = 0;
								break;

							case 4:
								ob->rot[0] = 0;
								ob->rot[1] = 0;
								ob->rot[2] = 0;
								break;
						}
						break;


					case 32:
						/* Lineup/Stack */

						if(ob->type == OB_MESH) {
							INIT_MINMAX(min, max);
							me = get_mesh(ob);
							mvert = me->mvert;
							for(a=0; a<me->totvert; a++, mvert++) {
								DO_MINMAX(mvert->co, min, max);
							}
						}
						if(ob->type == OB_LAMP) {
							max[0] = 1;
							max[1] = 1;
							max[2] = 1;
						}
						else {
							max[0] = 10;
							max[1] = 10;
							max[2] = 10;
						}

						switch (userValueSelected) {

							case 1:
							case 2:
								ob->loc[0] = theActiveObject->loc[0] + (amax[0]*userAmountSpecified)*lineupDirection;
								ob->loc[1] = theActiveObject->loc[1];
								ob->loc[2] = theActiveObject->loc[2];
								break;

							case 3:
							case 4:
								ob->loc[1] = theActiveObject->loc[1] + (amax[1]*userAmountSpecified)*lineupDirection;
								ob->loc[0] = theActiveObject->loc[0];
								ob->loc[2] = theActiveObject->loc[2];
								break;

							case 5:
							case 6:
								ob->loc[2] = theActiveObject->loc[2] + (amax[2]*userAmountSpecified)*lineupDirection;
								ob->loc[0] = theActiveObject->loc[0];
								ob->loc[1] = theActiveObject->loc[1];
								break;

							case 7:
								ob->loc[0] = theActiveObject->loc[0] + (amax[0]*userAmountSpecified)*lineupDirection;
								ob->loc[1] = theActiveObject->loc[1] + (amax[1]*userAmountSpecified)*lineupDirection;
								ob->loc[2] = theActiveObject->loc[2] + (amax[2]*userAmountSpecified)*lineupDirection;
								break;
						}

						amax[0] += max[0];
						amax[1] += max[1];
						amax[2] += max[2];

						break;

					case 33:
						/* Move Closer to Active Object */

						distanceDifference[0] = theActiveObject->loc[0] - ob->loc[0];
						distanceDifference[1] = theActiveObject->loc[1] - ob->loc[1];
						distanceDifference[2] = theActiveObject->loc[2] - ob->loc[2];

						switch (userValueSelected) {

							case 1:

								ob->loc[0] += ((distanceDifference[0]/5)*userAmountSpecified)/5;
								break;

							case 2:

								ob->loc[1] += ((distanceDifference[1]/5)*userAmountSpecified)/5;
								break;

							case 3:

								ob->loc[2] += ((distanceDifference[2]/5)*userAmountSpecified)/5;
								break;

							case 4:

								ob->loc[0] += ((distanceDifference[0]/5)*userAmountSpecified)/5;
								ob->loc[1] += ((distanceDifference[1]/5)*userAmountSpecified)/5;
								ob->loc[2] += ((distanceDifference[2]/5)*userAmountSpecified)/5;
								break;
						}
						break;

					case 34:
						/* Move Further Away from Active Object */

						distanceDifference[0] = theActiveObject->loc[0] - ob->loc[0];
						distanceDifference[1] = theActiveObject->loc[1] - ob->loc[1];
						distanceDifference[2] = theActiveObject->loc[2] - ob->loc[2];
						switch (userValueSelected) {

							case 1:

								ob->loc[0] -= ((distanceDifference[0]/5)*userAmountSpecified)/5;
								break;

							case 2:

								ob->loc[1] -= ((distanceDifference[1]/5)*userAmountSpecified)/5;
								break;

							case 3:

								ob->loc[2] -= ((distanceDifference[2]/5)*userAmountSpecified)/5;
								break;

							case 4:

								ob->loc[0] -= ((distanceDifference[0]/5)*userAmountSpecified)/5;
								ob->loc[1] -= ((distanceDifference[1]/5)*userAmountSpecified)/5;
								ob->loc[2] -= ((distanceDifference[2]/5)*userAmountSpecified)/5;
								break;
						}
						break;
				}
			}
		}
		base = base->next;
	}
	allqueue(REDRAWVIEW3D, 0);
}

--------------030207090104060305040607
Content-Type: text/plain;
 name="spacecpatch.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="spacecpatch.txt"

Index: space.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/src/space.c,v
retrieving revision 1.128
diff -r1.128 space.c
1134c1134,1136
< 					if((G.qual==LR_SHIFTKEY))
---
> 					if((G.qual & LR_SHIFTKEY) && (G.qual & LR_CTRLKEY))
> 						align_objects_menu();
> 					else if(G.qual==LR_SHIFTKEY)

--------------030207090104060305040607--