//
//	面接続(Tube)
//
/*
function private MinimumSearch( p1, p2, n1, n2 )
{
	var i, j;
	var len, lenmin, p1min, p2min;
	var tempv[MAXVERTEX];
	p1min = 0;
	p2min = 0;
	lenmin = VertexLength2(p1[0], p2[0]);
	for (i = 0; i < n1; i++) {
		for (j = 0; j < n2; j++) {
			len = VertexLength2(p1[i], p2[j]);
			if (len < lenmin) {
				lenmin = len;
				p1min = i;
				p2min = j;
			}
		}
	}

	j = p1min;
	for (i = 0; i < n1; i++) {
		tempv[i] = p1[j];
		j++;
		if (j == n1) j = 0;
	}
	for (i = 0; i < n1; i++) {
		p1[i] = tempv[i];
	}
	j = p2min;
	for (i = 0; i < n2; i++) {
		tempv[i] = p2[j];
		j++;
		if (j == n2) j = 0;
	}
	for (i = 0; i < n2; i++) {
		p2[i] = tempv[i];
	}
}
*/
function private MinimumSearch( p1, p2, n1, n2, m1, m2 )
{
	var i, j;
	var len, lenmin, p1min, p2min;
	var tempv[MAXVERTEX];
	var v1[MAXVERTEX], v2[MAXVERTEX];
	for (i = 0; i < n1; i++) {
		v1[i] = unit(Position(p1[i])*m1);
	}
	for (i = 0; i < n2; i++) {
		v2[i] = unit(Position(p2[i])*m2);
	}

	p1min = 0;
	p2min = 0;
	lenmin = v1[0] . v2[0];
	for (i = 0; i < n1; i++) {
		for (j = 0; j < n2; j++) {
			len = v1[i] . v2[j];
			if (len > lenmin) {
				lenmin = len;
				p1min = i;
				p2min = j;
			}
		}
	}

	j = p1min;
	for (i = 0; i < n1; i++) {
		tempv[i] = p1[j];
		j++;
		if (j == n1) j = 0;
	}
	for (i = 0; i < n1; i++) {
		p1[i] = tempv[i];
	}
	j = p2min;
	for (i = 0; i < n2; i++) {
		tempv[i] = p2[j];
		j++;
		if (j == n2) j = 0;
	}
	for (i = 0; i < n2; i++) {
		p2[i] = tempv[i];
	}
}

function private Invert(p1, n1)
{
	var begin,end, temp;
	begin = 1;
	end = n1-1;
	while (begin < end) {
		temp = p1[begin];
		p1[begin] = p1[end];
		p1[end] = temp;
		begin++;
		end--;
	}
}

function Tube2Polygon( p1, p2, n1, n2 )
{
	var i;
	var p1c, p2c;
	var p1begin, p1end, p2begin, p2end;
	var v1begin, v1end, v2begin, v2end;
	var v1beginnext, v1endprev, v2beginnext, v2endprev;

	var minmult, mult, mintype;
	var vx, vz;
	var p1mat, p2mat;
	var p3mat;

	var v1,v2;
	var flag;

//	MinimumSearch( p1, p2, n1, n2 );

	p1c = vector(0,0,0);
	p2c = p1c;
	for (i = 0; i < n1; i++) {
		p1c += Position(p1[i]);
	}
	p1c = p1c * (1.0 / n1);
	for (i = 0; i < n2; i++) {
		p2c += Position(p2[i]);
	}
	p2c = p2c * (1.0 / n1);
	vz = p2c - p1c;
	vx = Position(p1[0]) - p1c;

	p1mat = move(UNIT_MATRIX, p1c * (-1)) / vec(UNIT_MATRIX, vz, vx);
	p2mat = move(UNIT_MATRIX, p2c * (-1)) / vec(UNIT_MATRIX, vz, vx);

	MinimumSearch( p1, p2, n1, n2, p1mat, p2mat );

/*
	if ((Position(p1[1]) * p1mat) . vector(0,1,0) < 0) {
		Invert(p1, n1);
	}
	if ((Position(p2[1]) * p3mat) . vector(0,1,0) < 0) {
		Invert(p2, n2);
	}
*/
	if ( ((Position(p1[0]) * p1mat) * (Position(p1[1]) * p1mat))
	   . ((Position(p2[0]) * p2mat) * (Position(p2[1]) * p2mat)) < 0) {
		Invert(p2, n2);
	}


	p1[n1] = p1[0];
	p2[n2] = p2[0];

	p1begin = 0;
	p1end = n1;
	p2begin = 0;
	p2end = n2;

	v1begin = unit(Position(p1[0]) * p1mat);
	v1end = v1begin;
	v2begin = unit(Position(p2[0]) * p2mat);
	v2end = v2begin;

	PolyVertexs( 3 );
	PolyType( POLY_SIMPLE );
	PolyAttr( AttrCurrent());
	PolyObj( ObjCurrent());

	while ( (p1begin < p1end) | (p2begin < p2end) ) {
		minmult = -1;
		mintype = -1;
		if (p1begin < p1end) {
			v1beginnext = unit(Position(p1[p1begin+1]) * p1mat);
			mult = v1beginnext . v2begin;
			if (mult > minmult) {
				minmult = mult;
				mintype = 0;
			}
			v1endprev = unit(Position(p1[p1end-1]) * p1mat);
			mult = v1endprev . v2end;
			if (mult > minmult) {
				minmult = mult;
				mintype = 1;
			}
		}
		if (p2begin < p2end) {
			v2beginnext = unit(Position(p2[p2begin+1]) * p2mat);
			mult = v2beginnext . v1begin;
			if (mult > minmult) {
				minmult = mult;
				mintype = 2;
			}
			v2endprev = unit(Position(p2[p2end-1]) * p2mat);
			mult = v2endprev . v1end;
			if (mult > minmult) {
				minmult = mult;
				mintype = 3;
			}
		}
		flag = TRUE;
		if (mintype == 0) {
			if (p2begin < p2end) {
				v1 = unit(Position(p1[p1begin+1])-Position(p1[p1begin]));
				v2 = unit(Position(p2[p2begin+1])-Position(p2[p2begin]));
				if (v1.v2 > 0.999) {
					PolySetVertex(p1[p1begin], 0);
					PolySetVertex(p1[p1begin+1], 1);
					PolySetVertex(p2[p2begin+1], 2);
					PolySetVertex(p2[p2begin], 3);
					PolyVertexs( 4 );
					p2begin++;
					v2begin = v2beginnext;
					flag = FALSE;
				}
			}
			if (flag) {
				PolySetVertex(p1[p1begin], 0);
				PolySetVertex(p1[p1begin+1], 1);
				PolySetVertex(p2[p2begin], 2);
				PolyVertexs( 3 );
			}
			p1begin++;
			v1begin = v1beginnext;
		} else if (mintype == 1) {
			if (p2begin < p2end) {
				v1 = unit(Position(p1[p1end-1])-Position(p1[p1end]));
				v2 = unit(Position(p2[p2end-1])-Position(p2[p2end]));
				if (v1.v2 > 0.999) {
					PolySetVertex(p1[p1end], 0);
					PolySetVertex(p1[p1end-1], 1);
					PolySetVertex(p2[p2end-1], 2);
					PolySetVertex(p2[p2end], 3);
					PolyVertexs( 4 );
					p2end--;
					v2end = v2endprev;
					flag = FALSE;
				}
			}
			if (flag) {
				PolySetVertex(p1[p1end], 0);
				PolySetVertex(p1[p1end-1], 1);
				PolySetVertex(p2[p2end], 2);
				PolyVertexs( 3 );
			}
			p1end--;
			v1end = v1endprev;
		} else if (mintype == 2) {
			if (p1begin < p1end) {
				v1 = unit(Position(p1[p1begin+1])-Position(p1[p1begin]));
				v2 = unit(Position(p2[p2begin+1])-Position(p2[p2begin]));
				if (v1.v2 > 0.999) {
					PolySetVertex(p1[p1begin], 0);
					PolySetVertex(p1[p1begin+1], 1);
					PolySetVertex(p2[p2begin+1], 2);
					PolySetVertex(p2[p2begin], 3);
					PolyVertexs( 4 );
					p1begin++;
					v1begin = v1beginnext;
					flag = FALSE;
				}
			}
			if (flag) {
				PolySetVertex(p2[p2begin], 0);
				PolySetVertex(p2[p2begin+1], 1);
				PolySetVertex(p1[p1begin], 2);
				PolyVertexs( 3 );
			}
			p2begin++;
			v2begin = v2beginnext;
		} else if (mintype == 3) {
			if (p1begin < p1end) {
				v1 = unit(Position(p1[p1end-1])-Position(p1[p1end]));
				v2 = unit(Position(p2[p2end-1])-Position(p2[p2end]));
				if (v1.v2 > 0.999) {
					PolySetVertex(p1[p1end], 0);
					PolySetVertex(p1[p1end-1], 1);
					PolySetVertex(p2[p2end-1], 2);
					PolySetVertex(p2[p2end], 3);
					PolyVertexs( 4 );
					p1end--;
					v1end = v1endprev;
					flag = FALSE;
				}
			}
			if (flag) {
				PolySetVertex(p2[p2end], 0);
				PolySetVertex(p2[p2end-1], 1);
				PolySetVertex(p1[p1end], 2);
				PolyVertexs( 3 );
			}
			p2end--;
			v2end = v2endprev;
		} else {
			break;
		}
		PolyAppend( TRUE );
		ViewCursor( OFF );
		DrawCurrent( TRUE );
		ViewCursor( ON );
	}
}

function TubeMain(sel, pos1, pos2)
{
	var v1[MAXVERTEX], v2[MAXVERTEX], n1, n2, i;

	PolyLoad(sel,pos1);
	n1 = PolyVertexs();
	for (i = 0; i < n1; i++) {
		v1[i] = PolyGetVertex(i);
	}
	PolyLoad(sel,pos2);
	n2 = PolyVertexs();
	for (i = 0; i < n2; i++) {
		v2[i] = PolyGetVertex(i);
	}
	Tube2Polygon(v1, v2, n1, n2);
	return TRUE;
}

function Tube(sel)
{
	var const POLYMAX = 32;
	var center[POLYMAX], c;
	var flag[POLYMAX];
	var i, j;
	var sels, vers;
	var len, minlen, minp1, minp2;
	var mintype;
	var minpos;

	sels = SelectPolygons(sel);
	if (sels < 2 | sels > POLYMAX) {
		Warning();
		if( MESSAGE == ON )
		{
			if( sels < 2 )
				Message( "接続する面を指定してください" );
			else
				Message( "接続する面が多すぎます" );
		}
		return FALSE;
	}

	SelectAllFalse();
	SelectAll( FALSE );

	for (i = 0; i < sels; i++) {
		PolyLoad(sel, i);
		vers = PolyVertexs();
		c = vector(0,0,0);
		for (j = 0; j < vers; j++) {
			c += Position(PolyGetVertex(j));
		}
		center[i] = Vertex(c * (1.0/vers));
		flag[i] = TRUE;
	}
	minlen = VertexLength2(center[0], center[1]);
	minp1 = 0;
	minp2 = 1;
	for (i = 0; i < sels; i++) {
		for (j = i+1; j < sels; j++) {
			len = VertexLength2(center[i], center[j]);
			if (len < minlen) {
				minlen = len;
				minp1 = i;
				minp2 = j;
			}
		}
	}

	flag[minp1] = FALSE;
	flag[minp2] = FALSE;
	TubeMain(sel, minp1, minp2);
	while (TRUE) {
		mintype = -1;
		minlen = 999999999;
		for (i = 0; i < sels; i++) {
			if (flag[i]) {
				len = VertexLength2(center[minp1], center[i]);
				if (len < minlen) {
					minlen = len;
					mintype = 0;
					minpos = i;
				}
				len = VertexLength2(center[minp2], center[i]);
				if (len < minlen) {
					minlen = len;
					mintype = 1;
					minpos = i;
				}
			}
		}
		if (mintype == 0) {
			flag[minpos] = FALSE;
			TubeMain(sel, minp1, minpos);
			minp1 = minpos;
		} else if (mintype == 1) {
			flag[minpos] = FALSE;
			TubeMain(sel, minp2, minpos);
			minp2 = minpos;
		} else {
			break;
		}
	}
	return TRUE;
}
