Path: news.larc.nasa.gov!amiga-request
From: amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
Subject: v91i177: ED3 1.1 - a primitive 3D editor for use with NU3, Part06/06
Reply-To: rodent@netcom.com (Ben Discoe)
Newsgroups: comp.sources.amiga
Message-ID: <comp.sources.amiga.v91i177@ab20.larc.nasa.gov>
References: <comp.sources.amiga.v91i172@ab20.larc.nasa.gov>
Date: 07 Nov 91 15:54:43 GMT
Approved: tadguy@uunet.UU.NET (Tad Guy)
X-Mail-Submissions-To: amiga@uunet.uu.net
X-Post-Discussions-To: comp.sys.amiga.misc

Submitted-by: rodent@netcom.com (Ben Discoe)
Posting-number: Volume 91, Issue 177
Archive-name: utilities/ed3-1.1/part06

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 6 (of 6)."
# Contents:  edvan.c
# Wrapped by tadguy@ab20 on Thu Nov  7 10:53:52 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'edvan.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'edvan.c'\"
else
echo shar: Extracting \"'edvan.c'\" \(32224 characters\)
sed "s/^X//" >'edvan.c' <<'END_OF_FILE'
X/*
X	These are miscellaneous vanilla functions of ed3,
X		using no graphics or intuition calls.
X
X10-22-91 chg YZ to ZY
X		 fixed a very small (but serious) bug in find_dual
X10-13-91 added fibo() fibonacci (?) function
X		 stellate() now checks to see if there is room in the undo buf
X09-25-91 chg points_are_a_face2 to face_next_to_edge
X		 add adjacent_fp(), adjacent_pp(), adjacent_xx()
X		 fix a problem in find_dual with polys->polys
X09-06-91 adapted to use coord instead of short
X		 rem distance_between_points
X09-04-91 chg face_next_to_edge() to allow an ignored face
X09-03-91 chg rotate() to support the rotate_all flag
X		 implement deselect_connected()
X09-02-91 add center_to_origin(), move_point_rel(), move_point_to()
X08-27-91 add points_are_on_a_poly()
X08-26-91 fix to point_is_on_a_face()
X		 add point_is_on_a_poly()
X08-24-91 add stellate() (hey, it was easy!)
X		 add glue_points()	(also easy)
X08-23-91 added refresh_all(), toggle_dtool()
X08-21-91 added select_all(), select_connected(), deselect_all(),
X		 deselect_connected(), toggle_select();
X08-15-91 added find_center()
X		 added find_radius()
X		 chg find_dual to support assume_poly flag
X*/
X
X#include "sysnogr.h"
X
X
X#if INTEGER
Xvoid center_to_origin()
X{
X	double dcx, dcy, dcz;
X	pixel cx, cy, cz;
X	index p;
X
X	if (!points) return;
X
X	find_center(&dcx, &dcy, &dcz);
X	cx = dcx;
X	cy = dcy;
X	cz = dcz;
X
X	if (!cx && !cy && !cz)
X	{
X		screen_say("Points are already centered");
X		return;	/* already at center */
X	}
X
X	for (p = 0; p < points; p++)
X	  move_point_rel(p, -cx, -cy, -cz);
X
X	refresh_all();
X}
X#else
Xvoid center_to_origin()
X{
X	double dcx, dcy, dcz;
X	index p;
X
X	if (!points) return;
X
X	find_center(&dcx, &dcy, &dcz);
X
X	if ((dcx > -.001 && dcx < .001) &&
X		(dcy > -.001 && dcy < .001) &&
X		(dcz > -.001 && dcz < .001))
X	{
X		screen_say("Points are already centered");
X		return;	/* already at center */
X	}
X
X	for (p = 0; p < points; p++)
X	  move_point_rel(p, -dcx, -dcy, -dcz);
X
X	refresh_all();
X}
X#endif
X
X
Xvoid reset_zoom()
X{
X  SCALE = 1.0;
X  offset.x = offset.y = offset.z = 0;
X}
X
X
Xvoid move_point_rel(p, dx, dy, dz)
Xindex p;
Xcoord dx, dy, dz;
X{
X	action_move_p(p, dx, dy, dz);
X
X	point[p].x += dx;
X	point[p].y += dy;
X	point[p].z += dz;
X	convert_point(p);
X}
X
X
Xvoid move_point_to(p, x, y, z)
Xindex p;
Xcoord x, y, z;
X{
X	action_move_p(p, x-point[p].x, y-point[p].y, z-point[p].z);
X
X	point[p].x = x;
X	point[p].y = y;
X	point[p].z = z;
X	convert_point(p);
X}
X
X
Xvoid refresh_all()
X{
X	int i1;
X
X	draw_faces(1);
X	draw_points(0);
X	if (flags.display_dtool)
X		draw_distance_tool();
X	if (flags.show_coords) draw_coords(0);
X	if (mode == M_MORE || mode == M_KMORE)
X		redraw_newface();	/* redraw the partially completed face */
X	if (mode == M_MORE)
X	{
X		if (flags.shape == M_FACE)
X			for (i1 = 0; i1 < new_seg; i1++) tri_up_point(face[faces].p[i1]);
X		else
X			for (i1 = 0; i1 < new_seg; i1++) tri_up_point(temp_poly[i1]);
X	}
X	if (mode == M_KMORE)
X	{
X		if (flags.shape == M_FACE)
X			for (i1 = 0; i1 < new_seg; i1++) tri_down_point(face[faces].p[i1]);
X		else
X			for (i1 = 0; i1 < new_seg; i1++) tri_down_point(temp_poly[i1]);
X	}
X    if (flags.crosshair) draw_hair();			/* Erase/Redraw crosshair */
X	draw_bars();
X	show_counts();
X}
X
X
Xvoid toggle_dtool()
X{
X	flags.display_dtool ^= 1;
X	draw_distance_tool();
X	/* if we turn the dtool off, exit dtool mode */
X	if (!flags.display_dtool && mode == M_DIST)
X	{
X		mode = M_ADDP;
X		draw_bars();
X	}
X}
X
X
Xvoid select_all()
X{
X	index p, limit;
X
X	deselect_all();
X
X	limit = (points >= MAX_SELECT ? MAX_SELECT : points);
X	for (p = 0; p < limit; p++)
X	{
X		select_p[p] = p;
X		box_point(p);				/* select it visually */
X		point[p].code |= PF_SELECTED;	/* set selected flag */
X	}
X	selected = p;
X}
X
X
Xvoid deselect_all()
X{
X	index i1;
X
X	for (i1 = 0; i1 < selected; i1++)
X	{
X		point[select_p[i1]].code &= ~PF_SELECTED;	/* turn off selected flag */
X		box_point(select_p[i1]);					/* and deselect it visually */
X	}
X	selected = 0;
X}
X
X
X/*
X	If the starting point is specified, the search limits itself to points
X	connected to the starting point.  Otherwise, the search starts from
X	every selected point
X*/
X
Xvoid select_connected(starting_point)
Xindex starting_point;
X{
X	int sp, i1, i2, i3, verts;	/* selected point, face and polygon indices */
X	index start_p, p;
X	index orig_selected = selected;
X
X	start_p = 0;
X
X	if (starting_point >= 0)
X	{
X		for (i1 = 0; i1 < selected; i1++)
X			if (starting_point == select_p[i1])
X			{
X				start_p = i1;
X				break;
X			}
X	}
X
X	for (sp = start_p; sp < selected; sp++)
X	{
X		p = select_p[sp];
X
X		for (i1 = 0; i1 < faces; i1++)
X		for (i2 = 0; i2 < 3; i2++)
X			if (face[i1].p[i2] == p)
X			{
X				/* select the other points of this face */
X				select_point(face[i1].p[(i2+1)%3]);
X				select_point(face[i1].p[(i2+2)%3]);
X			}
X
X		for (i1 = 0; i1 < polys; i1++)
X		{
X			verts = poly[i1].verts;
X			for (i2 = 0; i2 < verts; i2++)
X			{
X				if (poly[i1].p[i2] == p)
X				{
X					/* select the other points of this poly */
X					for (i3 = 1; i3 < verts; i3++)
X					select_point(poly[i1].p[(i2 + i3) % verts]);
X				}
X			}
X		}
X
X		if (starting_point >= 0 && sp == start_p)
X			sp = orig_selected-1;
X	}
X}
X
X
X#define DS_MAX 500
Xindex dselect[DS_MAX];
Xindex dselected;
X
Xvoid deselect_connected(starting_point)
Xindex starting_point;
X{
X	int i1, i2, i3, verts;	/* selected point, face and polygon indices */
X	index dp, p, newp;
X
X	dselected = 1;
X	dselect[0] = starting_point;
X
X	for (dp = 0; dp < dselected; dp++)
X	{
X		p = dselect[dp];
X
X		for (i1 = 0; i1 < faces; i1++)
X		for (i2 = 0; i2 < 3; i2++)
X		if (face[i1].p[i2] == p)
X		{
X			/* deselect the other points of this face */
X			newp = face[i1].p[(i2+1)%3];
X			if (pselected(newp))
X			{
X				deselect_point(newp);
X				dselect[dselected++] = newp;
X				if (dselected == DS_MAX) return;
X			}
X
X			newp = face[i1].p[(i2+2)%3];
X			if (pselected(newp))
X			{
X				deselect_point(newp);
X				dselect[dselected++] = newp;
X				if (dselected == DS_MAX) return;
X			}
X		}
X
X		for (i1 = 0; i1 < polys; i1++)
X		{
X			verts = poly[i1].verts;
X			for (i2 = 0; i2 < verts; i2++)
X			if (poly[i1].p[i2] == p)
X			for (i3 = 1; i3 < verts; i3++)	/* select the other points of this poly */
X			{
X				newp = poly[i1].p[(i2 + i3) % verts];
X				if (pselected(newp))
X				{
X					deselect_point(newp);
X					dselect[dselected++] = newp;
X					if (dselected == DS_MAX) return;
X				}
X			}
X		}
X	}
X}
X
X
Xvoid toggle_select(buttons, tp)
Xint buttons;
Xindex tp;
X{
X	if (buttons & 2)	/* double click: select connected */
X	{
X		if (pselected(tp))
X			select_connected(tp);
X		else
X			deselect_connected(tp);
X	}
X	else		/* toggle individual point */
X	{
X		if (pselected(tp))
X			deselect_point(tp);
X		else
X			select_point(tp);
X	}
X}
X
X
Xvoid glue(nearest)
Xindex nearest;
X{
X	index second;
X
X	if (nearest < 0) return;	/* must have valid point */
X	second = find_nearest_in_space(point[nearest].x, point[nearest].y,
X			point[nearest].z, nearest);
X	if (second < 0) return;
X	begin_operation();
X	glue_points(nearest, second);
X	end_operation();
X	refresh_all();
X}
X
X
X/*
X	glue_points fuses two points together into one point.
X	They should be spatially close to begin with.
X*/
X
Xvoid glue_points(p0, p1)
X{
X	Point3D new;	/* coordinate of new fused point */
X	index i1, vert;
X	index changed[MAX_EDGES];
X	index found = 0;
X	index f, q;
X	index fp0, fp1, fp2;
X
X	new.x = (point[p0].x + point[p1].x)/2;
X	new.y = (point[p0].y + point[p1].y)/2;
X	new.z = (point[p0].z + point[p1].z)/2;
X
X	/* handle possible degenerations of faces and polys */
X	for (f = 0; f < faces; f++)		/* search all faces */
X	{
X		fp0 = face[f].p[0];
X		fp1 = face[f].p[1];
X		fp2 = face[f].p[2];
X
X		if ((fp0 == p0 && fp1 == p1) ||
X			(fp1 == p0 && fp0 == p1) ||
X			(fp0 == p0 && fp2 == p1) ||
X			(fp2 == p0 && fp0 == p1) ||
X			(fp1 == p0 && fp2 == p1) ||
X			(fp2 == p0 && fp1 == p1))
X		{
X			del_face(f, 0);	/* faces cannot degenerate into lines */
X			f--;	/* don't skip a face */
X		}
X	}
X	/* now look for a polygon having these two points as an edge */
X	/* yeah, calling a function here makes things slower, but hey, speed is
X		probably not important.  If it was, we could use our own loop here. */
X	while ((q = poly_next_to_edge(p0, p1, -1)) != -1)
X	{
X		/* which vertex is it? */
X		for (vert = 0; vert < poly[q].verts; vert++)
X			if (poly[q].p[vert] == p1)
X			{
X				delete_vertex(q, vert, 0);
X				break;	/* breaks out of for loop */
X			}
X		if (poly[q].verts == 3)	/* we have reduced it to a triangle */
X		{
X			poly_to_face(q, 0);
X			del_poly(q, 0);
X		}
X	}
X
X	/* change all instances of the second point into the first */
X	for (i1 = 0; i1 < faces; i1++)
X		for (vert = 0; vert < 3; vert++)
X			if (face[i1].p[vert] == p1)
X			{
X				changed[found++] = i1;
X				face[i1].p[vert] = p0;
X			}
X
X	for (i1 = 0; i1 < polys; i1++)
X		for (vert = 0; vert < poly[i1].verts; vert++)
X			if (poly[i1].p[vert] == p1)
X			{
X				changed[found++] = i1 | POLYFLAG;
X				poly[i1].p[vert] = p0;
X			}
X	/* the join_p event is really only necessary if there were facets
X		referencing the eliminated point */
X	if (found) action_join_p(p0, p1, changed, found);
X
X	del_point(p1, 1, 0);	/* kill quickly: assume the point is loose */
X							/* but register the action */
X	move_point_to(p0, new.x, new.y, new.z);
X}
X
X
Xvoid unfold()
X{
X}
X
X
Xvoid stellate()
X{
X	int go = 1, event;
X	int id;
X	long data = 100, mag = 100;	/* magnitude of stellation */
X	int rel_to;
X	int add_p, add_f, del_f, del_q;
X	index po0;
X	long total_verts = 0;	/* total edges of all polygons */
X	int max_verts = 0;		/* the most verts on any polygon */
X	int verts;
X
X	sys_window(35, 4, "Stellate All Facets");
X	sys_movecur(1,0);
X	sys_say_text("Magnitude:");
X	sys_get_long(data, 1);
X	sys_movecur(1,1);
X	sys_say_text("Stellate relative to the object's");
X	sys_movecur(1,2);
X	sys_boolean("Face Center", 2);
X	sys_say_text(" or ");
X	sys_boolean("Radius", 3);
X	sys_activate(1);
X
X	while (go)
X	{
X		event = sys_read_event(&id, &data);
X		switch (event)
X		{
X		case EV_CANCEL:
X			sys_close_window();
X			return;
X			break;
X		case EV_CHECKINT:
X		case EV_HITRETURN:
X		case EV_HITBUTTON:
X			if (id == 1)
X			{
X				if (data > 1000) data = 1000;
X				if (data < -1000) data = -1000;
X				mag = data;
X			}
X			else if (id == 2)
X			{
X				rel_to = 0;
X				go = 0;
X			}
X			else if (id == 3)
X			{
X				rel_to = 1;
X				go = 0;
X			}
X			break;
X		}
X	}
X	sys_close_window();
X
X	/* Estimate how many actions the stellation will require. */
X	for (po0 = 0; po0 < polys; po0++)
X	{
X		verts = poly[po0].verts;
X		total_verts += verts;
X		if (max_verts < verts) max_verts = verts;
X	}
X	add_p = faces + polys;
X	add_f = (faces * 3);		/* for the faces */
X	add_f += total_verts;		/* for the polys */
X	del_f = faces;
X	del_q = polys;
X
X	/* Make sure that this event won't overflow the undo buffer */
X	if (!enough_room(add_p, add_f, 0, 0, del_f, del_q, 0, max_verts))
X	{
X		/* this operation will overflow the undo buffer! */
X		if (!tell_user_overflow()) return;
X	}
X	begin_operation();
X	stellate0(mag, rel_to);
X	end_operation();
X}
X
X
Xvoid stellate0(stellar_mag, rel_to)
Xint stellar_mag;	/* magnitude of the stellation */
Xint rel_to;			/* 0 = relative to face center, 1 = relative to radius */
X{
X	uindex
X		p0, p1, i, j,
X		old_points, old_faces, old_polys,
X		edges;
X	index np;			/* new point (the one we've just created) */
X#if INTEGER
X	long vx, vy, vz;
X#else
X	double vx, vy, vz;
X#endif
X	double cx, cy, cz, radius;	/* center coordnates for polyhedron */
X	double new_radius, scale_factor;
X	index new_faces;
X	char text[80];
X
X	if (!faces && !polys) return;	/* must have something to stellate */
X
X	begin_operation();
X
X	/* estimate how many new faces will be generated */
X	new_faces = (faces * 3);
X	for (i = 0; i < polys; i++)
X		new_faces += poly[i].verts;
X
X	if (faces + new_faces >= MAX_FACES)	/* need to make room for the new faces */
X	{
X		if (more_faces(faces + new_faces + 100))
X		{
X			sprintf(text, "increased face space to %d", MAX_FACES);
X			screen_say(text);
X		}
X		else
X		{
X			sprintf(text, "not enough memory for %d new faces", new_faces);
X			screen_say(text);
X			return;				/* failure */
X		}
X	}
X	old_points = points;	/* After we've created the stellated points */
X	old_faces = faces;		/* and faces, we'll remove the old faces. */
X	old_polys = polys;		/* And polygons. (but NOT the old points) */
X
X	/* assume it's a polyhedron that we're operating on */
X	find_center(&cx, &cy, &cz);
X	find_radius(cx, cy, cz, &radius);
X
X	/**** First we create the new points from the old faces ****/
X	for (i = 0; i < old_faces; i++)
X	{
X		vx = vy = vz = 0;
X		for (j = 0; j < 3; j++)
X		{
X			p0 = face[i].p[j];
X			vx += (point[p0].x - cx);
X			vy += (point[p0].y - cy);
X			vz += (point[p0].z - cz);
X		}
X		/* project point at face center out to stellar length */
X		vx /= 3;
X		vy /= 3;
X		vz /= 3;
X		new_radius = sqrt((double)(vx*vx + vy*vy + vz*vz));
X		if (rel_to)
X			scale_factor = (new_radius + stellar_mag) / new_radius;
X		else
X			scale_factor = (radius + stellar_mag) / new_radius;
X		np = add_point((coord)(cx + (double)vx * scale_factor),
X					  (coord)(cy + (double)vy * scale_factor),
X					  (coord)(cz + (double)vz * scale_factor));
X
X		/* Add stellation */
X		add_face(face[i].p[0], face[i].p[1], np, colors.newface, 0);
X		add_face(face[i].p[1], face[i].p[2], np, colors.newface, 0);
X		add_face(face[i].p[2], face[i].p[0], np, colors.newface, 0);
X	}
X
X	/* and from the old polygons */
X	for (i = 0; i < old_polys; i++)
X	{
X		vx = vy = vz = 0;
X		edges = poly[i].verts;
X		for (j = 0; j < edges; j++)
X		{
X			p0 = poly[i].p[j];
X			vx += (point[p0].x - cx);
X			vy += (point[p0].y - cy);
X			vz += (point[p0].z - cz);
X		}
X		vx /= edges;
X		vy /= edges;
X		vz /= edges;
X		new_radius = sqrt((double)(vx*vx + vy*vy + vz*vz));
X		if (rel_to)
X			scale_factor = (new_radius + stellar_mag) / new_radius;
X		else
X			scale_factor = (radius + stellar_mag) / new_radius;
X		np = add_point((coord)(cx + (double)vx * scale_factor),
X					  (coord)(cy + (double)vy * scale_factor),
X					  (coord)(cz + (double)vz * scale_factor));
X		/* Add stellation */
X		for (j = 0; j < edges; j++)
X		{
X			p0 = poly[i].p[j];
X			p1 = poly[i].p[(j+1)%edges];
X			add_face(p0, p1, np, colors.newface, 1);
X		}
X	}
X
X	/*** Now we must destroy the original points, faces, and polys ***/
X	for (i = 0; i < faces-old_faces; i++) face[i] = face[old_faces+i];
X
X	/* make sure we release the memory held by the original polys */
X	for (i = 0; i < old_polys; i++) kill_poly(i);
X	for (i = 0; i < polys-old_polys; i++) poly[i] = poly[old_polys+i];
X
X	faces -= old_faces;
X	polys -= old_polys;
X
X	end_operation();
X}
X
X
Xvoid find_dual()
X{
X	uindex
X		p0, i, j, k,
X		af, adj_f[MAX_EDGES],	/* number and indices of the adjacent faces */
X		ap, adj_p[MAX_EDGES],	/* number and indices of the adjacent polys */
X		np, new_p[MAX_EDGES],
X		old_points, old_faces, old_polys,
X		edges;
X	index used_f[MAX_EDGES], used_p[MAX_EDGES];
X#if INTEGER
X	long vx, vy, vz;
X#else
X	double vx, vy, vz;
X#endif
X	double cx, cy, cz, radius;	/* center coordnates for polyhedron */
X	double new_radius, scale_factor;
X	int flag;
X#define DF_POLY 1
X#define DF_FACE 2
X	index previous;
X
X	if (!faces && !polys) return;	/* must have something to dualize */
X	if (!dual_ok()) return;
X
X	begin_operation();
X
X	old_points = points;	/* After we've created the dual's points */
X	old_faces = faces;		/* and faces, we'll remove the old ones. */
X	old_polys = polys;		/* And polygons. */
X
X	if (flags.assume_poly)	/* assume it's a polyhedron that we're operating on */
X	{
X		find_center(&cx, &cy, &cz);
X		find_radius(cx, cy, cz, &radius);
X	}
X
X	/**** First we create the new points from the old faces ****/
X	for (i = 0; i < old_faces; i++)
X	{
X		vx = vy = vz = 0;
X		for (j = 0; j < 3; j++)
X		{
X			p0 = face[i].p[j];
X			if (flags.assume_poly)
X			{
X				vx += (point[p0].x - cx);
X				vy += (point[p0].y - cy);
X				vz += (point[p0].z - cz);
X			}
X			else
X			{
X				vx += point[p0].x;
X				vy += point[p0].y;
X				vz += point[p0].z;
X			}
X		}
X		if (flags.assume_poly)	/* project point at face center out to radius length */
X		{
X			new_radius = sqrt((double)(vx*vx + vy*vy + vz*vz));
X			scale_factor = radius / new_radius;
X			add_point((coord)(cx + (double)vx * scale_factor),
X					  (coord)(cy + (double)vy * scale_factor),
X					  (coord)(cz + (double)vz * scale_factor));
X		}
X		else
X			add_point(vx/3, vy/3, vz/3);	/* add a point at the face's center */
X	}
X
X	/* and from the old polygons */
X	for (i = 0; i < old_polys; i++)
X	{
X		vx = vy = vz = 0;
X		edges = poly[i].verts;
X		for (j = 0; j < edges; j++)
X		{
X			p0 = poly[i].p[j];
X			if (flags.assume_poly)
X			{
X				vx += (point[p0].x - cx);
X				vy += (point[p0].y - cy);
X				vz += (point[p0].z - cz);
X			}
X			else
X			{
X				vx += point[p0].x;
X				vy += point[p0].y;
X				vz += point[p0].z;
X			}
X		}
X		if (flags.assume_poly)	/* project point at face center out to radius length */
X		{
X			new_radius = sqrt((double)(vx*vx + vy*vy + vz*vz));
X			scale_factor = radius / new_radius;
X			add_point((coord)(cx + (double)vx * scale_factor),
X					  (coord)(cy + (double)vy * scale_factor),
X					  (coord)(cz + (double)vz * scale_factor));
X		}
X		else add_point(vx/edges, vy/edges, vz/edges);	/* add a point at the poly's center */
X	}
X
X	/* then for each point, we find the surrounding faces */
X	/* and make a face out of their corresponding points */
X
X	for (i = 0; i < old_points; i++)
X	{
X		if (flags.debug) printf("Point %d: ", i);
X		af = ap = 0;
X
X		for (j = 0; j < old_faces; j++)
X			if (face[j].p[0] == i || face[j].p[1] == i || face[j].p[2] == i)
X				adj_f[af++] = j;
X
X		for (j = 0; j < old_polys; j++)
X			for (k = 0; k < poly[j].verts; k++)
X				if (poly[j].p[k] == i) adj_p[ap++] = j;
X
X		if (flags.debug)
X		{
X			if (flags.debug) printf("%d adjacent faces:", af);
X			if (af) for (j = 0; j < af; j++) printf(" %d", adj_f[j]);
X			printf("\n");
X			printf("         %d adjacent polys:", ap);
X			if (ap) for (j = 0; j < ap; j++) printf(" %d", adj_p[j]);
X			printf("\n");
X		}
X
X		if (af+ap == 3)		/* three points are a simple face */
X		{
X			if (flags.debug) printf(" %d %d  adding face:", af, ap);
X			np = 0;
X			for (j = 0; j < af; j++)
X				new_p[np++] = adj_f[j];
X			for (j = 0; j < ap; j++)
X				new_p[np++] = old_faces + adj_p[j];
X			if (flags.debug)
X			{
X				printf("   ->");
X				for (j = 0; j < 3; j++) printf(" %d", new_p[j]);
X				printf("\n");
X			}
X			add_face(new_p[0], new_p[1], new_p[2], colors.newface, 1);
X		}
X		else if (af+ap > 3)
X		{
X			if (flags.debug) printf(" %d %d  adding POLYGON:", af, ap);
X			for (j = 0; j < af; j++) used_f[j] = 0;
X			for (j = 0; j < ap; j++) used_p[j] = 0;
X			allocate_poly(af+ap, colors.newface);
X
X			/*** At this point we must arrange the points in the correct
X				order to produce a correct polygon. ***/
X			/* We pick one arbitrary starting face, then advance around
X				the point by finding adjacent faces/polys that we haven't
X				used before. */
X			np = 0;
X			if (af)	/* pick starting point at 0 */
X			{
X				previous = poly[polys].p[np++] = adj_f[0];
X				used_f[0] = 1;
X				flag = DF_FACE;
X			}
X			else
X			{
X				previous = adj_p[0];
X				poly[polys].p[np++] = old_faces + adj_p[0];
X				used_p[0] = 1;
X				flag = DF_POLY;
X			}
X			np = 1;
X			while (np < af+ap)
X			{
X				for (k = 0; k < af; k++)	/* search faces */
X				{
X					if (used_f[k]) continue;	/* skip already-used faces */
X					if (adjacent_xx(previous, adj_f[k], (flag == DF_POLY), 0))
X					{
X						previous = poly[polys].p[np++] = adj_f[k];
X						used_f[k] = 1;
X						flag = DF_FACE;
X					}
X				}
X				for (k = 0; k < ap; k++)	/* search polys */
X				{
X					if (used_p[k]) continue;	/* skip already-used polys */
X					if (adjacent_xx(previous, adj_p[k], (flag == DF_POLY), 1))
X					{
X						poly[polys].p[np++] = old_faces + adj_p[k];
X						previous = adj_p[k];
X						used_p[k] = 1;
X						flag = DF_POLY;
X					}
X				}
X			}
X			finish_poly(0);
X			if (flags.debug)
X			{
X				printf("   ->");
X				for (j = 0; j < af+ap; j++) printf(" %d", poly[polys-1].p[j]);
X				printf("\n");
X			}
X		}
X	}
X
X	if (flags.debug)
X	{
X		printf("points %d, faces %d, polys %d\n", points, faces, polys);
X		printf("starting destruction:\n");
X	}
X
X	/*** Now we must destroy the original points, faces, and polys ***/
X
X	for (i = 0; i < points-old_points; i++)
X		point[i] = point[old_points+i];
X	for (i = 0; i < faces-old_faces; i++) face[i] = face[old_faces+i];
X
X	/* make sure we release the memory held by the original polys */
X	for (i = 0; i < old_polys; i++) kill_poly(i);
X	for (i = 0; i < polys-old_polys; i++) poly[i] = poly[old_polys+i];
X
X	points -= old_points;
X	faces -= old_faces;
X	polys -= old_polys;
X
X	if (flags.debug)
X	{
X		printf("ending destruction:\n");
X		printf("points %d, faces %d, polys %d\n", points, faces, polys);
X	}
X	convert_points();
X	end_operation();
X}
X
X
X/* returns whether it is OK to perform a dualize operation */
X
Xint dual_ok()
X{
X	index p0, f0, q0, v0, surround;
X	index p, f, q, dp, df, dq;
X
X	if (!flags.undo_active) return 1;	/* always OK if undo is off */
X	p = f = q = 0;
X
X	/* Estimate how many faces and polys will need to be created */
X	for (p0 = 0; p0 < points; p0++)
X	{
X		surround = 0;
X		for (f0 = 0; f0 < faces; f0++)
X			if (face[f0].p[0] == p0 ||face[f0].p[2] == p0 ||face[f0].p[1] == p0)
X				surround ++;
X		for (q0 = 0; q0 < polys; q0++)
X			for (v0 = 0; v0 < poly[q0].verts; v0++)
X				if (poly[q0].p[v0] == p0)
X					surround ++;
X		if (surround == 3) f++;
X		if (surround > 3) q++;
X	}
X	p = faces + polys;	/* each facet becomes a point */
X	dp = points;
X	df = faces;
X	dq = polys;
X	/* Make sure that this event won't overflow the undo buffer */
X	if (!enough_room(p, f, q, dp, df, dq, 0, 0))
X	{
X		/* this operation will overflow the undo buffer! */
X		if (!tell_user_overflow()) return 0;
X	}
X	return 1;
X}
X
X
X/*
X	Compare a face to face, face to poly, poly to face, or poly to poly.
X	The two flag arguments indicate what type of face the first two arguments
X	are (flag = TRUE if they indicated argument is a poly)
X*/
X
Xindex adjacent_xx(qf0, qf1, poly_flag0, poly_flag1)
Xuindex qf0, qf1;
Xint poly_flag0, poly_flag1;
X{
X  if (poly_flag0)
X  {
X    if (poly_flag1)
X		return adjacent_pp(qf0, qf1);
X	else
X		return adjacent_fp(qf1, qf0);
X  }
X  else
X  {
X    if (poly_flag1)
X		return adjacent_fp(qf0, qf1);
X	else
X		return adjacent_ff(qf0, qf1);
X  }
X}
X
X
X/*
X	Compare two faces to see if they share an edge: returns 1 or -1
X	depending on the direction of the match, 0 if there is no shared
X	edge.
X*/
X
Xindex adjacent_ff(f0, f1)
Xuindex f0, f1;
X{
X	uindex e, e2, p00, p01, p10, p11;
X	index *fpp = face[f1].p;
X
X	for (e = 0; e < 3; e++)
X	{
X	  p00 = face[f0].p[e];
X	  p01 = face[f0].p[(e+1)%3];
X	  for (e2 = 0; e2 < 3; e2++)
X	  {
X		/* There are two ways that one edge can match another:
X			the point numbers can be identical or inverted.
X			Edge i has indices i, (i+1)%3 for i = 0,1,2.
X		*/
X		p10 = fpp[e2];
X		p11 = fpp[(e2+1)%3];
X
X		if (p00 == p10 && p01 == p11) return 1;
X		else if (p00 == p11 && p01 == p10) return -1;
X	  }
X	}
X	return (index)0;
X}
X
X
X/*
X	Compare a face to a poly to see if they share any edge: returns 1 or -1
X	depending on the direction of the match, 0 if there is no shared
X	edge.
X*/
X
Xindex adjacent_fp(f0, q0)
Xuindex f0, q0;
X{
X	uindex e, e2, p00, p01, p10, p11, verts;
X	index *fpp = face[f0].p;
X	index *qpp = poly[q0].p;
X
X	verts = poly[q0].verts;
X
X	for (e = 0; e < 3; e++)
X	{
X	  p00 = fpp[e];
X	  p01 = fpp[(e+1)%3];
X	  for (e2 = 0; e2 < verts; e2++)
X	  {
X		p10 = qpp[e2];
X		p11 = qpp[(e2+1)%verts];
X
X		if (p00 == p10 && p01 == p11) return 1;
X		else if (p00 == p11 && p01 == p10) return -1;
X	  }
X	}
X	return (index)0;
X}
X
X
X/*
X	Compare a poly to a poly to see if they share any edge: returns 1 or -1
X	depending on the direction of the match, 0 if there is no shared
X	edge.
X*/
X
Xindex adjacent_pp(q0, q1)
Xuindex q0, q1;
X{
X	uindex e, e2, p00, p01, p10, p11, verts0, verts1;
X	index *qp0 = poly[q0].p;
X	index *qp1 = poly[q1].p;
X
X	verts0 = poly[q0].verts;
X	verts1 = poly[q1].verts;
X
X	for (e = 0; e < verts0; e++)
X	{
X	  p00 = qp0[e];
X	  p01 = qp0[(e+1)%verts0];
X	  for (e2 = 0; e2 < verts1; e2++)
X	  {
X		p10 = qp1[e2];
X		p11 = qp1[(e2+1)%verts1];
X
X		if (p00 == p10 && p01 == p11) return 1;
X		else if (p00 == p11 && p01 == p10) return -1;
X	  }
X	}
X	return (index)0;
X}
X
X
X/*
X	The idea here is to match 3 points with the points
X		of some face.  There are 3! == 6 ways (permutations)
X		that the three point numbers can match the selected points.
X*/
X
Xindex points_are_a_face(ps0, ps1, ps2)
Xuindex ps0, ps1, ps2;
X{
X	uindex f, p0, p1, p2;
X
X	for (f = 0; f < faces; f++)		/* search all faces */
X	{
X		p0 = face[f].p[0];
X		p1 = face[f].p[1];
X		p2 = face[f].p[2];
X
X		if ((p0 == ps0 && p1 == ps1 && p2 == ps2) ||
X			(p0 == ps0 && p1 == ps2 && p2 == ps1) ||
X			(p0 == ps1 && p1 == ps0 && p2 == ps2) ||
X			(p0 == ps1 && p1 == ps2 && p2 == ps0) ||
X			(p0 == ps2 && p1 == ps0 && p2 == ps1) ||
X			(p0 == ps2 && p1 == ps1 && p2 == ps0))
X		{
X			return (index)f;
X		}
X	}
X	return (index)-1;
X}
X
X
X/*	Same as the above function, only it works with two points,
X	returning a face that the two points (edge) share (if there is one).
X	This function could be used to see if two points are "connected",
X	or to find a face adjacent to an edge.  For this second usage,
X	we don't want to find the original face, so we pass its number
X	so that we can avoid it.
X*/
X
Xindex face_next_to_edge(ps0, ps1, avoid_f)
Xuindex ps0, ps1;
Xindex avoid_f;
X{
X	uindex f, p0, p1, p2;
X
X	for (f = 0; f < faces; f++)		/* search all faces */
X	{
X		p0 = face[f].p[0];
X		p1 = face[f].p[1];
X		p2 = face[f].p[2];
X
X		if ((p0 == ps0 && p1 == ps1) ||
X			(p1 == ps0 && p0 == ps1) ||
X			(p0 == ps0 && p2 == ps1) ||
X			(p2 == ps0 && p0 == ps1) ||
X			(p1 == ps0 && p2 == ps1) ||
X			(p2 == ps0 && p1 == ps1))
X		{
X			if (f != avoid_f) return (index)f;
X		}
X	}
X	return (index)-1;
X}
X
X
X/* check if a point is a member of any face */
X
Xindex point_is_on_a_face(ps0)
Xuindex ps0;
X{
X	uindex f;
X
X	for (f = 0; f < faces; f++)		/* search all faces */
X		if (face[f].p[0] == ps0 || face[f].p[1] == ps0 || face[f].p[2] == ps0)
X			return (index)f;
X	return (index)-1;
X}
X
X
X/* check if a point is a member of any poly */
X
Xindex point_is_on_a_poly(ps0)
Xuindex ps0;
X{
X	uindex po, v;
X
X	for (po = 0; po < polys; po++)		/* search all faces */
X		for (v = 0; v < poly[po].verts; v++)
X			if (poly[po].p[v] == ps0)
X				return (index)po;
X	return (index)-1;
X}
X
X
Xindex points_are_on_a_poly(array, verts)
Xuindex *array, verts;
X{
X	uindex po, pverts, test;
X	register uindex i, j;
X
X	if (!polys) return (index)-1;
X
X	for (po = 0; po < polys; po++)
X	{
X		pverts = poly[po].verts;
X		if (pverts < verts) continue;	/* skip simpler polys */
X
X		for (i = 0; i < pverts; i++)
X		{
X			/* test forwards */
X			test = 1;
X			for (j = 0; j < verts; j++)
X				if (array[j] != poly[po].p[(i+j) % pverts])
X					{ test = 0; break; }
X			if (test) return (index)po;
X
X			/* test backwards */
X			test = 1;
X			for (j = 0; j < verts; j++)
X				if (array[verts-j-1] != poly[po].p[(i+j) % pverts])
X					{ test = 0; break; }
X			if (test) return (index)po;
X		}
X	}
X	return -1;
X}
X
X
X/*
X	Like face_next_to_edge, except it works with polys.
X	You can optionally pass a poly index for it to ignore.
X	Returns -1 on failure.
X*/
X
Xindex poly_next_to_edge(ps0, ps1, avoid_p)
Xuindex ps0, ps1;
Xindex avoid_p;
X{
X	uindex p, p0, p1, v, verts;
X
X	for (p = 0; p < polys; p++)		/* search all polys */
X	{
X		verts = poly[p].verts;
X		p0 = poly[p].p[verts-1];
X		for (v = 0; v < verts; v++)
X		{
X			p1 = poly[p].p[v];
X	
X			if ((p0 == ps0 && p1 == ps1) ||
X				(p1 == ps0 && p0 == ps1))
X			{
X				if (p != avoid_p) return (index)p;
X			}
X			p0 = p1;
X		}
X	}
X	return (index)-1;
X}
X
X
Xvoid zoom(buttons)
Xint buttons;
X{
X	register coord oldgx = gx, oldgy = gy, oldgz = gz;
X
X	if (buttons & 1)
X		SCALE /= 0.9;
X 	else
X		SCALE *= 0.9;
X
X	convert_to_xyz(mx, my);
X
X	offset.x += oldgx - gx;
X	offset.y += oldgy - gy;
X	offset.z += oldgz - gz;
X	convert_points();
X	refresh_all();
X}
X
X
Xvoid set_rot_axis(x, y, z)
Xcoord x, y, z;
X{
X	axis.x = x;
X	axis.y = y;
X	axis.z = z;
X
X	mode = M_ROTP;
X	draw_bars();
X	rot_angle = 0.0;
X    draw_rot();	/* Redraw angle */
X}
X
X
Xvoid rotate()
X{
X	register index i1;
X	double  co = cos(rot_angle),
X			si = sin(rot_angle);
X	int move_p;
X
X	if (flags.rotate_all)
X		move_p = points;
X	else
X		move_p = selected;
X
X	if (!enough_room(0, 0, 0, 0, 0, 0, move_p, 0))
X	{
X		/* this operation will overflow the undo buffer! */
X		if (!tell_user_overflow()) return;
X	}
X
X	begin_operation();
X	if (flags.rotate_all)
X	{
X		for (i1 = 0; i1 < points; i1++)
X		  rotate_point(i1, co, si);
X	}
X	else
X	{
X		for (i1 = 0; i1 < selected; i1++)
X		  rotate_point(select_p[i1], co, si);
X	}
X	end_operation();
X	mode = M_ROTA;
X	flags.copy_made = 0;
X	refresh_all();
X}
X
X
Xvoid rotate_point(p, co, si)
Xindex p;	/* the point to rotate */
Xdouble co, si;	/* the cosine and sine of the angle to rotate */
X{
X	coord dx, dy, dz;
X
X	dx = point[p].x - axis.x;
X	dy = point[p].y - axis.y;
X	dz = point[p].z - axis.z;
X
X	switch (dmode)
X	{
X		case DM_XY:
X			move_point_to(p, axis.x + (coord)(co*dx - si*dy),
X							 axis.y + (coord)(si*dx + co*dy), point[p].z);
X			break;
X		case DM_XZ:
X			move_point_to(p, axis.x + (coord)(co*dx - si*dz), point[p].y,
X							 axis.z + (coord)(si*dx + co*dz));
X			break;
X		case DM_ZY:
X			move_point_to(p, point[p].x, axis.y + (coord)(si*dz + co*dy),
X							 axis.z + (coord)(co*dz - si*dy));
X			break;
X		case DM_3D:
X			break;
X	}
X	convert_point(p);
X}
X
X
Xvoid find_center(cx, cy, cz)
Xdouble *cx, *cy, *cz;
X{
X	long sum_x, sum_y, sum_z;
X	register unsigned int i;
X
X	*cx = *cy = *cz = 0;
X
X	if (!points) return;
X
X	sum_x = sum_y = sum_z = 0;
X	for (i = 0; i < points; i++)
X	{
X		sum_x += point[i].x;
X		sum_y += point[i].y;
X		sum_z += point[i].z;
X	}
X	*cx = (double)sum_x / points;
X	*cy = (double)sum_y / points;
X	*cz = (double)sum_z / points;
X}
X
X
Xvoid find_radius(cx, cy, cz, radius)
Xdouble cx, cy, cz, *radius;
X{
X	register unsigned int i;
X	coord dx, dy, dz;
X	double dist = 0.0;
X
X	for (i = 0; i < points; i++)
X	{
X		dx = point[i].x - cx;
X		dy = point[i].y - cy;
X		dz = point[i].z - cz;
X		dist += sqrt((double)(dx*dx + dy*dy + dz*dz));
X	}
X	*radius = dist / (double)points;
X}
X
X
X/*
X	This integer sqrt function is about *15* times faster than
X	the standard double-precision math function under lattice.
X	It was the result of a thread on comp.graphics a while ago.
X	I've tested the precise accuracy of it's results up to 600000.
X 	I suppose if i was a real CS god i could PROVE that this algo
X	always works.
X*/
X
Xunsigned long isqrt(v)
Xunsigned long v;
X{
X	register long t = 1L<<30, r = 0, s;
X
X#define STEP(k) s = t + r; r >>= 1; if (s <= v) { v -= s; r |= t;}
X
X	STEP(15);	t >>= 2;
X	STEP(14);	t >>= 2;
X	STEP(13);	t >>= 2;
X	STEP(12);	t >>= 2;
X	STEP(11);	t >>= 2;
X	STEP(10);	t >>= 2;
X	STEP(9);	t >>= 2;
X	STEP(8);	t >>= 2;
X	STEP(7);	t >>= 2;
X	STEP(6);	t >>= 2;
X	STEP(5);	t >>= 2;
X	STEP(4);	t >>= 2;
X	STEP(3);	t >>= 2;
X	STEP(2);	t >>= 2;
X	STEP(1);	t >>= 2;
X	STEP(0);
X
X	return (ULONG)r;
X}
X
X
X/* return fibonacci element (sum of natural numbers up to n) */
X
Xfibo(n)
X{
X	int sum = 0;
X
X	while (n)
X	{
X		sum += n;
X		n--;
X	}
X	return sum;
X}
X
X
Xvoid set_clockwisdom()
X{
X	index f, q;
X
X	for (f = 0; f < faces; f++)
X	{
X		if (determine_clockwisdom(face[f].p[0], face[f].p[1], face[f].p[2]))
X		{
X			change_face_clockwisdom(f);
X		}
X	}
X	for (q = 0; q < polys; q++)
X	{
X		if (determine_clockwisdom(poly[q].p[0], poly[q].p[1], poly[q].p[2]))
X		{
X			change_face_clockwisdom(f);
X		}
X	}
X}
X
X
Xint determine_clockwisdom(p0, p1, p2)
Xindex p0, p1, p2;
X{
X	Point3D center;
X	Vector3D v0, v1, v2, normal;
X	coord dot;
X
X	center.x = zero;
X	center.y = zero;
X	center.z = zero;
X
X	v0.x = point[p0].x - center.x;
X	v0.y = point[p0].y - center.y;
X	v0.z = point[p0].z - center.z;
X
X	v1.x = point[p1].x - center.x;
X	v1.y = point[p1].y - center.y;
X	v1.z = point[p1].z - center.z;
X
X	v2.x = point[p2].x - center.x;
X	v2.y = point[p2].y - center.y;
X	v2.z = point[p2].z - center.z;
X
X	/* now we find the normal by finding the cross product v0 X v1 */
X	normal.x = v0.y * v1.z - v0.z * v1.y;
X	normal.y = v0.z * v1.x - v0.x * v1.z;
X	normal.z = v0.x * v1.y - v0.y * v1.x;
X	/* note that there is no need to normalize the normal */
X
X	/* we now have a definition of the plane through {center, p0, p1} */
X	/* the dot product of v2 with the plane's normal gives the distance
X		to the plane, of which we are only interested in the sign */
X	dot = v2.x * normal.x + v2.y * normal.y + v2.z * normal.z;
X	return (dot > zero);
X}
X
X
Xvoid change_face_clockwisdom(f)
Xindex f;
X{
X	index tmp;
X	tmp = face[f].p[1];
X	face[f].p[1] = face[f].p[2];
X	face[f].p[2] = tmp;
X}
X
X
Xvoid change_poly_clockwisdom(q)
Xindex q;
X{
X	index tmp;
X	index pi;	/* point index */
X	int verts = poly[q].verts;
X
X	for (pi = 1; pi < (verts+1)/2; pi++)
X	{
X		tmp = poly[q].p[pi];
X		poly[q].p[pi] = poly[q].p[verts - pi];
X		poly[q].p[verts - pi] = tmp;
X	}
X}
X
END_OF_FILE
if test 32224 -ne `wc -c <'edvan.c'`; then
    echo shar: \"'edvan.c'\" unpacked with wrong size!
fi
# end of 'edvan.c'
fi
echo shar: End of archive 6 \(of 6\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.
