Exemplo n.º 1
0
void BodyArch::removeBodypart(unsigned int id)
{
// 	cerr << "requested removal of bodypart id " << id << endl;
	
	// find constraints where this bodypart is id1, in order to remove connected bodyparts
	for ( unsigned int i = 0; i < archConstraints.size(); i++ )
	{
		archConstraint* c = &archConstraints[i];
		if ( c->id_1 == id )
		{
// 			cerr << " is connected to " << c->isMouthConstraint << " " << c->id_2 << endl;
			if ( c->isMouthConstraint )
				removeMouth( findMouth(c->id_2) );
			else
				removeBodypart( c->id_2 );
		}
	}

// 	cerr << "really removing " << id << " which is " << findBodypart( id ) << endl;
	archBodyparts.erase( archBodyparts.begin() + findBodypart(id) );
}
std::vector<float> FeatureVectorBuilder::detectFeatures(const cv::Mat& input) {

	//For saving puropse
	static int imgNumber = 0;

	assert(input.data != NULL);
	
	//Finding face size
	int rightFace, leftFace;
	int size = faceSize(input, leftFace, rightFace);

	//Eyes section
	int eyeLine = findEyesLine(input);

	cv::Mat rEye, lEye;
	cv::Rect rEyeRect, lEyeRect;

	findEyes(input, eyeLine, rEye, lEye, rEyeRect, lEyeRect);

	if(rEye.data == NULL || lEye.data == NULL) {
		return std::vector<float>(7);
	}

	cv::Point rEyeCenter, lEyeCenter;
	int rEyeRadius, lEyeRadius;

	findEyeCenter(rEye, rEyeCenter, rEyeRadius);
	findEyeCenter(lEye, lEyeCenter, lEyeRadius);

	transformPoint(rEyeCenter, rEyeRect);
	transformPoint(lEyeCenter, lEyeRect);

	//nose
	cv::Mat nose;
	cv::Rect noseRect = findNose(input);
 	input(noseRect).copyTo(nose);

	if((noseRect.width <= 0 && noseRect.height <= 0) || nose.data == NULL) {
		return std::vector<float>(7);
	}

	cv::Point noseLeft, noseRight;
	findNosePoints(nose, noseLeft, noseRight);

	transformPoint(noseLeft, noseRect);
	transformPoint(noseRight, noseRect);


	//mouth

	cv::Mat mouth;
	cv::Point left, right, up, down;
	cv::Rect mouthRect = findMouth(input);
	input(mouthRect).copyTo(mouth);

	if((mouthRect.width <= 0 && mouthRect.height <= 0) || mouth.data == NULL) {
		return std::vector<float>(7);
	}

	findMouthPoints(mouth, left, right, up, down);

	transformPoint(left, mouthRect);
	transformPoint(right, mouthRect);
	transformPoint(up, mouthRect);
	transformPoint(down, mouthRect);

#ifdef _DEBUG
	cv::Mat cpy;
	input.copyTo(cpy);

	cv::circle(cpy, lEyeCenter, 4, cv::Scalar(0, 0, 255));
	cv::circle(cpy, rEyeCenter, 4, cv::Scalar(0, 0, 255));
	cv::circle(cpy, noseLeft, 4, cv::Scalar(0, 255, 0));
	cv::circle(cpy, noseRight, 4, cv::Scalar(0, 255, 0));
	cv::circle(cpy, left, 4, cv::Scalar(255, 0, 255));
	cv::circle(cpy, right, 4, cv::Scalar(255, 0, 255));
	cv::circle(cpy, up, 4, cv::Scalar(255, 0, 255));
	cv::circle(cpy, down, 4, cv::Scalar(255, 0, 255));

	std::stringstream ss;
	ss << "debug//img" << imgNumber << ".jpg";
	cv::imwrite(ss.str(), cpy);
	imgNumber++;
#endif

	//wektor cech
	float x1, x2, x3, x4, x5, x6, x7;

	//odlegosc miedzy srodkami oczy
	x1 = distance(lEyeCenter, rEyeCenter);

	//szerokosc nosa
	x2 = distance(noseLeft, noseRight);

	//szerokosc ust
	x3 = distance(left, right);

	//wysokosc ust
	x4 = distance(up, down);

	//szerokosc twarzy
	x5 = (float)size;

	//odgleglosc miedzy linia oczu a lina nosa
	float tmp1, tmp2;
	tmp1 = distance(lEyeCenter, noseLeft);
	tmp2 = distance(rEyeCenter, noseRight);
	x6 = (tmp1 + tmp2) / 2.0f;

	//odleglosc miedzy linia oczu a linia ust
	tmp1 = distance(lEyeCenter, left);
	tmp2 = distance(rEyeCenter, right);
	x7 = (tmp1 + tmp2) / 2.0f;

	std::vector<float> characteristic;
	characteristic.push_back(x1/x2);
	characteristic.push_back(x1/x3);
	characteristic.push_back(x2/x3);
	characteristic.push_back(x1/x5);
	characteristic.push_back(x1/x6);
	characteristic.push_back(x1/x7);
	characteristic.push_back(x4/x5);

	return characteristic;
}
Exemplo n.º 3
0
void BodyArch::mutate(unsigned int runs)
{
	for ( unsigned int i=0; i < runs; i++ )
	{
		unsigned int tsum = 	settings->getCVar("body_percentmutateeffectchangecolor")
					+ settings->getCVar("body_percentmutateeffectchangecolor_slightly")
					+ settings->getCVar("body_percentmutateeffectaddbodypart")
					+ settings->getCVar("body_percentmutateeffectremovebodypart")
					+ settings->getCVar("body_percentmutateeffectresizebodypart")
					+ settings->getCVar("body_percentmutateeffectresizebodypart_slightly")
					+ settings->getCVar("body_percentmutateeffectresizehead")
					+ settings->getCVar("body_percentmutateeffectresizehead_slightly")
					+ settings->getCVar("body_percentmutateeffectchangeconstraintlimits")
					+ settings->getCVar("body_percentmutateeffectchangeconstraintlimits_slightly")
					+ settings->getCVar("body_percentmutateeffectchangeconstraintangles")
					+ settings->getCVar("body_percentmutateeffectchangeconstraintangles_slightly")
					+ settings->getCVar("body_percentmutateeffectchangeconstraintposition")
					+ settings->getCVar("body_percentmutateeffectchangeconstraintposition_slightly")
					+ settings->getCVar("body_percentmutateeffectrepositionhead")
				;

		unsigned int mode = randgen->Instance()->get(1,tsum);

		// CHANGE COLOR
			unsigned int modesum = settings->getCVar("body_percentmutateeffectchangecolor");
			if ( mode <= modesum )
			{
				// mutate color
				unsigned int ncolor = randgen->Instance()->get(0,2);

				if ( ncolor == 0 )
					color.r = (float)RandGen::Instance()->get(0,100)/100.0f;
				else if ( ncolor == 1 )
					color.g = (float)RandGen::Instance()->get(0,100)/100.0f;
				else if ( ncolor == 2 )
					color.b = (float)RandGen::Instance()->get(0,100)/100.0f;

				continue;
			}

		// CHANGE COLOR SLIGHTLY
			modesum += settings->getCVar("body_percentmutateeffectchangecolor_slightly");
			if ( mode <= modesum )
			{
				// mutate color
				unsigned int ncolor = randgen->Instance()->get(0,2);
				unsigned int nweight = randgen->Instance()->get(1,10);
				float amount = 0.01 * nweight;

				if ( randgen->Instance()->get(0,1) == 0 )
					amount *= -1;

				if ( ncolor == 0 )
					color.r += amount;
				else if ( ncolor == 1 )
					color.g += amount;
				else if ( ncolor == 2 )
					color.b += amount;
				
				if ( color.r < 0.1f )
				{
					float diff = 0.1f - color.r;
					color.r += diff; color.g += diff; color.b += diff; color.a += diff;
				}
				if ( color.g < 0.1f )
				{
					float diff = 0.1f - color.g;
					color.r += diff; color.g += diff; color.b += diff; color.a += diff;
				}
				if ( color.b < 0.1f )
				{
					float diff = 0.1f - color.b;
					color.r += diff; color.g += diff; color.b += diff; color.a += diff;
				}
			
				if ( color.r > 1.0f && color.g > 1.0f && color.b > 1.0f )
					color.normalize();

				continue;
			}

		// ADD BODYPART
			modesum += settings->getCVar("body_percentmutateeffectaddbodypart");
			if ( mode <= modesum )
			{
				if ( archBodyparts.size() < settings->getCVar("body_maxbodyparts") )
				{
// 					cerr << "adding bodypart" << endl;
					addRandomBodypart();
// 					cerr << "done adding bodypart" << endl;
				}
				else
					runs++;
				continue;
			}

		// REMOVE BODYPART
			modesum += settings->getCVar("body_percentmutateeffectremovebodypart");
			if ( mode <= modesum )
			{
				if ( archBodyparts.size() > 2 )
				{
					// pick a random bodypart
					unsigned int bid = randgen->Instance()->get( 0, archBodyparts.size()-1 );

					// if not main body, remove it
					if ( archBodyparts[bid].id != 1000 )
					{
// 						cerr << "removing bodypart " << bid << " id " << archBodyparts[bid].id  << endl;

						removeBodypart( archBodyparts[bid].id );

// 						cerr << "removing obsolete constraints, expected errors:" << endl;
						for ( int i = 0; i < (int)archConstraints.size(); i++ )
						{
							archConstraint* c = &archConstraints[i];
							if ( findBodypart( c->id_1 ) == -1 )
							{
								archConstraints.erase(archConstraints.begin()+i);
								i--;
							}
							else if ( c->isMouthConstraint && findMouth( c->id_2 ) == -1 )
							{
								archConstraints.erase(archConstraints.begin()+i);
								i--;
							}
							else if ( !c->isMouthConstraint && findBodypart( c->id_2 ) == -1 )
							{
								archConstraints.erase(archConstraints.begin()+i);
								i--;
							}
						}
// 						cerr << "done removing obsolete constraints" << endl << endl;

// 						cerr << "done removing bodypart" << endl;

						// re add mouth if needed
						if ( archMouths.size() == 0 )
								addRandomMouth();
					}
					else
						runs++;

				}
				else
					runs++;
				continue;
			}

		// RESIZE BODYPART
			modesum += settings->getCVar("body_percentmutateeffectresizebodypart");
			if ( mode <= modesum )
			{
// 				cerr << "resize bodypart" << endl;

					// pick a random bodypart
					unsigned int bid = randgen->Instance()->get( 0, archBodyparts.size()-1 );
					archBodypart *bp = &archBodyparts[bid];

					unsigned int axismode = randgen->Instance()->get(0,2);
					if ( axismode == 0 )
						bp->x = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") );
					else if ( axismode == 1 )
						bp->y = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") );
					else
						bp->z = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") );

					// reposition the constraints back to the resized bodypart
					repositiontoConstraints(bp);

// 				cerr << "done resize bodypart" << endl;
				continue;
			}

		// RESIZE BODYPART SLIGHTLY
			modesum += settings->getCVar("body_percentmutateeffectresizebodypart_slightly");
			if ( mode <= modesum )
			{
// 				cerr << "resize bodypart slightly" << endl;

					// pick a random bodypart
					unsigned int bid = randgen->Instance()->get( 0, archBodyparts.size()-1 );
					archBodypart* bp = &archBodyparts[bid];

					unsigned int axismode = randgen->Instance()->get(0,2);
					unsigned int direction = randgen->Instance()->get(0,1);
					if ( axismode == 0 )
					{
						if ( direction == 0 )
							bp->x += randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 );
						else
							bp->x -= randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 );
					}
					else if ( axismode == 1 )
					{
						if ( direction == 0 )
							bp->y += randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 );
						else
							bp->y -= randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 );
					}
					else
					{
						if ( direction == 0 )
							bp->z += randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 );
						else
							bp->z -= randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 );
					}

					// see that they didn't go over their limits
					if ( bp->x < settings->getCVar("body_minbodypartsize") )
						bp->x = settings->getCVar("body_minbodypartsize");
					else if ( bp->x > settings->getCVar("body_maxbodypartsize") )
						bp->x = settings->getCVar("body_minbodypartsize");

					if ( bp->y < settings->getCVar("body_minbodypartsize") )
						bp->y = settings->getCVar("body_minbodypartsize");
					else if ( bp->y > settings->getCVar("body_maxbodypartsize") )
						bp->y = settings->getCVar("body_minbodypartsize");

					if ( bp->z < settings->getCVar("body_minbodypartsize") )
						bp->z = settings->getCVar("body_minbodypartsize");
					else if ( bp->z > settings->getCVar("body_maxbodypartsize") )
						bp->z = settings->getCVar("body_minbodypartsize");

					// reposition the constraints back to the resized bodypart
					repositiontoConstraints(bp);

// 				cerr << "done resize bodypart" << endl;
				continue;
			}

		// RESIZE HEAD
			modesum += settings->getCVar("body_percentmutateeffectresizehead");
			if ( mode <= modesum )
			{
// 				cerr << "resize mouth" << endl;

					// pick a random head
					unsigned int mid = randgen->Instance()->get( 0, archMouths.size()-1 );
					archMouth* head = &archMouths[mid];

					unsigned int axismode = randgen->Instance()->get(0,2);
					if ( axismode == 0 )
						head->x = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") );
					else if ( axismode == 1 )
						head->y = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") );
					else
						head->z = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") );

					// reposition the constraints back to the resized bodypart
					repositiontoConstraints(head);

// 				cerr << "done resize head" << endl;
				continue;
			}

		// RESIZE HEAD SLIGHTLY
			modesum += settings->getCVar("body_percentmutateeffectresizehead_slightly");
			if ( mode <= modesum )
			{
// 				cerr << "resize head slightly" << endl;

					// pick a random head
					unsigned int mid = randgen->Instance()->get( 0, archMouths.size()-1 );
					archMouth* head = &archMouths[mid];

					unsigned int axismode = randgen->Instance()->get(0,2);
					unsigned int direction = randgen->Instance()->get(0,1);
					if ( axismode == 0 )
					{
						if ( direction == 0 )
							head->x += randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 );
						else
							head->x -= randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 );
					}
					else if ( axismode == 1 )
					{
						if ( direction == 0 )
							head->y += randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 );
						else
							head->y -= randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 );
					}
					else
					{
						if ( direction == 0 )
							head->z += randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 );
						else
							head->z -= randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 );
					}

					// see that they didn't go over their limits
					if ( head->x < settings->getCVar("body_minheadsize") )
						head->x = settings->getCVar("body_minheadsize");
					else if ( head->x > settings->getCVar("body_maxheadsize") )
						head->x = settings->getCVar("body_minheadsize");

					if ( head->y < settings->getCVar("body_minheadsize") )
						head->y = settings->getCVar("body_minheadsize");
					else if ( head->y > settings->getCVar("body_maxheadsize") )
						head->y = settings->getCVar("body_minheadsize");

					if ( head->z < settings->getCVar("body_minheadsize") )
						head->z = settings->getCVar("body_minheadsize");
					else if ( head->z > settings->getCVar("body_maxheadsize") )
						head->z = settings->getCVar("body_minheadsize");

					// reposition the constraints back to the resized bodypart
					repositiontoConstraints(head);

// 				cerr << "done resize head" << endl;
				continue;
			}

		// CHANGE CONSTRAINT LIMITS
			modesum += settings->getCVar("body_percentmutateeffectchangeconstraintlimits");
			if ( mode <= modesum )
			{
// 				cerr << "changing constraint limits" << endl;

				unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 );
				archConstraint* co = &archConstraints[cid];
				co->limit_1		= (float)randgen->Instance()->get( 0, 7853 ) / -10000;
				co->limit_2		= -1.0f * co->limit_1;

// 				cerr << "done changing constraint limits" << endl;
				continue;
			}
	
		// CHANGE CONSTRAINT LIMITS SLIGHTLY
			modesum += settings->getCVar("body_percentmutateeffectchangeconstraintlimits_slightly");
			if ( mode <= modesum )
			{
// 				cerr << "changing constraint limits" << endl;

				unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 );
				archConstraint* co = &archConstraints[cid];
				
				unsigned int direction = randgen->Instance()->get(0,1);

				if ( direction == 0 )
					co->limit_1 += 0.01f;
				else
					co->limit_1 -= 0.01f;
				// check limits limits, ya
				if ( co->limit_1 > 0.0f )
					co->limit_1 = 0.0f;
				if ( co->limit_1 < -0.7853f )
					co->limit_1 = -0.7853f;

				co->limit_2 = -1.0f * co->limit_1;

// 				cerr << "done changing constraint limits" << endl;
				continue;
			}
		// CHANGE CONSTRAINT ANGLES
			modesum += settings->getCVar("body_percentmutateeffectchangeconstraintangles");
			if ( mode <= modesum )
			{
// 				cerr << "changing constraint angles" << endl;

				unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 );
				archConstraint* co = &archConstraints[cid];
				co->rot_x_1		= ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000;
				co->rot_z_1		= ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000;
				co->rot_y_1		= ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000;

				co->rot_x_2		= ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000;
				co->rot_y_2		= ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000;
				co->rot_z_2		= ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000;

// 				cerr << "done changing constraint angles" << endl;
				continue;
			}

		// CHANGE CONSTRAINT ANGLES SLIGHTLY
			modesum += settings->getCVar("body_percentmutateeffectchangeconstraintangles_slightly");
			if ( mode <= modesum )
			{
// 				cerr << "changing constraint angles" << endl;

				unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 );
				archConstraint* co = &archConstraints[cid];

				unsigned int XYZ = randgen->Instance()->get(0,2);
				unsigned int direction = randgen->Instance()->get(0,1);
				if ( direction == 0 )
				{
					if ( XYZ == 0 )
						co->rot_x_1 += 0.01f;
					else if ( XYZ == 1 )
						co->rot_y_1 += 0.01f;
					else
						co->rot_z_1 += 0.01f;
				}
				else
				{
					if ( XYZ == 0 )
						co->rot_x_1 -= 0.01f;
					else if ( XYZ == 1 )
						co->rot_y_1 -= 0.01f;
					else
						co->rot_z_1 -= 0.01f;
				}

				XYZ = randgen->Instance()->get(0,2);
				direction = randgen->Instance()->get(0,1);
				if ( direction == 0 )
				{
					if ( XYZ == 0 )
						co->rot_x_2 += 0.01f;
					else if ( XYZ == 1 )
						co->rot_y_2 += 0.01f;
					else
						co->rot_z_2 += 0.01f;
				}
				else
				{
					if ( XYZ == 0 )
						co->rot_x_2 -= 0.01f;
					else if ( XYZ == 1 )
						co->rot_y_2 -= 0.01f;
					else
						co->rot_z_2 -= 0.01f;
				}

				if ( co->rot_x_1 < -0.1571f )
					co->rot_x_1 = -0.1571f;
				if ( co->rot_x_1 > 0.1571f )
					co->rot_x_1 = 0.1571f;
				if ( co->rot_y_1 < -0.1571f )
					co->rot_y_1 = -0.1571f;
				if ( co->rot_y_1 > 0.1571f )
					co->rot_y_1 = 0.1571f;
				if ( co->rot_z_1 < -0.1571f )
					co->rot_z_1 = -0.1571f;
				if ( co->rot_z_1 > 0.1571f )
					co->rot_z_1 = 0.1571f;

				if ( co->rot_x_2 < -0.1571f )
					co->rot_x_2 = -0.1571f;
				if ( co->rot_x_2 > 0.1571f )
					co->rot_x_2 = 0.1571f;
				if ( co->rot_y_2 < -0.1571f )
					co->rot_y_2 = -0.1571f;
				if ( co->rot_y_2 > 0.1571f )
					co->rot_y_2 = 0.1571f;
				if ( co->rot_z_2 < -0.1571f )
					co->rot_z_2 = -0.1571f;
				if ( co->rot_z_2 > 0.1571f )
					co->rot_z_2 = 0.1571f;

// 				cerr << "done changing constraint angles" << endl;
				continue;
			}

		// REPOSITION A CONSTRAINT
			modesum += settings->getCVar("body_percentmutateeffectchangeconstraintposition");
			if ( mode <= modesum )
			{
// 				cerr << "changing constraint position" << endl;

				unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 );
				archConstraint* co = &archConstraints[cid];

				int connID1 = findBodypart(co->id_1);
				int connID2;

				if ( co->isMouthConstraint )
					connID2 = findMouth(co->id_2);
				else
					connID2 = findBodypart(co->id_2);

				// pick one of 2 bodies to reconnect
				unsigned int body1or2 = randgen->Instance()->get( 1, 2 );

				if ( body1or2 == 1 )
					randomConstraintPosition(co, 1, connID1);
				else
					randomConstraintPosition(co, 2, connID2);

// 				cerr << "done changing constraint position" << endl;
				continue;
			}

		// REPOSITION A CONSTRAINT SLIGHTLY
			modesum += settings->getCVar("body_percentmutateeffectchangeconstraintposition_slightly");
			if ( mode <= modesum )
			{
// 				cerr << "changing constraint position" << endl;

				unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 );
				archConstraint* co = &archConstraints[cid];

				int connID1 = findBodypart(co->id_1);
				int connID2;

				if ( co->isMouthConstraint )
					connID2 = findMouth(co->id_2);
				else
					connID2 = findBodypart(co->id_2);

				// pick one of 2 bodies to reconnect
				unsigned int body1or2 = randgen->Instance()->get( 1, 2 );
				unsigned int direction = randgen->Instance()->get( 0, 1 );
				unsigned int axis1or2 = randgen->Instance()->get( 0, 1 );

				if ( body1or2 == 1 ) {
					// now we know the plane to connect to, determine positions
					if ( co->XYZ == 0 ) { // X
						if ( direction == 0 ) {
							if ( axis1or2 == 0 )	co->pos_y_1 += archBodyparts[connID1].y / 100000;
							else			co->pos_z_1 += archBodyparts[connID1].z / 100000;
						} else {
							if ( axis1or2 == 0 )	co->pos_y_1 -= archBodyparts[connID1].y / 100000;
							else			co->pos_z_1 -= archBodyparts[connID1].z / 100000;
						}
					}
					else if ( co->XYZ == 1 ) { // Y
						if ( direction == 0 ) {
							if ( axis1or2 == 0 )	co->pos_x_1 += archBodyparts[connID1].x / 100000;
							else			co->pos_z_1 += archBodyparts[connID1].z / 100000;
						} else {
							if ( axis1or2 == 0 )	co->pos_x_1 -= archBodyparts[connID1].x / 100000;
							else			co->pos_z_1 -= archBodyparts[connID1].z / 100000;
						}
					}
					else { // Z
						if ( direction == 0 ) {
							if ( axis1or2 == 0 )	co->pos_x_1 += archBodyparts[connID1].x / 100000;
							else			co->pos_y_1 += archBodyparts[connID1].y / 100000;
						} else {
							if ( axis1or2 == 0 )	co->pos_x_1 -= archBodyparts[connID1].x / 100000;
							else			co->pos_y_1 -= archBodyparts[connID1].y / 100000;
						}
					}
					if ( co->pos_x_1 < archBodyparts[connID1].x/-2000 )
						co->pos_x_1 = archBodyparts[connID1].x/-2000;
					if ( co->pos_x_1 > archBodyparts[connID1].x/2000 )
						co->pos_x_1 = archBodyparts[connID1].x/2000;
					if ( co->pos_y_1 < archBodyparts[connID1].y/-2000 )
						co->pos_y_1 = archBodyparts[connID1].y/-2000;
					if ( co->pos_y_1 > archBodyparts[connID1].y/2000 )
						co->pos_y_1 = archBodyparts[connID1].y/2000;
					if ( co->pos_z_1 < archBodyparts[connID1].z/-2000 )
						co->pos_z_1 = archBodyparts[connID1].z/-2000;
					if ( co->pos_z_1 > archBodyparts[connID1].z/2000 )
						co->pos_z_1 = archBodyparts[connID1].z/2000;
				}
				else {
					if ( !co->isMouthConstraint ) {
						// now we know the plane to connect to, determine positions
						if ( co->XYZ == 0 ) { // X
							if ( direction == 0 ) {
								if ( axis1or2 == 0 )	co->pos_y_2 += archBodyparts[connID2].y / 100000;
								else			co->pos_z_2 += archBodyparts[connID2].z / 100000;
							} else {
								if ( axis1or2 == 0 )	co->pos_y_2 -= archBodyparts[connID2].y / 100000;
								else			co->pos_z_2 -= archBodyparts[connID2].z / 100000;
							}
						}
						else if ( co->XYZ == 1 ) { // Y
							if ( direction == 0 ) {
								if ( axis1or2 == 0 )	co->pos_x_2 += archBodyparts[connID2].x / 100000;
								else			co->pos_z_2 += archBodyparts[connID2].z / 100000;
							} else {
								if ( axis1or2 == 0 )	co->pos_x_2 -= archBodyparts[connID2].x / 100000;
								else			co->pos_z_2 -= archBodyparts[connID2].z / 100000;
							}
						}
						else { // Z
							if ( direction == 0 ) {
								if ( axis1or2 == 0 )	co->pos_x_2 += archBodyparts[connID2].x / 100000;
								else			co->pos_y_2 += archBodyparts[connID2].y / 100000;
							} else {
								if ( axis1or2 == 0 )	co->pos_x_2 -= archBodyparts[connID2].x / 100000;
								else			co->pos_y_2 -= archBodyparts[connID2].y / 100000;
							}
						}
						if ( co->pos_x_2 < archBodyparts[connID2].x/-2000 )
							co->pos_x_2 = archBodyparts[connID2].x/-2000;
						if ( co->pos_x_2 > archBodyparts[connID2].x/2000 )
							co->pos_x_2 = archBodyparts[connID2].x/2000;
						if ( co->pos_y_2 < archBodyparts[connID2].y/-2000 )
							co->pos_y_2 = archBodyparts[connID2].y/-2000;
						if ( co->pos_y_2 > archBodyparts[connID2].y/2000 )
							co->pos_y_2 = archBodyparts[connID2].y/2000;
						if ( co->pos_z_2 < archBodyparts[connID2].z/-2000 )
							co->pos_z_2 = archBodyparts[connID2].z/-2000;
						if ( co->pos_z_2 > archBodyparts[connID2].z/2000 )
							co->pos_z_2 = archBodyparts[connID2].z/2000;
					}
					else {
						if ( co->XYZ == 0 ) { // X
							if ( direction == 0 ) {
								if ( axis1or2 == 0 )	co->pos_y_2 += archMouths[connID2].y / 100000;
								else			co->pos_z_2 += archMouths[connID2].z / 100000;
							} else {
								if ( axis1or2 == 0 )	co->pos_y_2 -= archMouths[connID2].y / 100000;
								else			co->pos_z_2 -= archMouths[connID2].z / 100000;
							}
						}
						else if ( co->XYZ == 1 ) { // Y
							if ( direction == 0 ) {
								if ( axis1or2 == 0 )	co->pos_x_2 += archMouths[connID2].x / 100000;
								else			co->pos_z_2 += archMouths[connID2].z / 100000;
							} else {
								if ( axis1or2 == 0 )	co->pos_x_2 -= archMouths[connID2].x / 100000;
								else			co->pos_z_2 -= archMouths[connID2].z / 100000;
							}
						}
						else { // Z
							if ( direction == 0 ) {
								if ( axis1or2 == 0 )	co->pos_x_2 += archMouths[connID2].x / 100000;
								else			co->pos_y_2 += archMouths[connID2].y / 100000;
							} else {
								if ( axis1or2 == 0 )	co->pos_x_2 -= archMouths[connID2].x / 100000;
								else			co->pos_y_2 -= archMouths[connID2].y / 100000;
							}
						}
						if ( co->pos_x_2 < archMouths[connID2].x/-2000 )
							co->pos_x_2 = archMouths[connID2].x/-2000;
						if ( co->pos_x_2 > archMouths[connID2].x/2000 )
							co->pos_x_2 = archMouths[connID2].x/2000;
						if ( co->pos_y_2 < archMouths[connID2].y/-2000 )
							co->pos_y_2 = archMouths[connID2].y/-2000;
						if ( co->pos_y_2 > archMouths[connID2].y/2000 )
							co->pos_y_2 = archMouths[connID2].y/2000;
						if ( co->pos_z_2 < archMouths[connID2].z/-2000 )
							co->pos_z_2 = archMouths[connID2].z/-2000;
						if ( co->pos_z_2 > archMouths[connID2].z/2000 )
							co->pos_z_2 = archMouths[connID2].z/2000;
					}
				}
					
// 					randomConstraintPosition(co, 2, connID2);

// 				cerr << "done changing constraint position" << endl;
				continue;
			}

		// REMOVE AND ADD MOUTH
			modesum += settings->getCVar("body_percentmutateeffectrepositionhead");
			if ( mode <= modesum )
			{
// 				cerr << "remove and add mouth" << endl;
				
				for ( int i = 0; i < (int)archConstraints.size(); i++ )
				{
					archConstraint* c = &archConstraints[i];
					if ( c->isMouthConstraint && c->id_2 == archMouths[0].id )
					{
						archConstraints.erase(archConstraints.begin()+i);
						i--;
					}
				}

				removeMouth(0);

				addRandomMouth();

// 				cerr << "done remove and add mouth" << endl;
				continue;
			}

		// if we reach here, none were processed, decrease runs by 1 to make sure we get a hit
			if ( modesum > 0 )
				runs++;
	}
}